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