| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (c) 2014 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 <memory> | |
| 12 | |
| 13 #include "webrtc/modules/audio_processing/utility/blocker.h" | |
| 14 | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | |
| 16 #include "webrtc/base/arraysize.h" | |
| 17 | |
| 18 namespace { | |
| 19 | |
| 20 // Callback Function to add 3 to every sample in the signal. | |
| 21 class PlusThreeBlockerCallback : public webrtc::BlockerCallback { | |
| 22 public: | |
| 23 void ProcessBlock(const float* const* input, | |
| 24 size_t num_frames, | |
| 25 size_t num_input_channels, | |
| 26 size_t num_output_channels, | |
| 27 float* const* output) override { | |
| 28 for (size_t i = 0; i < num_output_channels; ++i) { | |
| 29 for (size_t j = 0; j < num_frames; ++j) { | |
| 30 output[i][j] = input[i][j] + 3; | |
| 31 } | |
| 32 } | |
| 33 } | |
| 34 }; | |
| 35 | |
| 36 // No-op Callback Function. | |
| 37 class CopyBlockerCallback : public webrtc::BlockerCallback { | |
| 38 public: | |
| 39 void ProcessBlock(const float* const* input, | |
| 40 size_t num_frames, | |
| 41 size_t num_input_channels, | |
| 42 size_t num_output_channels, | |
| 43 float* const* output) override { | |
| 44 for (size_t i = 0; i < num_output_channels; ++i) { | |
| 45 for (size_t j = 0; j < num_frames; ++j) { | |
| 46 output[i][j] = input[i][j]; | |
| 47 } | |
| 48 } | |
| 49 } | |
| 50 }; | |
| 51 | |
| 52 } // namespace | |
| 53 | |
| 54 namespace webrtc { | |
| 55 | |
| 56 // Tests blocking with a window that multiplies the signal by 2, a callback | |
| 57 // that adds 3 to each sample in the signal, and different combinations of chunk | |
| 58 // size, block size, and shift amount. | |
| 59 class BlockerTest : public ::testing::Test { | |
| 60 protected: | |
| 61 void RunTest(Blocker* blocker, | |
| 62 size_t chunk_size, | |
| 63 size_t num_frames, | |
| 64 const float* const* input, | |
| 65 float* const* input_chunk, | |
| 66 float* const* output, | |
| 67 float* const* output_chunk, | |
| 68 size_t num_input_channels, | |
| 69 size_t num_output_channels) { | |
| 70 size_t start = 0; | |
| 71 size_t end = chunk_size - 1; | |
| 72 while (end < num_frames) { | |
| 73 CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); | |
| 74 blocker->ProcessChunk(input_chunk, | |
| 75 chunk_size, | |
| 76 num_input_channels, | |
| 77 num_output_channels, | |
| 78 output_chunk); | |
| 79 CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk); | |
| 80 | |
| 81 start += chunk_size; | |
| 82 end += chunk_size; | |
| 83 } | |
| 84 } | |
| 85 | |
| 86 void ValidateSignalEquality(const float* const* expected, | |
| 87 const float* const* actual, | |
| 88 size_t num_channels, | |
| 89 size_t num_frames) { | |
| 90 for (size_t i = 0; i < num_channels; ++i) { | |
| 91 for (size_t j = 0; j < num_frames; ++j) { | |
| 92 EXPECT_FLOAT_EQ(expected[i][j], actual[i][j]); | |
| 93 } | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 void ValidateInitialDelay(const float* const* output, | |
| 98 size_t num_channels, | |
| 99 size_t num_frames, | |
| 100 size_t initial_delay) { | |
| 101 for (size_t i = 0; i < num_channels; ++i) { | |
| 102 for (size_t j = 0; j < num_frames; ++j) { | |
| 103 if (j < initial_delay) { | |
| 104 EXPECT_FLOAT_EQ(output[i][j], 0.f); | |
| 105 } else { | |
| 106 EXPECT_GT(output[i][j], 0.f); | |
| 107 } | |
| 108 } | |
| 109 } | |
| 110 } | |
| 111 | |
| 112 static void CopyTo(float* const* dst, | |
| 113 size_t start_index_dst, | |
| 114 size_t start_index_src, | |
| 115 size_t num_channels, | |
| 116 size_t num_frames, | |
| 117 const float* const* src) { | |
| 118 for (size_t i = 0; i < num_channels; ++i) { | |
| 119 memcpy(&dst[i][start_index_dst], | |
| 120 &src[i][start_index_src], | |
| 121 num_frames * sizeof(float)); | |
| 122 } | |
| 123 } | |
| 124 }; | |
| 125 | |
| 126 TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { | |
| 127 const size_t kNumInputChannels = 3; | |
| 128 const size_t kNumOutputChannels = 2; | |
| 129 const size_t kNumFrames = 10; | |
| 130 const size_t kBlockSize = 4; | |
| 131 const size_t kChunkSize = 5; | |
| 132 const size_t kShiftAmount = 2; | |
| 133 | |
| 134 const float kInput[kNumInputChannels][kNumFrames] = { | |
| 135 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | |
| 136 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | |
| 137 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | |
| 138 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | |
| 139 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | |
| 140 | |
| 141 const float kExpectedOutput[kNumInputChannels][kNumFrames] = { | |
| 142 {6, 6, 12, 20, 20, 20, 20, 20, 20, 20}, | |
| 143 {6, 6, 12, 28, 28, 28, 28, 28, 28, 28}}; | |
| 144 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumInputChannels); | |
| 145 expected_output_cb.SetDataForTesting( | |
| 146 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); | |
| 147 | |
| 148 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; | |
| 149 | |
| 150 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); | |
| 151 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); | |
| 152 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); | |
| 153 | |
| 154 PlusThreeBlockerCallback callback; | |
| 155 Blocker blocker(kChunkSize, | |
| 156 kBlockSize, | |
| 157 kNumInputChannels, | |
| 158 kNumOutputChannels, | |
| 159 kWindow, | |
| 160 kShiftAmount, | |
| 161 &callback); | |
| 162 | |
| 163 RunTest(&blocker, | |
| 164 kChunkSize, | |
| 165 kNumFrames, | |
| 166 input_cb.channels(), | |
| 167 input_chunk_cb.channels(), | |
| 168 actual_output_cb.channels(), | |
| 169 output_chunk_cb.channels(), | |
| 170 kNumInputChannels, | |
| 171 kNumOutputChannels); | |
| 172 | |
| 173 ValidateSignalEquality(expected_output_cb.channels(), | |
| 174 actual_output_cb.channels(), | |
| 175 kNumOutputChannels, | |
| 176 kNumFrames); | |
| 177 } | |
| 178 | |
| 179 TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { | |
| 180 const size_t kNumInputChannels = 3; | |
| 181 const size_t kNumOutputChannels = 2; | |
| 182 const size_t kNumFrames = 12; | |
| 183 const size_t kBlockSize = 4; | |
| 184 const size_t kChunkSize = 6; | |
| 185 const size_t kShiftAmount = 3; | |
| 186 | |
| 187 const float kInput[kNumInputChannels][kNumFrames] = { | |
| 188 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | |
| 189 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | |
| 190 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | |
| 191 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | |
| 192 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | |
| 193 | |
| 194 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { | |
| 195 {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10}, | |
| 196 {6, 14, 14, 28, 14, 14, 28, 14, 14, 28, 14, 14}}; | |
| 197 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels); | |
| 198 expected_output_cb.SetDataForTesting( | |
| 199 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); | |
| 200 | |
| 201 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; | |
| 202 | |
| 203 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); | |
| 204 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); | |
| 205 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); | |
| 206 | |
| 207 PlusThreeBlockerCallback callback; | |
| 208 Blocker blocker(kChunkSize, | |
| 209 kBlockSize, | |
| 210 kNumInputChannels, | |
| 211 kNumOutputChannels, | |
| 212 kWindow, | |
| 213 kShiftAmount, | |
| 214 &callback); | |
| 215 | |
| 216 RunTest(&blocker, | |
| 217 kChunkSize, | |
| 218 kNumFrames, | |
| 219 input_cb.channels(), | |
| 220 input_chunk_cb.channels(), | |
| 221 actual_output_cb.channels(), | |
| 222 output_chunk_cb.channels(), | |
| 223 kNumInputChannels, | |
| 224 kNumOutputChannels); | |
| 225 | |
| 226 ValidateSignalEquality(expected_output_cb.channels(), | |
| 227 actual_output_cb.channels(), | |
| 228 kNumOutputChannels, | |
| 229 kNumFrames); | |
| 230 } | |
| 231 | |
| 232 TEST_F(BlockerTest, TestBlockerNoOverlap) { | |
| 233 const size_t kNumInputChannels = 3; | |
| 234 const size_t kNumOutputChannels = 2; | |
| 235 const size_t kNumFrames = 12; | |
| 236 const size_t kBlockSize = 4; | |
| 237 const size_t kChunkSize = 4; | |
| 238 const size_t kShiftAmount = 4; | |
| 239 | |
| 240 const float kInput[kNumInputChannels][kNumFrames] = { | |
| 241 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | |
| 242 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | |
| 243 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | |
| 244 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | |
| 245 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | |
| 246 | |
| 247 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { | |
| 248 {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | |
| 249 {14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}}; | |
| 250 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels); | |
| 251 expected_output_cb.SetDataForTesting( | |
| 252 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); | |
| 253 | |
| 254 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; | |
| 255 | |
| 256 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); | |
| 257 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); | |
| 258 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); | |
| 259 | |
| 260 PlusThreeBlockerCallback callback; | |
| 261 Blocker blocker(kChunkSize, | |
| 262 kBlockSize, | |
| 263 kNumInputChannels, | |
| 264 kNumOutputChannels, | |
| 265 kWindow, | |
| 266 kShiftAmount, | |
| 267 &callback); | |
| 268 | |
| 269 RunTest(&blocker, | |
| 270 kChunkSize, | |
| 271 kNumFrames, | |
| 272 input_cb.channels(), | |
| 273 input_chunk_cb.channels(), | |
| 274 actual_output_cb.channels(), | |
| 275 output_chunk_cb.channels(), | |
| 276 kNumInputChannels, | |
| 277 kNumOutputChannels); | |
| 278 | |
| 279 ValidateSignalEquality(expected_output_cb.channels(), | |
| 280 actual_output_cb.channels(), | |
| 281 kNumOutputChannels, | |
| 282 kNumFrames); | |
| 283 } | |
| 284 | |
| 285 TEST_F(BlockerTest, InitialDelaysAreMinimum) { | |
| 286 const size_t kNumInputChannels = 3; | |
| 287 const size_t kNumOutputChannels = 2; | |
| 288 const size_t kNumFrames = 1280; | |
| 289 const size_t kChunkSize[] = | |
| 290 {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160}; | |
| 291 const size_t kBlockSize[] = | |
| 292 {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256}; | |
| 293 const size_t kShiftAmount[] = | |
| 294 {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256}; | |
| 295 const size_t kInitialDelay[] = | |
| 296 {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224}; | |
| 297 | |
| 298 float input[kNumInputChannels][kNumFrames]; | |
| 299 for (size_t i = 0; i < kNumInputChannels; ++i) { | |
| 300 for (size_t j = 0; j < kNumFrames; ++j) { | |
| 301 input[i][j] = i + 1; | |
| 302 } | |
| 303 } | |
| 304 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | |
| 305 input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input)); | |
| 306 | |
| 307 ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels); | |
| 308 | |
| 309 CopyBlockerCallback callback; | |
| 310 | |
| 311 for (size_t i = 0; i < arraysize(kChunkSize); ++i) { | |
| 312 std::unique_ptr<float[]> window(new float[kBlockSize[i]]); | |
| 313 for (size_t j = 0; j < kBlockSize[i]; ++j) { | |
| 314 window[j] = 1.f; | |
| 315 } | |
| 316 | |
| 317 ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels); | |
| 318 ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels); | |
| 319 | |
| 320 Blocker blocker(kChunkSize[i], | |
| 321 kBlockSize[i], | |
| 322 kNumInputChannels, | |
| 323 kNumOutputChannels, | |
| 324 window.get(), | |
| 325 kShiftAmount[i], | |
| 326 &callback); | |
| 327 | |
| 328 RunTest(&blocker, | |
| 329 kChunkSize[i], | |
| 330 kNumFrames, | |
| 331 input_cb.channels(), | |
| 332 input_chunk_cb.channels(), | |
| 333 output_cb.channels(), | |
| 334 output_chunk_cb.channels(), | |
| 335 kNumInputChannels, | |
| 336 kNumOutputChannels); | |
| 337 | |
| 338 ValidateInitialDelay(output_cb.channels(), | |
| 339 kNumOutputChannels, | |
| 340 kNumFrames, | |
| 341 kInitialDelay[i]); | |
| 342 } | |
| 343 } | |
| 344 | |
| 345 } // namespace webrtc | |
| OLD | NEW |