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