blob: 21365e075e31c67ddd8439db986ade7084c678e7 [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.
Henrik Lundin64253a92022-02-04 09:02:48 +0000274 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200275 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100276 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100277 EXPECT_NOERR(
278 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000279
aluebsb0319552016-03-17 20:39:53 -0700280 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000281 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200282 EXPECT_CALL(mock, InitializeLocked).Times(1);
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}
286
Alessio Bazzicac054e782018-04-16 12:10:09 +0200287TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200288 rtc::scoped_refptr<AudioProcessing> apm =
289 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200290 webrtc::AudioProcessing::Config apm_config;
291 apm_config.pre_amplifier.enabled = true;
292 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
293 apm->ApplyConfig(apm_config);
294
Per Åhgren2507f8c2020-03-19 12:33:29 +0100295 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200296 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200297 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200298
Per Åhgren2507f8c2020-03-19 12:33:29 +0100299 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000300 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100301 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100302 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100303 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200304 << "With factor 1, frame shouldn't be modified.";
305
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200306 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200307 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200308 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200309
310 // Process for two frames to have time to ramp up gain.
311 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100312 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100313 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200314 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100315 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200316 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200317}
318
Per Åhgrendb5d7282021-03-15 16:31:04 +0000319TEST(AudioProcessingImplTest,
320 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200321 rtc::scoped_refptr<AudioProcessing> apm =
322 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000323 webrtc::AudioProcessing::Config apm_config;
324 apm_config.capture_level_adjustment.enabled = true;
325 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
326 apm->ApplyConfig(apm_config);
327
328 constexpr int kSampleRateHz = 48000;
329 constexpr int16_t kAudioLevel = 10000;
330 constexpr size_t kNumChannels = 2;
331
332 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000333 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000334 frame.fill(kAudioLevel);
335 apm->ProcessStream(frame.data(), config, config, frame.data());
336 EXPECT_EQ(frame[100], kAudioLevel)
337 << "With factor 1, frame shouldn't be modified.";
338
339 constexpr float kGainFactor = 2.f;
340 apm->SetRuntimeSetting(
341 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
342
343 // Process for two frames to have time to ramp up gain.
344 for (int i = 0; i < 2; ++i) {
345 frame.fill(kAudioLevel);
346 apm->ProcessStream(frame.data(), config, config, frame.data());
347 }
348 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
349 << "Frame should be amplified.";
350}
351
352TEST(AudioProcessingImplTest,
353 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200354 rtc::scoped_refptr<AudioProcessing> apm =
355 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000356 webrtc::AudioProcessing::Config apm_config;
357 apm_config.capture_level_adjustment.enabled = true;
358 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
359 apm->ApplyConfig(apm_config);
360
361 constexpr int kSampleRateHz = 48000;
362 constexpr int16_t kAudioLevel = 10000;
363 constexpr size_t kNumChannels = 2;
364
365 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000366 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000367 frame.fill(kAudioLevel);
368 apm->ProcessStream(frame.data(), config, config, frame.data());
369 EXPECT_EQ(frame[100], kAudioLevel)
370 << "With factor 1, frame shouldn't be modified.";
371
372 constexpr float kGainFactor = 2.f;
373 apm->SetRuntimeSetting(
374 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
375
376 // Process for two frames to have time to ramp up gain.
377 for (int i = 0; i < 2; ++i) {
378 frame.fill(kAudioLevel);
379 apm->ProcessStream(frame.data(), config, config, frame.data());
380 }
381 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
382 << "Frame should be amplified.";
383}
384
Per Åhgren652ada52021-03-03 10:52:44 +0000385TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
386 // Tests that the echo controller observes that the capture usage has been
387 // updated.
388 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
389 const MockEchoControlFactory* echo_control_factory_ptr =
390 echo_control_factory.get();
391
Niels Möller4f776ac2021-07-02 11:30:54 +0200392 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000393 AudioProcessingBuilderForTesting()
394 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200395 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000396
397 constexpr int16_t kAudioLevel = 10000;
398 constexpr int kSampleRateHz = 48000;
399 constexpr int kNumChannels = 2;
400 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000401 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000402 frame.fill(kAudioLevel);
403
404 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
405
406 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
407 // are passed.
408 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
409 apm->ProcessStream(frame.data(), config, config, frame.data());
410
411 // Ensure that SetCaptureOutputUsage is called with the right information when
412 // a runtime setting is passed.
413 EXPECT_CALL(*echo_control_mock,
414 SetCaptureOutputUsage(/*capture_output_used=*/false))
415 .Times(1);
416 EXPECT_TRUE(apm->PostRuntimeSetting(
417 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
418 /*capture_output_used=*/false)));
419 apm->ProcessStream(frame.data(), config, config, frame.data());
420
421 EXPECT_CALL(*echo_control_mock,
422 SetCaptureOutputUsage(/*capture_output_used=*/true))
423 .Times(1);
424 EXPECT_TRUE(apm->PostRuntimeSetting(
425 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
426 /*capture_output_used=*/true)));
427 apm->ProcessStream(frame.data(), config, config, frame.data());
428
429 // The number of positions to place items in the queue is equal to the queue
430 // size minus 1.
431 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
432
433 // Ensure that SetCaptureOutputUsage is called with the right information when
434 // many runtime settings are passed.
435 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
436 EXPECT_TRUE(apm->PostRuntimeSetting(
437 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
438 /*capture_output_used=*/false)));
439 }
440 EXPECT_CALL(*echo_control_mock,
441 SetCaptureOutputUsage(/*capture_output_used=*/false))
442 .Times(kNumSlotsInQueue - 1);
443 apm->ProcessStream(frame.data(), config, config, frame.data());
444
445 // Ensure that SetCaptureOutputUsage is properly called with the fallback
446 // value when the runtime settings queue becomes full.
447 for (int k = 0; k < kNumSlotsInQueue; ++k) {
448 EXPECT_TRUE(apm->PostRuntimeSetting(
449 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
450 /*capture_output_used=*/false)));
451 }
452 EXPECT_FALSE(apm->PostRuntimeSetting(
453 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
454 /*capture_output_used=*/false)));
455 EXPECT_FALSE(apm->PostRuntimeSetting(
456 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
457 /*capture_output_used=*/false)));
458 EXPECT_CALL(*echo_control_mock,
459 SetCaptureOutputUsage(/*capture_output_used=*/false))
460 .Times(kNumSlotsInQueue);
461 EXPECT_CALL(*echo_control_mock,
462 SetCaptureOutputUsage(/*capture_output_used=*/true))
463 .Times(1);
464 apm->ProcessStream(frame.data(), config, config, frame.data());
465}
466
Alessio Bazzicae4498052018-12-17 09:44:06 +0100467TEST(AudioProcessingImplTest,
468 EchoControllerObservesPreAmplifierEchoPathGainChange) {
469 // Tests that the echo controller observes an echo path gain change when the
470 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200471 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100472 const auto* echo_control_factory_ptr = echo_control_factory.get();
473
Niels Möller4f776ac2021-07-02 11:30:54 +0200474 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200475 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100476 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200477 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200478 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100479 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200480 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100481 apm_config.gain_controller2.enabled = false;
482 apm_config.pre_amplifier.enabled = true;
483 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
484 apm->ApplyConfig(apm_config);
485
Alessio Bazzicae4498052018-12-17 09:44:06 +0100486 constexpr int16_t kAudioLevel = 10000;
487 constexpr size_t kSampleRateHz = 48000;
488 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100489 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000490 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100491 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100492
493 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
494
Per Åhgren0aefbf02019-08-23 21:29:17 +0200495 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200496 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100497 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200498 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100499 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100500
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=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200504 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100505 apm->SetRuntimeSetting(
506 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100507 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100508}
509
510TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000511 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
512 // Tests that the echo controller observes an echo path gain change when the
513 // pre-amplifier submodule changes the gain.
514 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
515 const auto* echo_control_factory_ptr = echo_control_factory.get();
516
Niels Möller4f776ac2021-07-02 11:30:54 +0200517 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000518 AudioProcessingBuilderForTesting()
519 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200520 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000521 // Disable AGC.
522 webrtc::AudioProcessing::Config apm_config;
523 apm_config.gain_controller1.enabled = false;
524 apm_config.gain_controller2.enabled = false;
525 apm_config.capture_level_adjustment.enabled = true;
526 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
527 apm->ApplyConfig(apm_config);
528
529 constexpr int16_t kAudioLevel = 10000;
530 constexpr size_t kSampleRateHz = 48000;
531 constexpr size_t kNumChannels = 2;
532 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000533 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000534 frame.fill(kAudioLevel);
535
536 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
537
538 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
539 EXPECT_CALL(*echo_control_mock,
540 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
541 .Times(1);
542 apm->ProcessStream(frame.data(), config, config, frame.data());
543
544 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
545 EXPECT_CALL(*echo_control_mock,
546 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
547 .Times(1);
548 apm->SetRuntimeSetting(
549 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
550 apm->ProcessStream(frame.data(), config, config, frame.data());
551}
552
553TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100554 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
555 // Tests that the echo controller observes an echo path gain change when the
556 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200557 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100558 const auto* echo_control_factory_ptr = echo_control_factory.get();
559
Niels Möller4f776ac2021-07-02 11:30:54 +0200560 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200561 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100562 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200563 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100564 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200565 // Enable AGC1.
566 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200567 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100568 apm_config.gain_controller2.enabled = false;
569 apm_config.pre_amplifier.enabled = false;
570 apm->ApplyConfig(apm_config);
571
Alessio Bazzicae4498052018-12-17 09:44:06 +0100572 constexpr int16_t kAudioLevel = 1000;
573 constexpr size_t kSampleRateHz = 48000;
574 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100575 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000576 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100577 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100578
579 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
580
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200581 constexpr int kInitialStreamAnalogLevel = 123;
582 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
583
584 // When the first fame is processed, no echo path gain change must be
585 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200586 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200587 EXPECT_CALL(*echo_control_mock,
588 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100589 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100590 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100591
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200592 // Simulate the application of the recommended analog level.
593 int recommended_analog_level = apm->recommended_stream_analog_level();
594 if (recommended_analog_level == kInitialStreamAnalogLevel) {
595 // Force an analog gain change if it did not happen.
596 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100597 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200598 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100599
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200600 // After the first fame and with a stream analog level change, the echo path
601 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200602 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200603 EXPECT_CALL(*echo_control_mock,
604 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100605 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100606 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100607}
608
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200609// Tests that a stream is successfully processed when AGC2 adaptive digital is
610// used and when the field trial
611// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200612TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200613 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
614 webrtc::test::ScopedFieldTrials field_trials(
615 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/");
616 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
617 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200618 webrtc::AudioProcessing::Config apm_config;
619 // Disable AGC1 analog.
620 apm_config.gain_controller1.enabled = false;
621 // Enable AGC2 digital.
622 apm_config.gain_controller2.enabled = true;
623 apm_config.gain_controller2.adaptive_digital.enabled = true;
624 apm->ApplyConfig(apm_config);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200625 constexpr int kSampleRateHz = 48000;
626 constexpr int kNumChannels = 1;
627 std::array<float, kSampleRateHz / 100> buffer;
628 float* channel_pointers[] = {buffer.data()};
629 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
630 /*num_channels=*/kNumChannels);
631 Random random_generator(2341U);
632 constexpr int kFramesToProcess = 10;
633 for (int i = 0; i < kFramesToProcess; ++i) {
634 RandomizeSampleVector(&random_generator, buffer);
635 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
636 channel_pointers),
637 kNoErr);
638 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200639}
640
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200641// Tests that a stream is successfully processed when AGC2 adaptive digital is
642// used and when the field trial
643// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
644TEST(AudioProcessingImplTest,
645 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200646 webrtc::test::ScopedFieldTrials field_trials(
647 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/");
648 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
649 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
650 webrtc::AudioProcessing::Config apm_config;
651 // Disable AGC1 analog.
652 apm_config.gain_controller1.enabled = false;
653 // Enable AGC2 digital.
654 apm_config.gain_controller2.enabled = true;
655 apm_config.gain_controller2.adaptive_digital.enabled = true;
656 apm->ApplyConfig(apm_config);
657 constexpr int kSampleRateHz = 48000;
658 constexpr int kNumChannels = 1;
659 std::array<float, kSampleRateHz / 100> buffer;
660 float* channel_pointers[] = {buffer.data()};
661 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
662 /*num_channels=*/kNumChannels);
663 Random random_generator(2341U);
664 constexpr int kFramesToProcess = 10;
665 for (int i = 0; i < kFramesToProcess; ++i) {
666 RandomizeSampleVector(&random_generator, buffer);
667 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
668 channel_pointers),
669 kNoErr);
670 }
671}
672
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200673TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
674 // Tests that the echo controller observes an echo path gain change when a
675 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200676 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200677 const auto* echo_control_factory_ptr = echo_control_factory.get();
678
Niels Möller4f776ac2021-07-02 11:30:54 +0200679 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200680 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200681 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200682 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200683 // Disable AGC.
684 webrtc::AudioProcessing::Config apm_config;
685 apm_config.gain_controller1.enabled = false;
686 apm_config.gain_controller2.enabled = false;
687 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200688
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200689 constexpr int16_t kAudioLevel = 10000;
690 constexpr size_t kSampleRateHz = 48000;
691 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100692 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000693 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100694 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200695
696 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
697
Per Åhgren0aefbf02019-08-23 21:29:17 +0200698 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200699 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100700 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200701 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100702 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200703
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);
708 apm->SetRuntimeSetting(
709 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100710 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200711
Per Åhgren0aefbf02019-08-23 21:29:17 +0200712 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200713 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100714 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200715 .Times(1);
716 apm->SetRuntimeSetting(
717 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100718 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200719
Per Åhgren0aefbf02019-08-23 21:29:17 +0200720 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200721 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100722 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200723 .Times(1);
724 apm->SetRuntimeSetting(
725 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100726 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200727}
728
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200729TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
730 // Make sure that signal changes caused by a render pre-processing sub-module
731 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200732 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200733 std::unique_ptr<CustomProcessing> test_render_pre_processor(
734 new TestRenderPreProcessor());
735 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200736 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200737 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200738 .SetEchoDetector(test_echo_detector)
739 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200740 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200741 webrtc::AudioProcessing::Config apm_config;
742 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200743 apm->ApplyConfig(apm_config);
744
745 constexpr int16_t kAudioLevel = 1000;
746 constexpr int kSampleRateHz = 16000;
747 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100748 // Explicitly initialize APM to ensure no render frames are discarded.
749 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000750 {kSampleRateHz, kNumChannels},
751 {kSampleRateHz, kNumChannels},
752 {kSampleRateHz, kNumChannels},
753 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100754 }};
755 apm->Initialize(processing_config);
756
Per Åhgren2507f8c2020-03-19 12:33:29 +0100757 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000758 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200759
760 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
761 constexpr float kExpectedPreprocessedAudioLevel =
762 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
763 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
764
765 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100766 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200767 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100768 apm->ProcessReverseStream(frame.data(), stream_config,
769 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200770 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
771 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100772 frame.fill(kAudioLevel);
773 ASSERT_EQ(AudioProcessing::Error::kNoError,
774 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100775 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200776 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
777 // triggered, the line below checks that the call has occurred. If not, the
778 // APM implementation may have changed and this test might need to be adapted.
779 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
780 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
781 // produced by the render pre-processor.
782 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
783 test_echo_detector->last_render_audio_first_sample());
784}
785
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200786// Disabling build-optional submodules and trying to enable them via the APM
787// config should be bit-exact with running APM with said submodules disabled.
788// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
789TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200790 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200791 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
792
793 ApmSubmoduleCreationOverrides overrides;
794 overrides.transient_suppression = true;
795 apm->OverrideSubmoduleCreationForTesting(overrides);
796
797 AudioProcessing::Config apm_config = apm->GetConfig();
798 apm_config.transient_suppression.enabled = true;
799 apm->ApplyConfig(apm_config);
800
801 rtc::scoped_refptr<AudioProcessing> apm_reference =
802 AudioProcessingBuilder().Create();
803 apm_config = apm_reference->GetConfig();
804 apm_config.transient_suppression.enabled = false;
805 apm_reference->ApplyConfig(apm_config);
806
807 constexpr int kSampleRateHz = 16000;
808 constexpr int kNumChannels = 1;
809 std::array<float, kSampleRateHz / 100> buffer;
810 std::array<float, kSampleRateHz / 100> buffer_reference;
811 float* channel_pointers[] = {buffer.data()};
812 float* channel_pointers_reference[] = {buffer_reference.data()};
813 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000814 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200815 Random random_generator(2341U);
816 constexpr int kFramesToProcessPerConfiguration = 10;
817
818 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
819 RandomizeSampleVector(&random_generator, buffer);
820 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
821 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
822 channel_pointers),
823 kNoErr);
824 ASSERT_EQ(
825 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
826 stream_config, channel_pointers_reference),
827 kNoErr);
828 for (int j = 0; j < kSampleRateHz / 100; ++j) {
829 EXPECT_EQ(buffer[j], buffer_reference[j]);
830 }
831 }
832}
833
834// Disable transient suppressor creation and run APM in ways that should trigger
835// calls to the transient suppressor API.
836TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200837 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200838 ASSERT_EQ(apm->Initialize(), kNoErr);
839
840 ApmSubmoduleCreationOverrides overrides;
841 overrides.transient_suppression = true;
842 apm->OverrideSubmoduleCreationForTesting(overrides);
843
844 AudioProcessing::Config config = apm->GetConfig();
845 config.transient_suppression.enabled = true;
846 apm->ApplyConfig(config);
847 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
848 float buffer[960];
849 float* channel_pointers[] = {&buffer[0], &buffer[480]};
850 Random random_generator(2341U);
851 constexpr int kFramesToProcessPerConfiguration = 3;
852
853 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000854 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200855 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
856 RandomizeSampleVector(&random_generator, buffer);
857 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
858 initial_stream_config, channel_pointers),
859 kNoErr);
860 }
861
862 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000863 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200864 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
865 RandomizeSampleVector(&random_generator, buffer);
866 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
867 stereo_stream_config, channel_pointers),
868 kNoErr);
869 }
870
871 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000872 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200873 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
874 RandomizeSampleVector(&random_generator, buffer);
875 EXPECT_EQ(
876 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
877 high_sample_rate_stream_config, channel_pointers),
878 kNoErr);
879 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200880}
881
882// Disable transient suppressor creation and run APM in ways that should trigger
883// calls to the transient suppressor API.
884TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200885 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200886 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
887
888 ApmSubmoduleCreationOverrides overrides;
889 overrides.transient_suppression = true;
890 apm->OverrideSubmoduleCreationForTesting(overrides);
891
892 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
893 float buffer[960];
894 float* channel_pointers[] = {&buffer[0], &buffer[480]};
895 Random random_generator(2341U);
896 constexpr int kFramesToProcessPerConfiguration = 3;
897 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000898 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200899
900 AudioProcessing::Config config = apm->GetConfig();
901 config.transient_suppression.enabled = true;
902 apm->ApplyConfig(config);
903 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
904 RandomizeSampleVector(&random_generator, buffer);
905 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
906 channel_pointers),
907 kNoErr);
908 }
909
910 config = apm->GetConfig();
911 config.transient_suppression.enabled = false;
912 apm->ApplyConfig(config);
913 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
914 RandomizeSampleVector(&random_generator, buffer);
915 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
916 channel_pointers),
917 kNoErr);
918 }
919
920 config = apm->GetConfig();
921 config.transient_suppression.enabled = true;
922 apm->ApplyConfig(config);
923 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
924 RandomizeSampleVector(&random_generator, buffer);
925 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
926 channel_pointers),
927 kNoErr);
928 }
929}
Hanna Silenc69188d2022-09-16 11:38:56 +0200930
931// Tests that the minimum startup volume is applied at the startup.
932TEST_P(InputVolumeStartupParameterizedTest,
933 VerifyStartupMinVolumeAppliedAtStartup) {
934 const int applied_startup_input_volume = GetStartupVolume();
Hanna Silenc69188d2022-09-16 11:38:56 +0200935 const int expected_volume =
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200936 std::max(applied_startup_input_volume, GetMinVolume());
937 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200938
939 const int recommended_input_volume =
940 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
941
942 ASSERT_EQ(recommended_input_volume, expected_volume);
943}
944
945// Tests that the minimum input volume is applied if the volume is manually
946// adjusted to a non-zero value only if
947// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled.
948TEST_P(InputVolumeNotZeroParameterizedTest,
949 VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200950 const int applied_startup_input_volume = GetStartupVolume();
951 const int applied_input_volume = GetVolume();
952 const int expected_volume = std::max(applied_input_volume, GetMinVolume());
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200953 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200954
955 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
956 const int recommended_input_volume =
957 ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
958
959 ASSERT_NE(applied_input_volume, 0);
960 if (GetMinMicLevelExperimentEnabled()) {
961 ASSERT_EQ(recommended_input_volume, expected_volume);
962 } else {
963 ASSERT_EQ(recommended_input_volume, applied_input_volume);
964 }
965}
966
967// Tests that the minimum input volume is not applied if the volume is manually
968// adjusted to zero.
969TEST_P(InputVolumeZeroParameterizedTest,
970 VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200971 constexpr int kZeroVolume = 0;
972 const int applied_startup_input_volume = GetStartupVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200973 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200974
975 const int recommended_input_volume_after_startup =
976 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
977 const int recommended_input_volume =
978 ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
979
980 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
981 ASSERT_EQ(recommended_input_volume, kZeroVolume);
982}
983
984// Tests that the minimum input volume is applied if the volume is not zero
985// before it is automatically adjusted.
986TEST_P(InputVolumeNotZeroParameterizedTest,
987 VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200988 const int applied_startup_input_volume = GetStartupVolume();
989 const int applied_input_volume = GetVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200990 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +0200991
992 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
993 const int recommended_input_volume =
994 ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
995
996 ASSERT_NE(applied_input_volume, 0);
997 if (recommended_input_volume != applied_input_volume) {
998 ASSERT_GE(recommended_input_volume, GetMinVolume());
999 }
1000}
1001
1002// Tests that the minimum input volume is not applied if the volume is zero
1003// before it is automatically adjusted.
1004TEST_P(InputVolumeZeroParameterizedTest,
1005 VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001006 constexpr int kZeroVolume = 0;
1007 const int applied_startup_input_volume = GetStartupVolume();
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001008 auto apm = CreateApmForInputVolumeTest();
Hanna Silenc69188d2022-09-16 11:38:56 +02001009
1010 const int recommended_input_volume_after_startup =
1011 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1012 const int recommended_input_volume =
1013 ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
1014
1015 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
1016 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1017}
1018
1019INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1020 InputVolumeStartupParameterizedTest,
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001021 ::testing::Combine(::testing::Values(0, 5, 30),
Hanna Silenc69188d2022-09-16 11:38:56 +02001022 ::testing::Values(absl::nullopt,
1023 20)));
1024
1025INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1026 InputVolumeNotZeroParameterizedTest,
1027 ::testing::Combine(::testing::Values(0, 5, 15),
1028 ::testing::Values(1, 5, 30),
1029 ::testing::Values(absl::nullopt,
1030 20)));
1031
1032INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1033 InputVolumeZeroParameterizedTest,
1034 ::testing::Combine(::testing::Values(0, 5, 15),
1035 ::testing::Values(absl::nullopt,
1036 20)));
1037
Alessio Bazzica79beaa72022-10-31 16:42:34 +01001038// When the input volume is not emulated and no input volume controller is
1039// active, the recommended volume must always be the applied volume.
1040TEST(AudioProcessingImplTest,
1041 RecommendAppliedInputVolumeWithNoAgcWithNoEmulation) {
1042 auto apm = AudioProcessingBuilder()
1043 .SetConfig({.capture_level_adjustment = {.enabled = false},
1044 .gain_controller1 = {.enabled = false}})
1045 .Create();
1046
1047 constexpr int kOneFrame = 1;
1048 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1049 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1050 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1051}
1052
1053// When the input volume is emulated, the recommended volume must always be the
1054// applied volume and at any time it must not be that set in the input volume
1055// emulator.
1056// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1057TEST(AudioProcessingImplTest,
1058 DISABLED_RecommendAppliedInputVolumeWithNoAgcWithEmulation) {
1059 auto apm =
1060 AudioProcessingBuilder()
1061 .SetConfig({.capture_level_adjustment = {.enabled = true,
1062 .analog_mic_gain_emulation{
1063 .enabled = true,
1064 .initial_level = 255}},
1065 .gain_controller1 = {.enabled = false}})
1066 .Create();
1067
1068 constexpr int kOneFrame = 1;
1069 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1070 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1071 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1072}
1073
1074// Even if there is an enabled input volume controller, when the input volume is
1075// emulated, the recommended volume is always the applied volume because the
1076// active controller must only adjust the internally emulated volume and leave
1077// the externally applied volume unchanged.
1078// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1079TEST(AudioProcessingImplTest,
1080 DISABLED_RecommendAppliedInputVolumeWithAgcWithEmulation) {
1081 auto apm =
1082 AudioProcessingBuilder()
1083 .SetConfig({.capture_level_adjustment = {.enabled = true,
1084 .analog_mic_gain_emulation{
1085 .enabled = true}},
1086 .gain_controller1 = {.enabled = true,
1087 .analog_gain_controller{
1088 .enabled = true,
1089 }}})
1090 .Create();
1091
1092 constexpr int kOneFrame = 1;
1093 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1094 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1095 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1096}
1097
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001098} // namespace webrtc