blob: 05faa4fd70ab6138b933d0c2cae471c61a567be4 [file] [log] [blame]
peah522d71b2017-02-23 05:16:26 -08001/*
2 * Copyright (c) 2017 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/aec3/subtractor.h"
peah522d71b2017-02-23 05:16:26 -080012
13#include <algorithm>
Per Åhgrenb441acf2019-10-05 09:07:24 +020014#include <memory>
peah522d71b2017-02-23 05:16:26 -080015#include <numeric>
16#include <string>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/audio_processing/aec3/aec_state.h"
Per Åhgren8ba58612017-12-01 23:01:44 +010019#include "modules/audio_processing/aec3/render_delay_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/audio_processing/test/echo_canceller_test_tools.h"
Per Åhgrenb441acf2019-10-05 09:07:24 +020021#include "modules/audio_processing/utility/cascaded_biquad_filter.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/random.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020023#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020024#include "test/gtest.h"
peah522d71b2017-02-23 05:16:26 -080025
26namespace webrtc {
27namespace {
28
Per Åhgrenb441acf2019-10-05 09:07:24 +020029std::vector<float> RunSubtractorTest(
30 size_t num_render_channels,
31 size_t num_capture_channels,
32 int num_blocks_to_process,
33 int delay_samples,
34 int main_filter_length_blocks,
35 int shadow_filter_length_blocks,
36 bool uncorrelated_inputs,
37 const std::vector<int>& blocks_with_echo_path_changes) {
peah522d71b2017-02-23 05:16:26 -080038 ApmDataDumper data_dumper(42);
Per Åhgrence202a02019-09-02 17:01:19 +020039 constexpr int kSampleRateHz = 48000;
40 constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
Per Åhgren09a718a2017-12-11 22:28:45 +010041 EchoCanceller3Config config;
Per Åhgrenee8ad5f2018-08-10 21:15:48 +020042 config.filter.main.length_blocks = main_filter_length_blocks;
43 config.filter.shadow.length_blocks = shadow_filter_length_blocks;
44
Per Åhgrenb441acf2019-10-05 09:07:24 +020045 Subtractor subtractor(config, num_render_channels, num_capture_channels,
46 &data_dumper, DetectOptimization());
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020047 absl::optional<DelayEstimate> delay_estimate;
Per Åhgrence202a02019-09-02 17:01:19 +020048 std::vector<std::vector<std::vector<float>>> x(
49 kNumBands, std::vector<std::vector<float>>(
Per Åhgrenb441acf2019-10-05 09:07:24 +020050 num_render_channels, std::vector<float>(kBlockSize, 0.f)));
51 std::vector<std::vector<float>> y(num_capture_channels,
52 std::vector<float>(kBlockSize, 0.f));
peah522d71b2017-02-23 05:16:26 -080053 std::array<float, kBlockSize> x_old;
Per Åhgrenb441acf2019-10-05 09:07:24 +020054 std::vector<SubtractorOutput> output(num_capture_channels);
Per Åhgrenc59a5762017-12-11 21:34:19 +010055 config.delay.default_delay = 1;
Per Åhgren8ba58612017-12-01 23:01:44 +010056 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgrenb441acf2019-10-05 09:07:24 +020057 RenderDelayBuffer::Create(config, kSampleRateHz, num_render_channels));
Per Åhgren971de072018-03-14 23:23:47 +010058 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -080059 Random random_generator(42U);
60 Aec3Fft fft;
Per Åhgrenf9807252019-10-09 13:57:07 +020061 std::vector<std::array<float, kFftLengthBy2Plus1>> Y2(num_capture_channels);
62 std::vector<std::array<float, kFftLengthBy2Plus1>> E2_main(
63 num_capture_channels);
peah522d71b2017-02-23 05:16:26 -080064 std::array<float, kFftLengthBy2Plus1> E2_shadow;
Per Åhgrenb441acf2019-10-05 09:07:24 +020065 AecState aec_state(config, num_capture_channels);
peah522d71b2017-02-23 05:16:26 -080066 x_old.fill(0.f);
Per Åhgrenf9807252019-10-09 13:57:07 +020067 for (auto& Y2_ch : Y2) {
68 Y2_ch.fill(0.f);
69 }
70 for (auto& E2_main_ch : E2_main) {
71 E2_main_ch.fill(0.f);
72 }
peah522d71b2017-02-23 05:16:26 -080073 E2_shadow.fill(0.f);
74
Per Åhgrenb441acf2019-10-05 09:07:24 +020075 std::vector<std::vector<std::unique_ptr<DelayBuffer<float>>>> delay_buffer(
76 num_capture_channels);
77 for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) {
78 delay_buffer[capture_ch].resize(num_render_channels);
79 for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
80 delay_buffer[capture_ch][render_ch] =
81 std::make_unique<DelayBuffer<float>>(delay_samples);
peah522d71b2017-02-23 05:16:26 -080082 }
Per Åhgrenb441acf2019-10-05 09:07:24 +020083 }
84
85 // [B,A] = butter(2,100/8000,'high')
86 constexpr CascadedBiQuadFilter::BiQuadCoefficients
87 kHighPassFilterCoefficients = {{0.97261f, -1.94523f, 0.97261f},
88 {-1.94448f, 0.94598f}};
89 std::vector<std::unique_ptr<CascadedBiQuadFilter>> x_hp_filter(
90 num_render_channels);
91 for (size_t ch = 0; ch < num_render_channels; ++ch) {
92 x_hp_filter[ch] =
93 std::make_unique<CascadedBiQuadFilter>(kHighPassFilterCoefficients, 1);
94 }
95 std::vector<std::unique_ptr<CascadedBiQuadFilter>> y_hp_filter(
96 num_capture_channels);
97 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
98 y_hp_filter[ch] =
99 std::make_unique<CascadedBiQuadFilter>(kHighPassFilterCoefficients, 1);
100 }
101
102 for (int k = 0; k < num_blocks_to_process; ++k) {
103 for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
104 RandomizeSampleVector(&random_generator, x[0][render_ch]);
105 }
106 if (uncorrelated_inputs) {
107 for (size_t capture_ch = 0; capture_ch < num_capture_channels;
108 ++capture_ch) {
109 RandomizeSampleVector(&random_generator, y[capture_ch]);
110 }
111 } else {
112 for (size_t capture_ch = 0; capture_ch < num_capture_channels;
113 ++capture_ch) {
114 for (size_t render_ch = 0; render_ch < num_render_channels;
115 ++render_ch) {
116 std::array<float, kBlockSize> y_channel;
117 delay_buffer[capture_ch][render_ch]->Delay(x[0][render_ch],
118 y_channel);
119 for (size_t k = 0; k < y.size(); ++k) {
120 y[capture_ch][k] += y_channel[k] / num_render_channels;
121 }
122 }
123 }
124 }
125 for (size_t ch = 0; ch < num_render_channels; ++ch) {
126 x_hp_filter[ch]->Process(x[0][ch]);
127 }
128 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
129 y_hp_filter[ch]->Process(y[ch]);
130 }
131
Per Åhgren8ba58612017-12-01 23:01:44 +0100132 render_delay_buffer->Insert(x);
133 if (k == 0) {
134 render_delay_buffer->Reset();
135 }
Per Åhgrenc59a5762017-12-11 21:34:19 +0100136 render_delay_buffer->PrepareCaptureProcessing();
Per Åhgrenc59a5762017-12-11 21:34:19 +0100137 render_signal_analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
Per Åhgren5c532d32018-03-22 00:29:25 +0100138 aec_state.FilterDelayBlocks());
peah522d71b2017-02-23 05:16:26 -0800139
140 // Handle echo path changes.
141 if (std::find(blocks_with_echo_path_changes.begin(),
142 blocks_with_echo_path_changes.end(),
143 k) != blocks_with_echo_path_changes.end()) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100144 subtractor.HandleEchoPathChange(EchoPathVariability(
145 true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay,
146 false));
peah522d71b2017-02-23 05:16:26 -0800147 }
Per Åhgrenc59a5762017-12-11 21:34:19 +0100148 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Per Åhgren7bdf0732019-09-25 14:53:30 +0200149 render_signal_analyzer, aec_state, output);
peah522d71b2017-02-23 05:16:26 -0800150
Per Åhgren8ba58612017-12-01 23:01:44 +0100151 aec_state.HandleEchoPathChange(EchoPathVariability(
152 false, EchoPathVariability::DelayAdjustment::kNone, false));
Sam Zackrisson46b01402019-10-08 16:17:48 +0200153 aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
154 subtractor.FilterImpulseResponse(),
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100155 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200156 output);
peah522d71b2017-02-23 05:16:26 -0800157 }
158
Per Åhgrenb441acf2019-10-05 09:07:24 +0200159 std::vector<float> results(num_capture_channels);
160 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
161 const float output_power =
162 std::inner_product(output[ch].e_main.begin(), output[ch].e_main.end(),
163 output[ch].e_main.begin(), 0.f);
164 const float y_power =
165 std::inner_product(y[ch].begin(), y[ch].end(), y[ch].begin(), 0.f);
166 if (y_power == 0.f) {
167 ADD_FAILURE();
168 results[ch] = -1.f;
169 }
170 results[ch] = output_power / y_power;
peah522d71b2017-02-23 05:16:26 -0800171 }
Per Åhgrenb441acf2019-10-05 09:07:24 +0200172 return results;
peah522d71b2017-02-23 05:16:26 -0800173}
174
Per Åhgrenb441acf2019-10-05 09:07:24 +0200175std::string ProduceDebugText(size_t num_render_channels,
176 size_t num_capture_channels,
177 size_t delay,
178 int filter_length_blocks) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200179 rtc::StringBuilder ss;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200180 ss << "delay: " << delay << ", ";
181 ss << "filter_length_blocks:" << filter_length_blocks << ", ";
182 ss << "num_render_channels:" << num_render_channels << ", ";
183 ss << "num_capture_channels:" << num_capture_channels;
Jonas Olsson84df1c72018-09-14 16:59:32 +0200184 return ss.Release();
peah522d71b2017-02-23 05:16:26 -0800185}
186
187} // namespace
188
189#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
190
191// Verifies that the check for non data dumper works.
192TEST(Subtractor, NullDataDumper) {
Per Åhgren09a718a2017-12-11 22:28:45 +0100193 EXPECT_DEATH(
Per Åhgrena33dc012019-09-03 23:59:52 +0200194 Subtractor(EchoCanceller3Config(), 1, 1, nullptr, DetectOptimization()),
195 "");
peah522d71b2017-02-23 05:16:26 -0800196}
197
peah522d71b2017-02-23 05:16:26 -0800198// Verifies the check for the capture signal size.
199TEST(Subtractor, WrongCaptureSize) {
200 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100201 EchoCanceller3Config config;
Per Åhgrena33dc012019-09-03 23:59:52 +0200202 Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100203 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgrence202a02019-09-02 17:01:19 +0200204 RenderDelayBuffer::Create(config, 48000, 1));
Per Åhgren971de072018-03-14 23:23:47 +0100205 RenderSignalAnalyzer render_signal_analyzer(config);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200206 std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize - 1, 0.f));
207 std::array<SubtractorOutput, 1> output;
peah522d71b2017-02-23 05:16:26 -0800208
Per Åhgren09a718a2017-12-11 22:28:45 +0100209 EXPECT_DEATH(
210 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200211 render_signal_analyzer, AecState(config, 1), output),
Per Åhgren09a718a2017-12-11 22:28:45 +0100212 "");
peah522d71b2017-02-23 05:16:26 -0800213}
214
215#endif
216
217// Verifies that the subtractor is able to converge on correlated data.
218TEST(Subtractor, Convergence) {
219 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100220 for (size_t filter_length_blocks : {12, 20, 30}) {
221 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
Per Åhgrenb441acf2019-10-05 09:07:24 +0200222 SCOPED_TRACE(ProduceDebugText(1, 1, delay_samples, filter_length_blocks));
223 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
224 1, 1, 2500, delay_samples, filter_length_blocks, filter_length_blocks,
225 false, blocks_with_echo_path_changes);
peah522d71b2017-02-23 05:16:26 -0800226
Per Åhgrenb441acf2019-10-05 09:07:24 +0200227 for (float echo_to_nearend_power : echo_to_nearend_powers) {
Per Åhgren019008b2017-12-18 11:38:39 +0100228 EXPECT_GT(0.1f, echo_to_nearend_power);
Per Åhgrenb441acf2019-10-05 09:07:24 +0200229 }
230 }
231 }
232}
233
234// Verifies that the subtractor is able to converge on correlated data.
235TEST(Subtractor, ConvergenceMultiChannel) {
236 std::vector<int> blocks_with_echo_path_changes;
237 for (size_t num_render_channels : {1, 2, 4, 8}) {
238 for (size_t num_capture_channels : {1, 2, 4}) {
239 SCOPED_TRACE(
240 ProduceDebugText(num_render_channels, num_render_channels, 64, 20));
241 size_t num_blocks_to_process = 2500 * num_render_channels;
242 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
243 num_render_channels, num_capture_channels, num_blocks_to_process, 64,
244 20, 20, false, blocks_with_echo_path_changes);
245
246 for (float echo_to_nearend_power : echo_to_nearend_powers) {
247 EXPECT_GT(0.1f, echo_to_nearend_power);
Per Åhgren019008b2017-12-18 11:38:39 +0100248 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100249 }
peah522d71b2017-02-23 05:16:26 -0800250 }
251}
252
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200253// Verifies that the subtractor is able to handle the case when the main filter
254// is longer than the shadow filter.
255TEST(Subtractor, MainFilterLongerThanShadowFilter) {
256 std::vector<int> blocks_with_echo_path_changes;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200257 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
258 1, 1, 400, 64, 20, 15, false, blocks_with_echo_path_changes);
259 for (float echo_to_nearend_power : echo_to_nearend_powers) {
260 EXPECT_GT(0.5f, echo_to_nearend_power);
261 }
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200262}
263
264// Verifies that the subtractor is able to handle the case when the shadow
265// filter is longer than the main filter.
266TEST(Subtractor, ShadowFilterLongerThanMainFilter) {
267 std::vector<int> blocks_with_echo_path_changes;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200268 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
269 1, 1, 400, 64, 15, 20, false, blocks_with_echo_path_changes);
270 for (float echo_to_nearend_power : echo_to_nearend_powers) {
271 EXPECT_GT(0.5f, echo_to_nearend_power);
272 }
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200273}
274
peah522d71b2017-02-23 05:16:26 -0800275// Verifies that the subtractor does not converge on uncorrelated signals.
276TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
277 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100278 for (size_t filter_length_blocks : {12, 20, 30}) {
279 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
Per Åhgrenb441acf2019-10-05 09:07:24 +0200280 SCOPED_TRACE(ProduceDebugText(1, 1, delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800281
Per Åhgrenb441acf2019-10-05 09:07:24 +0200282 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
283 1, 1, 3000, delay_samples, filter_length_blocks, filter_length_blocks,
284 true, blocks_with_echo_path_changes);
285 for (float echo_to_nearend_power : echo_to_nearend_powers) {
286 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
287 }
288 }
289 }
290}
291
292// Verifies that the subtractor does not converge on uncorrelated signals.
293TEST(Subtractor, NonConvergenceOnUncorrelatedSignalsMultiChannel) {
294 std::vector<int> blocks_with_echo_path_changes;
295 for (size_t num_render_channels : {1, 2, 4}) {
296 for (size_t num_capture_channels : {1, 2, 4}) {
297 SCOPED_TRACE(
298 ProduceDebugText(num_render_channels, num_render_channels, 64, 20));
299 size_t num_blocks_to_process = 5000 * num_render_channels;
300 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
301 num_render_channels, num_capture_channels, num_blocks_to_process, 64,
302 20, 20, true, blocks_with_echo_path_changes);
303 for (float echo_to_nearend_power : echo_to_nearend_powers) {
304 EXPECT_LT(.8f, echo_to_nearend_power);
305 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.25f);
306 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100307 }
peah522d71b2017-02-23 05:16:26 -0800308 }
309}
310
peah522d71b2017-02-23 05:16:26 -0800311} // namespace webrtc