1 /*
2 * Copyright (c) 2016 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 #include <vector>
11
12 #include "api/array_view.h"
13 #include "modules/audio_processing/audio_buffer.h"
14 #include "modules/audio_processing/echo_cancellation_impl.h"
15 #include "modules/audio_processing/test/audio_buffer_tools.h"
16 #include "modules/audio_processing/test/bitexactness_tools.h"
17 #include "test/gtest.h"
18
19 namespace webrtc {
20 namespace {
21
22 const int kNumFramesToProcess = 100;
23
SetupComponent(int sample_rate_hz,EchoCancellation::SuppressionLevel suppression_level,bool drift_compensation_enabled,EchoCancellationImpl * echo_canceller)24 void SetupComponent(int sample_rate_hz,
25 EchoCancellation::SuppressionLevel suppression_level,
26 bool drift_compensation_enabled,
27 EchoCancellationImpl* echo_canceller) {
28 echo_canceller->Initialize(sample_rate_hz, 1, 1, 1);
29 EchoCancellation* ec = static_cast<EchoCancellation*>(echo_canceller);
30 ec->Enable(true);
31 ec->set_suppression_level(suppression_level);
32 ec->enable_drift_compensation(drift_compensation_enabled);
33
34 Config config;
35 config.Set<DelayAgnostic>(new DelayAgnostic(true));
36 config.Set<ExtendedFilter>(new ExtendedFilter(true));
37 echo_canceller->SetExtraOptions(config);
38 }
39
ProcessOneFrame(int sample_rate_hz,int stream_delay_ms,bool drift_compensation_enabled,int stream_drift_samples,AudioBuffer * render_audio_buffer,AudioBuffer * capture_audio_buffer,EchoCancellationImpl * echo_canceller)40 void ProcessOneFrame(int sample_rate_hz,
41 int stream_delay_ms,
42 bool drift_compensation_enabled,
43 int stream_drift_samples,
44 AudioBuffer* render_audio_buffer,
45 AudioBuffer* capture_audio_buffer,
46 EchoCancellationImpl* echo_canceller) {
47 if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
48 render_audio_buffer->SplitIntoFrequencyBands();
49 capture_audio_buffer->SplitIntoFrequencyBands();
50 }
51
52 std::vector<float> render_audio;
53 EchoCancellationImpl::PackRenderAudioBuffer(
54 render_audio_buffer, 1, render_audio_buffer->num_channels(),
55 &render_audio);
56 echo_canceller->ProcessRenderAudio(render_audio);
57
58 if (drift_compensation_enabled) {
59 static_cast<EchoCancellation*>(echo_canceller)
60 ->set_stream_drift_samples(stream_drift_samples);
61 }
62
63 echo_canceller->ProcessCaptureAudio(capture_audio_buffer, stream_delay_ms);
64
65 if (sample_rate_hz > AudioProcessing::kSampleRate16kHz) {
66 capture_audio_buffer->MergeFrequencyBands();
67 }
68 }
69
RunBitexactnessTest(int sample_rate_hz,size_t num_channels,int stream_delay_ms,bool drift_compensation_enabled,int stream_drift_samples,EchoCancellation::SuppressionLevel suppression_level,bool stream_has_echo_reference,const rtc::ArrayView<const float> & output_reference)70 void RunBitexactnessTest(int sample_rate_hz,
71 size_t num_channels,
72 int stream_delay_ms,
73 bool drift_compensation_enabled,
74 int stream_drift_samples,
75 EchoCancellation::SuppressionLevel suppression_level,
76 bool stream_has_echo_reference,
77 const rtc::ArrayView<const float>& output_reference) {
78 rtc::CriticalSection crit_render;
79 rtc::CriticalSection crit_capture;
80 EchoCancellationImpl echo_canceller(&crit_render, &crit_capture);
81 SetupComponent(sample_rate_hz, suppression_level, drift_compensation_enabled,
82 &echo_canceller);
83
84 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
85 const StreamConfig render_config(sample_rate_hz, num_channels, false);
86 AudioBuffer render_buffer(
87 render_config.num_frames(), render_config.num_channels(),
88 render_config.num_frames(), 1, render_config.num_frames());
89 test::InputAudioFile render_file(
90 test::GetApmRenderTestVectorFileName(sample_rate_hz));
91 std::vector<float> render_input(samples_per_channel * num_channels);
92
93 const StreamConfig capture_config(sample_rate_hz, num_channels, false);
94 AudioBuffer capture_buffer(
95 capture_config.num_frames(), capture_config.num_channels(),
96 capture_config.num_frames(), 1, capture_config.num_frames());
97 test::InputAudioFile capture_file(
98 test::GetApmCaptureTestVectorFileName(sample_rate_hz));
99 std::vector<float> capture_input(samples_per_channel * num_channels);
100
101 for (int frame_no = 0; frame_no < kNumFramesToProcess; ++frame_no) {
102 ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
103 &render_file, render_input);
104 ReadFloatSamplesFromStereoFile(samples_per_channel, num_channels,
105 &capture_file, capture_input);
106
107 test::CopyVectorToAudioBuffer(render_config, render_input, &render_buffer);
108 test::CopyVectorToAudioBuffer(capture_config, capture_input,
109 &capture_buffer);
110
111 ProcessOneFrame(sample_rate_hz, stream_delay_ms, drift_compensation_enabled,
112 stream_drift_samples, &render_buffer, &capture_buffer,
113 &echo_canceller);
114 }
115
116 // Extract and verify the test results.
117 std::vector<float> capture_output;
118 test::ExtractVectorFromAudioBuffer(capture_config, &capture_buffer,
119 &capture_output);
120
121 EXPECT_EQ(stream_has_echo_reference,
122 static_cast<EchoCancellation*>(&echo_canceller)->stream_has_echo());
123
124 // Compare the output with the reference. Only the first values of the output
125 // from last frame processed are compared in order not having to specify all
126 // preceeding frames as testvectors. As the algorithm being tested has a
127 // memory, testing only the last frame implicitly also tests the preceeding
128 // frames.
129 const float kElementErrorBound = 1.0f / 32768.0f;
130 EXPECT_TRUE(test::VerifyDeinterleavedArray(
131 capture_config.num_frames(), capture_config.num_channels(),
132 output_reference, capture_output, kElementErrorBound));
133 }
134
135 const bool kStreamHasEchoReference = true;
136
137 } // namespace
138
139 // TODO(peah): Activate all these tests for ARM and ARM64 once the issue on the
140 // Chromium ARM and ARM64 boths have been identified. This is tracked in the
141 // issue https://bugs.chromium.org/p/webrtc/issues/detail?id=5711.
142
143 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
144 defined(WEBRTC_ANDROID))
TEST(EchoCancellationBitExactnessTest,Mono8kHz_HighLevel_NoDrift_StreamDelay0)145 TEST(EchoCancellationBitExactnessTest,
146 Mono8kHz_HighLevel_NoDrift_StreamDelay0) {
147 #else
148 TEST(EchoCancellationBitExactnessTest,
149 DISABLED_Mono8kHz_HighLevel_NoDrift_StreamDelay0) {
150 #endif
151 const float kOutputReference[] = {-0.000646f, -0.001525f, 0.002688f};
152 RunBitexactnessTest(8000, 1, 0, false, 0,
153 EchoCancellation::SuppressionLevel::kHighSuppression,
154 kStreamHasEchoReference, kOutputReference);
155 }
156
157 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
158 defined(WEBRTC_ANDROID))
159 TEST(EchoCancellationBitExactnessTest,
160 Mono16kHz_HighLevel_NoDrift_StreamDelay0) {
161 #else
162 TEST(EchoCancellationBitExactnessTest,
163 DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay0) {
164 #endif
165 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
166 RunBitexactnessTest(16000, 1, 0, false, 0,
167 EchoCancellation::SuppressionLevel::kHighSuppression,
168 kStreamHasEchoReference, kOutputReference);
169 }
170
171 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
172 defined(WEBRTC_ANDROID))
173 TEST(EchoCancellationBitExactnessTest,
174 Mono32kHz_HighLevel_NoDrift_StreamDelay0) {
175 #else
176 TEST(EchoCancellationBitExactnessTest,
177 DISABLED_Mono32kHz_HighLevel_NoDrift_StreamDelay0) {
178 #endif
179 const float kOutputReference[] = {-0.000671f, 0.000061f, -0.000031f};
180 RunBitexactnessTest(32000, 1, 0, false, 0,
181 EchoCancellation::SuppressionLevel::kHighSuppression,
182 kStreamHasEchoReference, kOutputReference);
183 }
184
185 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
186 defined(WEBRTC_ANDROID))
187 TEST(EchoCancellationBitExactnessTest,
188 Mono48kHz_HighLevel_NoDrift_StreamDelay0) {
189 #else
190 TEST(EchoCancellationBitExactnessTest,
191 DISABLED_Mono48kHz_HighLevel_NoDrift_StreamDelay0) {
192 #endif
193 const float kOutputReference[] = {-0.001403f, -0.001411f, -0.000755f};
194 RunBitexactnessTest(48000, 1, 0, false, 0,
195 EchoCancellation::SuppressionLevel::kHighSuppression,
196 kStreamHasEchoReference, kOutputReference);
197 }
198
199 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
200 defined(WEBRTC_ANDROID))
201 TEST(EchoCancellationBitExactnessTest,
202 Mono16kHz_LowLevel_NoDrift_StreamDelay0) {
203 #else
204 TEST(EchoCancellationBitExactnessTest,
205 DISABLED_Mono16kHz_LowLevel_NoDrift_StreamDelay0) {
206 #endif
207 #if defined(WEBRTC_MAC)
208 const float kOutputReference[] = {-0.000145f, 0.000179f, 0.000917f};
209 #else
210 const float kOutputReference[] = {-0.000009f, 0.000363f, 0.001094f};
211 #endif
212 RunBitexactnessTest(16000, 1, 0, false, 0,
213 EchoCancellation::SuppressionLevel::kLowSuppression,
214 kStreamHasEchoReference, kOutputReference);
215 }
216
217 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
218 defined(WEBRTC_ANDROID))
219 TEST(EchoCancellationBitExactnessTest,
220 Mono16kHz_ModerateLevel_NoDrift_StreamDelay0) {
221 #else
222 TEST(EchoCancellationBitExactnessTest,
223 DISABLED_Mono16kHz_ModerateLevel_NoDrift_StreamDelay0) {
224 #endif
225 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
226 RunBitexactnessTest(16000, 1, 0, false, 0,
227 EchoCancellation::SuppressionLevel::kModerateSuppression,
228 kStreamHasEchoReference, kOutputReference);
229 }
230
231 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
232 defined(WEBRTC_ANDROID))
233 TEST(EchoCancellationBitExactnessTest,
234 Mono16kHz_HighLevel_NoDrift_StreamDelay10) {
235 #else
236 TEST(EchoCancellationBitExactnessTest,
237 DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay10) {
238 #endif
239 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
240 RunBitexactnessTest(16000, 1, 10, false, 0,
241 EchoCancellation::SuppressionLevel::kHighSuppression,
242 kStreamHasEchoReference, kOutputReference);
243 }
244
245 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
246 defined(WEBRTC_ANDROID))
247 TEST(EchoCancellationBitExactnessTest,
248 Mono16kHz_HighLevel_NoDrift_StreamDelay20) {
249 #else
250 TEST(EchoCancellationBitExactnessTest,
251 DISABLED_Mono16kHz_HighLevel_NoDrift_StreamDelay20) {
252 #endif
253 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
254 RunBitexactnessTest(16000, 1, 20, false, 0,
255 EchoCancellation::SuppressionLevel::kHighSuppression,
256 kStreamHasEchoReference, kOutputReference);
257 }
258
259 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
260 defined(WEBRTC_ANDROID))
261 TEST(EchoCancellationBitExactnessTest,
262 Mono16kHz_HighLevel_Drift0_StreamDelay0) {
263 #else
264 TEST(EchoCancellationBitExactnessTest,
265 DISABLED_Mono16kHz_HighLevel_Drift0_StreamDelay0) {
266 #endif
267 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
268 RunBitexactnessTest(16000, 1, 0, true, 0,
269 EchoCancellation::SuppressionLevel::kHighSuppression,
270 kStreamHasEchoReference, kOutputReference);
271 }
272
273 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
274 defined(WEBRTC_ANDROID))
275 TEST(EchoCancellationBitExactnessTest,
276 Mono16kHz_HighLevel_Drift5_StreamDelay0) {
277 #else
278 TEST(EchoCancellationBitExactnessTest,
279 DISABLED_Mono16kHz_HighLevel_Drift5_StreamDelay0) {
280 #endif
281 const float kOutputReference[] = {0.000055f, 0.000421f, 0.001149f};
282 RunBitexactnessTest(16000, 1, 0, true, 5,
283 EchoCancellation::SuppressionLevel::kHighSuppression,
284 kStreamHasEchoReference, kOutputReference);
285 }
286
287 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
288 defined(WEBRTC_ANDROID))
289 TEST(EchoCancellationBitExactnessTest,
290 Stereo8kHz_HighLevel_NoDrift_StreamDelay0) {
291 #else
292 TEST(EchoCancellationBitExactnessTest,
293 DISABLED_Stereo8kHz_HighLevel_NoDrift_StreamDelay0) {
294 #endif
295 #if defined(WEBRTC_MAC)
296 const float kOutputReference[] = {-0.000392f, -0.001449f, 0.003004f,
297 -0.000392f, -0.001449f, 0.003004f};
298 #else
299 const float kOutputReference[] = {-0.000464f, -0.001525f, 0.002933f,
300 -0.000464f, -0.001525f, 0.002933f};
301 #endif
302 RunBitexactnessTest(8000, 2, 0, false, 0,
303 EchoCancellation::SuppressionLevel::kHighSuppression,
304 kStreamHasEchoReference, kOutputReference);
305 }
306
307 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
308 defined(WEBRTC_ANDROID))
309 TEST(EchoCancellationBitExactnessTest,
310 Stereo16kHz_HighLevel_NoDrift_StreamDelay0) {
311 #else
312 TEST(EchoCancellationBitExactnessTest,
313 DISABLED_Stereo16kHz_HighLevel_NoDrift_StreamDelay0) {
314 #endif
315 const float kOutputReference[] = {0.000166f, 0.000735f, 0.000841f,
316 0.000166f, 0.000735f, 0.000841f};
317 RunBitexactnessTest(16000, 2, 0, false, 0,
318 EchoCancellation::SuppressionLevel::kHighSuppression,
319 kStreamHasEchoReference, kOutputReference);
320 }
321
322 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
323 defined(WEBRTC_ANDROID))
324 TEST(EchoCancellationBitExactnessTest,
325 Stereo32kHz_HighLevel_NoDrift_StreamDelay0) {
326 #else
327 TEST(EchoCancellationBitExactnessTest,
328 DISABLED_Stereo32kHz_HighLevel_NoDrift_StreamDelay0) {
329 #endif
330 #if defined(WEBRTC_MAC)
331 const float kOutputReference[] = {-0.000458f, 0.000244f, 0.000153f,
332 -0.000458f, 0.000244f, 0.000153f};
333 #else
334 const float kOutputReference[] = {-0.000427f, 0.000183f, 0.000183f,
335 -0.000427f, 0.000183f, 0.000183f};
336 #endif
337 RunBitexactnessTest(32000, 2, 0, false, 0,
338 EchoCancellation::SuppressionLevel::kHighSuppression,
339 kStreamHasEchoReference, kOutputReference);
340 }
341
342 #if !(defined(WEBRTC_ARCH_ARM64) || defined(WEBRTC_ARCH_ARM) || \
343 defined(WEBRTC_ANDROID))
344 TEST(EchoCancellationBitExactnessTest,
345 Stereo48kHz_HighLevel_NoDrift_StreamDelay0) {
346 #else
347 TEST(EchoCancellationBitExactnessTest,
348 DISABLED_Stereo48kHz_HighLevel_NoDrift_StreamDelay0) {
349 #endif
350 const float kOutputReference[] = {-0.001101f, -0.001101f, -0.000449f,
351 -0.001101f, -0.001101f, -0.000449f};
352 RunBitexactnessTest(48000, 2, 0, false, 0,
353 EchoCancellation::SuppressionLevel::kHighSuppression,
354 kStreamHasEchoReference, kOutputReference);
355 }
356
357 } // namespace webrtc
358