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 "modules/audio_processing/aec3/frame_blocker.h"
12
13 #include <string>
14 #include <vector>
15
16 #include "modules/audio_processing/aec3/aec3_common.h"
17 #include "modules/audio_processing/aec3/block_framer.h"
18 #include "rtc_base/strings/string_builder.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22 namespace {
23
ComputeSampleValue(size_t chunk_counter,size_t chunk_size,size_t band,size_t channel,size_t sample_index,int offset)24 float ComputeSampleValue(size_t chunk_counter,
25 size_t chunk_size,
26 size_t band,
27 size_t channel,
28 size_t sample_index,
29 int offset) {
30 float value =
31 static_cast<int>(chunk_counter * chunk_size + sample_index + channel) +
32 offset;
33 return value > 0 ? 5000 * band + value : 0;
34 }
35
FillSubFrame(size_t sub_frame_counter,int offset,std::vector<std::vector<std::vector<float>>> * sub_frame)36 void FillSubFrame(size_t sub_frame_counter,
37 int offset,
38 std::vector<std::vector<std::vector<float>>>* sub_frame) {
39 for (size_t band = 0; band < sub_frame->size(); ++band) {
40 for (size_t channel = 0; channel < (*sub_frame)[band].size(); ++channel) {
41 for (size_t sample = 0; sample < (*sub_frame)[band][channel].size();
42 ++sample) {
43 (*sub_frame)[band][channel][sample] = ComputeSampleValue(
44 sub_frame_counter, kSubFrameLength, band, channel, sample, offset);
45 }
46 }
47 }
48 }
49
FillSubFrameView(size_t sub_frame_counter,int offset,std::vector<std::vector<std::vector<float>>> * sub_frame,std::vector<std::vector<rtc::ArrayView<float>>> * sub_frame_view)50 void FillSubFrameView(
51 size_t sub_frame_counter,
52 int offset,
53 std::vector<std::vector<std::vector<float>>>* sub_frame,
54 std::vector<std::vector<rtc::ArrayView<float>>>* sub_frame_view) {
55 FillSubFrame(sub_frame_counter, offset, sub_frame);
56 for (size_t band = 0; band < sub_frame_view->size(); ++band) {
57 for (size_t channel = 0; channel < (*sub_frame_view)[band].size();
58 ++channel) {
59 (*sub_frame_view)[band][channel] = rtc::ArrayView<float>(
60 &(*sub_frame)[band][channel][0], (*sub_frame)[band][channel].size());
61 }
62 }
63 }
64
VerifySubFrame(size_t sub_frame_counter,int offset,const std::vector<std::vector<rtc::ArrayView<float>>> & sub_frame_view)65 bool VerifySubFrame(
66 size_t sub_frame_counter,
67 int offset,
68 const std::vector<std::vector<rtc::ArrayView<float>>>& sub_frame_view) {
69 std::vector<std::vector<std::vector<float>>> reference_sub_frame(
70 sub_frame_view.size(),
71 std::vector<std::vector<float>>(
72 sub_frame_view[0].size(),
73 std::vector<float>(sub_frame_view[0][0].size(), 0.f)));
74 FillSubFrame(sub_frame_counter, offset, &reference_sub_frame);
75 for (size_t band = 0; band < sub_frame_view.size(); ++band) {
76 for (size_t channel = 0; channel < sub_frame_view[band].size(); ++channel) {
77 for (size_t sample = 0; sample < sub_frame_view[band][channel].size();
78 ++sample) {
79 if (reference_sub_frame[band][channel][sample] !=
80 sub_frame_view[band][channel][sample]) {
81 return false;
82 }
83 }
84 }
85 }
86 return true;
87 }
88
VerifyBlock(size_t block_counter,int offset,const Block & block)89 bool VerifyBlock(size_t block_counter, int offset, const Block& block) {
90 for (int band = 0; band < block.NumBands(); ++band) {
91 for (int channel = 0; channel < block.NumChannels(); ++channel) {
92 for (size_t sample = 0; sample < kBlockSize; ++sample) {
93 auto it = block.begin(band, channel) + sample;
94 const float reference_value = ComputeSampleValue(
95 block_counter, kBlockSize, band, channel, sample, offset);
96 if (reference_value != *it) {
97 return false;
98 }
99 }
100 }
101 }
102 return true;
103 }
104
105 // Verifies that the FrameBlocker properly forms blocks out of the frames.
RunBlockerTest(int sample_rate_hz,size_t num_channels)106 void RunBlockerTest(int sample_rate_hz, size_t num_channels) {
107 constexpr size_t kNumSubFramesToProcess = 20;
108 const size_t num_bands = NumBandsForRate(sample_rate_hz);
109
110 Block block(num_bands, num_channels);
111 std::vector<std::vector<std::vector<float>>> input_sub_frame(
112 num_bands, std::vector<std::vector<float>>(
113 num_channels, std::vector<float>(kSubFrameLength, 0.f)));
114 std::vector<std::vector<rtc::ArrayView<float>>> input_sub_frame_view(
115 num_bands, std::vector<rtc::ArrayView<float>>(num_channels));
116 FrameBlocker blocker(num_bands, num_channels);
117
118 size_t block_counter = 0;
119 for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess;
120 ++sub_frame_index) {
121 FillSubFrameView(sub_frame_index, 0, &input_sub_frame,
122 &input_sub_frame_view);
123
124 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
125 VerifyBlock(block_counter++, 0, block);
126
127 if ((sub_frame_index + 1) % 4 == 0) {
128 EXPECT_TRUE(blocker.IsBlockAvailable());
129 } else {
130 EXPECT_FALSE(blocker.IsBlockAvailable());
131 }
132 if (blocker.IsBlockAvailable()) {
133 blocker.ExtractBlock(&block);
134 VerifyBlock(block_counter++, 0, block);
135 }
136 }
137 }
138
139 // Verifies that the FrameBlocker and BlockFramer work well together and produce
140 // the expected output.
RunBlockerAndFramerTest(int sample_rate_hz,size_t num_channels)141 void RunBlockerAndFramerTest(int sample_rate_hz, size_t num_channels) {
142 const size_t kNumSubFramesToProcess = 20;
143 const size_t num_bands = NumBandsForRate(sample_rate_hz);
144
145 Block block(num_bands, num_channels);
146 std::vector<std::vector<std::vector<float>>> input_sub_frame(
147 num_bands, std::vector<std::vector<float>>(
148 num_channels, std::vector<float>(kSubFrameLength, 0.f)));
149 std::vector<std::vector<std::vector<float>>> output_sub_frame(
150 num_bands, std::vector<std::vector<float>>(
151 num_channels, std::vector<float>(kSubFrameLength, 0.f)));
152 std::vector<std::vector<rtc::ArrayView<float>>> output_sub_frame_view(
153 num_bands, std::vector<rtc::ArrayView<float>>(num_channels));
154 std::vector<std::vector<rtc::ArrayView<float>>> input_sub_frame_view(
155 num_bands, std::vector<rtc::ArrayView<float>>(num_channels));
156 FrameBlocker blocker(num_bands, num_channels);
157 BlockFramer framer(num_bands, num_channels);
158
159 for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess;
160 ++sub_frame_index) {
161 FillSubFrameView(sub_frame_index, 0, &input_sub_frame,
162 &input_sub_frame_view);
163 FillSubFrameView(sub_frame_index, 0, &output_sub_frame,
164 &output_sub_frame_view);
165
166 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
167 framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view);
168
169 if ((sub_frame_index + 1) % 4 == 0) {
170 EXPECT_TRUE(blocker.IsBlockAvailable());
171 } else {
172 EXPECT_FALSE(blocker.IsBlockAvailable());
173 }
174 if (blocker.IsBlockAvailable()) {
175 blocker.ExtractBlock(&block);
176 framer.InsertBlock(block);
177 }
178 if (sub_frame_index > 1) {
179 EXPECT_TRUE(VerifySubFrame(sub_frame_index, -64, output_sub_frame_view));
180 }
181 }
182 }
183
184 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
185 // Verifies that the FrameBlocker crashes if the InsertSubFrameAndExtractBlock
186 // method is called for inputs with the wrong number of bands or band lengths.
RunWronglySizedInsertAndExtractParametersTest(int sample_rate_hz,size_t correct_num_channels,size_t num_block_bands,size_t num_block_channels,size_t num_sub_frame_bands,size_t num_sub_frame_channels,size_t sub_frame_length)187 void RunWronglySizedInsertAndExtractParametersTest(
188 int sample_rate_hz,
189 size_t correct_num_channels,
190 size_t num_block_bands,
191 size_t num_block_channels,
192 size_t num_sub_frame_bands,
193 size_t num_sub_frame_channels,
194 size_t sub_frame_length) {
195 const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
196
197 Block block(num_block_bands, num_block_channels);
198 std::vector<std::vector<std::vector<float>>> input_sub_frame(
199 num_sub_frame_bands,
200 std::vector<std::vector<float>>(
201 num_sub_frame_channels, std::vector<float>(sub_frame_length, 0.f)));
202 std::vector<std::vector<rtc::ArrayView<float>>> input_sub_frame_view(
203 input_sub_frame.size(),
204 std::vector<rtc::ArrayView<float>>(num_sub_frame_channels));
205 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
206 FrameBlocker blocker(correct_num_bands, correct_num_channels);
207 EXPECT_DEATH(
208 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block), "");
209 }
210
211 // Verifies that the FrameBlocker crashes if the ExtractBlock method is called
212 // for inputs with the wrong number of bands or band lengths.
RunWronglySizedExtractParameterTest(int sample_rate_hz,size_t correct_num_channels,size_t num_block_bands,size_t num_block_channels)213 void RunWronglySizedExtractParameterTest(int sample_rate_hz,
214 size_t correct_num_channels,
215 size_t num_block_bands,
216 size_t num_block_channels) {
217 const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
218
219 Block correct_block(correct_num_bands, correct_num_channels);
220 Block wrong_block(num_block_bands, num_block_channels);
221 std::vector<std::vector<std::vector<float>>> input_sub_frame(
222 correct_num_bands,
223 std::vector<std::vector<float>>(
224 correct_num_channels, std::vector<float>(kSubFrameLength, 0.f)));
225 std::vector<std::vector<rtc::ArrayView<float>>> input_sub_frame_view(
226 input_sub_frame.size(),
227 std::vector<rtc::ArrayView<float>>(correct_num_channels));
228 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
229 FrameBlocker blocker(correct_num_bands, correct_num_channels);
230 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
231 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
232 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
233 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block);
234
235 EXPECT_DEATH(blocker.ExtractBlock(&wrong_block), "");
236 }
237
238 // Verifies that the FrameBlocker crashes if the ExtractBlock method is called
239 // after a wrong number of previous InsertSubFrameAndExtractBlock method calls
240 // have been made.
RunWrongExtractOrderTest(int sample_rate_hz,size_t num_channels,size_t num_preceeding_api_calls)241 void RunWrongExtractOrderTest(int sample_rate_hz,
242 size_t num_channels,
243 size_t num_preceeding_api_calls) {
244 const size_t num_bands = NumBandsForRate(sample_rate_hz);
245
246 Block block(num_bands, num_channels);
247 std::vector<std::vector<std::vector<float>>> input_sub_frame(
248 num_bands, std::vector<std::vector<float>>(
249 num_channels, std::vector<float>(kSubFrameLength, 0.f)));
250 std::vector<std::vector<rtc::ArrayView<float>>> input_sub_frame_view(
251 input_sub_frame.size(), std::vector<rtc::ArrayView<float>>(num_channels));
252 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view);
253 FrameBlocker blocker(num_bands, num_channels);
254 for (size_t k = 0; k < num_preceeding_api_calls; ++k) {
255 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block);
256 }
257
258 EXPECT_DEATH(blocker.ExtractBlock(&block), "");
259 }
260 #endif
261
ProduceDebugText(int sample_rate_hz,size_t num_channels)262 std::string ProduceDebugText(int sample_rate_hz, size_t num_channels) {
263 rtc::StringBuilder ss;
264 ss << "Sample rate: " << sample_rate_hz;
265 ss << ", number of channels: " << num_channels;
266 return ss.Release();
267 }
268
269 } // namespace
270
271 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST(FrameBlockerDeathTest,WrongNumberOfBandsInBlockForInsertSubFrameAndExtractBlock)272 TEST(FrameBlockerDeathTest,
273 WrongNumberOfBandsInBlockForInsertSubFrameAndExtractBlock) {
274 for (auto rate : {16000, 32000, 48000}) {
275 for (size_t correct_num_channels : {1, 2, 4, 8}) {
276 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
277 const size_t correct_num_bands = NumBandsForRate(rate);
278 const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
279 RunWronglySizedInsertAndExtractParametersTest(
280 rate, correct_num_channels, wrong_num_bands, correct_num_channels,
281 correct_num_bands, correct_num_channels, kSubFrameLength);
282 }
283 }
284 }
285
TEST(FrameBlockerDeathTest,WrongNumberOfChannelsInBlockForInsertSubFrameAndExtractBlock)286 TEST(FrameBlockerDeathTest,
287 WrongNumberOfChannelsInBlockForInsertSubFrameAndExtractBlock) {
288 for (auto rate : {16000, 32000, 48000}) {
289 for (size_t correct_num_channels : {1, 2, 4, 8}) {
290 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
291 const size_t correct_num_bands = NumBandsForRate(rate);
292 const size_t wrong_num_channels = correct_num_channels + 1;
293 RunWronglySizedInsertAndExtractParametersTest(
294 rate, correct_num_channels, correct_num_bands, wrong_num_channels,
295 correct_num_bands, correct_num_channels, kSubFrameLength);
296 }
297 }
298 }
299
TEST(FrameBlockerDeathTest,WrongNumberOfBandsInSubFrameForInsertSubFrameAndExtractBlock)300 TEST(FrameBlockerDeathTest,
301 WrongNumberOfBandsInSubFrameForInsertSubFrameAndExtractBlock) {
302 for (auto rate : {16000, 32000, 48000}) {
303 for (size_t correct_num_channels : {1, 2, 4, 8}) {
304 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
305 const size_t correct_num_bands = NumBandsForRate(rate);
306 const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
307 RunWronglySizedInsertAndExtractParametersTest(
308 rate, correct_num_channels, correct_num_bands, correct_num_channels,
309 wrong_num_bands, correct_num_channels, kSubFrameLength);
310 }
311 }
312 }
313
TEST(FrameBlockerDeathTest,WrongNumberOfChannelsInSubFrameForInsertSubFrameAndExtractBlock)314 TEST(FrameBlockerDeathTest,
315 WrongNumberOfChannelsInSubFrameForInsertSubFrameAndExtractBlock) {
316 for (auto rate : {16000, 32000, 48000}) {
317 for (size_t correct_num_channels : {1, 2, 4, 8}) {
318 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
319 const size_t correct_num_bands = NumBandsForRate(rate);
320 const size_t wrong_num_channels = correct_num_channels + 1;
321 RunWronglySizedInsertAndExtractParametersTest(
322 rate, correct_num_channels, correct_num_bands, wrong_num_channels,
323 correct_num_bands, wrong_num_channels, kSubFrameLength);
324 }
325 }
326 }
327
TEST(FrameBlockerDeathTest,WrongNumberOfSamplesInSubFrameForInsertSubFrameAndExtractBlock)328 TEST(FrameBlockerDeathTest,
329 WrongNumberOfSamplesInSubFrameForInsertSubFrameAndExtractBlock) {
330 for (auto rate : {16000, 32000, 48000}) {
331 for (size_t correct_num_channels : {1, 2, 4, 8}) {
332 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
333 const size_t correct_num_bands = NumBandsForRate(rate);
334 RunWronglySizedInsertAndExtractParametersTest(
335 rate, correct_num_channels, correct_num_bands, correct_num_channels,
336 correct_num_bands, correct_num_channels, kSubFrameLength - 1);
337 }
338 }
339 }
340
TEST(FrameBlockerDeathTest,WrongNumberOfBandsInBlockForExtractBlock)341 TEST(FrameBlockerDeathTest, WrongNumberOfBandsInBlockForExtractBlock) {
342 for (auto rate : {16000, 32000, 48000}) {
343 for (size_t correct_num_channels : {1, 2, 4, 8}) {
344 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
345 const size_t correct_num_bands = NumBandsForRate(rate);
346 const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
347 RunWronglySizedExtractParameterTest(
348 rate, correct_num_channels, wrong_num_bands, correct_num_channels);
349 }
350 }
351 }
352
TEST(FrameBlockerDeathTest,WrongNumberOfChannelsInBlockForExtractBlock)353 TEST(FrameBlockerDeathTest, WrongNumberOfChannelsInBlockForExtractBlock) {
354 for (auto rate : {16000, 32000, 48000}) {
355 for (size_t correct_num_channels : {1, 2, 4, 8}) {
356 SCOPED_TRACE(ProduceDebugText(rate, correct_num_channels));
357 const size_t correct_num_bands = NumBandsForRate(rate);
358 const size_t wrong_num_channels = correct_num_channels + 1;
359 RunWronglySizedExtractParameterTest(
360 rate, correct_num_channels, correct_num_bands, wrong_num_channels);
361 }
362 }
363 }
364
TEST(FrameBlockerDeathTest,WrongNumberOfPreceedingApiCallsForExtractBlock)365 TEST(FrameBlockerDeathTest, WrongNumberOfPreceedingApiCallsForExtractBlock) {
366 for (auto rate : {16000, 32000, 48000}) {
367 for (size_t num_channels : {1, 2, 4, 8}) {
368 for (size_t num_calls = 0; num_calls < 4; ++num_calls) {
369 rtc::StringBuilder ss;
370 ss << "Sample rate: " << rate;
371 ss << "Num channels: " << num_channels;
372 ss << ", Num preceeding InsertSubFrameAndExtractBlock calls: "
373 << num_calls;
374
375 SCOPED_TRACE(ss.str());
376 RunWrongExtractOrderTest(rate, num_channels, num_calls);
377 }
378 }
379 }
380 }
381
382 // Verifies that the verification for 0 number of channels works.
TEST(FrameBlockerDeathTest,ZeroNumberOfChannelsParameter)383 TEST(FrameBlockerDeathTest, ZeroNumberOfChannelsParameter) {
384 EXPECT_DEATH(FrameBlocker(16000, 0), "");
385 }
386
387 // Verifies that the verification for 0 number of bands works.
TEST(FrameBlockerDeathTest,ZeroNumberOfBandsParameter)388 TEST(FrameBlockerDeathTest, ZeroNumberOfBandsParameter) {
389 EXPECT_DEATH(FrameBlocker(0, 1), "");
390 }
391
392 // Verifiers that the verification for null sub_frame pointer works.
TEST(FrameBlockerDeathTest,NullBlockParameter)393 TEST(FrameBlockerDeathTest, NullBlockParameter) {
394 std::vector<std::vector<std::vector<float>>> sub_frame(
395 1, std::vector<std::vector<float>>(
396 1, std::vector<float>(kSubFrameLength, 0.f)));
397 std::vector<std::vector<rtc::ArrayView<float>>> sub_frame_view(
398 sub_frame.size());
399 FillSubFrameView(0, 0, &sub_frame, &sub_frame_view);
400 EXPECT_DEATH(
401 FrameBlocker(1, 1).InsertSubFrameAndExtractBlock(sub_frame_view, nullptr),
402 "");
403 }
404
405 #endif
406
TEST(FrameBlocker,BlockBitexactness)407 TEST(FrameBlocker, BlockBitexactness) {
408 for (auto rate : {16000, 32000, 48000}) {
409 for (size_t num_channels : {1, 2, 4, 8}) {
410 SCOPED_TRACE(ProduceDebugText(rate, num_channels));
411 RunBlockerTest(rate, num_channels);
412 }
413 }
414 }
415
TEST(FrameBlocker,BlockerAndFramer)416 TEST(FrameBlocker, BlockerAndFramer) {
417 for (auto rate : {16000, 32000, 48000}) {
418 for (size_t num_channels : {1, 2, 4, 8}) {
419 SCOPED_TRACE(ProduceDebugText(rate, num_channels));
420 RunBlockerAndFramerTest(rate, num_channels);
421 }
422 }
423 }
424
425 } // namespace webrtc
426