blob: 3c896ee0ca6ded9f2bb88871494a340ac5c7d16d [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"
21#include "test/gtest.h"
peah522d71b2017-02-23 05:16:26 -080022
23namespace webrtc {
24namespace {
25
26float RunSubtractorTest(int num_blocks_to_process,
27 int delay_samples,
Per Åhgren09a718a2017-12-11 22:28:45 +010028 int filter_length_blocks,
peah522d71b2017-02-23 05:16:26 -080029 bool uncorrelated_inputs,
30 const std::vector<int>& blocks_with_echo_path_changes) {
31 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +010032 EchoCanceller3Config config;
Per Åhgren08ea5892018-01-15 08:07:41 +010033 config.filter.main.length_blocks = config.filter.shadow.length_blocks =
34 filter_length_blocks;
Per Åhgren09a718a2017-12-11 22:28:45 +010035 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020036 absl::optional<DelayEstimate> delay_estimate;
peah86afe9d2017-04-06 15:45:32 -070037 std::vector<std::vector<float>> x(3, std::vector<float>(kBlockSize, 0.f));
peah522d71b2017-02-23 05:16:26 -080038 std::vector<float> y(kBlockSize, 0.f);
39 std::array<float, kBlockSize> x_old;
40 SubtractorOutput output;
Per Åhgren8ba58612017-12-01 23:01:44 +010041 config.delay.min_echo_path_delay_blocks = 0;
Per Åhgrenc59a5762017-12-11 21:34:19 +010042 config.delay.default_delay = 1;
Per Åhgren8ba58612017-12-01 23:01:44 +010043 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
44 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +010045 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -080046 Random random_generator(42U);
47 Aec3Fft fft;
peah522d71b2017-02-23 05:16:26 -080048 std::array<float, kFftLengthBy2Plus1> Y2;
49 std::array<float, kFftLengthBy2Plus1> E2_main;
50 std::array<float, kFftLengthBy2Plus1> E2_shadow;
Per Åhgren09a718a2017-12-11 22:28:45 +010051 AecState aec_state(config);
peah522d71b2017-02-23 05:16:26 -080052 x_old.fill(0.f);
53 Y2.fill(0.f);
54 E2_main.fill(0.f);
55 E2_shadow.fill(0.f);
56
57 DelayBuffer<float> delay_buffer(delay_samples);
58 for (int k = 0; k < num_blocks_to_process; ++k) {
peah86afe9d2017-04-06 15:45:32 -070059 RandomizeSampleVector(&random_generator, x[0]);
peah522d71b2017-02-23 05:16:26 -080060 if (uncorrelated_inputs) {
61 RandomizeSampleVector(&random_generator, y);
62 } else {
peah86afe9d2017-04-06 15:45:32 -070063 delay_buffer.Delay(x[0], y);
peah522d71b2017-02-23 05:16:26 -080064 }
Per Åhgren8ba58612017-12-01 23:01:44 +010065 render_delay_buffer->Insert(x);
66 if (k == 0) {
67 render_delay_buffer->Reset();
68 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010069 render_delay_buffer->PrepareCaptureProcessing();
Per Åhgrenc59a5762017-12-11 21:34:19 +010070 render_signal_analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
Per Åhgren5c532d32018-03-22 00:29:25 +010071 aec_state.FilterDelayBlocks());
peah522d71b2017-02-23 05:16:26 -080072
73 // Handle echo path changes.
74 if (std::find(blocks_with_echo_path_changes.begin(),
75 blocks_with_echo_path_changes.end(),
76 k) != blocks_with_echo_path_changes.end()) {
Per Åhgren8ba58612017-12-01 23:01:44 +010077 subtractor.HandleEchoPathChange(EchoPathVariability(
78 true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay,
79 false));
peah522d71b2017-02-23 05:16:26 -080080 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010081 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Per Åhgren8ba58612017-12-01 23:01:44 +010082 render_signal_analyzer, aec_state, &output);
peah522d71b2017-02-23 05:16:26 -080083
Per Åhgren8ba58612017-12-01 23:01:44 +010084 aec_state.HandleEchoPathChange(EchoPathVariability(
85 false, EchoPathVariability::DelayAdjustment::kNone, false));
Per Åhgren3ab308f2018-02-21 08:46:03 +010086 aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
peah29103572017-07-11 02:54:02 -070087 subtractor.FilterImpulseResponse(),
Per Åhgren5c532d32018-03-22 00:29:25 +010088 subtractor.ConvergedFilter(), subtractor.DivergedFilter(),
Per Åhgren0e6d2f52017-12-20 22:19:56 +010089 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
Per Åhgren5c532d32018-03-22 00:29:25 +010090 output.s_main);
peah522d71b2017-02-23 05:16:26 -080091 }
92
93 const float output_power = std::inner_product(
94 output.e_main.begin(), output.e_main.end(), output.e_main.begin(), 0.f);
95 const float y_power = std::inner_product(y.begin(), y.end(), y.begin(), 0.f);
96 if (y_power == 0.f) {
97 ADD_FAILURE();
98 return -1.0;
99 }
100 return output_power / y_power;
101}
102
Per Åhgren09a718a2017-12-11 22:28:45 +0100103std::string ProduceDebugText(size_t delay, int filter_length_blocks) {
peah522d71b2017-02-23 05:16:26 -0800104 std::ostringstream ss;
Per Åhgren09a718a2017-12-11 22:28:45 +0100105 ss << "Delay: " << delay << ", ";
106 ss << "Length: " << filter_length_blocks;
peah522d71b2017-02-23 05:16:26 -0800107 return ss.str();
108}
109
110} // namespace
111
112#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
113
114// Verifies that the check for non data dumper works.
115TEST(Subtractor, NullDataDumper) {
Per Åhgren09a718a2017-12-11 22:28:45 +0100116 EXPECT_DEATH(
117 Subtractor(EchoCanceller3Config(), nullptr, DetectOptimization()), "");
peah522d71b2017-02-23 05:16:26 -0800118}
119
120// Verifies the check for null subtractor output.
121// TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
122// tests on test bots has been fixed.
123TEST(Subtractor, DISABLED_NullOutput) {
124 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100125 EchoCanceller3Config config;
126 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100127 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgren09a718a2017-12-11 22:28:45 +0100128 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +0100129 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -0800130 std::vector<float> y(kBlockSize, 0.f);
131
Per Åhgren09a718a2017-12-11 22:28:45 +0100132 EXPECT_DEATH(
133 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
134 render_signal_analyzer, AecState(config), nullptr),
135 "");
peah522d71b2017-02-23 05:16:26 -0800136}
137
138// Verifies the check for the capture signal size.
139TEST(Subtractor, WrongCaptureSize) {
140 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100141 EchoCanceller3Config config;
142 Subtractor subtractor(config, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100143 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgren09a718a2017-12-11 22:28:45 +0100144 RenderDelayBuffer::Create(config, 3));
Per Åhgren971de072018-03-14 23:23:47 +0100145 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -0800146 std::vector<float> y(kBlockSize - 1, 0.f);
147 SubtractorOutput output;
148
Per Åhgren09a718a2017-12-11 22:28:45 +0100149 EXPECT_DEATH(
150 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
151 render_signal_analyzer, AecState(config), &output),
152 "");
peah522d71b2017-02-23 05:16:26 -0800153}
154
155#endif
156
157// Verifies that the subtractor is able to converge on correlated data.
158TEST(Subtractor, Convergence) {
159 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100160 for (size_t filter_length_blocks : {12, 20, 30}) {
161 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
162 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800163
Per Åhgren09a718a2017-12-11 22:28:45 +0100164 float echo_to_nearend_power =
Per Åhgren7634c162017-12-18 15:45:49 +0100165 RunSubtractorTest(400, delay_samples, filter_length_blocks, false,
Per Åhgren09a718a2017-12-11 22:28:45 +0100166 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100167
168 // Use different criteria to take overmodelling into account.
169 if (filter_length_blocks == 12) {
170 EXPECT_GT(0.1f, echo_to_nearend_power);
171 } else {
172 EXPECT_GT(1.f, echo_to_nearend_power);
173 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100174 }
peah522d71b2017-02-23 05:16:26 -0800175 }
176}
177
178// Verifies that the subtractor does not converge on uncorrelated signals.
179TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
180 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100181 for (size_t filter_length_blocks : {12, 20, 30}) {
182 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
183 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800184
Per Åhgren09a718a2017-12-11 22:28:45 +0100185 float echo_to_nearend_power =
Per Åhgren019008b2017-12-18 11:38:39 +0100186 RunSubtractorTest(300, delay_samples, filter_length_blocks, true,
Per Åhgren09a718a2017-12-11 22:28:45 +0100187 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100188 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
Per Åhgren09a718a2017-12-11 22:28:45 +0100189 }
peah522d71b2017-02-23 05:16:26 -0800190 }
191}
192
193// Verifies that the subtractor is properly reset when there is an echo path
194// change.
195TEST(Subtractor, EchoPathChangeReset) {
196 std::vector<int> blocks_with_echo_path_changes;
197 blocks_with_echo_path_changes.push_back(99);
Per Åhgren09a718a2017-12-11 22:28:45 +0100198 for (size_t filter_length_blocks : {12, 20, 30}) {
199 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
200 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800201
Per Åhgren09a718a2017-12-11 22:28:45 +0100202 float echo_to_nearend_power =
203 RunSubtractorTest(100, delay_samples, filter_length_blocks, false,
204 blocks_with_echo_path_changes);
205 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.0000001f);
206 }
peah522d71b2017-02-23 05:16:26 -0800207 }
208}
209
210} // namespace webrtc