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