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
11 #include "modules/audio_processing/agc/agc_manager_direct.h"
12
13 #include <fstream>
14 #include <limits>
15 #include <tuple>
16 #include <vector>
17
18 #include "modules/audio_processing/agc/gain_control.h"
19 #include "modules/audio_processing/agc/mock_agc.h"
20 #include "modules/audio_processing/include/mock_audio_processing.h"
21 #include "rtc_base/numerics/safe_minmax.h"
22 #include "rtc_base/strings/string_builder.h"
23 #include "test/field_trial.h"
24 #include "test/gmock.h"
25 #include "test/gtest.h"
26 #include "test/testsupport/file_utils.h"
27
28 using ::testing::_;
29 using ::testing::AtLeast;
30 using ::testing::DoAll;
31 using ::testing::Return;
32 using ::testing::SetArgPointee;
33
34 namespace webrtc {
35 namespace {
36
37 constexpr int kSampleRateHz = 32000;
38 constexpr int kNumChannels = 1;
39 constexpr int kInitialInputVolume = 128;
40 constexpr int kClippedMin = 165; // Arbitrary, but different from the default.
41 constexpr float kAboveClippedThreshold = 0.2f;
42 constexpr int kMinMicLevel = 12;
43 constexpr int kClippedLevelStep = 15;
44 constexpr float kClippedRatioThreshold = 0.1f;
45 constexpr int kClippedWaitFrames = 300;
46 constexpr float kHighSpeechProbability = 0.7f;
47 constexpr float kSpeechLevelDbfs = -25.0f;
48
49 constexpr float kMinSample = std::numeric_limits<int16_t>::min();
50 constexpr float kMaxSample = std::numeric_limits<int16_t>::max();
51
52 using AnalogAgcConfig =
53 AudioProcessing::Config::GainController1::AnalogGainController;
54 using ClippingPredictorConfig = AudioProcessing::Config::GainController1::
55 AnalogGainController::ClippingPredictor;
56 constexpr AnalogAgcConfig kDefaultAnalogConfig{};
57
58 class MockGainControl : public GainControl {
59 public:
~MockGainControl()60 virtual ~MockGainControl() {}
61 MOCK_METHOD(int, set_stream_analog_level, (int level), (override));
62 MOCK_METHOD(int, stream_analog_level, (), (const, override));
63 MOCK_METHOD(int, set_mode, (Mode mode), (override));
64 MOCK_METHOD(Mode, mode, (), (const, override));
65 MOCK_METHOD(int, set_target_level_dbfs, (int level), (override));
66 MOCK_METHOD(int, target_level_dbfs, (), (const, override));
67 MOCK_METHOD(int, set_compression_gain_db, (int gain), (override));
68 MOCK_METHOD(int, compression_gain_db, (), (const, override));
69 MOCK_METHOD(int, enable_limiter, (bool enable), (override));
70 MOCK_METHOD(bool, is_limiter_enabled, (), (const, override));
71 MOCK_METHOD(int,
72 set_analog_level_limits,
73 (int minimum, int maximum),
74 (override));
75 MOCK_METHOD(int, analog_level_minimum, (), (const, override));
76 MOCK_METHOD(int, analog_level_maximum, (), (const, override));
77 MOCK_METHOD(bool, stream_is_saturated, (), (const, override));
78 };
79
80 // TODO(bugs.webrtc.org/12874): Remove and use designated initializers once
81 // fixed.
CreateAgcManagerDirect(int startup_min_volume,int clipped_level_step,float clipped_ratio_threshold,int clipped_wait_frames,const ClippingPredictorConfig & clipping_predictor_config=kDefaultAnalogConfig.clipping_predictor)82 std::unique_ptr<AgcManagerDirect> CreateAgcManagerDirect(
83 int startup_min_volume,
84 int clipped_level_step,
85 float clipped_ratio_threshold,
86 int clipped_wait_frames,
87 const ClippingPredictorConfig& clipping_predictor_config =
88 kDefaultAnalogConfig.clipping_predictor) {
89 AnalogAgcConfig config;
90 config.startup_min_volume = startup_min_volume;
91 config.clipped_level_min = kClippedMin;
92 config.enable_digital_adaptive = false;
93 config.clipped_level_step = clipped_level_step;
94 config.clipped_ratio_threshold = clipped_ratio_threshold;
95 config.clipped_wait_frames = clipped_wait_frames;
96 config.clipping_predictor = clipping_predictor_config;
97 return std::make_unique<AgcManagerDirect>(/*num_capture_channels=*/1, config);
98 }
99
100 // Deprecated.
101 // TODO(bugs.webrtc.org/7494): Delete this helper, use
102 // `AgcManagerDirectTestHelper::CallAgcSequence()` instead.
103 // Calls `AnalyzePreProcess()` on `manager` `num_calls` times. `peak_ratio` is a
104 // value in [0, 1] which determines the amplitude of the samples (1 maps to full
105 // scale). The first half of the calls is made on frames which are half filled
106 // with zeros in order to simulate a signal with different crest factors.
CallPreProcessAudioBuffer(int num_calls,float peak_ratio,AgcManagerDirect & manager)107 void CallPreProcessAudioBuffer(int num_calls,
108 float peak_ratio,
109 AgcManagerDirect& manager) {
110 RTC_DCHECK_LE(peak_ratio, 1.0f);
111 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
112 kNumChannels, kSampleRateHz, kNumChannels);
113 const int num_channels = audio_buffer.num_channels();
114 const int num_frames = audio_buffer.num_frames();
115
116 // Make half of the calls with half zeroed frames.
117 for (int ch = 0; ch < num_channels; ++ch) {
118 // 50% of the samples in one frame are zero.
119 for (int i = 0; i < num_frames; i += 2) {
120 audio_buffer.channels()[ch][i] = peak_ratio * 32767.0f;
121 audio_buffer.channels()[ch][i + 1] = 0.0f;
122 }
123 }
124 for (int n = 0; n < num_calls / 2; ++n) {
125 manager.AnalyzePreProcess(audio_buffer);
126 }
127
128 // Make the remaining half of the calls with frames whose samples are all set.
129 for (int ch = 0; ch < num_channels; ++ch) {
130 for (int i = 0; i < num_frames; ++i) {
131 audio_buffer.channels()[ch][i] = peak_ratio * 32767.0f;
132 }
133 }
134 for (int n = 0; n < num_calls - num_calls / 2; ++n) {
135 manager.AnalyzePreProcess(audio_buffer);
136 }
137 }
138
139 constexpr char kMinMicLevelFieldTrial[] =
140 "WebRTC-Audio-2ndAgcMinMicLevelExperiment";
141
GetAgcMinMicLevelExperimentFieldTrial(const std::string & value)142 std::string GetAgcMinMicLevelExperimentFieldTrial(const std::string& value) {
143 char field_trial_buffer[64];
144 rtc::SimpleStringBuilder builder(field_trial_buffer);
145 builder << kMinMicLevelFieldTrial << "/" << value << "/";
146 return builder.str();
147 }
148
GetAgcMinMicLevelExperimentFieldTrialEnabled(int enabled_value,const std::string & suffix="")149 std::string GetAgcMinMicLevelExperimentFieldTrialEnabled(
150 int enabled_value,
151 const std::string& suffix = "") {
152 RTC_DCHECK_GE(enabled_value, 0);
153 RTC_DCHECK_LE(enabled_value, 255);
154 char field_trial_buffer[64];
155 rtc::SimpleStringBuilder builder(field_trial_buffer);
156 builder << kMinMicLevelFieldTrial << "/Enabled-" << enabled_value << suffix
157 << "/";
158 return builder.str();
159 }
160
GetAgcMinMicLevelExperimentFieldTrial(absl::optional<int> min_mic_level)161 std::string GetAgcMinMicLevelExperimentFieldTrial(
162 absl::optional<int> min_mic_level) {
163 if (min_mic_level.has_value()) {
164 return GetAgcMinMicLevelExperimentFieldTrialEnabled(*min_mic_level);
165 }
166 return GetAgcMinMicLevelExperimentFieldTrial("Disabled");
167 }
168
169 // (Over)writes `samples_value` for the samples in `audio_buffer`.
170 // When `clipped_ratio`, a value in [0, 1], is greater than 0, the corresponding
171 // fraction of the frame is set to a full scale value to simulate clipping.
WriteAudioBufferSamples(float samples_value,float clipped_ratio,AudioBuffer & audio_buffer)172 void WriteAudioBufferSamples(float samples_value,
173 float clipped_ratio,
174 AudioBuffer& audio_buffer) {
175 RTC_DCHECK_GE(samples_value, kMinSample);
176 RTC_DCHECK_LE(samples_value, kMaxSample);
177 RTC_DCHECK_GE(clipped_ratio, 0.0f);
178 RTC_DCHECK_LE(clipped_ratio, 1.0f);
179 int num_channels = audio_buffer.num_channels();
180 int num_samples = audio_buffer.num_frames();
181 int num_clipping_samples = clipped_ratio * num_samples;
182 for (int ch = 0; ch < num_channels; ++ch) {
183 int i = 0;
184 for (; i < num_clipping_samples; ++i) {
185 audio_buffer.channels()[ch][i] = 32767.0f;
186 }
187 for (; i < num_samples; ++i) {
188 audio_buffer.channels()[ch][i] = samples_value;
189 }
190 }
191 }
192
193 // Deprecated.
194 // TODO(bugs.webrtc.org/7494): Delete this helper, use
195 // `AgcManagerDirectTestHelper::CallAgcSequence()` instead.
CallPreProcessAndProcess(int num_calls,const AudioBuffer & audio_buffer,absl::optional<float> speech_probability_override,absl::optional<float> speech_level_override,AgcManagerDirect & manager)196 void CallPreProcessAndProcess(int num_calls,
197 const AudioBuffer& audio_buffer,
198 absl::optional<float> speech_probability_override,
199 absl::optional<float> speech_level_override,
200 AgcManagerDirect& manager) {
201 for (int n = 0; n < num_calls; ++n) {
202 manager.AnalyzePreProcess(audio_buffer);
203 manager.Process(audio_buffer, speech_probability_override,
204 speech_level_override);
205 }
206 }
207
208 // Reads a given number of 10 ms chunks from a PCM file and feeds them to
209 // `AgcManagerDirect`.
210 class SpeechSamplesReader {
211 private:
212 // Recording properties.
213 static constexpr int kPcmSampleRateHz = 16000;
214 static constexpr int kPcmNumChannels = 1;
215 static constexpr int kPcmBytesPerSamples = sizeof(int16_t);
216
217 public:
SpeechSamplesReader()218 SpeechSamplesReader()
219 : is_(test::ResourcePath("audio_processing/agc/agc_audio", "pcm"),
220 std::ios::binary | std::ios::ate),
221 audio_buffer_(kPcmSampleRateHz,
222 kPcmNumChannels,
223 kPcmSampleRateHz,
224 kPcmNumChannels,
225 kPcmSampleRateHz,
226 kPcmNumChannels),
227 buffer_(audio_buffer_.num_frames()),
228 buffer_num_bytes_(buffer_.size() * kPcmBytesPerSamples) {
229 RTC_CHECK(is_);
230 }
231
232 // Reads `num_frames` 10 ms frames from the beginning of the PCM file, applies
233 // `gain_db` and feeds the frames into `agc` by calling `AnalyzePreProcess()`
234 // and `Process()` for each frame. Reads the number of 10 ms frames available
235 // in the PCM file if `num_frames` is too large - i.e., does not loop.
Feed(int num_frames,int gain_db,AgcManagerDirect & agc)236 void Feed(int num_frames, int gain_db, AgcManagerDirect& agc) {
237 float gain = std::pow(10.0f, gain_db / 20.0f); // From dB to linear gain.
238 is_.seekg(0, is_.beg); // Start from the beginning of the PCM file.
239
240 // Read and feed frames.
241 for (int i = 0; i < num_frames; ++i) {
242 is_.read(reinterpret_cast<char*>(buffer_.data()), buffer_num_bytes_);
243 if (is_.gcount() < buffer_num_bytes_) {
244 // EOF reached. Stop.
245 break;
246 }
247 // Apply gain and copy samples into `audio_buffer_`.
248 std::transform(buffer_.begin(), buffer_.end(),
249 audio_buffer_.channels()[0], [gain](int16_t v) -> float {
250 return rtc::SafeClamp(static_cast<float>(v) * gain,
251 kMinSample, kMaxSample);
252 });
253
254 agc.AnalyzePreProcess(audio_buffer_);
255 agc.Process(audio_buffer_);
256 }
257 }
258
259 // Reads `num_frames` 10 ms frames from the beginning of the PCM file, applies
260 // `gain_db` and feeds the frames into `agc` by calling `AnalyzePreProcess()`
261 // and `Process()` for each frame. Reads the number of 10 ms frames available
262 // in the PCM file if `num_frames` is too large - i.e., does not loop.
263 // `speech_probability_override` and `speech_level_override` are passed to
264 // `Process()` where they are used to override the `agc` RMS error if they
265 // have a value.
Feed(int num_frames,int gain_db,absl::optional<float> speech_probability_override,absl::optional<float> speech_level_override,AgcManagerDirect & agc)266 void Feed(int num_frames,
267 int gain_db,
268 absl::optional<float> speech_probability_override,
269 absl::optional<float> speech_level_override,
270 AgcManagerDirect& agc) {
271 float gain = std::pow(10.0f, gain_db / 20.0f); // From dB to linear gain.
272 is_.seekg(0, is_.beg); // Start from the beginning of the PCM file.
273
274 // Read and feed frames.
275 for (int i = 0; i < num_frames; ++i) {
276 is_.read(reinterpret_cast<char*>(buffer_.data()), buffer_num_bytes_);
277 if (is_.gcount() < buffer_num_bytes_) {
278 // EOF reached. Stop.
279 break;
280 }
281 // Apply gain and copy samples into `audio_buffer_`.
282 std::transform(buffer_.begin(), buffer_.end(),
283 audio_buffer_.channels()[0], [gain](int16_t v) -> float {
284 return rtc::SafeClamp(static_cast<float>(v) * gain,
285 kMinSample, kMaxSample);
286 });
287
288 agc.AnalyzePreProcess(audio_buffer_);
289 agc.Process(audio_buffer_, speech_probability_override,
290 speech_level_override);
291 }
292 }
293
294 private:
295 std::ifstream is_;
296 AudioBuffer audio_buffer_;
297 std::vector<int16_t> buffer_;
298 const std::streamsize buffer_num_bytes_;
299 };
300
301 } // namespace
302
303 // TODO(bugs.webrtc.org/12874): Use constexpr struct with designated
304 // initializers once fixed.
GetAnalogAgcTestConfig()305 constexpr AnalogAgcConfig GetAnalogAgcTestConfig() {
306 AnalogAgcConfig config;
307 config.enabled = true;
308 config.startup_min_volume = kInitialInputVolume;
309 config.clipped_level_min = kClippedMin;
310 config.enable_digital_adaptive = true;
311 config.clipped_level_step = kClippedLevelStep;
312 config.clipped_ratio_threshold = kClippedRatioThreshold;
313 config.clipped_wait_frames = kClippedWaitFrames;
314 config.clipping_predictor = kDefaultAnalogConfig.clipping_predictor;
315 return config;
316 }
317
GetDisabledAnalogAgcConfig()318 constexpr AnalogAgcConfig GetDisabledAnalogAgcConfig() {
319 AnalogAgcConfig config = GetAnalogAgcTestConfig();
320 config.enabled = false;
321 return config;
322 }
323
324 // Helper class that provides an `AgcManagerDirect` instance with an injected
325 // `Agc` mock, an `AudioBuffer` instance and `CallAgcSequence()`, a helper
326 // method that runs the `AgcManagerDirect` instance on the `AudioBuffer` one by
327 // sticking to the API contract.
328 class AgcManagerDirectTestHelper {
329 public:
330 // Ctor. Initializes `audio_buffer` with zeros.
AgcManagerDirectTestHelper()331 AgcManagerDirectTestHelper()
332 : audio_buffer(kSampleRateHz,
333 kNumChannels,
334 kSampleRateHz,
335 kNumChannels,
336 kSampleRateHz,
337 kNumChannels),
338 mock_agc(new ::testing::NiceMock<MockAgc>()),
339 manager(GetAnalogAgcTestConfig(), mock_agc) {
340 manager.Initialize();
341 manager.SetupDigitalGainControl(mock_gain_control);
342 WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipped_ratio=*/0.0f,
343 audio_buffer);
344 }
345
346 // Calls the sequence of `AgcManagerDirect` methods according to the API
347 // contract, namely:
348 // - Sets the applied input volume;
349 // - Uses `audio_buffer` to call `AnalyzePreProcess()` and `Process()`;
350 // - Sets the digital compression gain, if specified, on the injected
351 // `mock_agc`. Returns the recommended input volume. The RMS error from
352 // AGC is replaced by an override value if `speech_probability_override`
353 // and `speech_level_override` have a value.
CallAgcSequence(int applied_input_volume,absl::optional<float> speech_probability_override,absl::optional<float> speech_level_override)354 int CallAgcSequence(int applied_input_volume,
355 absl::optional<float> speech_probability_override,
356 absl::optional<float> speech_level_override) {
357 manager.set_stream_analog_level(applied_input_volume);
358 manager.AnalyzePreProcess(audio_buffer);
359 manager.Process(audio_buffer, speech_probability_override,
360 speech_level_override);
361 absl::optional<int> digital_gain = manager.GetDigitalComressionGain();
362 if (digital_gain) {
363 mock_gain_control.set_compression_gain_db(*digital_gain);
364 }
365 return manager.recommended_analog_level();
366 }
367
368 // Deprecated.
369 // TODO(bugs.webrtc.org/7494): Let the caller write `audio_buffer` and use
370 // `CallAgcSequence()`. The RMS error from AGC is replaced by an override
371 // value if `speech_probability_override` and `speech_level_override` have
372 // a value.
CallProcess(int num_calls,absl::optional<float> speech_probability_override,absl::optional<float> speech_level_override)373 void CallProcess(int num_calls,
374 absl::optional<float> speech_probability_override,
375 absl::optional<float> speech_level_override) {
376 for (int i = 0; i < num_calls; ++i) {
377 EXPECT_CALL(*mock_agc, Process(_)).WillOnce(Return());
378 manager.Process(audio_buffer, speech_probability_override,
379 speech_level_override);
380 absl::optional<int> new_digital_gain = manager.GetDigitalComressionGain();
381 if (new_digital_gain) {
382 mock_gain_control.set_compression_gain_db(*new_digital_gain);
383 }
384 }
385 }
386
387 // Deprecated.
388 // TODO(bugs.webrtc.org/7494): Let the caller write `audio_buffer` and use
389 // `CallAgcSequence()`.
CallPreProc(int num_calls,float clipped_ratio)390 void CallPreProc(int num_calls, float clipped_ratio) {
391 RTC_DCHECK_GE(clipped_ratio, 0.0f);
392 RTC_DCHECK_LE(clipped_ratio, 1.0f);
393 WriteAudioBufferSamples(/*samples_value=*/0.0f, clipped_ratio,
394 audio_buffer);
395 for (int i = 0; i < num_calls; ++i) {
396 manager.AnalyzePreProcess(audio_buffer);
397 }
398 }
399
400 // Deprecated.
401 // TODO(bugs.webrtc.org/7494): Let the caller write `audio_buffer` and use
402 // `CallAgcSequence()`.
CallPreProcForChangingAudio(int num_calls,float peak_ratio)403 void CallPreProcForChangingAudio(int num_calls, float peak_ratio) {
404 RTC_DCHECK_GE(peak_ratio, 0.0f);
405 RTC_DCHECK_LE(peak_ratio, 1.0f);
406 const float samples_value = peak_ratio * 32767.0f;
407
408 // Make half of the calls on a frame where the samples alternate
409 // `sample_values` and zeros.
410 WriteAudioBufferSamples(samples_value, /*clipped_ratio=*/0.0f,
411 audio_buffer);
412 for (size_t ch = 0; ch < audio_buffer.num_channels(); ++ch) {
413 for (size_t k = 1; k < audio_buffer.num_frames(); k += 2) {
414 audio_buffer.channels()[ch][k] = 0.0f;
415 }
416 }
417 for (int i = 0; i < num_calls / 2; ++i) {
418 manager.AnalyzePreProcess(audio_buffer);
419 }
420
421 // Make half of thecalls on a frame where all the samples equal
422 // `sample_values`.
423 WriteAudioBufferSamples(samples_value, /*clipped_ratio=*/0.0f,
424 audio_buffer);
425 for (int i = 0; i < num_calls - num_calls / 2; ++i) {
426 manager.AnalyzePreProcess(audio_buffer);
427 }
428 }
429
430 AudioBuffer audio_buffer;
431 MockAgc* mock_agc;
432 AgcManagerDirect manager;
433 MockGainControl mock_gain_control;
434 };
435
436 class AgcManagerDirectParametrizedTest
437 : public ::testing::TestWithParam<std::tuple<absl::optional<int>, bool>> {
438 protected:
AgcManagerDirectParametrizedTest()439 AgcManagerDirectParametrizedTest()
440 : field_trials_(
441 GetAgcMinMicLevelExperimentFieldTrial(std::get<0>(GetParam()))) {}
442
IsMinMicLevelOverridden() const443 bool IsMinMicLevelOverridden() const {
444 return std::get<0>(GetParam()).has_value();
445 }
GetMinMicLevel() const446 int GetMinMicLevel() const {
447 return std::get<0>(GetParam()).value_or(kMinMicLevel);
448 }
449
IsRmsErrorOverridden() const450 bool IsRmsErrorOverridden() const { return std::get<1>(GetParam()); }
GetOverrideOrEmpty(float value) const451 absl::optional<float> GetOverrideOrEmpty(float value) const {
452 return IsRmsErrorOverridden() ? absl::optional<float>(value)
453 : absl::nullopt;
454 }
455
456 private:
457 test::ScopedFieldTrials field_trials_;
458 };
459
460 INSTANTIATE_TEST_SUITE_P(
461 ,
462 AgcManagerDirectParametrizedTest,
463 ::testing::Combine(testing::Values(absl::nullopt, 12, 20),
464 testing::Bool()));
465
466 // Checks that when the analog controller is disabled, no downward adaptation
467 // takes place.
468 // TODO(webrtc:7494): Revisit the test after moving the number of override wait
469 // frames to AMP config. The test passes but internally the gain update timing
470 // differs.
TEST_P(AgcManagerDirectParametrizedTest,DisabledAnalogAgcDoesNotAdaptDownwards)471 TEST_P(AgcManagerDirectParametrizedTest,
472 DisabledAnalogAgcDoesNotAdaptDownwards) {
473 AgcManagerDirect manager_no_analog_agc(kNumChannels,
474 GetDisabledAnalogAgcConfig());
475 manager_no_analog_agc.Initialize();
476 AgcManagerDirect manager_with_analog_agc(kNumChannels,
477 GetAnalogAgcTestConfig());
478 manager_with_analog_agc.Initialize();
479
480 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
481 kNumChannels, kSampleRateHz, kNumChannels);
482
483 constexpr int kAnalogLevel = 250;
484 static_assert(kAnalogLevel > kInitialInputVolume, "Increase `kAnalogLevel`.");
485 manager_no_analog_agc.set_stream_analog_level(kAnalogLevel);
486 manager_with_analog_agc.set_stream_analog_level(kAnalogLevel);
487
488 // Make a first call with input that doesn't clip in order to let the
489 // controller read the input volume. That is needed because clipping input
490 // causes the controller to stay in idle state for
491 // `AnalogAgcConfig::clipped_wait_frames` frames.
492 WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipping_ratio=*/0.0f,
493 audio_buffer);
494 manager_no_analog_agc.AnalyzePreProcess(audio_buffer);
495 manager_with_analog_agc.AnalyzePreProcess(audio_buffer);
496 manager_no_analog_agc.Process(audio_buffer,
497 GetOverrideOrEmpty(kHighSpeechProbability),
498 GetOverrideOrEmpty(-18.0f));
499 manager_with_analog_agc.Process(audio_buffer,
500 GetOverrideOrEmpty(kHighSpeechProbability),
501 GetOverrideOrEmpty(-18.0f));
502
503 // Feed clipping input to trigger a downward adapation of the analog level.
504 WriteAudioBufferSamples(/*samples_value=*/0.0f, /*clipping_ratio=*/0.2f,
505 audio_buffer);
506 manager_no_analog_agc.AnalyzePreProcess(audio_buffer);
507 manager_with_analog_agc.AnalyzePreProcess(audio_buffer);
508 manager_no_analog_agc.Process(audio_buffer,
509 GetOverrideOrEmpty(kHighSpeechProbability),
510 GetOverrideOrEmpty(-10.0f));
511 manager_with_analog_agc.Process(audio_buffer,
512 GetOverrideOrEmpty(kHighSpeechProbability),
513 GetOverrideOrEmpty(-10.0f));
514
515 // Check that no adaptation occurs when the analog controller is disabled
516 // and make sure that the test triggers a downward adaptation otherwise.
517 EXPECT_EQ(manager_no_analog_agc.recommended_analog_level(), kAnalogLevel);
518 ASSERT_LT(manager_with_analog_agc.recommended_analog_level(), kAnalogLevel);
519 }
520
521 // Checks that when the analog controller is disabled, no upward adaptation
522 // takes place.
523 // TODO(webrtc:7494): Revisit the test after moving the number of override wait
524 // frames to APM config. The test passes but internally the gain update timing
525 // differs.
TEST_P(AgcManagerDirectParametrizedTest,DisabledAnalogAgcDoesNotAdaptUpwards)526 TEST_P(AgcManagerDirectParametrizedTest, DisabledAnalogAgcDoesNotAdaptUpwards) {
527 AgcManagerDirect manager_no_analog_agc(kNumChannels,
528 GetDisabledAnalogAgcConfig());
529 manager_no_analog_agc.Initialize();
530 AgcManagerDirect manager_with_analog_agc(kNumChannels,
531 GetAnalogAgcTestConfig());
532 manager_with_analog_agc.Initialize();
533
534 constexpr int kAnalogLevel = kInitialInputVolume;
535 manager_no_analog_agc.set_stream_analog_level(kAnalogLevel);
536 manager_with_analog_agc.set_stream_analog_level(kAnalogLevel);
537
538 // Feed speech with low energy to trigger an upward adapation of the analog
539 // level.
540 constexpr int kNumFrames = 125;
541 constexpr int kGainDb = -20;
542 SpeechSamplesReader reader;
543 reader.Feed(kNumFrames, kGainDb, GetOverrideOrEmpty(kHighSpeechProbability),
544 GetOverrideOrEmpty(-42.0f), manager_no_analog_agc);
545 reader.Feed(kNumFrames, kGainDb, GetOverrideOrEmpty(kHighSpeechProbability),
546 GetOverrideOrEmpty(-42.0f), manager_with_analog_agc);
547
548 // Check that no adaptation occurs when the analog controller is disabled
549 // and make sure that the test triggers an upward adaptation otherwise.
550 EXPECT_EQ(manager_no_analog_agc.recommended_analog_level(), kAnalogLevel);
551 ASSERT_GT(manager_with_analog_agc.recommended_analog_level(), kAnalogLevel);
552 }
553
TEST_P(AgcManagerDirectParametrizedTest,StartupMinVolumeConfigurationIsRespected)554 TEST_P(AgcManagerDirectParametrizedTest,
555 StartupMinVolumeConfigurationIsRespected) {
556 AgcManagerDirectTestHelper helper;
557 helper.CallAgcSequence(kInitialInputVolume,
558 GetOverrideOrEmpty(kHighSpeechProbability),
559 GetOverrideOrEmpty(kSpeechLevelDbfs));
560 EXPECT_EQ(kInitialInputVolume, helper.manager.recommended_analog_level());
561 }
562
TEST_P(AgcManagerDirectParametrizedTest,MicVolumeResponseToRmsError)563 TEST_P(AgcManagerDirectParametrizedTest, MicVolumeResponseToRmsError) {
564 const auto speech_probability_override =
565 GetOverrideOrEmpty(kHighSpeechProbability);
566
567 AgcManagerDirectTestHelper helper;
568 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
569 GetOverrideOrEmpty(kSpeechLevelDbfs));
570
571 // Compressor default; no residual error.
572 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
573 .WillOnce(DoAll(SetArgPointee<0>(5), Return(true)));
574 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
575 GetOverrideOrEmpty(-23.0f));
576
577 // Inside the compressor's window; no change of volume.
578 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
579 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)));
580 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
581 GetOverrideOrEmpty(-28.0f));
582
583 // Above the compressor's window; volume should be increased.
584 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
585 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
586 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
587 GetOverrideOrEmpty(-29.0f));
588 EXPECT_EQ(130, helper.manager.recommended_analog_level());
589
590 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
591 .WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
592 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
593 GetOverrideOrEmpty(-38.0f));
594 EXPECT_EQ(168, helper.manager.recommended_analog_level());
595
596 // Inside the compressor's window; no change of volume.
597 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
598 .WillOnce(DoAll(SetArgPointee<0>(5), Return(true)));
599 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
600 GetOverrideOrEmpty(-23.0f));
601 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
602 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)));
603 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
604 GetOverrideOrEmpty(-18.0f));
605
606 // Below the compressor's window; volume should be decreased.
607 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
608 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
609 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
610 GetOverrideOrEmpty(-17.0f));
611 EXPECT_EQ(167, helper.manager.recommended_analog_level());
612
613 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
614 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
615 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
616 GetOverrideOrEmpty(-17.0f));
617 EXPECT_EQ(163, helper.manager.recommended_analog_level());
618
619 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
620 .WillOnce(DoAll(SetArgPointee<0>(-9), Return(true)));
621 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
622 GetOverrideOrEmpty(-9.0f));
623 EXPECT_EQ(129, helper.manager.recommended_analog_level());
624 }
625
TEST_P(AgcManagerDirectParametrizedTest,MicVolumeIsLimited)626 TEST_P(AgcManagerDirectParametrizedTest, MicVolumeIsLimited) {
627 const auto speech_probability_override =
628 GetOverrideOrEmpty(kHighSpeechProbability);
629
630 AgcManagerDirectTestHelper helper;
631 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
632 GetOverrideOrEmpty(kSpeechLevelDbfs));
633
634 // Maximum upwards change is limited.
635 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
636 .WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
637 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
638 GetOverrideOrEmpty(-48.0f));
639 EXPECT_EQ(183, helper.manager.recommended_analog_level());
640
641 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
642 .WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
643 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
644 GetOverrideOrEmpty(-48.0f));
645 EXPECT_EQ(243, helper.manager.recommended_analog_level());
646
647 // Won't go higher than the maximum.
648 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
649 .WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
650 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
651 GetOverrideOrEmpty(-48.0f));
652 EXPECT_EQ(255, helper.manager.recommended_analog_level());
653
654 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
655 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
656 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
657 GetOverrideOrEmpty(-17.0f));
658 EXPECT_EQ(254, helper.manager.recommended_analog_level());
659
660 // Maximum downwards change is limited.
661 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
662 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
663 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
664 GetOverrideOrEmpty(22.0f));
665 EXPECT_EQ(194, helper.manager.recommended_analog_level());
666
667 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
668 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
669 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
670 GetOverrideOrEmpty(22.0f));
671 EXPECT_EQ(137, helper.manager.recommended_analog_level());
672
673 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
674 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
675 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
676 GetOverrideOrEmpty(22.0f));
677 EXPECT_EQ(88, helper.manager.recommended_analog_level());
678
679 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
680 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
681 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
682 GetOverrideOrEmpty(22.0f));
683 EXPECT_EQ(54, helper.manager.recommended_analog_level());
684
685 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
686 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
687 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
688 GetOverrideOrEmpty(22.0f));
689 EXPECT_EQ(33, helper.manager.recommended_analog_level());
690
691 // Won't go lower than the minimum.
692 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
693 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
694 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
695 GetOverrideOrEmpty(22.0f));
696 EXPECT_EQ(std::max(18, GetMinMicLevel()),
697 helper.manager.recommended_analog_level());
698
699 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
700 .WillOnce(DoAll(SetArgPointee<0>(-40), Return(true)));
701 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
702 GetOverrideOrEmpty(22.0f));
703 EXPECT_EQ(std::max(12, GetMinMicLevel()),
704 helper.manager.recommended_analog_level());
705 }
706
TEST_P(AgcManagerDirectParametrizedTest,CompressorStepsTowardsTarget)707 TEST_P(AgcManagerDirectParametrizedTest, CompressorStepsTowardsTarget) {
708 constexpr absl::optional<float> kNoOverride = absl::nullopt;
709 const auto speech_probability_override =
710 GetOverrideOrEmpty(kHighSpeechProbability);
711
712 AgcManagerDirectTestHelper helper;
713 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
714 GetOverrideOrEmpty(kSpeechLevelDbfs));
715
716 // Compressor default; no call to set_compression_gain_db.
717 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
718 .WillOnce(DoAll(SetArgPointee<0>(5), Return(true)))
719 .WillRepeatedly(Return(false));
720 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
721 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
722 GetOverrideOrEmpty(-23.0f));
723 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
724 // The mock `GetRmsErrorDb()` returns false; mimic this by passing
725 // absl::nullopt as an override.
726 helper.CallProcess(/*num_calls=*/19, kNoOverride, kNoOverride);
727
728 // Moves slowly upwards.
729 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
730 .WillOnce(DoAll(SetArgPointee<0>(9), Return(true)))
731 .WillRepeatedly(Return(false));
732 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
733 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
734 GetOverrideOrEmpty(-27.0f));
735 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
736 helper.CallProcess(/*num_calls=*/18, kNoOverride, kNoOverride);
737 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
738 .WillOnce(Return(0));
739 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
740
741 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
742 helper.CallProcess(/*num_calls=*/19, kNoOverride, kNoOverride);
743 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(9))
744 .WillOnce(Return(0));
745 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
746
747 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
748 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
749
750 // Moves slowly downward, then reverses before reaching the original target.
751 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
752 .WillOnce(DoAll(SetArgPointee<0>(5), Return(true)))
753 .WillRepeatedly(Return(false));
754 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
755 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
756 GetOverrideOrEmpty(-23.0f));
757 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
758 helper.CallProcess(/*num_calls=*/18, kNoOverride, kNoOverride);
759 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
760 .WillOnce(Return(0));
761 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
762
763 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
764 .WillOnce(DoAll(SetArgPointee<0>(9), Return(true)))
765 .WillRepeatedly(Return(false));
766 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
767 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
768 GetOverrideOrEmpty(-27.0f));
769 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
770 helper.CallProcess(/*num_calls=*/18, kNoOverride, kNoOverride);
771 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(9))
772 .WillOnce(Return(0));
773 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
774
775 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
776 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
777 }
778
TEST_P(AgcManagerDirectParametrizedTest,CompressorErrorIsDeemphasized)779 TEST_P(AgcManagerDirectParametrizedTest, CompressorErrorIsDeemphasized) {
780 constexpr absl::optional<float> kNoOverride = absl::nullopt;
781 const auto speech_probability_override =
782 GetOverrideOrEmpty(kHighSpeechProbability);
783
784 AgcManagerDirectTestHelper helper;
785 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
786 GetOverrideOrEmpty(kSpeechLevelDbfs));
787
788 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
789 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
790 .WillRepeatedly(Return(false));
791 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
792 GetOverrideOrEmpty(-28.0f));
793 // The mock `GetRmsErrorDb()` returns false; mimic this by passing
794 // absl::nullopt as an override.
795 helper.CallProcess(/*num_calls=*/18, kNoOverride, kNoOverride);
796 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
797 .WillOnce(Return(0));
798 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
799 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(9))
800 .WillOnce(Return(0));
801 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
802 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
803 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
804
805 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
806 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
807 .WillRepeatedly(Return(false));
808 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
809 GetOverrideOrEmpty(-18.0f));
810 helper.CallProcess(/*num_calls=*/18, kNoOverride, kNoOverride);
811 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
812 .WillOnce(Return(0));
813 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
814 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(7))
815 .WillOnce(Return(0));
816 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
817 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(6))
818 .WillOnce(Return(0));
819 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
820 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(_)).Times(0);
821 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
822 }
823
TEST_P(AgcManagerDirectParametrizedTest,CompressorReachesMaximum)824 TEST_P(AgcManagerDirectParametrizedTest, CompressorReachesMaximum) {
825 constexpr absl::optional<float> kNoOverride = absl::nullopt;
826 const auto speech_probability_override =
827 GetOverrideOrEmpty(kHighSpeechProbability);
828
829 AgcManagerDirectTestHelper helper;
830 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
831 GetOverrideOrEmpty(kSpeechLevelDbfs));
832
833 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
834 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
835 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
836 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
837 .WillOnce(DoAll(SetArgPointee<0>(10), Return(true)))
838 .WillRepeatedly(Return(false));
839 helper.CallProcess(/*num_calls=*/4, speech_probability_override,
840 GetOverrideOrEmpty(-28.0f));
841 // The mock `GetRmsErrorDb()` returns false; mimic this by passing
842 // absl::nullopt as an override.
843 helper.CallProcess(/*num_calls=*/15, kNoOverride, kNoOverride);
844 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
845 .WillOnce(Return(0));
846 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
847 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(9))
848 .WillOnce(Return(0));
849 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
850 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(10))
851 .WillOnce(Return(0));
852 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
853 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(11))
854 .WillOnce(Return(0));
855 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
856 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(12))
857 .WillOnce(Return(0));
858 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
859 }
860
TEST_P(AgcManagerDirectParametrizedTest,CompressorReachesMinimum)861 TEST_P(AgcManagerDirectParametrizedTest, CompressorReachesMinimum) {
862 constexpr absl::optional<float> kNoOverride = absl::nullopt;
863 const auto speech_probability_override =
864 GetOverrideOrEmpty(kHighSpeechProbability);
865
866 AgcManagerDirectTestHelper helper;
867 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
868 GetOverrideOrEmpty(kSpeechLevelDbfs));
869
870 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
871 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
872 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
873 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
874 .WillOnce(DoAll(SetArgPointee<0>(0), Return(true)))
875 .WillRepeatedly(Return(false));
876 helper.CallProcess(/*num_calls=*/4, speech_probability_override,
877 GetOverrideOrEmpty(-18.0f));
878 // The mock `GetRmsErrorDb()` returns false; mimic this by passing
879 // absl::nullopt as an override.
880 helper.CallProcess(/*num_calls=*/15, kNoOverride, kNoOverride);
881 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(6))
882 .WillOnce(Return(0));
883 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
884 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(5))
885 .WillOnce(Return(0));
886 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
887 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(4))
888 .WillOnce(Return(0));
889 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
890 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(3))
891 .WillOnce(Return(0));
892 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
893 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(2))
894 .WillOnce(Return(0));
895 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
896 }
897
TEST_P(AgcManagerDirectParametrizedTest,NoActionWhileMuted)898 TEST_P(AgcManagerDirectParametrizedTest, NoActionWhileMuted) {
899 AgcManagerDirectTestHelper helper;
900 helper.CallAgcSequence(kInitialInputVolume,
901 GetOverrideOrEmpty(kHighSpeechProbability),
902 GetOverrideOrEmpty(kSpeechLevelDbfs));
903
904 helper.manager.HandleCaptureOutputUsedChange(false);
905 helper.manager.Process(helper.audio_buffer,
906 GetOverrideOrEmpty(kHighSpeechProbability),
907 GetOverrideOrEmpty(kSpeechLevelDbfs));
908
909 absl::optional<int> new_digital_gain =
910 helper.manager.GetDigitalComressionGain();
911 if (new_digital_gain) {
912 helper.mock_gain_control.set_compression_gain_db(*new_digital_gain);
913 }
914 }
915
TEST_P(AgcManagerDirectParametrizedTest,UnmutingChecksVolumeWithoutRaising)916 TEST_P(AgcManagerDirectParametrizedTest, UnmutingChecksVolumeWithoutRaising) {
917 AgcManagerDirectTestHelper helper;
918 helper.CallAgcSequence(kInitialInputVolume,
919 GetOverrideOrEmpty(kHighSpeechProbability),
920 GetOverrideOrEmpty(kSpeechLevelDbfs));
921
922 helper.manager.HandleCaptureOutputUsedChange(false);
923 helper.manager.HandleCaptureOutputUsedChange(true);
924
925 constexpr int kInputVolume = 127;
926 helper.manager.set_stream_analog_level(kInputVolume);
927 EXPECT_CALL(*helper.mock_agc, Reset());
928
929 // SetMicVolume should not be called.
930 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_)).WillOnce(Return(false));
931 helper.CallProcess(/*num_calls=*/1,
932 GetOverrideOrEmpty(kHighSpeechProbability),
933 GetOverrideOrEmpty(kSpeechLevelDbfs));
934 EXPECT_EQ(127, helper.manager.recommended_analog_level());
935 }
936
TEST_P(AgcManagerDirectParametrizedTest,UnmutingRaisesTooLowVolume)937 TEST_P(AgcManagerDirectParametrizedTest, UnmutingRaisesTooLowVolume) {
938 AgcManagerDirectTestHelper helper;
939 helper.CallAgcSequence(kInitialInputVolume,
940 GetOverrideOrEmpty(kHighSpeechProbability),
941 GetOverrideOrEmpty(kSpeechLevelDbfs));
942
943 helper.manager.HandleCaptureOutputUsedChange(false);
944 helper.manager.HandleCaptureOutputUsedChange(true);
945
946 constexpr int kInputVolume = 11;
947 helper.manager.set_stream_analog_level(kInputVolume);
948 EXPECT_CALL(*helper.mock_agc, Reset());
949
950 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_)).WillOnce(Return(false));
951 helper.CallProcess(/*num_calls=*/1,
952 GetOverrideOrEmpty(kHighSpeechProbability),
953 GetOverrideOrEmpty(kSpeechLevelDbfs));
954 EXPECT_EQ(GetMinMicLevel(), helper.manager.recommended_analog_level());
955 }
956
TEST_P(AgcManagerDirectParametrizedTest,ManualLevelChangeResultsInNoSetMicCall)957 TEST_P(AgcManagerDirectParametrizedTest,
958 ManualLevelChangeResultsInNoSetMicCall) {
959 const auto speech_probability_override =
960 GetOverrideOrEmpty(kHighSpeechProbability);
961
962 AgcManagerDirectTestHelper helper;
963 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
964 GetOverrideOrEmpty(kSpeechLevelDbfs));
965
966 // Change outside of compressor's range, which would normally trigger a call
967 // to `SetMicVolume()`.
968 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
969 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
970
971 // When the analog volume changes, the gain controller is reset.
972 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
973
974 // GetMicVolume returns a value outside of the quantization slack, indicating
975 // a manual volume change.
976 ASSERT_NE(helper.manager.recommended_analog_level(), 154);
977 helper.manager.set_stream_analog_level(154);
978 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
979 GetOverrideOrEmpty(-29.0f));
980 EXPECT_EQ(154, helper.manager.recommended_analog_level());
981
982 // Do the same thing, except downwards now.
983 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
984 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
985 helper.manager.set_stream_analog_level(100);
986 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
987 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
988 GetOverrideOrEmpty(-17.0f));
989 EXPECT_EQ(100, helper.manager.recommended_analog_level());
990
991 // And finally verify the AGC continues working without a manual change.
992 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
993 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
994 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
995 GetOverrideOrEmpty(-17.0f));
996 EXPECT_EQ(99, helper.manager.recommended_analog_level());
997 }
998
TEST_P(AgcManagerDirectParametrizedTest,RecoveryAfterManualLevelChangeFromMax)999 TEST_P(AgcManagerDirectParametrizedTest,
1000 RecoveryAfterManualLevelChangeFromMax) {
1001 const auto speech_probability_override =
1002 GetOverrideOrEmpty(kHighSpeechProbability);
1003
1004 AgcManagerDirectTestHelper helper;
1005 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
1006 GetOverrideOrEmpty(kSpeechLevelDbfs));
1007
1008 // Force the mic up to max volume. Takes a few steps due to the residual
1009 // gain limitation.
1010 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1011 .WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
1012 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1013 GetOverrideOrEmpty(-48.0f));
1014 EXPECT_EQ(183, helper.manager.recommended_analog_level());
1015 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1016 GetOverrideOrEmpty(-48.0f));
1017 EXPECT_EQ(243, helper.manager.recommended_analog_level());
1018 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1019 GetOverrideOrEmpty(-48.0f));
1020 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1021
1022 // Manual change does not result in SetMicVolume call.
1023 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1024 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
1025 helper.manager.set_stream_analog_level(50);
1026 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1027 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1028 GetOverrideOrEmpty(-17.0f));
1029 EXPECT_EQ(50, helper.manager.recommended_analog_level());
1030
1031 // Continues working as usual afterwards.
1032 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1033 .WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
1034 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1035 GetOverrideOrEmpty(-38.0f));
1036
1037 EXPECT_EQ(69, helper.manager.recommended_analog_level());
1038 }
1039
1040 // Checks that, when the min mic level override is not specified, AGC ramps up
1041 // towards the minimum mic level after the mic level is manually set below the
1042 // minimum gain to enforce.
TEST_P(AgcManagerDirectParametrizedTest,RecoveryAfterManualLevelChangeBelowMinWithoutMiMicLevelnOverride)1043 TEST_P(AgcManagerDirectParametrizedTest,
1044 RecoveryAfterManualLevelChangeBelowMinWithoutMiMicLevelnOverride) {
1045 if (IsMinMicLevelOverridden()) {
1046 GTEST_SKIP() << "Skipped. Min mic level overridden.";
1047 }
1048
1049 const auto speech_probability_override =
1050 GetOverrideOrEmpty(kHighSpeechProbability);
1051
1052 AgcManagerDirectTestHelper helper;
1053 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
1054 GetOverrideOrEmpty(kSpeechLevelDbfs));
1055
1056 // Manual change below min, but strictly positive, otherwise AGC won't take
1057 // any action.
1058 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1059 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
1060 helper.manager.set_stream_analog_level(1);
1061 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1062 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1063 GetOverrideOrEmpty(-17.0f));
1064 EXPECT_EQ(1, helper.manager.recommended_analog_level());
1065
1066 // Continues working as usual afterwards.
1067 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1068 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)));
1069 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1070 GetOverrideOrEmpty(-29.0f));
1071 EXPECT_EQ(2, helper.manager.recommended_analog_level());
1072
1073 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1074 .WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
1075 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1076 GetOverrideOrEmpty(-48.0f));
1077 EXPECT_EQ(11, helper.manager.recommended_analog_level());
1078
1079 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1080 .WillOnce(DoAll(SetArgPointee<0>(20), Return(true)));
1081 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1082 GetOverrideOrEmpty(-38.0f));
1083 EXPECT_EQ(18, helper.manager.recommended_analog_level());
1084 }
1085
1086 // Checks that, when the min mic level override is specified, AGC immediately
1087 // applies the minimum mic level after the mic level is manually set below the
1088 // minimum gain to enforce.
TEST_P(AgcManagerDirectParametrizedTest,RecoveryAfterManualLevelChangeBelowMin)1089 TEST_P(AgcManagerDirectParametrizedTest,
1090 RecoveryAfterManualLevelChangeBelowMin) {
1091 if (!IsMinMicLevelOverridden()) {
1092 GTEST_SKIP() << "Skipped. Min mic level not overridden.";
1093 }
1094
1095 const auto speech_probability_override =
1096 GetOverrideOrEmpty(kHighSpeechProbability);
1097
1098 AgcManagerDirectTestHelper helper;
1099 helper.CallAgcSequence(kInitialInputVolume, speech_probability_override,
1100 GetOverrideOrEmpty(kSpeechLevelDbfs));
1101
1102 // Manual change below min, but strictly positive, otherwise
1103 // AGC won't take any action.
1104 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1105 .WillOnce(DoAll(SetArgPointee<0>(-1), Return(true)));
1106 helper.manager.set_stream_analog_level(1);
1107 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1108 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1109 GetOverrideOrEmpty(-17.0f));
1110 EXPECT_EQ(GetMinMicLevel(), helper.manager.recommended_analog_level());
1111 }
1112
TEST_P(AgcManagerDirectParametrizedTest,NoClippingHasNoImpact)1113 TEST_P(AgcManagerDirectParametrizedTest, NoClippingHasNoImpact) {
1114 AgcManagerDirectTestHelper helper;
1115 helper.CallAgcSequence(kInitialInputVolume,
1116 GetOverrideOrEmpty(kHighSpeechProbability),
1117 GetOverrideOrEmpty(kSpeechLevelDbfs));
1118
1119 helper.CallPreProc(/*num_calls=*/100, /*clipped_ratio=*/0);
1120 EXPECT_EQ(128, helper.manager.recommended_analog_level());
1121 }
1122
TEST_P(AgcManagerDirectParametrizedTest,ClippingUnderThresholdHasNoImpact)1123 TEST_P(AgcManagerDirectParametrizedTest, ClippingUnderThresholdHasNoImpact) {
1124 AgcManagerDirectTestHelper helper;
1125 helper.CallAgcSequence(kInitialInputVolume,
1126 GetOverrideOrEmpty(kHighSpeechProbability),
1127 GetOverrideOrEmpty(kSpeechLevelDbfs));
1128
1129 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/0.099);
1130 EXPECT_EQ(128, helper.manager.recommended_analog_level());
1131 }
1132
TEST_P(AgcManagerDirectParametrizedTest,ClippingLowersVolume)1133 TEST_P(AgcManagerDirectParametrizedTest, ClippingLowersVolume) {
1134 AgcManagerDirectTestHelper helper;
1135 helper.CallAgcSequence(/*applied_input_volume=*/255,
1136 GetOverrideOrEmpty(kHighSpeechProbability),
1137 GetOverrideOrEmpty(kSpeechLevelDbfs));
1138
1139 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1140 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/0.2);
1141 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1142 }
1143
TEST_P(AgcManagerDirectParametrizedTest,WaitingPeriodBetweenClippingChecks)1144 TEST_P(AgcManagerDirectParametrizedTest, WaitingPeriodBetweenClippingChecks) {
1145 AgcManagerDirectTestHelper helper;
1146 helper.CallAgcSequence(/*applied_input_volume=*/255,
1147 GetOverrideOrEmpty(kHighSpeechProbability),
1148 GetOverrideOrEmpty(kSpeechLevelDbfs));
1149
1150 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1151 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1152 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1153
1154 EXPECT_CALL(*helper.mock_agc, Reset()).Times(0);
1155 helper.CallPreProc(/*num_calls=*/300,
1156 /*clipped_ratio=*/kAboveClippedThreshold);
1157 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1158
1159 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1160 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1161 EXPECT_EQ(225, helper.manager.recommended_analog_level());
1162 }
1163
TEST_P(AgcManagerDirectParametrizedTest,ClippingLoweringIsLimited)1164 TEST_P(AgcManagerDirectParametrizedTest, ClippingLoweringIsLimited) {
1165 AgcManagerDirectTestHelper helper;
1166 helper.CallAgcSequence(/*applied_input_volume=*/180,
1167 GetOverrideOrEmpty(kHighSpeechProbability),
1168 GetOverrideOrEmpty(kSpeechLevelDbfs));
1169
1170 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1171 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1172 EXPECT_EQ(kClippedMin, helper.manager.recommended_analog_level());
1173
1174 EXPECT_CALL(*helper.mock_agc, Reset()).Times(0);
1175 helper.CallPreProc(/*num_calls=*/1000,
1176 /*clipped_ratio=*/kAboveClippedThreshold);
1177 EXPECT_EQ(kClippedMin, helper.manager.recommended_analog_level());
1178 }
1179
TEST_P(AgcManagerDirectParametrizedTest,ClippingMaxIsRespectedWhenEqualToLevel)1180 TEST_P(AgcManagerDirectParametrizedTest,
1181 ClippingMaxIsRespectedWhenEqualToLevel) {
1182 const auto speech_probability_override =
1183 GetOverrideOrEmpty(kHighSpeechProbability);
1184
1185 AgcManagerDirectTestHelper helper;
1186 helper.CallAgcSequence(/*applied_input_volume=*/255,
1187 speech_probability_override,
1188 GetOverrideOrEmpty(kSpeechLevelDbfs));
1189
1190 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1191 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1192 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1193
1194 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1195 .WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
1196 helper.CallProcess(/*num_calls=*/10, speech_probability_override,
1197 GetOverrideOrEmpty(-48.0f));
1198 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1199 }
1200
TEST_P(AgcManagerDirectParametrizedTest,ClippingMaxIsRespectedWhenHigherThanLevel)1201 TEST_P(AgcManagerDirectParametrizedTest,
1202 ClippingMaxIsRespectedWhenHigherThanLevel) {
1203 const auto speech_probability_override =
1204 GetOverrideOrEmpty(kHighSpeechProbability);
1205
1206 AgcManagerDirectTestHelper helper;
1207 helper.CallAgcSequence(/*applied_input_volume=*/200,
1208 speech_probability_override,
1209 GetOverrideOrEmpty(kSpeechLevelDbfs));
1210
1211 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1212 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1213 EXPECT_EQ(185, helper.manager.recommended_analog_level());
1214
1215 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1216 .WillRepeatedly(DoAll(SetArgPointee<0>(40), Return(true)));
1217 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1218 GetOverrideOrEmpty(-58.0f));
1219 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1220 helper.CallProcess(/*num_calls=*/10, speech_probability_override,
1221 GetOverrideOrEmpty(-58.0f));
1222 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1223 }
1224
TEST_P(AgcManagerDirectParametrizedTest,MaxCompressionIsIncreasedAfterClipping)1225 TEST_P(AgcManagerDirectParametrizedTest,
1226 MaxCompressionIsIncreasedAfterClipping) {
1227 constexpr absl::optional<float> kNoOverride = absl::nullopt;
1228 const auto speech_probability_override =
1229 GetOverrideOrEmpty(kHighSpeechProbability);
1230
1231 AgcManagerDirectTestHelper helper;
1232 helper.CallAgcSequence(/*applied_input_volume=*/210,
1233 speech_probability_override,
1234 GetOverrideOrEmpty(kSpeechLevelDbfs));
1235
1236 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1237 helper.CallPreProc(/*num_calls=*/1, kAboveClippedThreshold);
1238 EXPECT_EQ(195, helper.manager.recommended_analog_level());
1239
1240 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1241 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
1242 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
1243 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
1244 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
1245 .WillOnce(DoAll(SetArgPointee<0>(11), Return(true)))
1246 .WillRepeatedly(Return(false));
1247 helper.CallProcess(/*num_calls=*/5, speech_probability_override,
1248 GetOverrideOrEmpty(-29.0f));
1249 // The mock `GetRmsErrorDb()` returns false; mimic this by passing
1250 // absl::nullopt as an override.
1251 helper.CallProcess(/*num_calls=*/14, kNoOverride, kNoOverride);
1252 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(8))
1253 .WillOnce(Return(0));
1254 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1255 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(9))
1256 .WillOnce(Return(0));
1257 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1258 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(10))
1259 .WillOnce(Return(0));
1260 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1261 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(11))
1262 .WillOnce(Return(0));
1263 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1264 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(12))
1265 .WillOnce(Return(0));
1266 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1267 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(13))
1268 .WillOnce(Return(0));
1269 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
1270
1271 // Continue clipping until we hit the maximum surplus compression.
1272 helper.CallPreProc(/*num_calls=*/300,
1273 /*clipped_ratio=*/kAboveClippedThreshold);
1274 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1275 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1276 EXPECT_EQ(180, helper.manager.recommended_analog_level());
1277
1278 helper.CallPreProc(/*num_calls=*/300,
1279 /*clipped_ratio=*/kAboveClippedThreshold);
1280 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1281 helper.CallPreProc(1, kAboveClippedThreshold);
1282 EXPECT_EQ(kClippedMin, helper.manager.recommended_analog_level());
1283
1284 // Current level is now at the minimum, but the maximum allowed level still
1285 // has more to decrease.
1286 helper.CallPreProc(/*num_calls=*/300,
1287 /*clipped_ratio=*/kAboveClippedThreshold);
1288 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1289
1290 helper.CallPreProc(/*num_calls=*/300,
1291 /*clipped_ratio=*/kAboveClippedThreshold);
1292 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1293
1294 helper.CallPreProc(/*num_calls=*/300,
1295 /*clipped_ratio=*/kAboveClippedThreshold);
1296 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1297
1298 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1299 .WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
1300 .WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
1301 .WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
1302 .WillOnce(DoAll(SetArgPointee<0>(16), Return(true)))
1303 .WillRepeatedly(Return(false));
1304 helper.CallProcess(/*num_calls=*/4, speech_probability_override,
1305 GetOverrideOrEmpty(-34.0f));
1306 helper.CallProcess(/*num_calls=*/15, kNoOverride, kNoOverride);
1307 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(14))
1308 .WillOnce(Return(0));
1309 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1310 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(15))
1311 .WillOnce(Return(0));
1312 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1313 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(16))
1314 .WillOnce(Return(0));
1315 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1316 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(17))
1317 .WillOnce(Return(0));
1318 helper.CallProcess(/*num_calls=*/20, kNoOverride, kNoOverride);
1319 EXPECT_CALL(helper.mock_gain_control, set_compression_gain_db(18))
1320 .WillOnce(Return(0));
1321 helper.CallProcess(/*num_calls=*/1, kNoOverride, kNoOverride);
1322 }
1323
TEST_P(AgcManagerDirectParametrizedTest,UserCanRaiseVolumeAfterClipping)1324 TEST_P(AgcManagerDirectParametrizedTest, UserCanRaiseVolumeAfterClipping) {
1325 const auto speech_probability_override =
1326 GetOverrideOrEmpty(kHighSpeechProbability);
1327
1328 AgcManagerDirectTestHelper helper;
1329 helper.CallAgcSequence(/*applied_input_volume=*/225,
1330 speech_probability_override,
1331 GetOverrideOrEmpty(kSpeechLevelDbfs));
1332
1333 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1334 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1335 EXPECT_EQ(210, helper.manager.recommended_analog_level());
1336
1337 // High enough error to trigger a volume check.
1338 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1339 .WillOnce(DoAll(SetArgPointee<0>(14), Return(true)));
1340 // User changed the volume.
1341 helper.manager.set_stream_analog_level(250);
1342 EXPECT_CALL(*helper.mock_agc, Reset()).Times(AtLeast(1));
1343 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1344 GetOverrideOrEmpty(-32.0f));
1345 EXPECT_EQ(250, helper.manager.recommended_analog_level());
1346
1347 // Move down...
1348 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1349 .WillOnce(DoAll(SetArgPointee<0>(-10), Return(true)));
1350 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1351 GetOverrideOrEmpty(-8.0f));
1352 EXPECT_EQ(210, helper.manager.recommended_analog_level());
1353 // And back up to the new max established by the user.
1354 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1355 .WillOnce(DoAll(SetArgPointee<0>(40), Return(true)));
1356 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1357 GetOverrideOrEmpty(-58.0f));
1358 EXPECT_EQ(250, helper.manager.recommended_analog_level());
1359 // Will not move above new maximum.
1360 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1361 .WillOnce(DoAll(SetArgPointee<0>(30), Return(true)));
1362 helper.CallProcess(/*num_calls=*/1, speech_probability_override,
1363 GetOverrideOrEmpty(-48.0f));
1364 EXPECT_EQ(250, helper.manager.recommended_analog_level());
1365 }
1366
TEST_P(AgcManagerDirectParametrizedTest,ClippingDoesNotPullLowVolumeBackUp)1367 TEST_P(AgcManagerDirectParametrizedTest, ClippingDoesNotPullLowVolumeBackUp) {
1368 AgcManagerDirectTestHelper helper;
1369 helper.CallAgcSequence(/*applied_input_volume=*/80,
1370 GetOverrideOrEmpty(kHighSpeechProbability),
1371 GetOverrideOrEmpty(kSpeechLevelDbfs));
1372
1373 EXPECT_CALL(*helper.mock_agc, Reset()).Times(0);
1374 int initial_volume = helper.manager.recommended_analog_level();
1375 helper.CallPreProc(/*num_calls=*/1, /*clipped_ratio=*/kAboveClippedThreshold);
1376 EXPECT_EQ(initial_volume, helper.manager.recommended_analog_level());
1377 }
1378
TEST_P(AgcManagerDirectParametrizedTest,TakesNoActionOnZeroMicVolume)1379 TEST_P(AgcManagerDirectParametrizedTest, TakesNoActionOnZeroMicVolume) {
1380 AgcManagerDirectTestHelper helper;
1381 helper.CallAgcSequence(kInitialInputVolume,
1382 GetOverrideOrEmpty(kHighSpeechProbability),
1383 GetOverrideOrEmpty(kSpeechLevelDbfs));
1384
1385 EXPECT_CALL(*helper.mock_agc, GetRmsErrorDb(_))
1386 .WillRepeatedly(DoAll(SetArgPointee<0>(30), Return(true)));
1387 helper.manager.set_stream_analog_level(0);
1388 helper.CallProcess(/*num_calls=*/10,
1389 GetOverrideOrEmpty(kHighSpeechProbability),
1390 GetOverrideOrEmpty(-48.0f));
1391 EXPECT_EQ(0, helper.manager.recommended_analog_level());
1392 }
1393
TEST_P(AgcManagerDirectParametrizedTest,ClippingDetectionLowersVolume)1394 TEST_P(AgcManagerDirectParametrizedTest, ClippingDetectionLowersVolume) {
1395 AgcManagerDirectTestHelper helper;
1396 helper.CallAgcSequence(/*applied_input_volume=*/255,
1397 GetOverrideOrEmpty(kHighSpeechProbability),
1398 GetOverrideOrEmpty(kSpeechLevelDbfs));
1399
1400 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1401 helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f);
1402 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1403 helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/1.0f);
1404 EXPECT_EQ(240, helper.manager.recommended_analog_level());
1405 }
1406
TEST_P(AgcManagerDirectParametrizedTest,DisabledClippingPredictorDoesNotLowerVolume)1407 TEST_P(AgcManagerDirectParametrizedTest,
1408 DisabledClippingPredictorDoesNotLowerVolume) {
1409 AgcManagerDirectTestHelper helper;
1410 helper.CallAgcSequence(/*applied_input_volume=*/255,
1411 GetOverrideOrEmpty(kHighSpeechProbability),
1412 GetOverrideOrEmpty(kSpeechLevelDbfs));
1413
1414 EXPECT_FALSE(helper.manager.clipping_predictor_enabled());
1415 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1416 helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f);
1417 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1418 helper.CallPreProcForChangingAudio(/*num_calls=*/100, /*peak_ratio=*/0.99f);
1419 EXPECT_EQ(255, helper.manager.recommended_analog_level());
1420 }
1421
TEST_P(AgcManagerDirectParametrizedTest,DisableDigitalDisablesDigital)1422 TEST_P(AgcManagerDirectParametrizedTest, DisableDigitalDisablesDigital) {
1423 if (IsRmsErrorOverridden()) {
1424 GTEST_SKIP() << "Skipped. RMS error override does not affect the test.";
1425 }
1426
1427 auto agc = std::unique_ptr<Agc>(new ::testing::NiceMock<MockAgc>());
1428 MockGainControl mock_gain_control;
1429 EXPECT_CALL(mock_gain_control, set_mode(GainControl::kFixedDigital));
1430 EXPECT_CALL(mock_gain_control, set_target_level_dbfs(0));
1431 EXPECT_CALL(mock_gain_control, set_compression_gain_db(0));
1432 EXPECT_CALL(mock_gain_control, enable_limiter(false));
1433
1434 AnalogAgcConfig config;
1435 config.enable_digital_adaptive = false;
1436 auto manager = std::make_unique<AgcManagerDirect>(kNumChannels, config);
1437 manager->Initialize();
1438 manager->SetupDigitalGainControl(mock_gain_control);
1439 }
1440
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentDefault)1441 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentDefault) {
1442 std::unique_ptr<AgcManagerDirect> manager =
1443 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1444 kClippedRatioThreshold, kClippedWaitFrames);
1445 EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
1446 }
1447
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentDisabled)1448 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentDisabled) {
1449 for (const std::string& field_trial_suffix : {"", "_20220210"}) {
1450 test::ScopedFieldTrials field_trial(
1451 GetAgcMinMicLevelExperimentFieldTrial("Disabled" + field_trial_suffix));
1452 std::unique_ptr<AgcManagerDirect> manager =
1453 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1454 kClippedRatioThreshold, kClippedWaitFrames);
1455 EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
1456 }
1457 }
1458
1459 // Checks that a field-trial parameter outside of the valid range [0,255] is
1460 // ignored.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentOutOfRangeAbove)1461 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentOutOfRangeAbove) {
1462 test::ScopedFieldTrials field_trial(
1463 GetAgcMinMicLevelExperimentFieldTrial("Enabled-256"));
1464 std::unique_ptr<AgcManagerDirect> manager =
1465 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1466 kClippedRatioThreshold, kClippedWaitFrames);
1467 EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
1468 }
1469
1470 // Checks that a field-trial parameter outside of the valid range [0,255] is
1471 // ignored.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentOutOfRangeBelow)1472 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentOutOfRangeBelow) {
1473 test::ScopedFieldTrials field_trial(
1474 GetAgcMinMicLevelExperimentFieldTrial("Enabled--1"));
1475 std::unique_ptr<AgcManagerDirect> manager =
1476 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1477 kClippedRatioThreshold, kClippedWaitFrames);
1478 EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevel);
1479 }
1480
1481 // Verifies that a valid experiment changes the minimum microphone level. The
1482 // start volume is larger than the min level and should therefore not be
1483 // changed.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentEnabled50)1484 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentEnabled50) {
1485 constexpr int kMinMicLevelOverride = 50;
1486 for (const std::string& field_trial_suffix : {"", "_20220210"}) {
1487 SCOPED_TRACE(field_trial_suffix);
1488 test::ScopedFieldTrials field_trial(
1489 GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride,
1490 field_trial_suffix));
1491 std::unique_ptr<AgcManagerDirect> manager =
1492 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1493 kClippedRatioThreshold, kClippedWaitFrames);
1494 EXPECT_EQ(manager->channel_agcs_[0]->min_mic_level(), kMinMicLevelOverride);
1495 }
1496 }
1497
1498 // Checks that, when the "WebRTC-Audio-AgcMinMicLevelExperiment" field trial is
1499 // specified with a valid value, the mic level never gets lowered beyond the
1500 // override value in the presence of clipping.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentCheckMinLevelWithClipping)1501 TEST(AgcManagerDirectTest, AgcMinMicLevelExperimentCheckMinLevelWithClipping) {
1502 constexpr int kMinMicLevelOverride = 250;
1503
1504 // Create and initialize two AGCs by specifying and leaving unspecified the
1505 // relevant field trial.
1506 const auto factory = []() {
1507 std::unique_ptr<AgcManagerDirect> manager =
1508 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1509 kClippedRatioThreshold, kClippedWaitFrames);
1510 manager->Initialize();
1511 manager->set_stream_analog_level(kInitialInputVolume);
1512 return manager;
1513 };
1514 std::unique_ptr<AgcManagerDirect> manager = factory();
1515 std::unique_ptr<AgcManagerDirect> manager_with_override;
1516 {
1517 test::ScopedFieldTrials field_trial(
1518 GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride));
1519 manager_with_override = factory();
1520 }
1521
1522 // Create a test input signal which containts 80% of clipped samples.
1523 AudioBuffer audio_buffer(kSampleRateHz, 1, kSampleRateHz, 1, kSampleRateHz,
1524 1);
1525 WriteAudioBufferSamples(/*samples_value=*/4000.0f, /*clipped_ratio=*/0.8f,
1526 audio_buffer);
1527
1528 // Simulate 4 seconds of clipping; it is expected to trigger a downward
1529 // adjustment of the analog gain.
1530 CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
1531 /*speech_probability_override=*/absl::nullopt,
1532 /*speech_level_override=*/absl::nullopt, *manager);
1533 CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
1534 /*speech_probability_override=*/absl::nullopt,
1535 /*speech_level_override=*/absl::nullopt,
1536 *manager_with_override);
1537
1538 // Make sure that an adaptation occurred.
1539 ASSERT_GT(manager->recommended_analog_level(), 0);
1540
1541 // Check that the test signal triggers a larger downward adaptation for
1542 // `manager`, which is allowed to reach a lower gain.
1543 EXPECT_GT(manager_with_override->recommended_analog_level(),
1544 manager->recommended_analog_level());
1545 // Check that the gain selected by `manager_with_override` equals the minimum
1546 // value overridden via field trial.
1547 EXPECT_EQ(manager_with_override->recommended_analog_level(),
1548 kMinMicLevelOverride);
1549 }
1550
1551 // Checks that, when the "WebRTC-Audio-AgcMinMicLevelExperiment" field trial is
1552 // specified with a valid value, the mic level never gets lowered beyond the
1553 // override value in the presence of clipping when RMS error override is used.
1554 // TODO(webrtc:7494): Revisit the test after moving the number of override wait
1555 // frames to APM config. The test passes but internally the gain update timing
1556 // differs.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentCheckMinLevelWithClippingWithRmsErrorOverride)1557 TEST(AgcManagerDirectTest,
1558 AgcMinMicLevelExperimentCheckMinLevelWithClippingWithRmsErrorOverride) {
1559 constexpr int kMinMicLevelOverride = 250;
1560
1561 // Create and initialize two AGCs by specifying and leaving unspecified the
1562 // relevant field trial.
1563 const auto factory = []() {
1564 std::unique_ptr<AgcManagerDirect> manager =
1565 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1566 kClippedRatioThreshold, kClippedWaitFrames);
1567 manager->Initialize();
1568 manager->set_stream_analog_level(kInitialInputVolume);
1569 return manager;
1570 };
1571 std::unique_ptr<AgcManagerDirect> manager = factory();
1572 std::unique_ptr<AgcManagerDirect> manager_with_override;
1573 {
1574 test::ScopedFieldTrials field_trial(
1575 GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride));
1576 manager_with_override = factory();
1577 }
1578
1579 // Create a test input signal which containts 80% of clipped samples.
1580 AudioBuffer audio_buffer(kSampleRateHz, 1, kSampleRateHz, 1, kSampleRateHz,
1581 1);
1582 WriteAudioBufferSamples(/*samples_value=*/4000.0f, /*clipped_ratio=*/0.8f,
1583 audio_buffer);
1584
1585 // Simulate 4 seconds of clipping; it is expected to trigger a downward
1586 // adjustment of the analog gain.
1587 CallPreProcessAndProcess(
1588 /*num_calls=*/400, audio_buffer,
1589 /*speech_probability_override=*/0.7f,
1590 /*speech_probability_level=*/-18.0f, *manager);
1591 CallPreProcessAndProcess(
1592 /*num_calls=*/400, audio_buffer,
1593 /*speech_probability_override=*/absl::optional<float>(0.7f),
1594 /*speech_probability_level=*/absl::optional<float>(-18.0f),
1595 *manager_with_override);
1596
1597 // Make sure that an adaptation occurred.
1598 ASSERT_GT(manager->recommended_analog_level(), 0);
1599
1600 // Check that the test signal triggers a larger downward adaptation for
1601 // `manager`, which is allowed to reach a lower gain.
1602 EXPECT_GT(manager_with_override->recommended_analog_level(),
1603 manager->recommended_analog_level());
1604 // Check that the gain selected by `manager_with_override` equals the minimum
1605 // value overridden via field trial.
1606 EXPECT_EQ(manager_with_override->recommended_analog_level(),
1607 kMinMicLevelOverride);
1608 }
1609
1610 // Checks that, when the "WebRTC-Audio-AgcMinMicLevelExperiment" field trial is
1611 // specified with a value lower than the `clipped_level_min`, the behavior of
1612 // the analog gain controller is the same as that obtained when the field trial
1613 // is not specified.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentCompareMicLevelWithClipping)1614 TEST(AgcManagerDirectTest,
1615 AgcMinMicLevelExperimentCompareMicLevelWithClipping) {
1616 // Create and initialize two AGCs by specifying and leaving unspecified the
1617 // relevant field trial.
1618 const auto factory = []() {
1619 // Use a large clipped level step to more quickly decrease the analog gain
1620 // with clipping.
1621 AnalogAgcConfig config = kDefaultAnalogConfig;
1622 config.startup_min_volume = kInitialInputVolume;
1623 config.enable_digital_adaptive = false;
1624 config.clipped_level_step = 64;
1625 config.clipped_ratio_threshold = kClippedRatioThreshold;
1626 config.clipped_wait_frames = kClippedWaitFrames;
1627 auto controller =
1628 std::make_unique<AgcManagerDirect>(/*num_capture_channels=*/1, config);
1629 controller->Initialize();
1630 controller->set_stream_analog_level(kInitialInputVolume);
1631 return controller;
1632 };
1633 std::unique_ptr<AgcManagerDirect> manager = factory();
1634 std::unique_ptr<AgcManagerDirect> manager_with_override;
1635 {
1636 constexpr int kMinMicLevelOverride = 20;
1637 static_assert(
1638 kDefaultAnalogConfig.clipped_level_min >= kMinMicLevelOverride,
1639 "Use a lower override value.");
1640 test::ScopedFieldTrials field_trial(
1641 GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride));
1642 manager_with_override = factory();
1643 }
1644
1645 // Create a test input signal which containts 80% of clipped samples.
1646 AudioBuffer audio_buffer(kSampleRateHz, 1, kSampleRateHz, 1, kSampleRateHz,
1647 1);
1648 WriteAudioBufferSamples(/*samples_value=*/4000.0f, /*clipped_ratio=*/0.8f,
1649 audio_buffer);
1650
1651 // Simulate 4 seconds of clipping; it is expected to trigger a downward
1652 // adjustment of the analog gain.
1653 CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
1654 /*speech_probability_override=*/absl::nullopt,
1655 /*speech_level_override=*/absl::nullopt, *manager);
1656 CallPreProcessAndProcess(/*num_calls=*/400, audio_buffer,
1657 /*speech_probability_override=*/absl::nullopt,
1658 /*speech_level_override=*/absl::nullopt,
1659 *manager_with_override);
1660
1661 // Make sure that an adaptation occurred.
1662 ASSERT_GT(manager->recommended_analog_level(), 0);
1663
1664 // Check that the selected analog gain is the same for both controllers and
1665 // that it equals the minimum level reached when clipping is handled. That is
1666 // expected because the minimum microphone level override is less than the
1667 // minimum level used when clipping is detected.
1668 EXPECT_EQ(manager->recommended_analog_level(),
1669 manager_with_override->recommended_analog_level());
1670 EXPECT_EQ(manager_with_override->recommended_analog_level(),
1671 kDefaultAnalogConfig.clipped_level_min);
1672 }
1673
1674 // Checks that, when the "WebRTC-Audio-AgcMinMicLevelExperiment" field trial is
1675 // specified with a value lower than the `clipped_level_min`, the behavior of
1676 // the analog gain controller is the same as that obtained when the field trial
1677 // is not specified.
1678 // TODO(webrtc:7494): Revisit the test after moving the number of override wait
1679 // frames to APM config. The test passes but internally the gain update timing
1680 // differs.
TEST(AgcManagerDirectTest,AgcMinMicLevelExperimentCompareMicLevelWithClippingWithRmsErrorOverride)1681 TEST(AgcManagerDirectTest,
1682 AgcMinMicLevelExperimentCompareMicLevelWithClippingWithRmsErrorOverride) {
1683 // Create and initialize two AGCs by specifying and leaving unspecified the
1684 // relevant field trial.
1685 const auto factory = []() {
1686 // Use a large clipped level step to more quickly decrease the analog gain
1687 // with clipping.
1688 AnalogAgcConfig config = kDefaultAnalogConfig;
1689 config.startup_min_volume = kInitialInputVolume;
1690 config.enable_digital_adaptive = false;
1691 config.clipped_level_step = 64;
1692 config.clipped_ratio_threshold = kClippedRatioThreshold;
1693 config.clipped_wait_frames = kClippedWaitFrames;
1694 auto controller =
1695 std::make_unique<AgcManagerDirect>(/*num_capture_channels=*/1, config);
1696 controller->Initialize();
1697 controller->set_stream_analog_level(kInitialInputVolume);
1698 return controller;
1699 };
1700 std::unique_ptr<AgcManagerDirect> manager = factory();
1701 std::unique_ptr<AgcManagerDirect> manager_with_override;
1702 {
1703 constexpr int kMinMicLevelOverride = 20;
1704 static_assert(
1705 kDefaultAnalogConfig.clipped_level_min >= kMinMicLevelOverride,
1706 "Use a lower override value.");
1707 test::ScopedFieldTrials field_trial(
1708 GetAgcMinMicLevelExperimentFieldTrialEnabled(kMinMicLevelOverride));
1709 manager_with_override = factory();
1710 }
1711
1712 // Create a test input signal which containts 80% of clipped samples.
1713 AudioBuffer audio_buffer(kSampleRateHz, 1, kSampleRateHz, 1, kSampleRateHz,
1714 1);
1715 WriteAudioBufferSamples(/*samples_value=*/4000.0f, /*clipped_ratio=*/0.8f,
1716 audio_buffer);
1717
1718 CallPreProcessAndProcess(
1719 /*num_calls=*/400, audio_buffer,
1720 /*speech_probability_override=*/absl::optional<float>(0.7f),
1721 /*speech_level_override=*/absl::optional<float>(-18.0f), *manager);
1722 CallPreProcessAndProcess(
1723 /*num_calls=*/400, audio_buffer,
1724 /*speech_probability_override=*/absl::optional<float>(0.7f),
1725 /*speech_level_override=*/absl::optional<float>(-18.0f),
1726 *manager_with_override);
1727
1728 // Make sure that an adaptation occurred.
1729 ASSERT_GT(manager->recommended_analog_level(), 0);
1730
1731 // Check that the selected analog gain is the same for both controllers and
1732 // that it equals the minimum level reached when clipping is handled. That is
1733 // expected because the minimum microphone level override is less than the
1734 // minimum level used when clipping is detected.
1735 EXPECT_EQ(manager->recommended_analog_level(),
1736 manager_with_override->recommended_analog_level());
1737 EXPECT_EQ(manager_with_override->recommended_analog_level(),
1738 kDefaultAnalogConfig.clipped_level_min);
1739 }
1740
1741 // TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_level_step`.
1742 // TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_ratio_threshold`.
1743 // TODO(bugs.webrtc.org/12774): Test the bahavior of `clipped_wait_frames`.
1744 // Verifies that configurable clipping parameters are initialized as intended.
TEST_P(AgcManagerDirectParametrizedTest,ClippingParametersVerified)1745 TEST_P(AgcManagerDirectParametrizedTest, ClippingParametersVerified) {
1746 if (IsRmsErrorOverridden()) {
1747 GTEST_SKIP() << "Skipped. RMS error override does not affect the test.";
1748 }
1749
1750 std::unique_ptr<AgcManagerDirect> manager =
1751 CreateAgcManagerDirect(kInitialInputVolume, kClippedLevelStep,
1752 kClippedRatioThreshold, kClippedWaitFrames);
1753 manager->Initialize();
1754 EXPECT_EQ(manager->clipped_level_step_, kClippedLevelStep);
1755 EXPECT_EQ(manager->clipped_ratio_threshold_, kClippedRatioThreshold);
1756 EXPECT_EQ(manager->clipped_wait_frames_, kClippedWaitFrames);
1757 std::unique_ptr<AgcManagerDirect> manager_custom =
1758 CreateAgcManagerDirect(kInitialInputVolume,
1759 /*clipped_level_step=*/10,
1760 /*clipped_ratio_threshold=*/0.2f,
1761 /*clipped_wait_frames=*/50);
1762 manager_custom->Initialize();
1763 EXPECT_EQ(manager_custom->clipped_level_step_, 10);
1764 EXPECT_EQ(manager_custom->clipped_ratio_threshold_, 0.2f);
1765 EXPECT_EQ(manager_custom->clipped_wait_frames_, 50);
1766 }
1767
TEST_P(AgcManagerDirectParametrizedTest,DisableClippingPredictorDisablesClippingPredictor)1768 TEST_P(AgcManagerDirectParametrizedTest,
1769 DisableClippingPredictorDisablesClippingPredictor) {
1770 if (IsRmsErrorOverridden()) {
1771 GTEST_SKIP() << "Skipped. RMS error override does not affect the test.";
1772 }
1773
1774 // TODO(bugs.webrtc.org/12874): Use designated initializers once fixed.
1775 ClippingPredictorConfig config;
1776 config.enabled = false;
1777
1778 std::unique_ptr<AgcManagerDirect> manager = CreateAgcManagerDirect(
1779 kInitialInputVolume, kClippedLevelStep, kClippedRatioThreshold,
1780 kClippedWaitFrames, config);
1781 manager->Initialize();
1782 EXPECT_FALSE(manager->clipping_predictor_enabled());
1783 EXPECT_FALSE(manager->use_clipping_predictor_step());
1784 }
1785
TEST_P(AgcManagerDirectParametrizedTest,ClippingPredictorDisabledByDefault)1786 TEST_P(AgcManagerDirectParametrizedTest, ClippingPredictorDisabledByDefault) {
1787 if (IsRmsErrorOverridden()) {
1788 GTEST_SKIP() << "Skipped. RMS error override does not affect the test.";
1789 }
1790
1791 constexpr ClippingPredictorConfig kDefaultConfig;
1792 EXPECT_FALSE(kDefaultConfig.enabled);
1793 }
1794
TEST_P(AgcManagerDirectParametrizedTest,EnableClippingPredictorEnablesClippingPredictor)1795 TEST_P(AgcManagerDirectParametrizedTest,
1796 EnableClippingPredictorEnablesClippingPredictor) {
1797 if (IsRmsErrorOverridden()) {
1798 GTEST_SKIP() << "Skipped. RMS error override does not affect the test.";
1799 }
1800
1801 // TODO(bugs.webrtc.org/12874): Use designated initializers once fixed.
1802 ClippingPredictorConfig config;
1803 config.enabled = true;
1804 config.use_predicted_step = true;
1805
1806 std::unique_ptr<AgcManagerDirect> manager = CreateAgcManagerDirect(
1807 kInitialInputVolume, kClippedLevelStep, kClippedRatioThreshold,
1808 kClippedWaitFrames, config);
1809 manager->Initialize();
1810 EXPECT_TRUE(manager->clipping_predictor_enabled());
1811 EXPECT_TRUE(manager->use_clipping_predictor_step());
1812 }
1813
TEST_P(AgcManagerDirectParametrizedTest,DisableClippingPredictorDoesNotLowerVolume)1814 TEST_P(AgcManagerDirectParametrizedTest,
1815 DisableClippingPredictorDoesNotLowerVolume) {
1816 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
1817 kNumChannels, kSampleRateHz, kNumChannels);
1818
1819 AnalogAgcConfig config = GetAnalogAgcTestConfig();
1820 config.clipping_predictor.enabled = false;
1821 AgcManagerDirect manager(config, new ::testing::NiceMock<MockAgc>());
1822 manager.Initialize();
1823 manager.set_stream_analog_level(/*level=*/255);
1824 EXPECT_FALSE(manager.clipping_predictor_enabled());
1825 EXPECT_FALSE(manager.use_clipping_predictor_step());
1826 EXPECT_EQ(manager.recommended_analog_level(), 255);
1827 manager.Process(audio_buffer, GetOverrideOrEmpty(kHighSpeechProbability),
1828 GetOverrideOrEmpty(kSpeechLevelDbfs));
1829 CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager);
1830 EXPECT_EQ(manager.recommended_analog_level(), 255);
1831 CallPreProcessAudioBuffer(/*num_calls=*/300, /*peak_ratio=*/0.99f, manager);
1832 EXPECT_EQ(manager.recommended_analog_level(), 255);
1833 CallPreProcessAudioBuffer(/*num_calls=*/10, /*peak_ratio=*/0.99f, manager);
1834 EXPECT_EQ(manager.recommended_analog_level(), 255);
1835 }
1836
TEST_P(AgcManagerDirectParametrizedTest,UsedClippingPredictionsProduceLowerAnalogLevels)1837 TEST_P(AgcManagerDirectParametrizedTest,
1838 UsedClippingPredictionsProduceLowerAnalogLevels) {
1839 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
1840 kNumChannels, kSampleRateHz, kNumChannels);
1841
1842 AnalogAgcConfig config_with_prediction = GetAnalogAgcTestConfig();
1843 config_with_prediction.clipping_predictor.enabled = true;
1844 config_with_prediction.clipping_predictor.use_predicted_step = true;
1845 AnalogAgcConfig config_without_prediction = GetAnalogAgcTestConfig();
1846 config_without_prediction.clipping_predictor.enabled = false;
1847 AgcManagerDirect manager_with_prediction(config_with_prediction,
1848 new ::testing::NiceMock<MockAgc>());
1849 AgcManagerDirect manager_without_prediction(
1850 config_without_prediction, new ::testing::NiceMock<MockAgc>());
1851
1852 manager_with_prediction.Initialize();
1853 manager_without_prediction.Initialize();
1854
1855 constexpr int kInitialLevel = 255;
1856 constexpr float kClippingPeakRatio = 1.0f;
1857 constexpr float kCloseToClippingPeakRatio = 0.99f;
1858 constexpr float kZeroPeakRatio = 0.0f;
1859 manager_with_prediction.set_stream_analog_level(kInitialLevel);
1860 manager_without_prediction.set_stream_analog_level(kInitialLevel);
1861 manager_with_prediction.Process(audio_buffer,
1862 GetOverrideOrEmpty(kHighSpeechProbability),
1863 GetOverrideOrEmpty(kSpeechLevelDbfs));
1864 manager_without_prediction.Process(audio_buffer,
1865 GetOverrideOrEmpty(kHighSpeechProbability),
1866 GetOverrideOrEmpty(kSpeechLevelDbfs));
1867 EXPECT_TRUE(manager_with_prediction.clipping_predictor_enabled());
1868 EXPECT_FALSE(manager_without_prediction.clipping_predictor_enabled());
1869 EXPECT_TRUE(manager_with_prediction.use_clipping_predictor_step());
1870 EXPECT_EQ(manager_with_prediction.recommended_analog_level(), kInitialLevel);
1871 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1872 kInitialLevel);
1873
1874 // Expect a change in the analog level when the prediction step is used.
1875 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1876 manager_with_prediction);
1877 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1878 manager_without_prediction);
1879 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1880 kInitialLevel - kClippedLevelStep);
1881 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1882 kInitialLevel);
1883
1884 // Expect no change during waiting.
1885 CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio,
1886 manager_with_prediction);
1887 CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio,
1888 manager_without_prediction);
1889 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1890 kInitialLevel - kClippedLevelStep);
1891 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1892 kInitialLevel);
1893
1894 // Expect a change when the prediction step is used.
1895 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1896 manager_with_prediction);
1897 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1898 manager_without_prediction);
1899 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1900 kInitialLevel - 2 * kClippedLevelStep);
1901 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1902 kInitialLevel);
1903
1904 // Expect no change when clipping is not detected or predicted.
1905 CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio,
1906 manager_with_prediction);
1907 CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio,
1908 manager_without_prediction);
1909 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1910 kInitialLevel - 2 * kClippedLevelStep);
1911 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1912 kInitialLevel);
1913
1914 // Expect a change for clipping frames.
1915 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
1916 manager_with_prediction);
1917 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
1918 manager_without_prediction);
1919 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1920 kInitialLevel - 3 * kClippedLevelStep);
1921 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1922 kInitialLevel - kClippedLevelStep);
1923
1924 // Expect no change during waiting.
1925 CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio,
1926 manager_with_prediction);
1927 CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio,
1928 manager_without_prediction);
1929 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1930 kInitialLevel - 3 * kClippedLevelStep);
1931 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1932 kInitialLevel - kClippedLevelStep);
1933
1934 // Expect a change for clipping frames.
1935 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
1936 manager_with_prediction);
1937 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
1938 manager_without_prediction);
1939 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1940 kInitialLevel - 4 * kClippedLevelStep);
1941 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1942 kInitialLevel - 2 * kClippedLevelStep);
1943 }
1944
TEST_P(AgcManagerDirectParametrizedTest,UnusedClippingPredictionsProduceEqualAnalogLevels)1945 TEST_P(AgcManagerDirectParametrizedTest,
1946 UnusedClippingPredictionsProduceEqualAnalogLevels) {
1947 AudioBuffer audio_buffer(kSampleRateHz, kNumChannels, kSampleRateHz,
1948 kNumChannels, kSampleRateHz, kNumChannels);
1949
1950 AnalogAgcConfig config_with_prediction = GetAnalogAgcTestConfig();
1951 config_with_prediction.clipping_predictor.enabled = true;
1952 config_with_prediction.clipping_predictor.use_predicted_step = false;
1953 AnalogAgcConfig config_without_prediction = GetAnalogAgcTestConfig();
1954 config_without_prediction.clipping_predictor.enabled = false;
1955 AgcManagerDirect manager_with_prediction(config_with_prediction,
1956 new ::testing::NiceMock<MockAgc>());
1957 AgcManagerDirect manager_without_prediction(
1958 config_without_prediction, new ::testing::NiceMock<MockAgc>());
1959
1960 constexpr int kInitialLevel = 255;
1961 constexpr float kClippingPeakRatio = 1.0f;
1962 constexpr float kCloseToClippingPeakRatio = 0.99f;
1963 constexpr float kZeroPeakRatio = 0.0f;
1964 manager_with_prediction.Initialize();
1965 manager_without_prediction.Initialize();
1966 manager_with_prediction.set_stream_analog_level(kInitialLevel);
1967 manager_without_prediction.set_stream_analog_level(kInitialLevel);
1968 manager_with_prediction.Process(audio_buffer,
1969 GetOverrideOrEmpty(kHighSpeechProbability),
1970 GetOverrideOrEmpty(kSpeechLevelDbfs));
1971 manager_without_prediction.Process(audio_buffer,
1972 GetOverrideOrEmpty(kHighSpeechProbability),
1973 GetOverrideOrEmpty(kSpeechLevelDbfs));
1974
1975 EXPECT_TRUE(manager_with_prediction.clipping_predictor_enabled());
1976 EXPECT_FALSE(manager_without_prediction.clipping_predictor_enabled());
1977 EXPECT_FALSE(manager_with_prediction.use_clipping_predictor_step());
1978 EXPECT_EQ(manager_with_prediction.recommended_analog_level(), kInitialLevel);
1979 EXPECT_EQ(manager_without_prediction.recommended_analog_level(),
1980 kInitialLevel);
1981
1982 // Expect no change in the analog level for non-clipping frames.
1983 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1984 manager_with_prediction);
1985 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
1986 manager_without_prediction);
1987 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1988 manager_without_prediction.recommended_analog_level());
1989
1990 // Expect no change for non-clipping frames.
1991 CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio,
1992 manager_with_prediction);
1993 CallPreProcessAudioBuffer(kClippedWaitFrames, kCloseToClippingPeakRatio,
1994 manager_without_prediction);
1995 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
1996 manager_without_prediction.recommended_analog_level());
1997
1998 // Expect no change for non-clipping frames.
1999 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
2000 manager_with_prediction);
2001 CallPreProcessAudioBuffer(/*num_calls=*/10, kCloseToClippingPeakRatio,
2002 manager_without_prediction);
2003 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
2004 manager_without_prediction.recommended_analog_level());
2005
2006 // Expect no change when clipping is not detected or predicted.
2007 CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio,
2008 manager_with_prediction);
2009 CallPreProcessAudioBuffer(2 * kClippedWaitFrames, kZeroPeakRatio,
2010 manager_without_prediction);
2011 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
2012 manager_without_prediction.recommended_analog_level());
2013
2014 // Expect a change for clipping frames.
2015 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
2016 manager_with_prediction);
2017 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
2018 manager_without_prediction);
2019 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
2020 manager_without_prediction.recommended_analog_level());
2021
2022 // Expect no change during waiting.
2023 CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio,
2024 manager_with_prediction);
2025 CallPreProcessAudioBuffer(kClippedWaitFrames, kClippingPeakRatio,
2026 manager_without_prediction);
2027 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
2028 manager_without_prediction.recommended_analog_level());
2029
2030 // Expect a change for clipping frames.
2031 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
2032 manager_with_prediction);
2033 CallPreProcessAudioBuffer(/*num_calls=*/1, kClippingPeakRatio,
2034 manager_without_prediction);
2035 EXPECT_EQ(manager_with_prediction.recommended_analog_level(),
2036 manager_without_prediction.recommended_analog_level());
2037 }
2038
2039 // Checks that passing an empty speech level and probability overrides to
2040 // `Process()` has the same effect as passing no overrides.
TEST_P(AgcManagerDirectParametrizedTest,EmptyRmsErrorOverrideHasNoEffect)2041 TEST_P(AgcManagerDirectParametrizedTest, EmptyRmsErrorOverrideHasNoEffect) {
2042 AgcManagerDirect manager_1(kNumChannels, GetAnalogAgcTestConfig());
2043 AgcManagerDirect manager_2(kNumChannels, GetAnalogAgcTestConfig());
2044 manager_1.Initialize();
2045 manager_2.Initialize();
2046
2047 constexpr int kAnalogLevel = 50;
2048 manager_1.set_stream_analog_level(kAnalogLevel);
2049 manager_2.set_stream_analog_level(kAnalogLevel);
2050
2051 // Feed speech with low energy to trigger an upward adapation of the analog
2052 // level.
2053 constexpr int kNumFrames = 125;
2054 constexpr int kGainDb = -20;
2055 SpeechSamplesReader reader;
2056
2057 // Check the initial input volume.
2058 ASSERT_EQ(manager_1.recommended_analog_level(), kAnalogLevel);
2059 ASSERT_EQ(manager_2.recommended_analog_level(), kAnalogLevel);
2060
2061 reader.Feed(kNumFrames, kGainDb, absl::nullopt, absl::nullopt, manager_1);
2062 reader.Feed(kNumFrames, kGainDb, manager_2);
2063
2064 // Check that the states are the same and adaptation occurs.
2065 EXPECT_EQ(manager_1.recommended_analog_level(),
2066 manager_2.recommended_analog_level());
2067 ASSERT_GT(manager_1.recommended_analog_level(), kAnalogLevel);
2068 EXPECT_EQ(manager_1.voice_probability(), manager_2.voice_probability());
2069 EXPECT_EQ(manager_1.frames_since_clipped_, manager_2.frames_since_clipped_);
2070
2071 // Check that the states of the channel AGCs are the same.
2072 EXPECT_EQ(manager_1.num_channels(), manager_2.num_channels());
2073 for (int i = 0; i < manager_1.num_channels(); ++i) {
2074 EXPECT_EQ(manager_1.channel_agcs_[i]->recommended_analog_level(),
2075 manager_2.channel_agcs_[i]->recommended_analog_level());
2076 EXPECT_EQ(manager_1.channel_agcs_[i]->voice_probability(),
2077 manager_2.channel_agcs_[i]->voice_probability());
2078 }
2079 }
2080
2081 // Checks that passing a non-empty speech level and probability overrides to
2082 // `Process()` has an effect.
TEST_P(AgcManagerDirectParametrizedTest,NonEmptyRmsErrorOverrideHasEffect)2083 TEST_P(AgcManagerDirectParametrizedTest, NonEmptyRmsErrorOverrideHasEffect) {
2084 AgcManagerDirect manager_1(kNumChannels, GetAnalogAgcTestConfig());
2085 AgcManagerDirect manager_2(kNumChannels, GetAnalogAgcTestConfig());
2086 manager_1.Initialize();
2087 manager_2.Initialize();
2088
2089 constexpr int kInputVolume = 128;
2090 manager_1.set_stream_analog_level(kInputVolume);
2091 manager_2.set_stream_analog_level(kInputVolume);
2092
2093 // Feed speech with low energy to trigger an upward adapation of the input
2094 // volume.
2095 constexpr int kNumFrames = 125;
2096 constexpr int kGainDb = -20;
2097 SpeechSamplesReader reader;
2098
2099 // Make sure that the feeding samples triggers an adaptation when no override
2100 // is specified.
2101 reader.Feed(kNumFrames, kGainDb, manager_1);
2102 ASSERT_GT(manager_1.recommended_analog_level(), kInputVolume);
2103
2104 // Expect that feeding samples triggers an adaptation when the speech
2105 // probability and speech level overrides are specified.
2106 reader.Feed(kNumFrames, kGainDb,
2107 /*speech_probability_override=*/kHighSpeechProbability,
2108 /*speech_level_override=*/-45.0f, manager_2);
2109 EXPECT_GT(manager_2.recommended_analog_level(), kInputVolume);
2110
2111 // The voice probability override does not affect the `voice_probability()`
2112 // getter.
2113 EXPECT_EQ(manager_1.voice_probability(), manager_2.voice_probability());
2114 }
2115
2116 } // namespace webrtc
2117