blob: e67c5ee4e548587d0f82ac39e6a018a330abcf5a [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>
Hanna Silenc69188d2022-09-16 11:38:56 +020015#include <tuple>
Alessio Bazzicae4498052018-12-17 09:44:06 +010016
Hanna Silenc69188d2022-09-16 11:38:56 +020017#include "absl/types/optional.h"
Niels Möller105711e2022-06-14 15:48:26 +020018#include "api/make_ref_counted.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010019#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 14:23:11 +020020#include "modules/audio_processing/include/audio_processing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020021#include "modules/audio_processing/optionally_built_submodule_creators.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020022#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020023#include "modules/audio_processing/test/echo_canceller_test_tools.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010024#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020025#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010026#include "rtc_base/checks.h"
Sam Zackrissonb37e59d2020-04-27 08:39:33 +020027#include "rtc_base/random.h"
Hanna Silenc69188d2022-09-16 11:38:56 +020028#include "rtc_base/strings/string_builder.h"
Hanna Silen0c1ad292022-06-16 16:35:45 +020029#include "test/field_trial.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020030#include "test/gmock.h"
31#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000032
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000033namespace webrtc {
peaha9cc40b2017-06-29 08:32:09 -070034namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000035
Alessio Bazzicae4498052018-12-17 09:44:06 +010036using ::testing::Invoke;
37using ::testing::NotNull;
38
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000039class MockInitialize : public AudioProcessingImpl {
40 public:
Alessio Bazzicabe1b8982021-09-17 08:26:10 +020041 MockInitialize() : AudioProcessingImpl() {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000042
Per Åhgren0ade9832020-09-01 23:57:20 +020043 MOCK_METHOD(void, InitializeLocked, (), (override));
Niels Möller5b747232021-07-26 17:16:25 +020044 void RealInitializeLocked() {
45 AssertLockedForTest();
Per Åhgren0ade9832020-09-01 23:57:20 +020046 AudioProcessingImpl::InitializeLocked();
pbos@webrtc.org788acd12014-12-15 09:41:24 +000047 }
peaha9cc40b2017-06-29 08:32:09 -070048
Danil Chapovalov704fb552020-05-18 15:10:15 +020049 MOCK_METHOD(void, AddRef, (), (const, override));
50 MOCK_METHOD(rtc::RefCountReleaseStatus, Release, (), (const, override));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000051};
52
Alessio Bazzicae4498052018-12-17 09:44:06 +010053// Creates MockEchoControl instances and provides a raw pointer access to
54// the next created one. The raw pointer is meant to be used with gmock.
55// Returning a pointer of the next created MockEchoControl instance is necessary
56// for the following reasons: (i) gmock expectations must be set before any call
57// occurs, (ii) APM is initialized the first time that
58// AudioProcessingImpl::ProcessStream() is called and the initialization leads
59// to the creation of a new EchoControl object.
60class MockEchoControlFactory : public EchoControlFactory {
61 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020062 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010063 // Returns a pointer to the next MockEchoControl that this factory creates.
64 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010065 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
66 int num_render_channels,
67 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010068 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020069 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010070 return mock;
71 }
72
73 private:
74 std::unique_ptr<MockEchoControl> next_mock_;
75};
76
Alessio Bazzicad2b97402018-08-09 14:23:11 +020077// Mocks EchoDetector and records the first samples of the last analyzed render
78// stream frame. Used to check what data is read by an EchoDetector
79// implementation injected into an APM.
80class TestEchoDetector : public EchoDetector {
81 public:
82 TestEchoDetector()
83 : analyze_render_audio_called_(false),
84 last_render_audio_first_sample_(0.f) {}
85 ~TestEchoDetector() override = default;
86 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
87 last_render_audio_first_sample_ = render_audio[0];
88 analyze_render_audio_called_ = true;
89 }
90 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
91 }
92 void Initialize(int capture_sample_rate_hz,
93 int num_capture_channels,
94 int render_sample_rate_hz,
95 int num_render_channels) override {}
96 EchoDetector::Metrics GetMetrics() const override { return {}; }
97 // Returns true if AnalyzeRenderAudio() has been called at least once.
98 bool analyze_render_audio_called() const {
99 return analyze_render_audio_called_;
100 }
101 // Returns the first sample of the last analyzed render frame.
102 float last_render_audio_first_sample() const {
103 return last_render_audio_first_sample_;
104 }
105
106 private:
107 bool analyze_render_audio_called_;
108 float last_render_audio_first_sample_;
109};
110
111// Mocks CustomProcessing and applies ProcessSample() to all the samples.
112// Meant to be injected into an APM to modify samples in a known and detectable
113// way.
114class TestRenderPreProcessor : public CustomProcessing {
115 public:
116 TestRenderPreProcessor() = default;
117 ~TestRenderPreProcessor() = default;
118 void Initialize(int sample_rate_hz, int num_channels) override {}
119 void Process(AudioBuffer* audio) override {
120 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200121 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200122 audio->num_frames());
123 std::transform(channel_view.begin(), channel_view.end(),
124 channel_view.begin(), ProcessSample);
125 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100126 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200127 std::string ToString() const override { return "TestRenderPreProcessor"; }
128 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
129 // Modifies a sample. This member is used in Process() to modify a frame and
130 // it is publicly visible to enable tests.
131 static constexpr float ProcessSample(float x) { return 2.f * x; }
132};
133
Hanna Silenc69188d2022-09-16 11:38:56 +0200134// Creates a simple `AudioProcessing` instance for APM input volume testing
135// with analog and digital AGC enabled and minimum volume `startup_min_volume`
136// at the startup.
137rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest(
138 int startup_min_volume) {
139 webrtc::AudioProcessing::Config config;
140 // Enable AGC1 analog.
141 config.gain_controller1.enabled = true;
142 config.gain_controller1.analog_gain_controller.enabled = true;
143 config.gain_controller1.analog_gain_controller.startup_min_volume =
144 startup_min_volume;
145 // Enable AGC2 digital.
146 config.gain_controller2.enabled = true;
147 config.gain_controller2.adaptive_digital.enabled = true;
148
149 auto apm(AudioProcessingBuilder().Create());
150 apm->ApplyConfig(config);
151 return apm;
152}
153
154// Runs `apm` input processing for volume adjustments for `num_frames` random
155// frames starting from the volume `initial_volume`. This includes three steps:
156// 1) Set the input volume 2) Process the stream 3) Set the new recommended
157// input volume. Returns the new recommended input volume.
158int ProcessInputVolume(AudioProcessing& apm,
159 int num_frames,
160 int initial_volume) {
161 constexpr int kSampleRateHz = 48000;
162 constexpr int kNumChannels = 1;
163 std::array<float, kSampleRateHz / 100> buffer;
164 float* channel_pointers[] = {buffer.data()};
165 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
166 /*num_channels=*/kNumChannels);
167 int recommended_input_volume = initial_volume;
168 for (int i = 0; i < num_frames; ++i) {
169 Random random_generator(2341U);
170 RandomizeSampleVector(&random_generator, buffer);
171
172 apm.set_stream_analog_level(recommended_input_volume);
173 apm.ProcessStream(channel_pointers, stream_config, stream_config,
174 channel_pointers);
175 recommended_input_volume = apm.recommended_stream_analog_level();
176 }
177 return recommended_input_volume;
178}
179
180constexpr char kMinMicLevelFieldTrial[] =
181 "WebRTC-Audio-2ndAgcMinMicLevelExperiment";
182constexpr int kMinInputVolume = 12;
183
184std::string GetMinMicLevelExperimentFieldTrial(absl::optional<int> value) {
185 char field_trial_buffer[64];
186 rtc::SimpleStringBuilder builder(field_trial_buffer);
187 if (value.has_value()) {
188 RTC_DCHECK_GE(*value, 0);
189 RTC_DCHECK_LE(*value, 255);
190 builder << kMinMicLevelFieldTrial << "/Enabled-" << *value << "/";
191 } else {
192 builder << kMinMicLevelFieldTrial << "/Disabled/";
193 }
194 return builder.str();
195}
196
197// TODO(webrtc:7494): Remove the fieldtrial from the input volume tests when
198// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is removed.
199class InputVolumeStartupParameterizedTest
200 : public ::testing::TestWithParam<
201 std::tuple<int, int, absl::optional<int>>> {
202 protected:
203 InputVolumeStartupParameterizedTest()
204 : field_trials_(
205 GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
206 int GetMinStartupVolume() const { return std::get<0>(GetParam()); }
207 int GetStartupVolume() const { return std::get<1>(GetParam()); }
208 int GetMinVolume() const {
209 return std::get<2>(GetParam()).value_or(kMinInputVolume);
210 }
211
212 private:
213 test::ScopedFieldTrials field_trials_;
214};
215
216class InputVolumeNotZeroParameterizedTest
217 : public ::testing::TestWithParam<
218 std::tuple<int, int, absl::optional<int>>> {
219 protected:
220 InputVolumeNotZeroParameterizedTest()
221 : field_trials_(
222 GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
223 int GetStartupVolume() const { return std::get<0>(GetParam()); }
224 int GetVolume() const { return std::get<1>(GetParam()); }
225 int GetMinVolume() const {
226 return std::get<2>(GetParam()).value_or(kMinInputVolume);
227 }
228 bool GetMinMicLevelExperimentEnabled() {
229 return std::get<2>(GetParam()).has_value();
230 }
231
232 private:
233 test::ScopedFieldTrials field_trials_;
234};
235
236class InputVolumeZeroParameterizedTest
237 : public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
238 protected:
239 InputVolumeZeroParameterizedTest()
240 : field_trials_(
241 GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
242 int GetStartupVolume() const { return std::get<0>(GetParam()); }
243 int GetMinVolume() const {
244 return std::get<1>(GetParam()).value_or(kMinInputVolume);
245 }
246
247 private:
248 test::ScopedFieldTrials field_trials_;
249};
250
peaha9cc40b2017-06-29 08:32:09 -0700251} // namespace
252
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000253TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200254 MockInitialize mock;
255 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000256 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
257
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200258 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000259 mock.Initialize();
260
Per Åhgren2507f8c2020-03-19 12:33:29 +0100261 constexpr size_t kMaxSampleRateHz = 32000;
262 constexpr size_t kMaxNumChannels = 2;
263 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
264 frame.fill(0);
Henrik Lundin64253a92022-02-04 09:02:48 +0000265 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 04:42:27 -0700266 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200267 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100268 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100269 EXPECT_NOERR(
270 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000271
272 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48 +0000273 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200274 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100275 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000276
277 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700278 // TODO(peah): Investigate why this causes 2 inits.
Henrik Lundin64253a92022-02-04 09:02:48 +0000279 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200280 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100281 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000282 // ProcessStream sets num_channels_ == num_output_channels.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100283 EXPECT_NOERR(
284 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000285
aluebsb0319552016-03-17 20:39:53 -0700286 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000287 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200288 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100289 EXPECT_NOERR(
290 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000291}
292
Alessio Bazzicac054e782018-04-16 12:10:09 +0200293TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200294 rtc::scoped_refptr<AudioProcessing> apm =
295 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200296 webrtc::AudioProcessing::Config apm_config;
297 apm_config.pre_amplifier.enabled = true;
298 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
299 apm->ApplyConfig(apm_config);
300
Per Åhgren2507f8c2020-03-19 12:33:29 +0100301 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200302 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200303 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200304
Per Åhgren2507f8c2020-03-19 12:33:29 +0100305 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000306 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100307 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100308 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100309 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200310 << "With factor 1, frame shouldn't be modified.";
311
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200312 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200313 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200314 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200315
316 // Process for two frames to have time to ramp up gain.
317 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100318 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100319 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200320 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100321 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200322 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200323}
324
Per Åhgrendb5d7282021-03-15 16:31:04 +0000325TEST(AudioProcessingImplTest,
326 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200327 rtc::scoped_refptr<AudioProcessing> apm =
328 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000329 webrtc::AudioProcessing::Config apm_config;
330 apm_config.capture_level_adjustment.enabled = true;
331 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
332 apm->ApplyConfig(apm_config);
333
334 constexpr int kSampleRateHz = 48000;
335 constexpr int16_t kAudioLevel = 10000;
336 constexpr size_t kNumChannels = 2;
337
338 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000339 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000340 frame.fill(kAudioLevel);
341 apm->ProcessStream(frame.data(), config, config, frame.data());
342 EXPECT_EQ(frame[100], kAudioLevel)
343 << "With factor 1, frame shouldn't be modified.";
344
345 constexpr float kGainFactor = 2.f;
346 apm->SetRuntimeSetting(
347 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
348
349 // Process for two frames to have time to ramp up gain.
350 for (int i = 0; i < 2; ++i) {
351 frame.fill(kAudioLevel);
352 apm->ProcessStream(frame.data(), config, config, frame.data());
353 }
354 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
355 << "Frame should be amplified.";
356}
357
358TEST(AudioProcessingImplTest,
359 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200360 rtc::scoped_refptr<AudioProcessing> apm =
361 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000362 webrtc::AudioProcessing::Config apm_config;
363 apm_config.capture_level_adjustment.enabled = true;
364 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
365 apm->ApplyConfig(apm_config);
366
367 constexpr int kSampleRateHz = 48000;
368 constexpr int16_t kAudioLevel = 10000;
369 constexpr size_t kNumChannels = 2;
370
371 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000372 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000373 frame.fill(kAudioLevel);
374 apm->ProcessStream(frame.data(), config, config, frame.data());
375 EXPECT_EQ(frame[100], kAudioLevel)
376 << "With factor 1, frame shouldn't be modified.";
377
378 constexpr float kGainFactor = 2.f;
379 apm->SetRuntimeSetting(
380 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
381
382 // Process for two frames to have time to ramp up gain.
383 for (int i = 0; i < 2; ++i) {
384 frame.fill(kAudioLevel);
385 apm->ProcessStream(frame.data(), config, config, frame.data());
386 }
387 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
388 << "Frame should be amplified.";
389}
390
Per Åhgren652ada52021-03-03 10:52:44 +0000391TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
392 // Tests that the echo controller observes that the capture usage has been
393 // updated.
394 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
395 const MockEchoControlFactory* echo_control_factory_ptr =
396 echo_control_factory.get();
397
Niels Möller4f776ac2021-07-02 11:30:54 +0200398 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000399 AudioProcessingBuilderForTesting()
400 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200401 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000402
403 constexpr int16_t kAudioLevel = 10000;
404 constexpr int kSampleRateHz = 48000;
405 constexpr int kNumChannels = 2;
406 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000407 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000408 frame.fill(kAudioLevel);
409
410 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
411
412 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
413 // are passed.
414 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
415 apm->ProcessStream(frame.data(), config, config, frame.data());
416
417 // Ensure that SetCaptureOutputUsage is called with the right information when
418 // a runtime setting is passed.
419 EXPECT_CALL(*echo_control_mock,
420 SetCaptureOutputUsage(/*capture_output_used=*/false))
421 .Times(1);
422 EXPECT_TRUE(apm->PostRuntimeSetting(
423 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
424 /*capture_output_used=*/false)));
425 apm->ProcessStream(frame.data(), config, config, frame.data());
426
427 EXPECT_CALL(*echo_control_mock,
428 SetCaptureOutputUsage(/*capture_output_used=*/true))
429 .Times(1);
430 EXPECT_TRUE(apm->PostRuntimeSetting(
431 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
432 /*capture_output_used=*/true)));
433 apm->ProcessStream(frame.data(), config, config, frame.data());
434
435 // The number of positions to place items in the queue is equal to the queue
436 // size minus 1.
437 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
438
439 // Ensure that SetCaptureOutputUsage is called with the right information when
440 // many runtime settings are passed.
441 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
442 EXPECT_TRUE(apm->PostRuntimeSetting(
443 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
444 /*capture_output_used=*/false)));
445 }
446 EXPECT_CALL(*echo_control_mock,
447 SetCaptureOutputUsage(/*capture_output_used=*/false))
448 .Times(kNumSlotsInQueue - 1);
449 apm->ProcessStream(frame.data(), config, config, frame.data());
450
451 // Ensure that SetCaptureOutputUsage is properly called with the fallback
452 // value when the runtime settings queue becomes full.
453 for (int k = 0; k < kNumSlotsInQueue; ++k) {
454 EXPECT_TRUE(apm->PostRuntimeSetting(
455 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
456 /*capture_output_used=*/false)));
457 }
458 EXPECT_FALSE(apm->PostRuntimeSetting(
459 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
460 /*capture_output_used=*/false)));
461 EXPECT_FALSE(apm->PostRuntimeSetting(
462 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
463 /*capture_output_used=*/false)));
464 EXPECT_CALL(*echo_control_mock,
465 SetCaptureOutputUsage(/*capture_output_used=*/false))
466 .Times(kNumSlotsInQueue);
467 EXPECT_CALL(*echo_control_mock,
468 SetCaptureOutputUsage(/*capture_output_used=*/true))
469 .Times(1);
470 apm->ProcessStream(frame.data(), config, config, frame.data());
471}
472
Alessio Bazzicae4498052018-12-17 09:44:06 +0100473TEST(AudioProcessingImplTest,
474 EchoControllerObservesPreAmplifierEchoPathGainChange) {
475 // Tests that the echo controller observes an echo path gain change when the
476 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200477 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100478 const auto* echo_control_factory_ptr = echo_control_factory.get();
479
Niels Möller4f776ac2021-07-02 11:30:54 +0200480 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200481 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100482 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200483 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200484 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100485 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200486 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100487 apm_config.gain_controller2.enabled = false;
488 apm_config.pre_amplifier.enabled = true;
489 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
490 apm->ApplyConfig(apm_config);
491
Alessio Bazzicae4498052018-12-17 09:44:06 +0100492 constexpr int16_t kAudioLevel = 10000;
493 constexpr size_t kSampleRateHz = 48000;
494 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100495 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000496 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100497 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100498
499 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
500
Per Åhgren0aefbf02019-08-23 21:29:17 +0200501 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200502 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100503 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200504 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100505 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100506
Per Åhgren0aefbf02019-08-23 21:29:17 +0200507 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200508 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100509 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200510 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100511 apm->SetRuntimeSetting(
512 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100513 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100514}
515
516TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000517 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
518 // Tests that the echo controller observes an echo path gain change when the
519 // pre-amplifier submodule changes the gain.
520 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
521 const auto* echo_control_factory_ptr = echo_control_factory.get();
522
Niels Möller4f776ac2021-07-02 11:30:54 +0200523 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000524 AudioProcessingBuilderForTesting()
525 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200526 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000527 // Disable AGC.
528 webrtc::AudioProcessing::Config apm_config;
529 apm_config.gain_controller1.enabled = false;
530 apm_config.gain_controller2.enabled = false;
531 apm_config.capture_level_adjustment.enabled = true;
532 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
533 apm->ApplyConfig(apm_config);
534
535 constexpr int16_t kAudioLevel = 10000;
536 constexpr size_t kSampleRateHz = 48000;
537 constexpr size_t kNumChannels = 2;
538 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000539 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000540 frame.fill(kAudioLevel);
541
542 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
543
544 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
545 EXPECT_CALL(*echo_control_mock,
546 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
547 .Times(1);
548 apm->ProcessStream(frame.data(), config, config, frame.data());
549
550 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
551 EXPECT_CALL(*echo_control_mock,
552 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
553 .Times(1);
554 apm->SetRuntimeSetting(
555 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
556 apm->ProcessStream(frame.data(), config, config, frame.data());
557}
558
559TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100560 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
561 // Tests that the echo controller observes an echo path gain change when the
562 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200563 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100564 const auto* echo_control_factory_ptr = echo_control_factory.get();
565
Niels Möller4f776ac2021-07-02 11:30:54 +0200566 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200567 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100568 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200569 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100570 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200571 // Enable AGC1.
572 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200573 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100574 apm_config.gain_controller2.enabled = false;
575 apm_config.pre_amplifier.enabled = false;
576 apm->ApplyConfig(apm_config);
577
Alessio Bazzicae4498052018-12-17 09:44:06 +0100578 constexpr int16_t kAudioLevel = 1000;
579 constexpr size_t kSampleRateHz = 48000;
580 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100581 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000582 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100583 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100584
585 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
586
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200587 constexpr int kInitialStreamAnalogLevel = 123;
588 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
589
590 // When the first fame is processed, no echo path gain change must be
591 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200592 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200593 EXPECT_CALL(*echo_control_mock,
594 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100595 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100596 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100597
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200598 // Simulate the application of the recommended analog level.
599 int recommended_analog_level = apm->recommended_stream_analog_level();
600 if (recommended_analog_level == kInitialStreamAnalogLevel) {
601 // Force an analog gain change if it did not happen.
602 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100603 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200604 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100605
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200606 // After the first fame and with a stream analog level change, the echo path
607 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200608 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200609 EXPECT_CALL(*echo_control_mock,
610 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100611 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100612 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100613}
614
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200615// Tests that a stream is successfully processed when AGC2 adaptive digital is
616// used and when the field trial
617// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200618TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200619 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
620 webrtc::test::ScopedFieldTrials field_trials(
621 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/");
622 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
623 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200624 webrtc::AudioProcessing::Config apm_config;
625 // Disable AGC1 analog.
626 apm_config.gain_controller1.enabled = false;
627 // Enable AGC2 digital.
628 apm_config.gain_controller2.enabled = true;
629 apm_config.gain_controller2.adaptive_digital.enabled = true;
630 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200631 constexpr int kSampleRateHz = 48000;
632 constexpr int kNumChannels = 1;
633 std::array<float, kSampleRateHz / 100> buffer;
634 float* channel_pointers[] = {buffer.data()};
635 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
636 /*num_channels=*/kNumChannels);
637 Random random_generator(2341U);
638 constexpr int kFramesToProcess = 10;
639 for (int i = 0; i < kFramesToProcess; ++i) {
640 RandomizeSampleVector(&random_generator, buffer);
641 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
642 channel_pointers),
643 kNoErr);
644 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200645}
646
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200647// Tests that a stream is successfully processed when AGC2 adaptive digital is
648// used and when the field trial
649// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
650TEST(AudioProcessingImplTest,
651 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200652 webrtc::test::ScopedFieldTrials field_trials(
653 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/");
654 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
655 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
656 webrtc::AudioProcessing::Config apm_config;
657 // Disable AGC1 analog.
658 apm_config.gain_controller1.enabled = false;
659 // Enable AGC2 digital.
660 apm_config.gain_controller2.enabled = true;
661 apm_config.gain_controller2.adaptive_digital.enabled = true;
662 apm->ApplyConfig(apm_config);
663 constexpr int kSampleRateHz = 48000;
664 constexpr int kNumChannels = 1;
665 std::array<float, kSampleRateHz / 100> buffer;
666 float* channel_pointers[] = {buffer.data()};
667 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
668 /*num_channels=*/kNumChannels);
669 Random random_generator(2341U);
670 constexpr int kFramesToProcess = 10;
671 for (int i = 0; i < kFramesToProcess; ++i) {
672 RandomizeSampleVector(&random_generator, buffer);
673 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
674 channel_pointers),
675 kNoErr);
676 }
677}
678
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200679TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
680 // Tests that the echo controller observes an echo path gain change when a
681 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200682 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200683 const auto* echo_control_factory_ptr = echo_control_factory.get();
684
Niels Möller4f776ac2021-07-02 11:30:54 +0200685 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200686 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200687 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200688 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200689 // Disable AGC.
690 webrtc::AudioProcessing::Config apm_config;
691 apm_config.gain_controller1.enabled = false;
692 apm_config.gain_controller2.enabled = false;
693 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200694
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200695 constexpr int16_t kAudioLevel = 10000;
696 constexpr size_t kSampleRateHz = 48000;
697 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100698 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000699 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100700 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200701
702 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
703
Per Åhgren0aefbf02019-08-23 21:29:17 +0200704 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200705 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100706 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200707 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100708 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200709
Per Åhgren0aefbf02019-08-23 21:29:17 +0200710 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200711 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100712 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200713 .Times(1);
714 apm->SetRuntimeSetting(
715 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100716 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200717
Per Åhgren0aefbf02019-08-23 21:29:17 +0200718 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200719 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100720 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200721 .Times(1);
722 apm->SetRuntimeSetting(
723 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100724 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200725
Per Åhgren0aefbf02019-08-23 21:29:17 +0200726 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200727 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100728 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200729 .Times(1);
730 apm->SetRuntimeSetting(
731 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100732 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200733}
734
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200735TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
736 // Make sure that signal changes caused by a render pre-processing sub-module
737 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200738 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200739 std::unique_ptr<CustomProcessing> test_render_pre_processor(
740 new TestRenderPreProcessor());
741 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200742 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200743 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200744 .SetEchoDetector(test_echo_detector)
745 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200746 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200747 webrtc::AudioProcessing::Config apm_config;
748 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200749 apm->ApplyConfig(apm_config);
750
751 constexpr int16_t kAudioLevel = 1000;
752 constexpr int kSampleRateHz = 16000;
753 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100754 // Explicitly initialize APM to ensure no render frames are discarded.
755 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000756 {kSampleRateHz, kNumChannels},
757 {kSampleRateHz, kNumChannels},
758 {kSampleRateHz, kNumChannels},
759 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100760 }};
761 apm->Initialize(processing_config);
762
Per Åhgren2507f8c2020-03-19 12:33:29 +0100763 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000764 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200765
766 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
767 constexpr float kExpectedPreprocessedAudioLevel =
768 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
769 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
770
771 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100772 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200773 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100774 apm->ProcessReverseStream(frame.data(), stream_config,
775 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200776 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
777 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100778 frame.fill(kAudioLevel);
779 ASSERT_EQ(AudioProcessing::Error::kNoError,
780 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100781 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200782 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
783 // triggered, the line below checks that the call has occurred. If not, the
784 // APM implementation may have changed and this test might need to be adapted.
785 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
786 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
787 // produced by the render pre-processor.
788 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
789 test_echo_detector->last_render_audio_first_sample());
790}
791
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200792// Disabling build-optional submodules and trying to enable them via the APM
793// config should be bit-exact with running APM with said submodules disabled.
794// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
795TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200796 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200797 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
798
799 ApmSubmoduleCreationOverrides overrides;
800 overrides.transient_suppression = true;
801 apm->OverrideSubmoduleCreationForTesting(overrides);
802
803 AudioProcessing::Config apm_config = apm->GetConfig();
804 apm_config.transient_suppression.enabled = true;
805 apm->ApplyConfig(apm_config);
806
807 rtc::scoped_refptr<AudioProcessing> apm_reference =
808 AudioProcessingBuilder().Create();
809 apm_config = apm_reference->GetConfig();
810 apm_config.transient_suppression.enabled = false;
811 apm_reference->ApplyConfig(apm_config);
812
813 constexpr int kSampleRateHz = 16000;
814 constexpr int kNumChannels = 1;
815 std::array<float, kSampleRateHz / 100> buffer;
816 std::array<float, kSampleRateHz / 100> buffer_reference;
817 float* channel_pointers[] = {buffer.data()};
818 float* channel_pointers_reference[] = {buffer_reference.data()};
819 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000820 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200821 Random random_generator(2341U);
822 constexpr int kFramesToProcessPerConfiguration = 10;
823
824 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
825 RandomizeSampleVector(&random_generator, buffer);
826 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
827 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
828 channel_pointers),
829 kNoErr);
830 ASSERT_EQ(
831 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
832 stream_config, channel_pointers_reference),
833 kNoErr);
834 for (int j = 0; j < kSampleRateHz / 100; ++j) {
835 EXPECT_EQ(buffer[j], buffer_reference[j]);
836 }
837 }
838}
839
840// Disable transient suppressor creation and run APM in ways that should trigger
841// calls to the transient suppressor API.
842TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200843 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200844 ASSERT_EQ(apm->Initialize(), kNoErr);
845
846 ApmSubmoduleCreationOverrides overrides;
847 overrides.transient_suppression = true;
848 apm->OverrideSubmoduleCreationForTesting(overrides);
849
850 AudioProcessing::Config config = apm->GetConfig();
851 config.transient_suppression.enabled = true;
852 apm->ApplyConfig(config);
853 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
854 float buffer[960];
855 float* channel_pointers[] = {&buffer[0], &buffer[480]};
856 Random random_generator(2341U);
857 constexpr int kFramesToProcessPerConfiguration = 3;
858
859 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000860 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200861 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
862 RandomizeSampleVector(&random_generator, buffer);
863 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
864 initial_stream_config, channel_pointers),
865 kNoErr);
866 }
867
868 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000869 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200870 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
871 RandomizeSampleVector(&random_generator, buffer);
872 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
873 stereo_stream_config, channel_pointers),
874 kNoErr);
875 }
876
877 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000878 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200879 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
880 RandomizeSampleVector(&random_generator, buffer);
881 EXPECT_EQ(
882 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
883 high_sample_rate_stream_config, channel_pointers),
884 kNoErr);
885 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200886}
887
888// Disable transient suppressor creation and run APM in ways that should trigger
889// calls to the transient suppressor API.
890TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200891 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200892 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
893
894 ApmSubmoduleCreationOverrides overrides;
895 overrides.transient_suppression = true;
896 apm->OverrideSubmoduleCreationForTesting(overrides);
897
898 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
899 float buffer[960];
900 float* channel_pointers[] = {&buffer[0], &buffer[480]};
901 Random random_generator(2341U);
902 constexpr int kFramesToProcessPerConfiguration = 3;
903 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000904 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200905
906 AudioProcessing::Config config = apm->GetConfig();
907 config.transient_suppression.enabled = true;
908 apm->ApplyConfig(config);
909 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
910 RandomizeSampleVector(&random_generator, buffer);
911 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
912 channel_pointers),
913 kNoErr);
914 }
915
916 config = apm->GetConfig();
917 config.transient_suppression.enabled = false;
918 apm->ApplyConfig(config);
919 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
920 RandomizeSampleVector(&random_generator, buffer);
921 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
922 channel_pointers),
923 kNoErr);
924 }
925
926 config = apm->GetConfig();
927 config.transient_suppression.enabled = true;
928 apm->ApplyConfig(config);
929 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
930 RandomizeSampleVector(&random_generator, buffer);
931 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
932 channel_pointers),
933 kNoErr);
934 }
935}
Hanna Silenc69188d2022-09-16 11:38:56 +0200936
937// Tests that the minimum startup volume is applied at the startup.
938TEST_P(InputVolumeStartupParameterizedTest,
939 VerifyStartupMinVolumeAppliedAtStartup) {
940 const int applied_startup_input_volume = GetStartupVolume();
941 const int startup_min_volume = GetMinStartupVolume();
942 const int min_volume = std::max(startup_min_volume, GetMinVolume());
943 const int expected_volume =
944 std::max(applied_startup_input_volume, min_volume);
945 auto apm(CreateApmForInputVolumeTest(startup_min_volume));
946
947 const int recommended_input_volume =
948 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
949
950 ASSERT_EQ(recommended_input_volume, expected_volume);
951}
952
953// Tests that the minimum input volume is applied if the volume is manually
954// adjusted to a non-zero value only if
955// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled.
956TEST_P(InputVolumeNotZeroParameterizedTest,
957 VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
958 constexpr int kStartupMinVolume = 0;
959 const int applied_startup_input_volume = GetStartupVolume();
960 const int applied_input_volume = GetVolume();
961 const int expected_volume = std::max(applied_input_volume, GetMinVolume());
962 auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
963
964 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
965 const int recommended_input_volume =
966 ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
967
968 ASSERT_NE(applied_input_volume, 0);
969 if (GetMinMicLevelExperimentEnabled()) {
970 ASSERT_EQ(recommended_input_volume, expected_volume);
971 } else {
972 ASSERT_EQ(recommended_input_volume, applied_input_volume);
973 }
974}
975
976// Tests that the minimum input volume is not applied if the volume is manually
977// adjusted to zero.
978TEST_P(InputVolumeZeroParameterizedTest,
979 VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
980 constexpr int kStartupMinVolume = 0;
981 constexpr int kZeroVolume = 0;
982 const int applied_startup_input_volume = GetStartupVolume();
983 auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
984
985 const int recommended_input_volume_after_startup =
986 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
987 const int recommended_input_volume =
988 ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
989
990 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
991 ASSERT_EQ(recommended_input_volume, kZeroVolume);
992}
993
994// Tests that the minimum input volume is applied if the volume is not zero
995// before it is automatically adjusted.
996TEST_P(InputVolumeNotZeroParameterizedTest,
997 VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
998 constexpr int kStartupMinVolume = 0;
999 const int applied_startup_input_volume = GetStartupVolume();
1000 const int applied_input_volume = GetVolume();
1001 auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
1002
1003 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1004 const int recommended_input_volume =
1005 ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
1006
1007 ASSERT_NE(applied_input_volume, 0);
1008 if (recommended_input_volume != applied_input_volume) {
1009 ASSERT_GE(recommended_input_volume, GetMinVolume());
1010 }
1011}
1012
1013// Tests that the minimum input volume is not applied if the volume is zero
1014// before it is automatically adjusted.
1015TEST_P(InputVolumeZeroParameterizedTest,
1016 VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
1017 constexpr int kStartupMinVolume = 0;
1018 constexpr int kZeroVolume = 0;
1019 const int applied_startup_input_volume = GetStartupVolume();
1020 auto apm(CreateApmForInputVolumeTest(kStartupMinVolume));
1021
1022 const int recommended_input_volume_after_startup =
1023 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1024 const int recommended_input_volume =
1025 ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
1026
1027 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
1028 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1029}
1030
1031INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1032 InputVolumeStartupParameterizedTest,
1033 ::testing::Combine(::testing::Values(0, 5, 15),
1034 ::testing::Values(0, 5, 30),
1035 ::testing::Values(absl::nullopt,
1036 20)));
1037
1038INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1039 InputVolumeNotZeroParameterizedTest,
1040 ::testing::Combine(::testing::Values(0, 5, 15),
1041 ::testing::Values(1, 5, 30),
1042 ::testing::Values(absl::nullopt,
1043 20)));
1044
1045INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1046 InputVolumeZeroParameterizedTest,
1047 ::testing::Combine(::testing::Values(0, 5, 15),
1048 ::testing::Values(absl::nullopt,
1049 20)));
1050
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001051} // namespace webrtc