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