blob: bb016e01fbee92550c3db27ac274ccfd0c33d8c6 [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
Per Åhgren2507f8c2020-03-19 12:33:29 +010013#include <array>
Alessio Bazzicae4498052018-12-17 09:44:06 +010014#include <memory>
15
Niels Möller105711e2022-06-14 15:48:26 +020016#include "api/make_ref_counted.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010017#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 14:23:11 +020018#include "modules/audio_processing/include/audio_processing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020019#include "modules/audio_processing/optionally_built_submodule_creators.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020020#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020021#include "modules/audio_processing/test/echo_canceller_test_tools.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010022#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010024#include "rtc_base/checks.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020025#include "rtc_base/random.h"
Hanna Silen0c1ad292022-06-16 16:35:45 +020026#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020027#include "test/gmock.h"
28#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000029
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000030namespace webrtc {
peaha9cc40b2017-06-29 08:32:09 -070031namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000032
Alessio Bazzicae4498052018-12-17 09:44:06 +010033using ::testing::Invoke;
34using ::testing::NotNull;
35
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000036class MockInitialize : public AudioProcessingImpl {
37 public:
Alessio Bazzicabe1b8982021-09-17 08:26:10 +020038 MockInitialize() : AudioProcessingImpl() {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000039
Per Åhgren0ade9832020-09-01 23:57:20 +020040 MOCK_METHOD(void, InitializeLocked, (), (override));
Niels Möller5b747232021-07-26 17:16:25 +020041 void RealInitializeLocked() {
42 AssertLockedForTest();
Per Åhgren0ade9832020-09-01 23:57:20 +020043 AudioProcessingImpl::InitializeLocked();
pbos@webrtc.org788acd12014-12-15 09:41:24 +000044 }
peaha9cc40b2017-06-29 08:32:09 -070045
Danil Chapovalov704fb552020-05-18 15:10:15 +020046 MOCK_METHOD(void, AddRef, (), (const, override));
47 MOCK_METHOD(rtc::RefCountReleaseStatus, Release, (), (const, override));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000048};
49
Alessio Bazzicae4498052018-12-17 09:44:06 +010050// Creates MockEchoControl instances and provides a raw pointer access to
51// the next created one. The raw pointer is meant to be used with gmock.
52// Returning a pointer of the next created MockEchoControl instance is necessary
53// for the following reasons: (i) gmock expectations must be set before any call
54// occurs, (ii) APM is initialized the first time that
55// AudioProcessingImpl::ProcessStream() is called and the initialization leads
56// to the creation of a new EchoControl object.
57class MockEchoControlFactory : public EchoControlFactory {
58 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020059 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010060 // Returns a pointer to the next MockEchoControl that this factory creates.
61 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010062 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
63 int num_render_channels,
64 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010065 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020066 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010067 return mock;
68 }
69
70 private:
71 std::unique_ptr<MockEchoControl> next_mock_;
72};
73
Alessio Bazzicad2b97402018-08-09 14:23:11 +020074// Mocks EchoDetector and records the first samples of the last analyzed render
75// stream frame. Used to check what data is read by an EchoDetector
76// implementation injected into an APM.
77class TestEchoDetector : public EchoDetector {
78 public:
79 TestEchoDetector()
80 : analyze_render_audio_called_(false),
81 last_render_audio_first_sample_(0.f) {}
82 ~TestEchoDetector() override = default;
83 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
84 last_render_audio_first_sample_ = render_audio[0];
85 analyze_render_audio_called_ = true;
86 }
87 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
88 }
89 void Initialize(int capture_sample_rate_hz,
90 int num_capture_channels,
91 int render_sample_rate_hz,
92 int num_render_channels) override {}
93 EchoDetector::Metrics GetMetrics() const override { return {}; }
94 // Returns true if AnalyzeRenderAudio() has been called at least once.
95 bool analyze_render_audio_called() const {
96 return analyze_render_audio_called_;
97 }
98 // Returns the first sample of the last analyzed render frame.
99 float last_render_audio_first_sample() const {
100 return last_render_audio_first_sample_;
101 }
102
103 private:
104 bool analyze_render_audio_called_;
105 float last_render_audio_first_sample_;
106};
107
108// Mocks CustomProcessing and applies ProcessSample() to all the samples.
109// Meant to be injected into an APM to modify samples in a known and detectable
110// way.
111class TestRenderPreProcessor : public CustomProcessing {
112 public:
113 TestRenderPreProcessor() = default;
114 ~TestRenderPreProcessor() = default;
115 void Initialize(int sample_rate_hz, int num_channels) override {}
116 void Process(AudioBuffer* audio) override {
117 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200118 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200119 audio->num_frames());
120 std::transform(channel_view.begin(), channel_view.end(),
121 channel_view.begin(), ProcessSample);
122 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100123 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200124 std::string ToString() const override { return "TestRenderPreProcessor"; }
125 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
126 // Modifies a sample. This member is used in Process() to modify a frame and
127 // it is publicly visible to enable tests.
128 static constexpr float ProcessSample(float x) { return 2.f * x; }
129};
130
peaha9cc40b2017-06-29 08:32:09 -0700131} // namespace
132
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000133TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200134 MockInitialize mock;
135 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000136 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
137
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200138 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000139 mock.Initialize();
140
Per Åhgren2507f8c2020-03-19 12:33:29 +0100141 constexpr size_t kMaxSampleRateHz = 32000;
142 constexpr size_t kMaxNumChannels = 2;
143 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
144 frame.fill(0);
Henrik Lundin64253a92022-02-04 09:02:48 +0000145 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 04:42:27 -0700146 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200147 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100148 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100149 EXPECT_NOERR(
150 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000151
152 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48 +0000153 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200154 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100155 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000156
157 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700158 // TODO(peah): Investigate why this causes 2 inits.
Henrik Lundin64253a92022-02-04 09:02:48 +0000159 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200160 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100161 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000162 // ProcessStream sets num_channels_ == num_output_channels.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100163 EXPECT_NOERR(
164 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000165
aluebsb0319552016-03-17 20:39:53 -0700166 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000167 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200168 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100169 EXPECT_NOERR(
170 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000171}
172
Alessio Bazzicac054e782018-04-16 12:10:09 +0200173TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200174 rtc::scoped_refptr<AudioProcessing> apm =
175 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200176 webrtc::AudioProcessing::Config apm_config;
177 apm_config.pre_amplifier.enabled = true;
178 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
179 apm->ApplyConfig(apm_config);
180
Per Åhgren2507f8c2020-03-19 12:33:29 +0100181 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200182 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200183 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200184
Per Åhgren2507f8c2020-03-19 12:33:29 +0100185 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000186 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100187 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100188 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100189 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200190 << "With factor 1, frame shouldn't be modified.";
191
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200192 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200193 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200194 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200195
196 // Process for two frames to have time to ramp up gain.
197 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100198 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100199 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200200 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100201 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200202 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200203}
204
Per Åhgrendb5d7282021-03-15 16:31:04 +0000205TEST(AudioProcessingImplTest,
206 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200207 rtc::scoped_refptr<AudioProcessing> apm =
208 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000209 webrtc::AudioProcessing::Config apm_config;
210 apm_config.capture_level_adjustment.enabled = true;
211 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
212 apm->ApplyConfig(apm_config);
213
214 constexpr int kSampleRateHz = 48000;
215 constexpr int16_t kAudioLevel = 10000;
216 constexpr size_t kNumChannels = 2;
217
218 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000219 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000220 frame.fill(kAudioLevel);
221 apm->ProcessStream(frame.data(), config, config, frame.data());
222 EXPECT_EQ(frame[100], kAudioLevel)
223 << "With factor 1, frame shouldn't be modified.";
224
225 constexpr float kGainFactor = 2.f;
226 apm->SetRuntimeSetting(
227 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
228
229 // Process for two frames to have time to ramp up gain.
230 for (int i = 0; i < 2; ++i) {
231 frame.fill(kAudioLevel);
232 apm->ProcessStream(frame.data(), config, config, frame.data());
233 }
234 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
235 << "Frame should be amplified.";
236}
237
238TEST(AudioProcessingImplTest,
239 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200240 rtc::scoped_refptr<AudioProcessing> apm =
241 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000242 webrtc::AudioProcessing::Config apm_config;
243 apm_config.capture_level_adjustment.enabled = true;
244 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
245 apm->ApplyConfig(apm_config);
246
247 constexpr int kSampleRateHz = 48000;
248 constexpr int16_t kAudioLevel = 10000;
249 constexpr size_t kNumChannels = 2;
250
251 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000252 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000253 frame.fill(kAudioLevel);
254 apm->ProcessStream(frame.data(), config, config, frame.data());
255 EXPECT_EQ(frame[100], kAudioLevel)
256 << "With factor 1, frame shouldn't be modified.";
257
258 constexpr float kGainFactor = 2.f;
259 apm->SetRuntimeSetting(
260 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
261
262 // Process for two frames to have time to ramp up gain.
263 for (int i = 0; i < 2; ++i) {
264 frame.fill(kAudioLevel);
265 apm->ProcessStream(frame.data(), config, config, frame.data());
266 }
267 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
268 << "Frame should be amplified.";
269}
270
Per Åhgren652ada52021-03-03 10:52:44 +0000271TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
272 // Tests that the echo controller observes that the capture usage has been
273 // updated.
274 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
275 const MockEchoControlFactory* echo_control_factory_ptr =
276 echo_control_factory.get();
277
Niels Möller4f776ac2021-07-02 11:30:54 +0200278 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000279 AudioProcessingBuilderForTesting()
280 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200281 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000282
283 constexpr int16_t kAudioLevel = 10000;
284 constexpr int kSampleRateHz = 48000;
285 constexpr int kNumChannels = 2;
286 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000287 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000288 frame.fill(kAudioLevel);
289
290 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
291
292 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
293 // are passed.
294 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
295 apm->ProcessStream(frame.data(), config, config, frame.data());
296
297 // Ensure that SetCaptureOutputUsage is called with the right information when
298 // a runtime setting is passed.
299 EXPECT_CALL(*echo_control_mock,
300 SetCaptureOutputUsage(/*capture_output_used=*/false))
301 .Times(1);
302 EXPECT_TRUE(apm->PostRuntimeSetting(
303 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
304 /*capture_output_used=*/false)));
305 apm->ProcessStream(frame.data(), config, config, frame.data());
306
307 EXPECT_CALL(*echo_control_mock,
308 SetCaptureOutputUsage(/*capture_output_used=*/true))
309 .Times(1);
310 EXPECT_TRUE(apm->PostRuntimeSetting(
311 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
312 /*capture_output_used=*/true)));
313 apm->ProcessStream(frame.data(), config, config, frame.data());
314
315 // The number of positions to place items in the queue is equal to the queue
316 // size minus 1.
317 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
318
319 // Ensure that SetCaptureOutputUsage is called with the right information when
320 // many runtime settings are passed.
321 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
322 EXPECT_TRUE(apm->PostRuntimeSetting(
323 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
324 /*capture_output_used=*/false)));
325 }
326 EXPECT_CALL(*echo_control_mock,
327 SetCaptureOutputUsage(/*capture_output_used=*/false))
328 .Times(kNumSlotsInQueue - 1);
329 apm->ProcessStream(frame.data(), config, config, frame.data());
330
331 // Ensure that SetCaptureOutputUsage is properly called with the fallback
332 // value when the runtime settings queue becomes full.
333 for (int k = 0; k < kNumSlotsInQueue; ++k) {
334 EXPECT_TRUE(apm->PostRuntimeSetting(
335 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
336 /*capture_output_used=*/false)));
337 }
338 EXPECT_FALSE(apm->PostRuntimeSetting(
339 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
340 /*capture_output_used=*/false)));
341 EXPECT_FALSE(apm->PostRuntimeSetting(
342 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
343 /*capture_output_used=*/false)));
344 EXPECT_CALL(*echo_control_mock,
345 SetCaptureOutputUsage(/*capture_output_used=*/false))
346 .Times(kNumSlotsInQueue);
347 EXPECT_CALL(*echo_control_mock,
348 SetCaptureOutputUsage(/*capture_output_used=*/true))
349 .Times(1);
350 apm->ProcessStream(frame.data(), config, config, frame.data());
351}
352
Alessio Bazzicae4498052018-12-17 09:44:06 +0100353TEST(AudioProcessingImplTest,
354 EchoControllerObservesPreAmplifierEchoPathGainChange) {
355 // Tests that the echo controller observes an echo path gain change when the
356 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200357 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100358 const auto* echo_control_factory_ptr = echo_control_factory.get();
359
Niels Möller4f776ac2021-07-02 11:30:54 +0200360 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200361 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100362 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200363 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200364 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100365 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200366 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100367 apm_config.gain_controller2.enabled = false;
368 apm_config.pre_amplifier.enabled = true;
369 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
370 apm->ApplyConfig(apm_config);
371
Alessio Bazzicae4498052018-12-17 09:44:06 +0100372 constexpr int16_t kAudioLevel = 10000;
373 constexpr size_t kSampleRateHz = 48000;
374 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100375 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000376 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100377 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100378
379 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
380
Per Åhgren0aefbf02019-08-23 21:29:17 +0200381 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200382 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100383 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200384 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100385 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100386
Per Åhgren0aefbf02019-08-23 21:29:17 +0200387 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200388 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100389 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200390 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100391 apm->SetRuntimeSetting(
392 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100393 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100394}
395
396TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000397 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
398 // Tests that the echo controller observes an echo path gain change when the
399 // pre-amplifier submodule changes the gain.
400 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
401 const auto* echo_control_factory_ptr = echo_control_factory.get();
402
Niels Möller4f776ac2021-07-02 11:30:54 +0200403 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000404 AudioProcessingBuilderForTesting()
405 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200406 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000407 // Disable AGC.
408 webrtc::AudioProcessing::Config apm_config;
409 apm_config.gain_controller1.enabled = false;
410 apm_config.gain_controller2.enabled = false;
411 apm_config.capture_level_adjustment.enabled = true;
412 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
413 apm->ApplyConfig(apm_config);
414
415 constexpr int16_t kAudioLevel = 10000;
416 constexpr size_t kSampleRateHz = 48000;
417 constexpr size_t kNumChannels = 2;
418 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000419 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000420 frame.fill(kAudioLevel);
421
422 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
423
424 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
425 EXPECT_CALL(*echo_control_mock,
426 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
427 .Times(1);
428 apm->ProcessStream(frame.data(), config, config, frame.data());
429
430 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
431 EXPECT_CALL(*echo_control_mock,
432 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
433 .Times(1);
434 apm->SetRuntimeSetting(
435 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
436 apm->ProcessStream(frame.data(), config, config, frame.data());
437}
438
439TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100440 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
441 // Tests that the echo controller observes an echo path gain change when the
442 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200443 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100444 const auto* echo_control_factory_ptr = echo_control_factory.get();
445
Niels Möller4f776ac2021-07-02 11:30:54 +0200446 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200447 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100448 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200449 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100450 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200451 // Enable AGC1.
452 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200453 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100454 apm_config.gain_controller2.enabled = false;
455 apm_config.pre_amplifier.enabled = false;
456 apm->ApplyConfig(apm_config);
457
Alessio Bazzicae4498052018-12-17 09:44:06 +0100458 constexpr int16_t kAudioLevel = 1000;
459 constexpr size_t kSampleRateHz = 48000;
460 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100461 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000462 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100463 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100464
465 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
466
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200467 constexpr int kInitialStreamAnalogLevel = 123;
468 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
469
470 // When the first fame is processed, no echo path gain change must be
471 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200472 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200473 EXPECT_CALL(*echo_control_mock,
474 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100475 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100476 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100477
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200478 // Simulate the application of the recommended analog level.
479 int recommended_analog_level = apm->recommended_stream_analog_level();
480 if (recommended_analog_level == kInitialStreamAnalogLevel) {
481 // Force an analog gain change if it did not happen.
482 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100483 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200484 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100485
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200486 // After the first fame and with a stream analog level change, the echo path
487 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200488 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200489 EXPECT_CALL(*echo_control_mock,
490 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100491 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100492 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100493}
494
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200495// Tests that a stream is successfully processed when AGC2 adaptive digital is
496// used and when the field trial
497// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200498TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200499 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
500 webrtc::test::ScopedFieldTrials field_trials(
501 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/");
502 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
503 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200504 webrtc::AudioProcessing::Config apm_config;
505 // Disable AGC1 analog.
506 apm_config.gain_controller1.enabled = false;
507 // Enable AGC2 digital.
508 apm_config.gain_controller2.enabled = true;
509 apm_config.gain_controller2.adaptive_digital.enabled = true;
510 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200511 constexpr int kSampleRateHz = 48000;
512 constexpr int kNumChannels = 1;
513 std::array<float, kSampleRateHz / 100> buffer;
514 float* channel_pointers[] = {buffer.data()};
515 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
516 /*num_channels=*/kNumChannels);
517 Random random_generator(2341U);
518 constexpr int kFramesToProcess = 10;
519 for (int i = 0; i < kFramesToProcess; ++i) {
520 RandomizeSampleVector(&random_generator, buffer);
521 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
522 channel_pointers),
523 kNoErr);
524 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200525}
526
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200527// Tests that a stream is successfully processed when AGC2 adaptive digital is
528// used and when the field trial
529// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
530TEST(AudioProcessingImplTest,
531 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200532 webrtc::test::ScopedFieldTrials field_trials(
533 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/");
534 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
535 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
536 webrtc::AudioProcessing::Config apm_config;
537 // Disable AGC1 analog.
538 apm_config.gain_controller1.enabled = false;
539 // Enable AGC2 digital.
540 apm_config.gain_controller2.enabled = true;
541 apm_config.gain_controller2.adaptive_digital.enabled = true;
542 apm->ApplyConfig(apm_config);
543 constexpr int kSampleRateHz = 48000;
544 constexpr int kNumChannels = 1;
545 std::array<float, kSampleRateHz / 100> buffer;
546 float* channel_pointers[] = {buffer.data()};
547 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
548 /*num_channels=*/kNumChannels);
549 Random random_generator(2341U);
550 constexpr int kFramesToProcess = 10;
551 for (int i = 0; i < kFramesToProcess; ++i) {
552 RandomizeSampleVector(&random_generator, buffer);
553 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
554 channel_pointers),
555 kNoErr);
556 }
557}
558
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200559TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
560 // Tests that the echo controller observes an echo path gain change when a
561 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200562 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200563 const auto* echo_control_factory_ptr = echo_control_factory.get();
564
Niels Möller4f776ac2021-07-02 11:30:54 +0200565 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200566 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200567 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200568 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200569 // Disable AGC.
570 webrtc::AudioProcessing::Config apm_config;
571 apm_config.gain_controller1.enabled = false;
572 apm_config.gain_controller2.enabled = false;
573 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200574
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200575 constexpr int16_t kAudioLevel = 10000;
576 constexpr size_t kSampleRateHz = 48000;
577 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100578 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000579 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100580 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200581
582 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
583
Per Åhgren0aefbf02019-08-23 21:29:17 +0200584 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200585 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100586 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200587 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100588 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200589
Per Åhgren0aefbf02019-08-23 21:29:17 +0200590 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200591 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100592 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200593 .Times(1);
594 apm->SetRuntimeSetting(
595 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100596 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200597
Per Åhgren0aefbf02019-08-23 21:29:17 +0200598 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200599 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100600 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200601 .Times(1);
602 apm->SetRuntimeSetting(
603 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100604 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200605
Per Åhgren0aefbf02019-08-23 21:29:17 +0200606 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200607 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100608 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200609 .Times(1);
610 apm->SetRuntimeSetting(
611 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100612 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200613}
614
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200615TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
616 // Make sure that signal changes caused by a render pre-processing sub-module
617 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200618 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200619 std::unique_ptr<CustomProcessing> test_render_pre_processor(
620 new TestRenderPreProcessor());
621 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200622 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200623 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200624 .SetEchoDetector(test_echo_detector)
625 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200626 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200627 webrtc::AudioProcessing::Config apm_config;
628 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200629 apm->ApplyConfig(apm_config);
630
631 constexpr int16_t kAudioLevel = 1000;
632 constexpr int kSampleRateHz = 16000;
633 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100634 // Explicitly initialize APM to ensure no render frames are discarded.
635 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000636 {kSampleRateHz, kNumChannels},
637 {kSampleRateHz, kNumChannels},
638 {kSampleRateHz, kNumChannels},
639 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100640 }};
641 apm->Initialize(processing_config);
642
Per Åhgren2507f8c2020-03-19 12:33:29 +0100643 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000644 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200645
646 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
647 constexpr float kExpectedPreprocessedAudioLevel =
648 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
649 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
650
651 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100652 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200653 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100654 apm->ProcessReverseStream(frame.data(), stream_config,
655 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200656 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
657 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100658 frame.fill(kAudioLevel);
659 ASSERT_EQ(AudioProcessing::Error::kNoError,
660 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100661 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200662 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
663 // triggered, the line below checks that the call has occurred. If not, the
664 // APM implementation may have changed and this test might need to be adapted.
665 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
666 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
667 // produced by the render pre-processor.
668 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
669 test_echo_detector->last_render_audio_first_sample());
670}
671
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200672// Disabling build-optional submodules and trying to enable them via the APM
673// config should be bit-exact with running APM with said submodules disabled.
674// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
675TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200676 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200677 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
678
679 ApmSubmoduleCreationOverrides overrides;
680 overrides.transient_suppression = true;
681 apm->OverrideSubmoduleCreationForTesting(overrides);
682
683 AudioProcessing::Config apm_config = apm->GetConfig();
684 apm_config.transient_suppression.enabled = true;
685 apm->ApplyConfig(apm_config);
686
687 rtc::scoped_refptr<AudioProcessing> apm_reference =
688 AudioProcessingBuilder().Create();
689 apm_config = apm_reference->GetConfig();
690 apm_config.transient_suppression.enabled = false;
691 apm_reference->ApplyConfig(apm_config);
692
693 constexpr int kSampleRateHz = 16000;
694 constexpr int kNumChannels = 1;
695 std::array<float, kSampleRateHz / 100> buffer;
696 std::array<float, kSampleRateHz / 100> buffer_reference;
697 float* channel_pointers[] = {buffer.data()};
698 float* channel_pointers_reference[] = {buffer_reference.data()};
699 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000700 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200701 Random random_generator(2341U);
702 constexpr int kFramesToProcessPerConfiguration = 10;
703
704 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
705 RandomizeSampleVector(&random_generator, buffer);
706 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
707 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
708 channel_pointers),
709 kNoErr);
710 ASSERT_EQ(
711 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
712 stream_config, channel_pointers_reference),
713 kNoErr);
714 for (int j = 0; j < kSampleRateHz / 100; ++j) {
715 EXPECT_EQ(buffer[j], buffer_reference[j]);
716 }
717 }
718}
719
720// Disable transient suppressor creation and run APM in ways that should trigger
721// calls to the transient suppressor API.
722TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200723 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200724 ASSERT_EQ(apm->Initialize(), kNoErr);
725
726 ApmSubmoduleCreationOverrides overrides;
727 overrides.transient_suppression = true;
728 apm->OverrideSubmoduleCreationForTesting(overrides);
729
730 AudioProcessing::Config config = apm->GetConfig();
731 config.transient_suppression.enabled = true;
732 apm->ApplyConfig(config);
733 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
734 float buffer[960];
735 float* channel_pointers[] = {&buffer[0], &buffer[480]};
736 Random random_generator(2341U);
737 constexpr int kFramesToProcessPerConfiguration = 3;
738
739 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000740 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200741 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
742 RandomizeSampleVector(&random_generator, buffer);
743 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
744 initial_stream_config, channel_pointers),
745 kNoErr);
746 }
747
748 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000749 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200750 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
751 RandomizeSampleVector(&random_generator, buffer);
752 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
753 stereo_stream_config, channel_pointers),
754 kNoErr);
755 }
756
757 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000758 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200759 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
760 RandomizeSampleVector(&random_generator, buffer);
761 EXPECT_EQ(
762 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
763 high_sample_rate_stream_config, channel_pointers),
764 kNoErr);
765 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200766}
767
768// Disable transient suppressor creation and run APM in ways that should trigger
769// calls to the transient suppressor API.
770TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200771 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200772 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
773
774 ApmSubmoduleCreationOverrides overrides;
775 overrides.transient_suppression = true;
776 apm->OverrideSubmoduleCreationForTesting(overrides);
777
778 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
779 float buffer[960];
780 float* channel_pointers[] = {&buffer[0], &buffer[480]};
781 Random random_generator(2341U);
782 constexpr int kFramesToProcessPerConfiguration = 3;
783 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000784 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200785
786 AudioProcessing::Config config = apm->GetConfig();
787 config.transient_suppression.enabled = true;
788 apm->ApplyConfig(config);
789 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
790 RandomizeSampleVector(&random_generator, buffer);
791 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
792 channel_pointers),
793 kNoErr);
794 }
795
796 config = apm->GetConfig();
797 config.transient_suppression.enabled = false;
798 apm->ApplyConfig(config);
799 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
800 RandomizeSampleVector(&random_generator, buffer);
801 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
802 channel_pointers),
803 kNoErr);
804 }
805
806 config = apm->GetConfig();
807 config.transient_suppression.enabled = true;
808 apm->ApplyConfig(config);
809 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
810 RandomizeSampleVector(&random_generator, buffer);
811 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
812 channel_pointers),
813 kNoErr);
814 }
815}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000816} // namespace webrtc