Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: webrtc/modules/audio_processing/aec3/echo_canceller3_unittest.cc

Issue 2584493002: Added first layer of the echo canceller 3 functionality (Closed)
Patch Set: Changes in response to reviewer comments Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
11 #include <deque>
12 #include <vector>
13
14 #include "webrtc/modules/audio_processing/aec3/aec3_constants.h"
15 #include "webrtc/modules/audio_processing/aec3/block_framer.h"
16 #include "webrtc/modules/audio_processing/aec3/block_processor.h"
17 #include "webrtc/modules/audio_processing/aec3/echo_canceller3.h"
18 #include "webrtc/modules/audio_processing/aec3/frame_blocker.h"
19 #include "webrtc/modules/audio_processing/audio_buffer.h"
20 #include "webrtc/test/gtest.h"
21
22 namespace webrtc {
23 namespace {
24 void PopulateInputFrame(size_t frame_length,
hlundin-webrtc 2016/12/20 15:10:35 Please, comment on how the frame is filled. What v
peah-webrtc 2016/12/21 23:13:53 Done.
25 size_t num_bands,
26 size_t frame_index,
27 float* const* frame,
28 int offset) {
29 for (size_t k = 0; k < num_bands; ++k) {
30 for (size_t i = 0; i < frame_length; ++i) {
31 float value = static_cast<int>(frame_index * frame_length + i) + offset;
32 frame[k][i] = (value > 0 ? 5000 * k + value : 0);
33 }
34 }
35 }
36
37 bool VerifyInputFrame(size_t frame_length,
38 size_t num_bands,
39 size_t frame_index,
40 float* const* frame,
hlundin-webrtc 2016/12/20 15:10:35 More const.
peah-webrtc 2016/12/21 23:13:51 Done.
41 int offset) {
42 float reference_frame_data[num_bands][frame_length];
43 float* reference_frame[num_bands];
44 for (size_t k = 0; k < num_bands; ++k) {
45 reference_frame[k] = &reference_frame_data[k][0];
46 }
47
48 PopulateInputFrame(frame_length, num_bands, frame_index, reference_frame,
49 offset);
50 for (size_t k = 0; k < num_bands; ++k) {
51 for (size_t i = 0; i < frame_length; ++i) {
52 if (reference_frame[k][i] != frame[k][i]) {
53 return false;
54 }
55 }
56 }
57
58 return true;
59 }
60
61 void FillSubFrameView(
62 const float* const* frame,
63 size_t sub_frame_index,
64 rtc::ArrayView<rtc::ArrayView<const float>> sub_frame_view) {
65 for (size_t k = 0; k < sub_frame_view.size(); ++k) {
66 sub_frame_view[k] = rtc::ArrayView<const float>(
67 &frame[k][sub_frame_index * kSubFrameLength], kSubFrameLength);
68 }
69 }
70
71 void FillSubFrameView(float* const* frame,
72 size_t sub_frame_index,
73 rtc::ArrayView<rtc::ArrayView<float>> sub_frame_view) {
74 for (size_t k = 0; k < sub_frame_view.size(); ++k) {
75 sub_frame_view[k] = rtc::ArrayView<float>(
76 &frame[k][sub_frame_index * kSubFrameLength], kSubFrameLength);
77 }
78 }
79
80 // Class for testing that echo leakage is properly reported to the
hlundin-webrtc 2016/12/20 15:10:35 This is not used for the next 400 lines. Define th
peah-webrtc 2016/12/21 23:13:52 Done.
81 // BlockProcessor.
82 class BlockProcessorEchoLeakageReport : public BlockProcessor {
83 public:
84 explicit BlockProcessorEchoLeakageReport(size_t num_bands);
85 ~BlockProcessorEchoLeakageReport() override;
86
87 void ProcessCapture(bool known_echo_path_change,
88 bool saturated_microphone_signal,
89 std::vector<std::vector<float>>* capture_block) override;
90
91 bool BufferRender(std::vector<std::vector<float>>* block) override;
92
93 void ReportEchoLeakage(bool leakage_detected) override;
94
95 private:
96 float echo_leakage_indicator_ = 0.f;
97 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorEchoLeakageReport);
98 };
99
100 BlockProcessorEchoLeakageReport::BlockProcessorEchoLeakageReport(
hlundin-webrtc 2016/12/20 15:10:36 Merge definitions into the class declaration above
peah-webrtc 2016/12/21 23:13:52 Done.
101 size_t num_bands) {}
102
103 BlockProcessorEchoLeakageReport::~BlockProcessorEchoLeakageReport() = default;
104
105 void BlockProcessorEchoLeakageReport::ProcessCapture(
106 bool known_echo_path_change,
107 bool saturated_microphone_signal,
108 std::vector<std::vector<float>>* capture_block) {
109 for (auto& c : (*capture_block)[0]) {
110 c = echo_leakage_indicator_;
111 }
112 }
113
114 bool BlockProcessorEchoLeakageReport::BufferRender(
115 std::vector<std::vector<float>>* block) {
116 return false;
117 }
118
119 void BlockProcessorEchoLeakageReport::ReportEchoLeakage(bool leakage_detected) {
120 echo_leakage_indicator_ = leakage_detected ? 1.f : 0.f;
121 }
122
123 // Class for testing that echo leakage is properly reported to the
hlundin-webrtc 2016/12/20 15:10:35 Copy-paste failure with the comment.
peah-webrtc 2016/12/21 23:13:52 Done.
124 // BlockProcessor.
125 class BlockProcessorCaptureSaturationReport : public BlockProcessor {
126 public:
127 explicit BlockProcessorCaptureSaturationReport(size_t num_bands);
128 ~BlockProcessorCaptureSaturationReport() override;
129
130 void ProcessCapture(bool known_echo_path_change,
131 bool saturated_microphone_signal,
132 std::vector<std::vector<float>>* capture_block) override;
133
134 bool BufferRender(std::vector<std::vector<float>>* block) override;
135
136 void ReportEchoLeakage(bool leakage_detected) override;
137
138 private:
139 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorCaptureSaturationReport);
140 };
141
142 BlockProcessorCaptureSaturationReport::BlockProcessorCaptureSaturationReport(
143 size_t num_bands) {}
144
145 BlockProcessorCaptureSaturationReport::
146 ~BlockProcessorCaptureSaturationReport() = default;
147
148 void BlockProcessorCaptureSaturationReport::ProcessCapture(
149 bool known_echo_path_change,
150 bool saturated_microphone_signal,
151 std::vector<std::vector<float>>* capture_block) {
152 for (auto& c : (*capture_block)[0]) {
153 c = saturated_microphone_signal ? 1 : 0;
aleloi 2016/12/21 10:07:45 Nit: 1.f, 0.f for consistency.
peah-webrtc 2016/12/21 23:13:52 Done.
154 }
155 }
156
157 bool BlockProcessorCaptureSaturationReport::BufferRender(
158 std::vector<std::vector<float>>* block) {
159 return false;
160 }
161
162 void BlockProcessorCaptureSaturationReport::ReportEchoLeakage(
163 bool leakage_detected) {}
164
165 // Class for testing that a known echo path change is properly reported to the
166 // BlockProcessor.
167 class BlockProcessorKnownEchoPathChangeReport : public BlockProcessor {
168 public:
169 explicit BlockProcessorKnownEchoPathChangeReport(size_t num_bands);
170 ~BlockProcessorKnownEchoPathChangeReport() override;
171
172 void ProcessCapture(bool known_echo_path_change,
173 bool saturated_microphone_signal,
174 std::vector<std::vector<float>>* capture_block) override;
175
176 bool BufferRender(std::vector<std::vector<float>>* block) override;
177
178 void ReportEchoLeakage(bool leakage_detected) override;
179
180 private:
181 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorKnownEchoPathChangeReport);
182 };
183
184 BlockProcessorKnownEchoPathChangeReport::
185 BlockProcessorKnownEchoPathChangeReport(size_t num_bands) {}
186
187 BlockProcessorKnownEchoPathChangeReport::
188 ~BlockProcessorKnownEchoPathChangeReport() = default;
189
190 void BlockProcessorKnownEchoPathChangeReport::ProcessCapture(
191 bool known_echo_path_change,
192 bool saturated_microphone_signal,
193 std::vector<std::vector<float>>* capture_block) {
194 for (auto& c : (*capture_block)[0]) {
195 c = known_echo_path_change ? 1 : 0;
aleloi 2016/12/21 10:07:45 nit: 1.f, 0.f
peah-webrtc 2016/12/21 23:13:52 Done.
196 }
197 }
198
199 bool BlockProcessorKnownEchoPathChangeReport::BufferRender(
200 std::vector<std::vector<float>>* block) {
201 return false;
202 }
203
204 void BlockProcessorKnownEchoPathChangeReport::ReportEchoLeakage(
205 bool leakage_detected) {}
206
207 // Class for testing that the render data is properly received by the block
208 // processor.
209 class BlockProcessorRenderRedirect : public BlockProcessor {
hlundin-webrtc 2016/12/20 15:10:35 Move closer to where it is used.
peah-webrtc 2016/12/21 23:13:52 Done.
210 public:
211 explicit BlockProcessorRenderRedirect(size_t num_bands);
212 ~BlockProcessorRenderRedirect() override;
213
214 void ProcessCapture(bool known_echo_path_change,
215 bool saturated_microphone_signal,
216 std::vector<std::vector<float>>* capture_block) override;
217
218 bool BufferRender(std::vector<std::vector<float>>* block) override;
219
220 void ReportEchoLeakage(bool leakage_detected) override;
221
222 private:
223 std::deque<std::vector<std::vector<float>>> received_render_blocks_;
224 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorRenderRedirect);
225 };
226
227 BlockProcessorRenderRedirect::BlockProcessorRenderRedirect(size_t num_bands) {}
hlundin-webrtc 2016/12/20 15:10:35 Merge definitions into class declaration.
peah-webrtc 2016/12/21 23:13:52 Done.
228
229 BlockProcessorRenderRedirect::~BlockProcessorRenderRedirect() = default;
230
231 void BlockProcessorRenderRedirect::ProcessCapture(
232 bool known_echo_path_change,
233 bool saturated_microphone_signal,
234 std::vector<std::vector<float>>* capture_block) {
235 std::vector<std::vector<float>> render_block =
236 received_render_blocks_.front();
237 received_render_blocks_.pop_front();
238 capture_block->swap(render_block);
239 }
240
241 bool BlockProcessorRenderRedirect::BufferRender(
242 std::vector<std::vector<float>>* block) {
243 received_render_blocks_.push_back(*block);
244 return false;
245 }
246
247 void BlockProcessorRenderRedirect::ReportEchoLeakage(bool leakage_detected) {}
248
249 // Class for testing that the capture data is properly received by the block
250 // processor.
251 class BlockProcessorTransparentCapture : public BlockProcessor {
ivoc 2016/12/21 14:52:13 Is it me or does this class do nothing? Why is it
peah-webrtc 2016/12/21 23:13:52 It is needed to ensure that the capture signal is
ivoc 2016/12/22 13:38:13 Acknowledged.
peah-webrtc 2017/01/02 08:45:10 Acknowledged.
252 public:
253 explicit BlockProcessorTransparentCapture(size_t num_bands);
254 ~BlockProcessorTransparentCapture() override;
255
256 void ProcessCapture(bool known_echo_path_change,
257 bool saturated_microphone_signal,
258 std::vector<std::vector<float>>* capture_block) override;
259
260 bool BufferRender(std::vector<std::vector<float>>* block) override;
261
262 void ReportEchoLeakage(bool leakage_detected) override;
263
264 private:
265 RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BlockProcessorTransparentCapture);
266 };
267
268 BlockProcessorTransparentCapture::BlockProcessorTransparentCapture(
hlundin-webrtc 2016/12/20 15:10:35 Merge definitions into class declaration.
peah-webrtc 2016/12/21 23:13:52 Done.
269 size_t num_bands) {}
270
271 BlockProcessorTransparentCapture::~BlockProcessorTransparentCapture() = default;
272
273 void BlockProcessorTransparentCapture::ProcessCapture(
274 bool known_echo_path_change,
275 bool saturated_microphone_signal,
276 std::vector<std::vector<float>>* capture_block) {}
277
278 bool BlockProcessorTransparentCapture::BufferRender(
279 std::vector<std::vector<float>>* block) {
280 return false;
281 }
282
283 void BlockProcessorTransparentCapture::ReportEchoLeakage(
284 bool leakage_detected) {}
285
286 void RunCapturePipelineVerificationTest(int sample_rate_hz) {
hlundin-webrtc 2016/12/20 15:10:35 Write a comment about what the test actually tests
peah-webrtc 2016/12/21 23:13:53 Done.
287 const size_t num_bands = NumBandsForRate(sample_rate_hz);
hlundin-webrtc 2016/12/20 15:10:35 You are duplicating these 10-20 lines an awful lot
peah-webrtc 2016/12/21 23:13:52 I made a tester class that unifies the common part
hlundin-webrtc 2016/12/22 10:23:56 OK. That's _almost_ a test fixture then... :)
peah-webrtc 2017/01/02 08:45:10 :-) Yes, but more explicit.
288 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
289 float input_frame_data[num_bands][frame_length];
290 float* input_frame[num_bands];
291 float output_frame_data[num_bands][frame_length];
292 float* output_frame[num_bands];
293 for (size_t k = 0; k < num_bands; ++k) {
294 input_frame[k] = &input_frame_data[k][0];
295 output_frame[k] = &output_frame_data[k][0];
296 }
297
298 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
299 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
300 samples_per_channel);
301 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
302 samples_per_channel);
303
304 EchoCanceller3 aec3(sample_rate_hz, false,
305 new BlockProcessorTransparentCapture(num_bands));
306
307 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
308 aec3.AnalyzeCapture(&capture_buffer);
309 if (sample_rate_hz > 16000) {
310 capture_buffer.SplitIntoFrequencyBands();
311 render_buffer.SplitIntoFrequencyBands();
312 }
313
314 PopulateInputFrame(frame_length, num_bands, frame_index,
315 &capture_buffer.split_bands_f(0)[0], 0);
316 PopulateInputFrame(frame_length, num_bands, frame_index,
317 &render_buffer.split_bands_f(0)[0], 100);
318
319 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
320 aec3.ProcessCapture(&capture_buffer, false);
321 EXPECT_TRUE(VerifyInputFrame(frame_length, num_bands, frame_index,
322 &capture_buffer.split_bands_f(0)[0], -64));
323 }
324 }
325
326 void RunRenderPipelineVerificationTest(int sample_rate_hz) {
327 const size_t num_bands = NumBandsForRate(sample_rate_hz);
328 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
329 float input_frame_data[num_bands][frame_length];
330 float* input_frame[num_bands];
331 float output_frame_data[num_bands][frame_length];
332 float* output_frame[num_bands];
333 for (size_t k = 0; k < num_bands; ++k) {
334 input_frame[k] = &input_frame_data[k][0];
335 output_frame[k] = &output_frame_data[k][0];
336 }
337
338 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
339 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
340 samples_per_channel);
341 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
342 samples_per_channel);
343
344 EchoCanceller3 aec3(sample_rate_hz, false,
345 new BlockProcessorRenderRedirect(num_bands));
346
347 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
348 aec3.AnalyzeCapture(&capture_buffer);
349 if (sample_rate_hz > 16000) {
350 capture_buffer.SplitIntoFrequencyBands();
351 render_buffer.SplitIntoFrequencyBands();
352 }
353
354 PopulateInputFrame(frame_length, num_bands, frame_index,
355 &capture_buffer.split_bands_f(0)[0], 100);
356 PopulateInputFrame(frame_length, num_bands, frame_index,
357 &render_buffer.split_bands_f(0)[0], 0);
358
359 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
360 aec3.ProcessCapture(&capture_buffer, false);
361 EXPECT_TRUE(VerifyInputFrame(frame_length, num_bands, frame_index,
362 &capture_buffer.split_bands_f(0)[0], -64));
363 }
364 }
365
366 enum class EchoPathTestVariant { kNone, kOneSticky, kOneNonSticky };
ivoc 2016/12/21 14:52:13 Please add a comment to explain what each variant
peah-webrtc 2016/12/21 23:13:52 Done.
367
368 void RunEchoPathChangeVerificationTest(
369 int sample_rate_hz,
370 EchoPathTestVariant echo_path_change_test_variant) {
371 const size_t num_bands = NumBandsForRate(sample_rate_hz);
372 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
373 float input_frame_data[num_bands][frame_length];
374 float* input_frame[num_bands];
375 float output_frame_data[num_bands][frame_length];
376 float* output_frame[num_bands];
377 for (size_t k = 0; k < num_bands; ++k) {
378 input_frame[k] = &input_frame_data[k][0];
379 output_frame[k] = &output_frame_data[k][0];
380 }
381
382 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
383 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
384 samples_per_channel);
385 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
386 samples_per_channel);
387
388 EchoCanceller3 aec3(sample_rate_hz, false,
389 new BlockProcessorKnownEchoPathChangeReport(num_bands));
hlundin-webrtc 2016/12/20 15:10:36 Use a mock instead to verify that BlockProcessor::
peah-webrtc 2016/12/21 23:13:52 Done.
390
391 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
392 bool echo_path_change = false;
393 switch (echo_path_change_test_variant) {
394 case EchoPathTestVariant::kNone:
395 break;
396 case EchoPathTestVariant::kOneSticky:
397 echo_path_change = true;
398 break;
399 case EchoPathTestVariant::kOneNonSticky:
400 if (frame_index == 0) {
401 echo_path_change = true;
402 }
403 break;
404 default:
hlundin-webrtc 2016/12/20 15:10:35 You can omit the default case. Since you are switc
peah-webrtc 2016/12/21 23:13:52 Great! Thanks! Done.
405 RTC_NOTREACHED();
406 }
407
408 aec3.AnalyzeCapture(&capture_buffer);
409 if (sample_rate_hz > 16000) {
410 capture_buffer.SplitIntoFrequencyBands();
411 render_buffer.SplitIntoFrequencyBands();
412 }
413
414 PopulateInputFrame(frame_length, num_bands, frame_index,
415 &capture_buffer.split_bands_f(0)[0], 100);
416 PopulateInputFrame(frame_length, num_bands, frame_index,
417 &render_buffer.split_bands_f(0)[0], 0);
418
419 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
420 aec3.ProcessCapture(&capture_buffer, echo_path_change);
421
422 switch (echo_path_change_test_variant) {
423 case EchoPathTestVariant::kNone:
424 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
425 break;
426 case EchoPathTestVariant::kOneSticky:
427 if (frame_index > 0) {
428 EXPECT_EQ(1.f, capture_buffer.split_bands_f(0)[0][0]);
429 }
430 break;
431 case EchoPathTestVariant::kOneNonSticky:
432 if (frame_index > 10) {
433 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
434 }
435 break;
436 default:
hlundin-webrtc 2016/12/20 15:10:35 Remove default.
peah-webrtc 2016/12/21 23:13:53 Done.
437 RTC_NOTREACHED();
438 }
439 }
440 }
441
442 enum class EchoLeakageTestVariant {
ivoc 2016/12/21 14:52:13 Please add a comment here as well to explain the v
peah-webrtc 2016/12/21 23:13:52 Done.
443 kNone,
444 kFalseSticky,
445 kTrueSticky,
446 kTrueNonSticky
447 };
448
449 void RunEchoLeakageVerificationTest(
450 int sample_rate_hz,
451 EchoLeakageTestVariant leakage_report_variant) {
452 const size_t num_bands = NumBandsForRate(sample_rate_hz);
453 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
454 float input_frame_data[num_bands][frame_length];
455 float* input_frame[num_bands];
456 float output_frame_data[num_bands][frame_length];
457 float* output_frame[num_bands];
458 for (size_t k = 0; k < num_bands; ++k) {
459 input_frame[k] = &input_frame_data[k][0];
460 output_frame[k] = &output_frame_data[k][0];
461 }
462
463 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
464 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
465 samples_per_channel);
466 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
467 samples_per_channel);
468
469 EchoCanceller3 aec3(sample_rate_hz, false,
470 new BlockProcessorEchoLeakageReport(num_bands));
hlundin-webrtc 2016/12/20 15:10:35 Rewrite this test to use a mock instead of BlockPr
peah-webrtc 2016/12/21 23:13:52 Done.
471
472 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
473 switch (leakage_report_variant) {
474 case EchoLeakageTestVariant::kNone:
475 break;
476 case EchoLeakageTestVariant::kFalseSticky:
477 if (frame_index == 0) {
478 aec3.ReportEchoLeakage(false);
479 }
480 break;
481 case EchoLeakageTestVariant::kTrueSticky:
482 if (frame_index == 0) {
483 aec3.ReportEchoLeakage(true);
484 }
485 break;
486 case EchoLeakageTestVariant::kTrueNonSticky:
487 if (frame_index == 0) {
488 aec3.ReportEchoLeakage(true);
489 } else {
490 aec3.ReportEchoLeakage(false);
491 }
492
493 break;
494 default:
hlundin-webrtc 2016/12/20 15:10:35 Remove default.
peah-webrtc 2016/12/21 23:13:52 Done.
495 RTC_NOTREACHED();
496 }
497
498 aec3.AnalyzeCapture(&capture_buffer);
499 if (sample_rate_hz > 16000) {
500 capture_buffer.SplitIntoFrequencyBands();
501 render_buffer.SplitIntoFrequencyBands();
502 }
503
504 PopulateInputFrame(frame_length, num_bands, frame_index,
505 &capture_buffer.split_bands_f(0)[0], 100);
506 PopulateInputFrame(frame_length, num_bands, frame_index,
507 &render_buffer.split_bands_f(0)[0], 0);
508
509 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
510 aec3.ProcessCapture(&capture_buffer, false);
511
512 switch (leakage_report_variant) {
513 case EchoLeakageTestVariant::kNone:
514 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
515 break;
516 case EchoLeakageTestVariant::kFalseSticky:
517 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
518 break;
519 case EchoLeakageTestVariant::kTrueSticky:
520 if (frame_index > 0) {
521 EXPECT_EQ(1.f, capture_buffer.split_bands_f(0)[0][0]);
522 }
523 break;
524 case EchoLeakageTestVariant::kTrueNonSticky:
525 if (frame_index == 0) {
526 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
527 } else if (frame_index == 1) {
528 EXPECT_EQ(1.f, capture_buffer.split_bands_f(0)[0][0]);
529 } else if (frame_index > 2) {
530 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
531 }
532 break;
533 default:
hlundin-webrtc 2016/12/20 15:10:36 Remove default.
peah-webrtc 2016/12/21 23:13:52 Done.
534 RTC_NOTREACHED();
535 }
536 }
537 }
538
539 enum class SaturationTestVariant {
ivoc 2016/12/21 14:52:13 Comment about variants, please.
peah-webrtc 2016/12/21 23:13:53 Done.
540 kNone,
541 kOneNegative,
542 kOnePositive,
543 kNotSticky
544 };
545
546 void RunCaptureSaturationVerificationTest(
547 int sample_rate_hz,
548 SaturationTestVariant saturation_variant) {
549 const size_t num_bands = NumBandsForRate(sample_rate_hz);
550 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
551 float input_frame_data[num_bands][frame_length];
552 float* input_frame[num_bands];
553 float output_frame_data[num_bands][frame_length];
554 float* output_frame[num_bands];
555 for (size_t k = 0; k < num_bands; ++k) {
556 input_frame[k] = &input_frame_data[k][0];
557 output_frame[k] = &output_frame_data[k][0];
558 }
559
560 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
561 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
562 samples_per_channel);
563 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
564 samples_per_channel);
565
566 EchoCanceller3 aec3(sample_rate_hz, false,
567 new BlockProcessorCaptureSaturationReport(num_bands));
hlundin-webrtc 2016/12/20 15:10:35 Use a mock instead to verify that BlockProcessor::
peah-webrtc 2016/12/21 23:13:51 Done.
568
569 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
570 for (int k = 0; k < samples_per_channel; ++k) {
571 capture_buffer.channels_f()[0][k] = 0.f;
572 }
573 switch (saturation_variant) {
574 case SaturationTestVariant::kNone:
575 break;
576 case SaturationTestVariant::kOneNegative:
577 capture_buffer.channels_f()[0][10] = -32768.f;
578 break;
579 case SaturationTestVariant::kOnePositive:
580 capture_buffer.channels_f()[0][10] = 32767.f;
581 break;
582 case SaturationTestVariant::kNotSticky:
583 if (frame_index < 14) {
584 capture_buffer.channels_f()[0][10] = 32767.f;
585 }
586 break;
587 default:
hlundin-webrtc 2016/12/20 15:10:36 Remove default.
peah-webrtc 2016/12/21 23:13:52 Done.
588 RTC_NOTREACHED();
589 }
590
591 aec3.AnalyzeCapture(&capture_buffer);
592 if (sample_rate_hz > 16000) {
593 capture_buffer.SplitIntoFrequencyBands();
594 render_buffer.SplitIntoFrequencyBands();
595 }
596
597 PopulateInputFrame(frame_length, num_bands, frame_index,
598 &capture_buffer.split_bands_f(0)[0], 100);
599 PopulateInputFrame(frame_length, num_bands, frame_index,
600 &render_buffer.split_bands_f(0)[0], 0);
601
602 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
603 aec3.ProcessCapture(&capture_buffer, false);
604
605 switch (saturation_variant) {
606 case SaturationTestVariant::kNone:
607 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
608 break;
609 case SaturationTestVariant::kOneNegative:
610 if (frame_index > 0) {
611 EXPECT_EQ(1.f, capture_buffer.split_bands_f(0)[0][0]);
612 }
613 break;
614 case SaturationTestVariant::kOnePositive:
615 if (frame_index > 0) {
616 EXPECT_EQ(1.f, capture_buffer.split_bands_f(0)[0][0]);
617 }
618 break;
619 case SaturationTestVariant::kNotSticky:
620 if (frame_index > 15) {
621 EXPECT_EQ(0.f, capture_buffer.split_bands_f(0)[0][0]);
622 }
623 break;
624 default:
hlundin-webrtc 2016/12/20 15:10:35 Remove default.
peah-webrtc 2016/12/21 23:13:52 Done.
625 RTC_NOTREACHED();
626 }
627 }
628 }
629
630 void RunRenderPipelineSwapQueueTest(int sample_rate_hz) {
hlundin-webrtc 2016/12/20 15:10:35 Comment on what this test does.
peah-webrtc 2016/12/21 23:13:51 Done.
631 const size_t num_bands = NumBandsForRate(sample_rate_hz);
632 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
633 float input_frame_data[num_bands][frame_length];
634 float* input_frame[num_bands];
635 float output_frame_data[num_bands][frame_length];
636 float* output_frame[num_bands];
637 for (size_t k = 0; k < num_bands; ++k) {
638 input_frame[k] = &input_frame_data[k][0];
639 output_frame[k] = &output_frame_data[k][0];
640 }
641
642 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
643 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
644 samples_per_channel);
645 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
646 samples_per_channel);
647
648 EchoCanceller3 aec3(sample_rate_hz, false,
649 new BlockProcessorRenderRedirect(num_bands));
650
651 const size_t kNumFramesToProcess = 30;
652 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
653 ++frame_index) {
654 if (sample_rate_hz > 16000) {
655 render_buffer.SplitIntoFrequencyBands();
656 }
657 PopulateInputFrame(frame_length, num_bands, frame_index,
658 &render_buffer.split_bands_f(0)[0], 0);
659
660 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
661 }
662
663 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
664 ++frame_index) {
665 aec3.AnalyzeCapture(&capture_buffer);
666 if (sample_rate_hz > 16000) {
667 capture_buffer.SplitIntoFrequencyBands();
668 }
669
670 PopulateInputFrame(frame_length, num_bands, frame_index,
671 &capture_buffer.split_bands_f(0)[0], 100);
672
673 aec3.ProcessCapture(&capture_buffer, false);
674 EXPECT_TRUE(VerifyInputFrame(frame_length, num_bands, frame_index,
675 &capture_buffer.split_bands_f(0)[0], -64));
676 }
677 }
678
679 void RunRenderPipelineSwapQueueOverrunReturnValueTest(int sample_rate_hz) {
hlundin-webrtc 2016/12/20 15:10:35 Comment...
peah-webrtc 2016/12/21 23:13:52 Done.
680 const size_t num_bands = NumBandsForRate(sample_rate_hz);
681 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
682 float input_frame_data[num_bands][frame_length];
683 float* input_frame[num_bands];
684 float output_frame_data[num_bands][frame_length];
685 float* output_frame[num_bands];
686 for (size_t k = 0; k < num_bands; ++k) {
687 input_frame[k] = &input_frame_data[k][0];
688 output_frame[k] = &output_frame_data[k][0];
689 }
690
691 const int samples_per_channel = rtc::CheckedDivExact(sample_rate_hz, 100);
692 AudioBuffer capture_buffer(samples_per_channel, 1, samples_per_channel, 1,
693 samples_per_channel);
694 AudioBuffer render_buffer(samples_per_channel, 1, samples_per_channel, 1,
695 samples_per_channel);
696
697 EchoCanceller3 aec3(sample_rate_hz, false);
698
699 const size_t kNumFramesToProcess = 30;
700 for (size_t k = 0; k < 2; ++k) {
701 for (size_t frame_index = 0; frame_index < kNumFramesToProcess;
702 ++frame_index) {
703 if (sample_rate_hz > 16000) {
704 render_buffer.SplitIntoFrequencyBands();
705 }
706 PopulateInputFrame(frame_length, num_bands, frame_index,
707 &render_buffer.split_bands_f(0)[0], 0);
708
709 if (k == 0) {
710 EXPECT_TRUE(aec3.AnalyzeRender(&render_buffer));
711 } else {
712 EXPECT_FALSE(aec3.AnalyzeRender(&render_buffer));
713 }
714 }
715 }
716 }
717
718 void RunBlockerAndFramerTest(int sample_rate_hz) {
hlundin-webrtc 2016/12/20 15:10:35 This looks like unit tests for FrameBlocker and Bl
peah-webrtc 2016/12/21 23:13:51 Done.
719 const size_t num_bands = NumBandsForRate(sample_rate_hz);
720 const size_t frame_length = sample_rate_hz == 8000 ? 80 : 160;
721 const size_t num_sub_frames = frame_length / 80;
722 float input_frame_data[num_bands][frame_length];
723 float* input_frame[num_bands];
724 float output_frame_data[num_bands][frame_length];
725 float* output_frame[num_bands];
726 for (size_t k = 0; k < num_bands; ++k) {
727 input_frame[k] = &input_frame_data[k][0];
728 output_frame[k] = &output_frame_data[k][0];
729 }
730
731 std::vector<std::vector<float>> block(num_bands, std::vector<float>(64, 0.f));
732 FrameBlocker blocker(num_bands);
733 BlockFramer framer(num_bands);
734
735 for (size_t frame_index = 0; frame_index < 20; ++frame_index) {
736 PopulateInputFrame(frame_length, num_bands, frame_index, input_frame, 0);
737 for (size_t sub_frame_index = 0; sub_frame_index < num_sub_frames;
738 ++sub_frame_index) {
739 rtc::ArrayView<float> sub_frame_view_data[num_bands];
740 rtc::ArrayView<const float> sub_frame_const_view_data[num_bands];
741 auto sub_frame_view = rtc::ArrayView<rtc::ArrayView<float>>(
742 &sub_frame_view_data[0], num_bands);
743 auto sub_frame_const_view = rtc::ArrayView<rtc::ArrayView<const float>>(
744 &sub_frame_const_view_data[0], num_bands);
745 FillSubFrameView(output_frame, sub_frame_index, sub_frame_view);
746 FillSubFrameView(input_frame, sub_frame_index, sub_frame_const_view);
747
748 blocker.InsertSubFrameAndExtractBlock(sub_frame_const_view, &block);
749
750 framer.InsertBlockAndExtractSubFrame(block, sub_frame_view);
751 if ((frame_index * num_sub_frames + sub_frame_index + 1) % 4 == 0) {
752 EXPECT_TRUE(blocker.IsBlockAvailable());
753 } else {
754 EXPECT_FALSE(blocker.IsBlockAvailable());
755 }
756 if (blocker.IsBlockAvailable()) {
757 blocker.ExtractBlock(&block);
758 framer.InsertBlock(block);
759 }
760 }
761 EXPECT_TRUE(VerifyInputFrame(frame_length, num_bands, frame_index,
762 output_frame, -64));
763 }
764 }
765
766 } // namespace
767
768 TEST(EchoCanceller3Pipeline, CaptureBitexactness) {
769 for (auto rate : {8000, 16000, 32000, 48000}) {
hlundin-webrtc 2016/12/20 15:10:36 This makes it tricky to know which test case is ac
peah-webrtc 2016/12/21 23:13:52 Good point! I went for SCOPED_TRACE. PTAL
770 RunCapturePipelineVerificationTest(rate);
771 }
772 }
773
774 TEST(EchoCanceller3Pipeline, RenderBitexactness) {
775 for (auto rate : {8000, 16000, 32000, 48000}) {
776 RunRenderPipelineVerificationTest(rate);
777 }
778 }
779
780 TEST(EchoCanceller3Pipeline, CaptureSaturation) {
781 auto variants = {
782 SaturationTestVariant::kNone, SaturationTestVariant::kOneNegative,
783 SaturationTestVariant::kOnePositive, SaturationTestVariant::kNotSticky};
784 for (auto rate : {8000, 16000, 32000, 48000}) {
785 for (auto variant : variants) {
786 RunCaptureSaturationVerificationTest(rate, variant);
787 }
788 }
789 }
790
791 TEST(EchoCanceller3Pipeline, EchoPathChange) {
792 auto variants = {EchoPathTestVariant::kNone, EchoPathTestVariant::kOneSticky,
793 EchoPathTestVariant::kOneNonSticky};
794 for (auto rate : {8000, 16000, 32000, 48000}) {
795 for (auto variant : variants) {
796 RunEchoPathChangeVerificationTest(rate, variant);
797 }
798 }
799 }
800
801 TEST(EchoCanceller3Pipeline, EchoLeakage) {
802 auto variants = {EchoLeakageTestVariant::kNone,
803 EchoLeakageTestVariant::kFalseSticky,
804 EchoLeakageTestVariant::kTrueSticky,
805 EchoLeakageTestVariant::kTrueNonSticky};
806 for (auto rate : {8000, 16000, 32000, 48000}) {
807 for (auto variant : variants) {
808 RunEchoLeakageVerificationTest(rate, variant);
809 }
810 }
811 }
812
813 TEST(EchoCanceller3Pipeline, RenderSwapQueue) {
814 for (auto rate : {8000, 16000, 32000, 48000}) {
815 RunRenderPipelineSwapQueueTest(rate);
816 }
817 }
818
819 TEST(EchoCanceller3Pipeline, RenderSwapQueueOverrunReturnValue) {
820 for (auto rate : {8000, 16000, 32000, 48000}) {
821 RunRenderPipelineSwapQueueOverrunReturnValueTest(rate);
822 }
823 }
824
825 TEST(EchoCanceller3Pipeline, BlockerAndFramer) {
826 for (auto rate : {8000, 16000, 32000, 48000}) {
827 RunBlockerAndFramerTest(rate);
828 }
829 }
830
831 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698