pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #ifndef MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ |
| 12 | #define MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 13 | |
kwiberg | 88788ad | 2016-02-19 07:04:49 -0800 | [diff] [blame] | 14 | #include <memory> |
| 15 | |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 16 | #include "absl/types/optional.h" |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 17 | #include "modules/audio_processing/agc/agc.h" |
Hanna Silen | a004715 | 2021-06-03 03:29:38 +0200 | [diff] [blame] | 18 | #include "modules/audio_processing/agc/clipping_predictor.h" |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 19 | #include "modules/audio_processing/agc/clipping_predictor_evaluator.h" |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 20 | #include "modules/audio_processing/audio_buffer.h" |
Alex Loiko | c167673 | 2018-07-02 12:05:28 +0200 | [diff] [blame] | 21 | #include "modules/audio_processing/logging/apm_data_dumper.h" |
Alex Loiko | 9489c3a | 2018-08-09 15:04:24 +0200 | [diff] [blame] | 22 | #include "rtc_base/gtest_prod_util.h" |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 23 | |
| 24 | namespace webrtc { |
| 25 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 26 | class MonoAgc; |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 27 | class GainControl; |
| 28 | |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 29 | // Direct interface to use AGC to set volume and compression values. |
| 30 | // AudioProcessing uses this interface directly to integrate the callback-less |
Alejandro Luebs | d094c04 | 2015-09-29 15:43:42 -0700 | [diff] [blame] | 31 | // AGC. |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 32 | // |
| 33 | // This class is not thread-safe. |
Alejandro Luebs | d094c04 | 2015-09-29 15:43:42 -0700 | [diff] [blame] | 34 | class AgcManagerDirect final { |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 35 | public: |
| 36 | // AgcManagerDirect will configure GainControl internally. The user is |
| 37 | // responsible for processing the audio using it after the call to Process. |
Bjorn Volcker | adc46c4 | 2015-04-15 11:42:40 +0200 | [diff] [blame] | 38 | // The operating range of startup_min_level is [12, 255] and any input value |
Hanna Silen | b8dc7fa | 2021-05-20 17:37:56 +0200 | [diff] [blame] | 39 | // outside that range will be clamped. `clipped_level_step` is the amount |
| 40 | // the microphone level is lowered with every clipping event, limited to |
| 41 | // (0, 255]. `clipped_ratio_threshold` is the proportion of clipped |
| 42 | // samples required to declare a clipping event, limited to (0.f, 1.f). |
| 43 | // `clipped_wait_frames` is the time in frames to wait after a clipping event |
| 44 | // before checking again, limited to values higher than 0. |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 45 | AgcManagerDirect( |
| 46 | int num_capture_channels, |
| 47 | int startup_min_level, |
| 48 | int clipped_level_min, |
| 49 | bool disable_digital_adaptive, |
| 50 | int sample_rate_hz, |
| 51 | int clipped_level_step, |
| 52 | float clipped_ratio_threshold, |
| 53 | int clipped_wait_frames, |
| 54 | const AudioProcessing::Config::GainController1::AnalogGainController:: |
| 55 | ClippingPredictor& clipping_config); |
Alex Loiko | 64cb83b | 2018-07-02 13:38:19 +0200 | [diff] [blame] | 56 | |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 57 | ~AgcManagerDirect(); |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 58 | AgcManagerDirect(const AgcManagerDirect&) = delete; |
| 59 | AgcManagerDirect& operator=(const AgcManagerDirect&) = delete; |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 60 | |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 61 | void Initialize(); |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 62 | void SetupDigitalGainControl(GainControl* gain_control) const; |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 63 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 64 | void AnalyzePreProcess(const AudioBuffer* audio); |
| 65 | void Process(const AudioBuffer* audio); |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 66 | |
Per Åhgren | 0a144a7 | 2021-02-09 08:47:51 +0100 | [diff] [blame] | 67 | // Call when the capture stream output has been flagged to be used/not-used. |
| 68 | // If unused, the manager disregards all incoming audio. |
| 69 | void HandleCaptureOutputUsedChange(bool capture_output_used); |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 70 | float voice_probability() const; |
Alejandro Luebs | d094c04 | 2015-09-29 15:43:42 -0700 | [diff] [blame] | 71 | |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 72 | int stream_analog_level() const { return stream_analog_level_; } |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 73 | void set_stream_analog_level(int level); |
| 74 | int num_channels() const { return num_capture_channels_; } |
| 75 | int sample_rate_hz() const { return sample_rate_hz_; } |
| 76 | |
| 77 | // If available, returns a new compression gain for the digital gain control. |
| 78 | absl::optional<int> GetDigitalComressionGain(); |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 79 | |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 80 | // Returns true if clipping prediction is enabled. |
| 81 | bool clipping_predictor_enabled() const { return !!clipping_predictor_; } |
| 82 | |
| 83 | // Returns true if clipping prediction is used to adjust the analog gain. |
| 84 | bool use_clipping_predictor_step() const { |
| 85 | return use_clipping_predictor_step_; |
| 86 | } |
| 87 | |
Alejandro Luebs | d094c04 | 2015-09-29 15:43:42 -0700 | [diff] [blame] | 88 | private: |
Alex Loiko | 2ffafa8 | 2018-07-06 15:35:42 +0200 | [diff] [blame] | 89 | friend class AgcManagerDirectTest; |
| 90 | |
Alex Loiko | 9489c3a | 2018-08-09 15:04:24 +0200 | [diff] [blame] | 91 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 92 | DisableDigitalDisablesDigital); |
henrika | ebf4552 | 2019-11-04 13:59:21 +0100 | [diff] [blame] | 93 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 94 | AgcMinMicLevelExperiment); |
Alessio Bazzica | 42eef86 | 2021-01-15 16:41:48 +0100 | [diff] [blame] | 95 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 96 | AgcMinMicLevelExperimentDisabled); |
| 97 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 98 | AgcMinMicLevelExperimentOutOfRangeAbove); |
| 99 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 100 | AgcMinMicLevelExperimentOutOfRangeBelow); |
| 101 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 102 | AgcMinMicLevelExperimentEnabled50); |
| 103 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 104 | AgcMinMicLevelExperimentEnabledAboveStartupLevel); |
Hanna Silen | b8dc7fa | 2021-05-20 17:37:56 +0200 | [diff] [blame] | 105 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 106 | ClippingParametersVerified); |
Hanna Silen | a004715 | 2021-06-03 03:29:38 +0200 | [diff] [blame] | 107 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 108 | DisableClippingPredictorDoesNotLowerVolume); |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 109 | FRIEND_TEST_ALL_PREFIXES( |
| 110 | AgcManagerDirectStandaloneTest, |
| 111 | EnableClippingPredictorWithUnusedPredictedStepDoesNotLowerVolume); |
Hanna Silen | a004715 | 2021-06-03 03:29:38 +0200 | [diff] [blame] | 112 | FRIEND_TEST_ALL_PREFIXES(AgcManagerDirectStandaloneTest, |
| 113 | EnableClippingPredictorLowersVolume); |
Alex Loiko | 9489c3a | 2018-08-09 15:04:24 +0200 | [diff] [blame] | 114 | |
Alex Loiko | 2ffafa8 | 2018-07-06 15:35:42 +0200 | [diff] [blame] | 115 | // Dependency injection for testing. Don't delete |agc| as the memory is owned |
| 116 | // by the manager. |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 117 | AgcManagerDirect( |
| 118 | Agc* agc, |
| 119 | int startup_min_level, |
| 120 | int clipped_level_min, |
| 121 | int sample_rate_hz, |
| 122 | int clipped_level_step, |
| 123 | float clipped_ratio_threshold, |
| 124 | int clipped_wait_frames, |
| 125 | const AudioProcessing::Config::GainController1::AnalogGainController:: |
| 126 | ClippingPredictor& clipping_config); |
Alex Loiko | 2ffafa8 | 2018-07-06 15:35:42 +0200 | [diff] [blame] | 127 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 128 | void AnalyzePreProcess(const float* const* audio, size_t samples_per_channel); |
| 129 | |
| 130 | void AggregateChannelLevels(); |
| 131 | |
| 132 | std::unique_ptr<ApmDataDumper> data_dumper_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 133 | static int instance_counter_; |
Per Åhgren | 26cc5e6 | 2019-11-26 22:58:53 +0100 | [diff] [blame] | 134 | const bool use_min_channel_level_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 135 | const int sample_rate_hz_; |
| 136 | const int num_capture_channels_; |
| 137 | const bool disable_digital_adaptive_; |
| 138 | |
| 139 | int frames_since_clipped_; |
| 140 | int stream_analog_level_ = 0; |
Per Åhgren | 0a144a7 | 2021-02-09 08:47:51 +0100 | [diff] [blame] | 141 | bool capture_output_used_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 142 | int channel_controlling_gain_ = 0; |
| 143 | |
Hanna Silen | b8dc7fa | 2021-05-20 17:37:56 +0200 | [diff] [blame] | 144 | const int clipped_level_step_; |
| 145 | const float clipped_ratio_threshold_; |
| 146 | const int clipped_wait_frames_; |
| 147 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 148 | std::vector<std::unique_ptr<MonoAgc>> channel_agcs_; |
| 149 | std::vector<absl::optional<int>> new_compressions_to_set_; |
Hanna Silen | a004715 | 2021-06-03 03:29:38 +0200 | [diff] [blame] | 150 | |
| 151 | const std::unique_ptr<ClippingPredictor> clipping_predictor_; |
Alessio Bazzica | 42dacda | 2021-06-17 17:18:46 +0200 | [diff] [blame] | 152 | const bool use_clipping_predictor_step_; |
| 153 | ClippingPredictorEvaluator clipping_predictor_evaluator_; |
| 154 | int clipping_predictor_log_counter_; |
Hanna Silen | e7e9292 | 2021-07-08 17:26:31 +0200 | [diff] [blame] | 155 | float clipping_rate_log_; |
| 156 | int clipping_rate_log_counter_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 157 | }; |
| 158 | |
| 159 | class MonoAgc { |
| 160 | public: |
| 161 | MonoAgc(ApmDataDumper* data_dumper, |
| 162 | int startup_min_level, |
| 163 | int clipped_level_min, |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 164 | bool disable_digital_adaptive, |
| 165 | int min_mic_level); |
| 166 | ~MonoAgc(); |
| 167 | MonoAgc(const MonoAgc&) = delete; |
| 168 | MonoAgc& operator=(const MonoAgc&) = delete; |
| 169 | |
| 170 | void Initialize(); |
Per Åhgren | 0a144a7 | 2021-02-09 08:47:51 +0100 | [diff] [blame] | 171 | void HandleCaptureOutputUsedChange(bool capture_output_used); |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 172 | |
Hanna Silen | b8dc7fa | 2021-05-20 17:37:56 +0200 | [diff] [blame] | 173 | void HandleClipping(int clipped_level_step); |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 174 | |
| 175 | void Process(const int16_t* audio, |
| 176 | size_t samples_per_channel, |
| 177 | int sample_rate_hz); |
| 178 | |
| 179 | void set_stream_analog_level(int level) { stream_analog_level_ = level; } |
| 180 | int stream_analog_level() const { return stream_analog_level_; } |
| 181 | float voice_probability() const { return agc_->voice_probability(); } |
| 182 | void ActivateLogging() { log_to_histograms_ = true; } |
| 183 | absl::optional<int> new_compression() const { |
| 184 | return new_compression_to_set_; |
| 185 | } |
| 186 | |
| 187 | // Only used for testing. |
| 188 | void set_agc(Agc* agc) { agc_.reset(agc); } |
henrika | ebf4552 | 2019-11-04 13:59:21 +0100 | [diff] [blame] | 189 | int min_mic_level() const { return min_mic_level_; } |
| 190 | int startup_min_level() const { return startup_min_level_; } |
| 191 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 192 | private: |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 193 | // Sets a new microphone level, after first checking that it hasn't been |
| 194 | // updated by the user, in which case no action is taken. |
| 195 | void SetLevel(int new_level); |
| 196 | |
| 197 | // Set the maximum level the AGC is allowed to apply. Also updates the |
| 198 | // maximum compression gain to compensate. The level must be at least |
| 199 | // |kClippedLevelMin|. |
| 200 | void SetMaxLevel(int level); |
| 201 | |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 202 | int CheckVolumeAndReset(); |
| 203 | void UpdateGain(); |
| 204 | void UpdateCompressor(); |
| 205 | |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 206 | const int min_mic_level_; |
| 207 | const bool disable_digital_adaptive_; |
kwiberg | 88788ad | 2016-02-19 07:04:49 -0800 | [diff] [blame] | 208 | std::unique_ptr<Agc> agc_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 209 | int level_ = 0; |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 210 | int max_level_; |
| 211 | int max_compression_gain_; |
| 212 | int target_compression_; |
| 213 | int compression_; |
| 214 | float compression_accumulator_; |
Per Åhgren | 0a144a7 | 2021-02-09 08:47:51 +0100 | [diff] [blame] | 215 | bool capture_output_used_ = true; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 216 | bool check_volume_on_next_process_ = true; |
| 217 | bool startup_ = true; |
Bjorn Volcker | adc46c4 | 2015-04-15 11:42:40 +0200 | [diff] [blame] | 218 | int startup_min_level_; |
Alex Loiko | f3122e0 | 2018-08-10 14:43:51 +0200 | [diff] [blame] | 219 | int calls_since_last_gain_log_ = 0; |
Per Åhgren | 0e3198e | 2019-11-18 08:52:22 +0100 | [diff] [blame] | 220 | int stream_analog_level_ = 0; |
| 221 | absl::optional<int> new_compression_to_set_; |
Per Åhgren | 3daedb6 | 2019-11-22 12:11:40 +0100 | [diff] [blame] | 222 | bool log_to_histograms_ = false; |
| 223 | const int clipped_level_min_; |
pbos@webrtc.org | 788acd1 | 2014-12-15 09:41:24 +0000 | [diff] [blame] | 224 | }; |
| 225 | |
| 226 | } // namespace webrtc |
| 227 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 228 | #endif // MODULES_AUDIO_PROCESSING_AGC_AGC_MANAGER_DIRECT_H_ |