1 /*
2 * Copyright (c) 2012 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/neteq/audio_vector.h"
12
13 #include <stdlib.h>
14
15 #include <string>
16
17 #include "rtc_base/numerics/safe_conversions.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21
22 class AudioVectorTest : public ::testing::Test {
23 protected:
SetUp()24 virtual void SetUp() {
25 // Populate test array.
26 for (size_t i = 0; i < array_length(); ++i) {
27 array_[i] = rtc::checked_cast<int16_t>(i);
28 }
29 }
30
array_length() const31 size_t array_length() const { return sizeof(array_) / sizeof(array_[0]); }
32
33 int16_t array_[10];
34 };
35
36 // Create and destroy AudioVector objects, both empty and with a predefined
37 // length.
TEST_F(AudioVectorTest,CreateAndDestroy)38 TEST_F(AudioVectorTest, CreateAndDestroy) {
39 AudioVector vec1;
40 EXPECT_TRUE(vec1.Empty());
41 EXPECT_EQ(0u, vec1.Size());
42
43 size_t initial_size = 17;
44 AudioVector vec2(initial_size);
45 EXPECT_FALSE(vec2.Empty());
46 EXPECT_EQ(initial_size, vec2.Size());
47 }
48
49 // Test the subscript operator [] for getting and setting.
TEST_F(AudioVectorTest,SubscriptOperator)50 TEST_F(AudioVectorTest, SubscriptOperator) {
51 AudioVector vec(array_length());
52 for (size_t i = 0; i < array_length(); ++i) {
53 vec[i] = static_cast<int16_t>(i);
54 const int16_t& value = vec[i]; // Make sure to use the const version.
55 EXPECT_EQ(static_cast<int16_t>(i), value);
56 }
57 }
58
59 // Test the PushBack method and the CopyFrom method. The Clear method is also
60 // invoked.
TEST_F(AudioVectorTest,PushBackAndCopy)61 TEST_F(AudioVectorTest, PushBackAndCopy) {
62 AudioVector vec;
63 AudioVector vec_copy;
64 vec.PushBack(array_, array_length());
65 vec.CopyTo(&vec_copy); // Copy from `vec` to `vec_copy`.
66 ASSERT_EQ(array_length(), vec.Size());
67 ASSERT_EQ(array_length(), vec_copy.Size());
68 for (size_t i = 0; i < array_length(); ++i) {
69 EXPECT_EQ(array_[i], vec[i]);
70 EXPECT_EQ(array_[i], vec_copy[i]);
71 }
72
73 // Clear `vec` and verify that it is empty.
74 vec.Clear();
75 EXPECT_TRUE(vec.Empty());
76
77 // Now copy the empty vector and verify that the copy becomes empty too.
78 vec.CopyTo(&vec_copy);
79 EXPECT_TRUE(vec_copy.Empty());
80 }
81
82 // Test the PushBack method with another AudioVector as input argument.
TEST_F(AudioVectorTest,PushBackVector)83 TEST_F(AudioVectorTest, PushBackVector) {
84 static const size_t kLength = 10;
85 AudioVector vec1(kLength);
86 AudioVector vec2(kLength);
87 // Set the first vector to [0, 1, ..., kLength - 1].
88 // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1].
89 for (size_t i = 0; i < kLength; ++i) {
90 vec1[i] = static_cast<int16_t>(i);
91 vec2[i] = static_cast<int16_t>(i + kLength);
92 }
93 // Append vec2 to the back of vec1.
94 vec1.PushBack(vec2);
95 ASSERT_EQ(2 * kLength, vec1.Size());
96 for (size_t i = 0; i < 2 * kLength; ++i) {
97 EXPECT_EQ(static_cast<int16_t>(i), vec1[i]);
98 }
99 }
100
101 // Test the PushFront method.
TEST_F(AudioVectorTest,PushFront)102 TEST_F(AudioVectorTest, PushFront) {
103 AudioVector vec;
104 vec.PushFront(array_, array_length());
105 ASSERT_EQ(array_length(), vec.Size());
106 for (size_t i = 0; i < array_length(); ++i) {
107 EXPECT_EQ(array_[i], vec[i]);
108 }
109 }
110
111 // Test the PushFront method with another AudioVector as input argument.
TEST_F(AudioVectorTest,PushFrontVector)112 TEST_F(AudioVectorTest, PushFrontVector) {
113 static const size_t kLength = 10;
114 AudioVector vec1(kLength);
115 AudioVector vec2(kLength);
116 // Set the first vector to [0, 1, ..., kLength - 1].
117 // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1].
118 for (size_t i = 0; i < kLength; ++i) {
119 vec1[i] = static_cast<int16_t>(i);
120 vec2[i] = static_cast<int16_t>(i + kLength);
121 }
122 // Prepend vec1 to the front of vec2.
123 vec2.PushFront(vec1);
124 ASSERT_EQ(2 * kLength, vec2.Size());
125 for (size_t i = 0; i < 2 * kLength; ++i) {
126 EXPECT_EQ(static_cast<int16_t>(i), vec2[i]);
127 }
128 }
129
130 // Test the PopFront method.
TEST_F(AudioVectorTest,PopFront)131 TEST_F(AudioVectorTest, PopFront) {
132 AudioVector vec;
133 vec.PushBack(array_, array_length());
134 vec.PopFront(1); // Remove one element.
135 EXPECT_EQ(array_length() - 1u, vec.Size());
136 for (size_t i = 0; i < array_length() - 1; ++i) {
137 EXPECT_EQ(static_cast<int16_t>(i + 1), vec[i]);
138 }
139 vec.PopFront(array_length()); // Remove more elements than vector size.
140 EXPECT_EQ(0u, vec.Size());
141 }
142
143 // Test the PopBack method.
TEST_F(AudioVectorTest,PopBack)144 TEST_F(AudioVectorTest, PopBack) {
145 AudioVector vec;
146 vec.PushBack(array_, array_length());
147 vec.PopBack(1); // Remove one element.
148 EXPECT_EQ(array_length() - 1u, vec.Size());
149 for (size_t i = 0; i < array_length() - 1; ++i) {
150 EXPECT_EQ(static_cast<int16_t>(i), vec[i]);
151 }
152 vec.PopBack(array_length()); // Remove more elements than vector size.
153 EXPECT_EQ(0u, vec.Size());
154 }
155
156 // Test the Extend method.
TEST_F(AudioVectorTest,Extend)157 TEST_F(AudioVectorTest, Extend) {
158 AudioVector vec;
159 vec.PushBack(array_, array_length());
160 vec.Extend(5); // Extend with 5 elements, which should all be zeros.
161 ASSERT_EQ(array_length() + 5u, vec.Size());
162 // Verify that all are zero.
163 for (size_t i = array_length(); i < array_length() + 5; ++i) {
164 EXPECT_EQ(0, vec[i]);
165 }
166 }
167
168 // Test the InsertAt method with an insert position in the middle of the vector.
TEST_F(AudioVectorTest,InsertAt)169 TEST_F(AudioVectorTest, InsertAt) {
170 AudioVector vec;
171 vec.PushBack(array_, array_length());
172 static const int kNewLength = 5;
173 int16_t new_array[kNewLength];
174 // Set array elements to {100, 101, 102, ... }.
175 for (int i = 0; i < kNewLength; ++i) {
176 new_array[i] = 100 + i;
177 }
178 int insert_position = 5;
179 vec.InsertAt(new_array, kNewLength, insert_position);
180 // Verify that the vector looks as follows:
181 // {0, 1, ..., `insert_position` - 1, 100, 101, ..., 100 + kNewLength - 1,
182 // `insert_position`, `insert_position` + 1, ..., kLength - 1}.
183 size_t pos = 0;
184 for (int i = 0; i < insert_position; ++i) {
185 EXPECT_EQ(array_[i], vec[pos]);
186 ++pos;
187 }
188 for (int i = 0; i < kNewLength; ++i) {
189 EXPECT_EQ(new_array[i], vec[pos]);
190 ++pos;
191 }
192 for (size_t i = insert_position; i < array_length(); ++i) {
193 EXPECT_EQ(array_[i], vec[pos]);
194 ++pos;
195 }
196 }
197
198 // Test the InsertZerosAt method with an insert position in the middle of the
199 // vector. Use the InsertAt method as reference.
TEST_F(AudioVectorTest,InsertZerosAt)200 TEST_F(AudioVectorTest, InsertZerosAt) {
201 AudioVector vec;
202 AudioVector vec_ref;
203 vec.PushBack(array_, array_length());
204 vec_ref.PushBack(array_, array_length());
205 static const int kNewLength = 5;
206 int insert_position = 5;
207 vec.InsertZerosAt(kNewLength, insert_position);
208 int16_t new_array[kNewLength] = {0}; // All zero elements.
209 vec_ref.InsertAt(new_array, kNewLength, insert_position);
210 // Verify that the vectors are identical.
211 ASSERT_EQ(vec_ref.Size(), vec.Size());
212 for (size_t i = 0; i < vec.Size(); ++i) {
213 EXPECT_EQ(vec_ref[i], vec[i]);
214 }
215 }
216
217 // Test the InsertAt method with an insert position at the start of the vector.
TEST_F(AudioVectorTest,InsertAtBeginning)218 TEST_F(AudioVectorTest, InsertAtBeginning) {
219 AudioVector vec;
220 vec.PushBack(array_, array_length());
221 static const int kNewLength = 5;
222 int16_t new_array[kNewLength];
223 // Set array elements to {100, 101, 102, ... }.
224 for (int i = 0; i < kNewLength; ++i) {
225 new_array[i] = 100 + i;
226 }
227 int insert_position = 0;
228 vec.InsertAt(new_array, kNewLength, insert_position);
229 // Verify that the vector looks as follows:
230 // {100, 101, ..., 100 + kNewLength - 1,
231 // 0, 1, ..., kLength - 1}.
232 size_t pos = 0;
233 for (int i = 0; i < kNewLength; ++i) {
234 EXPECT_EQ(new_array[i], vec[pos]);
235 ++pos;
236 }
237 for (size_t i = insert_position; i < array_length(); ++i) {
238 EXPECT_EQ(array_[i], vec[pos]);
239 ++pos;
240 }
241 }
242
243 // Test the InsertAt method with an insert position at the end of the vector.
TEST_F(AudioVectorTest,InsertAtEnd)244 TEST_F(AudioVectorTest, InsertAtEnd) {
245 AudioVector vec;
246 vec.PushBack(array_, array_length());
247 static const int kNewLength = 5;
248 int16_t new_array[kNewLength];
249 // Set array elements to {100, 101, 102, ... }.
250 for (int i = 0; i < kNewLength; ++i) {
251 new_array[i] = 100 + i;
252 }
253 int insert_position = rtc::checked_cast<int>(array_length());
254 vec.InsertAt(new_array, kNewLength, insert_position);
255 // Verify that the vector looks as follows:
256 // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }.
257 size_t pos = 0;
258 for (size_t i = 0; i < array_length(); ++i) {
259 EXPECT_EQ(array_[i], vec[pos]);
260 ++pos;
261 }
262 for (int i = 0; i < kNewLength; ++i) {
263 EXPECT_EQ(new_array[i], vec[pos]);
264 ++pos;
265 }
266 }
267
268 // Test the InsertAt method with an insert position beyond the end of the
269 // vector. Verify that a position beyond the end of the vector does not lead to
270 // an error. The expected outcome is the same as if the vector end was used as
271 // input position. That is, the input position should be capped at the maximum
272 // allowed value.
TEST_F(AudioVectorTest,InsertBeyondEnd)273 TEST_F(AudioVectorTest, InsertBeyondEnd) {
274 AudioVector vec;
275 vec.PushBack(array_, array_length());
276 static const int kNewLength = 5;
277 int16_t new_array[kNewLength];
278 // Set array elements to {100, 101, 102, ... }.
279 for (int i = 0; i < kNewLength; ++i) {
280 new_array[i] = 100 + i;
281 }
282 int insert_position =
283 rtc::checked_cast<int>(array_length() + 10); // Too large.
284 vec.InsertAt(new_array, kNewLength, insert_position);
285 // Verify that the vector looks as follows:
286 // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }.
287 size_t pos = 0;
288 for (size_t i = 0; i < array_length(); ++i) {
289 EXPECT_EQ(array_[i], vec[pos]);
290 ++pos;
291 }
292 for (int i = 0; i < kNewLength; ++i) {
293 EXPECT_EQ(new_array[i], vec[pos]);
294 ++pos;
295 }
296 }
297
298 // Test the OverwriteAt method with a position such that all of the new values
299 // fit within the old vector.
TEST_F(AudioVectorTest,OverwriteAt)300 TEST_F(AudioVectorTest, OverwriteAt) {
301 AudioVector vec;
302 vec.PushBack(array_, array_length());
303 static const int kNewLength = 5;
304 int16_t new_array[kNewLength];
305 // Set array elements to {100, 101, 102, ... }.
306 for (int i = 0; i < kNewLength; ++i) {
307 new_array[i] = 100 + i;
308 }
309 size_t insert_position = 2;
310 vec.OverwriteAt(new_array, kNewLength, insert_position);
311 // Verify that the vector looks as follows:
312 // {0, ..., `insert_position` - 1, 100, 101, ..., 100 + kNewLength - 1,
313 // `insert_position`, `insert_position` + 1, ..., kLength - 1}.
314 size_t pos = 0;
315 for (pos = 0; pos < insert_position; ++pos) {
316 EXPECT_EQ(array_[pos], vec[pos]);
317 }
318 for (int i = 0; i < kNewLength; ++i) {
319 EXPECT_EQ(new_array[i], vec[pos]);
320 ++pos;
321 }
322 for (; pos < array_length(); ++pos) {
323 EXPECT_EQ(array_[pos], vec[pos]);
324 }
325 }
326
327 // Test the OverwriteAt method with a position such that some of the new values
328 // extend beyond the end of the current vector. This is valid, and the vector is
329 // expected to expand to accommodate the new values.
TEST_F(AudioVectorTest,OverwriteBeyondEnd)330 TEST_F(AudioVectorTest, OverwriteBeyondEnd) {
331 AudioVector vec;
332 vec.PushBack(array_, array_length());
333 static const int kNewLength = 5;
334 int16_t new_array[kNewLength];
335 // Set array elements to {100, 101, 102, ... }.
336 for (int i = 0; i < kNewLength; ++i) {
337 new_array[i] = 100 + i;
338 }
339 int insert_position = rtc::checked_cast<int>(array_length() - 2);
340 vec.OverwriteAt(new_array, kNewLength, insert_position);
341 ASSERT_EQ(array_length() - 2u + kNewLength, vec.Size());
342 // Verify that the vector looks as follows:
343 // {0, ..., `insert_position` - 1, 100, 101, ..., 100 + kNewLength - 1,
344 // `insert_position`, `insert_position` + 1, ..., kLength - 1}.
345 int pos = 0;
346 for (pos = 0; pos < insert_position; ++pos) {
347 EXPECT_EQ(array_[pos], vec[pos]);
348 }
349 for (int i = 0; i < kNewLength; ++i) {
350 EXPECT_EQ(new_array[i], vec[pos]);
351 ++pos;
352 }
353 // Verify that we checked to the end of `vec`.
354 EXPECT_EQ(vec.Size(), static_cast<size_t>(pos));
355 }
356
TEST_F(AudioVectorTest,CrossFade)357 TEST_F(AudioVectorTest, CrossFade) {
358 static const size_t kLength = 100;
359 static const size_t kFadeLength = 10;
360 AudioVector vec1(kLength);
361 AudioVector vec2(kLength);
362 // Set all vector elements to 0 in `vec1` and 100 in `vec2`.
363 for (size_t i = 0; i < kLength; ++i) {
364 vec1[i] = 0;
365 vec2[i] = 100;
366 }
367 vec1.CrossFade(vec2, kFadeLength);
368 ASSERT_EQ(2 * kLength - kFadeLength, vec1.Size());
369 // First part untouched.
370 for (size_t i = 0; i < kLength - kFadeLength; ++i) {
371 EXPECT_EQ(0, vec1[i]);
372 }
373 // Check mixing zone.
374 for (size_t i = 0; i < kFadeLength; ++i) {
375 EXPECT_NEAR((i + 1) * 100 / (kFadeLength + 1),
376 vec1[kLength - kFadeLength + i], 1);
377 }
378 // Second part untouched.
379 for (size_t i = kLength; i < vec1.Size(); ++i) {
380 EXPECT_EQ(100, vec1[i]);
381 }
382 }
383
384 } // namespace webrtc
385