blob: 346b5f5e14194809a8fd8a87db632c89ed7a1841 [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
Hanna Silend4dbe452022-11-30 15:16:21 +0100135// with AGC1 analog and/or AGC2 input volume controller enabled and AGC2
136// digital controller enabled.
137rtc::scoped_refptr<AudioProcessing> CreateApmForInputVolumeTest(
138 bool agc1_analog_gain_controller_enabled,
139 bool agc2_input_volume_controller_enabled) {
Hanna Silenc69188d2022-09-16 11:38:56 +0200140 webrtc::AudioProcessing::Config config;
Hanna Silend4dbe452022-11-30 15:16:21 +0100141 // Enable AGC1 analog controller.
142 config.gain_controller1.enabled = agc1_analog_gain_controller_enabled;
143 config.gain_controller1.analog_gain_controller.enabled =
144 agc1_analog_gain_controller_enabled;
145 // Enable AG2 input volume controller
146 config.gain_controller2.input_volume_controller.enabled =
147 agc2_input_volume_controller_enabled;
148 // Enable AGC2 adaptive digital controller.
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200149 config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
150 false;
Hanna Silenc69188d2022-09-16 11:38:56 +0200151 config.gain_controller2.enabled = true;
152 config.gain_controller2.adaptive_digital.enabled = true;
153
154 auto apm(AudioProcessingBuilder().Create());
155 apm->ApplyConfig(config);
Hanna Silend4dbe452022-11-30 15:16:21 +0100156
Hanna Silenc69188d2022-09-16 11:38:56 +0200157 return apm;
158}
159
160// Runs `apm` input processing for volume adjustments for `num_frames` random
161// frames starting from the volume `initial_volume`. This includes three steps:
162// 1) Set the input volume 2) Process the stream 3) Set the new recommended
163// input volume. Returns the new recommended input volume.
164int ProcessInputVolume(AudioProcessing& apm,
165 int num_frames,
166 int initial_volume) {
167 constexpr int kSampleRateHz = 48000;
168 constexpr int kNumChannels = 1;
169 std::array<float, kSampleRateHz / 100> buffer;
170 float* channel_pointers[] = {buffer.data()};
171 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
172 /*num_channels=*/kNumChannels);
173 int recommended_input_volume = initial_volume;
174 for (int i = 0; i < num_frames; ++i) {
175 Random random_generator(2341U);
176 RandomizeSampleVector(&random_generator, buffer);
177
178 apm.set_stream_analog_level(recommended_input_volume);
179 apm.ProcessStream(channel_pointers, stream_config, stream_config,
180 channel_pointers);
181 recommended_input_volume = apm.recommended_stream_analog_level();
182 }
183 return recommended_input_volume;
184}
185
186constexpr char kMinMicLevelFieldTrial[] =
187 "WebRTC-Audio-2ndAgcMinMicLevelExperiment";
Hanna Silend4dbe452022-11-30 15:16:21 +0100188constexpr char kMinInputVolumeFieldTrial[] = "WebRTC-Audio-Agc2-MinInputVolume";
Hanna Silenc69188d2022-09-16 11:38:56 +0200189constexpr int kMinInputVolume = 12;
190
191std::string GetMinMicLevelExperimentFieldTrial(absl::optional<int> value) {
Hanna Silend4dbe452022-11-30 15:16:21 +0100192 char field_trial_buffer[128];
Hanna Silenc69188d2022-09-16 11:38:56 +0200193 rtc::SimpleStringBuilder builder(field_trial_buffer);
194 if (value.has_value()) {
195 RTC_DCHECK_GE(*value, 0);
196 RTC_DCHECK_LE(*value, 255);
197 builder << kMinMicLevelFieldTrial << "/Enabled-" << *value << "/";
Hanna Silend4dbe452022-11-30 15:16:21 +0100198 builder << kMinInputVolumeFieldTrial << "/Enabled-" << *value << "/";
Hanna Silenc69188d2022-09-16 11:38:56 +0200199 } else {
200 builder << kMinMicLevelFieldTrial << "/Disabled/";
Hanna Silend4dbe452022-11-30 15:16:21 +0100201 builder << kMinInputVolumeFieldTrial << "/Disabled/";
Hanna Silenc69188d2022-09-16 11:38:56 +0200202 }
203 return builder.str();
204}
205
206// TODO(webrtc:7494): Remove the fieldtrial from the input volume tests when
Hanna Silend4dbe452022-11-30 15:16:21 +0100207// "WebRTC-Audio-2ndAgcMinMicLevelExperiment" and
208// "WebRTC-Audio-Agc2-MinInputVolume" are removed.
Hanna Silenc69188d2022-09-16 11:38:56 +0200209class InputVolumeStartupParameterizedTest
Hanna Silend4dbe452022-11-30 15:16:21 +0100210 : public ::testing::TestWithParam<
211 std::tuple<int, absl::optional<int>, bool, bool>> {
Hanna Silenc69188d2022-09-16 11:38:56 +0200212 protected:
213 InputVolumeStartupParameterizedTest()
214 : field_trials_(
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200215 GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
216 int GetStartupVolume() const { return std::get<0>(GetParam()); }
Hanna Silenc69188d2022-09-16 11:38:56 +0200217 int GetMinVolume() const {
Alessio Bazzica9ea53812022-10-13 17:09:15 +0200218 return std::get<1>(GetParam()).value_or(kMinInputVolume);
Hanna Silenc69188d2022-09-16 11:38:56 +0200219 }
Hanna Silend4dbe452022-11-30 15:16:21 +0100220 bool GetAgc1AnalogControllerEnabled() const {
221 return std::get<2>(GetParam());
222 }
223 bool GetAgc2InputVolumeControllerEnabled() const {
224 return std::get<3>(GetParam());
225 }
Hanna Silenc69188d2022-09-16 11:38:56 +0200226
227 private:
228 test::ScopedFieldTrials field_trials_;
229};
230
231class InputVolumeNotZeroParameterizedTest
232 : public ::testing::TestWithParam<
Hanna Silend4dbe452022-11-30 15:16:21 +0100233 std::tuple<int, int, absl::optional<int>, bool, bool>> {
Hanna Silenc69188d2022-09-16 11:38:56 +0200234 protected:
235 InputVolumeNotZeroParameterizedTest()
236 : field_trials_(
237 GetMinMicLevelExperimentFieldTrial(std::get<2>(GetParam()))) {}
238 int GetStartupVolume() const { return std::get<0>(GetParam()); }
239 int GetVolume() const { return std::get<1>(GetParam()); }
240 int GetMinVolume() const {
241 return std::get<2>(GetParam()).value_or(kMinInputVolume);
242 }
243 bool GetMinMicLevelExperimentEnabled() {
244 return std::get<2>(GetParam()).has_value();
245 }
Hanna Silend4dbe452022-11-30 15:16:21 +0100246 bool GetAgc1AnalogControllerEnabled() const {
247 return std::get<3>(GetParam());
248 }
249 bool GetAgc2InputVolumeControllerEnabled() const {
250 return std::get<4>(GetParam());
251 }
Hanna Silenc69188d2022-09-16 11:38:56 +0200252
253 private:
254 test::ScopedFieldTrials field_trials_;
255};
256
257class InputVolumeZeroParameterizedTest
Hanna Silend4dbe452022-11-30 15:16:21 +0100258 : public ::testing::TestWithParam<
259 std::tuple<int, absl::optional<int>, bool, bool>> {
Hanna Silenc69188d2022-09-16 11:38:56 +0200260 protected:
261 InputVolumeZeroParameterizedTest()
262 : field_trials_(
263 GetMinMicLevelExperimentFieldTrial(std::get<1>(GetParam()))) {}
264 int GetStartupVolume() const { return std::get<0>(GetParam()); }
265 int GetMinVolume() const {
266 return std::get<1>(GetParam()).value_or(kMinInputVolume);
267 }
Hanna Silend4dbe452022-11-30 15:16:21 +0100268 bool GetAgc1AnalogControllerEnabled() const {
269 return std::get<2>(GetParam());
270 }
271 bool GetAgc2InputVolumeControllerEnabled() const {
272 return std::get<3>(GetParam());
273 }
Hanna Silenc69188d2022-09-16 11:38:56 +0200274
275 private:
276 test::ScopedFieldTrials field_trials_;
277};
278
peaha9cc40b2017-06-29 08:32:09 -0700279} // namespace
280
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000281TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200282 MockInitialize mock;
283 ON_CALL(mock, InitializeLocked)
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000284 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
285
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200286 EXPECT_CALL(mock, InitializeLocked).Times(1);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000287 mock.Initialize();
288
Per Åhgren2507f8c2020-03-19 12:33:29 +0100289 constexpr size_t kMaxSampleRateHz = 32000;
290 constexpr size_t kMaxNumChannels = 2;
291 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
292 frame.fill(0);
Henrik Lundin64253a92022-02-04 09:02:48 +0000293 StreamConfig config(16000, 1);
peah2ace3f92016-09-10 04:42:27 -0700294 // Call with the default parameters; there should be an init.
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200295 EXPECT_CALL(mock, InitializeLocked).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100296 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100297 EXPECT_NOERR(
298 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000299
300 // New sample rate. (Only impacts ProcessStream).
Henrik Lundin64253a92022-02-04 09:02:48 +0000301 config = StreamConfig(32000, 1);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200302 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100303 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000304
305 // New number of channels.
Henrik Lundin64253a92022-02-04 09:02:48 +0000306 config = StreamConfig(32000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200307 EXPECT_CALL(mock, InitializeLocked).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100308 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100309 EXPECT_NOERR(
310 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000311
aluebsb0319552016-03-17 20:39:53 -0700312 // A new sample rate passed to ProcessReverseStream should cause an init.
Henrik Lundin64253a92022-02-04 09:02:48 +0000313 config = StreamConfig(16000, 2);
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200314 EXPECT_CALL(mock, InitializeLocked).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100315 EXPECT_NOERR(
316 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000317}
318
Alessio Bazzicac054e782018-04-16 12:10:09 +0200319TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200320 rtc::scoped_refptr<AudioProcessing> apm =
321 AudioProcessingBuilderForTesting().Create();
Alex Loikob5c9a792018-04-16 16:31:22 +0200322 webrtc::AudioProcessing::Config apm_config;
323 apm_config.pre_amplifier.enabled = true;
324 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
325 apm->ApplyConfig(apm_config);
326
Per Åhgren2507f8c2020-03-19 12:33:29 +0100327 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200328 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200329 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200330
Per Åhgren2507f8c2020-03-19 12:33:29 +0100331 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000332 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100333 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100334 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100335 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200336 << "With factor 1, frame shouldn't be modified.";
337
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200338 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200339 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200340 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200341
342 // Process for two frames to have time to ramp up gain.
343 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100344 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100345 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200346 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100347 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200348 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200349}
350
Per Åhgrendb5d7282021-03-15 16:31:04 +0000351TEST(AudioProcessingImplTest,
352 LevelAdjustmentUpdateCapturePreGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200353 rtc::scoped_refptr<AudioProcessing> apm =
354 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000355 webrtc::AudioProcessing::Config apm_config;
356 apm_config.capture_level_adjustment.enabled = true;
357 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
358 apm->ApplyConfig(apm_config);
359
360 constexpr int kSampleRateHz = 48000;
361 constexpr int16_t kAudioLevel = 10000;
362 constexpr size_t kNumChannels = 2;
363
364 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000365 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000366 frame.fill(kAudioLevel);
367 apm->ProcessStream(frame.data(), config, config, frame.data());
368 EXPECT_EQ(frame[100], kAudioLevel)
369 << "With factor 1, frame shouldn't be modified.";
370
371 constexpr float kGainFactor = 2.f;
372 apm->SetRuntimeSetting(
373 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
374
375 // Process for two frames to have time to ramp up gain.
376 for (int i = 0; i < 2; ++i) {
377 frame.fill(kAudioLevel);
378 apm->ProcessStream(frame.data(), config, config, frame.data());
379 }
380 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
381 << "Frame should be amplified.";
382}
383
384TEST(AudioProcessingImplTest,
385 LevelAdjustmentUpdateCapturePostGainRuntimeSetting) {
Niels Möller4f776ac2021-07-02 11:30:54 +0200386 rtc::scoped_refptr<AudioProcessing> apm =
387 AudioProcessingBuilderForTesting().Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000388 webrtc::AudioProcessing::Config apm_config;
389 apm_config.capture_level_adjustment.enabled = true;
390 apm_config.capture_level_adjustment.post_gain_factor = 1.f;
391 apm->ApplyConfig(apm_config);
392
393 constexpr int kSampleRateHz = 48000;
394 constexpr int16_t kAudioLevel = 10000;
395 constexpr size_t kNumChannels = 2;
396
397 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000398 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000399 frame.fill(kAudioLevel);
400 apm->ProcessStream(frame.data(), config, config, frame.data());
401 EXPECT_EQ(frame[100], kAudioLevel)
402 << "With factor 1, frame shouldn't be modified.";
403
404 constexpr float kGainFactor = 2.f;
405 apm->SetRuntimeSetting(
406 AudioProcessing::RuntimeSetting::CreateCapturePostGain(kGainFactor));
407
408 // Process for two frames to have time to ramp up gain.
409 for (int i = 0; i < 2; ++i) {
410 frame.fill(kAudioLevel);
411 apm->ProcessStream(frame.data(), config, config, frame.data());
412 }
413 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
414 << "Frame should be amplified.";
415}
416
Per Åhgren652ada52021-03-03 10:52:44 +0000417TEST(AudioProcessingImplTest, EchoControllerObservesSetCaptureUsageChange) {
418 // Tests that the echo controller observes that the capture usage has been
419 // updated.
420 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
421 const MockEchoControlFactory* echo_control_factory_ptr =
422 echo_control_factory.get();
423
Niels Möller4f776ac2021-07-02 11:30:54 +0200424 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgren652ada52021-03-03 10:52:44 +0000425 AudioProcessingBuilderForTesting()
426 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200427 .Create();
Per Åhgren652ada52021-03-03 10:52:44 +0000428
429 constexpr int16_t kAudioLevel = 10000;
430 constexpr int kSampleRateHz = 48000;
431 constexpr int kNumChannels = 2;
432 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000433 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren652ada52021-03-03 10:52:44 +0000434 frame.fill(kAudioLevel);
435
436 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
437
438 // Ensure that SetCaptureOutputUsage is not called when no runtime settings
439 // are passed.
440 EXPECT_CALL(*echo_control_mock, SetCaptureOutputUsage(testing::_)).Times(0);
441 apm->ProcessStream(frame.data(), config, config, frame.data());
442
443 // Ensure that SetCaptureOutputUsage is called with the right information when
444 // a runtime setting is passed.
445 EXPECT_CALL(*echo_control_mock,
446 SetCaptureOutputUsage(/*capture_output_used=*/false))
447 .Times(1);
448 EXPECT_TRUE(apm->PostRuntimeSetting(
449 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
450 /*capture_output_used=*/false)));
451 apm->ProcessStream(frame.data(), config, config, frame.data());
452
453 EXPECT_CALL(*echo_control_mock,
454 SetCaptureOutputUsage(/*capture_output_used=*/true))
455 .Times(1);
456 EXPECT_TRUE(apm->PostRuntimeSetting(
457 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
458 /*capture_output_used=*/true)));
459 apm->ProcessStream(frame.data(), config, config, frame.data());
460
461 // The number of positions to place items in the queue is equal to the queue
462 // size minus 1.
463 constexpr int kNumSlotsInQueue = RuntimeSettingQueueSize();
464
465 // Ensure that SetCaptureOutputUsage is called with the right information when
466 // many runtime settings are passed.
467 for (int k = 0; k < kNumSlotsInQueue - 1; ++k) {
468 EXPECT_TRUE(apm->PostRuntimeSetting(
469 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
470 /*capture_output_used=*/false)));
471 }
472 EXPECT_CALL(*echo_control_mock,
473 SetCaptureOutputUsage(/*capture_output_used=*/false))
474 .Times(kNumSlotsInQueue - 1);
475 apm->ProcessStream(frame.data(), config, config, frame.data());
476
477 // Ensure that SetCaptureOutputUsage is properly called with the fallback
478 // value when the runtime settings queue becomes full.
479 for (int k = 0; k < kNumSlotsInQueue; ++k) {
480 EXPECT_TRUE(apm->PostRuntimeSetting(
481 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
482 /*capture_output_used=*/false)));
483 }
484 EXPECT_FALSE(apm->PostRuntimeSetting(
485 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
486 /*capture_output_used=*/false)));
487 EXPECT_FALSE(apm->PostRuntimeSetting(
488 AudioProcessing::RuntimeSetting::CreateCaptureOutputUsedSetting(
489 /*capture_output_used=*/false)));
490 EXPECT_CALL(*echo_control_mock,
491 SetCaptureOutputUsage(/*capture_output_used=*/false))
492 .Times(kNumSlotsInQueue);
493 EXPECT_CALL(*echo_control_mock,
494 SetCaptureOutputUsage(/*capture_output_used=*/true))
495 .Times(1);
496 apm->ProcessStream(frame.data(), config, config, frame.data());
497}
498
Alessio Bazzicae4498052018-12-17 09:44:06 +0100499TEST(AudioProcessingImplTest,
500 EchoControllerObservesPreAmplifierEchoPathGainChange) {
501 // Tests that the echo controller observes an echo path gain change when the
502 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200503 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100504 const auto* echo_control_factory_ptr = echo_control_factory.get();
505
Niels Möller4f776ac2021-07-02 11:30:54 +0200506 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200507 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100508 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200509 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200510 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100511 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200512 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100513 apm_config.gain_controller2.enabled = false;
514 apm_config.pre_amplifier.enabled = true;
515 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
516 apm->ApplyConfig(apm_config);
517
Alessio Bazzicae4498052018-12-17 09:44:06 +0100518 constexpr int16_t kAudioLevel = 10000;
519 constexpr size_t kSampleRateHz = 48000;
520 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100521 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000522 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100523 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100524
525 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
526
Per Åhgren0aefbf02019-08-23 21:29:17 +0200527 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200528 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100529 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200530 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100531 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100532
Per Åhgren0aefbf02019-08-23 21:29:17 +0200533 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200534 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100535 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200536 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100537 apm->SetRuntimeSetting(
538 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100539 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100540}
541
542TEST(AudioProcessingImplTest,
Per Åhgrendb5d7282021-03-15 16:31:04 +0000543 EchoControllerObservesLevelAdjustmentPreGainEchoPathGainChange) {
544 // Tests that the echo controller observes an echo path gain change when the
545 // pre-amplifier submodule changes the gain.
546 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
547 const auto* echo_control_factory_ptr = echo_control_factory.get();
548
Niels Möller4f776ac2021-07-02 11:30:54 +0200549 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrendb5d7282021-03-15 16:31:04 +0000550 AudioProcessingBuilderForTesting()
551 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200552 .Create();
Per Åhgrendb5d7282021-03-15 16:31:04 +0000553 // Disable AGC.
554 webrtc::AudioProcessing::Config apm_config;
555 apm_config.gain_controller1.enabled = false;
556 apm_config.gain_controller2.enabled = false;
557 apm_config.capture_level_adjustment.enabled = true;
558 apm_config.capture_level_adjustment.pre_gain_factor = 1.f;
559 apm->ApplyConfig(apm_config);
560
561 constexpr int16_t kAudioLevel = 10000;
562 constexpr size_t kSampleRateHz = 48000;
563 constexpr size_t kNumChannels = 2;
564 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000565 StreamConfig config(kSampleRateHz, kNumChannels);
Per Åhgrendb5d7282021-03-15 16:31:04 +0000566 frame.fill(kAudioLevel);
567
568 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
569
570 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
571 EXPECT_CALL(*echo_control_mock,
572 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
573 .Times(1);
574 apm->ProcessStream(frame.data(), config, config, frame.data());
575
576 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
577 EXPECT_CALL(*echo_control_mock,
578 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
579 .Times(1);
580 apm->SetRuntimeSetting(
581 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
582 apm->ProcessStream(frame.data(), config, config, frame.data());
583}
584
585TEST(AudioProcessingImplTest,
Alessio Bazzicae4498052018-12-17 09:44:06 +0100586 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
587 // Tests that the echo controller observes an echo path gain change when the
588 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200589 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100590 const auto* echo_control_factory_ptr = echo_control_factory.get();
591
Niels Möller4f776ac2021-07-02 11:30:54 +0200592 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200593 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100594 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200595 .Create();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100596 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200597 // Enable AGC1.
598 apm_config.gain_controller1.enabled = true;
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200599 apm_config.gain_controller1.analog_gain_controller.enabled = true;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100600 apm_config.gain_controller2.enabled = false;
601 apm_config.pre_amplifier.enabled = false;
602 apm->ApplyConfig(apm_config);
603
Alessio Bazzicae4498052018-12-17 09:44:06 +0100604 constexpr int16_t kAudioLevel = 1000;
605 constexpr size_t kSampleRateHz = 48000;
606 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100607 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000608 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100609 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100610
611 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
612
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200613 constexpr int kInitialStreamAnalogLevel = 123;
614 apm->set_stream_analog_level(kInitialStreamAnalogLevel);
615
616 // When the first fame is processed, no echo path gain change must be
617 // detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200618 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200619 EXPECT_CALL(*echo_control_mock,
620 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100621 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100622 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100623
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200624 // Simulate the application of the recommended analog level.
625 int recommended_analog_level = apm->recommended_stream_analog_level();
626 if (recommended_analog_level == kInitialStreamAnalogLevel) {
627 // Force an analog gain change if it did not happen.
628 recommended_analog_level++;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100629 }
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200630 apm->set_stream_analog_level(recommended_analog_level);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100631
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200632 // After the first fame and with a stream analog level change, the echo path
633 // gain change must be detected.
Per Åhgren0aefbf02019-08-23 21:29:17 +0200634 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200635 EXPECT_CALL(*echo_control_mock,
636 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100637 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100638 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100639}
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-Default/` is set.
Hanna Silen0c1ad292022-06-16 16:35:45 +0200644TEST(AudioProcessingImplTest,
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200645 ProcessWithAgc2AndTransientSuppressorVadModeDefault) {
646 webrtc::test::ScopedFieldTrials field_trials(
647 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-Default/");
648 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
649 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
Hanna Silen0c1ad292022-06-16 16:35:45 +0200650 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);
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200657 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 }
Hanna Silen0c1ad292022-06-16 16:35:45 +0200671}
672
Alessio Bazzicaa5aaedb2022-09-06 16:39:07 +0200673// Tests that a stream is successfully processed when AGC2 adaptive digital is
674// used and when the field trial
675// `WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/` is set.
676TEST(AudioProcessingImplTest,
677 ProcessWithAgc2AndTransientSuppressorVadModeRnnVad) {
Hanna Silen0c1ad292022-06-16 16:35:45 +0200678 webrtc::test::ScopedFieldTrials field_trials(
679 "WebRTC-Audio-TransientSuppressorVadMode/Enabled-RnnVad/");
680 rtc::scoped_refptr<AudioProcessing> apm = AudioProcessingBuilder().Create();
681 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
682 webrtc::AudioProcessing::Config apm_config;
683 // Disable AGC1 analog.
684 apm_config.gain_controller1.enabled = false;
685 // Enable AGC2 digital.
686 apm_config.gain_controller2.enabled = true;
687 apm_config.gain_controller2.adaptive_digital.enabled = true;
688 apm->ApplyConfig(apm_config);
689 constexpr int kSampleRateHz = 48000;
690 constexpr int kNumChannels = 1;
691 std::array<float, kSampleRateHz / 100> buffer;
692 float* channel_pointers[] = {buffer.data()};
693 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
694 /*num_channels=*/kNumChannels);
695 Random random_generator(2341U);
696 constexpr int kFramesToProcess = 10;
697 for (int i = 0; i < kFramesToProcess; ++i) {
698 RandomizeSampleVector(&random_generator, buffer);
699 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
700 channel_pointers),
701 kNoErr);
702 }
703}
704
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200705TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
706 // Tests that the echo controller observes an echo path gain change when a
707 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200708 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200709 const auto* echo_control_factory_ptr = echo_control_factory.get();
710
Niels Möller4f776ac2021-07-02 11:30:54 +0200711 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200712 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200713 .SetEchoControlFactory(std::move(echo_control_factory))
Niels Möller4f776ac2021-07-02 11:30:54 +0200714 .Create();
Sam Zackrisson41478c72019-10-15 10:10:26 +0200715 // Disable AGC.
716 webrtc::AudioProcessing::Config apm_config;
717 apm_config.gain_controller1.enabled = false;
718 apm_config.gain_controller2.enabled = false;
719 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200720
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200721 constexpr int16_t kAudioLevel = 10000;
722 constexpr size_t kSampleRateHz = 48000;
723 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100724 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000725 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100726 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200727
728 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
729
Per Åhgren0aefbf02019-08-23 21:29:17 +0200730 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200731 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100732 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200733 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100734 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200735
Per Åhgren0aefbf02019-08-23 21:29:17 +0200736 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200737 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100738 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200739 .Times(1);
740 apm->SetRuntimeSetting(
741 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100742 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200743
Per Åhgren0aefbf02019-08-23 21:29:17 +0200744 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200745 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100746 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200747 .Times(1);
748 apm->SetRuntimeSetting(
749 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100750 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200751
Per Åhgren0aefbf02019-08-23 21:29:17 +0200752 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200753 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100754 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200755 .Times(1);
756 apm->SetRuntimeSetting(
757 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100758 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200759}
760
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200761TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
762 // Make sure that signal changes caused by a render pre-processing sub-module
763 // take place before any echo detector analysis.
Tommi87f70902021-04-27 14:43:08 +0200764 auto test_echo_detector = rtc::make_ref_counted<TestEchoDetector>();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200765 std::unique_ptr<CustomProcessing> test_render_pre_processor(
766 new TestRenderPreProcessor());
767 // Create APM injecting the test echo detector and render pre-processor.
Niels Möller4f776ac2021-07-02 11:30:54 +0200768 rtc::scoped_refptr<AudioProcessing> apm =
Per Åhgrencc73ed32020-04-26 23:56:17 +0200769 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200770 .SetEchoDetector(test_echo_detector)
771 .SetRenderPreProcessing(std::move(test_render_pre_processor))
Niels Möller4f776ac2021-07-02 11:30:54 +0200772 .Create();
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200773 webrtc::AudioProcessing::Config apm_config;
774 apm_config.pre_amplifier.enabled = true;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200775 apm->ApplyConfig(apm_config);
776
777 constexpr int16_t kAudioLevel = 1000;
778 constexpr int kSampleRateHz = 16000;
779 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100780 // Explicitly initialize APM to ensure no render frames are discarded.
781 const ProcessingConfig processing_config = {{
Henrik Lundin64253a92022-02-04 09:02:48 +0000782 {kSampleRateHz, kNumChannels},
783 {kSampleRateHz, kNumChannels},
784 {kSampleRateHz, kNumChannels},
785 {kSampleRateHz, kNumChannels},
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100786 }};
787 apm->Initialize(processing_config);
788
Per Åhgren2507f8c2020-03-19 12:33:29 +0100789 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
Henrik Lundin64253a92022-02-04 09:02:48 +0000790 StreamConfig stream_config(kSampleRateHz, kNumChannels);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200791
792 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
793 constexpr float kExpectedPreprocessedAudioLevel =
794 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
795 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
796
797 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100798 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200799 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100800 apm->ProcessReverseStream(frame.data(), stream_config,
801 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200802 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
803 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100804 frame.fill(kAudioLevel);
805 ASSERT_EQ(AudioProcessing::Error::kNoError,
806 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100807 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200808 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
809 // triggered, the line below checks that the call has occurred. If not, the
810 // APM implementation may have changed and this test might need to be adapted.
811 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
812 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
813 // produced by the render pre-processor.
814 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
815 test_echo_detector->last_render_audio_first_sample());
816}
817
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200818// Disabling build-optional submodules and trying to enable them via the APM
819// config should be bit-exact with running APM with said submodules disabled.
820// This mainly tests that SetCreateOptionalSubmodulesForTesting has an effect.
821TEST(ApmWithSubmodulesExcludedTest, BitexactWithDisabledModules) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200822 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200823 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
824
825 ApmSubmoduleCreationOverrides overrides;
826 overrides.transient_suppression = true;
827 apm->OverrideSubmoduleCreationForTesting(overrides);
828
829 AudioProcessing::Config apm_config = apm->GetConfig();
830 apm_config.transient_suppression.enabled = true;
831 apm->ApplyConfig(apm_config);
832
833 rtc::scoped_refptr<AudioProcessing> apm_reference =
834 AudioProcessingBuilder().Create();
835 apm_config = apm_reference->GetConfig();
836 apm_config.transient_suppression.enabled = false;
837 apm_reference->ApplyConfig(apm_config);
838
839 constexpr int kSampleRateHz = 16000;
840 constexpr int kNumChannels = 1;
841 std::array<float, kSampleRateHz / 100> buffer;
842 std::array<float, kSampleRateHz / 100> buffer_reference;
843 float* channel_pointers[] = {buffer.data()};
844 float* channel_pointers_reference[] = {buffer_reference.data()};
845 StreamConfig stream_config(/*sample_rate_hz=*/kSampleRateHz,
Henrik Lundin64253a92022-02-04 09:02:48 +0000846 /*num_channels=*/kNumChannels);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200847 Random random_generator(2341U);
848 constexpr int kFramesToProcessPerConfiguration = 10;
849
850 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
851 RandomizeSampleVector(&random_generator, buffer);
852 std::copy(buffer.begin(), buffer.end(), buffer_reference.begin());
853 ASSERT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
854 channel_pointers),
855 kNoErr);
856 ASSERT_EQ(
857 apm_reference->ProcessStream(channel_pointers_reference, stream_config,
858 stream_config, channel_pointers_reference),
859 kNoErr);
860 for (int j = 0; j < kSampleRateHz / 100; ++j) {
861 EXPECT_EQ(buffer[j], buffer_reference[j]);
862 }
863 }
864}
865
866// Disable transient suppressor creation and run APM in ways that should trigger
867// calls to the transient suppressor API.
868TEST(ApmWithSubmodulesExcludedTest, ReinitializeTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200869 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200870 ASSERT_EQ(apm->Initialize(), kNoErr);
871
872 ApmSubmoduleCreationOverrides overrides;
873 overrides.transient_suppression = true;
874 apm->OverrideSubmoduleCreationForTesting(overrides);
875
876 AudioProcessing::Config config = apm->GetConfig();
877 config.transient_suppression.enabled = true;
878 apm->ApplyConfig(config);
879 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
880 float buffer[960];
881 float* channel_pointers[] = {&buffer[0], &buffer[480]};
882 Random random_generator(2341U);
883 constexpr int kFramesToProcessPerConfiguration = 3;
884
885 StreamConfig initial_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000886 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200887 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
888 RandomizeSampleVector(&random_generator, buffer);
889 EXPECT_EQ(apm->ProcessStream(channel_pointers, initial_stream_config,
890 initial_stream_config, channel_pointers),
891 kNoErr);
892 }
893
894 StreamConfig stereo_stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000895 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200896 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
897 RandomizeSampleVector(&random_generator, buffer);
898 EXPECT_EQ(apm->ProcessStream(channel_pointers, stereo_stream_config,
899 stereo_stream_config, channel_pointers),
900 kNoErr);
901 }
902
903 StreamConfig high_sample_rate_stream_config(/*sample_rate_hz=*/48000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000904 /*num_channels=*/2);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200905 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
906 RandomizeSampleVector(&random_generator, buffer);
907 EXPECT_EQ(
908 apm->ProcessStream(channel_pointers, high_sample_rate_stream_config,
909 high_sample_rate_stream_config, channel_pointers),
910 kNoErr);
911 }
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200912}
913
914// Disable transient suppressor creation and run APM in ways that should trigger
915// calls to the transient suppressor API.
916TEST(ApmWithSubmodulesExcludedTest, ToggleTransientSuppressor) {
Alessio Bazzicabe1b8982021-09-17 08:26:10 +0200917 auto apm = rtc::make_ref_counted<AudioProcessingImpl>();
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200918 ASSERT_EQ(apm->Initialize(), AudioProcessing::kNoError);
919
920 ApmSubmoduleCreationOverrides overrides;
921 overrides.transient_suppression = true;
922 apm->OverrideSubmoduleCreationForTesting(overrides);
923
924 // 960 samples per frame: 10 ms of <= 48 kHz audio with <= 2 channels.
925 float buffer[960];
926 float* channel_pointers[] = {&buffer[0], &buffer[480]};
927 Random random_generator(2341U);
928 constexpr int kFramesToProcessPerConfiguration = 3;
929 StreamConfig stream_config(/*sample_rate_hz=*/16000,
Henrik Lundin64253a92022-02-04 09:02:48 +0000930 /*num_channels=*/1);
Sam Zackrissonb37e59d2020-04-27 08:39:33 +0200931
932 AudioProcessing::Config config = apm->GetConfig();
933 config.transient_suppression.enabled = true;
934 apm->ApplyConfig(config);
935 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
936 RandomizeSampleVector(&random_generator, buffer);
937 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
938 channel_pointers),
939 kNoErr);
940 }
941
942 config = apm->GetConfig();
943 config.transient_suppression.enabled = false;
944 apm->ApplyConfig(config);
945 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
946 RandomizeSampleVector(&random_generator, buffer);
947 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
948 channel_pointers),
949 kNoErr);
950 }
951
952 config = apm->GetConfig();
953 config.transient_suppression.enabled = true;
954 apm->ApplyConfig(config);
955 for (int i = 0; i < kFramesToProcessPerConfiguration; ++i) {
956 RandomizeSampleVector(&random_generator, buffer);
957 EXPECT_EQ(apm->ProcessStream(channel_pointers, stream_config, stream_config,
958 channel_pointers),
959 kNoErr);
960 }
961}
Hanna Silenc69188d2022-09-16 11:38:56 +0200962
Alessio Bazzica352f38c2022-12-07 16:13:35 +0100963TEST(AudioProcessingImplTest, CanDisableTransientSuppressor) {
964 // Do not explicitly disable "WebRTC-ApmTransientSuppressorKillSwitch" since
965 // to check that, by default, it is disabled.
966 auto apm = AudioProcessingBuilder()
967 .SetConfig({.transient_suppression = {.enabled = false}})
968 .Create();
969 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
970}
971
972TEST(AudioProcessingImplTest, CanEnableTransientSuppressor) {
973 // Do not explicitly disable "WebRTC-ApmTransientSuppressorKillSwitch" since
974 // to check that, by default, it is disabled.
975 auto apm = AudioProcessingBuilder()
976 .SetConfig({.transient_suppression = {.enabled = true}})
977 .Create();
978 EXPECT_TRUE(apm->GetConfig().transient_suppression.enabled);
979}
980
981TEST(AudioProcessingImplTest, CanDisableTransientSuppressorIfUsageAllowed) {
982 // Disable the field trial that disallows to enable transient suppression.
983 test::ScopedFieldTrials field_trials(
984 "WebRTC-ApmTransientSuppressorKillSwitch/Disabled/");
985 auto apm = AudioProcessingBuilder()
986 .SetConfig({.transient_suppression = {.enabled = false}})
987 .Create();
988 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
989}
990
991TEST(AudioProcessingImplTest, CanEnableTransientSuppressorIfUsageAllowed) {
992 // Disable the field trial that disallows to enable transient suppression.
993 test::ScopedFieldTrials field_trials(
994 "WebRTC-ApmTransientSuppressorKillSwitch/Disabled/");
995 auto apm = AudioProcessingBuilder()
996 .SetConfig({.transient_suppression = {.enabled = true}})
997 .Create();
998 EXPECT_TRUE(apm->GetConfig().transient_suppression.enabled);
999}
1000
1001TEST(AudioProcessingImplTest,
1002 CannotEnableTransientSuppressorIfUsageDisallowed) {
1003 // Enable the field trial that disallows to enable transient suppression.
1004 test::ScopedFieldTrials field_trials(
1005 "WebRTC-ApmTransientSuppressorKillSwitch/Enabled/");
1006 auto apm = AudioProcessingBuilder()
1007 .SetConfig({.transient_suppression = {.enabled = true}})
1008 .Create();
1009 EXPECT_FALSE(apm->GetConfig().transient_suppression.enabled);
1010}
1011
Hanna Silenc69188d2022-09-16 11:38:56 +02001012// Tests that the minimum startup volume is applied at the startup.
1013TEST_P(InputVolumeStartupParameterizedTest,
1014 VerifyStartupMinVolumeAppliedAtStartup) {
1015 const int applied_startup_input_volume = GetStartupVolume();
Hanna Silenc69188d2022-09-16 11:38:56 +02001016 const int expected_volume =
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001017 std::max(applied_startup_input_volume, GetMinVolume());
Hanna Silend4dbe452022-11-30 15:16:21 +01001018 const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
1019 const bool agc2_input_volume_controller_enabled =
1020 GetAgc2InputVolumeControllerEnabled();
1021 auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
1022 agc2_input_volume_controller_enabled);
Hanna Silenc69188d2022-09-16 11:38:56 +02001023
1024 const int recommended_input_volume =
1025 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1026
Hanna Silend4dbe452022-11-30 15:16:21 +01001027 if (!agc1_analog_controller_enabled &&
1028 !agc2_input_volume_controller_enabled) {
1029 // No input volume changes if none of the analog controllers is enabled.
1030 ASSERT_EQ(recommended_input_volume, applied_startup_input_volume);
1031 } else {
1032 ASSERT_EQ(recommended_input_volume, expected_volume);
1033 }
Hanna Silenc69188d2022-09-16 11:38:56 +02001034}
1035
1036// Tests that the minimum input volume is applied if the volume is manually
Hanna Silend4dbe452022-11-30 15:16:21 +01001037// adjusted to a non-zero value 1) always for AGC2 input volume controller and
1038// 2) only if "WebRTC-Audio-2ndAgcMinMicLevelExperiment" is enabled for AGC1
1039// analog controller.
Hanna Silenc69188d2022-09-16 11:38:56 +02001040TEST_P(InputVolumeNotZeroParameterizedTest,
1041 VerifyMinVolumeMaybeAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001042 const int applied_startup_input_volume = GetStartupVolume();
1043 const int applied_input_volume = GetVolume();
1044 const int expected_volume = std::max(applied_input_volume, GetMinVolume());
Hanna Silend4dbe452022-11-30 15:16:21 +01001045 const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
1046 const bool agc2_input_volume_controller_enabled =
1047 GetAgc2InputVolumeControllerEnabled();
1048 auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
1049 agc2_input_volume_controller_enabled);
Hanna Silenc69188d2022-09-16 11:38:56 +02001050
1051 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1052 const int recommended_input_volume =
1053 ProcessInputVolume(*apm, /*num_frames=*/1, applied_input_volume);
1054
1055 ASSERT_NE(applied_input_volume, 0);
Hanna Silend4dbe452022-11-30 15:16:21 +01001056
1057 if (!agc1_analog_controller_enabled &&
1058 !agc2_input_volume_controller_enabled) {
1059 // No input volume changes if none of the analog controllers is enabled.
Hanna Silenc69188d2022-09-16 11:38:56 +02001060 ASSERT_EQ(recommended_input_volume, applied_input_volume);
Hanna Silend4dbe452022-11-30 15:16:21 +01001061 } else {
1062 if (GetMinMicLevelExperimentEnabled() ||
1063 (!agc1_analog_controller_enabled &&
1064 agc2_input_volume_controller_enabled)) {
1065 ASSERT_EQ(recommended_input_volume, expected_volume);
1066 } else {
1067 ASSERT_EQ(recommended_input_volume, applied_input_volume);
1068 }
Hanna Silenc69188d2022-09-16 11:38:56 +02001069 }
1070}
1071
1072// Tests that the minimum input volume is not applied if the volume is manually
1073// adjusted to zero.
1074TEST_P(InputVolumeZeroParameterizedTest,
1075 VerifyMinVolumeNotAppliedAfterManualVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001076 constexpr int kZeroVolume = 0;
1077 const int applied_startup_input_volume = GetStartupVolume();
Hanna Silend4dbe452022-11-30 15:16:21 +01001078 const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
1079 const bool agc2_input_volume_controller_enabled =
1080 GetAgc2InputVolumeControllerEnabled();
1081 auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
1082 agc2_input_volume_controller_enabled);
Hanna Silenc69188d2022-09-16 11:38:56 +02001083
1084 const int recommended_input_volume_after_startup =
1085 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1086 const int recommended_input_volume =
1087 ProcessInputVolume(*apm, /*num_frames=*/1, kZeroVolume);
1088
Hanna Silend4dbe452022-11-30 15:16:21 +01001089 if (!agc1_analog_controller_enabled &&
1090 !agc2_input_volume_controller_enabled) {
1091 // No input volume changes if none of the analog controllers is enabled.
1092 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1093 } else {
1094 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
1095 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1096 }
Hanna Silenc69188d2022-09-16 11:38:56 +02001097}
1098
1099// Tests that the minimum input volume is applied if the volume is not zero
1100// before it is automatically adjusted.
1101TEST_P(InputVolumeNotZeroParameterizedTest,
1102 VerifyMinVolumeAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001103 const int applied_startup_input_volume = GetStartupVolume();
1104 const int applied_input_volume = GetVolume();
Hanna Silend4dbe452022-11-30 15:16:21 +01001105 const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
1106 const bool agc2_input_volume_controller_enabled =
1107 GetAgc2InputVolumeControllerEnabled();
1108 auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
1109 agc2_input_volume_controller_enabled);
Hanna Silenc69188d2022-09-16 11:38:56 +02001110
1111 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1112 const int recommended_input_volume =
1113 ProcessInputVolume(*apm, /*num_frames=*/400, applied_input_volume);
1114
1115 ASSERT_NE(applied_input_volume, 0);
Hanna Silend4dbe452022-11-30 15:16:21 +01001116
1117 if (!agc1_analog_controller_enabled &&
1118 !agc2_input_volume_controller_enabled) {
1119 // No input volume changes if none of the analog controllers is enabled.
1120 ASSERT_EQ(recommended_input_volume, applied_input_volume);
1121 } else {
1122 if (recommended_input_volume != applied_input_volume) {
1123 ASSERT_GE(recommended_input_volume, GetMinVolume());
1124 }
Hanna Silenc69188d2022-09-16 11:38:56 +02001125 }
1126}
1127
1128// Tests that the minimum input volume is not applied if the volume is zero
1129// before it is automatically adjusted.
1130TEST_P(InputVolumeZeroParameterizedTest,
1131 VerifyMinVolumeNotAppliedAfterAutomaticVolumeAdjustments) {
Hanna Silenc69188d2022-09-16 11:38:56 +02001132 constexpr int kZeroVolume = 0;
1133 const int applied_startup_input_volume = GetStartupVolume();
Hanna Silend4dbe452022-11-30 15:16:21 +01001134 const bool agc1_analog_controller_enabled = GetAgc1AnalogControllerEnabled();
1135 const bool agc2_input_volume_controller_enabled =
1136 GetAgc2InputVolumeControllerEnabled();
1137 auto apm = CreateApmForInputVolumeTest(agc1_analog_controller_enabled,
1138 agc2_input_volume_controller_enabled);
Hanna Silenc69188d2022-09-16 11:38:56 +02001139
1140 const int recommended_input_volume_after_startup =
1141 ProcessInputVolume(*apm, /*num_frames=*/1, applied_startup_input_volume);
1142 const int recommended_input_volume =
1143 ProcessInputVolume(*apm, /*num_frames=*/400, kZeroVolume);
1144
Hanna Silend4dbe452022-11-30 15:16:21 +01001145 if (!agc1_analog_controller_enabled &&
1146 !agc2_input_volume_controller_enabled) {
1147 // No input volume changes if none of the analog controllers is enabled.
1148 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1149 } else {
1150 ASSERT_NE(recommended_input_volume, recommended_input_volume_after_startup);
1151 ASSERT_EQ(recommended_input_volume, kZeroVolume);
1152 }
Hanna Silenc69188d2022-09-16 11:38:56 +02001153}
1154
1155INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1156 InputVolumeStartupParameterizedTest,
Alessio Bazzica9ea53812022-10-13 17:09:15 +02001157 ::testing::Combine(::testing::Values(0, 5, 30),
Hanna Silenc69188d2022-09-16 11:38:56 +02001158 ::testing::Values(absl::nullopt,
Hanna Silend4dbe452022-11-30 15:16:21 +01001159 20),
1160 ::testing::Bool(),
1161 ::testing::Bool()));
Hanna Silenc69188d2022-09-16 11:38:56 +02001162
1163INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1164 InputVolumeNotZeroParameterizedTest,
1165 ::testing::Combine(::testing::Values(0, 5, 15),
1166 ::testing::Values(1, 5, 30),
1167 ::testing::Values(absl::nullopt,
Hanna Silend4dbe452022-11-30 15:16:21 +01001168 20),
1169 ::testing::Bool(),
1170 ::testing::Bool()));
Hanna Silenc69188d2022-09-16 11:38:56 +02001171
1172INSTANTIATE_TEST_SUITE_P(AudioProcessingImplTest,
1173 InputVolumeZeroParameterizedTest,
1174 ::testing::Combine(::testing::Values(0, 5, 15),
1175 ::testing::Values(absl::nullopt,
Hanna Silend4dbe452022-11-30 15:16:21 +01001176 20),
1177 ::testing::Bool(),
1178 ::testing::Bool()));
Hanna Silenc69188d2022-09-16 11:38:56 +02001179
Alessio Bazzica79beaa72022-10-31 16:42:34 +01001180// When the input volume is not emulated and no input volume controller is
1181// active, the recommended volume must always be the applied volume.
1182TEST(AudioProcessingImplTest,
1183 RecommendAppliedInputVolumeWithNoAgcWithNoEmulation) {
1184 auto apm = AudioProcessingBuilder()
1185 .SetConfig({.capture_level_adjustment = {.enabled = false},
1186 .gain_controller1 = {.enabled = false}})
1187 .Create();
1188
1189 constexpr int kOneFrame = 1;
1190 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1191 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1192 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1193}
1194
1195// When the input volume is emulated, the recommended volume must always be the
1196// applied volume and at any time it must not be that set in the input volume
1197// emulator.
1198// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1199TEST(AudioProcessingImplTest,
1200 DISABLED_RecommendAppliedInputVolumeWithNoAgcWithEmulation) {
1201 auto apm =
1202 AudioProcessingBuilder()
1203 .SetConfig({.capture_level_adjustment = {.enabled = true,
1204 .analog_mic_gain_emulation{
1205 .enabled = true,
1206 .initial_level = 255}},
1207 .gain_controller1 = {.enabled = false}})
1208 .Create();
1209
1210 constexpr int kOneFrame = 1;
1211 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1212 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1213 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1214}
1215
1216// Even if there is an enabled input volume controller, when the input volume is
1217// emulated, the recommended volume is always the applied volume because the
1218// active controller must only adjust the internally emulated volume and leave
1219// the externally applied volume unchanged.
1220// TODO(bugs.webrtc.org/14581): Enable when APM fixed to let this test pass.
1221TEST(AudioProcessingImplTest,
1222 DISABLED_RecommendAppliedInputVolumeWithAgcWithEmulation) {
1223 auto apm =
1224 AudioProcessingBuilder()
1225 .SetConfig({.capture_level_adjustment = {.enabled = true,
1226 .analog_mic_gain_emulation{
1227 .enabled = true}},
1228 .gain_controller1 = {.enabled = true,
1229 .analog_gain_controller{
1230 .enabled = true,
1231 }}})
1232 .Create();
1233
1234 constexpr int kOneFrame = 1;
1235 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/123), 123);
1236 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/59), 59);
1237 EXPECT_EQ(ProcessInputVolume(*apm, kOneFrame, /*initial_volume=*/135), 135);
1238}
1239
Hanna Silena6574902022-11-30 16:59:05 +01001240TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1241 ConfigAdjustedWhenExperimentEnabledAndAgc1AnalogEnabled) {
1242 webrtc::test::ScopedFieldTrials field_trials(
1243 "WebRTC-Audio-InputVolumeControllerExperiment/"
1244 "Enabled,"
1245 "enable_clipping_predictor:true,"
1246 "clipped_level_min:20,"
1247 "clipped_level_step:30,"
1248 "clipped_ratio_threshold:0.4,"
1249 "clipped_wait_frames:50,"
1250 "target_range_max_dbfs:-6,"
1251 "target_range_min_dbfs:-70,"
1252 "update_input_volume_wait_frames:80,"
1253 "speech_probability_threshold:0.9,"
1254 "speech_ratio_threshold:1.0/");
1255
1256 AudioProcessingBuilderForTesting apm_builder;
1257
1258 // Set a config with analog AGC1 enabled.
1259 AudioProcessing::Config config;
1260 config.gain_controller1.enabled = true;
1261 config.gain_controller1.analog_gain_controller.enabled = true;
1262 config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
1263 config.gain_controller2.enabled = false;
1264 config.gain_controller1.mode =
1265 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1266
1267 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1268
1269 apm_builder.SetConfig(config);
1270
1271 auto apm = apm_builder.Create();
1272 auto adjusted_config = apm->GetConfig();
1273
1274 // Expect the config to be adjusted.
1275 EXPECT_FALSE(adjusted_config.gain_controller1.enabled);
1276 EXPECT_FALSE(adjusted_config.gain_controller1.analog_gain_controller.enabled);
1277 EXPECT_TRUE(adjusted_config.gain_controller2.enabled);
1278 EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled);
1279 EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled);
1280
1281 // Change config back and compare.
1282 adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled;
1283 adjusted_config.gain_controller1.analog_gain_controller.enabled =
1284 config.gain_controller1.analog_gain_controller.enabled;
1285 adjusted_config.gain_controller2.enabled = config.gain_controller2.enabled;
1286 adjusted_config.gain_controller2.adaptive_digital.enabled =
1287 config.gain_controller2.adaptive_digital.enabled;
1288 adjusted_config.gain_controller2.input_volume_controller.enabled =
1289 config.gain_controller2.input_volume_controller.enabled;
1290
1291 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1292}
1293
1294TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1295 ConfigAdjustedWhenExperimentEnabledAndHybridAgcEnabled) {
1296 webrtc::test::ScopedFieldTrials field_trials(
1297 "WebRTC-Audio-InputVolumeControllerExperiment/"
1298 "Enabled,"
1299 "enable_clipping_predictor:true,"
1300 "clipped_level_min:20,"
1301 "clipped_level_step:30,"
1302 "clipped_ratio_threshold:0.4,"
1303 "clipped_wait_frames:50,"
1304 "target_range_max_dbfs:-6,"
1305 "target_range_min_dbfs:-70,"
1306 "update_input_volume_wait_frames:80,"
1307 "speech_probability_threshold:0.9,"
1308 "speech_ratio_threshold:1.0/");
1309
1310 AudioProcessingBuilderForTesting apm_builder;
1311
1312 // Set a config with hybrid AGC enabled.
1313 AudioProcessing::Config config;
1314 config.gain_controller1.enabled = true;
1315 config.gain_controller1.analog_gain_controller.enabled = true;
1316 config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
1317 false;
1318 config.gain_controller2.enabled = true;
1319 config.gain_controller2.adaptive_digital.enabled = true;
1320 config.gain_controller1.mode =
1321 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1322
1323 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1324
1325 apm_builder.SetConfig(config);
1326
1327 auto apm = apm_builder.Create();
1328 auto adjusted_config = apm->GetConfig();
1329
1330 // Expect the config to be adjusted.
1331 EXPECT_FALSE(adjusted_config.gain_controller1.enabled);
1332 EXPECT_FALSE(adjusted_config.gain_controller1.analog_gain_controller.enabled);
1333 EXPECT_TRUE(adjusted_config.gain_controller2.enabled);
1334 EXPECT_TRUE(adjusted_config.gain_controller2.adaptive_digital.enabled);
1335 EXPECT_TRUE(adjusted_config.gain_controller2.input_volume_controller.enabled);
1336
1337 // Change config back and compare.
1338 adjusted_config.gain_controller1.enabled = config.gain_controller1.enabled;
1339 adjusted_config.gain_controller1.analog_gain_controller.enabled =
1340 config.gain_controller1.analog_gain_controller.enabled;
1341 adjusted_config.gain_controller2.enabled = config.gain_controller2.enabled;
1342 adjusted_config.gain_controller2.adaptive_digital.enabled =
1343 config.gain_controller2.adaptive_digital.enabled;
1344 adjusted_config.gain_controller2.input_volume_controller.enabled =
1345 config.gain_controller2.input_volume_controller.enabled;
1346
1347 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1348}
1349
1350TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1351 ConfigNotAdjustedWhenExperimentEnabledAndAgc1AnalogNotEnabled) {
1352 webrtc::test::ScopedFieldTrials field_trials(
1353 "WebRTC-Audio-InputVolumeControllerExperiment/"
1354 "Enabled,"
1355 "enable_clipping_predictor:true,"
1356 "clipped_level_min:20,"
1357 "clipped_level_step:30,"
1358 "clipped_ratio_threshold:0.4,"
1359 "clipped_wait_frames:50,"
1360 "target_range_max_dbfs:-6,"
1361 "target_range_min_dbfs:-70,"
1362 "update_input_volume_wait_frames:80,"
1363 "speech_probability_threshold:0.9,"
1364 "speech_ratio_threshold:1.0/");
1365
1366 AudioProcessingBuilderForTesting apm_builder;
1367
1368 // Set a config with analog AGC1 not enabled.
1369 AudioProcessing::Config config;
1370 config.gain_controller1.enabled = false;
1371 config.gain_controller1.analog_gain_controller.enabled = true;
1372 config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
1373 config.gain_controller2.enabled = false;
1374 config.gain_controller1.mode =
1375 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1376
1377 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1378
1379 apm_builder.SetConfig(config);
1380
1381 auto apm = apm_builder.Create();
1382 auto adjusted_config = apm->GetConfig();
1383
1384 EXPECT_EQ(config.gain_controller1.enabled,
1385 adjusted_config.gain_controller1.enabled);
1386 EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
1387 adjusted_config.gain_controller1.analog_gain_controller.enabled);
1388 EXPECT_EQ(config.gain_controller2.enabled,
1389 adjusted_config.gain_controller2.enabled);
1390 EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
1391 adjusted_config.gain_controller2.adaptive_digital.enabled);
1392 EXPECT_FALSE(
1393 adjusted_config.gain_controller2.input_volume_controller.enabled);
1394
1395 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1396}
1397
1398TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1399 ConfigNotAdjustedWhenExperimentEnabledAndHybridAgcNotEnabled) {
1400 webrtc::test::ScopedFieldTrials field_trials(
1401 "WebRTC-Audio-InputVolumeControllerExperiment/"
1402 "Enabled,"
1403 "enable_clipping_predictor:true,"
1404 "clipped_level_min:20,"
1405 "clipped_level_step:30,"
1406 "clipped_ratio_threshold:0.4,"
1407 "clipped_wait_frames:50,"
1408 "target_range_max_dbfs:-6,"
1409 "target_range_min_dbfs:-70,"
1410 "update_input_volume_wait_frames:80,"
1411 "speech_probability_threshold:0.9,"
1412 "speech_ratio_threshold:1.0/");
1413
1414 AudioProcessingBuilderForTesting apm_builder;
1415
1416 // Set a config with hybrid AGC analog not enabled.
1417 AudioProcessing::Config config;
1418 config.gain_controller1.enabled = false;
1419 config.gain_controller1.analog_gain_controller.enabled = true;
1420 config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
1421 false;
1422 config.gain_controller2.enabled = true;
1423 config.gain_controller2.adaptive_digital.enabled = true;
1424 config.gain_controller1.mode =
1425 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1426
1427 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1428
1429 apm_builder.SetConfig(config);
1430
1431 auto apm = apm_builder.Create();
1432 auto adjusted_config = apm->GetConfig();
1433
1434 EXPECT_EQ(config.gain_controller1.enabled,
1435 adjusted_config.gain_controller1.enabled);
1436 EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
1437 adjusted_config.gain_controller1.analog_gain_controller.enabled);
1438 EXPECT_EQ(config.gain_controller2.enabled,
1439 adjusted_config.gain_controller2.enabled);
1440 EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
1441 adjusted_config.gain_controller2.adaptive_digital.enabled);
1442 EXPECT_FALSE(
1443 adjusted_config.gain_controller2.input_volume_controller.enabled);
1444
1445 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1446}
1447
1448TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1449 ConfigNotAdjustedWhenExperimentNotEnabledAndAgc1AnalogEnabled) {
1450 AudioProcessingBuilderForTesting apm_builder;
1451
1452 // Set a config with analog AGC1 analog enabled.
1453 AudioProcessing::Config config;
1454 config.gain_controller1.enabled = true;
1455 config.gain_controller1.analog_gain_controller.enabled = true;
1456 config.gain_controller1.analog_gain_controller.enable_digital_adaptive = true;
1457 config.gain_controller2.enabled = false;
1458 config.gain_controller1.mode =
1459 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1460
1461 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1462
1463 apm_builder.SetConfig(config);
1464
1465 auto apm = apm_builder.Create();
1466 auto adjusted_config = apm->GetConfig();
1467
1468 EXPECT_EQ(config.gain_controller1.enabled,
1469 adjusted_config.gain_controller1.enabled);
1470 EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
1471 adjusted_config.gain_controller1.analog_gain_controller.enabled);
1472 EXPECT_EQ(config.gain_controller2.enabled,
1473 adjusted_config.gain_controller2.enabled);
1474 EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
1475 adjusted_config.gain_controller2.adaptive_digital.enabled);
1476 EXPECT_FALSE(
1477 adjusted_config.gain_controller2.input_volume_controller.enabled);
1478
1479 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1480}
1481
1482TEST(AudioProcessingImplInputVolumeControllerExperimentTest,
1483 ConfigNotAdjustedWhenExperimentNotEnabledAndHybridAgcEnabled) {
1484 AudioProcessingBuilderForTesting apm_builder;
1485
1486 // Set a config with hybrid AGC enabled.
1487 AudioProcessing::Config config;
1488 config.gain_controller1.enabled = true;
1489 config.gain_controller1.analog_gain_controller.enabled = true;
1490 config.gain_controller1.analog_gain_controller.enable_digital_adaptive =
1491 false;
1492 config.gain_controller2.enabled = true;
1493 config.gain_controller2.adaptive_digital.enabled = true;
1494 config.gain_controller1.mode =
1495 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
1496
1497 EXPECT_FALSE(config.gain_controller2.input_volume_controller.enabled);
1498
1499 apm_builder.SetConfig(config);
1500
1501 auto apm = apm_builder.Create();
1502 auto adjusted_config = apm->GetConfig();
1503
1504 EXPECT_EQ(config.gain_controller1.enabled,
1505 adjusted_config.gain_controller1.enabled);
1506 EXPECT_EQ(config.gain_controller1.analog_gain_controller.enabled,
1507 adjusted_config.gain_controller1.analog_gain_controller.enabled);
1508 EXPECT_EQ(config.gain_controller2.enabled,
1509 adjusted_config.gain_controller2.enabled);
1510 EXPECT_EQ(config.gain_controller2.adaptive_digital.enabled,
1511 adjusted_config.gain_controller2.adaptive_digital.enabled);
1512 EXPECT_FALSE(
1513 adjusted_config.gain_controller2.input_volume_controller.enabled);
1514
1515 EXPECT_THAT(adjusted_config.ToString(), ::testing::StrEq(config.ToString()));
1516}
1517
andrew@webrtc.org60730cf2014-01-07 17:45:09 +00001518} // namespace webrtc