blob: 3c5458d151f2bc4511fa792f3306a6cae3061ef1 [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>
15
Mirko Bonadeid9708072019-01-25 20:26:48 +010016#include "api/scoped_refptr.h"
Alessio Bazzicad2b97402018-08-09 14:23:11 +020017#include "modules/audio_processing/include/audio_processing.h"
Per Åhgrencc73ed32020-04-26 23:56:17 +020018#include "modules/audio_processing/test/audio_processing_builder_for_testing.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010019#include "modules/audio_processing/test/echo_control_mock.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/audio_processing/test/test_utils.h"
Alessio Bazzicae4498052018-12-17 09:44:06 +010021#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080022#include "rtc_base/ref_counted_object.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020023#include "test/gmock.h"
24#include "test/gtest.h"
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000025
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000026namespace webrtc {
peaha9cc40b2017-06-29 08:32:09 -070027namespace {
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000028
Alessio Bazzicae4498052018-12-17 09:44:06 +010029using ::testing::Invoke;
30using ::testing::NotNull;
31
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000032class MockInitialize : public AudioProcessingImpl {
33 public:
peah88ac8532016-09-12 16:47:25 -070034 explicit MockInitialize(const webrtc::Config& config)
35 : AudioProcessingImpl(config) {}
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000036
andrew@webrtc.orge84978f2014-01-25 02:09:06 +000037 MOCK_METHOD0(InitializeLocked, int());
danilchap56359be2017-09-07 07:53:45 -070038 int RealInitializeLocked() RTC_NO_THREAD_SAFETY_ANALYSIS {
pbos@webrtc.org788acd12014-12-15 09:41:24 +000039 return AudioProcessingImpl::InitializeLocked();
40 }
peaha9cc40b2017-06-29 08:32:09 -070041
Niels Möller6f72f562017-10-19 13:15:17 +020042 MOCK_CONST_METHOD0(AddRef, void());
43 MOCK_CONST_METHOD0(Release, rtc::RefCountReleaseStatus());
andrew@webrtc.org60730cf2014-01-07 17:45:09 +000044};
45
Alessio Bazzicae4498052018-12-17 09:44:06 +010046// Creates MockEchoControl instances and provides a raw pointer access to
47// the next created one. The raw pointer is meant to be used with gmock.
48// Returning a pointer of the next created MockEchoControl instance is necessary
49// for the following reasons: (i) gmock expectations must be set before any call
50// occurs, (ii) APM is initialized the first time that
51// AudioProcessingImpl::ProcessStream() is called and the initialization leads
52// to the creation of a new EchoControl object.
53class MockEchoControlFactory : public EchoControlFactory {
54 public:
Mirko Bonadei317a1f02019-09-17 17:06:18 +020055 MockEchoControlFactory() : next_mock_(std::make_unique<MockEchoControl>()) {}
Alessio Bazzicae4498052018-12-17 09:44:06 +010056 // Returns a pointer to the next MockEchoControl that this factory creates.
57 MockEchoControl* GetNext() const { return next_mock_.get(); }
Per Åhgren4e5c7092019-11-01 20:44:11 +010058 std::unique_ptr<EchoControl> Create(int sample_rate_hz,
59 int num_render_channels,
60 int num_capture_channels) override {
Alessio Bazzicae4498052018-12-17 09:44:06 +010061 std::unique_ptr<EchoControl> mock = std::move(next_mock_);
Mirko Bonadei317a1f02019-09-17 17:06:18 +020062 next_mock_ = std::make_unique<MockEchoControl>();
Alessio Bazzicae4498052018-12-17 09:44:06 +010063 return mock;
64 }
65
66 private:
67 std::unique_ptr<MockEchoControl> next_mock_;
68};
69
Alessio Bazzicad2b97402018-08-09 14:23:11 +020070// Mocks EchoDetector and records the first samples of the last analyzed render
71// stream frame. Used to check what data is read by an EchoDetector
72// implementation injected into an APM.
73class TestEchoDetector : public EchoDetector {
74 public:
75 TestEchoDetector()
76 : analyze_render_audio_called_(false),
77 last_render_audio_first_sample_(0.f) {}
78 ~TestEchoDetector() override = default;
79 void AnalyzeRenderAudio(rtc::ArrayView<const float> render_audio) override {
80 last_render_audio_first_sample_ = render_audio[0];
81 analyze_render_audio_called_ = true;
82 }
83 void AnalyzeCaptureAudio(rtc::ArrayView<const float> capture_audio) override {
84 }
85 void Initialize(int capture_sample_rate_hz,
86 int num_capture_channels,
87 int render_sample_rate_hz,
88 int num_render_channels) override {}
89 EchoDetector::Metrics GetMetrics() const override { return {}; }
90 // Returns true if AnalyzeRenderAudio() has been called at least once.
91 bool analyze_render_audio_called() const {
92 return analyze_render_audio_called_;
93 }
94 // Returns the first sample of the last analyzed render frame.
95 float last_render_audio_first_sample() const {
96 return last_render_audio_first_sample_;
97 }
98
99 private:
100 bool analyze_render_audio_called_;
101 float last_render_audio_first_sample_;
102};
103
104// Mocks CustomProcessing and applies ProcessSample() to all the samples.
105// Meant to be injected into an APM to modify samples in a known and detectable
106// way.
107class TestRenderPreProcessor : public CustomProcessing {
108 public:
109 TestRenderPreProcessor() = default;
110 ~TestRenderPreProcessor() = default;
111 void Initialize(int sample_rate_hz, int num_channels) override {}
112 void Process(AudioBuffer* audio) override {
113 for (size_t k = 0; k < audio->num_channels(); ++k) {
Per Åhgrend47941e2019-08-22 11:51:13 +0200114 rtc::ArrayView<float> channel_view(audio->channels()[k],
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200115 audio->num_frames());
116 std::transform(channel_view.begin(), channel_view.end(),
117 channel_view.begin(), ProcessSample);
118 }
Mirko Bonadeic4dd7302019-02-25 09:12:02 +0100119 }
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200120 std::string ToString() const override { return "TestRenderPreProcessor"; }
121 void SetRuntimeSetting(AudioProcessing::RuntimeSetting setting) override {}
122 // Modifies a sample. This member is used in Process() to modify a frame and
123 // it is publicly visible to enable tests.
124 static constexpr float ProcessSample(float x) { return 2.f * x; }
125};
126
peaha9cc40b2017-06-29 08:32:09 -0700127} // namespace
128
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000129TEST(AudioProcessingImplTest, AudioParameterChangeTriggersInit) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100130 webrtc::Config webrtc_config;
131 MockInitialize mock(webrtc_config);
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000132 ON_CALL(mock, InitializeLocked())
133 .WillByDefault(Invoke(&mock, &MockInitialize::RealInitializeLocked));
134
135 EXPECT_CALL(mock, InitializeLocked()).Times(1);
136 mock.Initialize();
137
Per Åhgren2507f8c2020-03-19 12:33:29 +0100138 constexpr size_t kMaxSampleRateHz = 32000;
139 constexpr size_t kMaxNumChannels = 2;
140 std::array<int16_t, kMaxNumChannels * kMaxSampleRateHz / 100> frame;
141 frame.fill(0);
142 StreamConfig config(16000, 1, /*has_keyboard=*/false);
peah2ace3f92016-09-10 04:42:27 -0700143 // Call with the default parameters; there should be an init.
Per Åhgren4bdced52017-06-27 16:00:38 +0200144 EXPECT_CALL(mock, InitializeLocked()).Times(0);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100145 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
Per Åhgren2507f8c2020-03-19 12:33:29 +0100146 EXPECT_NOERR(
147 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000148
149 // New sample rate. (Only impacts ProcessStream).
Per Åhgren2507f8c2020-03-19 12:33:29 +0100150 config = StreamConfig(32000, 1, /*has_keyboard=*/false);
Yves Gerey665174f2018-06-19 15:03:05 +0200151 EXPECT_CALL(mock, InitializeLocked()).Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100152 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000153
154 // New number of channels.
peah2ace3f92016-09-10 04:42:27 -0700155 // TODO(peah): Investigate why this causes 2 inits.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100156 config = StreamConfig(32000, 2, /*has_keyboard=*/false);
Yves Gerey665174f2018-06-19 15:03:05 +0200157 EXPECT_CALL(mock, InitializeLocked()).Times(2);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100158 EXPECT_NOERR(mock.ProcessStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000159 // ProcessStream sets num_channels_ == num_output_channels.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100160 EXPECT_NOERR(
161 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000162
aluebsb0319552016-03-17 20:39:53 -0700163 // A new sample rate passed to ProcessReverseStream should cause an init.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100164 config = StreamConfig(16000, 2, /*has_keyboard=*/false);
Alex Luebs5b830fe2016-03-08 17:52:52 +0100165 EXPECT_CALL(mock, InitializeLocked()).Times(1);
Per Åhgren2507f8c2020-03-19 12:33:29 +0100166 EXPECT_NOERR(
167 mock.ProcessReverseStream(frame.data(), config, config, frame.data()));
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000168}
169
Alessio Bazzicac054e782018-04-16 12:10:09 +0200170TEST(AudioProcessingImplTest, UpdateCapturePreGainRuntimeSetting) {
Per Åhgrencc73ed32020-04-26 23:56:17 +0200171 std::unique_ptr<AudioProcessing> apm(
172 AudioProcessingBuilderForTesting().Create());
Alex Loikob5c9a792018-04-16 16:31:22 +0200173 webrtc::AudioProcessing::Config apm_config;
174 apm_config.pre_amplifier.enabled = true;
175 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
176 apm->ApplyConfig(apm_config);
177
Per Åhgren2507f8c2020-03-19 12:33:29 +0100178 constexpr int kSampleRateHz = 48000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200179 constexpr int16_t kAudioLevel = 10000;
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200180 constexpr size_t kNumChannels = 2;
Alex Loikob5c9a792018-04-16 16:31:22 +0200181
Per Åhgren2507f8c2020-03-19 12:33:29 +0100182 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
183 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
184 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100185 apm->ProcessStream(frame.data(), config, config, frame.data());
Per Åhgren2507f8c2020-03-19 12:33:29 +0100186 EXPECT_EQ(frame[100], kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200187 << "With factor 1, frame shouldn't be modified.";
188
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200189 constexpr float kGainFactor = 2.f;
Alex Loikob5c9a792018-04-16 16:31:22 +0200190 apm->SetRuntimeSetting(
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200191 AudioProcessing::RuntimeSetting::CreateCapturePreGain(kGainFactor));
Alex Loikob5c9a792018-04-16 16:31:22 +0200192
193 // Process for two frames to have time to ramp up gain.
194 for (int i = 0; i < 2; ++i) {
Per Åhgren2507f8c2020-03-19 12:33:29 +0100195 frame.fill(kAudioLevel);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100196 apm->ProcessStream(frame.data(), config, config, frame.data());
Alex Loikob5c9a792018-04-16 16:31:22 +0200197 }
Per Åhgren2507f8c2020-03-19 12:33:29 +0100198 EXPECT_EQ(frame[100], kGainFactor * kAudioLevel)
Alex Loikob5c9a792018-04-16 16:31:22 +0200199 << "Frame should be amplified.";
Alessio Bazzicac054e782018-04-16 12:10:09 +0200200}
201
Alessio Bazzicae4498052018-12-17 09:44:06 +0100202TEST(AudioProcessingImplTest,
203 EchoControllerObservesPreAmplifierEchoPathGainChange) {
204 // Tests that the echo controller observes an echo path gain change when the
205 // pre-amplifier submodule changes the gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200206 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100207 const auto* echo_control_factory_ptr = echo_control_factory.get();
208
209 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +0200210 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100211 .SetEchoControlFactory(std::move(echo_control_factory))
212 .Create());
Sam Zackrisson41478c72019-10-15 10:10:26 +0200213 // Disable AGC.
Alessio Bazzicae4498052018-12-17 09:44:06 +0100214 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200215 apm_config.gain_controller1.enabled = false;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100216 apm_config.gain_controller2.enabled = false;
217 apm_config.pre_amplifier.enabled = true;
218 apm_config.pre_amplifier.fixed_gain_factor = 1.f;
219 apm->ApplyConfig(apm_config);
220
Alessio Bazzicae4498052018-12-17 09:44:06 +0100221 constexpr int16_t kAudioLevel = 10000;
222 constexpr size_t kSampleRateHz = 48000;
223 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100224 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
225 StreamConfig config(kSampleRateHz, kNumChannels, /*has_keyboard=*/false);
226 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100227
228 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
229
Per Åhgren0aefbf02019-08-23 21:29:17 +0200230 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200231 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100232 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200233 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100234 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100235
Per Åhgren0aefbf02019-08-23 21:29:17 +0200236 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200237 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100238 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistbf47f342019-05-09 10:50:31 +0200239 .Times(1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100240 apm->SetRuntimeSetting(
241 AudioProcessing::RuntimeSetting::CreateCapturePreGain(2.f));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100242 apm->ProcessStream(frame.data(), config, config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100243}
244
245TEST(AudioProcessingImplTest,
246 EchoControllerObservesAnalogAgc1EchoPathGainChange) {
247 // Tests that the echo controller observes an echo path gain change when the
248 // AGC1 analog adaptive submodule changes the analog gain.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200249 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Alessio Bazzicae4498052018-12-17 09:44:06 +0100250 const auto* echo_control_factory_ptr = echo_control_factory.get();
251
252 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +0200253 AudioProcessingBuilderForTesting()
Alessio Bazzicae4498052018-12-17 09:44:06 +0100254 .SetEchoControlFactory(std::move(echo_control_factory))
255 .Create());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100256 webrtc::AudioProcessing::Config apm_config;
Sam Zackrisson41478c72019-10-15 10:10:26 +0200257 // Enable AGC1.
258 apm_config.gain_controller1.enabled = true;
259 apm_config.gain_controller1.mode =
260 AudioProcessing::Config::GainController1::kAdaptiveAnalog;
Alessio Bazzicae4498052018-12-17 09:44:06 +0100261 apm_config.gain_controller2.enabled = false;
262 apm_config.pre_amplifier.enabled = false;
263 apm->ApplyConfig(apm_config);
264
Alessio Bazzicae4498052018-12-17 09:44:06 +0100265 constexpr int16_t kAudioLevel = 1000;
266 constexpr size_t kSampleRateHz = 48000;
267 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100268 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
269 StreamConfig stream_config(kSampleRateHz, kNumChannels,
270 /*has_keyboard=*/false);
271 frame.fill(kAudioLevel);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100272
273 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
274
Sam Zackrisson41478c72019-10-15 10:10:26 +0200275 const int initial_analog_gain = apm->recommended_stream_analog_level();
Per Åhgren0aefbf02019-08-23 21:29:17 +0200276 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100277 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, false))
278 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100279 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100280
281 // Force an analog gain change if it did not happen.
Sam Zackrisson41478c72019-10-15 10:10:26 +0200282 if (initial_analog_gain == apm->recommended_stream_analog_level()) {
283 apm->set_stream_analog_level(initial_analog_gain + 1);
Alessio Bazzicae4498052018-12-17 09:44:06 +0100284 }
285
Per Åhgren0aefbf02019-08-23 21:29:17 +0200286 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100287 EXPECT_CALL(*echo_control_mock, ProcessCapture(NotNull(), testing::_, true))
288 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100289 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Alessio Bazzicae4498052018-12-17 09:44:06 +0100290}
291
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200292TEST(AudioProcessingImplTest, EchoControllerObservesPlayoutVolumeChange) {
293 // Tests that the echo controller observes an echo path gain change when a
294 // playout volume change is reported.
Mirko Bonadei317a1f02019-09-17 17:06:18 +0200295 auto echo_control_factory = std::make_unique<MockEchoControlFactory>();
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200296 const auto* echo_control_factory_ptr = echo_control_factory.get();
297
298 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +0200299 AudioProcessingBuilderForTesting()
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200300 .SetEchoControlFactory(std::move(echo_control_factory))
301 .Create());
Sam Zackrisson41478c72019-10-15 10:10:26 +0200302 // Disable AGC.
303 webrtc::AudioProcessing::Config apm_config;
304 apm_config.gain_controller1.enabled = false;
305 apm_config.gain_controller2.enabled = false;
306 apm->ApplyConfig(apm_config);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200307
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200308 constexpr int16_t kAudioLevel = 10000;
309 constexpr size_t kSampleRateHz = 48000;
310 constexpr size_t kNumChannels = 2;
Per Åhgren2507f8c2020-03-19 12:33:29 +0100311 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
312 StreamConfig stream_config(kSampleRateHz, kNumChannels,
313 /*has_keyboard=*/false);
314 frame.fill(kAudioLevel);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200315
316 MockEchoControl* echo_control_mock = echo_control_factory_ptr->GetNext();
317
Per Åhgren0aefbf02019-08-23 21:29:17 +0200318 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200319 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100320 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200321 .Times(1);
Per Åhgrendc5522b2020-03-19 14:55:58 +0100322 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200323
Per Åhgren0aefbf02019-08-23 21:29:17 +0200324 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200325 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100326 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200327 .Times(1);
328 apm->SetRuntimeSetting(
329 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100330 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200331
Per Åhgren0aefbf02019-08-23 21:29:17 +0200332 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200333 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100334 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/false))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200335 .Times(1);
336 apm->SetRuntimeSetting(
337 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(50));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100338 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200339
Per Åhgren0aefbf02019-08-23 21:29:17 +0200340 EXPECT_CALL(*echo_control_mock, AnalyzeCapture(testing::_)).Times(1);
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200341 EXPECT_CALL(*echo_control_mock,
Per Åhgrenc20a19c2019-11-13 11:12:29 +0100342 ProcessCapture(NotNull(), testing::_, /*echo_path_change=*/true))
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200343 .Times(1);
344 apm->SetRuntimeSetting(
345 AudioProcessing::RuntimeSetting::CreatePlayoutVolumeChange(100));
Per Åhgrendc5522b2020-03-19 14:55:58 +0100346 apm->ProcessStream(frame.data(), stream_config, stream_config, frame.data());
Fredrik Hernqvistca362852019-05-10 15:50:02 +0200347}
348
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200349TEST(AudioProcessingImplTest, RenderPreProcessorBeforeEchoDetector) {
350 // Make sure that signal changes caused by a render pre-processing sub-module
351 // take place before any echo detector analysis.
352 rtc::scoped_refptr<TestEchoDetector> test_echo_detector(
353 new rtc::RefCountedObject<TestEchoDetector>());
354 std::unique_ptr<CustomProcessing> test_render_pre_processor(
355 new TestRenderPreProcessor());
356 // Create APM injecting the test echo detector and render pre-processor.
357 std::unique_ptr<AudioProcessing> apm(
Per Åhgrencc73ed32020-04-26 23:56:17 +0200358 AudioProcessingBuilderForTesting()
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200359 .SetEchoDetector(test_echo_detector)
360 .SetRenderPreProcessing(std::move(test_render_pre_processor))
361 .Create());
362 webrtc::AudioProcessing::Config apm_config;
363 apm_config.pre_amplifier.enabled = true;
364 apm_config.residual_echo_detector.enabled = true;
365 apm->ApplyConfig(apm_config);
366
367 constexpr int16_t kAudioLevel = 1000;
368 constexpr int kSampleRateHz = 16000;
369 constexpr size_t kNumChannels = 1;
Sam Zackrisson12e319a2020-01-03 14:54:20 +0100370 // Explicitly initialize APM to ensure no render frames are discarded.
371 const ProcessingConfig processing_config = {{
372 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
373 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
374 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
375 {kSampleRateHz, kNumChannels, /*has_keyboard=*/false},
376 }};
377 apm->Initialize(processing_config);
378
Per Åhgren2507f8c2020-03-19 12:33:29 +0100379 std::array<int16_t, kNumChannels * kSampleRateHz / 100> frame;
380 StreamConfig stream_config(kSampleRateHz, kNumChannels,
381 /*has_keyboard=*/false);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200382
383 constexpr float kAudioLevelFloat = static_cast<float>(kAudioLevel);
384 constexpr float kExpectedPreprocessedAudioLevel =
385 TestRenderPreProcessor::ProcessSample(kAudioLevelFloat);
386 ASSERT_NE(kAudioLevelFloat, kExpectedPreprocessedAudioLevel);
387
388 // Analyze a render stream frame.
Per Åhgren2507f8c2020-03-19 12:33:29 +0100389 frame.fill(kAudioLevel);
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200390 ASSERT_EQ(AudioProcessing::Error::kNoError,
Per Åhgren2507f8c2020-03-19 12:33:29 +0100391 apm->ProcessReverseStream(frame.data(), stream_config,
392 stream_config, frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200393 // Trigger a call to in EchoDetector::AnalyzeRenderAudio() via
394 // ProcessStream().
Per Åhgren2507f8c2020-03-19 12:33:29 +0100395 frame.fill(kAudioLevel);
396 ASSERT_EQ(AudioProcessing::Error::kNoError,
397 apm->ProcessStream(frame.data(), stream_config, stream_config,
Per Åhgrendc5522b2020-03-19 14:55:58 +0100398 frame.data()));
Alessio Bazzicad2b97402018-08-09 14:23:11 +0200399 // Regardless of how the call to in EchoDetector::AnalyzeRenderAudio() is
400 // triggered, the line below checks that the call has occurred. If not, the
401 // APM implementation may have changed and this test might need to be adapted.
402 ASSERT_TRUE(test_echo_detector->analyze_render_audio_called());
403 // Check that the data read in EchoDetector::AnalyzeRenderAudio() is that
404 // produced by the render pre-processor.
405 EXPECT_EQ(kExpectedPreprocessedAudioLevel,
406 test_echo_detector->last_render_audio_first_sample());
407}
408
andrew@webrtc.org60730cf2014-01-07 17:45:09 +0000409} // namespace webrtc