blob: c68ce41652784194b9818b12fcd00ae84eaf1fdd [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
Mirko Bonadeid9708072019-01-25 20:26:48 +010016#include "api/scoped_refptr.h"
Per Åhgren652ada52021-03-03 10:52:44 +000017#include "modules/audio_processing/common.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"
Steve Anton10542f22019-01-11 09:11:00 -080026#include "rtc_base/ref_counted_object.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:
peah88ac8532016-09-12 16:47:25 -070038 explicit MockInitialize(const webrtc::Config& config)
39 : AudioProcessingImpl(config) {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000040
Per Åhgren0ade9832020-09-01 23:57:20 +020041 MOCK_METHOD(void, InitializeLocked, (), (override));
Niels Möller5b747232021-07-26 17:16:25 +020042 void RealInitializeLocked() {
43 AssertLockedForTest();
Per Åhgren0ade9832020-09-01 23:57:20 +020044 AudioProcessingImpl::InitializeLocked();
pbos@webrtc.org788acd12014-12-15 09:41:24 +000045 }
peaha9cc40b2017-06-29 08:32:09 -070046
Danil Chapovalov704fb552020-05-18 15:10:15 +020047 MOCK_METHOD(void, AddRef, (), (const, override));
48 MOCK_METHOD(rtc::RefCountReleaseStatus, Release, (), (const, override));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000049};
50
Alessio Bazzicae4498052018-12-17 09:44:06 +010051// Creates MockEchoControl instances and provides a raw pointer access to
52// the next created one. The raw pointer is meant to be used with gmock.
53// Returning a pointer of the next created MockEchoControl instance is necessary
54// for the following reasons: (i) gmock expectations must be set before any call
55// occurs, (ii) APM is initialized the first time that
56// AudioProcessingImpl::ProcessStream() is called and the initialization leads
57// to the creation of a new EchoControl object.
58class MockEchoControlFactory : public EchoControlFactory {
59 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020060 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010061 // Returns a pointer to the next MockEchoControl that this factory creates.
62 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010063 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
64 int num_render_channels,
65 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010066 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020067 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010068 return mock;
69 }
70
71 private:
72 std::unique_ptr<MockEchoControl> next_mock_;
73};
74
Alessio Bazzicad2b97402018-08-09 14:23:11 +020075// Mocks EchoDetector and records the first samples of the last analyzed render
76// stream frame. Used to check what data is read by an EchoDetector
77// implementation injected into an APM.
78class TestEchoDetector : public EchoDetector {
79 public:
80 TestEchoDetector()
81 : analyze_render_audio_called_(false),
82 last_render_audio_first_sample_(0.f) {}
83 ~TestEchoDetector() override = default;
84 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
85 last_render_audio_first_sample_ = render_audio[0];
86 analyze_render_audio_called_ = true;
87 }
88 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
89 }
90 void Initialize(int capture_sample_rate_hz,
91 int num_capture_channels,
92 int render_sample_rate_hz,
93 int num_render_channels) override {}
94 EchoDetector::Metrics GetMetrics() const override { return {}; }
95 // Returns true if AnalyzeRenderAudio() has been called at least once.
96 bool analyze_render_audio_called() const {
97 return analyze_render_audio_called_;
98 }
99 // Returns the first sample of the last analyzed render frame.
100 float last_render_audio_first_sample() const {
101 return last_render_audio_first_sample_;
102 }
103
104 private:
105 bool analyze_render_audio_called_;
106 float last_render_audio_first_sample_;
107};
108
109// Mocks CustomProcessing and applies ProcessSample() to all the samples.
110// Meant to be injected into an APM to modify samples in a known and detectable
111// way.
112class TestRenderPreProcessor : public CustomProcessing {
113 public:
114 TestRenderPreProcessor() = default;
115 ~TestRenderPreProcessor() = default;
116 void Initialize(int sample_rate_hz, int num_channels) override {}
117 void Process(AudioBuffer* audio) override {
118 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200119 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200120 audio->num_frames());
121 std::transform(channel_view.begin(), channel_view.end(),
122 channel_view.begin(), ProcessSample);
123 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100124 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200125 std::string ToString() const override { return "TestRenderPreProcessor"; }
126 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
127 // Modifies a sample. This member is used in Process() to modify a frame and
128 // it is publicly visible to enable tests.
129 static constexpr float ProcessSample(float x) { return 2.f * x; }
130};
131
peaha9cc40b2017-06-29 08:32:09 -0700132} // namespace
133
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000134TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100135 webrtc::Config webrtc_config;
136 MockInitialize mock(webrtc_config);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000137 ON_CALL(mock, InitializeLocked())
138 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
139
140 EXPECT_CALL(mock, InitializeLocked()).Times(1);
141 mock.Initialize();
142
Per Åhgren2507f8c2020-03-19 12:33:29 +0100143 constexpr size_t kMaxSampleRateHz = 32000;
144 constexpr size_t kMaxNumChannels = 2;
145 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
146 frame.fill(0);
147 StreamConfig config(16000, 1, /*has_keyboard=*/false);
peah2ace3f92016-09-10 04:42:27 -0700148 // Call with the default parameters; there should be an init.
Per Åhgren4bdced52017-06-27 16:00:38 +0200149 EXPECT_CALL(mock, InitializeLocked()).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100150 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100151 EXPECT_NOERR(
152 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000153
154 // New sample rate. (Only impacts ProcessStream).
Per Åhgren2507f8c2020-03-19 12:33:29 +0100155 config = StreamConfig(32000, 1, /*has_keyboard=*/false);
Yves Gerey665174f2018-06-19 15:03:05 +0200156 EXPECT_CALL(mock, InitializeLocked()).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100157 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000158
159 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700160 // TODO(peah): Investigate why this causes 2 inits.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100161 config = StreamConfig(32000, 2, /*has_keyboard=*/false);
Yves Gerey665174f2018-06-19 15:03:05 +0200162 EXPECT_CALL(mock, InitializeLocked()).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100163 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000164 // ProcessStream sets num_channels_ == num_output_channels.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100165 EXPECT_NOERR(
166 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000167
aluebsb0319552016-03-17 20:39:53 -0700168 // A new sample rate passed to ProcessReverseStream should cause an init.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100169 config = StreamConfig(16000, 2, /*has_keyboard=*/false);
Alex Luebs5b830fe2016-03-08 17:52:52 +0100170 EXPECT_CALL(mock, InitializeLocked()).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100171 EXPECT_NOERR(
172 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000173}
174
Alessio Bazzicac054e782018-04-16 12:10:09 +0200175TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200176 rtc::scoped_refptr<AudioProcessing> apm =
177 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200178 webrtc::AudioProcessing::Config apm_config;
179 apm_config.pre_amplifier.enabled = true;
180 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
181 apm->ApplyConfig(apm_config);
182
Per Åhgren2507f8c2020-03-19 12:33:29 +0100183 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200184 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200185 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200186
Per Åhgren2507f8c2020-03-19 12:33:29 +0100187 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
188 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
189 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100190 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100191 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200192 << "With factor 1, frame shouldn't be modified.";
193
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200194 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200195 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200196 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200197
198 // Process for two frames to have time to ramp up gain.
199 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100200 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100201 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200202 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100203 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200204 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200205}
206
Per Åhgrendb5d7282021-03-15 16:31:04 +0000207TEST(AudioProcessingImplTest,
208 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200209 rtc::scoped_refptr<AudioProcessing> apm =
210 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000211 webrtc::AudioProcessing::Config apm_config;
212 apm_config.capture_level_adjustment.enabled = true;
213 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
214 apm->ApplyConfig(apm_config);
215
216 constexpr int kSampleRateHz = 48000;
217 constexpr int16_t kAudioLevel = 10000;
218 constexpr size_t kNumChannels = 2;
219
220 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
221 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
222 frame.fill(kAudioLevel);
223 apm->ProcessStream(frame.data(), config, config, frame.data());
224 EXPECT_EQ(frame[100], kAudioLevel)
225 << "With factor 1, frame shouldn't be modified.";
226
227 constexpr float kGainFactor = 2.f;
228 apm->SetRuntimeSetting(
229 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
230
231 // Process for two frames to have time to ramp up gain.
232 for (int i = 0; i < 2; ++i) {
233 frame.fill(kAudioLevel);
234 apm->ProcessStream(frame.data(), config, config, frame.data());
235 }
236 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
237 << "Frame should be amplified.";
238}
239
240TEST(AudioProcessingImplTest,
241 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200242 rtc::scoped_refptr<AudioProcessing> apm =
243 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000244 webrtc::AudioProcessing::Config apm_config;
245 apm_config.capture_level_adjustment.enabled = true;
246 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
247 apm->ApplyConfig(apm_config);
248
249 constexpr int kSampleRateHz = 48000;
250 constexpr int16_t kAudioLevel = 10000;
251 constexpr size_t kNumChannels = 2;
252
253 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
254 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
255 frame.fill(kAudioLevel);
256 apm->ProcessStream(frame.data(), config, config, frame.data());
257 EXPECT_EQ(frame[100], kAudioLevel)
258 << "With factor 1, frame shouldn't be modified.";
259
260 constexpr float kGainFactor = 2.f;
261 apm->SetRuntimeSetting(
262 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
263
264 // Process for two frames to have time to ramp up gain.
265 for (int i = 0; i < 2; ++i) {
266 frame.fill(kAudioLevel);
267 apm->ProcessStream(frame.data(), config, config, frame.data());
268 }
269 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
270 << "Frame should be amplified.";
271}
272
Per Åhgren652ada52021-03-03 10:52:44 +0000273TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
274 // Tests that the echo controller observes that the capture usage has been
275 // updated.
276 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
277 const MockEchoControlFactory* echo_control_factory_ptr =
278 echo_control_factory.get();
279
Niels Möller4f776ac2021-07-02 11:30:54 +0200280 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000281 AudioProcessingBuilderForTesting()
282 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200283 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000284
285 constexpr int16_t kAudioLevel = 10000;
286 constexpr int kSampleRateHz = 48000;
287 constexpr int kNumChannels = 2;
288 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
289 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
290 frame.fill(kAudioLevel);
291
292 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
293
294 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
295 // are passed.
296 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
297 apm->ProcessStream(frame.data(), config, config, frame.data());
298
299 // Ensure that SetCaptureOutputUsage is called with the right information when
300 // a runtime setting is passed.
301 EXPECT_CALL(*echo_control_mock,
302 SetCaptureOutputUsage(/*capture_output_used=*/false))
303 .Times(1);
304 EXPECT_TRUE(apm->PostRuntimeSetting(
305 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
306 /*capture_output_used=*/false)));
307 apm->ProcessStream(frame.data(), config, config, frame.data());
308
309 EXPECT_CALL(*echo_control_mock,
310 SetCaptureOutputUsage(/*capture_output_used=*/true))
311 .Times(1);
312 EXPECT_TRUE(apm->PostRuntimeSetting(
313 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
314 /*capture_output_used=*/true)));
315 apm->ProcessStream(frame.data(), config, config, frame.data());
316
317 // The number of positions to place items in the queue is equal to the queue
318 // size minus 1.
319 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
320
321 // Ensure that SetCaptureOutputUsage is called with the right information when
322 // many runtime settings are passed.
323 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
324 EXPECT_TRUE(apm->PostRuntimeSetting(
325 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
326 /*capture_output_used=*/false)));
327 }
328 EXPECT_CALL(*echo_control_mock,
329 SetCaptureOutputUsage(/*capture_output_used=*/false))
330 .Times(kNumSlotsInQueue - 1);
331 apm->ProcessStream(frame.data(), config, config, frame.data());
332
333 // Ensure that SetCaptureOutputUsage is properly called with the fallback
334 // value when the runtime settings queue becomes full.
335 for (int k = 0; k < kNumSlotsInQueue; ++k) {
336 EXPECT_TRUE(apm->PostRuntimeSetting(
337 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
338 /*capture_output_used=*/false)));
339 }
340 EXPECT_FALSE(apm->PostRuntimeSetting(
341 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
342 /*capture_output_used=*/false)));
343 EXPECT_FALSE(apm->PostRuntimeSetting(
344 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
345 /*capture_output_used=*/false)));
346 EXPECT_CALL(*echo_control_mock,
347 SetCaptureOutputUsage(/*capture_output_used=*/false))
348 .Times(kNumSlotsInQueue);
349 EXPECT_CALL(*echo_control_mock,
350 SetCaptureOutputUsage(/*capture_output_used=*/true))
351 .Times(1);
352 apm->ProcessStream(frame.data(), config, config, frame.data());
353}
354
Alessio Bazzicae4498052018-12-17 09:44:06 +0100355TEST(AudioProcessingImplTest,
356 EchoControllerObservesPreAmplifierEchoPathGainChange) {
357 // Tests that the echo controller observes an echo path gain change when the
358 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200359 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100360 const auto* echo_control_factory_ptr = echo_control_factory.get();
361
Niels Möller4f776ac2021-07-02 11:30:54 +0200362 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200363 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100364 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200365 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200366 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100367 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200368 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100369 apm_config.gain_controller2.enabled = false;
370 apm_config.pre_amplifier.enabled = true;
371 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
372 apm->ApplyConfig(apm_config);
373
Alessio Bazzicae4498052018-12-17 09:44:06 +0100374 constexpr int16_t kAudioLevel = 10000;
375 constexpr size_t kSampleRateHz = 48000;
376 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100377 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
378 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
379 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100380
381 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
382
Per Åhgren0aefbf02019-08-23 21:29:17 +0200383 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200384 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100385 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200386 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100387 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100388
Per Åhgren0aefbf02019-08-23 21:29:17 +0200389 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200390 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100391 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200392 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100393 apm->SetRuntimeSetting(
394 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100395 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100396}
397
398TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000399 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
400 // Tests that the echo controller observes an echo path gain change when the
401 // pre-amplifier submodule changes the gain.
402 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
403 const auto* echo_control_factory_ptr = echo_control_factory.get();
404
Niels Möller4f776ac2021-07-02 11:30:54 +0200405 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000406 AudioProcessingBuilderForTesting()
407 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200408 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000409 // Disable AGC.
410 webrtc::AudioProcessing::Config apm_config;
411 apm_config.gain_controller1.enabled = false;
412 apm_config.gain_controller2.enabled = false;
413 apm_config.capture_level_adjustment.enabled = true;
414 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
415 apm->ApplyConfig(apm_config);
416
417 constexpr int16_t kAudioLevel = 10000;
418 constexpr size_t kSampleRateHz = 48000;
419 constexpr size_t kNumChannels = 2;
420 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
421 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
422 frame.fill(kAudioLevel);
423
424 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
425
426 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
427 EXPECT_CALL(*echo_control_mock,
428 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
429 .Times(1);
430 apm->ProcessStream(frame.data(), config, config, frame.data());
431
432 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
433 EXPECT_CALL(*echo_control_mock,
434 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
435 .Times(1);
436 apm->SetRuntimeSetting(
437 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
438 apm->ProcessStream(frame.data(), config, config, frame.data());
439}
440
441TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100442 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
443 // Tests that the echo controller observes an echo path gain change when the
444 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200445 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100446 const auto* echo_control_factory_ptr = echo_control_factory.get();
447
Niels Möller4f776ac2021-07-02 11:30:54 +0200448 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200449 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100450 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200451 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100452 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200453 // Enable AGC1.
454 apm_config.gain_controller1.enabled = true;
455 apm_config.gain_controller1.mode =
456 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100457 apm_config.gain_controller2.enabled = false;
458 apm_config.pre_amplifier.enabled = false;
459 apm->ApplyConfig(apm_config);
460
Alessio Bazzicae4498052018-12-17 09:44:06 +0100461 constexpr int16_t kAudioLevel = 1000;
462 constexpr size_t kSampleRateHz = 48000;
463 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100464 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
465 StreamConfig stream_config(kSampleRateHz, kNumChannels,
466 /*has_keyboard=*/false);
467 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100468
469 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
470
Sam Zackrisson41478c72019-10-15 10:10:26 +0200471 const int initial_analog_gain = apm->recommended_stream_analog_level();
Per Åhgren0aefbf02019-08-23 21:29:17 +0200472 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100473 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, false))
474 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100475 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100476
477 // Force an analog gain change if it did not happen.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200478 if (initial_analog_gain == apm->recommended_stream_analog_level()) {
479 apm->set_stream_analog_level(initial_analog_gain + 1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100480 }
481
Per Åhgren0aefbf02019-08-23 21:29:17 +0200482 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100483 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, true))
484 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100485 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100486}
487
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200488TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
489 // Tests that the echo controller observes an echo path gain change when a
490 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200491 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200492 const auto* echo_control_factory_ptr = echo_control_factory.get();
493
Niels Möller4f776ac2021-07-02 11:30:54 +0200494 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200495 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200496 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200497 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200498 // Disable AGC.
499 webrtc::AudioProcessing::Config apm_config;
500 apm_config.gain_controller1.enabled = false;
501 apm_config.gain_controller2.enabled = false;
502 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200503
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200504 constexpr int16_t kAudioLevel = 10000;
505 constexpr size_t kSampleRateHz = 48000;
506 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100507 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
508 StreamConfig stream_config(kSampleRateHz, kNumChannels,
509 /*has_keyboard=*/false);
510 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200511
512 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
513
Per Åhgren0aefbf02019-08-23 21:29:17 +0200514 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200515 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100516 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200517 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100518 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200519
Per Åhgren0aefbf02019-08-23 21:29:17 +0200520 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200521 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100522 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200523 .Times(1);
524 apm->SetRuntimeSetting(
525 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100526 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200527
Per Åhgren0aefbf02019-08-23 21:29:17 +0200528 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200529 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100530 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200531 .Times(1);
532 apm->SetRuntimeSetting(
533 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100534 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200535
Per Åhgren0aefbf02019-08-23 21:29:17 +0200536 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200537 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100538 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200539 .Times(1);
540 apm->SetRuntimeSetting(
541 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100542 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200543}
544
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200545TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
546 // Make sure that signal changes caused by a render pre-processing sub-module
547 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200548 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200549 std::unique_ptr<CustomProcessing> test_render_pre_processor(
550 new TestRenderPreProcessor());
551 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200552 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200553 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200554 .SetEchoDetector(test_echo_detector)
555 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200556 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200557 webrtc::AudioProcessing::Config apm_config;
558 apm_config.pre_amplifier.enabled = true;
559 apm_config.residual_echo_detector.enabled = true;
560 apm->ApplyConfig(apm_config);
561
562 constexpr int16_t kAudioLevel = 1000;
563 constexpr int kSampleRateHz = 16000;
564 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100565 // Explicitly initialize APM to ensure no render frames are discarded.
566 const ProcessingConfig processing_config = {{
567 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
568 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
569 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
570 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
571 }};
572 apm->Initialize(processing_config);
573
Per Åhgren2507f8c2020-03-19 12:33:29 +0100574 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
575 StreamConfig stream_config(kSampleRateHz, kNumChannels,
576 /*has_keyboard=*/false);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200577
578 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
579 constexpr float kExpectedPreprocessedAudioLevel =
580 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
581 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
582
583 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100584 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200585 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100586 apm->ProcessReverseStream(frame.data(), stream_config,
587 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200588 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
589 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100590 frame.fill(kAudioLevel);
591 ASSERT_EQ(AudioProcessing::Error::kNoError,
592 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100593 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200594 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
595 // triggered, the line below checks that the call has occurred. If not, the
596 // APM implementation may have changed and this test might need to be adapted.
597 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
598 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
599 // produced by the render pre-processor.
600 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
601 test_echo_detector->last_render_audio_first_sample());
602}
603
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200604// Disabling build-optional submodules and trying to enable them via the APM
605// config should be bit-exact with running APM with said submodules disabled.
606// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
607TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Tommi87f70902021-04-27 14:43:08 +0200608 auto apm = rtc::make_ref_counted<AudioProcessingImpl>(webrtc::Config());
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200609 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
610
611 ApmSubmoduleCreationOverrides overrides;
612 overrides.transient_suppression = true;
613 apm->OverrideSubmoduleCreationForTesting(overrides);
614
615 AudioProcessing::Config apm_config = apm->GetConfig();
616 apm_config.transient_suppression.enabled = true;
617 apm->ApplyConfig(apm_config);
618
619 rtc::scoped_refptr<AudioProcessing> apm_reference =
620 AudioProcessingBuilder().Create();
621 apm_config = apm_reference->GetConfig();
622 apm_config.transient_suppression.enabled = false;
623 apm_reference->ApplyConfig(apm_config);
624
625 constexpr int kSampleRateHz = 16000;
626 constexpr int kNumChannels = 1;
627 std::array<float, kSampleRateHz / 100> buffer;
628 std::array<float, kSampleRateHz / 100> buffer_reference;
629 float* channel_pointers[] = {buffer.data()};
630 float* channel_pointers_reference[] = {buffer_reference.data()};
631 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
632 /*num_channels=*/kNumChannels,
633 /*has_keyboard=*/false);
634 Random random_generator(2341U);
635 constexpr int kFramesToProcessPerConfiguration = 10;
636
637 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
638 RandomizeSampleVector(&random_generator, buffer);
639 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
640 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
641 channel_pointers),
642 kNoErr);
643 ASSERT_EQ(
644 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
645 stream_config, channel_pointers_reference),
646 kNoErr);
647 for (int j = 0; j < kSampleRateHz / 100; ++j) {
648 EXPECT_EQ(buffer[j], buffer_reference[j]);
649 }
650 }
651}
652
653// Disable transient suppressor creation and run APM in ways that should trigger
654// calls to the transient suppressor API.
655TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Tommi87f70902021-04-27 14:43:08 +0200656 auto apm = rtc::make_ref_counted<AudioProcessingImpl>(webrtc::Config());
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200657 ASSERT_EQ(apm->Initialize(), kNoErr);
658
659 ApmSubmoduleCreationOverrides overrides;
660 overrides.transient_suppression = true;
661 apm->OverrideSubmoduleCreationForTesting(overrides);
662
663 AudioProcessing::Config config = apm->GetConfig();
664 config.transient_suppression.enabled = true;
665 apm->ApplyConfig(config);
666 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
667 float buffer[960];
668 float* channel_pointers[] = {&buffer[0], &buffer[480]};
669 Random random_generator(2341U);
670 constexpr int kFramesToProcessPerConfiguration = 3;
671
672 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
673 /*num_channels=*/1,
674 /*has_keyboard=*/false);
675 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
676 RandomizeSampleVector(&random_generator, buffer);
677 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
678 initial_stream_config, channel_pointers),
679 kNoErr);
680 }
681
682 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
683 /*num_channels=*/2,
684 /*has_keyboard=*/false);
685 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
686 RandomizeSampleVector(&random_generator, buffer);
687 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
688 stereo_stream_config, channel_pointers),
689 kNoErr);
690 }
691
692 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
693 /*num_channels=*/1,
694 /*has_keyboard=*/false);
695 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
696 RandomizeSampleVector(&random_generator, buffer);
697 EXPECT_EQ(
698 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
699 high_sample_rate_stream_config, channel_pointers),
700 kNoErr);
701 }
702
703 StreamConfig keyboard_stream_config(/*sample_rate_hz=*/16000,
704 /*num_channels=*/1,
705 /*has_keyboard=*/true);
706 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
707 RandomizeSampleVector(&random_generator, buffer);
708 EXPECT_EQ(apm->ProcessStream(channel_pointers, keyboard_stream_config,
709 keyboard_stream_config, channel_pointers),
710 kNoErr);
711 }
712}
713
714// Disable transient suppressor creation and run APM in ways that should trigger
715// calls to the transient suppressor API.
716TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Tommi87f70902021-04-27 14:43:08 +0200717 auto apm = rtc::make_ref_counted<AudioProcessingImpl>(webrtc::Config());
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200718 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
719
720 ApmSubmoduleCreationOverrides overrides;
721 overrides.transient_suppression = true;
722 apm->OverrideSubmoduleCreationForTesting(overrides);
723
724 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
725 float buffer[960];
726 float* channel_pointers[] = {&buffer[0], &buffer[480]};
727 Random random_generator(2341U);
728 constexpr int kFramesToProcessPerConfiguration = 3;
729 StreamConfig stream_config(/*sample_rate_hz=*/16000,
730 /*num_channels=*/1,
731 /*has_keyboard=*/false);
732
733 AudioProcessing::Config config = apm->GetConfig();
734 config.transient_suppression.enabled = true;
735 apm->ApplyConfig(config);
736 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
737 RandomizeSampleVector(&random_generator, buffer);
738 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
739 channel_pointers),
740 kNoErr);
741 }
742
743 config = apm->GetConfig();
744 config.transient_suppression.enabled = false;
745 apm->ApplyConfig(config);
746 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
747 RandomizeSampleVector(&random_generator, buffer);
748 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
749 channel_pointers),
750 kNoErr);
751 }
752
753 config = apm->GetConfig();
754 config.transient_suppression.enabled = true;
755 apm->ApplyConfig(config);
756 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
757 RandomizeSampleVector(&random_generator, buffer);
758 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
759 channel_pointers),
760 kNoErr);
761 }
762}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000763} // namespace webrtc