xref: /aosp_15_r20/external/webrtc/modules/audio_processing/aec3/frame_blocker_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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