1 /*
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
11 #include "modules/audio_processing/aec3/echo_path_delay_estimator.h"
12
13 #include <algorithm>
14 #include <sstream>
15 #include <string>
16
17 #include "modules/audio_processing/aec3/aec3_common.h"
18 #include "modules/audio_processing/aec3/render_delay_buffer.h"
19 #include "modules/audio_processing/logging/apm_data_dumper.h"
20 #include "modules/audio_processing/test/echo_canceller_test_tools.h"
21 #include "rtc_base/random.h"
22 #include "test/gtest.h"
23
24 namespace webrtc {
25 namespace {
26
ProduceDebugText(size_t delay)27 std::string ProduceDebugText(size_t delay) {
28 std::ostringstream ss;
29 ss << "Delay: " << delay;
30 return ss.str();
31 }
32
33 } // namespace
34
35 // Verifies that the basic API calls work.
TEST(EchoPathDelayEstimator,BasicApiCalls)36 TEST(EchoPathDelayEstimator, BasicApiCalls) {
37 ApmDataDumper data_dumper(0);
38 EchoCanceller3Config config;
39 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
40 RenderDelayBuffer::Create(
41 3, config.delay.down_sampling_factor,
42 GetDownSampledBufferSize(config.delay.down_sampling_factor,
43 config.delay.num_filters),
44 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
45 config.delay.num_filters)));
46 EchoPathDelayEstimator estimator(&data_dumper, config);
47 std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
48 std::vector<float> capture(kBlockSize);
49 for (size_t k = 0; k < 100; ++k) {
50 render_delay_buffer->Insert(render);
51 estimator.EstimateDelay(render_delay_buffer->GetDownsampledRenderBuffer(),
52 capture);
53 }
54 }
55
56 // Verifies that the delay estimator produces correct delay for artificially
57 // delayed signals.
TEST(EchoPathDelayEstimator,DelayEstimation)58 TEST(EchoPathDelayEstimator, DelayEstimation) {
59 Random random_generator(42U);
60 std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
61 std::vector<float> capture(kBlockSize);
62 ApmDataDumper data_dumper(0);
63 constexpr size_t kDownSamplingFactors[] = {2, 4, 8};
64 for (auto down_sampling_factor : kDownSamplingFactors) {
65 EchoCanceller3Config config;
66 config.delay.down_sampling_factor = down_sampling_factor;
67 config.delay.num_filters = 10;
68 for (size_t delay_samples : {30, 64, 150, 200, 800, 4000}) {
69 SCOPED_TRACE(ProduceDebugText(delay_samples));
70 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
71 RenderDelayBuffer::Create(
72 3, config.delay.down_sampling_factor,
73 GetDownSampledBufferSize(config.delay.down_sampling_factor,
74 config.delay.num_filters),
75 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
76 config.delay.num_filters)));
77 DelayBuffer<float> signal_delay_buffer(delay_samples);
78 EchoPathDelayEstimator estimator(&data_dumper, config);
79
80 rtc::Optional<size_t> estimated_delay_samples;
81 for (size_t k = 0; k < (300 + delay_samples / kBlockSize); ++k) {
82 RandomizeSampleVector(&random_generator, render[0]);
83 signal_delay_buffer.Delay(render[0], capture);
84 render_delay_buffer->Insert(render);
85 render_delay_buffer->UpdateBuffers();
86 estimated_delay_samples = estimator.EstimateDelay(
87 render_delay_buffer->GetDownsampledRenderBuffer(), capture);
88 }
89 if (estimated_delay_samples) {
90 // Due to the internal down-sampling done inside the delay estimator
91 // the estimated delay cannot be expected to be exact to the true delay.
92 EXPECT_NEAR(delay_samples, *estimated_delay_samples,
93 config.delay.down_sampling_factor);
94 } else {
95 ADD_FAILURE();
96 }
97 }
98 }
99 }
100
101 // Verifies that the delay estimator does not produce delay estimates too
102 // quickly.
TEST(EchoPathDelayEstimator,NoInitialDelayestimates)103 TEST(EchoPathDelayEstimator, NoInitialDelayestimates) {
104 Random random_generator(42U);
105 EchoCanceller3Config config;
106 std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
107 std::vector<float> capture(kBlockSize);
108 ApmDataDumper data_dumper(0);
109 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
110 RenderDelayBuffer::Create(
111 3, config.delay.down_sampling_factor,
112 GetDownSampledBufferSize(config.delay.down_sampling_factor,
113 config.delay.num_filters),
114 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
115 config.delay.num_filters)));
116
117 EchoPathDelayEstimator estimator(&data_dumper, config);
118 for (size_t k = 0; k < 19; ++k) {
119 RandomizeSampleVector(&random_generator, render[0]);
120 std::copy(render[0].begin(), render[0].end(), capture.begin());
121 render_delay_buffer->Insert(render);
122 render_delay_buffer->UpdateBuffers();
123 EXPECT_FALSE(estimator.EstimateDelay(
124 render_delay_buffer->GetDownsampledRenderBuffer(), capture));
125 }
126 }
127
128 // Verifies that the delay estimator does not produce delay estimates for render
129 // signals of low level.
TEST(EchoPathDelayEstimator,NoDelayEstimatesForLowLevelRenderSignals)130 TEST(EchoPathDelayEstimator, NoDelayEstimatesForLowLevelRenderSignals) {
131 Random random_generator(42U);
132 EchoCanceller3Config config;
133 std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
134 std::vector<float> capture(kBlockSize);
135 ApmDataDumper data_dumper(0);
136 EchoPathDelayEstimator estimator(&data_dumper, config);
137 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
138 RenderDelayBuffer::Create(
139 3, config.delay.down_sampling_factor,
140 GetDownSampledBufferSize(config.delay.down_sampling_factor,
141 config.delay.num_filters),
142 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
143 config.delay.num_filters)));
144 for (size_t k = 0; k < 100; ++k) {
145 RandomizeSampleVector(&random_generator, render[0]);
146 for (auto& render_k : render[0]) {
147 render_k *= 100.f / 32767.f;
148 }
149 std::copy(render[0].begin(), render[0].end(), capture.begin());
150 render_delay_buffer->Insert(render);
151 render_delay_buffer->UpdateBuffers();
152 EXPECT_FALSE(estimator.EstimateDelay(
153 render_delay_buffer->GetDownsampledRenderBuffer(), capture));
154 }
155 }
156
157 // Verifies that the delay estimator does not produce delay estimates for
158 // uncorrelated signals.
TEST(EchoPathDelayEstimator,NoDelayEstimatesForUncorrelatedSignals)159 TEST(EchoPathDelayEstimator, NoDelayEstimatesForUncorrelatedSignals) {
160 Random random_generator(42U);
161 EchoCanceller3Config config;
162 std::vector<std::vector<float>> render(3, std::vector<float>(kBlockSize));
163 std::vector<float> capture(kBlockSize);
164 ApmDataDumper data_dumper(0);
165 EchoPathDelayEstimator estimator(&data_dumper, config);
166 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
167 RenderDelayBuffer::Create(
168 3, config.delay.down_sampling_factor,
169 GetDownSampledBufferSize(config.delay.down_sampling_factor,
170 config.delay.num_filters),
171 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
172 config.delay.num_filters)));
173 for (size_t k = 0; k < 100; ++k) {
174 RandomizeSampleVector(&random_generator, render[0]);
175 RandomizeSampleVector(&random_generator, capture);
176 render_delay_buffer->Insert(render);
177 render_delay_buffer->UpdateBuffers();
178 EXPECT_FALSE(estimator.EstimateDelay(
179 render_delay_buffer->GetDownsampledRenderBuffer(), capture));
180 }
181 }
182
183 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
184
185 // Verifies the check for the render blocksize.
186 // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
187 // tests on test bots has been fixed.
TEST(EchoPathDelayEstimator,DISABLED_WrongRenderBlockSize)188 TEST(EchoPathDelayEstimator, DISABLED_WrongRenderBlockSize) {
189 ApmDataDumper data_dumper(0);
190 EchoCanceller3Config config;
191 EchoPathDelayEstimator estimator(&data_dumper, config);
192 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
193 RenderDelayBuffer::Create(
194 3, config.delay.down_sampling_factor,
195 GetDownSampledBufferSize(config.delay.down_sampling_factor,
196 config.delay.num_filters),
197 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
198 config.delay.num_filters)));
199 std::vector<float> capture(kBlockSize);
200 EXPECT_DEATH(estimator.EstimateDelay(
201 render_delay_buffer->GetDownsampledRenderBuffer(), capture),
202 "");
203 }
204
205 // Verifies the check for the capture blocksize.
206 // TODO(peah): Re-enable the test once the issue with memory leaks during DEATH
207 // tests on test bots has been fixed.
TEST(EchoPathDelayEstimator,WrongCaptureBlockSize)208 TEST(EchoPathDelayEstimator, WrongCaptureBlockSize) {
209 ApmDataDumper data_dumper(0);
210 EchoCanceller3Config config;
211 EchoPathDelayEstimator estimator(&data_dumper, config);
212 std::unique_ptr<RenderDelayBuffer> render_delay_buffer(
213 RenderDelayBuffer::Create(
214 3, config.delay.down_sampling_factor,
215 GetDownSampledBufferSize(config.delay.down_sampling_factor,
216 config.delay.num_filters),
217 GetRenderDelayBufferSize(config.delay.down_sampling_factor,
218 config.delay.num_filters)));
219 std::vector<float> capture(std::vector<float>(kBlockSize - 1));
220 EXPECT_DEATH(estimator.EstimateDelay(
221 render_delay_buffer->GetDownsampledRenderBuffer(), capture),
222 "");
223 }
224
225 // Verifies the check for non-null data dumper.
TEST(EchoPathDelayEstimator,NullDataDumper)226 TEST(EchoPathDelayEstimator, NullDataDumper) {
227 EXPECT_DEATH(EchoPathDelayEstimator(nullptr, EchoCanceller3Config()), "");
228 }
229
230 #endif
231
232 } // namespace webrtc
233