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