OLD | NEW |
---|---|
(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 | |
OLD | NEW |