blob: 717b4813484513e98b068102822c14c1f9b6eb2f [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;
peah522d71b2017-02-23 05:16:26 -080061 std::array<float, kFftLengthBy2Plus1> Y2;
62 std::array<float, kFftLengthBy2Plus1> E2_main;
63 std::array<float, kFftLengthBy2Plus1> E2_shadow;
Per Åhgrenb441acf2019-10-05 09:07:24 +020064 AecState aec_state(config, num_capture_channels);
peah522d71b2017-02-23 05:16:26 -080065 x_old.fill(0.f);
66 Y2.fill(0.f);
67 E2_main.fill(0.f);
68 E2_shadow.fill(0.f);
69
Per Åhgrenb441acf2019-10-05 09:07:24 +020070 std::vector<std::vector<std::unique_ptr<DelayBuffer<float>>>> delay_buffer(
71 num_capture_channels);
72 for (size_t capture_ch = 0; capture_ch < num_capture_channels; ++capture_ch) {
73 delay_buffer[capture_ch].resize(num_render_channels);
74 for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
75 delay_buffer[capture_ch][render_ch] =
76 std::make_unique<DelayBuffer<float>>(delay_samples);
peah522d71b2017-02-23 05:16:26 -080077 }
Per Åhgrenb441acf2019-10-05 09:07:24 +020078 }
79
80 // [B,A] = butter(2,100/8000,'high')
81 constexpr CascadedBiQuadFilter::BiQuadCoefficients
82 kHighPassFilterCoefficients = {{0.97261f, -1.94523f, 0.97261f},
83 {-1.94448f, 0.94598f}};
84 std::vector<std::unique_ptr<CascadedBiQuadFilter>> x_hp_filter(
85 num_render_channels);
86 for (size_t ch = 0; ch < num_render_channels; ++ch) {
87 x_hp_filter[ch] =
88 std::make_unique<CascadedBiQuadFilter>(kHighPassFilterCoefficients, 1);
89 }
90 std::vector<std::unique_ptr<CascadedBiQuadFilter>> y_hp_filter(
91 num_capture_channels);
92 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
93 y_hp_filter[ch] =
94 std::make_unique<CascadedBiQuadFilter>(kHighPassFilterCoefficients, 1);
95 }
96
97 for (int k = 0; k < num_blocks_to_process; ++k) {
98 for (size_t render_ch = 0; render_ch < num_render_channels; ++render_ch) {
99 RandomizeSampleVector(&random_generator, x[0][render_ch]);
100 }
101 if (uncorrelated_inputs) {
102 for (size_t capture_ch = 0; capture_ch < num_capture_channels;
103 ++capture_ch) {
104 RandomizeSampleVector(&random_generator, y[capture_ch]);
105 }
106 } else {
107 for (size_t capture_ch = 0; capture_ch < num_capture_channels;
108 ++capture_ch) {
109 for (size_t render_ch = 0; render_ch < num_render_channels;
110 ++render_ch) {
111 std::array<float, kBlockSize> y_channel;
112 delay_buffer[capture_ch][render_ch]->Delay(x[0][render_ch],
113 y_channel);
114 for (size_t k = 0; k < y.size(); ++k) {
115 y[capture_ch][k] += y_channel[k] / num_render_channels;
116 }
117 }
118 }
119 }
120 for (size_t ch = 0; ch < num_render_channels; ++ch) {
121 x_hp_filter[ch]->Process(x[0][ch]);
122 }
123 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
124 y_hp_filter[ch]->Process(y[ch]);
125 }
126
Per Åhgren8ba58612017-12-01 23:01:44 +0100127 render_delay_buffer->Insert(x);
128 if (k == 0) {
129 render_delay_buffer->Reset();
130 }
Per Åhgrenc59a5762017-12-11 21:34:19 +0100131 render_delay_buffer->PrepareCaptureProcessing();
Per Åhgrenc59a5762017-12-11 21:34:19 +0100132 render_signal_analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
Per Åhgren5c532d32018-03-22 00:29:25 +0100133 aec_state.FilterDelayBlocks());
peah522d71b2017-02-23 05:16:26 -0800134
135 // Handle echo path changes.
136 if (std::find(blocks_with_echo_path_changes.begin(),
137 blocks_with_echo_path_changes.end(),
138 k) != blocks_with_echo_path_changes.end()) {
Per Åhgren8ba58612017-12-01 23:01:44 +0100139 subtractor.HandleEchoPathChange(EchoPathVariability(
140 true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay,
141 false));
peah522d71b2017-02-23 05:16:26 -0800142 }
Per Åhgrenc59a5762017-12-11 21:34:19 +0100143 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Per Åhgren7bdf0732019-09-25 14:53:30 +0200144 render_signal_analyzer, aec_state, output);
peah522d71b2017-02-23 05:16:26 -0800145
Per Åhgren8ba58612017-12-01 23:01:44 +0100146 aec_state.HandleEchoPathChange(EchoPathVariability(
147 false, EchoPathVariability::DelayAdjustment::kNone, false));
Sam Zackrisson46b01402019-10-08 16:17:48 +0200148 aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
149 subtractor.FilterImpulseResponse(),
Per Åhgren0e6d2f52017-12-20 22:19:56 +0100150 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200151 output);
peah522d71b2017-02-23 05:16:26 -0800152 }
153
Per Åhgrenb441acf2019-10-05 09:07:24 +0200154 std::vector<float> results(num_capture_channels);
155 for (size_t ch = 0; ch < num_capture_channels; ++ch) {
156 const float output_power =
157 std::inner_product(output[ch].e_main.begin(), output[ch].e_main.end(),
158 output[ch].e_main.begin(), 0.f);
159 const float y_power =
160 std::inner_product(y[ch].begin(), y[ch].end(), y[ch].begin(), 0.f);
161 if (y_power == 0.f) {
162 ADD_FAILURE();
163 results[ch] = -1.f;
164 }
165 results[ch] = output_power / y_power;
peah522d71b2017-02-23 05:16:26 -0800166 }
Per Åhgrenb441acf2019-10-05 09:07:24 +0200167 return results;
peah522d71b2017-02-23 05:16:26 -0800168}
169
Per Åhgrenb441acf2019-10-05 09:07:24 +0200170std::string ProduceDebugText(size_t num_render_channels,
171 size_t num_capture_channels,
172 size_t delay,
173 int filter_length_blocks) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200174 rtc::StringBuilder ss;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200175 ss << "delay: " << delay << ", ";
176 ss << "filter_length_blocks:" << filter_length_blocks << ", ";
177 ss << "num_render_channels:" << num_render_channels << ", ";
178 ss << "num_capture_channels:" << num_capture_channels;
Jonas Olsson84df1c72018-09-14 16:59:32 +0200179 return ss.Release();
peah522d71b2017-02-23 05:16:26 -0800180}
181
182} // namespace
183
184#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
185
186// Verifies that the check for non data dumper works.
187TEST(Subtractor, NullDataDumper) {
Per Åhgren09a718a2017-12-11 22:28:45 +0100188 EXPECT_DEATH(
Per Åhgrena33dc012019-09-03 23:59:52 +0200189 Subtractor(EchoCanceller3Config(), 1, 1, nullptr, DetectOptimization()),
190 "");
peah522d71b2017-02-23 05:16:26 -0800191}
192
peah522d71b2017-02-23 05:16:26 -0800193// Verifies the check for the capture signal size.
194TEST(Subtractor, WrongCaptureSize) {
195 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100196 EchoCanceller3Config config;
Per Åhgrena33dc012019-09-03 23:59:52 +0200197 Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100198 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgrence202a02019-09-02 17:01:19 +0200199 RenderDelayBuffer::Create(config, 48000, 1));
Per Åhgren971de072018-03-14 23:23:47 +0100200 RenderSignalAnalyzer render_signal_analyzer(config);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200201 std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize - 1, 0.f));
202 std::array<SubtractorOutput, 1> output;
peah522d71b2017-02-23 05:16:26 -0800203
Per Åhgren09a718a2017-12-11 22:28:45 +0100204 EXPECT_DEATH(
205 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200206 render_signal_analyzer, AecState(config, 1), output),
Per Åhgren09a718a2017-12-11 22:28:45 +0100207 "");
peah522d71b2017-02-23 05:16:26 -0800208}
209
210#endif
211
212// Verifies that the subtractor is able to converge on correlated data.
213TEST(Subtractor, Convergence) {
214 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100215 for (size_t filter_length_blocks : {12, 20, 30}) {
216 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
Per Åhgrenb441acf2019-10-05 09:07:24 +0200217 SCOPED_TRACE(ProduceDebugText(1, 1, delay_samples, filter_length_blocks));
218 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
219 1, 1, 2500, delay_samples, filter_length_blocks, filter_length_blocks,
220 false, blocks_with_echo_path_changes);
peah522d71b2017-02-23 05:16:26 -0800221
Per Åhgrenb441acf2019-10-05 09:07:24 +0200222 for (float echo_to_nearend_power : echo_to_nearend_powers) {
Per Åhgren019008b2017-12-18 11:38:39 +0100223 EXPECT_GT(0.1f, echo_to_nearend_power);
Per Åhgrenb441acf2019-10-05 09:07:24 +0200224 }
225 }
226 }
227}
228
229// Verifies that the subtractor is able to converge on correlated data.
230TEST(Subtractor, ConvergenceMultiChannel) {
231 std::vector<int> blocks_with_echo_path_changes;
232 for (size_t num_render_channels : {1, 2, 4, 8}) {
233 for (size_t num_capture_channels : {1, 2, 4}) {
234 SCOPED_TRACE(
235 ProduceDebugText(num_render_channels, num_render_channels, 64, 20));
236 size_t num_blocks_to_process = 2500 * num_render_channels;
237 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
238 num_render_channels, num_capture_channels, num_blocks_to_process, 64,
239 20, 20, false, blocks_with_echo_path_changes);
240
241 for (float echo_to_nearend_power : echo_to_nearend_powers) {
242 EXPECT_GT(0.1f, echo_to_nearend_power);
Per Åhgren019008b2017-12-18 11:38:39 +0100243 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100244 }
peah522d71b2017-02-23 05:16:26 -0800245 }
246}
247
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200248// Verifies that the subtractor is able to handle the case when the main filter
249// is longer than the shadow filter.
250TEST(Subtractor, MainFilterLongerThanShadowFilter) {
251 std::vector<int> blocks_with_echo_path_changes;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200252 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
253 1, 1, 400, 64, 20, 15, false, blocks_with_echo_path_changes);
254 for (float echo_to_nearend_power : echo_to_nearend_powers) {
255 EXPECT_GT(0.5f, echo_to_nearend_power);
256 }
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200257}
258
259// Verifies that the subtractor is able to handle the case when the shadow
260// filter is longer than the main filter.
261TEST(Subtractor, ShadowFilterLongerThanMainFilter) {
262 std::vector<int> blocks_with_echo_path_changes;
Per Åhgrenb441acf2019-10-05 09:07:24 +0200263 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
264 1, 1, 400, 64, 15, 20, false, blocks_with_echo_path_changes);
265 for (float echo_to_nearend_power : echo_to_nearend_powers) {
266 EXPECT_GT(0.5f, echo_to_nearend_power);
267 }
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200268}
269
peah522d71b2017-02-23 05:16:26 -0800270// Verifies that the subtractor does not converge on uncorrelated signals.
271TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
272 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100273 for (size_t filter_length_blocks : {12, 20, 30}) {
274 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
Per Åhgrenb441acf2019-10-05 09:07:24 +0200275 SCOPED_TRACE(ProduceDebugText(1, 1, delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800276
Per Åhgrenb441acf2019-10-05 09:07:24 +0200277 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
278 1, 1, 3000, delay_samples, filter_length_blocks, filter_length_blocks,
279 true, blocks_with_echo_path_changes);
280 for (float echo_to_nearend_power : echo_to_nearend_powers) {
281 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
282 }
283 }
284 }
285}
286
287// Verifies that the subtractor does not converge on uncorrelated signals.
288TEST(Subtractor, NonConvergenceOnUncorrelatedSignalsMultiChannel) {
289 std::vector<int> blocks_with_echo_path_changes;
290 for (size_t num_render_channels : {1, 2, 4}) {
291 for (size_t num_capture_channels : {1, 2, 4}) {
292 SCOPED_TRACE(
293 ProduceDebugText(num_render_channels, num_render_channels, 64, 20));
294 size_t num_blocks_to_process = 5000 * num_render_channels;
295 std::vector<float> echo_to_nearend_powers = RunSubtractorTest(
296 num_render_channels, num_capture_channels, num_blocks_to_process, 64,
297 20, 20, true, blocks_with_echo_path_changes);
298 for (float echo_to_nearend_power : echo_to_nearend_powers) {
299 EXPECT_LT(.8f, echo_to_nearend_power);
300 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.25f);
301 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100302 }
peah522d71b2017-02-23 05:16:26 -0800303 }
304}
305
peah522d71b2017-02-23 05:16:26 -0800306} // namespace webrtc