blob: e03f966b0655c1fbe010d2fb49e78ad9511803e2 [file] [log] [blame]
andrew@webrtc.org60730cf2014-01-07 17:45:091/*
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 04:47:3111#include "modules/audio_processing/audio_processing_impl.h"
andrew@webrtc.org60730cf2014-01-07 17:45:0912
Alessio Bazzica3b51cd32022-12-14 15:36:1013#include <algorithm>
Per Åhgren2507f8c2020-03-19 11:33:2914#include <array>
Alessio Bazzicae4498052018-12-17 08:44:0615#include <memory>
Hanna Silenc69188d2022-09-16 09:38:5616#include <tuple>
Alessio Bazzicae4498052018-12-17 08:44:0617
Hanna Silenc69188d2022-09-16 09:38:5618#include "absl/types/optional.h"
Niels Möller105711e2022-06-14 13:48:2619#include "api/make_ref_counted.h"
Mirko Bonadeid9708072019-01-25 19:26:4820#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 12:23:1121#include "modules/audio_processing/include/audio_processing.h"
Sam Zackrissonb37e59d2020-04-27 06:39:3322#include "modules/audio_processing/optionally_built_submodule_creators.h"
Per Åhgrencc73ed32020-04-26 21:56:1723#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Sam Zackrissonb37e59d2020-04-27 06:39:3324#include "modules/audio_processing/test/echo_canceller_test_tools.h"
Alessio Bazzicae4498052018-12-17 08:44:0625#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3126#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 08:44:0627#include "rtc_base/checks.h"
Sam Zackrissonb37e59d2020-04-27 06:39:3328#include "rtc_base/random.h"
Hanna Silenc69188d2022-09-16 09:38:5629#include "rtc_base/strings/string_builder.h"
Hanna Silen0c1ad292022-06-16 14:35:4530#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3131#include "test/gmock.h"
32#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:0933
andrew@webrtc.org60730cf2014-01-07 17:45:0934namespace webrtc {
peaha9cc40b2017-06-29 15:32:0935namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:0936
Alessio Bazzicae4498052018-12-17 08:44:0637using ::testing::Invoke;
38using ::testing::NotNull;
39
andrew@webrtc.org60730cf2014-01-07 17:45:0940class MockInitialize : public AudioProcessingImpl {
41 public:
Alessio Bazzicabe1b8982021-09-17 06:26:1042 MockInitialize() : AudioProcessingImpl() {}
andrew@webrtc.org60730cf2014-01-07 17:45:0943
Per Åhgren0ade9832020-09-01 21:57:2044 MOCK_METHOD(void, InitializeLocked, (), (override));
Niels Möller5b747232021-07-26 15:16:2545 void RealInitializeLocked() {
46 AssertLockedForTest();
Per Åhgren0ade9832020-09-01 21:57:2047 AudioProcessingImpl::InitializeLocked();
pbos@webrtc.org788acd12014-12-15 09:41:2448 }
peaha9cc40b2017-06-29 15:32:0949
Danil Chapovalov704fb552020-05-18 13:10:1550 MOCK_METHOD(void, AddRef, (), (const, override));
Harald Alvestrand78f905e2023-11-02 14:09:2651 MOCK_METHOD(RefCountReleaseStatus, Release, (), (const, override));
andrew@webrtc.org60730cf2014-01-07 17:45:0952};
53
Alessio Bazzicae4498052018-12-17 08:44:0654// 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 15:06:1863 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 08:44:0664 // Returns a pointer to the next MockEchoControl that this factory creates.
65 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 19:44:1166 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
67 int num_render_channels,
68 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 08:44:0669 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 15:06:1870 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 08:44:0671 return mock;
72 }
73
74 private:
75 std::unique_ptr<MockEchoControl> next_mock_;
76};
77
Alessio Bazzicad2b97402018-08-09 12:23:1178// 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 09:51:13122 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 12:23:11123 audio->num_frames());
124 std::transform(channel_view.begin(), channel_view.end(),
125 channel_view.begin(), ProcessSample);
126 }
Mirko Bonadeic4dd7302019-02-25 08:12:02127 }
Alessio Bazzicad2b97402018-08-09 12:23:11128 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 09:38:56135// 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 15:32:09161} // namespace
162
andrew@webrtc.org60730cf2014-01-07 17:45:09163TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 06:26:10164 MockInitialize mock;
165 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09166 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
167
Alessio Bazzicabe1b8982021-09-17 06:26:10168 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09169 mock.Initialize();
170
Per Åhgren2507f8c2020-03-19 11:33:29171 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:48175 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 11:42:27176 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 06:26:10177 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 13:55:58178 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 11:33:29179 EXPECT_NOERR(
180 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09181
182 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48183 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 06:26:10184 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 13:55:58185 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09186
187 // New number of channels.
Henrik Lundin64253a92022-02-04 09:02:48188 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 06:26:10189 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 13:55:58190 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 11:33:29191 EXPECT_NOERR(
192 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09193
aluebsb0319552016-03-18 03:39:53194 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48195 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 06:26:10196 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 11:33:29197 EXPECT_NOERR(
198 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09199}
200
Alessio Bazzicac054e782018-04-16 10:10:09201TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 09:30:54202 rtc::scoped_refptr<AudioProcessing> apm =
203 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 14:31:22204 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 11:33:29209 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 12:23:11210 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 12:23:11211 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 14:31:22212
Per Åhgren2507f8c2020-03-19 11:33:29213 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48214 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 11:33:29215 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 13:55:58216 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 11:33:29217 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 14:31:22218 << "With factor 1, frame shouldn't be modified.";
219
Alessio Bazzicad2b97402018-08-09 12:23:11220 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 14:31:22221 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 12:23:11222 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 14:31:22223
224 // Process for two frames to have time to ramp up gain.
225 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 11:33:29226 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 13:55:58227 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 14:31:22228 }
Per Åhgren2507f8c2020-03-19 11:33:29229 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 14:31:22230 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 10:10:09231}
232
Per Åhgrendb5d7282021-03-15 16:31:04233TEST(AudioProcessingImplTest,
234 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 09:30:54235 rtc::scoped_refptr<AudioProcessing> apm =
236 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04237 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:48247 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04248 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 09:30:54268 rtc::scoped_refptr<AudioProcessing> apm =
269 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04270 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:48280 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04281 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:44299TEST(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 09:30:54306 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44307 AudioProcessingBuilderForTesting()
308 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 09:30:54309 .Create();
Per Åhgren652ada52021-03-03 10:52:44310
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:48315 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44316 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 08:44:06381TEST(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 15:06:18385 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 08:44:06386 const auto* echo_control_factory_ptr = echo_control_factory.get();
387
Niels Möller4f776ac2021-07-02 09:30:54388 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:17389 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 08:44:06390 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 09:30:54391 .Create();
Sam Zackrisson41478c72019-10-15 08:10:26392 // Disable AGC.
Alessio Bazzicae4498052018-12-17 08:44:06393 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 08:10:26394 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 08:44:06395 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 08:44:06400 constexpr int16_t kAudioLevel = 10000;
401 constexpr size_t kSampleRateHz = 48000;
402 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 11:33:29403 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48404 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 11:33:29405 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 08:44:06406
407 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
408
Per Åhgren0aefbf02019-08-23 19:29:17409 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 08:50:31410 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29411 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 08:50:31412 .Times(1);
Per Åhgrendc5522b2020-03-19 13:55:58413 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 08:44:06414
Per Åhgren0aefbf02019-08-23 19:29:17415 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 08:50:31416 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29417 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 08:50:31418 .Times(1);
Alessio Bazzicae4498052018-12-17 08:44:06419 apm->SetRuntimeSetting(
420 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 13:55:58421 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 08:44:06422}
423
424TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04425 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 09:30:54431 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04432 AudioProcessingBuilderForTesting()
433 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 09:30:54434 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04435 // 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:48447 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04448 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 08:44:06468 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 15:06:18471 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 08:44:06472 const auto* echo_control_factory_ptr = echo_control_factory.get();
473
Niels Möller4f776ac2021-07-02 09:30:54474 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:17475 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 08:44:06476 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 09:30:54477 .Create();
Alessio Bazzicae4498052018-12-17 08:44:06478 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 08:10:26479 // Enable AGC1.
480 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 14:39:07481 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 08:44:06482 apm_config.gain_controller2.enabled = false;
483 apm_config.pre_amplifier.enabled = false;
484 apm->ApplyConfig(apm_config);
485
Alessio Bazzicae4498052018-12-17 08:44:06486 constexpr int16_t kAudioLevel = 1000;
487 constexpr size_t kSampleRateHz = 48000;
488 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 11:33:29489 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48490 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 11:33:29491 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 08:44:06492
493 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
494
Alessio Bazzicaa5aaedb2022-09-06 14:39:07495 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 19:29:17500 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 14:39:07501 EXPECT_CALL(*echo_control_mock,
502 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 10:12:29503 .Times(1);
Per Åhgrendc5522b2020-03-19 13:55:58504 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 08:44:06505
Alessio Bazzicaa5aaedb2022-09-06 14:39:07506 // 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 08:44:06511 }
Alessio Bazzicaa5aaedb2022-09-06 14:39:07512 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 08:44:06513
Alessio Bazzicaa5aaedb2022-09-06 14:39:07514 // After the first fame and with a stream analog level change, the echo path
515 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 19:29:17516 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 14:39:07517 EXPECT_CALL(*echo_control_mock,
518 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 10:12:29519 .Times(1);
Per Åhgrendc5522b2020-03-19 13:55:58520 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 08:44:06521}
522
Hanna Silen0c1ad292022-06-16 14:35:45523TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 14:39:07524 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
525 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:10526 "WebRTC-Audio-GainController2/Disabled/");
527 auto apm = AudioProcessingBuilder()
528 .SetConfig({.gain_controller1{.enabled = false}})
529 .Create();
Alessio Bazzicaa5aaedb2022-09-06 14:39:07530 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 14:35:45531 webrtc::AudioProcessing::Config apm_config;
Hanna Silen0c1ad292022-06-16 14:35:45532 apm_config.gain_controller1.enabled = false;
Hanna Silen0c1ad292022-06-16 14:35:45533 apm_config.gain_controller2.enabled = true;
534 apm_config.gain_controller2.adaptive_digital.enabled = true;
Alessio Bazzica17e14fd2022-12-07 16:08:45535 apm_config.transient_suppression.enabled = true;
Hanna Silen0c1ad292022-06-16 14:35:45536 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 14:39:07537 constexpr int kSampleRateHz = 48000;
538 constexpr int kNumChannels = 1;
539 std::array<float, kSampleRateHz / 100> buffer;
540 float* channel_pointers[] = {buffer.data()};
541 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
542 /*num_channels=*/kNumChannels);
543 Random random_generator(2341U);
544 constexpr int kFramesToProcess = 10;
545 for (int i = 0; i < kFramesToProcess; ++i) {
546 RandomizeSampleVector(&random_generator, buffer);
547 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
548 channel_pointers),
549 kNoErr);
550 }
Hanna Silen0c1ad292022-06-16 14:35:45551}
552
Alessio Bazzicaa5aaedb2022-09-06 14:39:07553TEST(AudioProcessingImplTest,
554 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 14:35:45555 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:10556 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
Hanna Silen0c1ad292022-06-16 14:35:45557 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
558 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
559 webrtc::AudioProcessing::Config apm_config;
Hanna Silen0c1ad292022-06-16 14:35:45560 apm_config.gain_controller1.enabled = false;
Hanna Silen0c1ad292022-06-16 14:35:45561 apm_config.gain_controller2.enabled = true;
562 apm_config.gain_controller2.adaptive_digital.enabled = true;
Alessio Bazzica17e14fd2022-12-07 16:08:45563 apm_config.transient_suppression.enabled = true;
Hanna Silen0c1ad292022-06-16 14:35:45564 apm->ApplyConfig(apm_config);
565 constexpr int kSampleRateHz = 48000;
566 constexpr int kNumChannels = 1;
567 std::array<float, kSampleRateHz / 100> buffer;
568 float* channel_pointers[] = {buffer.data()};
569 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
570 /*num_channels=*/kNumChannels);
571 Random random_generator(2341U);
572 constexpr int kFramesToProcess = 10;
573 for (int i = 0; i < kFramesToProcess; ++i) {
574 RandomizeSampleVector(&random_generator, buffer);
575 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
576 channel_pointers),
577 kNoErr);
578 }
579}
580
Fredrik Hernqvistca362852019-05-10 13:50:02581TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
582 // Tests that the echo controller observes an echo path gain change when a
583 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 15:06:18584 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 13:50:02585 const auto* echo_control_factory_ptr = echo_control_factory.get();
586
Niels Möller4f776ac2021-07-02 09:30:54587 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:17588 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 13:50:02589 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 09:30:54590 .Create();
Sam Zackrisson41478c72019-10-15 08:10:26591 // Disable AGC.
592 webrtc::AudioProcessing::Config apm_config;
593 apm_config.gain_controller1.enabled = false;
594 apm_config.gain_controller2.enabled = false;
595 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 13:50:02596
Fredrik Hernqvistca362852019-05-10 13:50:02597 constexpr int16_t kAudioLevel = 10000;
598 constexpr size_t kSampleRateHz = 48000;
599 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 11:33:29600 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48601 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 11:33:29602 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 13:50:02603
604 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
605
Per Åhgren0aefbf02019-08-23 19:29:17606 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 13:50:02607 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29608 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 13:50:02609 .Times(1);
Per Åhgrendc5522b2020-03-19 13:55:58610 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 13:50:02611
Per Åhgren0aefbf02019-08-23 19:29:17612 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 13:50:02613 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29614 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 13:50:02615 .Times(1);
616 apm->SetRuntimeSetting(
617 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 13:55:58618 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 13:50:02619
Per Åhgren0aefbf02019-08-23 19:29:17620 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 13:50:02621 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29622 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 13:50:02623 .Times(1);
624 apm->SetRuntimeSetting(
625 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 13:55:58626 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 13:50:02627
Per Åhgren0aefbf02019-08-23 19:29:17628 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 13:50:02629 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 10:12:29630 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 13:50:02631 .Times(1);
632 apm->SetRuntimeSetting(
633 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 13:55:58634 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 13:50:02635}
636
Alessio Bazzicad2b97402018-08-09 12:23:11637TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
638 // Make sure that signal changes caused by a render pre-processing sub-module
639 // take place before any echo detector analysis.
Tommi87f70902021-04-27 12:43:08640 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 12:23:11641 std::unique_ptr<CustomProcessing> test_render_pre_processor(
642 new TestRenderPreProcessor());
643 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 09:30:54644 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 21:56:17645 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 12:23:11646 .SetEchoDetector(test_echo_detector)
647 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 09:30:54648 .Create();
Alessio Bazzicad2b97402018-08-09 12:23:11649 webrtc::AudioProcessing::Config apm_config;
650 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 12:23:11651 apm->ApplyConfig(apm_config);
652
653 constexpr int16_t kAudioLevel = 1000;
654 constexpr int kSampleRateHz = 16000;
655 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 13:54:20656 // Explicitly initialize APM to ensure no render frames are discarded.
657 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48658 {kSampleRateHz, kNumChannels},
659 {kSampleRateHz, kNumChannels},
660 {kSampleRateHz, kNumChannels},
661 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 13:54:20662 }};
663 apm->Initialize(processing_config);
664
Per Åhgren2507f8c2020-03-19 11:33:29665 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48666 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 12:23:11667
668 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
669 constexpr float kExpectedPreprocessedAudioLevel =
670 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
671 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
672
673 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 11:33:29674 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 12:23:11675 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 11:33:29676 apm->ProcessReverseStream(frame.data(), stream_config,
677 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 12:23:11678 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
679 // ProcessStream().
Per Åhgren2507f8c2020-03-19 11:33:29680 frame.fill(kAudioLevel);
681 ASSERT_EQ(AudioProcessing::Error::kNoError,
682 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 13:55:58683 frame.data()));
Alessio Bazzicad2b97402018-08-09 12:23:11684 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
685 // triggered, the line below checks that the call has occurred. If not, the
686 // APM implementation may have changed and this test might need to be adapted.
687 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
688 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
689 // produced by the render pre-processor.
690 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
691 test_echo_detector->last_render_audio_first_sample());
692}
693
Sam Zackrissonb37e59d2020-04-27 06:39:33694// Disabling build-optional submodules and trying to enable them via the APM
695// config should be bit-exact with running APM with said submodules disabled.
696// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
697TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 06:26:10698 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 06:39:33699 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
700
701 ApmSubmoduleCreationOverrides overrides;
702 overrides.transient_suppression = true;
703 apm->OverrideSubmoduleCreationForTesting(overrides);
704
705 AudioProcessing::Config apm_config = apm->GetConfig();
706 apm_config.transient_suppression.enabled = true;
707 apm->ApplyConfig(apm_config);
708
709 rtc::scoped_refptr<AudioProcessing> apm_reference =
710 AudioProcessingBuilder().Create();
711 apm_config = apm_reference->GetConfig();
712 apm_config.transient_suppression.enabled = false;
713 apm_reference->ApplyConfig(apm_config);
714
715 constexpr int kSampleRateHz = 16000;
716 constexpr int kNumChannels = 1;
717 std::array<float, kSampleRateHz / 100> buffer;
718 std::array<float, kSampleRateHz / 100> buffer_reference;
719 float* channel_pointers[] = {buffer.data()};
720 float* channel_pointers_reference[] = {buffer_reference.data()};
721 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48722 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 06:39:33723 Random random_generator(2341U);
724 constexpr int kFramesToProcessPerConfiguration = 10;
725
726 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
727 RandomizeSampleVector(&random_generator, buffer);
728 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
729 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
730 channel_pointers),
731 kNoErr);
732 ASSERT_EQ(
733 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
734 stream_config, channel_pointers_reference),
735 kNoErr);
736 for (int j = 0; j < kSampleRateHz / 100; ++j) {
737 EXPECT_EQ(buffer[j], buffer_reference[j]);
738 }
739 }
740}
741
742// Disable transient suppressor creation and run APM in ways that should trigger
743// calls to the transient suppressor API.
744TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 06:26:10745 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 06:39:33746 ASSERT_EQ(apm->Initialize(), kNoErr);
747
748 ApmSubmoduleCreationOverrides overrides;
749 overrides.transient_suppression = true;
750 apm->OverrideSubmoduleCreationForTesting(overrides);
751
752 AudioProcessing::Config config = apm->GetConfig();
753 config.transient_suppression.enabled = true;
754 apm->ApplyConfig(config);
755 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
756 float buffer[960];
757 float* channel_pointers[] = {&buffer[0], &buffer[480]};
758 Random random_generator(2341U);
759 constexpr int kFramesToProcessPerConfiguration = 3;
760
761 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48762 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 06:39:33763 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
764 RandomizeSampleVector(&random_generator, buffer);
765 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
766 initial_stream_config, channel_pointers),
767 kNoErr);
768 }
769
770 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48771 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 06:39:33772 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
773 RandomizeSampleVector(&random_generator, buffer);
774 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
775 stereo_stream_config, channel_pointers),
776 kNoErr);
777 }
778
779 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48780 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 06:39:33781 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
782 RandomizeSampleVector(&random_generator, buffer);
783 EXPECT_EQ(
784 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
785 high_sample_rate_stream_config, channel_pointers),
786 kNoErr);
787 }
Sam Zackrissonb37e59d2020-04-27 06:39:33788}
789
790// Disable transient suppressor creation and run APM in ways that should trigger
791// calls to the transient suppressor API.
792TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 06:26:10793 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 06:39:33794 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
795
796 ApmSubmoduleCreationOverrides overrides;
797 overrides.transient_suppression = true;
798 apm->OverrideSubmoduleCreationForTesting(overrides);
799
800 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
801 float buffer[960];
802 float* channel_pointers[] = {&buffer[0], &buffer[480]};
803 Random random_generator(2341U);
804 constexpr int kFramesToProcessPerConfiguration = 3;
805 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48806 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 06:39:33807
808 AudioProcessing::Config config = apm->GetConfig();
809 config.transient_suppression.enabled = true;
810 apm->ApplyConfig(config);
811 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
812 RandomizeSampleVector(&random_generator, buffer);
813 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
814 channel_pointers),
815 kNoErr);
816 }
817
818 config = apm->GetConfig();
819 config.transient_suppression.enabled = false;
820 apm->ApplyConfig(config);
821 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
822 RandomizeSampleVector(&random_generator, buffer);
823 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
824 channel_pointers),
825 kNoErr);
826 }
827
828 config = apm->GetConfig();
829 config.transient_suppression.enabled = true;
830 apm->ApplyConfig(config);
831 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
832 RandomizeSampleVector(&random_generator, buffer);
833 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
834 channel_pointers),
835 kNoErr);
836 }
837}
Hanna Silenc69188d2022-09-16 09:38:56838
Alessio Bazzica4f26c252022-12-20 12:46:01839class StartupInputVolumeParameterizedTest
840 : public ::testing::TestWithParam<int> {};
841
842// Tests that, when no input volume controller is used, the startup input volume
843// is never modified.
844TEST_P(StartupInputVolumeParameterizedTest,
845 WithNoInputVolumeControllerStartupVolumeNotModified) {
846 webrtc::AudioProcessing::Config config;
847 config.gain_controller1.enabled = false;
848 config.gain_controller2.enabled = false;
849 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
850
851 int startup_volume = GetParam();
852 int recommended_volume = ProcessInputVolume(
853 *apm, /*num_frames=*/1, /*initial_volume=*/startup_volume);
854 EXPECT_EQ(recommended_volume, startup_volume);
855}
856
857INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
858 StartupInputVolumeParameterizedTest,
859 ::testing::Values(0, 5, 15, 50, 100));
860
861// Tests that, when no input volume controller is used, the recommended input
862// volume always matches the applied one.
863TEST(AudioProcessingImplTest,
864 WithNoInputVolumeControllerAppliedAndRecommendedVolumesMatch) {
865 webrtc::AudioProcessing::Config config;
866 config.gain_controller1.enabled = false;
867 config.gain_controller2.enabled = false;
868 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
869
870 Random rand_gen(42);
871 for (int i = 0; i < 32; ++i) {
872 SCOPED_TRACE(i);
873 int32_t applied_volume = rand_gen.Rand(/*low=*/0, /*high=*/255);
874 int recommended_volume =
875 ProcessInputVolume(*apm, /*num_frames=*/1, applied_volume);
876 EXPECT_EQ(recommended_volume, applied_volume);
877 }
878}
879
Alessio Bazzica3b51cd32022-12-14 15:36:10880class ApmInputVolumeControllerParametrizedTest
881 : public ::testing::TestWithParam<
882 std::tuple<int, int, AudioProcessing::Config>> {
883 protected:
884 ApmInputVolumeControllerParametrizedTest()
885 : sample_rate_hz_(std::get<0>(GetParam())),
886 num_channels_(std::get<1>(GetParam())),
887 channels_(num_channels_),
888 channel_pointers_(num_channels_) {
889 const int frame_size = sample_rate_hz_ / 100;
890 for (int c = 0; c < num_channels_; ++c) {
891 channels_[c].resize(frame_size);
892 channel_pointers_[c] = channels_[c].data();
893 std::fill(channels_[c].begin(), channels_[c].end(), 0.0f);
Hanna Silend4dbe452022-11-30 14:16:21894 }
Hanna Silenc69188d2022-09-16 09:38:56895 }
Alessio Bazzica3b51cd32022-12-14 15:36:10896
897 int sample_rate_hz() const { return sample_rate_hz_; }
898 int num_channels() const { return num_channels_; }
899 AudioProcessing::Config GetConfig() const { return std::get<2>(GetParam()); }
900
901 float* const* channel_pointers() { return channel_pointers_.data(); }
902
903 private:
904 const int sample_rate_hz_;
905 const int num_channels_;
906 std::vector<std::vector<float>> channels_;
907 std::vector<float*> channel_pointers_;
908};
909
910TEST_P(ApmInputVolumeControllerParametrizedTest,
911 EnforceMinInputVolumeAtStartupWithZeroVolume) {
912 const StreamConfig stream_config(sample_rate_hz(), num_channels());
913 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
914
915 apm->set_stream_analog_level(0);
916 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
917 channel_pointers());
918 EXPECT_GT(apm->recommended_stream_analog_level(), 0);
Hanna Silenc69188d2022-09-16 09:38:56919}
920
Alessio Bazzica3b51cd32022-12-14 15:36:10921TEST_P(ApmInputVolumeControllerParametrizedTest,
922 EnforceMinInputVolumeAtStartupWithNonZeroVolume) {
923 const StreamConfig stream_config(sample_rate_hz(), num_channels());
924 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
Hanna Silenc69188d2022-09-16 09:38:56925
Alessio Bazzica3b51cd32022-12-14 15:36:10926 constexpr int kStartupVolume = 3;
927 apm->set_stream_analog_level(kStartupVolume);
928 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
929 channel_pointers());
930 EXPECT_GT(apm->recommended_stream_analog_level(), kStartupVolume);
931}
Hanna Silenc69188d2022-09-16 09:38:56932
Alessio Bazzica3b51cd32022-12-14 15:36:10933TEST_P(ApmInputVolumeControllerParametrizedTest,
934 EnforceMinInputVolumeAfterManualVolumeAdjustment) {
935 const auto config = GetConfig();
936 if (config.gain_controller1.enabled) {
937 // After a downward manual adjustment, AGC1 slowly converges to the minimum
938 // input volume.
939 GTEST_SKIP() << "Does not apply to AGC1";
Hanna Silend4dbe452022-11-30 14:16:21940 }
Alessio Bazzica3b51cd32022-12-14 15:36:10941 const StreamConfig stream_config(sample_rate_hz(), num_channels());
942 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
943
944 apm->set_stream_analog_level(20);
945 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
946 channel_pointers());
947 constexpr int kManuallyAdjustedVolume = 3;
948 apm->set_stream_analog_level(kManuallyAdjustedVolume);
949 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
950 channel_pointers());
951 EXPECT_GT(apm->recommended_stream_analog_level(), kManuallyAdjustedVolume);
Hanna Silenc69188d2022-09-16 09:38:56952}
953
Alessio Bazzica3b51cd32022-12-14 15:36:10954TEST_P(ApmInputVolumeControllerParametrizedTest,
Alessio Bazzica4f26c252022-12-20 12:46:01955 DoNotEnforceMinInputVolumeAtStartupWithHighVolume) {
956 const StreamConfig stream_config(sample_rate_hz(), num_channels());
957 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
958
959 constexpr int kStartupVolume = 200;
960 apm->set_stream_analog_level(kStartupVolume);
961 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
962 channel_pointers());
963 EXPECT_EQ(apm->recommended_stream_analog_level(), kStartupVolume);
964}
965
966TEST_P(ApmInputVolumeControllerParametrizedTest,
Alessio Bazzica3b51cd32022-12-14 15:36:10967 DoNotEnforceMinInputVolumeAfterManualVolumeAdjustmentToZero) {
968 const StreamConfig stream_config(sample_rate_hz(), num_channels());
969 auto apm = AudioProcessingBuilder().SetConfig(GetConfig()).Create();
Hanna Silenc69188d2022-09-16 09:38:56970
Alessio Bazzica3b51cd32022-12-14 15:36:10971 apm->set_stream_analog_level(100);
972 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
973 channel_pointers());
974 apm->set_stream_analog_level(0);
975 apm->ProcessStream(channel_pointers(), stream_config, stream_config,
976 channel_pointers());
977 EXPECT_EQ(apm->recommended_stream_analog_level(), 0);
Hanna Silenc69188d2022-09-16 09:38:56978}
979
Alessio Bazzica3b51cd32022-12-14 15:36:10980INSTANTIATE_TEST_SUITE_P(
981 AudioProcessingImplTest,
982 ApmInputVolumeControllerParametrizedTest,
983 ::testing::Combine(
984 ::testing::Values(8000, 16000, 32000, 48000), // Sample rates.
985 ::testing::Values(1, 2), // Number of channels.
986 ::testing::Values(
987 // Full AGC1.
988 AudioProcessing::Config{
989 .gain_controller1 = {.enabled = true,
990 .analog_gain_controller =
991 {.enabled = true,
992 .enable_digital_adaptive = true}},
993 .gain_controller2 = {.enabled = false}},
994 // Hybrid AGC.
995 AudioProcessing::Config{
996 .gain_controller1 = {.enabled = true,
997 .analog_gain_controller =
998 {.enabled = true,
999 .enable_digital_adaptive = false}},
1000 .gain_controller2 = {.enabled = true,
1001 .adaptive_digital = {.enabled = true}}})));
Hanna Silenc69188d2022-09-16 09:38:561002
Alessio Bazzica79beaa72022-10-31 15:42:341003// When the input volume is not emulated and no input volume controller is
1004// active, the recommended volume must always be the applied volume.
1005TEST(AudioProcessingImplTest,
1006 RecommendAppliedInputVolumeWithNoAgcWithNoEmulation) {
1007 auto apm = AudioProcessingBuilder()
1008 .SetConfig({.capture_level_adjustment = {.enabled = false},
1009 .gain_controller1 = {.enabled = false}})
1010 .Create();
1011
1012 constexpr int kOneFrame = 1;
1013 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1014 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1015 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1016}
1017
1018// When the input volume is emulated, the recommended volume must always be the
1019// applied volume and at any time it must not be that set in the input volume
1020// emulator.
1021// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1022TEST(AudioProcessingImplTest,
1023 DISABLED_RecommendAppliedInputVolumeWithNoAgcWithEmulation) {
1024 auto apm =
1025 AudioProcessingBuilder()
1026 .SetConfig({.capture_level_adjustment = {.enabled = true,
1027 .analog_mic_gain_emulation{
1028 .enabled = true,
1029 .initial_level = 255}},
1030 .gain_controller1 = {.enabled = false}})
1031 .Create();
1032
1033 constexpr int kOneFrame = 1;
1034 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1035 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1036 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1037}
1038
1039// Even if there is an enabled input volume controller, when the input volume is
1040// emulated, the recommended volume is always the applied volume because the
1041// active controller must only adjust the internally emulated volume and leave
1042// the externally applied volume unchanged.
1043// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1044TEST(AudioProcessingImplTest,
1045 DISABLED_RecommendAppliedInputVolumeWithAgcWithEmulation) {
1046 auto apm =
1047 AudioProcessingBuilder()
1048 .SetConfig({.capture_level_adjustment = {.enabled = true,
1049 .analog_mic_gain_emulation{
1050 .enabled = true}},
1051 .gain_controller1 = {.enabled = true,
1052 .analog_gain_controller{
1053 .enabled = true,
1054 }}})
1055 .Create();
1056
1057 constexpr int kOneFrame = 1;
1058 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1059 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1060 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1061}
1062
Alessio Bazzica3b51cd32022-12-14 15:36:101063TEST(AudioProcessingImplTest,
1064 Agc2FieldTrialDoNotSwitchToFullAgc2WhenNoAgcIsActive) {
1065 constexpr AudioProcessing::Config kOriginal{
1066 .gain_controller1{.enabled = false},
1067 .gain_controller2{.enabled = false},
1068 };
1069 webrtc::test::ScopedFieldTrials field_trials(
1070 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1071
1072 // Test config application via `AudioProcessing` ctor.
1073 auto adjusted =
1074 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1075 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1076 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1077
1078 // Test config application via `AudioProcessing::ApplyConfig()`.
1079 auto apm = AudioProcessingBuilder().Create();
1080 apm->ApplyConfig(kOriginal);
1081 adjusted = apm->GetConfig();
1082 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1083 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1084}
1085
1086TEST(AudioProcessingImplTest,
1087 Agc2FieldTrialDoNotSwitchToFullAgc2WithAgc1Agc2InputVolumeControllers) {
1088 constexpr AudioProcessing::Config kOriginal{
1089 .gain_controller1{.enabled = true,
1090 .analog_gain_controller{.enabled = true}},
1091 .gain_controller2{.enabled = true,
1092 .input_volume_controller{.enabled = true}},
1093 };
1094 webrtc::test::ScopedFieldTrials field_trials(
1095 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1096
1097 // Test config application via `AudioProcessing` ctor.
1098 auto adjusted =
1099 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1100 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1101 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1102
1103 // Test config application via `AudioProcessing::ApplyConfig()`.
1104 auto apm = AudioProcessingBuilder().Create();
1105 apm->ApplyConfig(kOriginal);
1106 adjusted = apm->GetConfig();
1107 EXPECT_EQ(adjusted.gain_controller1, kOriginal.gain_controller1);
1108 EXPECT_EQ(adjusted.gain_controller2, kOriginal.gain_controller2);
1109}
1110
1111class Agc2FieldTrialParametrizedTest
Alessio Bazzicadfba28e2022-12-09 09:02:411112 : public ::testing::TestWithParam<AudioProcessing::Config> {};
1113
Alessio Bazzica3b51cd32022-12-14 15:36:101114TEST_P(Agc2FieldTrialParametrizedTest, DoNotChangeConfigIfDisabled) {
1115 const AudioProcessing::Config original = GetParam();
Alessio Bazzicadfba28e2022-12-09 09:02:411116 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:101117 "WebRTC-Audio-GainController2/Disabled/");
1118
1119 // Test config application via `AudioProcessing` ctor.
1120 auto adjusted =
1121 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1122 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1123 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1124
1125 // Test config application via `AudioProcessing::ApplyConfig()`.
1126 auto apm = AudioProcessingBuilder().Create();
1127 apm->ApplyConfig(original);
1128 adjusted = apm->GetConfig();
1129 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1130 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1131}
1132
1133TEST_P(Agc2FieldTrialParametrizedTest, DoNotChangeConfigIfNoOverride) {
1134 const AudioProcessing::Config original = GetParam();
1135 webrtc::test::ScopedFieldTrials field_trials(
1136 "WebRTC-Audio-GainController2/Enabled,"
1137 "switch_to_agc2:false,"
1138 "disallow_transient_suppressor_usage:false/");
1139
1140 // Test config application via `AudioProcessing` ctor.
1141 auto adjusted =
1142 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1143 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1144 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1145
1146 // Test config application via `AudioProcessing::ApplyConfig()`.
1147 auto apm = AudioProcessingBuilder().Create();
1148 apm->ApplyConfig(original);
1149 adjusted = apm->GetConfig();
1150 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1151 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1152}
1153
1154TEST_P(Agc2FieldTrialParametrizedTest, DoNotSwitchToFullAgc2) {
1155 const AudioProcessing::Config original = GetParam();
1156 webrtc::test::ScopedFieldTrials field_trials(
1157 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:false/");
1158
1159 // Test config application via `AudioProcessing` ctor.
1160 auto adjusted =
1161 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1162 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1163 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1164
1165 // Test config application via `AudioProcessing::ApplyConfig()`.
1166 auto apm = AudioProcessingBuilder().Create();
1167 apm->ApplyConfig(original);
1168 adjusted = apm->GetConfig();
1169 EXPECT_EQ(adjusted.gain_controller1, original.gain_controller1);
1170 EXPECT_EQ(adjusted.gain_controller2, original.gain_controller2);
1171}
1172
1173TEST_P(Agc2FieldTrialParametrizedTest, SwitchToFullAgc2) {
1174 const AudioProcessing::Config original = GetParam();
1175 webrtc::test::ScopedFieldTrials field_trials(
1176 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true/");
1177
1178 // Test config application via `AudioProcessing` ctor.
1179 auto adjusted =
1180 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1181 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1182 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1183 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1184 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1185
1186 // Test config application via `AudioProcessing::ApplyConfig()`.
1187 auto apm = AudioProcessingBuilder().Create();
1188 apm->ApplyConfig(original);
1189 adjusted = apm->GetConfig();
1190 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1191 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1192 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1193 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1194}
1195
1196TEST_P(Agc2FieldTrialParametrizedTest,
1197 SwitchToFullAgc2AndOverrideInputVolumeControllerParameters) {
1198 const AudioProcessing::Config original = GetParam();
1199 webrtc::test::ScopedFieldTrials field_trials(
1200 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true,"
1201 "min_input_volume:123,"
Alessio Bazzicadfba28e2022-12-09 09:02:411202 "clipped_level_min:20,"
1203 "clipped_level_step:30,"
1204 "clipped_ratio_threshold:0.4,"
1205 "clipped_wait_frames:50,"
Alessio Bazzica3b51cd32022-12-14 15:36:101206 "enable_clipping_predictor:true,"
Alessio Bazzicadfba28e2022-12-09 09:02:411207 "target_range_max_dbfs:-6,"
1208 "target_range_min_dbfs:-70,"
1209 "update_input_volume_wait_frames:80,"
1210 "speech_probability_threshold:0.9,"
Alessio Bazzica3b51cd32022-12-14 15:36:101211 "speech_ratio_threshold:1.0/");
1212
1213 // Test config application via `AudioProcessing` ctor.
1214 auto adjusted =
1215 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1216 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1217 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1218 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1219 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1220
1221 // Test config application via `AudioProcessing::ApplyConfig()`.
1222 auto apm = AudioProcessingBuilder().Create();
1223 apm->ApplyConfig(original);
1224 adjusted = apm->GetConfig();
1225 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1226 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1227 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1228 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1229}
1230
1231TEST_P(Agc2FieldTrialParametrizedTest,
1232 SwitchToFullAgc2AndOverrideAdaptiveDigitalControllerParameters) {
1233 const AudioProcessing::Config original = GetParam();
1234 webrtc::test::ScopedFieldTrials field_trials(
1235 "WebRTC-Audio-GainController2/Enabled,switch_to_agc2:true,"
Alessio Bazzicadfba28e2022-12-09 09:02:411236 "headroom_db:10,"
1237 "max_gain_db:20,"
1238 "initial_gain_db:7,"
1239 "max_gain_change_db_per_second:5,"
1240 "max_output_noise_level_dbfs:-40/");
1241
Alessio Bazzica3b51cd32022-12-14 15:36:101242 // Test config application via `AudioProcessing` ctor.
1243 auto adjusted =
1244 AudioProcessingBuilder().SetConfig(original).Create()->GetConfig();
1245 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1246 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1247 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1248 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1249 ASSERT_NE(adjusted.gain_controller2.adaptive_digital,
1250 original.gain_controller2.adaptive_digital);
1251 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.headroom_db, 10);
1252 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.max_gain_db, 20);
1253 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.initial_gain_db, 7);
1254 EXPECT_EQ(
1255 adjusted.gain_controller2.adaptive_digital.max_gain_change_db_per_second,
1256 5);
1257 EXPECT_EQ(
1258 adjusted.gain_controller2.adaptive_digital.max_output_noise_level_dbfs,
1259 -40);
Alessio Bazzicadfba28e2022-12-09 09:02:411260
Alessio Bazzica3b51cd32022-12-14 15:36:101261 // Test config application via `AudioProcessing::ApplyConfig()`.
1262 auto apm = AudioProcessingBuilder().Create();
1263 apm->ApplyConfig(original);
1264 adjusted = apm->GetConfig();
1265 EXPECT_FALSE(adjusted.gain_controller1.enabled);
1266 EXPECT_TRUE(adjusted.gain_controller2.enabled);
1267 EXPECT_TRUE(adjusted.gain_controller2.input_volume_controller.enabled);
1268 EXPECT_TRUE(adjusted.gain_controller2.adaptive_digital.enabled);
1269 ASSERT_NE(adjusted.gain_controller2.adaptive_digital,
1270 original.gain_controller2.adaptive_digital);
1271 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.headroom_db, 10);
1272 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.max_gain_db, 20);
1273 EXPECT_EQ(adjusted.gain_controller2.adaptive_digital.initial_gain_db, 7);
1274 EXPECT_EQ(
1275 adjusted.gain_controller2.adaptive_digital.max_gain_change_db_per_second,
1276 5);
1277 EXPECT_EQ(
1278 adjusted.gain_controller2.adaptive_digital.max_output_noise_level_dbfs,
1279 -40);
1280}
Alessio Bazzicadfba28e2022-12-09 09:02:411281
Alessio Bazzica3b51cd32022-12-14 15:36:101282TEST_P(Agc2FieldTrialParametrizedTest, ProcessSucceedsWithTs) {
1283 AudioProcessing::Config config = GetParam();
Alessio Bazzica40b5bd72023-01-16 19:19:481284 if (!config.transient_suppression.enabled) {
1285 GTEST_SKIP() << "TS is disabled, skip.";
1286 }
1287
Alessio Bazzica3b51cd32022-12-14 15:36:101288 webrtc::test::ScopedFieldTrials field_trials(
1289 "WebRTC-Audio-GainController2/Disabled/");
1290 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
1291
1292 constexpr int kSampleRateHz = 48000;
1293 constexpr int kNumChannels = 1;
1294 std::array<float, kSampleRateHz / 100> buffer;
1295 float* channel_pointers[] = {buffer.data()};
1296 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1297 Random random_generator(2341U);
1298 constexpr int kFramesToProcess = 10;
1299 int volume = 100;
1300 for (int i = 0; i < kFramesToProcess; ++i) {
1301 SCOPED_TRACE(i);
1302 RandomizeSampleVector(&random_generator, buffer);
1303 apm->set_stream_analog_level(volume);
1304 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1305 channel_pointers),
1306 kNoErr);
1307 volume = apm->recommended_stream_analog_level();
1308 }
1309}
1310
1311TEST_P(Agc2FieldTrialParametrizedTest, ProcessSucceedsWithoutTs) {
1312 webrtc::test::ScopedFieldTrials field_trials(
1313 "WebRTC-Audio-GainController2/Enabled,"
1314 "switch_to_agc2:false,"
1315 "disallow_transient_suppressor_usage:true/");
1316 auto apm = AudioProcessingBuilder().SetConfig(GetParam()).Create();
1317
1318 constexpr int kSampleRateHz = 48000;
1319 constexpr int kNumChannels = 1;
1320 std::array<float, kSampleRateHz / 100> buffer;
1321 float* channel_pointers[] = {buffer.data()};
1322 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1323 Random random_generator(2341U);
1324 constexpr int kFramesToProcess = 10;
1325 int volume = 100;
1326 for (int i = 0; i < kFramesToProcess; ++i) {
1327 SCOPED_TRACE(i);
1328 RandomizeSampleVector(&random_generator, buffer);
1329 apm->set_stream_analog_level(volume);
1330 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1331 channel_pointers),
1332 kNoErr);
1333 volume = apm->recommended_stream_analog_level();
1334 }
1335}
1336
1337TEST_P(Agc2FieldTrialParametrizedTest,
1338 ProcessSucceedsWhenSwitchToFullAgc2WithTs) {
1339 AudioProcessing::Config config = GetParam();
Alessio Bazzica40b5bd72023-01-16 19:19:481340 if (!config.transient_suppression.enabled) {
1341 GTEST_SKIP() << "TS is disabled, skip.";
1342 }
1343
Alessio Bazzica3b51cd32022-12-14 15:36:101344 webrtc::test::ScopedFieldTrials field_trials(
1345 "WebRTC-Audio-GainController2/Enabled,"
1346 "switch_to_agc2:true,"
1347 "disallow_transient_suppressor_usage:false/");
1348 auto apm = AudioProcessingBuilder().SetConfig(config).Create();
1349
1350 constexpr int kSampleRateHz = 48000;
1351 constexpr int kNumChannels = 1;
1352 std::array<float, kSampleRateHz / 100> buffer;
1353 float* channel_pointers[] = {buffer.data()};
1354 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1355 Random random_generator(2341U);
1356 constexpr int kFramesToProcess = 10;
1357 int volume = 100;
1358 for (int i = 0; i < kFramesToProcess; ++i) {
1359 SCOPED_TRACE(i);
1360 RandomizeSampleVector(&random_generator, buffer);
1361 apm->set_stream_analog_level(volume);
1362 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1363 channel_pointers),
1364 kNoErr);
1365 volume = apm->recommended_stream_analog_level();
1366 }
1367}
1368
1369TEST_P(Agc2FieldTrialParametrizedTest,
1370 ProcessSucceedsWhenSwitchToFullAgc2WithoutTs) {
1371 webrtc::test::ScopedFieldTrials field_trials(
1372 "WebRTC-Audio-GainController2/Enabled,"
1373 "switch_to_agc2:true,"
1374 "disallow_transient_suppressor_usage:true/");
1375 auto apm = AudioProcessingBuilder().SetConfig(GetParam()).Create();
1376
1377 constexpr int kSampleRateHz = 48000;
1378 constexpr int kNumChannels = 1;
1379 std::array<float, kSampleRateHz / 100> buffer;
1380 float* channel_pointers[] = {buffer.data()};
1381 StreamConfig stream_config(kSampleRateHz, kNumChannels);
1382 Random random_generator(2341U);
1383 constexpr int kFramesToProcess = 10;
1384 int volume = 100;
1385 for (int i = 0; i < kFramesToProcess; ++i) {
1386 SCOPED_TRACE(i);
1387 RandomizeSampleVector(&random_generator, buffer);
1388 apm->set_stream_analog_level(volume);
1389 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
1390 channel_pointers),
1391 kNoErr);
1392 volume = apm->recommended_stream_analog_level();
1393 }
Alessio Bazzicadfba28e2022-12-09 09:02:411394}
1395
1396INSTANTIATE_TEST_SUITE_P(
1397 AudioProcessingImplTest,
Alessio Bazzica3b51cd32022-12-14 15:36:101398 Agc2FieldTrialParametrizedTest,
Alessio Bazzicadfba28e2022-12-09 09:02:411399 ::testing::Values(
Alessio Bazzica40b5bd72023-01-16 19:19:481400 // Full AGC1, TS disabled.
Alessio Bazzicadfba28e2022-12-09 09:02:411401 AudioProcessing::Config{
Alessio Bazzica40b5bd72023-01-16 19:19:481402 .transient_suppression = {.enabled = false},
Alessio Bazzicadfba28e2022-12-09 09:02:411403 .gain_controller1 =
1404 {.enabled = true,
1405 .analog_gain_controller = {.enabled = true,
1406 .enable_digital_adaptive = true}},
1407 .gain_controller2 = {.enabled = false}},
Alessio Bazzica40b5bd72023-01-16 19:19:481408 // Full AGC1, TS enabled.
Alessio Bazzicadfba28e2022-12-09 09:02:411409 AudioProcessing::Config{
Alessio Bazzica40b5bd72023-01-16 19:19:481410 .transient_suppression = {.enabled = true},
1411 .gain_controller1 =
1412 {.enabled = true,
1413 .analog_gain_controller = {.enabled = true,
1414 .enable_digital_adaptive = true}},
1415 .gain_controller2 = {.enabled = false}},
1416 // Hybrid AGC, TS disabled.
1417 AudioProcessing::Config{
1418 .transient_suppression = {.enabled = false},
1419 .gain_controller1 =
1420 {.enabled = true,
1421 .analog_gain_controller = {.enabled = true,
1422 .enable_digital_adaptive = false}},
1423 .gain_controller2 = {.enabled = true,
1424 .adaptive_digital = {.enabled = true}}},
1425 // Hybrid AGC, TS enabled.
1426 AudioProcessing::Config{
1427 .transient_suppression = {.enabled = true},
Alessio Bazzicadfba28e2022-12-09 09:02:411428 .gain_controller1 =
1429 {.enabled = true,
1430 .analog_gain_controller = {.enabled = true,
1431 .enable_digital_adaptive = false}},
1432 .gain_controller2 = {.enabled = true,
1433 .adaptive_digital = {.enabled = true}}}));
1434
Alessio Bazzica3b51cd32022-12-14 15:36:101435TEST(AudioProcessingImplTest, CanDisableTransientSuppressor) {
1436 constexpr AudioProcessing::Config kOriginal = {
1437 .transient_suppression = {.enabled = false}};
1438
1439 // Test config application via `AudioProcessing` ctor.
1440 auto adjusted =
1441 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1442 EXPECT_FALSE(adjusted.transient_suppression.enabled);
1443
1444 // Test config application via `AudioProcessing::ApplyConfig()`.
1445 auto apm = AudioProcessingBuilder().Create();
1446 apm->ApplyConfig(kOriginal);
1447 adjusted = apm->GetConfig();
1448 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
1449}
1450
1451TEST(AudioProcessingImplTest, CanEnableTs) {
1452 constexpr AudioProcessing::Config kOriginal = {
1453 .transient_suppression = {.enabled = true}};
1454
1455 // Test config application via `AudioProcessing` ctor.
1456 auto adjusted =
1457 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1458 EXPECT_TRUE(adjusted.transient_suppression.enabled);
1459
1460 // Test config application via `AudioProcessing::ApplyConfig()`.
1461 auto apm = AudioProcessingBuilder().Create();
1462 apm->ApplyConfig(kOriginal);
1463 adjusted = apm->GetConfig();
1464 EXPECT_TRUE(adjusted.transient_suppression.enabled);
1465}
1466
1467TEST(AudioProcessingImplTest, CanDisableTsWithAgc2FieldTrialDisabled) {
1468 constexpr AudioProcessing::Config kOriginal = {
1469 .transient_suppression = {.enabled = false}};
Hanna Silena6574902022-11-30 15:59:051470 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:101471 "WebRTC-Audio-GainController2/Disabled/");
Hanna Silena6574902022-11-30 15:59:051472
Alessio Bazzica3b51cd32022-12-14 15:36:101473 // Test config application via `AudioProcessing` ctor.
1474 auto adjusted =
1475 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1476 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051477
Alessio Bazzica3b51cd32022-12-14 15:36:101478 // Test config application via `AudioProcessing::ApplyConfig()`.
1479 auto apm = AudioProcessingBuilder().Create();
1480 apm->ApplyConfig(kOriginal);
1481 adjusted = apm->GetConfig();
1482 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051483}
1484
Alessio Bazzica3b51cd32022-12-14 15:36:101485TEST(AudioProcessingImplTest, CanEnableTsWithAgc2FieldTrialDisabled) {
1486 constexpr AudioProcessing::Config kOriginal = {
1487 .transient_suppression = {.enabled = true}};
Hanna Silena6574902022-11-30 15:59:051488 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:101489 "WebRTC-Audio-GainController2/Disabled/");
Hanna Silena6574902022-11-30 15:59:051490
Alessio Bazzica3b51cd32022-12-14 15:36:101491 // Test config application via `AudioProcessing` ctor.
1492 auto adjusted =
1493 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1494 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051495
Alessio Bazzica3b51cd32022-12-14 15:36:101496 // Test config application via `AudioProcessing::ApplyConfig()`.
1497 auto apm = AudioProcessingBuilder().Create();
1498 apm->ApplyConfig(kOriginal);
1499 adjusted = apm->GetConfig();
1500 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051501}
1502
Alessio Bazzica3b51cd32022-12-14 15:36:101503TEST(AudioProcessingImplTest,
1504 CanDisableTsWithAgc2FieldTrialEnabledAndUsageAllowed) {
1505 constexpr AudioProcessing::Config kOriginal = {
1506 .transient_suppression = {.enabled = false}};
Hanna Silena6574902022-11-30 15:59:051507 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:101508 "WebRTC-Audio-GainController2/Enabled,"
1509 "disallow_transient_suppressor_usage:false/");
Hanna Silena6574902022-11-30 15:59:051510
Alessio Bazzica3b51cd32022-12-14 15:36:101511 // Test config application via `AudioProcessing` ctor.
1512 auto adjusted =
1513 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1514 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051515
Alessio Bazzica3b51cd32022-12-14 15:36:101516 // Test config application via `AudioProcessing::ApplyConfig()`.
1517 auto apm = AudioProcessingBuilder().Create();
1518 apm->ApplyConfig(kOriginal);
1519 adjusted = apm->GetConfig();
1520 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051521}
1522
Alessio Bazzica3b51cd32022-12-14 15:36:101523TEST(AudioProcessingImplTest,
1524 CanEnableTsWithAgc2FieldTrialEnabledAndUsageAllowed) {
1525 constexpr AudioProcessing::Config kOriginal = {
1526 .transient_suppression = {.enabled = true}};
Hanna Silena6574902022-11-30 15:59:051527 webrtc::test::ScopedFieldTrials field_trials(
Alessio Bazzica3b51cd32022-12-14 15:36:101528 "WebRTC-Audio-GainController2/Enabled,"
1529 "disallow_transient_suppressor_usage:false/");
Hanna Silena6574902022-11-30 15:59:051530
Alessio Bazzica3b51cd32022-12-14 15:36:101531 // Test config application via `AudioProcessing` ctor.
1532 auto adjusted =
1533 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1534 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051535
Alessio Bazzica3b51cd32022-12-14 15:36:101536 // Test config application via `AudioProcessing::ApplyConfig()`.
1537 auto apm = AudioProcessingBuilder().Create();
1538 apm->ApplyConfig(kOriginal);
1539 adjusted = apm->GetConfig();
1540 EXPECT_TRUE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051541}
1542
Alessio Bazzica3b51cd32022-12-14 15:36:101543TEST(AudioProcessingImplTest,
1544 CannotEnableTsWithAgc2FieldTrialEnabledAndUsageDisallowed) {
1545 constexpr AudioProcessing::Config kOriginal = {
1546 .transient_suppression = {.enabled = true}};
1547 webrtc::test::ScopedFieldTrials field_trials(
1548 "WebRTC-Audio-GainController2/Enabled,"
1549 "disallow_transient_suppressor_usage:true/");
Hanna Silena6574902022-11-30 15:59:051550
Alessio Bazzica3b51cd32022-12-14 15:36:101551 // Test config application via `AudioProcessing` ctor.
1552 auto adjusted =
1553 AudioProcessingBuilder().SetConfig(kOriginal).Create()->GetConfig();
1554 EXPECT_FALSE(adjusted.transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051555
Alessio Bazzica3b51cd32022-12-14 15:36:101556 // Test config application via `AudioProcessing::ApplyConfig()`.
1557 auto apm = AudioProcessingBuilder().Create();
1558 apm->ApplyConfig(kOriginal);
1559 adjusted = apm->GetConfig();
1560 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
Hanna Silena6574902022-11-30 15:59:051561}
1562
andrew@webrtc.org60730cf2014-01-07 17:45:091563} // namespace webrtc