blob: 729da345bc7626ad0b910fb4b8caac082855af18 [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
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200135// with analog and digital AGC enabled.
136rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest() {
Hanna Silenc69188d2022-09-16 11:38:56 +0200137 webrtc::AudioProcessing::Config config;
138 // Enable AGC1 analog.
139 config.gain_controller1.enabled = true;
140 config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200141 // Enable AGC2 adaptive digital.
142 config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
143 false;
Hanna Silenc69188d2022-09-16 11:38:56 +0200144 config.gain_controller2.enabled = true;
145 config.gain_controller2.adaptive_digital.enabled = true;
146
147 auto apm(AudioProcessingBuilder().Create());
148 apm->ApplyConfig(config);
149 return apm;
150}
151
152// Runs `apm` input processing for volume adjustments for `num_frames` random
153// frames starting from the volume `initial_volume`. This includes three steps:
154// 1) Set the input volume 2) Process the stream 3) Set the new recommended
155// input volume. Returns the new recommended input volume.
156int ProcessInputVolume(AudioProcessing& apm,
157 int num_frames,
158 int initial_volume) {
159 constexpr int kSampleRateHz = 48000;
160 constexpr int kNumChannels = 1;
161 std::array<float, kSampleRateHz / 100> buffer;
162 float* channel_pointers[] = {buffer.data()};
163 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
164 /*num_channels=*/kNumChannels);
165 int recommended_input_volume = initial_volume;
166 for (int i = 0; i < num_frames; ++i) {
167 Random random_generator(2341U);
168 RandomizeSampleVector(&random_generator, buffer);
169
170 apm.set_stream_analog_level(recommended_input_volume);
171 apm.ProcessStream(channel_pointers, stream_config, stream_config,
172 channel_pointers);
173 recommended_input_volume = apm.recommended_stream_analog_level();
174 }
175 return recommended_input_volume;
176}
177
178constexpr char kMinMicLevelFieldTrial[] =
179 "WebRTC-Audio-2ndAgcMinMicLevelExperiment";
180constexpr int kMinInputVolume = 12;
181
182std::string GetMinMicLevelExperimentFieldTrial(absl::optional<int> value) {
183 char field_trial_buffer[64];
184 rtc::SimpleStringBuilder builder(field_trial_buffer);
185 if (value.has_value()) {
186 RTC_DCHECK_GE(*value, 0);
187 RTC_DCHECK_LE(*value, 255);
188 builder << kMinMicLevelFieldTrial << "/Enabled-" << *value << "/";
189 } else {
190 builder << kMinMicLevelFieldTrial << "/Disabled/";
191 }
192 return builder.str();
193}
194
195// TODO(webrtc:7494): Remove the fieldtrial from the input volume tests when
196// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is removed.
197class InputVolumeStartupParameterizedTest
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200198 : public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
Hanna Silenc69188d2022-09-16 11:38:56 +0200199 protected:
200 InputVolumeStartupParameterizedTest()
201 : field_trials_(
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200202 GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
203 int GetStartupVolume() const { return std::get<0>(GetParam()); }
Hanna Silenc69188d2022-09-16 11:38:56 +0200204 int GetMinVolume() const {
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200205 return std::get<1>(GetParam()).value_or(kMinInputVolume);
Hanna Silenc69188d2022-09-16 11:38:56 +0200206 }
207
208 private:
209 test::ScopedFieldTrials field_trials_;
210};
211
212class InputVolumeNotZeroParameterizedTest
213 : public ::testing::TestWithParam<
214 std::tuple<int, int, absl::optional<int>>> {
215 protected:
216 InputVolumeNotZeroParameterizedTest()
217 : field_trials_(
218 GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
219 int GetStartupVolume() const { return std::get<0>(GetParam()); }
220 int GetVolume() const { return std::get<1>(GetParam()); }
221 int GetMinVolume() const {
222 return std::get<2>(GetParam()).value_or(kMinInputVolume);
223 }
224 bool GetMinMicLevelExperimentEnabled() {
225 return std::get<2>(GetParam()).has_value();
226 }
227
228 private:
229 test::ScopedFieldTrials field_trials_;
230};
231
232class InputVolumeZeroParameterizedTest
233 : public ::testing::TestWithParam<std::tuple<int, absl::optional<int>>> {
234 protected:
235 InputVolumeZeroParameterizedTest()
236 : field_trials_(
237 GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
238 int GetStartupVolume() const { return std::get<0>(GetParam()); }
239 int GetMinVolume() const {
240 return std::get<1>(GetParam()).value_or(kMinInputVolume);
241 }
242
243 private:
244 test::ScopedFieldTrials field_trials_;
245};
246
peaha9cc40b2017-06-29 08:32:09 -0700247} // namespace
248
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000249TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200250 MockInitialize mock;
251 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000252 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
253
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200254 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000255 mock.Initialize();
256
Per Åhgren2507f8c2020-03-19 12:33:29 +0100257 constexpr size_t kMaxSampleRateHz = 32000;
258 constexpr size_t kMaxNumChannels = 2;
259 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
260 frame.fill(0);
Henrik Lundin64253a92022-02-04 09:02:48 +0000261 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 04:42:27 -0700262 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200263 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100264 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100265 EXPECT_NOERR(
266 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000267
268 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48 +0000269 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200270 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100271 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000272
273 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700274 // TODO(peah): Investigate why this causes 2 inits.
Henrik Lundin64253a92022-02-04 09:02:48 +0000275 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200276 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100277 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000278 // ProcessStream sets num_channels_ == num_output_channels.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100279 EXPECT_NOERR(
280 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000281
aluebsb0319552016-03-17 20:39:53 -0700282 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000283 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200284 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100285 EXPECT_NOERR(
286 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000287}
288
Alessio Bazzicac054e782018-04-16 12:10:09 +0200289TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200290 rtc::scoped_refptr<AudioProcessing> apm =
291 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200292 webrtc::AudioProcessing::Config apm_config;
293 apm_config.pre_amplifier.enabled = true;
294 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
295 apm->ApplyConfig(apm_config);
296
Per Åhgren2507f8c2020-03-19 12:33:29 +0100297 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200298 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200299 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200300
Per Åhgren2507f8c2020-03-19 12:33:29 +0100301 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000302 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100303 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100304 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100305 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200306 << "With factor 1, frame shouldn't be modified.";
307
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200308 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200309 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200310 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200311
312 // Process for two frames to have time to ramp up gain.
313 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100314 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100315 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200316 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100317 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200318 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200319}
320
Per Åhgrendb5d7282021-03-15 16:31:04 +0000321TEST(AudioProcessingImplTest,
322 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200323 rtc::scoped_refptr<AudioProcessing> apm =
324 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000325 webrtc::AudioProcessing::Config apm_config;
326 apm_config.capture_level_adjustment.enabled = true;
327 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
328 apm->ApplyConfig(apm_config);
329
330 constexpr int kSampleRateHz = 48000;
331 constexpr int16_t kAudioLevel = 10000;
332 constexpr size_t kNumChannels = 2;
333
334 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000335 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000336 frame.fill(kAudioLevel);
337 apm->ProcessStream(frame.data(), config, config, frame.data());
338 EXPECT_EQ(frame[100], kAudioLevel)
339 << "With factor 1, frame shouldn't be modified.";
340
341 constexpr float kGainFactor = 2.f;
342 apm->SetRuntimeSetting(
343 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
344
345 // Process for two frames to have time to ramp up gain.
346 for (int i = 0; i < 2; ++i) {
347 frame.fill(kAudioLevel);
348 apm->ProcessStream(frame.data(), config, config, frame.data());
349 }
350 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
351 << "Frame should be amplified.";
352}
353
354TEST(AudioProcessingImplTest,
355 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200356 rtc::scoped_refptr<AudioProcessing> apm =
357 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000358 webrtc::AudioProcessing::Config apm_config;
359 apm_config.capture_level_adjustment.enabled = true;
360 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
361 apm->ApplyConfig(apm_config);
362
363 constexpr int kSampleRateHz = 48000;
364 constexpr int16_t kAudioLevel = 10000;
365 constexpr size_t kNumChannels = 2;
366
367 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000368 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000369 frame.fill(kAudioLevel);
370 apm->ProcessStream(frame.data(), config, config, frame.data());
371 EXPECT_EQ(frame[100], kAudioLevel)
372 << "With factor 1, frame shouldn't be modified.";
373
374 constexpr float kGainFactor = 2.f;
375 apm->SetRuntimeSetting(
376 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
377
378 // Process for two frames to have time to ramp up gain.
379 for (int i = 0; i < 2; ++i) {
380 frame.fill(kAudioLevel);
381 apm->ProcessStream(frame.data(), config, config, frame.data());
382 }
383 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
384 << "Frame should be amplified.";
385}
386
Per Åhgren652ada52021-03-03 10:52:44 +0000387TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
388 // Tests that the echo controller observes that the capture usage has been
389 // updated.
390 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
391 const MockEchoControlFactory* echo_control_factory_ptr =
392 echo_control_factory.get();
393
Niels Möller4f776ac2021-07-02 11:30:54 +0200394 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000395 AudioProcessingBuilderForTesting()
396 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200397 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000398
399 constexpr int16_t kAudioLevel = 10000;
400 constexpr int kSampleRateHz = 48000;
401 constexpr int kNumChannels = 2;
402 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000403 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000404 frame.fill(kAudioLevel);
405
406 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
407
408 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
409 // are passed.
410 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
411 apm->ProcessStream(frame.data(), config, config, frame.data());
412
413 // Ensure that SetCaptureOutputUsage is called with the right information when
414 // a runtime setting is passed.
415 EXPECT_CALL(*echo_control_mock,
416 SetCaptureOutputUsage(/*capture_output_used=*/false))
417 .Times(1);
418 EXPECT_TRUE(apm->PostRuntimeSetting(
419 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
420 /*capture_output_used=*/false)));
421 apm->ProcessStream(frame.data(), config, config, frame.data());
422
423 EXPECT_CALL(*echo_control_mock,
424 SetCaptureOutputUsage(/*capture_output_used=*/true))
425 .Times(1);
426 EXPECT_TRUE(apm->PostRuntimeSetting(
427 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
428 /*capture_output_used=*/true)));
429 apm->ProcessStream(frame.data(), config, config, frame.data());
430
431 // The number of positions to place items in the queue is equal to the queue
432 // size minus 1.
433 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
434
435 // Ensure that SetCaptureOutputUsage is called with the right information when
436 // many runtime settings are passed.
437 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
438 EXPECT_TRUE(apm->PostRuntimeSetting(
439 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
440 /*capture_output_used=*/false)));
441 }
442 EXPECT_CALL(*echo_control_mock,
443 SetCaptureOutputUsage(/*capture_output_used=*/false))
444 .Times(kNumSlotsInQueue - 1);
445 apm->ProcessStream(frame.data(), config, config, frame.data());
446
447 // Ensure that SetCaptureOutputUsage is properly called with the fallback
448 // value when the runtime settings queue becomes full.
449 for (int k = 0; k < kNumSlotsInQueue; ++k) {
450 EXPECT_TRUE(apm->PostRuntimeSetting(
451 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
452 /*capture_output_used=*/false)));
453 }
454 EXPECT_FALSE(apm->PostRuntimeSetting(
455 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
456 /*capture_output_used=*/false)));
457 EXPECT_FALSE(apm->PostRuntimeSetting(
458 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
459 /*capture_output_used=*/false)));
460 EXPECT_CALL(*echo_control_mock,
461 SetCaptureOutputUsage(/*capture_output_used=*/false))
462 .Times(kNumSlotsInQueue);
463 EXPECT_CALL(*echo_control_mock,
464 SetCaptureOutputUsage(/*capture_output_used=*/true))
465 .Times(1);
466 apm->ProcessStream(frame.data(), config, config, frame.data());
467}
468
Alessio Bazzicae4498052018-12-17 09:44:06 +0100469TEST(AudioProcessingImplTest,
470 EchoControllerObservesPreAmplifierEchoPathGainChange) {
471 // Tests that the echo controller observes an echo path gain change when the
472 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200473 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100474 const auto* echo_control_factory_ptr = echo_control_factory.get();
475
Niels Möller4f776ac2021-07-02 11:30:54 +0200476 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200477 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100478 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200479 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200480 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100481 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200482 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100483 apm_config.gain_controller2.enabled = false;
484 apm_config.pre_amplifier.enabled = true;
485 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
486 apm->ApplyConfig(apm_config);
487
Alessio Bazzicae4498052018-12-17 09:44:06 +0100488 constexpr int16_t kAudioLevel = 10000;
489 constexpr size_t kSampleRateHz = 48000;
490 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100491 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000492 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100493 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100494
495 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
496
Per Åhgren0aefbf02019-08-23 21:29:17 +0200497 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200498 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100499 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200500 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100501 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100502
Per Åhgren0aefbf02019-08-23 21:29:17 +0200503 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200504 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100505 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200506 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100507 apm->SetRuntimeSetting(
508 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100509 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100510}
511
512TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000513 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
514 // Tests that the echo controller observes an echo path gain change when the
515 // pre-amplifier submodule changes the gain.
516 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
517 const auto* echo_control_factory_ptr = echo_control_factory.get();
518
Niels Möller4f776ac2021-07-02 11:30:54 +0200519 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000520 AudioProcessingBuilderForTesting()
521 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200522 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000523 // Disable AGC.
524 webrtc::AudioProcessing::Config apm_config;
525 apm_config.gain_controller1.enabled = false;
526 apm_config.gain_controller2.enabled = false;
527 apm_config.capture_level_adjustment.enabled = true;
528 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
529 apm->ApplyConfig(apm_config);
530
531 constexpr int16_t kAudioLevel = 10000;
532 constexpr size_t kSampleRateHz = 48000;
533 constexpr size_t kNumChannels = 2;
534 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000535 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000536 frame.fill(kAudioLevel);
537
538 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
539
540 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
541 EXPECT_CALL(*echo_control_mock,
542 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
543 .Times(1);
544 apm->ProcessStream(frame.data(), config, config, frame.data());
545
546 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
547 EXPECT_CALL(*echo_control_mock,
548 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
549 .Times(1);
550 apm->SetRuntimeSetting(
551 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
552 apm->ProcessStream(frame.data(), config, config, frame.data());
553}
554
555TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100556 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
557 // Tests that the echo controller observes an echo path gain change when the
558 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200559 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100560 const auto* echo_control_factory_ptr = echo_control_factory.get();
561
Niels Möller4f776ac2021-07-02 11:30:54 +0200562 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200563 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100564 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200565 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100566 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200567 // Enable AGC1.
568 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200569 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100570 apm_config.gain_controller2.enabled = false;
571 apm_config.pre_amplifier.enabled = false;
572 apm->ApplyConfig(apm_config);
573
Alessio Bazzicae4498052018-12-17 09:44:06 +0100574 constexpr int16_t kAudioLevel = 1000;
575 constexpr size_t kSampleRateHz = 48000;
576 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100577 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000578 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100579 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100580
581 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
582
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200583 constexpr int kInitialStreamAnalogLevel = 123;
584 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
585
586 // When the first fame is processed, no echo path gain change must be
587 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200588 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200589 EXPECT_CALL(*echo_control_mock,
590 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100591 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100592 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100593
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200594 // Simulate the application of the recommended analog level.
595 int recommended_analog_level = apm->recommended_stream_analog_level();
596 if (recommended_analog_level == kInitialStreamAnalogLevel) {
597 // Force an analog gain change if it did not happen.
598 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100599 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200600 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100601
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200602 // After the first fame and with a stream analog level change, the echo path
603 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200604 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200605 EXPECT_CALL(*echo_control_mock,
606 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100607 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100608 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100609}
610
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200611// Tests that a stream is successfully processed when AGC2 adaptive digital is
612// used and when the field trial
613// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200614TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200615 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
616 webrtc::test::ScopedFieldTrials field_trials(
617 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/");
618 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
619 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200620 webrtc::AudioProcessing::Config apm_config;
621 // Disable AGC1 analog.
622 apm_config.gain_controller1.enabled = false;
623 // Enable AGC2 digital.
624 apm_config.gain_controller2.enabled = true;
625 apm_config.gain_controller2.adaptive_digital.enabled = true;
626 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200627 constexpr int kSampleRateHz = 48000;
628 constexpr int kNumChannels = 1;
629 std::array<float, kSampleRateHz / 100> buffer;
630 float* channel_pointers[] = {buffer.data()};
631 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
632 /*num_channels=*/kNumChannels);
633 Random random_generator(2341U);
634 constexpr int kFramesToProcess = 10;
635 for (int i = 0; i < kFramesToProcess; ++i) {
636 RandomizeSampleVector(&random_generator, buffer);
637 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
638 channel_pointers),
639 kNoErr);
640 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200641}
642
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200643// Tests that a stream is successfully processed when AGC2 adaptive digital is
644// used and when the field trial
645// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
646TEST(AudioProcessingImplTest,
647 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200648 webrtc::test::ScopedFieldTrials field_trials(
649 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/");
650 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
651 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
652 webrtc::AudioProcessing::Config apm_config;
653 // Disable AGC1 analog.
654 apm_config.gain_controller1.enabled = false;
655 // Enable AGC2 digital.
656 apm_config.gain_controller2.enabled = true;
657 apm_config.gain_controller2.adaptive_digital.enabled = true;
658 apm->ApplyConfig(apm_config);
659 constexpr int kSampleRateHz = 48000;
660 constexpr int kNumChannels = 1;
661 std::array<float, kSampleRateHz / 100> buffer;
662 float* channel_pointers[] = {buffer.data()};
663 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
664 /*num_channels=*/kNumChannels);
665 Random random_generator(2341U);
666 constexpr int kFramesToProcess = 10;
667 for (int i = 0; i < kFramesToProcess; ++i) {
668 RandomizeSampleVector(&random_generator, buffer);
669 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
670 channel_pointers),
671 kNoErr);
672 }
673}
674
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200675TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
676 // Tests that the echo controller observes an echo path gain change when a
677 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200678 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200679 const auto* echo_control_factory_ptr = echo_control_factory.get();
680
Niels Möller4f776ac2021-07-02 11:30:54 +0200681 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200682 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200683 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200684 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200685 // Disable AGC.
686 webrtc::AudioProcessing::Config apm_config;
687 apm_config.gain_controller1.enabled = false;
688 apm_config.gain_controller2.enabled = false;
689 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200690
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200691 constexpr int16_t kAudioLevel = 10000;
692 constexpr size_t kSampleRateHz = 48000;
693 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100694 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000695 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100696 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200697
698 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
699
Per Åhgren0aefbf02019-08-23 21:29:17 +0200700 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200701 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100702 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200703 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100704 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200705
Per Åhgren0aefbf02019-08-23 21:29:17 +0200706 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200707 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100708 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200709 .Times(1);
710 apm->SetRuntimeSetting(
711 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100712 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200713
Per Åhgren0aefbf02019-08-23 21:29:17 +0200714 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200715 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100716 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200717 .Times(1);
718 apm->SetRuntimeSetting(
719 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100720 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200721
Per Åhgren0aefbf02019-08-23 21:29:17 +0200722 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200723 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100724 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200725 .Times(1);
726 apm->SetRuntimeSetting(
727 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100728 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200729}
730
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200731TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
732 // Make sure that signal changes caused by a render pre-processing sub-module
733 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200734 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200735 std::unique_ptr<CustomProcessing> test_render_pre_processor(
736 new TestRenderPreProcessor());
737 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200738 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200739 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200740 .SetEchoDetector(test_echo_detector)
741 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200742 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200743 webrtc::AudioProcessing::Config apm_config;
744 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200745 apm->ApplyConfig(apm_config);
746
747 constexpr int16_t kAudioLevel = 1000;
748 constexpr int kSampleRateHz = 16000;
749 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100750 // Explicitly initialize APM to ensure no render frames are discarded.
751 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000752 {kSampleRateHz, kNumChannels},
753 {kSampleRateHz, kNumChannels},
754 {kSampleRateHz, kNumChannels},
755 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100756 }};
757 apm->Initialize(processing_config);
758
Per Åhgren2507f8c2020-03-19 12:33:29 +0100759 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000760 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200761
762 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
763 constexpr float kExpectedPreprocessedAudioLevel =
764 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
765 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
766
767 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100768 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200769 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100770 apm->ProcessReverseStream(frame.data(), stream_config,
771 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200772 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
773 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100774 frame.fill(kAudioLevel);
775 ASSERT_EQ(AudioProcessing::Error::kNoError,
776 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100777 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200778 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
779 // triggered, the line below checks that the call has occurred. If not, the
780 // APM implementation may have changed and this test might need to be adapted.
781 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
782 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
783 // produced by the render pre-processor.
784 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
785 test_echo_detector->last_render_audio_first_sample());
786}
787
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200788// Disabling build-optional submodules and trying to enable them via the APM
789// config should be bit-exact with running APM with said submodules disabled.
790// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
791TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200792 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200793 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
794
795 ApmSubmoduleCreationOverrides overrides;
796 overrides.transient_suppression = true;
797 apm->OverrideSubmoduleCreationForTesting(overrides);
798
799 AudioProcessing::Config apm_config = apm->GetConfig();
800 apm_config.transient_suppression.enabled = true;
801 apm->ApplyConfig(apm_config);
802
803 rtc::scoped_refptr<AudioProcessing> apm_reference =
804 AudioProcessingBuilder().Create();
805 apm_config = apm_reference->GetConfig();
806 apm_config.transient_suppression.enabled = false;
807 apm_reference->ApplyConfig(apm_config);
808
809 constexpr int kSampleRateHz = 16000;
810 constexpr int kNumChannels = 1;
811 std::array<float, kSampleRateHz / 100> buffer;
812 std::array<float, kSampleRateHz / 100> buffer_reference;
813 float* channel_pointers[] = {buffer.data()};
814 float* channel_pointers_reference[] = {buffer_reference.data()};
815 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000816 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200817 Random random_generator(2341U);
818 constexpr int kFramesToProcessPerConfiguration = 10;
819
820 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
821 RandomizeSampleVector(&random_generator, buffer);
822 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
823 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
824 channel_pointers),
825 kNoErr);
826 ASSERT_EQ(
827 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
828 stream_config, channel_pointers_reference),
829 kNoErr);
830 for (int j = 0; j < kSampleRateHz / 100; ++j) {
831 EXPECT_EQ(buffer[j], buffer_reference[j]);
832 }
833 }
834}
835
836// Disable transient suppressor creation and run APM in ways that should trigger
837// calls to the transient suppressor API.
838TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200839 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200840 ASSERT_EQ(apm->Initialize(), kNoErr);
841
842 ApmSubmoduleCreationOverrides overrides;
843 overrides.transient_suppression = true;
844 apm->OverrideSubmoduleCreationForTesting(overrides);
845
846 AudioProcessing::Config config = apm->GetConfig();
847 config.transient_suppression.enabled = true;
848 apm->ApplyConfig(config);
849 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
850 float buffer[960];
851 float* channel_pointers[] = {&buffer[0], &buffer[480]};
852 Random random_generator(2341U);
853 constexpr int kFramesToProcessPerConfiguration = 3;
854
855 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000856 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200857 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
858 RandomizeSampleVector(&random_generator, buffer);
859 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
860 initial_stream_config, channel_pointers),
861 kNoErr);
862 }
863
864 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000865 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200866 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
867 RandomizeSampleVector(&random_generator, buffer);
868 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
869 stereo_stream_config, channel_pointers),
870 kNoErr);
871 }
872
873 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000874 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200875 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
876 RandomizeSampleVector(&random_generator, buffer);
877 EXPECT_EQ(
878 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
879 high_sample_rate_stream_config, channel_pointers),
880 kNoErr);
881 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200882}
883
884// Disable transient suppressor creation and run APM in ways that should trigger
885// calls to the transient suppressor API.
886TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200887 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200888 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
889
890 ApmSubmoduleCreationOverrides overrides;
891 overrides.transient_suppression = true;
892 apm->OverrideSubmoduleCreationForTesting(overrides);
893
894 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
895 float buffer[960];
896 float* channel_pointers[] = {&buffer[0], &buffer[480]};
897 Random random_generator(2341U);
898 constexpr int kFramesToProcessPerConfiguration = 3;
899 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000900 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200901
902 AudioProcessing::Config config = apm->GetConfig();
903 config.transient_suppression.enabled = true;
904 apm->ApplyConfig(config);
905 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
906 RandomizeSampleVector(&random_generator, buffer);
907 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
908 channel_pointers),
909 kNoErr);
910 }
911
912 config = apm->GetConfig();
913 config.transient_suppression.enabled = false;
914 apm->ApplyConfig(config);
915 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
916 RandomizeSampleVector(&random_generator, buffer);
917 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
918 channel_pointers),
919 kNoErr);
920 }
921
922 config = apm->GetConfig();
923 config.transient_suppression.enabled = true;
924 apm->ApplyConfig(config);
925 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
926 RandomizeSampleVector(&random_generator, buffer);
927 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
928 channel_pointers),
929 kNoErr);
930 }
931}
Hanna Silenc69188d2022-09-16 11:38:56 +0200932
933// Tests that the minimum startup volume is applied at the startup.
934TEST_P(InputVolumeStartupParameterizedTest,
935 VerifyStartupMinVolumeAppliedAtStartup) {
936 const int applied_startup_input_volume = GetStartupVolume();
Hanna Silenc69188d2022-09-16 11:38:56 +0200937 const int expected_volume =
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200938 std::max(applied_startup_input_volume, GetMinVolume());
939 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200940
941 const int recommended_input_volume =
942 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
943
944 ASSERT_EQ(recommended_input_volume, expected_volume);
945}
946
947// Tests that the minimum input volume is applied if the volume is manually
948// adjusted to a non-zero value only if
949// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled.
950TEST_P(InputVolumeNotZeroParameterizedTest,
951 VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200952 const int applied_startup_input_volume = GetStartupVolume();
953 const int applied_input_volume = GetVolume();
954 const int expected_volume = std::max(applied_input_volume, GetMinVolume());
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200955 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200956
957 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
958 const int recommended_input_volume =
959 ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
960
961 ASSERT_NE(applied_input_volume, 0);
962 if (GetMinMicLevelExperimentEnabled()) {
963 ASSERT_EQ(recommended_input_volume, expected_volume);
964 } else {
965 ASSERT_EQ(recommended_input_volume, applied_input_volume);
966 }
967}
968
969// Tests that the minimum input volume is not applied if the volume is manually
970// adjusted to zero.
971TEST_P(InputVolumeZeroParameterizedTest,
972 VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200973 constexpr int kZeroVolume = 0;
974 const int applied_startup_input_volume = GetStartupVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200975 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200976
977 const int recommended_input_volume_after_startup =
978 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
979 const int recommended_input_volume =
980 ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
981
982 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
983 ASSERT_EQ(recommended_input_volume, kZeroVolume);
984}
985
986// Tests that the minimum input volume is applied if the volume is not zero
987// before it is automatically adjusted.
988TEST_P(InputVolumeNotZeroParameterizedTest,
989 VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200990 const int applied_startup_input_volume = GetStartupVolume();
991 const int applied_input_volume = GetVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200992 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200993
994 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
995 const int recommended_input_volume =
996 ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
997
998 ASSERT_NE(applied_input_volume, 0);
999 if (recommended_input_volume != applied_input_volume) {
1000 ASSERT_GE(recommended_input_volume, GetMinVolume());
1001 }
1002}
1003
1004// Tests that the minimum input volume is not applied if the volume is zero
1005// before it is automatically adjusted.
1006TEST_P(InputVolumeZeroParameterizedTest,
1007 VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001008 constexpr int kZeroVolume = 0;
1009 const int applied_startup_input_volume = GetStartupVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001010 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +02001011
1012 const int recommended_input_volume_after_startup =
1013 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1014 const int recommended_input_volume =
1015 ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
1016
1017 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
1018 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1019}
1020
1021INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1022 InputVolumeStartupParameterizedTest,
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001023 ::testing::Combine(::testing::Values(0, 5, 30),
Hanna Silenc69188d2022-09-16 11:38:56 +02001024 ::testing::Values(absl::nullopt,
1025 20)));
1026
1027INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1028 InputVolumeNotZeroParameterizedTest,
1029 ::testing::Combine(::testing::Values(0, 5, 15),
1030 ::testing::Values(1, 5, 30),
1031 ::testing::Values(absl::nullopt,
1032 20)));
1033
1034INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1035 InputVolumeZeroParameterizedTest,
1036 ::testing::Combine(::testing::Values(0, 5, 15),
1037 ::testing::Values(absl::nullopt,
1038 20)));
1039
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001040} // namespace webrtc