| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ | 9 */ |
| 10 | 10 |
| 11 #include "webrtc/common_audio/blocker.h" | 11 #include "webrtc/common_audio/blocker.h" |
| 12 | 12 |
| 13 #include "testing/gtest/include/gtest/gtest.h" | 13 #include "testing/gtest/include/gtest/gtest.h" |
| 14 | 14 |
| 15 namespace { | 15 namespace { |
| 16 | 16 |
| 17 // Callback Function to add 3 to every sample in the signal. | 17 // Callback Function to add 3 to every sample in the signal. |
| 18 class PlusThreeBlockerCallback : public webrtc::BlockerCallback { | 18 class PlusThreeBlockerCallback : public webrtc::BlockerCallback { |
| 19 public: | 19 public: |
| 20 void ProcessBlock(const float* const* input, | 20 void ProcessBlock(const float* const* input, |
| 21 size_t num_frames, | 21 size_t num_frames, |
| 22 int num_input_channels, | 22 size_t num_input_channels, |
| 23 int num_output_channels, | 23 size_t num_output_channels, |
| 24 float* const* output) override { | 24 float* const* output) override { |
| 25 for (int i = 0; i < num_output_channels; ++i) { | 25 for (size_t i = 0; i < num_output_channels; ++i) { |
| 26 for (size_t j = 0; j < num_frames; ++j) { | 26 for (size_t j = 0; j < num_frames; ++j) { |
| 27 output[i][j] = input[i][j] + 3; | 27 output[i][j] = input[i][j] + 3; |
| 28 } | 28 } |
| 29 } | 29 } |
| 30 } | 30 } |
| 31 }; | 31 }; |
| 32 | 32 |
| 33 // No-op Callback Function. | 33 // No-op Callback Function. |
| 34 class CopyBlockerCallback : public webrtc::BlockerCallback { | 34 class CopyBlockerCallback : public webrtc::BlockerCallback { |
| 35 public: | 35 public: |
| 36 void ProcessBlock(const float* const* input, | 36 void ProcessBlock(const float* const* input, |
| 37 size_t num_frames, | 37 size_t num_frames, |
| 38 int num_input_channels, | 38 size_t num_input_channels, |
| 39 int num_output_channels, | 39 size_t num_output_channels, |
| 40 float* const* output) override { | 40 float* const* output) override { |
| 41 for (int i = 0; i < num_output_channels; ++i) { | 41 for (size_t i = 0; i < num_output_channels; ++i) { |
| 42 for (size_t j = 0; j < num_frames; ++j) { | 42 for (size_t j = 0; j < num_frames; ++j) { |
| 43 output[i][j] = input[i][j]; | 43 output[i][j] = input[i][j]; |
| 44 } | 44 } |
| 45 } | 45 } |
| 46 } | 46 } |
| 47 }; | 47 }; |
| 48 | 48 |
| 49 } // namespace | 49 } // namespace |
| 50 | 50 |
| 51 namespace webrtc { | 51 namespace webrtc { |
| 52 | 52 |
| 53 // Tests blocking with a window that multiplies the signal by 2, a callback | 53 // Tests blocking with a window that multiplies the signal by 2, a callback |
| 54 // that adds 3 to each sample in the signal, and different combinations of chunk | 54 // that adds 3 to each sample in the signal, and different combinations of chunk |
| 55 // size, block size, and shift amount. | 55 // size, block size, and shift amount. |
| 56 class BlockerTest : public ::testing::Test { | 56 class BlockerTest : public ::testing::Test { |
| 57 protected: | 57 protected: |
| 58 void RunTest(Blocker* blocker, | 58 void RunTest(Blocker* blocker, |
| 59 int chunk_size, | 59 size_t chunk_size, |
| 60 int num_frames, | 60 size_t num_frames, |
| 61 const float* const* input, | 61 const float* const* input, |
| 62 float* const* input_chunk, | 62 float* const* input_chunk, |
| 63 float* const* output, | 63 float* const* output, |
| 64 float* const* output_chunk, | 64 float* const* output_chunk, |
| 65 int num_input_channels, | 65 size_t num_input_channels, |
| 66 int num_output_channels) { | 66 size_t num_output_channels) { |
| 67 int start = 0; | 67 size_t start = 0; |
| 68 int end = chunk_size - 1; | 68 size_t end = chunk_size - 1; |
| 69 while (end < num_frames) { | 69 while (end < num_frames) { |
| 70 CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); | 70 CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); |
| 71 blocker->ProcessChunk(input_chunk, | 71 blocker->ProcessChunk(input_chunk, |
| 72 chunk_size, | 72 chunk_size, |
| 73 num_input_channels, | 73 num_input_channels, |
| 74 num_output_channels, | 74 num_output_channels, |
| 75 output_chunk); | 75 output_chunk); |
| 76 CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk); | 76 CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk); |
| 77 | 77 |
| 78 start = start + chunk_size; | 78 start += chunk_size; |
| 79 end = end + chunk_size; | 79 end += chunk_size; |
| 80 } | 80 } |
| 81 } | 81 } |
| 82 | 82 |
| 83 void ValidateSignalEquality(const float* const* expected, | 83 void ValidateSignalEquality(const float* const* expected, |
| 84 const float* const* actual, | 84 const float* const* actual, |
| 85 int num_channels, | 85 size_t num_channels, |
| 86 int num_frames) { | 86 size_t num_frames) { |
| 87 for (int i = 0; i < num_channels; ++i) { | 87 for (size_t i = 0; i < num_channels; ++i) { |
| 88 for (int j = 0; j < num_frames; ++j) { | 88 for (size_t j = 0; j < num_frames; ++j) { |
| 89 EXPECT_FLOAT_EQ(expected[i][j], actual[i][j]); | 89 EXPECT_FLOAT_EQ(expected[i][j], actual[i][j]); |
| 90 } | 90 } |
| 91 } | 91 } |
| 92 } | 92 } |
| 93 | 93 |
| 94 void ValidateInitialDelay(const float* const* output, | 94 void ValidateInitialDelay(const float* const* output, |
| 95 int num_channels, | 95 size_t num_channels, |
| 96 int num_frames, | 96 size_t num_frames, |
| 97 int initial_delay) { | 97 size_t initial_delay) { |
| 98 for (int i = 0; i < num_channels; ++i) { | 98 for (size_t i = 0; i < num_channels; ++i) { |
| 99 for (int j = 0; j < num_frames; ++j) { | 99 for (size_t j = 0; j < num_frames; ++j) { |
| 100 if (j < initial_delay) { | 100 if (j < initial_delay) { |
| 101 EXPECT_FLOAT_EQ(output[i][j], 0.f); | 101 EXPECT_FLOAT_EQ(output[i][j], 0.f); |
| 102 } else { | 102 } else { |
| 103 EXPECT_GT(output[i][j], 0.f); | 103 EXPECT_GT(output[i][j], 0.f); |
| 104 } | 104 } |
| 105 } | 105 } |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 | 108 |
| 109 static void CopyTo(float* const* dst, | 109 static void CopyTo(float* const* dst, |
| 110 int start_index_dst, | 110 size_t start_index_dst, |
| 111 int start_index_src, | 111 size_t start_index_src, |
| 112 int num_channels, | 112 size_t num_channels, |
| 113 int num_frames, | 113 size_t num_frames, |
| 114 const float* const* src) { | 114 const float* const* src) { |
| 115 for (int i = 0; i < num_channels; ++i) { | 115 for (size_t i = 0; i < num_channels; ++i) { |
| 116 memcpy(&dst[i][start_index_dst], | 116 memcpy(&dst[i][start_index_dst], |
| 117 &src[i][start_index_src], | 117 &src[i][start_index_src], |
| 118 num_frames * sizeof(float)); | 118 num_frames * sizeof(float)); |
| 119 } | 119 } |
| 120 } | 120 } |
| 121 }; | 121 }; |
| 122 | 122 |
| 123 TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { | 123 TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { |
| 124 const int kNumInputChannels = 3; | 124 const size_t kNumInputChannels = 3; |
| 125 const int kNumOutputChannels = 2; | 125 const size_t kNumOutputChannels = 2; |
| 126 const int kNumFrames = 10; | 126 const size_t kNumFrames = 10; |
| 127 const int kBlockSize = 4; | 127 const size_t kBlockSize = 4; |
| 128 const int kChunkSize = 5; | 128 const size_t kChunkSize = 5; |
| 129 const int kShiftAmount = 2; | 129 const size_t kShiftAmount = 2; |
| 130 | 130 |
| 131 const float kInput[kNumInputChannels][kNumFrames] = { | 131 const float kInput[kNumInputChannels][kNumFrames] = { |
| 132 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | 132 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
| 133 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | 133 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, |
| 134 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | 134 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; |
| 135 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | 135 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); |
| 136 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | 136 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); |
| 137 | 137 |
| 138 const float kExpectedOutput[kNumInputChannels][kNumFrames] = { | 138 const float kExpectedOutput[kNumInputChannels][kNumFrames] = { |
| 139 {6, 6, 12, 20, 20, 20, 20, 20, 20, 20}, | 139 {6, 6, 12, 20, 20, 20, 20, 20, 20, 20}, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 167 kNumInputChannels, | 167 kNumInputChannels, |
| 168 kNumOutputChannels); | 168 kNumOutputChannels); |
| 169 | 169 |
| 170 ValidateSignalEquality(expected_output_cb.channels(), | 170 ValidateSignalEquality(expected_output_cb.channels(), |
| 171 actual_output_cb.channels(), | 171 actual_output_cb.channels(), |
| 172 kNumOutputChannels, | 172 kNumOutputChannels, |
| 173 kNumFrames); | 173 kNumFrames); |
| 174 } | 174 } |
| 175 | 175 |
| 176 TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { | 176 TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { |
| 177 const int kNumInputChannels = 3; | 177 const size_t kNumInputChannels = 3; |
| 178 const int kNumOutputChannels = 2; | 178 const size_t kNumOutputChannels = 2; |
| 179 const int kNumFrames = 12; | 179 const size_t kNumFrames = 12; |
| 180 const int kBlockSize = 4; | 180 const size_t kBlockSize = 4; |
| 181 const int kChunkSize = 6; | 181 const size_t kChunkSize = 6; |
| 182 const int kShiftAmount = 3; | 182 const size_t kShiftAmount = 3; |
| 183 | 183 |
| 184 const float kInput[kNumInputChannels][kNumFrames] = { | 184 const float kInput[kNumInputChannels][kNumFrames] = { |
| 185 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | 185 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
| 186 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | 186 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, |
| 187 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | 187 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; |
| 188 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | 188 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); |
| 189 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | 189 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); |
| 190 | 190 |
| 191 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { | 191 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { |
| 192 {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10}, | 192 {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10}, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 220 kNumInputChannels, | 220 kNumInputChannels, |
| 221 kNumOutputChannels); | 221 kNumOutputChannels); |
| 222 | 222 |
| 223 ValidateSignalEquality(expected_output_cb.channels(), | 223 ValidateSignalEquality(expected_output_cb.channels(), |
| 224 actual_output_cb.channels(), | 224 actual_output_cb.channels(), |
| 225 kNumOutputChannels, | 225 kNumOutputChannels, |
| 226 kNumFrames); | 226 kNumFrames); |
| 227 } | 227 } |
| 228 | 228 |
| 229 TEST_F(BlockerTest, TestBlockerNoOverlap) { | 229 TEST_F(BlockerTest, TestBlockerNoOverlap) { |
| 230 const int kNumInputChannels = 3; | 230 const size_t kNumInputChannels = 3; |
| 231 const int kNumOutputChannels = 2; | 231 const size_t kNumOutputChannels = 2; |
| 232 const int kNumFrames = 12; | 232 const size_t kNumFrames = 12; |
| 233 const int kBlockSize = 4; | 233 const size_t kBlockSize = 4; |
| 234 const int kChunkSize = 4; | 234 const size_t kChunkSize = 4; |
| 235 const int kShiftAmount = 4; | 235 const size_t kShiftAmount = 4; |
| 236 | 236 |
| 237 const float kInput[kNumInputChannels][kNumFrames] = { | 237 const float kInput[kNumInputChannels][kNumFrames] = { |
| 238 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, | 238 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, |
| 239 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, | 239 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, |
| 240 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; | 240 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; |
| 241 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | 241 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); |
| 242 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); | 242 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); |
| 243 | 243 |
| 244 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { | 244 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { |
| 245 {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, | 245 {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 273 kNumInputChannels, | 273 kNumInputChannels, |
| 274 kNumOutputChannels); | 274 kNumOutputChannels); |
| 275 | 275 |
| 276 ValidateSignalEquality(expected_output_cb.channels(), | 276 ValidateSignalEquality(expected_output_cb.channels(), |
| 277 actual_output_cb.channels(), | 277 actual_output_cb.channels(), |
| 278 kNumOutputChannels, | 278 kNumOutputChannels, |
| 279 kNumFrames); | 279 kNumFrames); |
| 280 } | 280 } |
| 281 | 281 |
| 282 TEST_F(BlockerTest, InitialDelaysAreMinimum) { | 282 TEST_F(BlockerTest, InitialDelaysAreMinimum) { |
| 283 const int kNumInputChannels = 3; | 283 const size_t kNumInputChannels = 3; |
| 284 const int kNumOutputChannels = 2; | 284 const size_t kNumOutputChannels = 2; |
| 285 const int kNumFrames = 1280; | 285 const size_t kNumFrames = 1280; |
| 286 const int kChunkSize[] = | 286 const size_t kChunkSize[] = |
| 287 {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160}; | 287 {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160}; |
| 288 const int kBlockSize[] = | 288 const size_t kBlockSize[] = |
| 289 {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256}; | 289 {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256}; |
| 290 const int kShiftAmount[] = | 290 const size_t kShiftAmount[] = |
| 291 {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256}; | 291 {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256}; |
| 292 const int kInitialDelay[] = | 292 const size_t kInitialDelay[] = |
| 293 {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224}; | 293 {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224}; |
| 294 | 294 |
| 295 float input[kNumInputChannels][kNumFrames]; | 295 float input[kNumInputChannels][kNumFrames]; |
| 296 for (int i = 0; i < kNumInputChannels; ++i) { | 296 for (size_t i = 0; i < kNumInputChannels; ++i) { |
| 297 for (int j = 0; j < kNumFrames; ++j) { | 297 for (size_t j = 0; j < kNumFrames; ++j) { |
| 298 input[i][j] = i + 1; | 298 input[i][j] = i + 1; |
| 299 } | 299 } |
| 300 } | 300 } |
| 301 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); | 301 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); |
| 302 input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input)); | 302 input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input)); |
| 303 | 303 |
| 304 ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels); | 304 ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels); |
| 305 | 305 |
| 306 CopyBlockerCallback callback; | 306 CopyBlockerCallback callback; |
| 307 | 307 |
| 308 for (size_t i = 0; i < (sizeof(kChunkSize) / sizeof(*kChunkSize)); ++i) { | 308 for (size_t i = 0; i < (sizeof(kChunkSize) / sizeof(*kChunkSize)); ++i) { |
| 309 rtc::scoped_ptr<float[]> window(new float[kBlockSize[i]]); | 309 rtc::scoped_ptr<float[]> window(new float[kBlockSize[i]]); |
| 310 for (int j = 0; j < kBlockSize[i]; ++j) { | 310 for (size_t j = 0; j < kBlockSize[i]; ++j) { |
| 311 window[j] = 1.f; | 311 window[j] = 1.f; |
| 312 } | 312 } |
| 313 | 313 |
| 314 ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels); | 314 ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels); |
| 315 ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels); | 315 ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels); |
| 316 | 316 |
| 317 Blocker blocker(kChunkSize[i], | 317 Blocker blocker(kChunkSize[i], |
| 318 kBlockSize[i], | 318 kBlockSize[i], |
| 319 kNumInputChannels, | 319 kNumInputChannels, |
| 320 kNumOutputChannels, | 320 kNumOutputChannels, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 333 kNumOutputChannels); | 333 kNumOutputChannels); |
| 334 | 334 |
| 335 ValidateInitialDelay(output_cb.channels(), | 335 ValidateInitialDelay(output_cb.channels(), |
| 336 kNumOutputChannels, | 336 kNumOutputChannels, |
| 337 kNumFrames, | 337 kNumFrames, |
| 338 kInitialDelay[i]); | 338 kInitialDelay[i]); |
| 339 } | 339 } |
| 340 } | 340 } |
| 341 | 341 |
| 342 } // namespace webrtc | 342 } // namespace webrtc |
| OLD | NEW |