blob: 5354f54d35d7829610fa2b9122e00fe103ed9b8c [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:
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);
145 StreamConfig config(16000, 1, /*has_keyboard=*/false);
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).
Per Åhgren2507f8c2020-03-19 12:33:29 +0100153 config = StreamConfig(32000, 1, /*has_keyboard=*/false);
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.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100159 config = StreamConfig(32000, 2, /*has_keyboard=*/false);
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.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100167 config = StreamConfig(16000, 2, /*has_keyboard=*/false);
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;
186 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
187 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;
219 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
220 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;
252 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
253 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;
287 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
288 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;
376 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
377 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;
419 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
420 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;
453 apm_config.gain_controller1.mode =
454 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100455 apm_config.gain_controller2.enabled = false;
456 apm_config.pre_amplifier.enabled = false;
457 apm->ApplyConfig(apm_config);
458
Alessio Bazzicae4498052018-12-17 09:44:06 +0100459 constexpr int16_t kAudioLevel = 1000;
460 constexpr size_t kSampleRateHz = 48000;
461 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100462 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
463 StreamConfig stream_config(kSampleRateHz, kNumChannels,
464 /*has_keyboard=*/false);
465 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100466
467 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
468
Sam Zackrisson41478c72019-10-15 10:10:26 +0200469 const int initial_analog_gain = apm->recommended_stream_analog_level();
Per Åhgren0aefbf02019-08-23 21:29:17 +0200470 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100471 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, false))
472 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100473 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100474
475 // Force an analog gain change if it did not happen.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200476 if (initial_analog_gain == apm->recommended_stream_analog_level()) {
477 apm->set_stream_analog_level(initial_analog_gain + 1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100478 }
479
Per Åhgren0aefbf02019-08-23 21:29:17 +0200480 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100481 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, true))
482 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100483 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100484}
485
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200486TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
487 // Tests that the echo controller observes an echo path gain change when a
488 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200489 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200490 const auto* echo_control_factory_ptr = echo_control_factory.get();
491
Niels Möller4f776ac2021-07-02 11:30:54 +0200492 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200493 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200494 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200495 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200496 // Disable AGC.
497 webrtc::AudioProcessing::Config apm_config;
498 apm_config.gain_controller1.enabled = false;
499 apm_config.gain_controller2.enabled = false;
500 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200501
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200502 constexpr int16_t kAudioLevel = 10000;
503 constexpr size_t kSampleRateHz = 48000;
504 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100505 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
506 StreamConfig stream_config(kSampleRateHz, kNumChannels,
507 /*has_keyboard=*/false);
508 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200509
510 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
511
Per Åhgren0aefbf02019-08-23 21:29:17 +0200512 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200513 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100514 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200515 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100516 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200517
Per Åhgren0aefbf02019-08-23 21:29:17 +0200518 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200519 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100520 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200521 .Times(1);
522 apm->SetRuntimeSetting(
523 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100524 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200525
Per Åhgren0aefbf02019-08-23 21:29:17 +0200526 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200527 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100528 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200529 .Times(1);
530 apm->SetRuntimeSetting(
531 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100532 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200533
Per Åhgren0aefbf02019-08-23 21:29:17 +0200534 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200535 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100536 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200537 .Times(1);
538 apm->SetRuntimeSetting(
539 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100540 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200541}
542
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200543TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
544 // Make sure that signal changes caused by a render pre-processing sub-module
545 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200546 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200547 std::unique_ptr<CustomProcessing> test_render_pre_processor(
548 new TestRenderPreProcessor());
549 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200550 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200551 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200552 .SetEchoDetector(test_echo_detector)
553 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200554 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200555 webrtc::AudioProcessing::Config apm_config;
556 apm_config.pre_amplifier.enabled = true;
557 apm_config.residual_echo_detector.enabled = true;
558 apm->ApplyConfig(apm_config);
559
560 constexpr int16_t kAudioLevel = 1000;
561 constexpr int kSampleRateHz = 16000;
562 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100563 // Explicitly initialize APM to ensure no render frames are discarded.
564 const ProcessingConfig processing_config = {{
565 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
566 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
567 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
568 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
569 }};
570 apm->Initialize(processing_config);
571
Per Åhgren2507f8c2020-03-19 12:33:29 +0100572 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
573 StreamConfig stream_config(kSampleRateHz, kNumChannels,
574 /*has_keyboard=*/false);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200575
576 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
577 constexpr float kExpectedPreprocessedAudioLevel =
578 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
579 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
580
581 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100582 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200583 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100584 apm->ProcessReverseStream(frame.data(), stream_config,
585 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200586 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
587 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100588 frame.fill(kAudioLevel);
589 ASSERT_EQ(AudioProcessing::Error::kNoError,
590 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100591 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200592 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
593 // triggered, the line below checks that the call has occurred. If not, the
594 // APM implementation may have changed and this test might need to be adapted.
595 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
596 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
597 // produced by the render pre-processor.
598 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
599 test_echo_detector->last_render_audio_first_sample());
600}
601
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200602// Disabling build-optional submodules and trying to enable them via the APM
603// config should be bit-exact with running APM with said submodules disabled.
604// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
605TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200606 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200607 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
608
609 ApmSubmoduleCreationOverrides overrides;
610 overrides.transient_suppression = true;
611 apm->OverrideSubmoduleCreationForTesting(overrides);
612
613 AudioProcessing::Config apm_config = apm->GetConfig();
614 apm_config.transient_suppression.enabled = true;
615 apm->ApplyConfig(apm_config);
616
617 rtc::scoped_refptr<AudioProcessing> apm_reference =
618 AudioProcessingBuilder().Create();
619 apm_config = apm_reference->GetConfig();
620 apm_config.transient_suppression.enabled = false;
621 apm_reference->ApplyConfig(apm_config);
622
623 constexpr int kSampleRateHz = 16000;
624 constexpr int kNumChannels = 1;
625 std::array<float, kSampleRateHz / 100> buffer;
626 std::array<float, kSampleRateHz / 100> buffer_reference;
627 float* channel_pointers[] = {buffer.data()};
628 float* channel_pointers_reference[] = {buffer_reference.data()};
629 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
630 /*num_channels=*/kNumChannels,
631 /*has_keyboard=*/false);
632 Random random_generator(2341U);
633 constexpr int kFramesToProcessPerConfiguration = 10;
634
635 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
636 RandomizeSampleVector(&random_generator, buffer);
637 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
638 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
639 channel_pointers),
640 kNoErr);
641 ASSERT_EQ(
642 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
643 stream_config, channel_pointers_reference),
644 kNoErr);
645 for (int j = 0; j < kSampleRateHz / 100; ++j) {
646 EXPECT_EQ(buffer[j], buffer_reference[j]);
647 }
648 }
649}
650
651// Disable transient suppressor creation and run APM in ways that should trigger
652// calls to the transient suppressor API.
653TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200654 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200655 ASSERT_EQ(apm->Initialize(), kNoErr);
656
657 ApmSubmoduleCreationOverrides overrides;
658 overrides.transient_suppression = true;
659 apm->OverrideSubmoduleCreationForTesting(overrides);
660
661 AudioProcessing::Config config = apm->GetConfig();
662 config.transient_suppression.enabled = true;
663 apm->ApplyConfig(config);
664 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
665 float buffer[960];
666 float* channel_pointers[] = {&buffer[0], &buffer[480]};
667 Random random_generator(2341U);
668 constexpr int kFramesToProcessPerConfiguration = 3;
669
670 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
671 /*num_channels=*/1,
672 /*has_keyboard=*/false);
673 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
674 RandomizeSampleVector(&random_generator, buffer);
675 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
676 initial_stream_config, channel_pointers),
677 kNoErr);
678 }
679
680 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
681 /*num_channels=*/2,
682 /*has_keyboard=*/false);
683 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
684 RandomizeSampleVector(&random_generator, buffer);
685 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
686 stereo_stream_config, channel_pointers),
687 kNoErr);
688 }
689
690 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
691 /*num_channels=*/1,
692 /*has_keyboard=*/false);
693 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
694 RandomizeSampleVector(&random_generator, buffer);
695 EXPECT_EQ(
696 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
697 high_sample_rate_stream_config, channel_pointers),
698 kNoErr);
699 }
700
701 StreamConfig keyboard_stream_config(/*sample_rate_hz=*/16000,
702 /*num_channels=*/1,
703 /*has_keyboard=*/true);
704 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
705 RandomizeSampleVector(&random_generator, buffer);
706 EXPECT_EQ(apm->ProcessStream(channel_pointers, keyboard_stream_config,
707 keyboard_stream_config, channel_pointers),
708 kNoErr);
709 }
710}
711
712// Disable transient suppressor creation and run APM in ways that should trigger
713// calls to the transient suppressor API.
714TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200715 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200716 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
717
718 ApmSubmoduleCreationOverrides overrides;
719 overrides.transient_suppression = true;
720 apm->OverrideSubmoduleCreationForTesting(overrides);
721
722 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
723 float buffer[960];
724 float* channel_pointers[] = {&buffer[0], &buffer[480]};
725 Random random_generator(2341U);
726 constexpr int kFramesToProcessPerConfiguration = 3;
727 StreamConfig stream_config(/*sample_rate_hz=*/16000,
728 /*num_channels=*/1,
729 /*has_keyboard=*/false);
730
731 AudioProcessing::Config config = apm->GetConfig();
732 config.transient_suppression.enabled = true;
733 apm->ApplyConfig(config);
734 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
735 RandomizeSampleVector(&random_generator, buffer);
736 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
737 channel_pointers),
738 kNoErr);
739 }
740
741 config = apm->GetConfig();
742 config.transient_suppression.enabled = false;
743 apm->ApplyConfig(config);
744 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
745 RandomizeSampleVector(&random_generator, buffer);
746 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
747 channel_pointers),
748 kNoErr);
749 }
750
751 config = apm->GetConfig();
752 config.transient_suppression.enabled = true;
753 apm->ApplyConfig(config);
754 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
755 RandomizeSampleVector(&random_generator, buffer);
756 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
757 channel_pointers),
758 kNoErr);
759 }
760}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000761} // namespace webrtc