blocker_unittest.cc (11338B)
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 "modules/audio_coding/codecs/opus/test/blocker.h" 12 13 #include <cstddef> 14 #include <cstring> 15 #include <iterator> 16 #include <memory> 17 18 #include "common_audio/channel_buffer.h" 19 #include "test/gtest.h" 20 21 namespace { 22 23 // Callback Function to add 3 to every sample in the signal. 24 class PlusThreeBlockerCallback : public webrtc::BlockerCallback { 25 public: 26 void ProcessBlock(const float* const* input, 27 size_t num_frames, 28 size_t /* num_input_channels */, 29 size_t num_output_channels, 30 float* const* output) override { 31 for (size_t i = 0; i < num_output_channels; ++i) { 32 for (size_t j = 0; j < num_frames; ++j) { 33 output[i][j] = input[i][j] + 3; 34 } 35 } 36 } 37 }; 38 39 // No-op Callback Function. 40 class CopyBlockerCallback : public webrtc::BlockerCallback { 41 public: 42 void ProcessBlock(const float* const* input, 43 size_t num_frames, 44 size_t /* num_input_channels */, 45 size_t num_output_channels, 46 float* const* output) override { 47 for (size_t i = 0; i < num_output_channels; ++i) { 48 for (size_t j = 0; j < num_frames; ++j) { 49 output[i][j] = input[i][j]; 50 } 51 } 52 } 53 }; 54 55 } // namespace 56 57 namespace webrtc { 58 59 // Tests blocking with a window that multiplies the signal by 2, a callback 60 // that adds 3 to each sample in the signal, and different combinations of chunk 61 // size, block size, and shift amount. 62 class BlockerTest : public ::testing::Test { 63 protected: 64 void RunTest(Blocker* blocker, 65 size_t chunk_size, 66 size_t num_frames, 67 const float* const* input, 68 float* const* input_chunk, 69 float* const* output, 70 float* const* output_chunk, 71 size_t num_input_channels, 72 size_t num_output_channels) { 73 size_t start = 0; 74 size_t end = chunk_size - 1; 75 while (end < num_frames) { 76 CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input); 77 blocker->ProcessChunk(input_chunk, chunk_size, num_input_channels, 78 num_output_channels, 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], &src[i][start_index_src], 120 num_frames * sizeof(float)); 121 } 122 } 123 }; 124 125 TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) { 126 const size_t kNumInputChannels = 3; 127 const size_t kNumOutputChannels = 2; 128 const size_t kNumFrames = 10; 129 const size_t kBlockSize = 4; 130 const size_t kChunkSize = 5; 131 const size_t kShiftAmount = 2; 132 133 const float kInput[kNumInputChannels][kNumFrames] = { 134 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 135 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 136 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; 137 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); 138 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); 139 140 const float kExpectedOutput[kNumInputChannels][kNumFrames] = { 141 {6, 6, 12, 20, 20, 20, 20, 20, 20, 20}, 142 {6, 6, 12, 28, 28, 28, 28, 28, 28, 28}}; 143 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumInputChannels); 144 expected_output_cb.SetDataForTesting( 145 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); 146 147 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; 148 149 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); 150 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); 151 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); 152 153 PlusThreeBlockerCallback callback; 154 Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, 155 kWindow, kShiftAmount, &callback); 156 157 RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), 158 input_chunk_cb.channels(), actual_output_cb.channels(), 159 output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); 160 161 ValidateSignalEquality(expected_output_cb.channels(), 162 actual_output_cb.channels(), kNumOutputChannels, 163 kNumFrames); 164 } 165 166 TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) { 167 const size_t kNumInputChannels = 3; 168 const size_t kNumOutputChannels = 2; 169 const size_t kNumFrames = 12; 170 const size_t kBlockSize = 4; 171 const size_t kChunkSize = 6; 172 const size_t kShiftAmount = 3; 173 174 const float kInput[kNumInputChannels][kNumFrames] = { 175 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 176 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 177 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; 178 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); 179 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); 180 181 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { 182 {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10}, 183 {6, 14, 14, 28, 14, 14, 28, 14, 14, 28, 14, 14}}; 184 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels); 185 expected_output_cb.SetDataForTesting( 186 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); 187 188 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; 189 190 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); 191 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); 192 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); 193 194 PlusThreeBlockerCallback callback; 195 Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, 196 kWindow, kShiftAmount, &callback); 197 198 RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), 199 input_chunk_cb.channels(), actual_output_cb.channels(), 200 output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); 201 202 ValidateSignalEquality(expected_output_cb.channels(), 203 actual_output_cb.channels(), kNumOutputChannels, 204 kNumFrames); 205 } 206 207 TEST_F(BlockerTest, TestBlockerNoOverlap) { 208 const size_t kNumInputChannels = 3; 209 const size_t kNumOutputChannels = 2; 210 const size_t kNumFrames = 12; 211 const size_t kBlockSize = 4; 212 const size_t kChunkSize = 4; 213 const size_t kShiftAmount = 4; 214 215 const float kInput[kNumInputChannels][kNumFrames] = { 216 {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, 217 {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}, 218 {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}}; 219 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); 220 input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput)); 221 222 const float kExpectedOutput[kNumOutputChannels][kNumFrames] = { 223 {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, 224 {14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}}; 225 ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels); 226 expected_output_cb.SetDataForTesting( 227 kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput)); 228 229 const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f}; 230 231 ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels); 232 ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels); 233 ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels); 234 235 PlusThreeBlockerCallback callback; 236 Blocker blocker(kChunkSize, kBlockSize, kNumInputChannels, kNumOutputChannels, 237 kWindow, kShiftAmount, &callback); 238 239 RunTest(&blocker, kChunkSize, kNumFrames, input_cb.channels(), 240 input_chunk_cb.channels(), actual_output_cb.channels(), 241 output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); 242 243 ValidateSignalEquality(expected_output_cb.channels(), 244 actual_output_cb.channels(), kNumOutputChannels, 245 kNumFrames); 246 } 247 248 TEST_F(BlockerTest, InitialDelaysAreMinimum) { 249 const size_t kNumInputChannels = 3; 250 const size_t kNumOutputChannels = 2; 251 const size_t kNumFrames = 1280; 252 const size_t kChunkSize[] = {80, 80, 80, 80, 80, 80, 253 160, 160, 160, 160, 160, 160}; 254 const size_t kBlockSize[] = {64, 64, 64, 128, 128, 128, 255 128, 128, 128, 256, 256, 256}; 256 const size_t kShiftAmount[] = {16, 32, 64, 32, 64, 128, 257 32, 64, 128, 64, 128, 256}; 258 const size_t kInitialDelay[] = {48, 48, 48, 112, 112, 112, 259 96, 96, 96, 224, 224, 224}; 260 261 float input[kNumInputChannels][kNumFrames]; 262 for (size_t i = 0; i < kNumInputChannels; ++i) { 263 for (size_t j = 0; j < kNumFrames; ++j) { 264 input[i][j] = i + 1; 265 } 266 } 267 ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels); 268 input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input)); 269 270 ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels); 271 272 CopyBlockerCallback callback; 273 274 for (size_t i = 0; i < std::size(kChunkSize); ++i) { 275 std::unique_ptr<float[]> window(new float[kBlockSize[i]]); 276 for (size_t j = 0; j < kBlockSize[i]; ++j) { 277 window[j] = 1.f; 278 } 279 280 ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels); 281 ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels); 282 283 Blocker blocker(kChunkSize[i], kBlockSize[i], kNumInputChannels, 284 kNumOutputChannels, window.get(), kShiftAmount[i], 285 &callback); 286 287 RunTest(&blocker, kChunkSize[i], kNumFrames, input_cb.channels(), 288 input_chunk_cb.channels(), output_cb.channels(), 289 output_chunk_cb.channels(), kNumInputChannels, kNumOutputChannels); 290 291 ValidateInitialDelay(output_cb.channels(), kNumOutputChannels, kNumFrames, 292 kInitialDelay[i]); 293 } 294 } 295 296 } // namespace webrtc