blob: 180960a620513f42fa4fc8c38f75bec6deb3c46a [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
Alessio Bazzicae4498052018-12-17 09:44:06 +010013#include <memory>
14
Mirko Bonadeid9708072019-01-25 20:26:48 +010015#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 14:23:11 +020016#include "modules/audio_processing/include/audio_processing.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010017#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010019#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080020#include "rtc_base/ref_counted_object.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020021#include "test/gmock.h"
22#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000023
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000024namespace webrtc {
peaha9cc40b2017-06-29 08:32:09 -070025namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000026
Alessio Bazzicae4498052018-12-17 09:44:06 +010027using ::testing::Invoke;
28using ::testing::NotNull;
29
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000030class MockInitialize : public AudioProcessingImpl {
31 public:
peah88ac8532016-09-12 16:47:25 -070032 explicit MockInitialize(const webrtc::Config& config)
33 : AudioProcessingImpl(config) {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000034
andrew@webrtc.orge84978f2014-01-25 02:09:06 +000035 MOCK_METHOD0(InitializeLocked, int());
danilchap56359be2017-09-07 07:53:45 -070036 int RealInitializeLocked() RTC_NO_THREAD_SAFETY_ANALYSIS {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000037 return AudioProcessingImpl::InitializeLocked();
38 }
peaha9cc40b2017-06-29 08:32:09 -070039
Niels Möller6f72f562017-10-19 13:15:17 +020040 MOCK_CONST_METHOD0(AddRef, void());
41 MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000042};
43
Alessio Bazzicae4498052018-12-17 09:44:06 +010044// Creates MockEchoControl instances and provides a raw pointer access to
45// the next created one. The raw pointer is meant to be used with gmock.
46// Returning a pointer of the next created MockEchoControl instance is necessary
47// for the following reasons: (i) gmock expectations must be set before any call
48// occurs, (ii) APM is initialized the first time that
49// AudioProcessingImpl::ProcessStream() is called and the initialization leads
50// to the creation of a new EchoControl object.
51class MockEchoControlFactory : public EchoControlFactory {
52 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020053 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010054 // Returns a pointer to the next MockEchoControl that this factory creates.
55 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010056 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
57 int num_render_channels,
58 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010059 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020060 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010061 return mock;
62 }
63
64 private:
65 std::unique_ptr<MockEchoControl> next_mock_;
66};
67
Alessio Bazzicad2b97402018-08-09 14:23:11 +020068void InitializeAudioFrame(size_t input_rate,
69 size_t num_channels,
70 AudioFrame* frame) {
Alex Loikob5c9a792018-04-16 16:31:22 +020071 const size_t samples_per_input_channel = rtc::CheckedDivExact(
72 input_rate, static_cast<size_t>(rtc::CheckedDivExact(
73 1000, AudioProcessing::kChunkSizeMs)));
Alex Loikob5c9a792018-04-16 16:31:22 +020074 RTC_DCHECK_LE(samples_per_input_channel * num_channels,
75 AudioFrame::kMaxDataSizeSamples);
Alessio Bazzicad2b97402018-08-09 14:23:11 +020076 frame->samples_per_channel_ = samples_per_input_channel;
77 frame->sample_rate_hz_ = input_rate;
78 frame->num_channels_ = num_channels;
79}
80
81void FillFixedFrame(int16_t audio_level, AudioFrame* frame) {
82 const size_t num_samples = frame->samples_per_channel_ * frame->num_channels_;
83 for (size_t i = 0; i < num_samples; ++i) {
84 frame->mutable_data()[i] = audio_level;
Alex Loikob5c9a792018-04-16 16:31:22 +020085 }
86}
87
Alessio Bazzicad2b97402018-08-09 14:23:11 +020088// Mocks EchoDetector and records the first samples of the last analyzed render
89// stream frame. Used to check what data is read by an EchoDetector
90// implementation injected into an APM.
91class TestEchoDetector : public EchoDetector {
92 public:
93 TestEchoDetector()
94 : analyze_render_audio_called_(false),
95 last_render_audio_first_sample_(0.f) {}
96 ~TestEchoDetector() override = default;
97 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
98 last_render_audio_first_sample_ = render_audio[0];
99 analyze_render_audio_called_ = true;
100 }
101 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
102 }
103 void Initialize(int capture_sample_rate_hz,
104 int num_capture_channels,
105 int render_sample_rate_hz,
106 int num_render_channels) override {}
107 EchoDetector::Metrics GetMetrics() const override { return {}; }
108 // Returns true if AnalyzeRenderAudio() has been called at least once.
109 bool analyze_render_audio_called() const {
110 return analyze_render_audio_called_;
111 }
112 // Returns the first sample of the last analyzed render frame.
113 float last_render_audio_first_sample() const {
114 return last_render_audio_first_sample_;
115 }
116
117 private:
118 bool analyze_render_audio_called_;
119 float last_render_audio_first_sample_;
120};
121
122// Mocks CustomProcessing and applies ProcessSample() to all the samples.
123// Meant to be injected into an APM to modify samples in a known and detectable
124// way.
125class TestRenderPreProcessor : public CustomProcessing {
126 public:
127 TestRenderPreProcessor() = default;
128 ~TestRenderPreProcessor() = default;
129 void Initialize(int sample_rate_hz, int num_channels) override {}
130 void Process(AudioBuffer* audio) override {
131 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200132 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200133 audio->num_frames());
134 std::transform(channel_view.begin(), channel_view.end(),
135 channel_view.begin(), ProcessSample);
136 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100137 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200138 std::string ToString() const override { return "TestRenderPreProcessor"; }
139 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
140 // Modifies a sample. This member is used in Process() to modify a frame and
141 // it is publicly visible to enable tests.
142 static constexpr float ProcessSample(float x) { return 2.f * x; }
143};
144
peaha9cc40b2017-06-29 08:32:09 -0700145} // namespace
146
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000147TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
peah88ac8532016-09-12 16:47:25 -0700148 webrtc::Config config;
andrew@webrtc.orge84978f2014-01-25 02:09:06 +0000149 MockInitialize mock(config);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000150 ON_CALL(mock, InitializeLocked())
151 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
152
153 EXPECT_CALL(mock, InitializeLocked()).Times(1);
154 mock.Initialize();
155
156 AudioFrame frame;
peah2ace3f92016-09-10 04:42:27 -0700157 // Call with the default parameters; there should be an init.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000158 frame.num_channels_ = 1;
159 SetFrameSampleRate(&frame, 16000);
Per Åhgren4bdced52017-06-27 16:00:38 +0200160 EXPECT_CALL(mock, InitializeLocked()).Times(0);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000161 EXPECT_NOERR(mock.ProcessStream(&frame));
aluebsb0319552016-03-17 20:39:53 -0700162 EXPECT_NOERR(mock.ProcessReverseStream(&frame));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000163
164 // New sample rate. (Only impacts ProcessStream).
165 SetFrameSampleRate(&frame, 32000);
Yves Gerey665174f2018-06-19 15:03:05 +0200166 EXPECT_CALL(mock, InitializeLocked()).Times(1);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000167 EXPECT_NOERR(mock.ProcessStream(&frame));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000168
169 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700170 // TODO(peah): Investigate why this causes 2 inits.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000171 frame.num_channels_ = 2;
Yves Gerey665174f2018-06-19 15:03:05 +0200172 EXPECT_CALL(mock, InitializeLocked()).Times(2);
andrew@webrtc.orga8b97372014-03-10 22:26:12 +0000173 EXPECT_NOERR(mock.ProcessStream(&frame));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000174 // ProcessStream sets num_channels_ == num_output_channels.
175 frame.num_channels_ = 2;
aluebsb0319552016-03-17 20:39:53 -0700176 EXPECT_NOERR(mock.ProcessReverseStream(&frame));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000177
aluebsb0319552016-03-17 20:39:53 -0700178 // A new sample rate passed to ProcessReverseStream should cause an init.
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000179 SetFrameSampleRate(&frame, 16000);
Alex Luebs5b830fe2016-03-08 17:52:52 +0100180 EXPECT_CALL(mock, InitializeLocked()).Times(1);
aluebsb0319552016-03-17 20:39:53 -0700181 EXPECT_NOERR(mock.ProcessReverseStream(&frame));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000182}
183
Alessio Bazzicac054e782018-04-16 12:10:09 +0200184TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Alex Loikob5c9a792018-04-16 16:31:22 +0200185 std::unique_ptr<AudioProcessing> apm(AudioProcessingBuilder().Create());
186 webrtc::AudioProcessing::Config apm_config;
187 apm_config.pre_amplifier.enabled = true;
188 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
189 apm->ApplyConfig(apm_config);
190
191 AudioFrame frame;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200192 constexpr int16_t kAudioLevel = 10000;
193 constexpr size_t kSampleRateHz = 48000;
194 constexpr size_t kNumChannels = 2;
195 InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
Alex Loikob5c9a792018-04-16 16:31:22 +0200196
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200197 FillFixedFrame(kAudioLevel, &frame);
Alex Loikob5c9a792018-04-16 16:31:22 +0200198 apm->ProcessStream(&frame);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200199 EXPECT_EQ(frame.data()[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200200 << "With factor 1, frame shouldn't be modified.";
201
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200202 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200203 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200204 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200205
206 // Process for two frames to have time to ramp up gain.
207 for (int i = 0; i < 2; ++i) {
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200208 FillFixedFrame(kAudioLevel, &frame);
Alex Loikob5c9a792018-04-16 16:31:22 +0200209 apm->ProcessStream(&frame);
210 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200211 EXPECT_EQ(frame.data()[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200212 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200213}
214
Alessio Bazzicae4498052018-12-17 09:44:06 +0100215TEST(AudioProcessingImplTest,
216 EchoControllerObservesPreAmplifierEchoPathGainChange) {
217 // Tests that the echo controller observes an echo path gain change when the
218 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200219 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100220 const auto* echo_control_factory_ptr = echo_control_factory.get();
221
222 std::unique_ptr<AudioProcessing> apm(
223 AudioProcessingBuilder()
224 .SetEchoControlFactory(std::move(echo_control_factory))
225 .Create());
Sam Zackrisson41478c72019-10-15 10:10:26 +0200226 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100227 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200228 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100229 apm_config.gain_controller2.enabled = false;
230 apm_config.pre_amplifier.enabled = true;
231 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
232 apm->ApplyConfig(apm_config);
233
234 AudioFrame frame;
235 constexpr int16_t kAudioLevel = 10000;
236 constexpr size_t kSampleRateHz = 48000;
237 constexpr size_t kNumChannels = 2;
238 InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
239 FillFixedFrame(kAudioLevel, &frame);
240
241 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
242
Per Åhgren0aefbf02019-08-23 21:29:17 +0200243 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200244 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100245 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200246 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100247 apm->ProcessStream(&frame);
248
Per Åhgren0aefbf02019-08-23 21:29:17 +0200249 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200250 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100251 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200252 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100253 apm->SetRuntimeSetting(
254 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
255 apm->ProcessStream(&frame);
256}
257
258TEST(AudioProcessingImplTest,
259 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
260 // Tests that the echo controller observes an echo path gain change when the
261 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200262 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100263 const auto* echo_control_factory_ptr = echo_control_factory.get();
264
265 std::unique_ptr<AudioProcessing> apm(
266 AudioProcessingBuilder()
267 .SetEchoControlFactory(std::move(echo_control_factory))
268 .Create());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100269 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200270 // Enable AGC1.
271 apm_config.gain_controller1.enabled = true;
272 apm_config.gain_controller1.mode =
273 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100274 apm_config.gain_controller2.enabled = false;
275 apm_config.pre_amplifier.enabled = false;
276 apm->ApplyConfig(apm_config);
277
278 AudioFrame frame;
279 constexpr int16_t kAudioLevel = 1000;
280 constexpr size_t kSampleRateHz = 48000;
281 constexpr size_t kNumChannels = 2;
282 InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
283 FillFixedFrame(kAudioLevel, &frame);
284
285 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
286
Sam Zackrisson41478c72019-10-15 10:10:26 +0200287 const int initial_analog_gain = apm->recommended_stream_analog_level();
Per Åhgren0aefbf02019-08-23 21:29:17 +0200288 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100289 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, false))
290 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100291 apm->ProcessStream(&frame);
292
293 // Force an analog gain change if it did not happen.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200294 if (initial_analog_gain == apm->recommended_stream_analog_level()) {
295 apm->set_stream_analog_level(initial_analog_gain + 1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100296 }
297
Per Åhgren0aefbf02019-08-23 21:29:17 +0200298 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100299 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, true))
300 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100301 apm->ProcessStream(&frame);
302}
303
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200304TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
305 // Tests that the echo controller observes an echo path gain change when a
306 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200307 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200308 const auto* echo_control_factory_ptr = echo_control_factory.get();
309
310 std::unique_ptr<AudioProcessing> apm(
311 AudioProcessingBuilder()
312 .SetEchoControlFactory(std::move(echo_control_factory))
313 .Create());
Sam Zackrisson41478c72019-10-15 10:10:26 +0200314 // Disable AGC.
315 webrtc::AudioProcessing::Config apm_config;
316 apm_config.gain_controller1.enabled = false;
317 apm_config.gain_controller2.enabled = false;
318 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200319
320 AudioFrame frame;
321 constexpr int16_t kAudioLevel = 10000;
322 constexpr size_t kSampleRateHz = 48000;
323 constexpr size_t kNumChannels = 2;
324 InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
325 FillFixedFrame(kAudioLevel, &frame);
326
327 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
328
Per Åhgren0aefbf02019-08-23 21:29:17 +0200329 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200330 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100331 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200332 .Times(1);
333 apm->ProcessStream(&frame);
334
Per Åhgren0aefbf02019-08-23 21:29:17 +0200335 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200336 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100337 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200338 .Times(1);
339 apm->SetRuntimeSetting(
340 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
341 apm->ProcessStream(&frame);
342
Per Åhgren0aefbf02019-08-23 21:29:17 +0200343 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200344 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100345 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200346 .Times(1);
347 apm->SetRuntimeSetting(
348 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
349 apm->ProcessStream(&frame);
350
Per Åhgren0aefbf02019-08-23 21:29:17 +0200351 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200352 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100353 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200354 .Times(1);
355 apm->SetRuntimeSetting(
356 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
357 apm->ProcessStream(&frame);
358}
359
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200360TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
361 // Make sure that signal changes caused by a render pre-processing sub-module
362 // take place before any echo detector analysis.
363 rtc::scoped_refptr<TestEchoDetector> test_echo_detector(
364 new rtc::RefCountedObject<TestEchoDetector>());
365 std::unique_ptr<CustomProcessing> test_render_pre_processor(
366 new TestRenderPreProcessor());
367 // Create APM injecting the test echo detector and render pre-processor.
368 std::unique_ptr<AudioProcessing> apm(
369 AudioProcessingBuilder()
370 .SetEchoDetector(test_echo_detector)
371 .SetRenderPreProcessing(std::move(test_render_pre_processor))
372 .Create());
373 webrtc::AudioProcessing::Config apm_config;
374 apm_config.pre_amplifier.enabled = true;
375 apm_config.residual_echo_detector.enabled = true;
376 apm->ApplyConfig(apm_config);
377
378 constexpr int16_t kAudioLevel = 1000;
379 constexpr int kSampleRateHz = 16000;
380 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100381 // Explicitly initialize APM to ensure no render frames are discarded.
382 const ProcessingConfig processing_config = {{
383 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
384 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
385 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
386 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
387 }};
388 apm->Initialize(processing_config);
389
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200390 AudioFrame frame;
391 InitializeAudioFrame(kSampleRateHz, kNumChannels, &frame);
392
393 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
394 constexpr float kExpectedPreprocessedAudioLevel =
395 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
396 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
397
398 // Analyze a render stream frame.
399 FillFixedFrame(kAudioLevel, &frame);
400 ASSERT_EQ(AudioProcessing::Error::kNoError,
401 apm->ProcessReverseStream(&frame));
402 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
403 // ProcessStream().
404 FillFixedFrame(kAudioLevel, &frame);
405 ASSERT_EQ(AudioProcessing::Error::kNoError, apm->ProcessStream(&frame));
406 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
407 // triggered, the line below checks that the call has occurred. If not, the
408 // APM implementation may have changed and this test might need to be adapted.
409 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
410 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
411 // produced by the render pre-processor.
412 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
413 test_echo_detector->last_render_audio_first_sample());
414}
415
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000416} // namespace webrtc