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 "modules/audio_processing/aec3/block_framer.h"
12 
13 #include <sstream>
14 #include <string>
15 #include <vector>
16 
17 #include "modules/audio_processing/aec3/aec3_common.h"
18 #include "test/gtest.h"
19 
20 namespace webrtc {
21 namespace {
22 
SetupSubFrameView(std::vector<std::vector<float>> * sub_frame,std::vector<rtc::ArrayView<float>> * sub_frame_view)23 void SetupSubFrameView(std::vector<std::vector<float>>* sub_frame,
24                        std::vector<rtc::ArrayView<float>>* sub_frame_view) {
25   for (size_t k = 0; k < sub_frame_view->size(); ++k) {
26     (*sub_frame_view)[k] =
27         rtc::ArrayView<float>((*sub_frame)[k].data(), (*sub_frame)[k].size());
28   }
29 }
30 
ComputeSampleValue(size_t chunk_counter,size_t chunk_size,size_t band,size_t sample_index,int offset)31 float ComputeSampleValue(size_t chunk_counter,
32                          size_t chunk_size,
33                          size_t band,
34                          size_t sample_index,
35                          int offset) {
36   float value =
37       static_cast<int>(chunk_counter * chunk_size + sample_index) + offset;
38   return value > 0 ? 5000 * band + value : 0;
39 }
40 
VerifySubFrame(size_t sub_frame_counter,int offset,const std::vector<rtc::ArrayView<float>> & sub_frame_view)41 bool VerifySubFrame(size_t sub_frame_counter,
42                     int offset,
43                     const std::vector<rtc::ArrayView<float>>& sub_frame_view) {
44   for (size_t k = 0; k < sub_frame_view.size(); ++k) {
45     for (size_t i = 0; i < sub_frame_view[k].size(); ++i) {
46       const float reference_value =
47           ComputeSampleValue(sub_frame_counter, kSubFrameLength, k, i, offset);
48       if (reference_value != sub_frame_view[k][i]) {
49         return false;
50       }
51     }
52   }
53   return true;
54 }
55 
FillBlock(size_t block_counter,std::vector<std::vector<float>> * block)56 void FillBlock(size_t block_counter, std::vector<std::vector<float>>* block) {
57   for (size_t k = 0; k < block->size(); ++k) {
58     for (size_t i = 0; i < (*block)[0].size(); ++i) {
59       (*block)[k][i] = ComputeSampleValue(block_counter, kBlockSize, k, i, 0);
60     }
61   }
62 }
63 
64 // Verifies that the BlockFramer is able to produce the expected frame content.
RunFramerTest(int sample_rate_hz)65 void RunFramerTest(int sample_rate_hz) {
66   constexpr size_t kNumSubFramesToProcess = 2;
67   const size_t num_bands = NumBandsForRate(sample_rate_hz);
68 
69   std::vector<std::vector<float>> block(num_bands,
70                                         std::vector<float>(kBlockSize, 0.f));
71   std::vector<std::vector<float>> output_sub_frame(
72       num_bands, std::vector<float>(kSubFrameLength, 0.f));
73   std::vector<rtc::ArrayView<float>> output_sub_frame_view(num_bands);
74   SetupSubFrameView(&output_sub_frame, &output_sub_frame_view);
75   BlockFramer framer(num_bands);
76 
77   size_t block_index = 0;
78   for (size_t sub_frame_index = 0; sub_frame_index < kNumSubFramesToProcess;
79        ++sub_frame_index) {
80     FillBlock(block_index++, &block);
81     framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view);
82     EXPECT_TRUE(VerifySubFrame(sub_frame_index, -64, output_sub_frame_view));
83 
84     if ((sub_frame_index + 1) % 4 == 0) {
85       FillBlock(block_index++, &block);
86       framer.InsertBlock(block);
87     }
88   }
89 }
90 
91 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
92 // Verifies that the BlockFramer crashes if the InsertBlockAndExtractSubFrame
93 // method is called for inputs with the wrong number of bands or band lengths.
RunWronglySizedInsertAndExtractParametersTest(int sample_rate_hz,size_t num_block_bands,size_t block_length,size_t num_sub_frame_bands,size_t sub_frame_length)94 void RunWronglySizedInsertAndExtractParametersTest(int sample_rate_hz,
95                                                    size_t num_block_bands,
96                                                    size_t block_length,
97                                                    size_t num_sub_frame_bands,
98                                                    size_t sub_frame_length) {
99   const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
100 
101   std::vector<std::vector<float>> block(num_block_bands,
102                                         std::vector<float>(block_length, 0.f));
103   std::vector<std::vector<float>> output_sub_frame(
104       num_sub_frame_bands, std::vector<float>(sub_frame_length, 0.f));
105   std::vector<rtc::ArrayView<float>> output_sub_frame_view(
106       output_sub_frame.size());
107   SetupSubFrameView(&output_sub_frame, &output_sub_frame_view);
108   BlockFramer framer(correct_num_bands);
109   EXPECT_DEATH(
110       framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view), "");
111 }
112 
113 // Verifies that the BlockFramer crashes if the InsertBlock method is called for
114 // inputs with the wrong number of bands or band lengths.
RunWronglySizedInsertParameterTest(int sample_rate_hz,size_t num_block_bands,size_t block_length)115 void RunWronglySizedInsertParameterTest(int sample_rate_hz,
116                                         size_t num_block_bands,
117                                         size_t block_length) {
118   const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
119 
120   std::vector<std::vector<float>> correct_block(
121       correct_num_bands, std::vector<float>(kBlockSize, 0.f));
122   std::vector<std::vector<float>> wrong_block(
123       num_block_bands, std::vector<float>(block_length, 0.f));
124   std::vector<std::vector<float>> output_sub_frame(
125       correct_num_bands, std::vector<float>(kSubFrameLength, 0.f));
126   std::vector<rtc::ArrayView<float>> output_sub_frame_view(
127       output_sub_frame.size());
128   SetupSubFrameView(&output_sub_frame, &output_sub_frame_view);
129   BlockFramer framer(correct_num_bands);
130   framer.InsertBlockAndExtractSubFrame(correct_block, &output_sub_frame_view);
131   framer.InsertBlockAndExtractSubFrame(correct_block, &output_sub_frame_view);
132   framer.InsertBlockAndExtractSubFrame(correct_block, &output_sub_frame_view);
133   framer.InsertBlockAndExtractSubFrame(correct_block, &output_sub_frame_view);
134 
135   EXPECT_DEATH(framer.InsertBlock(wrong_block), "");
136 }
137 
138 // Verifies that the BlockFramer crashes if the InsertBlock method is called
139 // after a wrong number of previous InsertBlockAndExtractSubFrame method calls
140 // have been made.
RunWronglyInsertOrderTest(int sample_rate_hz,size_t num_preceeding_api_calls)141 void RunWronglyInsertOrderTest(int sample_rate_hz,
142                                size_t num_preceeding_api_calls) {
143   const size_t correct_num_bands = NumBandsForRate(sample_rate_hz);
144 
145   std::vector<std::vector<float>> block(correct_num_bands,
146                                         std::vector<float>(kBlockSize, 0.f));
147   std::vector<std::vector<float>> output_sub_frame(
148       correct_num_bands, std::vector<float>(kSubFrameLength, 0.f));
149   std::vector<rtc::ArrayView<float>> output_sub_frame_view(
150       output_sub_frame.size());
151   SetupSubFrameView(&output_sub_frame, &output_sub_frame_view);
152   BlockFramer framer(correct_num_bands);
153   for (size_t k = 0; k < num_preceeding_api_calls; ++k) {
154     framer.InsertBlockAndExtractSubFrame(block, &output_sub_frame_view);
155   }
156 
157   EXPECT_DEATH(framer.InsertBlock(block), "");
158 }
159 #endif
160 
ProduceDebugText(int sample_rate_hz)161 std::string ProduceDebugText(int sample_rate_hz) {
162   std::ostringstream ss;
163   ss << "Sample rate: " << sample_rate_hz;
164   return ss.str();
165 }
166 
167 }  // namespace
168 
169 #if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
TEST(BlockFramer,WrongNumberOfBandsInBlockForInsertBlockAndExtractSubFrame)170 TEST(BlockFramer, WrongNumberOfBandsInBlockForInsertBlockAndExtractSubFrame) {
171   for (auto rate : {8000, 16000, 32000, 48000}) {
172     SCOPED_TRACE(ProduceDebugText(rate));
173     const size_t correct_num_bands = NumBandsForRate(rate);
174     const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
175     RunWronglySizedInsertAndExtractParametersTest(
176         rate, wrong_num_bands, kBlockSize, correct_num_bands, kSubFrameLength);
177   }
178 }
179 
TEST(BlockFramer,WrongNumberOfBandsInSubFrameForInsertBlockAndExtractSubFrame)180 TEST(BlockFramer,
181      WrongNumberOfBandsInSubFrameForInsertBlockAndExtractSubFrame) {
182   for (auto rate : {8000, 16000, 32000, 48000}) {
183     SCOPED_TRACE(ProduceDebugText(rate));
184     const size_t correct_num_bands = NumBandsForRate(rate);
185     const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
186     RunWronglySizedInsertAndExtractParametersTest(
187         rate, correct_num_bands, kBlockSize, wrong_num_bands, kSubFrameLength);
188   }
189 }
190 
TEST(BlockFramer,WrongNumberOfSamplesInBlockForInsertBlockAndExtractSubFrame)191 TEST(BlockFramer, WrongNumberOfSamplesInBlockForInsertBlockAndExtractSubFrame) {
192   for (auto rate : {8000, 16000, 32000, 48000}) {
193     SCOPED_TRACE(ProduceDebugText(rate));
194     const size_t correct_num_bands = NumBandsForRate(rate);
195     RunWronglySizedInsertAndExtractParametersTest(
196         rate, correct_num_bands, kBlockSize - 1, correct_num_bands,
197         kSubFrameLength);
198   }
199 }
200 
TEST(BlockFramer,WrongNumberOfSamplesInSubFrameForInsertBlockAndExtractSubFrame)201 TEST(BlockFramer,
202      WrongNumberOfSamplesInSubFrameForInsertBlockAndExtractSubFrame) {
203   for (auto rate : {8000, 16000, 32000, 48000}) {
204     SCOPED_TRACE(ProduceDebugText(rate));
205     const size_t correct_num_bands = NumBandsForRate(rate);
206     RunWronglySizedInsertAndExtractParametersTest(rate, correct_num_bands,
207                                                   kBlockSize, correct_num_bands,
208                                                   kSubFrameLength - 1);
209   }
210 }
211 
TEST(BlockFramer,WrongNumberOfBandsInBlockForInsertBlock)212 TEST(BlockFramer, WrongNumberOfBandsInBlockForInsertBlock) {
213   for (auto rate : {8000, 16000, 32000, 48000}) {
214     SCOPED_TRACE(ProduceDebugText(rate));
215     const size_t correct_num_bands = NumBandsForRate(rate);
216     const size_t wrong_num_bands = (correct_num_bands % 3) + 1;
217     RunWronglySizedInsertParameterTest(rate, wrong_num_bands, kBlockSize);
218   }
219 }
220 
TEST(BlockFramer,WrongNumberOfSamplesInBlockForInsertBlock)221 TEST(BlockFramer, WrongNumberOfSamplesInBlockForInsertBlock) {
222   for (auto rate : {8000, 16000, 32000, 48000}) {
223     SCOPED_TRACE(ProduceDebugText(rate));
224     const size_t correct_num_bands = NumBandsForRate(rate);
225     RunWronglySizedInsertParameterTest(rate, correct_num_bands, kBlockSize - 1);
226   }
227 }
228 
TEST(BlockFramer,WrongNumberOfPreceedingApiCallsForInsertBlock)229 TEST(BlockFramer, WrongNumberOfPreceedingApiCallsForInsertBlock) {
230   for (auto rate : {8000, 16000, 32000, 48000}) {
231     for (size_t num_calls = 0; num_calls < 4; ++num_calls) {
232       std::ostringstream ss;
233       ss << "Sample rate: " << rate;
234       ss << ", Num preceeding InsertBlockAndExtractSubFrame calls: "
235          << num_calls;
236 
237       SCOPED_TRACE(ss.str());
238       RunWronglyInsertOrderTest(rate, num_calls);
239     }
240   }
241 }
242 
243 // Verifiers that the verification for null sub_frame pointer works.
TEST(BlockFramer,NullSubFrameParameter)244 TEST(BlockFramer, NullSubFrameParameter) {
245   EXPECT_DEATH(BlockFramer(1).InsertBlockAndExtractSubFrame(
246                    std::vector<std::vector<float>>(
247                        1, std::vector<float>(kBlockSize, 0.f)),
248                    nullptr),
249                "");
250 }
251 
252 #endif
253 
TEST(BlockFramer,FrameBitexactness)254 TEST(BlockFramer, FrameBitexactness) {
255   for (auto rate : {8000, 16000, 32000, 48000}) {
256     SCOPED_TRACE(ProduceDebugText(rate));
257     RunFramerTest(rate);
258   }
259 }
260 
261 }  // namespace webrtc
262