blob: b5635f4b84dea936a6aef2876beaff802ae1eca1 [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 Åhgrence202a02019-09-02 17:01:19 +020034 constexpr size_t kNumChannels = 1;
35 constexpr int kSampleRateHz = 48000;
36 constexpr size_t kNumBands = NumBandsForRate(kSampleRateHz);
Per Åhgren09a718a2017-12-11 22:28:45 +010037 EchoCanceller3Config config;
Per Åhgrenee8ad5f2018-08-10 21:15:48 +020038 config.filter.main.length_blocks = main_filter_length_blocks;
39 config.filter.shadow.length_blocks = shadow_filter_length_blocks;
40
Per Åhgrena33dc012019-09-03 23:59:52 +020041 Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
Danil Chapovalovdb9f7ab2018-06-19 10:50:11 +020042 absl::optional<DelayEstimate> delay_estimate;
Per Åhgrence202a02019-09-02 17:01:19 +020043 std::vector<std::vector<std::vector<float>>> x(
44 kNumBands, std::vector<std::vector<float>>(
45 kNumChannels, std::vector<float>(kBlockSize, 0.f)));
Per Åhgren7bdf0732019-09-25 14:53:30 +020046 std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize, 0.f));
peah522d71b2017-02-23 05:16:26 -080047 std::array<float, kBlockSize> x_old;
Per Åhgren7bdf0732019-09-25 14:53:30 +020048 std::array<SubtractorOutput, 1> output;
Per Åhgrenc59a5762017-12-11 21:34:19 +010049 config.delay.default_delay = 1;
Per Åhgren8ba58612017-12-01 23:01:44 +010050 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgrence202a02019-09-02 17:01:19 +020051 RenderDelayBuffer::Create(config, kSampleRateHz, kNumChannels));
Per Åhgren971de072018-03-14 23:23:47 +010052 RenderSignalAnalyzer render_signal_analyzer(config);
peah522d71b2017-02-23 05:16:26 -080053 Random random_generator(42U);
54 Aec3Fft fft;
peah522d71b2017-02-23 05:16:26 -080055 std::array<float, kFftLengthBy2Plus1> Y2;
56 std::array<float, kFftLengthBy2Plus1> E2_main;
57 std::array<float, kFftLengthBy2Plus1> E2_shadow;
Sam Zackrisson8f736c02019-10-01 12:47:53 +020058 AecState aec_state(config, kNumChannels);
peah522d71b2017-02-23 05:16:26 -080059 x_old.fill(0.f);
60 Y2.fill(0.f);
61 E2_main.fill(0.f);
62 E2_shadow.fill(0.f);
63
64 DelayBuffer<float> delay_buffer(delay_samples);
65 for (int k = 0; k < num_blocks_to_process; ++k) {
Per Åhgrence202a02019-09-02 17:01:19 +020066 RandomizeSampleVector(&random_generator, x[0][0]);
peah522d71b2017-02-23 05:16:26 -080067 if (uncorrelated_inputs) {
Per Åhgren7bdf0732019-09-25 14:53:30 +020068 RandomizeSampleVector(&random_generator, y[0]);
peah522d71b2017-02-23 05:16:26 -080069 } else {
Per Åhgren7bdf0732019-09-25 14:53:30 +020070 delay_buffer.Delay(x[0][0], y[0]);
peah522d71b2017-02-23 05:16:26 -080071 }
Per Åhgren8ba58612017-12-01 23:01:44 +010072 render_delay_buffer->Insert(x);
73 if (k == 0) {
74 render_delay_buffer->Reset();
75 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010076 render_delay_buffer->PrepareCaptureProcessing();
Per Åhgrenc59a5762017-12-11 21:34:19 +010077 render_signal_analyzer.Update(*render_delay_buffer->GetRenderBuffer(),
Per Åhgren5c532d32018-03-22 00:29:25 +010078 aec_state.FilterDelayBlocks());
peah522d71b2017-02-23 05:16:26 -080079
80 // Handle echo path changes.
81 if (std::find(blocks_with_echo_path_changes.begin(),
82 blocks_with_echo_path_changes.end(),
83 k) != blocks_with_echo_path_changes.end()) {
Per Åhgren8ba58612017-12-01 23:01:44 +010084 subtractor.HandleEchoPathChange(EchoPathVariability(
85 true, EchoPathVariability::DelayAdjustment::kNewDetectedDelay,
86 false));
peah522d71b2017-02-23 05:16:26 -080087 }
Per Åhgrenc59a5762017-12-11 21:34:19 +010088 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Per Åhgren7bdf0732019-09-25 14:53:30 +020089 render_signal_analyzer, aec_state, output);
peah522d71b2017-02-23 05:16:26 -080090
Per Åhgren8ba58612017-12-01 23:01:44 +010091 aec_state.HandleEchoPathChange(EchoPathVariability(
92 false, EchoPathVariability::DelayAdjustment::kNone, false));
Per Åhgren3ab308f2018-02-21 08:46:03 +010093 aec_state.Update(delay_estimate, subtractor.FilterFrequencyResponse(),
peah29103572017-07-11 02:54:02 -070094 subtractor.FilterImpulseResponse(),
Per Åhgren0e6d2f52017-12-20 22:19:56 +010095 *render_delay_buffer->GetRenderBuffer(), E2_main, Y2,
Sam Zackrisson8f736c02019-10-01 12:47:53 +020096 output);
peah522d71b2017-02-23 05:16:26 -080097 }
98
Per Åhgren7bdf0732019-09-25 14:53:30 +020099 const float output_power =
100 std::inner_product(output[0].e_main.begin(), output[0].e_main.end(),
101 output[0].e_main.begin(), 0.f);
102 const float y_power =
103 std::inner_product(y[0].begin(), y[0].end(), y[0].begin(), 0.f);
peah522d71b2017-02-23 05:16:26 -0800104 if (y_power == 0.f) {
105 ADD_FAILURE();
106 return -1.0;
107 }
108 return output_power / y_power;
109}
110
Per Åhgren09a718a2017-12-11 22:28:45 +0100111std::string ProduceDebugText(size_t delay, int filter_length_blocks) {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200112 rtc::StringBuilder ss;
Per Åhgren09a718a2017-12-11 22:28:45 +0100113 ss << "Delay: " << delay << ", ";
114 ss << "Length: " << filter_length_blocks;
Jonas Olsson84df1c72018-09-14 16:59:32 +0200115 return ss.Release();
peah522d71b2017-02-23 05:16:26 -0800116}
117
118} // namespace
119
120#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
121
122// Verifies that the check for non data dumper works.
123TEST(Subtractor, NullDataDumper) {
Per Åhgren09a718a2017-12-11 22:28:45 +0100124 EXPECT_DEATH(
Per Åhgrena33dc012019-09-03 23:59:52 +0200125 Subtractor(EchoCanceller3Config(), 1, 1, nullptr, DetectOptimization()),
126 "");
peah522d71b2017-02-23 05:16:26 -0800127}
128
peah522d71b2017-02-23 05:16:26 -0800129// Verifies the check for the capture signal size.
130TEST(Subtractor, WrongCaptureSize) {
131 ApmDataDumper data_dumper(42);
Per Åhgren09a718a2017-12-11 22:28:45 +0100132 EchoCanceller3Config config;
Per Åhgrena33dc012019-09-03 23:59:52 +0200133 Subtractor subtractor(config, 1, 1, &data_dumper, DetectOptimization());
Per Åhgren8ba58612017-12-01 23:01:44 +0100134 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
Per Åhgrence202a02019-09-02 17:01:19 +0200135 RenderDelayBuffer::Create(config, 48000, 1));
Per Åhgren971de072018-03-14 23:23:47 +0100136 RenderSignalAnalyzer render_signal_analyzer(config);
Per Åhgren7bdf0732019-09-25 14:53:30 +0200137 std::vector<std::vector<float>> y(1, std::vector<float>(kBlockSize - 1, 0.f));
138 std::array<SubtractorOutput, 1> output;
peah522d71b2017-02-23 05:16:26 -0800139
Per Åhgren09a718a2017-12-11 22:28:45 +0100140 EXPECT_DEATH(
141 subtractor.Process(*render_delay_buffer->GetRenderBuffer(), y,
Sam Zackrisson8f736c02019-10-01 12:47:53 +0200142 render_signal_analyzer, AecState(config, 1), output),
Per Åhgren09a718a2017-12-11 22:28:45 +0100143 "");
peah522d71b2017-02-23 05:16:26 -0800144}
145
146#endif
147
148// Verifies that the subtractor is able to converge on correlated data.
149TEST(Subtractor, Convergence) {
150 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100151 for (size_t filter_length_blocks : {12, 20, 30}) {
152 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
153 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800154
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200155 float echo_to_nearend_power = RunSubtractorTest(
156 400, delay_samples, filter_length_blocks, filter_length_blocks, false,
157 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100158
159 // Use different criteria to take overmodelling into account.
160 if (filter_length_blocks == 12) {
161 EXPECT_GT(0.1f, echo_to_nearend_power);
162 } else {
163 EXPECT_GT(1.f, echo_to_nearend_power);
164 }
Per Åhgren09a718a2017-12-11 22:28:45 +0100165 }
peah522d71b2017-02-23 05:16:26 -0800166 }
167}
168
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200169// Verifies that the subtractor is able to handle the case when the main filter
170// is longer than the shadow filter.
171TEST(Subtractor, MainFilterLongerThanShadowFilter) {
172 std::vector<int> blocks_with_echo_path_changes;
173 float echo_to_nearend_power =
174 RunSubtractorTest(400, 64, 20, 15, false, blocks_with_echo_path_changes);
175 EXPECT_GT(0.5f, echo_to_nearend_power);
176}
177
178// Verifies that the subtractor is able to handle the case when the shadow
179// filter is longer than the main filter.
180TEST(Subtractor, ShadowFilterLongerThanMainFilter) {
181 std::vector<int> blocks_with_echo_path_changes;
182 float echo_to_nearend_power =
183 RunSubtractorTest(400, 64, 15, 20, false, blocks_with_echo_path_changes);
184 EXPECT_GT(0.5f, echo_to_nearend_power);
185}
186
peah522d71b2017-02-23 05:16:26 -0800187// Verifies that the subtractor does not converge on uncorrelated signals.
188TEST(Subtractor, NonConvergenceOnUncorrelatedSignals) {
189 std::vector<int> blocks_with_echo_path_changes;
Per Åhgren09a718a2017-12-11 22:28:45 +0100190 for (size_t filter_length_blocks : {12, 20, 30}) {
191 for (size_t delay_samples : {0, 64, 150, 200, 301}) {
192 SCOPED_TRACE(ProduceDebugText(delay_samples, filter_length_blocks));
peah522d71b2017-02-23 05:16:26 -0800193
Per Åhgrenee8ad5f2018-08-10 21:15:48 +0200194 float echo_to_nearend_power = RunSubtractorTest(
195 300, delay_samples, filter_length_blocks, filter_length_blocks, true,
196 blocks_with_echo_path_changes);
Per Åhgren019008b2017-12-18 11:38:39 +0100197 EXPECT_NEAR(1.f, echo_to_nearend_power, 0.1);
Per Åhgren09a718a2017-12-11 22:28:45 +0100198 }
peah522d71b2017-02-23 05:16:26 -0800199 }
200}
201
peah522d71b2017-02-23 05:16:26 -0800202} // namespace webrtc