OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2016 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/modules/audio_processing/aec3/frame_blocker.h" | |
12 | |
13 #include <sstream> | |
14 #include <string> | |
15 #include <vector> | |
16 | |
17 #include "webrtc/modules/audio_processing/aec3/aec3_constants.h" | |
18 #include "webrtc/modules/audio_processing/aec3/block_framer.h" | |
19 #include "webrtc/test/gtest.h" | |
20 | |
21 namespace webrtc { | |
22 namespace { | |
23 | |
24 float ComputeSampleValue(size_t chunk_counter, | |
25 size_t chunk_size, | |
26 size_t band, | |
27 size_t sample_index, | |
28 int offset) { | |
29 float value = | |
30 static_cast<int>(chunk_counter * chunk_size + sample_index) + offset; | |
31 return value > 0 ? 5000 * band + value : 0; | |
32 } | |
33 | |
34 void FillSubFrame(size_t sub_frame_counter, | |
35 int offset, | |
36 std::vector<std::vector<float>>* sub_frame) { | |
37 for (size_t k = 0; k < sub_frame->size(); ++k) { | |
38 for (size_t i = 0; i < (*sub_frame)[0].size(); ++i) { | |
39 (*sub_frame)[k][i] = | |
40 ComputeSampleValue(sub_frame_counter, kSubFrameLength, k, i, offset); | |
41 } | |
42 } | |
43 } | |
44 | |
45 void FillSubFrameView(size_t sub_frame_counter, | |
46 int offset, | |
47 std::vector<std::vector<float>>* sub_frame, | |
48 std::vector<rtc::ArrayView<float>>* sub_frame_view) { | |
49 FillSubFrame(sub_frame_counter, offset, sub_frame); | |
50 for (size_t k = 0; k < sub_frame_view->size(); ++k) { | |
51 (*sub_frame_view)[k] = | |
52 rtc::ArrayView<float>(&(*sub_frame)[k][0], (*sub_frame)[k].size()); | |
53 } | |
54 } | |
55 | |
56 bool VerifySubFrame(size_t sub_frame_counter, | |
57 int offset, | |
58 const std::vector<rtc::ArrayView<float>>& sub_frame_view) { | |
59 std::vector<std::vector<float>> reference_sub_frame( | |
60 sub_frame_view.size(), std::vector<float>(sub_frame_view[0].size(), 0.f)); | |
61 FillSubFrame(sub_frame_counter, offset, &reference_sub_frame); | |
62 for (size_t k = 0; k < sub_frame_view.size(); ++k) { | |
63 for (size_t i = 0; i < sub_frame_view[k].size(); ++i) { | |
64 if (reference_sub_frame[k][i] != sub_frame_view[k][i]) { | |
65 return false; | |
66 } | |
67 } | |
68 } | |
69 return true; | |
70 } | |
71 | |
72 bool VerifyBlock(size_t block_counter, | |
73 int offset, | |
74 const std::vector<std::vector<float>>& block) { | |
75 for (size_t k = 0; k < block.size(); ++k) { | |
76 for (size_t i = 0; i < block[k].size(); ++i) { | |
77 const float reference_value = | |
78 ComputeSampleValue(block_counter, kBlockSize, k, i, offset); | |
79 if (reference_value != block[k][i]) { | |
80 return false; | |
81 } | |
82 } | |
83 } | |
84 return true; | |
85 } | |
86 | |
87 // Verifies that the FrameBlocker properly forms blocks out of the frames. | |
88 void RunBlockerTest(int sample_rate_hz) { | |
89 constexpr size_t kNumSubFramesToProcess = 20; | |
90 const size_t num_bands = NumBandsForRate(sample_rate_hz); | |
91 | |
92 std::vector<std::vector<float>> block(num_bands, | |
93 std::vector<float>(kBlockSize, 0.f)); | |
94 std::vector<std::vector<float>> input_sub_frame( | |
95 num_bands, std::vector<float>(kSubFrameLength, 0.f)); | |
96 std::vector<rtc::ArrayView<float>> input_sub_frame_view(num_bands); | |
97 FrameBlocker blocker(num_bands); | |
98 | |
99 size_t block_counter = 0; | |
100 for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess; | |
101 ++sub_frame_index) { | |
102 FillSubFrameView(sub_frame_index, 0, &input_sub_frame, | |
103 &input_sub_frame_view); | |
104 | |
105 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block); | |
106 VerifyBlock(block_counter++, 0, block); | |
107 | |
108 if ((sub_frame_index + 1) % 4 == 0) { | |
109 EXPECT_TRUE(blocker.IsBlockAvailable()); | |
110 } else { | |
111 EXPECT_FALSE(blocker.IsBlockAvailable()); | |
112 } | |
113 if (blocker.IsBlockAvailable()) { | |
114 blocker.ExtractBlock(&block); | |
115 VerifyBlock(block_counter++, 0, block); | |
116 } | |
117 } | |
118 } | |
119 | |
120 // Verifies that the FrameBlocker and BlockFramer work well together and produce | |
121 // the expected output. | |
122 void RunBlockerAndFramerTest(int sample_rate_hz) { | |
123 const size_t kNumSubFramesToProcess = 20; | |
124 const size_t num_bands = NumBandsForRate(sample_rate_hz); | |
125 | |
126 std::vector<std::vector<float>> block(num_bands, | |
127 std::vector<float>(kBlockSize, 0.f)); | |
128 std::vector<std::vector<float>> input_sub_frame( | |
129 num_bands, std::vector<float>(kSubFrameLength, 0.f)); | |
130 std::vector<std::vector<float>> output_sub_frame( | |
131 num_bands, std::vector<float>(kSubFrameLength, 0.f)); | |
132 std::vector<rtc::ArrayView<float>> output_sub_frame_view(num_bands); | |
133 std::vector<rtc::ArrayView<float>> input_sub_frame_view(num_bands); | |
134 FrameBlocker blocker(num_bands); | |
135 BlockFramer framer(num_bands); | |
136 | |
137 for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess; | |
138 ++sub_frame_index) { | |
139 FillSubFrameView(sub_frame_index, 0, &input_sub_frame, | |
140 &input_sub_frame_view); | |
141 FillSubFrameView(sub_frame_index, 0, &output_sub_frame, | |
142 &output_sub_frame_view); | |
143 | |
144 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block); | |
145 framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view); | |
146 | |
147 if ((sub_frame_index + 1) % 4 == 0) { | |
148 EXPECT_TRUE(blocker.IsBlockAvailable()); | |
149 } else { | |
150 EXPECT_FALSE(blocker.IsBlockAvailable()); | |
151 } | |
152 if (blocker.IsBlockAvailable()) { | |
153 blocker.ExtractBlock(&block); | |
154 framer.InsertBlock(block); | |
155 } | |
156 EXPECT_TRUE(VerifySubFrame(sub_frame_index, -64, output_sub_frame_view)); | |
157 } | |
158 } | |
159 | |
160 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) | |
161 // Verifies that the FrameBlocker crashes if the InsertSubFrameAndExtractBlock | |
162 // method is called for inputs with the wrong number of bands or band lengths. | |
163 void RunWronglySizedInsertAndExtractParametersTest(int sample_rate_hz, | |
164 size_t num_block_bands, | |
165 size_t block_length, | |
166 size_t num_sub_frame_bands, | |
167 size_t sub_frame_length) { | |
168 const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); | |
169 | |
170 std::vector<std::vector<float>> block(num_block_bands, | |
171 std::vector<float>(block_length, 0.f)); | |
172 std::vector<std::vector<float>> input_sub_frame( | |
173 num_sub_frame_bands, std::vector<float>(sub_frame_length, 0.f)); | |
174 std::vector<rtc::ArrayView<float>> input_sub_frame_view( | |
175 input_sub_frame.size()); | |
176 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view); | |
177 FrameBlocker blocker(correct_num_bands); | |
178 EXPECT_DEATH( | |
179 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block), ""); | |
180 } | |
181 | |
182 // Verifies that the FrameBlocker crashes if the ExtractBlock method is called | |
183 // for inputs with the wrong number of bands or band lengths. | |
184 void RunWronglySizedExtractParameterTest(int sample_rate_hz, | |
185 size_t num_block_bands, | |
186 size_t block_length) { | |
187 const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); | |
188 | |
189 std::vector<std::vector<float>> correct_block( | |
190 correct_num_bands, std::vector<float>(kBlockSize, 0.f)); | |
191 std::vector<std::vector<float>> wrong_block( | |
192 num_block_bands, std::vector<float>(block_length, 0.f)); | |
193 std::vector<std::vector<float>> input_sub_frame( | |
194 correct_num_bands, std::vector<float>(kSubFrameLength, 0.f)); | |
195 std::vector<rtc::ArrayView<float>> input_sub_frame_view( | |
196 input_sub_frame.size()); | |
197 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view); | |
198 FrameBlocker blocker(correct_num_bands); | |
199 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block); | |
200 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block); | |
201 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block); | |
202 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &correct_block); | |
203 | |
204 EXPECT_DEATH(blocker.ExtractBlock(&wrong_block), ""); | |
205 } | |
206 | |
207 // Verifies that the FrameBlocker crashes if the ExtractBlock method is called | |
208 // after a wrong number of previous InsertSubFrameAndExtractBlock method calls | |
209 // have been made. | |
210 void RunWrongExtractOrderTest(int sample_rate_hz, | |
211 size_t num_preceeding_api_calls) { | |
212 const size_t correct_num_bands = NumBandsForRate(sample_rate_hz); | |
213 | |
214 std::vector<std::vector<float>> block(correct_num_bands, | |
215 std::vector<float>(kBlockSize, 0.f)); | |
216 std::vector<std::vector<float>> input_sub_frame( | |
217 correct_num_bands, std::vector<float>(kSubFrameLength, 0.f)); | |
218 std::vector<rtc::ArrayView<float>> input_sub_frame_view( | |
219 input_sub_frame.size()); | |
220 FillSubFrameView(0, 0, &input_sub_frame, &input_sub_frame_view); | |
221 FrameBlocker blocker(correct_num_bands); | |
222 for (size_t k = 0; k < num_preceeding_api_calls; ++k) { | |
223 blocker.InsertSubFrameAndExtractBlock(input_sub_frame_view, &block); | |
224 } | |
225 | |
226 EXPECT_DEATH(blocker.ExtractBlock(&block), ""); | |
227 } | |
228 #endif | |
229 | |
230 std::string ProduceDebugText(int sample_rate_hz) { | |
231 std::ostringstream ss; | |
232 ss << "Sample rate: " << sample_rate_hz; | |
233 return ss.str(); | |
234 } | |
235 | |
236 } // namespace | |
237 | |
238 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) | |
239 TEST(FrameBlocker, WrongNumberOfBandsInBlockForInsertSubFrameAndExtractBlock) { | |
240 for (auto rate : {8000, 16000, 32000, 48000}) { | |
241 SCOPED_TRACE(ProduceDebugText(rate)); | |
242 const size_t correct_num_bands = NumBandsForRate(rate); | |
243 const size_t wrong_num_bands = (correct_num_bands % 3) + 1; | |
244 RunWronglySizedInsertAndExtractParametersTest( | |
245 rate, wrong_num_bands, kBlockSize, correct_num_bands, kSubFrameLength); | |
246 } | |
247 } | |
248 | |
249 TEST(FrameBlocker, | |
250 WrongNumberOfBandsInSubFrameForInsertSubFrameAndExtractBlock) { | |
251 for (auto rate : {8000, 16000, 32000, 48000}) { | |
252 SCOPED_TRACE(ProduceDebugText(rate)); | |
253 const size_t correct_num_bands = NumBandsForRate(rate); | |
254 const size_t wrong_num_bands = (correct_num_bands % 3) + 1; | |
255 RunWronglySizedInsertAndExtractParametersTest( | |
256 rate, correct_num_bands, kBlockSize, wrong_num_bands, kSubFrameLength); | |
257 } | |
258 } | |
259 | |
260 TEST(FrameBlocker, | |
261 WrongNumberOfSamplesInBlockForInsertSubFrameAndExtractBlock) { | |
262 for (auto rate : {8000, 16000, 32000, 48000}) { | |
263 SCOPED_TRACE(ProduceDebugText(rate)); | |
264 const size_t correct_num_bands = NumBandsForRate(rate); | |
265 RunWronglySizedInsertAndExtractParametersTest( | |
266 rate, correct_num_bands, kBlockSize - 1, correct_num_bands, | |
267 kSubFrameLength); | |
268 } | |
269 } | |
270 | |
271 TEST(FrameBlocker, | |
272 WrongNumberOfSamplesInSubFrameForInsertSubFrameAndExtractBlock) { | |
273 for (auto rate : {8000, 16000, 32000, 48000}) { | |
274 SCOPED_TRACE(ProduceDebugText(rate)); | |
275 const size_t correct_num_bands = NumBandsForRate(rate); | |
276 RunWronglySizedInsertAndExtractParametersTest(rate, correct_num_bands, | |
277 kBlockSize, correct_num_bands, | |
278 kSubFrameLength - 1); | |
279 } | |
280 } | |
281 | |
282 TEST(FrameBlocker, WrongNumberOfBandsInBlockForExtractBlock) { | |
283 for (auto rate : {8000, 16000, 32000, 48000}) { | |
284 SCOPED_TRACE(ProduceDebugText(rate)); | |
285 const size_t correct_num_bands = NumBandsForRate(rate); | |
286 const size_t wrong_num_bands = (correct_num_bands % 3) + 1; | |
287 RunWronglySizedExtractParameterTest(rate, wrong_num_bands, kBlockSize); | |
288 } | |
289 } | |
290 | |
291 TEST(FrameBlocker, WrongNumberOfSamplesInBlockForExtractBlock) { | |
292 for (auto rate : {8000, 16000, 32000, 48000}) { | |
293 SCOPED_TRACE(ProduceDebugText(rate)); | |
294 const size_t correct_num_bands = NumBandsForRate(rate); | |
295 RunWronglySizedExtractParameterTest(rate, correct_num_bands, | |
296 kBlockSize - 1); | |
297 } | |
298 } | |
299 | |
300 TEST(FrameBlocker, WrongNumberOfPreceedingApiCallsForExtractBlock) { | |
301 for (auto rate : {8000, 16000, 32000, 48000}) { | |
302 for (size_t num_calls = 0; num_calls < 4; ++num_calls) { | |
303 std::ostringstream ss; | |
304 ss << "Sample rate: " << rate; | |
305 ss << ", Num preceeding InsertSubFrameAndExtractBlock calls: " | |
306 << num_calls; | |
307 | |
308 SCOPED_TRACE(ss.str()); | |
309 RunWrongExtractOrderTest(rate, num_calls); | |
310 } | |
311 } | |
312 } | |
313 | |
314 // Verifiers that the verification for null sub_frame pointer works. | |
315 TEST(FrameBlocker, NullBlockParameter) { | |
316 std::vector<std::vector<float>> sub_frame( | |
317 1, std::vector<float>(kSubFrameLength, 0.f)); | |
318 std::vector<rtc::ArrayView<float>> sub_frame_view(sub_frame.size()); | |
319 FillSubFrameView(0, 0, &sub_frame, &sub_frame_view); | |
320 EXPECT_DEATH( | |
321 FrameBlocker(1).InsertSubFrameAndExtractBlock(sub_frame_view, nullptr), | |
322 ""); | |
323 } | |
324 | |
325 #endif | |
326 | |
327 TEST(FrameBlocker, BlockBitexactness) { | |
328 for (auto rate : {8000, 16000, 32000, 48000}) { | |
329 SCOPED_TRACE(ProduceDebugText(rate)); | |
330 RunBlockerTest(rate); | |
331 } | |
332 } | |
333 | |
334 TEST(FrameBlocker, BlockerAndFramer) { | |
335 for (auto rate : {8000, 16000, 32000, 48000}) { | |
336 SCOPED_TRACE(ProduceDebugText(rate)); | |
337 RunBlockerAndFramerTest(rate); | |
338 } | |
339 } | |
340 | |
341 } // namespace webrtc | |
OLD | NEW |