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