blob: b308d38f95c601d1558b1fb5c487e968aba97682 [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>
14#include <numeric>
15#include <string>
16
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "modules/audio_processing/aec3/aec_state.h"
Per Åhgren8ba58612017-12-01 23:01:44 +010018#include "modules/audio_processing/aec3/render_delay_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "modules/audio_processing/test/echo_canceller_test_tools.h"
20#include "rtc_base/random.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020021#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "test/gtest.h"
peah522d71b2017-02-23 05:16:26 -080023
24namespace webrtc {
25namespace {
26
27float RunSubtractorTest(int num_blocks_to_process,
28 int delay_samples,
Per Åhgrenee8ad5f2018-08-10 21:15:48 +020029 int main_filter_length_blocks,
30 int shadow_filter_length_blocks,
peah522d71b2017-02-23 05:16:26 -080031 bool uncorrelated_inputs,
32 const std::vector<int>& blocks_with_echo_path_changes) {
33 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +010034 EchoCanceller3Config config;
Per Åhgrenee8ad5f2018-08-10 21:15:48 +020035 config.filter.main.length_blocks = main_filter_length_blocks;
36 config.filter.shadow.length_blocks = shadow_filter_length_blocks;
37
Per Åhgren09a718a2017-12-11 22:28:45 +010038 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020039 absl::optional<DelayEstimate> delay_estimate;
peah86afe9d2017-04-06 15:45:32 -070040 std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
peah522d71b2017-02-23 05:16:26 -080041 std::vector<float> y(kBlockSize, 0.f);
42 std::array<float, kBlockSize> x_old;
43 SubtractorOutput output;
Per Åhgren8ba58612017-12-01 23:01:44 +010044 config.delay.min_echo_path_delay_blocks = 0;
Per Åhgrenc59a5762017-12-11 21:34:19 +010045 config.delay.default_delay = 1;
Per Åhgren8ba58612017-12-01 23:01:44 +010046 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
47 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +010048 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -080049 Random random_generator(42U);
50 Aec3Fft fft;
peah522d71b2017-02-23 05:16:26 -080051 std::array<float, kFftLengthBy2Plus1> Y2;
52 std::array<float, kFftLengthBy2Plus1> E2_main;
53 std::array<float, kFftLengthBy2Plus1> E2_shadow;
Per Åhgren09a718a2017-12-11 22:28:45 +010054 AecState aec_state(config);
peah522d71b2017-02-23 05:16:26 -080055 x_old.fill(0.f);
56 Y2.fill(0.f);
57 E2_main.fill(0.f);
58 E2_shadow.fill(0.f);
59
60 DelayBuffer<float> delay_buffer(delay_samples);
61 for (int k = 0; k < num_blocks_to_process; ++k) {
peah86afe9d2017-04-06 15:45:32 -070062 RandomizeSampleVector(&random_generator, x[0]);
peah522d71b2017-02-23 05:16:26 -080063 if (uncorrelated_inputs) {
64 RandomizeSampleVector(&random_generator, y);
65 } else {
peah86afe9d2017-04-06 15:45:32 -070066 delay_buffer.Delay(x[0], y);
peah522d71b2017-02-23 05:16:26 -080067 }
Per Åhgren8ba58612017-12-01 23:01:44 +010068 render_delay_buffer->Insert(x);
69 if (k == 0) {
70 render_delay_buffer->Reset();
71 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010072 render_delay_buffer->PrepareCaptureProcessing();
Per Åhgrenc59a5762017-12-11 21:34:19 +010073 render_signal_analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
Per Åhgren5c532d32018-03-22 00:29:25 +010074 aec_state.FilterDelayBlocks());
peah522d71b2017-02-23 05:16:26 -080075
76 // Handle echo path changes.
77 if (std::find(blocks_with_echo_path_changes.begin(),
78 blocks_with_echo_path_changes.end(),
79 k) != blocks_with_echo_path_changes.end()) {
Per Åhgren8ba58612017-12-01 23:01:44 +010080 subtractor.HandleEchoPathChange(EchoPathVariability(
81 true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay,
82 false));
peah522d71b2017-02-23 05:16:26 -080083 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010084 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Per Åhgren8ba58612017-12-01 23:01:44 +010085 render_signal_analyzer, aec_state, &output);
peah522d71b2017-02-23 05:16:26 -080086
Per Åhgren8ba58612017-12-01 23:01:44 +010087 aec_state.HandleEchoPathChange(EchoPathVariability(
88 false, EchoPathVariability::DelayAdjustment::kNone, false));
Per Åhgren3ab308f2018-02-21 08:46:03 +010089 aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
peah29103572017-07-11 02:54:02 -070090 subtractor.FilterImpulseResponse(),
Per Åhgren0e6d2f52017-12-20 22:19:56 +010091 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
Per Åhgrenb20b9372018-07-13 00:22:54 +020092 output, y);
peah522d71b2017-02-23 05:16:26 -080093 }
94
95 const float output_power = std::inner_product(
96 output.e_main.begin(), output.e_main.end(), output.e_main.begin(), 0.f);
97 const float y_power = std::inner_product(y.begin(), y.end(), y.begin(), 0.f);
98 if (y_power == 0.f) {
99 ADD_FAILURE();
100 return -1.0;
101 }
102 return output_power / y_power;
103}
104
Per Åhgren09a718a2017-12-11 22:28:45 +0100105std::string ProduceDebugText(size_t delay, int filter_length_blocks) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200106 rtc::StringBuilder ss;
Per Åhgren09a718a2017-12-11 22:28:45 +0100107 ss << "Delay: " << delay << ", ";
108 ss << "Length: " << filter_length_blocks;
peah522d71b2017-02-23 05:16:26 -0800109 return ss.str();
110}
111
112} // namespace
113
114#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
115
116// Verifies that the check for non data dumper works.
117TEST(Subtractor, NullDataDumper) {
Per Åhgren09a718a2017-12-11 22:28:45 +0100118 EXPECT_DEATH(
119 Subtractor(EchoCanceller3Config(), nullptr, DetectOptimization()), "");
peah522d71b2017-02-23 05:16:26 -0800120}
121
122// Verifies the check for null subtractor output.
123// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
124// tests on test bots has been fixed.
125TEST(Subtractor, DISABLED_NullOutput) {
126 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100127 EchoCanceller3Config config;
128 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100129 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgren09a718a2017-12-11 22:28:45 +0100130 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +0100131 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -0800132 std::vector<float> y(kBlockSize, 0.f);
133
Per Åhgren09a718a2017-12-11 22:28:45 +0100134 EXPECT_DEATH(
135 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
136 render_signal_analyzer, AecState(config), nullptr),
137 "");
peah522d71b2017-02-23 05:16:26 -0800138}
139
140// Verifies the check for the capture signal size.
141TEST(Subtractor, WrongCaptureSize) {
142 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100143 EchoCanceller3Config config;
144 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100145 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgren09a718a2017-12-11 22:28:45 +0100146 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +0100147 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -0800148 std::vector<float> y(kBlockSize - 1, 0.f);
149 SubtractorOutput output;
150
Per Åhgren09a718a2017-12-11 22:28:45 +0100151 EXPECT_DEATH(
152 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
153 render_signal_analyzer, AecState(config), &output),
154 "");
peah522d71b2017-02-23 05:16:26 -0800155}
156
157#endif
158
159// Verifies that the subtractor is able to converge on correlated data.
160TEST(Subtractor, Convergence) {
161 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100162 for (size_t filter_length_blocks : {12, 20, 30}) {
163 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
164 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800165
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200166 float echo_to_nearend_power = RunSubtractorTest(
167 400, delay_samples, filter_length_blocks, filter_length_blocks, false,
168 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100169
170 // Use different criteria to take overmodelling into account.
171 if (filter_length_blocks == 12) {
172 EXPECT_GT(0.1f, echo_to_nearend_power);
173 } else {
174 EXPECT_GT(1.f, echo_to_nearend_power);
175 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100176 }
peah522d71b2017-02-23 05:16:26 -0800177 }
178}
179
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200180// Verifies that the subtractor is able to handle the case when the main filter
181// is longer than the shadow filter.
182TEST(Subtractor, MainFilterLongerThanShadowFilter) {
183 std::vector<int> blocks_with_echo_path_changes;
184 float echo_to_nearend_power =
185 RunSubtractorTest(400, 64, 20, 15, false, blocks_with_echo_path_changes);
186 EXPECT_GT(0.5f, echo_to_nearend_power);
187}
188
189// Verifies that the subtractor is able to handle the case when the shadow
190// filter is longer than the main filter.
191TEST(Subtractor, ShadowFilterLongerThanMainFilter) {
192 std::vector<int> blocks_with_echo_path_changes;
193 float echo_to_nearend_power =
194 RunSubtractorTest(400, 64, 15, 20, false, blocks_with_echo_path_changes);
195 EXPECT_GT(0.5f, echo_to_nearend_power);
196}
197
peah522d71b2017-02-23 05:16:26 -0800198// Verifies that the subtractor does not converge on uncorrelated signals.
199TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
200 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100201 for (size_t filter_length_blocks : {12, 20, 30}) {
202 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
203 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800204
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200205 float echo_to_nearend_power = RunSubtractorTest(
206 300, delay_samples, filter_length_blocks, filter_length_blocks, true,
207 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100208 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
Per Åhgren09a718a2017-12-11 22:28:45 +0100209 }
peah522d71b2017-02-23 05:16:26 -0800210 }
211}
212
213// Verifies that the subtractor is properly reset when there is an echo path
214// change.
215TEST(Subtractor, EchoPathChangeReset) {
216 std::vector<int> blocks_with_echo_path_changes;
217 blocks_with_echo_path_changes.push_back(99);
Per Åhgren09a718a2017-12-11 22:28:45 +0100218 for (size_t filter_length_blocks : {12, 20, 30}) {
219 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
220 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800221
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200222 float echo_to_nearend_power = RunSubtractorTest(
223 100, delay_samples, filter_length_blocks, filter_length_blocks, false,
224 blocks_with_echo_path_changes);
Per Åhgren09a718a2017-12-11 22:28:45 +0100225 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.0000001f);
226 }
peah522d71b2017-02-23 05:16:26 -0800227 }
228}
229
230} // namespace webrtc