blob: e48a5d88837f573faff3684c37de439211af28e6 [file] [log] [blame]
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001/*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_processing/audio_processing_impl.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000012
Alessio Bazzica3b51cd32022-12-14 16:36:10 +010013#include <algorithm>
Per Åhgren2507f8c2020-03-19 12:33:29 +010014#include <array>
Alessio Bazzicae4498052018-12-17 09:44:06 +010015#include <memory>
Hanna Silenc69188d2022-09-16 11:38:56 +020016#include <tuple>
Alessio Bazzicae4498052018-12-17 09:44:06 +010017
Hanna Silenc69188d2022-09-16 11:38:56 +020018#include "absl/types/optional.h"
Niels Möller105711e2022-06-14 15:48:26 +020019#include "api/make_ref_counted.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010020#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 14:23:11 +020021#include "modules/audio_processing/include/audio_processing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020022#include "modules/audio_processing/optionally_built_submodule_creators.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020023#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020024#include "modules/audio_processing/test/echo_canceller_test_tools.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010025#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010027#include "rtc_base/checks.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020028#include "rtc_base/random.h"
Hanna Silenc69188d2022-09-16 11:38:56 +020029#include "rtc_base/strings/string_builder.h"
Hanna Silen0c1ad292022-06-16 16:35:45 +020030#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020031#include "test/gmock.h"
32#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000033
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000034namespace webrtc {
peaha9cc40b2017-06-29 08:32:09 -070035namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000036
Alessio Bazzicae4498052018-12-17 09:44:06 +010037using ::testing::Invoke;
38using ::testing::NotNull;
39
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000040class MockInitialize : public AudioProcessingImpl {
41 public:
Alessio Bazzicabe1b8982021-09-17 08:26:10 +020042 MockInitialize() : AudioProcessingImpl() {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000043
Per Åhgren0ade9832020-09-01 23:57:20 +020044 MOCK_METHOD(void, InitializeLocked, (), (override));
Niels Möller5b747232021-07-26 17:16:25 +020045 void RealInitializeLocked() {
46 AssertLockedForTest();
Per Åhgren0ade9832020-09-01 23:57:20 +020047 AudioProcessingImpl::InitializeLocked();
pbos@webrtc.org788acd12014-12-15 09:41:24 +000048 }
peaha9cc40b2017-06-29 08:32:09 -070049
Danil Chapovalov704fb552020-05-18 15:10:15 +020050 MOCK_METHOD(void, AddRef, (), (const, override));
51 MOCK_METHOD(rtc::RefCountReleaseStatus, Release, (), (const, override));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000052};
53
Alessio Bazzicae4498052018-12-17 09:44:06 +010054// Creates MockEchoControl instances and provides a raw pointer access to
55// the next created one. The raw pointer is meant to be used with gmock.
56// Returning a pointer of the next created MockEchoControl instance is necessary
57// for the following reasons: (i) gmock expectations must be set before any call
58// occurs, (ii) APM is initialized the first time that
59// AudioProcessingImpl::ProcessStream() is called and the initialization leads
60// to the creation of a new EchoControl object.
61class MockEchoControlFactory : public EchoControlFactory {
62 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020063 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010064 // Returns a pointer to the next MockEchoControl that this factory creates.
65 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010066 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
67 int num_render_channels,
68 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010069 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020070 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010071 return mock;
72 }
73
74 private:
75 std::unique_ptr<MockEchoControl> next_mock_;
76};
77
Alessio Bazzicad2b97402018-08-09 14:23:11 +020078// Mocks EchoDetector and records the first samples of the last analyzed render
79// stream frame. Used to check what data is read by an EchoDetector
80// implementation injected into an APM.
81class TestEchoDetector : public EchoDetector {
82 public:
83 TestEchoDetector()
84 : analyze_render_audio_called_(false),
85 last_render_audio_first_sample_(0.f) {}
86 ~TestEchoDetector() override = default;
87 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
88 last_render_audio_first_sample_ = render_audio[0];
89 analyze_render_audio_called_ = true;
90 }
91 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
92 }
93 void Initialize(int capture_sample_rate_hz,
94 int num_capture_channels,
95 int render_sample_rate_hz,
96 int num_render_channels) override {}
97 EchoDetector::Metrics GetMetrics() const override { return {}; }
98 // Returns true if AnalyzeRenderAudio() has been called at least once.
99 bool analyze_render_audio_called() const {
100 return analyze_render_audio_called_;
101 }
102 // Returns the first sample of the last analyzed render frame.
103 float last_render_audio_first_sample() const {
104 return last_render_audio_first_sample_;
105 }
106
107 private:
108 bool analyze_render_audio_called_;
109 float last_render_audio_first_sample_;
110};
111
112// Mocks CustomProcessing and applies ProcessSample() to all the samples.
113// Meant to be injected into an APM to modify samples in a known and detectable
114// way.
115class TestRenderPreProcessor : public CustomProcessing {
116 public:
117 TestRenderPreProcessor() = default;
118 ~TestRenderPreProcessor() = default;
119 void Initialize(int sample_rate_hz, int num_channels) override {}
120 void Process(AudioBuffer* audio) override {
121 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200122 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200123 audio->num_frames());
124 std::transform(channel_view.begin(), channel_view.end(),
125 channel_view.begin(), ProcessSample);
126 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100127 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200128 std::string ToString() const override { return "TestRenderPreProcessor"; }
129 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
130 // Modifies a sample. This member is used in Process() to modify a frame and
131 // it is publicly visible to enable tests.
132 static constexpr float ProcessSample(float x) { return 2.f * x; }
133};
134
Hanna Silenc69188d2022-09-16 11:38:56 +0200135// Runs `apm` input processing for volume adjustments for `num_frames` random
136// frames starting from the volume `initial_volume`. This includes three steps:
137// 1) Set the input volume 2) Process the stream 3) Set the new recommended
138// input volume. Returns the new recommended input volume.
139int ProcessInputVolume(AudioProcessing& apm,
140 int num_frames,
141 int initial_volume) {
142 constexpr int kSampleRateHz = 48000;
143 constexpr int kNumChannels = 1;
144 std::array<float, kSampleRateHz / 100> buffer;
145 float* channel_pointers[] = {buffer.data()};
146 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
147 /*num_channels=*/kNumChannels);
148 int recommended_input_volume = initial_volume;
149 for (int i = 0; i < num_frames; ++i) {
150 Random random_generator(2341U);
151 RandomizeSampleVector(&random_generator, buffer);
152
153 apm.set_stream_analog_level(recommended_input_volume);
154 apm.ProcessStream(channel_pointers, stream_config, stream_config,
155 channel_pointers);
156 recommended_input_volume = apm.recommended_stream_analog_level();
157 }
158 return recommended_input_volume;
159}
160
peaha9cc40b2017-06-29 08:32:09 -0700161} // namespace
162
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000163TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200164 MockInitialize mock;
165 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000166 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
167
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200168 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000169 mock.Initialize();
170
Per Åhgren2507f8c2020-03-19 12:33:29 +0100171 constexpr size_t kMaxSampleRateHz = 32000;
172 constexpr size_t kMaxNumChannels = 2;
173 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
174 frame.fill(0);
Henrik Lundin64253a92022-02-04 09:02:48 +0000175 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 04:42:27 -0700176 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200177 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100178 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100179 EXPECT_NOERR(
180 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000181
182 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48 +0000183 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200184 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100185 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000186
187 // New number of channels.
Henrik Lundin64253a92022-02-04 09:02:48 +0000188 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200189 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100190 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100191 EXPECT_NOERR(
192 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000193
aluebsb0319552016-03-17 20:39:53 -0700194 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000195 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200196 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100197 EXPECT_NOERR(
198 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000199}
200
Alessio Bazzicac054e782018-04-16 12:10:09 +0200201TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200202 rtc::scoped_refptr<AudioProcessing> apm =
203 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200204 webrtc::AudioProcessing::Config apm_config;
205 apm_config.pre_amplifier.enabled = true;
206 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
207 apm->ApplyConfig(apm_config);
208
Per Åhgren2507f8c2020-03-19 12:33:29 +0100209 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200210 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200211 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200212
Per Åhgren2507f8c2020-03-19 12:33:29 +0100213 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000214 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100215 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100216 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100217 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200218 << "With factor 1, frame shouldn't be modified.";
219
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200220 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200221 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200222 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200223
224 // Process for two frames to have time to ramp up gain.
225 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100226 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100227 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200228 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100229 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200230 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200231}
232
Per Åhgrendb5d7282021-03-15 16:31:04 +0000233TEST(AudioProcessingImplTest,
234 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200235 rtc::scoped_refptr<AudioProcessing> apm =
236 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000237 webrtc::AudioProcessing::Config apm_config;
238 apm_config.capture_level_adjustment.enabled = true;
239 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
240 apm->ApplyConfig(apm_config);
241
242 constexpr int kSampleRateHz = 48000;
243 constexpr int16_t kAudioLevel = 10000;
244 constexpr size_t kNumChannels = 2;
245
246 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000247 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000248 frame.fill(kAudioLevel);
249 apm->ProcessStream(frame.data(), config, config, frame.data());
250 EXPECT_EQ(frame[100], kAudioLevel)
251 << "With factor 1, frame shouldn't be modified.";
252
253 constexpr float kGainFactor = 2.f;
254 apm->SetRuntimeSetting(
255 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
256
257 // Process for two frames to have time to ramp up gain.
258 for (int i = 0; i < 2; ++i) {
259 frame.fill(kAudioLevel);
260 apm->ProcessStream(frame.data(), config, config, frame.data());
261 }
262 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
263 << "Frame should be amplified.";
264}
265
266TEST(AudioProcessingImplTest,
267 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200268 rtc::scoped_refptr<AudioProcessing> apm =
269 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000270 webrtc::AudioProcessing::Config apm_config;
271 apm_config.capture_level_adjustment.enabled = true;
272 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
273 apm->ApplyConfig(apm_config);
274
275 constexpr int kSampleRateHz = 48000;
276 constexpr int16_t kAudioLevel = 10000;
277 constexpr size_t kNumChannels = 2;
278
279 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000280 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000281 frame.fill(kAudioLevel);
282 apm->ProcessStream(frame.data(), config, config, frame.data());
283 EXPECT_EQ(frame[100], kAudioLevel)
284 << "With factor 1, frame shouldn't be modified.";
285
286 constexpr float kGainFactor = 2.f;
287 apm->SetRuntimeSetting(
288 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
289
290 // Process for two frames to have time to ramp up gain.
291 for (int i = 0; i < 2; ++i) {
292 frame.fill(kAudioLevel);
293 apm->ProcessStream(frame.data(), config, config, frame.data());
294 }
295 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
296 << "Frame should be amplified.";
297}
298
Per Åhgren652ada52021-03-03 10:52:44 +0000299TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
300 // Tests that the echo controller observes that the capture usage has been
301 // updated.
302 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
303 const MockEchoControlFactory* echo_control_factory_ptr =
304 echo_control_factory.get();
305
Niels Möller4f776ac2021-07-02 11:30:54 +0200306 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000307 AudioProcessingBuilderForTesting()
308 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200309 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000310
311 constexpr int16_t kAudioLevel = 10000;
312 constexpr int kSampleRateHz = 48000;
313 constexpr int kNumChannels = 2;
314 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000315 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000316 frame.fill(kAudioLevel);
317
318 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
319
320 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
321 // are passed.
322 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
323 apm->ProcessStream(frame.data(), config, config, frame.data());
324
325 // Ensure that SetCaptureOutputUsage is called with the right information when
326 // a runtime setting is passed.
327 EXPECT_CALL(*echo_control_mock,
328 SetCaptureOutputUsage(/*capture_output_used=*/false))
329 .Times(1);
330 EXPECT_TRUE(apm->PostRuntimeSetting(
331 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
332 /*capture_output_used=*/false)));
333 apm->ProcessStream(frame.data(), config, config, frame.data());
334
335 EXPECT_CALL(*echo_control_mock,
336 SetCaptureOutputUsage(/*capture_output_used=*/true))
337 .Times(1);
338 EXPECT_TRUE(apm->PostRuntimeSetting(
339 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
340 /*capture_output_used=*/true)));
341 apm->ProcessStream(frame.data(), config, config, frame.data());
342
343 // The number of positions to place items in the queue is equal to the queue
344 // size minus 1.
345 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
346
347 // Ensure that SetCaptureOutputUsage is called with the right information when
348 // many runtime settings are passed.
349 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
350 EXPECT_TRUE(apm->PostRuntimeSetting(
351 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
352 /*capture_output_used=*/false)));
353 }
354 EXPECT_CALL(*echo_control_mock,
355 SetCaptureOutputUsage(/*capture_output_used=*/false))
356 .Times(kNumSlotsInQueue - 1);
357 apm->ProcessStream(frame.data(), config, config, frame.data());
358
359 // Ensure that SetCaptureOutputUsage is properly called with the fallback
360 // value when the runtime settings queue becomes full.
361 for (int k = 0; k < kNumSlotsInQueue; ++k) {
362 EXPECT_TRUE(apm->PostRuntimeSetting(
363 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
364 /*capture_output_used=*/false)));
365 }
366 EXPECT_FALSE(apm->PostRuntimeSetting(
367 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
368 /*capture_output_used=*/false)));
369 EXPECT_FALSE(apm->PostRuntimeSetting(
370 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
371 /*capture_output_used=*/false)));
372 EXPECT_CALL(*echo_control_mock,
373 SetCaptureOutputUsage(/*capture_output_used=*/false))
374 .Times(kNumSlotsInQueue);
375 EXPECT_CALL(*echo_control_mock,
376 SetCaptureOutputUsage(/*capture_output_used=*/true))
377 .Times(1);
378 apm->ProcessStream(frame.data(), config, config, frame.data());
379}
380
Alessio Bazzicae4498052018-12-17 09:44:06 +0100381TEST(AudioProcessingImplTest,
382 EchoControllerObservesPreAmplifierEchoPathGainChange) {
383 // Tests that the echo controller observes an echo path gain change when the
384 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200385 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100386 const auto* echo_control_factory_ptr = echo_control_factory.get();
387
Niels Möller4f776ac2021-07-02 11:30:54 +0200388 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200389 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100390 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200391 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200392 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100393 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200394 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100395 apm_config.gain_controller2.enabled = false;
396 apm_config.pre_amplifier.enabled = true;
397 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
398 apm->ApplyConfig(apm_config);
399
Alessio Bazzicae4498052018-12-17 09:44:06 +0100400 constexpr int16_t kAudioLevel = 10000;
401 constexpr size_t kSampleRateHz = 48000;
402 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100403 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000404 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100405 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100406
407 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
408
Per Åhgren0aefbf02019-08-23 21:29:17 +0200409 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200410 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100411 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200412 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100413 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100414
Per Åhgren0aefbf02019-08-23 21:29:17 +0200415 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200416 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100417 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200418 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100419 apm->SetRuntimeSetting(
420 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100421 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100422}
423
424TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000425 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
426 // Tests that the echo controller observes an echo path gain change when the
427 // pre-amplifier submodule changes the gain.
428 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
429 const auto* echo_control_factory_ptr = echo_control_factory.get();
430
Niels Möller4f776ac2021-07-02 11:30:54 +0200431 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000432 AudioProcessingBuilderForTesting()
433 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200434 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000435 // Disable AGC.
436 webrtc::AudioProcessing::Config apm_config;
437 apm_config.gain_controller1.enabled = false;
438 apm_config.gain_controller2.enabled = false;
439 apm_config.capture_level_adjustment.enabled = true;
440 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
441 apm->ApplyConfig(apm_config);
442
443 constexpr int16_t kAudioLevel = 10000;
444 constexpr size_t kSampleRateHz = 48000;
445 constexpr size_t kNumChannels = 2;
446 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000447 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000448 frame.fill(kAudioLevel);
449
450 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
451
452 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
453 EXPECT_CALL(*echo_control_mock,
454 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
455 .Times(1);
456 apm->ProcessStream(frame.data(), config, config, frame.data());
457
458 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
459 EXPECT_CALL(*echo_control_mock,
460 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
461 .Times(1);
462 apm->SetRuntimeSetting(
463 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
464 apm->ProcessStream(frame.data(), config, config, frame.data());
465}
466
467TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100468 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
469 // Tests that the echo controller observes an echo path gain change when the
470 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200471 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100472 const auto* echo_control_factory_ptr = echo_control_factory.get();
473
Niels Möller4f776ac2021-07-02 11:30:54 +0200474 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200475 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100476 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200477 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100478 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200479 // Enable AGC1.
480 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200481 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100482 apm_config.gain_controller2.enabled = false;
483 apm_config.pre_amplifier.enabled = false;
484 apm->ApplyConfig(apm_config);
485
Alessio Bazzicae4498052018-12-17 09:44:06 +0100486 constexpr int16_t kAudioLevel = 1000;
487 constexpr size_t kSampleRateHz = 48000;
488 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100489 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000490 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100491 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100492
493 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
494
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200495 constexpr int kInitialStreamAnalogLevel = 123;
496 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
497
498 // When the first fame is processed, no echo path gain change must be
499 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200500 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200501 EXPECT_CALL(*echo_control_mock,
502 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100503 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100504 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100505
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200506 // Simulate the application of the recommended analog level.
507 int recommended_analog_level = apm->recommended_stream_analog_level();
508 if (recommended_analog_level == kInitialStreamAnalogLevel) {
509 // Force an analog gain change if it did not happen.
510 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100511 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200512 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100513
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200514 // After the first fame and with a stream analog level change, the echo path
515 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200516 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200517 EXPECT_CALL(*echo_control_mock,
518 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100519 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100520 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100521}
522
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200523// Tests that a stream is successfully processed when AGC2 adaptive digital is
524// used and when the field trial
525// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200526TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200527 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
528 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100529 "WebRTC-Audio-GainController2/Disabled/");
530 auto apm = AudioProcessingBuilder()
531 .SetConfig({.gain_controller1{.enabled = false}})
532 .Create();
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200533 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200534 webrtc::AudioProcessing::Config apm_config;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200535 apm_config.gain_controller1.enabled = false;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200536 apm_config.gain_controller2.enabled = true;
537 apm_config.gain_controller2.adaptive_digital.enabled = true;
Alessio Bazzica17e14fd2022-12-07 17:08:45 +0100538 apm_config.transient_suppression.enabled = true;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200539 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200540 constexpr int kSampleRateHz = 48000;
541 constexpr int kNumChannels = 1;
542 std::array<float, kSampleRateHz / 100> buffer;
543 float* channel_pointers[] = {buffer.data()};
544 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
545 /*num_channels=*/kNumChannels);
546 Random random_generator(2341U);
547 constexpr int kFramesToProcess = 10;
548 for (int i = 0; i < kFramesToProcess; ++i) {
549 RandomizeSampleVector(&random_generator, buffer);
550 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
551 channel_pointers),
552 kNoErr);
553 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200554}
555
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200556// Tests that a stream is successfully processed when AGC2 adaptive digital is
557// used and when the field trial
558// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
559TEST(AudioProcessingImplTest,
560 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200561 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100562 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
Hanna Silen0c1ad292022-06-16 16:35:45 +0200563 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
564 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
565 webrtc::AudioProcessing::Config apm_config;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200566 apm_config.gain_controller1.enabled = false;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200567 apm_config.gain_controller2.enabled = true;
568 apm_config.gain_controller2.adaptive_digital.enabled = true;
Alessio Bazzica17e14fd2022-12-07 17:08:45 +0100569 apm_config.transient_suppression.enabled = true;
Hanna Silen0c1ad292022-06-16 16:35:45 +0200570 apm->ApplyConfig(apm_config);
571 constexpr int kSampleRateHz = 48000;
572 constexpr int kNumChannels = 1;
573 std::array<float, kSampleRateHz / 100> buffer;
574 float* channel_pointers[] = {buffer.data()};
575 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
576 /*num_channels=*/kNumChannels);
577 Random random_generator(2341U);
578 constexpr int kFramesToProcess = 10;
579 for (int i = 0; i < kFramesToProcess; ++i) {
580 RandomizeSampleVector(&random_generator, buffer);
581 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
582 channel_pointers),
583 kNoErr);
584 }
585}
586
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200587TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
588 // Tests that the echo controller observes an echo path gain change when a
589 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200590 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200591 const auto* echo_control_factory_ptr = echo_control_factory.get();
592
Niels Möller4f776ac2021-07-02 11:30:54 +0200593 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200594 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200595 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200596 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200597 // Disable AGC.
598 webrtc::AudioProcessing::Config apm_config;
599 apm_config.gain_controller1.enabled = false;
600 apm_config.gain_controller2.enabled = false;
601 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200602
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200603 constexpr int16_t kAudioLevel = 10000;
604 constexpr size_t kSampleRateHz = 48000;
605 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100606 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000607 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100608 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200609
610 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
611
Per Åhgren0aefbf02019-08-23 21:29:17 +0200612 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200613 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100614 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200615 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100616 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200617
Per Åhgren0aefbf02019-08-23 21:29:17 +0200618 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200619 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100620 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200621 .Times(1);
622 apm->SetRuntimeSetting(
623 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100624 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200625
Per Åhgren0aefbf02019-08-23 21:29:17 +0200626 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200627 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100628 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200629 .Times(1);
630 apm->SetRuntimeSetting(
631 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100632 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200633
Per Åhgren0aefbf02019-08-23 21:29:17 +0200634 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200635 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100636 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200637 .Times(1);
638 apm->SetRuntimeSetting(
639 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100640 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200641}
642
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200643TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
644 // Make sure that signal changes caused by a render pre-processing sub-module
645 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200646 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200647 std::unique_ptr<CustomProcessing> test_render_pre_processor(
648 new TestRenderPreProcessor());
649 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200650 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200651 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200652 .SetEchoDetector(test_echo_detector)
653 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200654 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200655 webrtc::AudioProcessing::Config apm_config;
656 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200657 apm->ApplyConfig(apm_config);
658
659 constexpr int16_t kAudioLevel = 1000;
660 constexpr int kSampleRateHz = 16000;
661 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100662 // Explicitly initialize APM to ensure no render frames are discarded.
663 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000664 {kSampleRateHz, kNumChannels},
665 {kSampleRateHz, kNumChannels},
666 {kSampleRateHz, kNumChannels},
667 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100668 }};
669 apm->Initialize(processing_config);
670
Per Åhgren2507f8c2020-03-19 12:33:29 +0100671 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000672 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200673
674 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
675 constexpr float kExpectedPreprocessedAudioLevel =
676 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
677 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
678
679 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100680 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200681 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100682 apm->ProcessReverseStream(frame.data(), stream_config,
683 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200684 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
685 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100686 frame.fill(kAudioLevel);
687 ASSERT_EQ(AudioProcessing::Error::kNoError,
688 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100689 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200690 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
691 // triggered, the line below checks that the call has occurred. If not, the
692 // APM implementation may have changed and this test might need to be adapted.
693 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
694 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
695 // produced by the render pre-processor.
696 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
697 test_echo_detector->last_render_audio_first_sample());
698}
699
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200700// Disabling build-optional submodules and trying to enable them via the APM
701// config should be bit-exact with running APM with said submodules disabled.
702// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
703TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200704 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200705 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
706
707 ApmSubmoduleCreationOverrides overrides;
708 overrides.transient_suppression = true;
709 apm->OverrideSubmoduleCreationForTesting(overrides);
710
711 AudioProcessing::Config apm_config = apm->GetConfig();
712 apm_config.transient_suppression.enabled = true;
713 apm->ApplyConfig(apm_config);
714
715 rtc::scoped_refptr<AudioProcessing> apm_reference =
716 AudioProcessingBuilder().Create();
717 apm_config = apm_reference->GetConfig();
718 apm_config.transient_suppression.enabled = false;
719 apm_reference->ApplyConfig(apm_config);
720
721 constexpr int kSampleRateHz = 16000;
722 constexpr int kNumChannels = 1;
723 std::array<float, kSampleRateHz / 100> buffer;
724 std::array<float, kSampleRateHz / 100> buffer_reference;
725 float* channel_pointers[] = {buffer.data()};
726 float* channel_pointers_reference[] = {buffer_reference.data()};
727 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000728 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200729 Random random_generator(2341U);
730 constexpr int kFramesToProcessPerConfiguration = 10;
731
732 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
733 RandomizeSampleVector(&random_generator, buffer);
734 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
735 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
736 channel_pointers),
737 kNoErr);
738 ASSERT_EQ(
739 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
740 stream_config, channel_pointers_reference),
741 kNoErr);
742 for (int j = 0; j < kSampleRateHz / 100; ++j) {
743 EXPECT_EQ(buffer[j], buffer_reference[j]);
744 }
745 }
746}
747
748// Disable transient suppressor creation and run APM in ways that should trigger
749// calls to the transient suppressor API.
750TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200751 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200752 ASSERT_EQ(apm->Initialize(), kNoErr);
753
754 ApmSubmoduleCreationOverrides overrides;
755 overrides.transient_suppression = true;
756 apm->OverrideSubmoduleCreationForTesting(overrides);
757
758 AudioProcessing::Config config = apm->GetConfig();
759 config.transient_suppression.enabled = true;
760 apm->ApplyConfig(config);
761 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
762 float buffer[960];
763 float* channel_pointers[] = {&buffer[0], &buffer[480]};
764 Random random_generator(2341U);
765 constexpr int kFramesToProcessPerConfiguration = 3;
766
767 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000768 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200769 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
770 RandomizeSampleVector(&random_generator, buffer);
771 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
772 initial_stream_config, channel_pointers),
773 kNoErr);
774 }
775
776 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000777 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200778 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
779 RandomizeSampleVector(&random_generator, buffer);
780 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
781 stereo_stream_config, channel_pointers),
782 kNoErr);
783 }
784
785 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000786 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200787 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
788 RandomizeSampleVector(&random_generator, buffer);
789 EXPECT_EQ(
790 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
791 high_sample_rate_stream_config, channel_pointers),
792 kNoErr);
793 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200794}
795
796// Disable transient suppressor creation and run APM in ways that should trigger
797// calls to the transient suppressor API.
798TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200799 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200800 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
801
802 ApmSubmoduleCreationOverrides overrides;
803 overrides.transient_suppression = true;
804 apm->OverrideSubmoduleCreationForTesting(overrides);
805
806 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
807 float buffer[960];
808 float* channel_pointers[] = {&buffer[0], &buffer[480]};
809 Random random_generator(2341U);
810 constexpr int kFramesToProcessPerConfiguration = 3;
811 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000812 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200813
814 AudioProcessing::Config config = apm->GetConfig();
815 config.transient_suppression.enabled = true;
816 apm->ApplyConfig(config);
817 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
818 RandomizeSampleVector(&random_generator, buffer);
819 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
820 channel_pointers),
821 kNoErr);
822 }
823
824 config = apm->GetConfig();
825 config.transient_suppression.enabled = false;
826 apm->ApplyConfig(config);
827 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
828 RandomizeSampleVector(&random_generator, buffer);
829 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
830 channel_pointers),
831 kNoErr);
832 }
833
834 config = apm->GetConfig();
835 config.transient_suppression.enabled = true;
836 apm->ApplyConfig(config);
837 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
838 RandomizeSampleVector(&random_generator, buffer);
839 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
840 channel_pointers),
841 kNoErr);
842 }
843}
Hanna Silenc69188d2022-09-16 11:38:56 +0200844
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100845class ApmInputVolumeControllerParametrizedTest
846 : public ::testing::TestWithParam<
847 std::tuple<int, int, AudioProcessing::Config>> {
848 protected:
849 ApmInputVolumeControllerParametrizedTest()
850 : sample_rate_hz_(std::get<0>(GetParam())),
851 num_channels_(std::get<1>(GetParam())),
852 channels_(num_channels_),
853 channel_pointers_(num_channels_) {
854 const int frame_size = sample_rate_hz_ / 100;
855 for (int c = 0; c < num_channels_; ++c) {
856 channels_[c].resize(frame_size);
857 channel_pointers_[c] = channels_[c].data();
858 std::fill(channels_[c].begin(), channels_[c].end(), 0.0f);
Hanna Silend4dbe452022-11-30 15:16:21 +0100859 }
Hanna Silenc69188d2022-09-16 11:38:56 +0200860 }
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100861
862 int sample_rate_hz() const { return sample_rate_hz_; }
863 int num_channels() const { return num_channels_; }
864 AudioProcessing::Config GetConfig() const { return std::get<2>(GetParam()); }
865
866 float* const* channel_pointers() { return channel_pointers_.data(); }
867
868 private:
869 const int sample_rate_hz_;
870 const int num_channels_;
871 std::vector<std::vector<float>> channels_;
872 std::vector<float*> channel_pointers_;
873};
874
875TEST_P(ApmInputVolumeControllerParametrizedTest,
876 EnforceMinInputVolumeAtStartupWithZeroVolume) {
877 const StreamConfig stream_config(sample_rate_hz(), num_channels());
878 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
879
880 apm->set_stream_analog_level(0);
881 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
882 channel_pointers());
883 EXPECT_GT(apm->recommended_stream_analog_level(), 0);
Hanna Silenc69188d2022-09-16 11:38:56 +0200884}
885
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100886TEST_P(ApmInputVolumeControllerParametrizedTest,
887 EnforceMinInputVolumeAtStartupWithNonZeroVolume) {
888 const StreamConfig stream_config(sample_rate_hz(), num_channels());
889 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
Hanna Silenc69188d2022-09-16 11:38:56 +0200890
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100891 constexpr int kStartupVolume = 3;
892 apm->set_stream_analog_level(kStartupVolume);
893 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
894 channel_pointers());
895 EXPECT_GT(apm->recommended_stream_analog_level(), kStartupVolume);
896}
Hanna Silenc69188d2022-09-16 11:38:56 +0200897
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100898TEST_P(ApmInputVolumeControllerParametrizedTest,
899 EnforceMinInputVolumeAfterManualVolumeAdjustment) {
900 const auto config = GetConfig();
901 if (config.gain_controller1.enabled) {
902 // After a downward manual adjustment, AGC1 slowly converges to the minimum
903 // input volume.
904 GTEST_SKIP() << "Does not apply to AGC1";
Hanna Silend4dbe452022-11-30 15:16:21 +0100905 }
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100906 const StreamConfig stream_config(sample_rate_hz(), num_channels());
907 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
908
909 apm->set_stream_analog_level(20);
910 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
911 channel_pointers());
912 constexpr int kManuallyAdjustedVolume = 3;
913 apm->set_stream_analog_level(kManuallyAdjustedVolume);
914 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
915 channel_pointers());
916 EXPECT_GT(apm->recommended_stream_analog_level(), kManuallyAdjustedVolume);
Hanna Silenc69188d2022-09-16 11:38:56 +0200917}
918
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100919TEST_P(ApmInputVolumeControllerParametrizedTest,
920 DoNotEnforceMinInputVolumeAfterManualVolumeAdjustmentToZero) {
921 const StreamConfig stream_config(sample_rate_hz(), num_channels());
922 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
Hanna Silenc69188d2022-09-16 11:38:56 +0200923
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100924 apm->set_stream_analog_level(100);
925 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
926 channel_pointers());
927 apm->set_stream_analog_level(0);
928 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
929 channel_pointers());
930 EXPECT_EQ(apm->recommended_stream_analog_level(), 0);
Hanna Silenc69188d2022-09-16 11:38:56 +0200931}
932
Alessio Bazzica3b51cd32022-12-14 16:36:10 +0100933INSTANTIATE_TEST_SUITE_P(
934 AudioProcessingImplTest,
935 ApmInputVolumeControllerParametrizedTest,
936 ::testing::Combine(
937 ::testing::Values(8000, 16000, 32000, 48000), // Sample rates.
938 ::testing::Values(1, 2), // Number of channels.
939 ::testing::Values(
940 // Full AGC1.
941 AudioProcessing::Config{
942 .gain_controller1 = {.enabled = true,
943 .analog_gain_controller =
944 {.enabled = true,
945 .enable_digital_adaptive = true}},
946 .gain_controller2 = {.enabled = false}},
947 // Hybrid AGC.
948 AudioProcessing::Config{
949 .gain_controller1 = {.enabled = true,
950 .analog_gain_controller =
951 {.enabled = true,
952 .enable_digital_adaptive = false}},
953 .gain_controller2 = {.enabled = true,
954 .adaptive_digital = {.enabled = true}}})));
Hanna Silenc69188d2022-09-16 11:38:56 +0200955
Alessio Bazzica79beaa72022-10-31 16:42:34 +0100956// When the input volume is not emulated and no input volume controller is
957// active, the recommended volume must always be the applied volume.
958TEST(AudioProcessingImplTest,
959 RecommendAppliedInputVolumeWithNoAgcWithNoEmulation) {
960 auto apm = AudioProcessingBuilder()
961 .SetConfig({.capture_level_adjustment = {.enabled = false},
962 .gain_controller1 = {.enabled = false}})
963 .Create();
964
965 constexpr int kOneFrame = 1;
966 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
967 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
968 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
969}
970
971// When the input volume is emulated, the recommended volume must always be the
972// applied volume and at any time it must not be that set in the input volume
973// emulator.
974// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
975TEST(AudioProcessingImplTest,
976 DISABLED_RecommendAppliedInputVolumeWithNoAgcWithEmulation) {
977 auto apm =
978 AudioProcessingBuilder()
979 .SetConfig({.capture_level_adjustment = {.enabled = true,
980 .analog_mic_gain_emulation{
981 .enabled = true,
982 .initial_level = 255}},
983 .gain_controller1 = {.enabled = false}})
984 .Create();
985
986 constexpr int kOneFrame = 1;
987 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
988 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
989 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
990}
991
992// Even if there is an enabled input volume controller, when the input volume is
993// emulated, the recommended volume is always the applied volume because the
994// active controller must only adjust the internally emulated volume and leave
995// the externally applied volume unchanged.
996// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
997TEST(AudioProcessingImplTest,
998 DISABLED_RecommendAppliedInputVolumeWithAgcWithEmulation) {
999 auto apm =
1000 AudioProcessingBuilder()
1001 .SetConfig({.capture_level_adjustment = {.enabled = true,
1002 .analog_mic_gain_emulation{
1003 .enabled = true}},
1004 .gain_controller1 = {.enabled = true,
1005 .analog_gain_controller{
1006 .enabled = true,
1007 }}})
1008 .Create();
1009
1010 constexpr int kOneFrame = 1;
1011 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1012 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1013 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1014}
1015
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001016TEST(AudioProcessingImplTest,
1017 Agc2FieldTrialDoNotSwitchToFullAgc2WhenNoAgcIsActive) {
1018 constexpr AudioProcessing::Config kOriginal{
1019 .gain_controller1{.enabled = false},
1020 .gain_controller2{.enabled = false},
1021 };
1022 webrtc::test::ScopedFieldTrials field_trials(
1023 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1024
1025 // Test config application via `AudioProcessing` ctor.
1026 auto adjusted =
1027 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1028 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1029 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1030
1031 // Test config application via `AudioProcessing::ApplyConfig()`.
1032 auto apm = AudioProcessingBuilder().Create();
1033 apm->ApplyConfig(kOriginal);
1034 adjusted = apm->GetConfig();
1035 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1036 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1037}
1038
1039TEST(AudioProcessingImplTest,
1040 Agc2FieldTrialDoNotSwitchToFullAgc2WithAgc1Agc2InputVolumeControllers) {
1041 constexpr AudioProcessing::Config kOriginal{
1042 .gain_controller1{.enabled = true,
1043 .analog_gain_controller{.enabled = true}},
1044 .gain_controller2{.enabled = true,
1045 .input_volume_controller{.enabled = true}},
1046 };
1047 webrtc::test::ScopedFieldTrials field_trials(
1048 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1049
1050 // Test config application via `AudioProcessing` ctor.
1051 auto adjusted =
1052 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1053 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1054 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1055
1056 // Test config application via `AudioProcessing::ApplyConfig()`.
1057 auto apm = AudioProcessingBuilder().Create();
1058 apm->ApplyConfig(kOriginal);
1059 adjusted = apm->GetConfig();
1060 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1061 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1062}
1063
1064class Agc2FieldTrialParametrizedTest
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001065 : public ::testing::TestWithParam<AudioProcessing::Config> {};
1066
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001067TEST_P(Agc2FieldTrialParametrizedTest, DoNotChangeConfigIfDisabled) {
1068 const AudioProcessing::Config original = GetParam();
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001069 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001070 "WebRTC-Audio-GainController2/Disabled/");
1071
1072 // Test config application via `AudioProcessing` ctor.
1073 auto adjusted =
1074 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1075 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1076 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1077
1078 // Test config application via `AudioProcessing::ApplyConfig()`.
1079 auto apm = AudioProcessingBuilder().Create();
1080 apm->ApplyConfig(original);
1081 adjusted = apm->GetConfig();
1082 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1083 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1084}
1085
1086TEST_P(Agc2FieldTrialParametrizedTest, DoNotChangeConfigIfNoOverride) {
1087 const AudioProcessing::Config original = GetParam();
1088 webrtc::test::ScopedFieldTrials field_trials(
1089 "WebRTC-Audio-GainController2/Enabled,"
1090 "switch_to_agc2:false,"
1091 "disallow_transient_suppressor_usage:false/");
1092
1093 // Test config application via `AudioProcessing` ctor.
1094 auto adjusted =
1095 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1096 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1097 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1098
1099 // Test config application via `AudioProcessing::ApplyConfig()`.
1100 auto apm = AudioProcessingBuilder().Create();
1101 apm->ApplyConfig(original);
1102 adjusted = apm->GetConfig();
1103 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1104 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1105}
1106
1107TEST_P(Agc2FieldTrialParametrizedTest, DoNotSwitchToFullAgc2) {
1108 const AudioProcessing::Config original = GetParam();
1109 webrtc::test::ScopedFieldTrials field_trials(
1110 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:false/");
1111
1112 // Test config application via `AudioProcessing` ctor.
1113 auto adjusted =
1114 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1115 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1116 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1117
1118 // Test config application via `AudioProcessing::ApplyConfig()`.
1119 auto apm = AudioProcessingBuilder().Create();
1120 apm->ApplyConfig(original);
1121 adjusted = apm->GetConfig();
1122 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1123 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1124}
1125
1126TEST_P(Agc2FieldTrialParametrizedTest, SwitchToFullAgc2) {
1127 const AudioProcessing::Config original = GetParam();
1128 webrtc::test::ScopedFieldTrials field_trials(
1129 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1130
1131 // Test config application via `AudioProcessing` ctor.
1132 auto adjusted =
1133 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1134 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1135 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1136 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1137 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1138
1139 // Test config application via `AudioProcessing::ApplyConfig()`.
1140 auto apm = AudioProcessingBuilder().Create();
1141 apm->ApplyConfig(original);
1142 adjusted = apm->GetConfig();
1143 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1144 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1145 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1146 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1147}
1148
1149TEST_P(Agc2FieldTrialParametrizedTest,
1150 SwitchToFullAgc2AndOverrideInputVolumeControllerParameters) {
1151 const AudioProcessing::Config original = GetParam();
1152 webrtc::test::ScopedFieldTrials field_trials(
1153 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true,"
1154 "min_input_volume:123,"
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001155 "clipped_level_min:20,"
1156 "clipped_level_step:30,"
1157 "clipped_ratio_threshold:0.4,"
1158 "clipped_wait_frames:50,"
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001159 "enable_clipping_predictor:true,"
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001160 "target_range_max_dbfs:-6,"
1161 "target_range_min_dbfs:-70,"
1162 "update_input_volume_wait_frames:80,"
1163 "speech_probability_threshold:0.9,"
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001164 "speech_ratio_threshold:1.0/");
1165
1166 // Test config application via `AudioProcessing` ctor.
1167 auto adjusted =
1168 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1169 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1170 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1171 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1172 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1173
1174 // Test config application via `AudioProcessing::ApplyConfig()`.
1175 auto apm = AudioProcessingBuilder().Create();
1176 apm->ApplyConfig(original);
1177 adjusted = apm->GetConfig();
1178 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1179 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1180 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1181 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1182}
1183
1184TEST_P(Agc2FieldTrialParametrizedTest,
1185 SwitchToFullAgc2AndOverrideAdaptiveDigitalControllerParameters) {
1186 const AudioProcessing::Config original = GetParam();
1187 webrtc::test::ScopedFieldTrials field_trials(
1188 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true,"
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001189 "headroom_db:10,"
1190 "max_gain_db:20,"
1191 "initial_gain_db:7,"
1192 "max_gain_change_db_per_second:5,"
1193 "max_output_noise_level_dbfs:-40/");
1194
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001195 // Test config application via `AudioProcessing` ctor.
1196 auto adjusted =
1197 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1198 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1199 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1200 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1201 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1202 ASSERT_NE(adjusted.gain_controller2.adaptive_digital,
1203 original.gain_controller2.adaptive_digital);
1204 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.headroom_db, 10);
1205 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.max_gain_db, 20);
1206 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.initial_gain_db, 7);
1207 EXPECT_EQ(
1208 adjusted.gain_controller2.adaptive_digital.max_gain_change_db_per_second,
1209 5);
1210 EXPECT_EQ(
1211 adjusted.gain_controller2.adaptive_digital.max_output_noise_level_dbfs,
1212 -40);
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001213
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001214 // Test config application via `AudioProcessing::ApplyConfig()`.
1215 auto apm = AudioProcessingBuilder().Create();
1216 apm->ApplyConfig(original);
1217 adjusted = apm->GetConfig();
1218 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1219 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1220 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1221 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1222 ASSERT_NE(adjusted.gain_controller2.adaptive_digital,
1223 original.gain_controller2.adaptive_digital);
1224 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.headroom_db, 10);
1225 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.max_gain_db, 20);
1226 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.initial_gain_db, 7);
1227 EXPECT_EQ(
1228 adjusted.gain_controller2.adaptive_digital.max_gain_change_db_per_second,
1229 5);
1230 EXPECT_EQ(
1231 adjusted.gain_controller2.adaptive_digital.max_output_noise_level_dbfs,
1232 -40);
1233}
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001234
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001235TEST_P(Agc2FieldTrialParametrizedTest, ProcessSucceedsWithTs) {
1236 AudioProcessing::Config config = GetParam();
1237 config.transient_suppression.enabled = true;
1238 webrtc::test::ScopedFieldTrials field_trials(
1239 "WebRTC-Audio-GainController2/Disabled/");
1240 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
1241
1242 constexpr int kSampleRateHz = 48000;
1243 constexpr int kNumChannels = 1;
1244 std::array<float, kSampleRateHz / 100> buffer;
1245 float* channel_pointers[] = {buffer.data()};
1246 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1247 Random random_generator(2341U);
1248 constexpr int kFramesToProcess = 10;
1249 int volume = 100;
1250 for (int i = 0; i < kFramesToProcess; ++i) {
1251 SCOPED_TRACE(i);
1252 RandomizeSampleVector(&random_generator, buffer);
1253 apm->set_stream_analog_level(volume);
1254 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1255 channel_pointers),
1256 kNoErr);
1257 volume = apm->recommended_stream_analog_level();
1258 }
1259}
1260
1261TEST_P(Agc2FieldTrialParametrizedTest, ProcessSucceedsWithoutTs) {
1262 webrtc::test::ScopedFieldTrials field_trials(
1263 "WebRTC-Audio-GainController2/Enabled,"
1264 "switch_to_agc2:false,"
1265 "disallow_transient_suppressor_usage:true/");
1266 auto apm = AudioProcessingBuilder().SetConfig(GetParam()).Create();
1267
1268 constexpr int kSampleRateHz = 48000;
1269 constexpr int kNumChannels = 1;
1270 std::array<float, kSampleRateHz / 100> buffer;
1271 float* channel_pointers[] = {buffer.data()};
1272 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1273 Random random_generator(2341U);
1274 constexpr int kFramesToProcess = 10;
1275 int volume = 100;
1276 for (int i = 0; i < kFramesToProcess; ++i) {
1277 SCOPED_TRACE(i);
1278 RandomizeSampleVector(&random_generator, buffer);
1279 apm->set_stream_analog_level(volume);
1280 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1281 channel_pointers),
1282 kNoErr);
1283 volume = apm->recommended_stream_analog_level();
1284 }
1285}
1286
1287TEST_P(Agc2FieldTrialParametrizedTest,
1288 ProcessSucceedsWhenSwitchToFullAgc2WithTs) {
1289 AudioProcessing::Config config = GetParam();
1290 config.transient_suppression.enabled = true;
1291 webrtc::test::ScopedFieldTrials field_trials(
1292 "WebRTC-Audio-GainController2/Enabled,"
1293 "switch_to_agc2:true,"
1294 "disallow_transient_suppressor_usage:false/");
1295 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
1296
1297 constexpr int kSampleRateHz = 48000;
1298 constexpr int kNumChannels = 1;
1299 std::array<float, kSampleRateHz / 100> buffer;
1300 float* channel_pointers[] = {buffer.data()};
1301 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1302 Random random_generator(2341U);
1303 constexpr int kFramesToProcess = 10;
1304 int volume = 100;
1305 for (int i = 0; i < kFramesToProcess; ++i) {
1306 SCOPED_TRACE(i);
1307 RandomizeSampleVector(&random_generator, buffer);
1308 apm->set_stream_analog_level(volume);
1309 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1310 channel_pointers),
1311 kNoErr);
1312 volume = apm->recommended_stream_analog_level();
1313 }
1314}
1315
1316TEST_P(Agc2FieldTrialParametrizedTest,
1317 ProcessSucceedsWhenSwitchToFullAgc2WithoutTs) {
1318 webrtc::test::ScopedFieldTrials field_trials(
1319 "WebRTC-Audio-GainController2/Enabled,"
1320 "switch_to_agc2:true,"
1321 "disallow_transient_suppressor_usage:true/");
1322 auto apm = AudioProcessingBuilder().SetConfig(GetParam()).Create();
1323
1324 constexpr int kSampleRateHz = 48000;
1325 constexpr int kNumChannels = 1;
1326 std::array<float, kSampleRateHz / 100> buffer;
1327 float* channel_pointers[] = {buffer.data()};
1328 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1329 Random random_generator(2341U);
1330 constexpr int kFramesToProcess = 10;
1331 int volume = 100;
1332 for (int i = 0; i < kFramesToProcess; ++i) {
1333 SCOPED_TRACE(i);
1334 RandomizeSampleVector(&random_generator, buffer);
1335 apm->set_stream_analog_level(volume);
1336 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1337 channel_pointers),
1338 kNoErr);
1339 volume = apm->recommended_stream_analog_level();
1340 }
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001341}
1342
1343INSTANTIATE_TEST_SUITE_P(
1344 AudioProcessingImplTest,
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001345 Agc2FieldTrialParametrizedTest,
Alessio Bazzicadfba28e2022-12-09 10:02:41 +01001346 ::testing::Values(
1347 // Full AGC1.
1348 AudioProcessing::Config{
1349 .gain_controller1 =
1350 {.enabled = true,
1351 .analog_gain_controller = {.enabled = true,
1352 .enable_digital_adaptive = true}},
1353 .gain_controller2 = {.enabled = false}},
1354 // Hybrid AGC.
1355 AudioProcessing::Config{
1356 .gain_controller1 =
1357 {.enabled = true,
1358 .analog_gain_controller = {.enabled = true,
1359 .enable_digital_adaptive = false}},
1360 .gain_controller2 = {.enabled = true,
1361 .adaptive_digital = {.enabled = true}}}));
1362
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001363TEST(AudioProcessingImplTest, CanDisableTransientSuppressor) {
1364 constexpr AudioProcessing::Config kOriginal = {
1365 .transient_suppression = {.enabled = false}};
1366
1367 // Test config application via `AudioProcessing` ctor.
1368 auto adjusted =
1369 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1370 EXPECT_FALSE(adjusted.transient_suppression.enabled);
1371
1372 // Test config application via `AudioProcessing::ApplyConfig()`.
1373 auto apm = AudioProcessingBuilder().Create();
1374 apm->ApplyConfig(kOriginal);
1375 adjusted = apm->GetConfig();
1376 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
1377}
1378
1379TEST(AudioProcessingImplTest, CanEnableTs) {
1380 constexpr AudioProcessing::Config kOriginal = {
1381 .transient_suppression = {.enabled = true}};
1382
1383 // Test config application via `AudioProcessing` ctor.
1384 auto adjusted =
1385 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1386 EXPECT_TRUE(adjusted.transient_suppression.enabled);
1387
1388 // Test config application via `AudioProcessing::ApplyConfig()`.
1389 auto apm = AudioProcessingBuilder().Create();
1390 apm->ApplyConfig(kOriginal);
1391 adjusted = apm->GetConfig();
1392 EXPECT_TRUE(adjusted.transient_suppression.enabled);
1393}
1394
1395TEST(AudioProcessingImplTest, CanDisableTsWithAgc2FieldTrialDisabled) {
1396 constexpr AudioProcessing::Config kOriginal = {
1397 .transient_suppression = {.enabled = false}};
Hanna Silena6574902022-11-30 16:59:05 +01001398 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001399 "WebRTC-Audio-GainController2/Disabled/");
Hanna Silena6574902022-11-30 16:59:05 +01001400
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001401 // Test config application via `AudioProcessing` ctor.
1402 auto adjusted =
1403 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1404 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001405
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001406 // Test config application via `AudioProcessing::ApplyConfig()`.
1407 auto apm = AudioProcessingBuilder().Create();
1408 apm->ApplyConfig(kOriginal);
1409 adjusted = apm->GetConfig();
1410 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001411}
1412
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001413TEST(AudioProcessingImplTest, CanEnableTsWithAgc2FieldTrialDisabled) {
1414 constexpr AudioProcessing::Config kOriginal = {
1415 .transient_suppression = {.enabled = true}};
Hanna Silena6574902022-11-30 16:59:05 +01001416 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001417 "WebRTC-Audio-GainController2/Disabled/");
Hanna Silena6574902022-11-30 16:59:05 +01001418
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001419 // Test config application via `AudioProcessing` ctor.
1420 auto adjusted =
1421 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1422 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001423
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001424 // Test config application via `AudioProcessing::ApplyConfig()`.
1425 auto apm = AudioProcessingBuilder().Create();
1426 apm->ApplyConfig(kOriginal);
1427 adjusted = apm->GetConfig();
1428 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001429}
1430
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001431TEST(AudioProcessingImplTest,
1432 CanDisableTsWithAgc2FieldTrialEnabledAndUsageAllowed) {
1433 constexpr AudioProcessing::Config kOriginal = {
1434 .transient_suppression = {.enabled = false}};
Hanna Silena6574902022-11-30 16:59:05 +01001435 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001436 "WebRTC-Audio-GainController2/Enabled,"
1437 "disallow_transient_suppressor_usage:false/");
Hanna Silena6574902022-11-30 16:59:05 +01001438
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001439 // Test config application via `AudioProcessing` ctor.
1440 auto adjusted =
1441 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1442 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001443
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001444 // Test config application via `AudioProcessing::ApplyConfig()`.
1445 auto apm = AudioProcessingBuilder().Create();
1446 apm->ApplyConfig(kOriginal);
1447 adjusted = apm->GetConfig();
1448 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001449}
1450
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001451TEST(AudioProcessingImplTest,
1452 CanEnableTsWithAgc2FieldTrialEnabledAndUsageAllowed) {
1453 constexpr AudioProcessing::Config kOriginal = {
1454 .transient_suppression = {.enabled = true}};
Hanna Silena6574902022-11-30 16:59:05 +01001455 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001456 "WebRTC-Audio-GainController2/Enabled,"
1457 "disallow_transient_suppressor_usage:false/");
Hanna Silena6574902022-11-30 16:59:05 +01001458
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001459 // Test config application via `AudioProcessing` ctor.
1460 auto adjusted =
1461 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1462 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001463
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001464 // Test config application via `AudioProcessing::ApplyConfig()`.
1465 auto apm = AudioProcessingBuilder().Create();
1466 apm->ApplyConfig(kOriginal);
1467 adjusted = apm->GetConfig();
1468 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001469}
1470
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001471TEST(AudioProcessingImplTest,
1472 CannotEnableTsWithAgc2FieldTrialEnabledAndUsageDisallowed) {
1473 constexpr AudioProcessing::Config kOriginal = {
1474 .transient_suppression = {.enabled = true}};
1475 webrtc::test::ScopedFieldTrials field_trials(
1476 "WebRTC-Audio-GainController2/Enabled,"
1477 "disallow_transient_suppressor_usage:true/");
Hanna Silena6574902022-11-30 16:59:05 +01001478
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001479 // Test config application via `AudioProcessing` ctor.
1480 auto adjusted =
1481 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1482 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001483
Alessio Bazzica3b51cd32022-12-14 16:36:10 +01001484 // Test config application via `AudioProcessing::ApplyConfig()`.
1485 auto apm = AudioProcessingBuilder().Create();
1486 apm->ApplyConfig(kOriginal);
1487 adjusted = apm->GetConfig();
1488 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
Hanna Silena6574902022-11-30 16:59:05 +01001489}
1490
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001491} // namespace webrtc