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_multi_vector.h"
12
13 #include <stdlib.h>
14
15 #include <string>
16 #include <vector>
17
18 #include "rtc_base/numerics/safe_conversions.h"
19 #include "test/gtest.h"
20
21 namespace webrtc {
22
23 // This is a value-parameterized test. The test cases are instantiated with
24 // different values for the test parameter, which is used to determine the
25 // number of channels in the AudioMultiBuffer. Note that it is not possible
26 // to combine typed testing with value-parameterized testing, and since the
27 // tests for AudioVector already covers a number of different type parameters,
28 // this test focuses on testing different number of channels, and keeping the
29 // value type constant.
30
31 class AudioMultiVectorTest : public ::testing::TestWithParam<size_t> {
32 protected:
AudioMultiVectorTest()33 AudioMultiVectorTest()
34 : num_channels_(GetParam()), // Get the test parameter.
35 array_interleaved_(num_channels_ * array_length()) {}
36
37 ~AudioMultiVectorTest() = default;
38
SetUp()39 virtual void SetUp() {
40 // Populate test arrays.
41 for (size_t i = 0; i < array_length(); ++i) {
42 array_[i] = static_cast<int16_t>(i);
43 }
44 int16_t* ptr = array_interleaved_.data();
45 // Write 100, 101, 102, ... for first channel.
46 // Write 200, 201, 202, ... for second channel.
47 // And so on.
48 for (size_t i = 0; i < array_length(); ++i) {
49 for (size_t j = 1; j <= num_channels_; ++j) {
50 *ptr = rtc::checked_cast<int16_t>(j * 100 + i);
51 ++ptr;
52 }
53 }
54 }
55
array_length() const56 size_t array_length() const { return sizeof(array_) / sizeof(array_[0]); }
57
58 const size_t num_channels_;
59 int16_t array_[10];
60 std::vector<int16_t> array_interleaved_;
61 };
62
63 // Create and destroy AudioMultiVector objects, both empty and with a predefined
64 // length.
TEST_P(AudioMultiVectorTest,CreateAndDestroy)65 TEST_P(AudioMultiVectorTest, CreateAndDestroy) {
66 AudioMultiVector vec1(num_channels_);
67 EXPECT_TRUE(vec1.Empty());
68 EXPECT_EQ(num_channels_, vec1.Channels());
69 EXPECT_EQ(0u, vec1.Size());
70
71 size_t initial_size = 17;
72 AudioMultiVector vec2(num_channels_, initial_size);
73 EXPECT_FALSE(vec2.Empty());
74 EXPECT_EQ(num_channels_, vec2.Channels());
75 EXPECT_EQ(initial_size, vec2.Size());
76 }
77
78 // Test the subscript operator [] for getting and setting.
TEST_P(AudioMultiVectorTest,SubscriptOperator)79 TEST_P(AudioMultiVectorTest, SubscriptOperator) {
80 AudioMultiVector vec(num_channels_, array_length());
81 for (size_t channel = 0; channel < num_channels_; ++channel) {
82 for (size_t i = 0; i < array_length(); ++i) {
83 vec[channel][i] = static_cast<int16_t>(i);
84 // Make sure to use the const version.
85 const AudioVector& audio_vec = vec[channel];
86 EXPECT_EQ(static_cast<int16_t>(i), audio_vec[i]);
87 }
88 }
89 }
90
91 // Test the PushBackInterleaved method and the CopyFrom method. The Clear
92 // method is also invoked.
TEST_P(AudioMultiVectorTest,PushBackInterleavedAndCopy)93 TEST_P(AudioMultiVectorTest, PushBackInterleavedAndCopy) {
94 AudioMultiVector vec(num_channels_);
95 vec.PushBackInterleaved(array_interleaved_);
96 AudioMultiVector vec_copy(num_channels_);
97 vec.CopyTo(&vec_copy); // Copy from `vec` to `vec_copy`.
98 ASSERT_EQ(num_channels_, vec.Channels());
99 ASSERT_EQ(array_length(), vec.Size());
100 ASSERT_EQ(num_channels_, vec_copy.Channels());
101 ASSERT_EQ(array_length(), vec_copy.Size());
102 for (size_t channel = 0; channel < vec.Channels(); ++channel) {
103 for (size_t i = 0; i < array_length(); ++i) {
104 EXPECT_EQ(static_cast<int16_t>((channel + 1) * 100 + i), vec[channel][i]);
105 EXPECT_EQ(vec[channel][i], vec_copy[channel][i]);
106 }
107 }
108
109 // Clear `vec` and verify that it is empty.
110 vec.Clear();
111 EXPECT_TRUE(vec.Empty());
112
113 // Now copy the empty vector and verify that the copy becomes empty too.
114 vec.CopyTo(&vec_copy);
115 EXPECT_TRUE(vec_copy.Empty());
116 }
117
118 // Try to copy to a NULL pointer. Nothing should happen.
TEST_P(AudioMultiVectorTest,CopyToNull)119 TEST_P(AudioMultiVectorTest, CopyToNull) {
120 AudioMultiVector vec(num_channels_);
121 AudioMultiVector* vec_copy = NULL;
122 vec.PushBackInterleaved(array_interleaved_);
123 vec.CopyTo(vec_copy);
124 }
125
126 // Test the PushBack method with another AudioMultiVector as input argument.
TEST_P(AudioMultiVectorTest,PushBackVector)127 TEST_P(AudioMultiVectorTest, PushBackVector) {
128 AudioMultiVector vec1(num_channels_, array_length());
129 AudioMultiVector vec2(num_channels_, array_length());
130 // Set the first vector to [0, 1, ..., array_length() - 1] +
131 // 100 * channel_number.
132 // Set the second vector to [array_length(), array_length() + 1, ...,
133 // 2 * array_length() - 1] + 100 * channel_number.
134 for (size_t channel = 0; channel < num_channels_; ++channel) {
135 for (size_t i = 0; i < array_length(); ++i) {
136 vec1[channel][i] = static_cast<int16_t>(i + 100 * channel);
137 vec2[channel][i] =
138 static_cast<int16_t>(i + 100 * channel + array_length());
139 }
140 }
141 // Append vec2 to the back of vec1.
142 vec1.PushBack(vec2);
143 ASSERT_EQ(2u * array_length(), vec1.Size());
144 for (size_t channel = 0; channel < num_channels_; ++channel) {
145 for (size_t i = 0; i < 2 * array_length(); ++i) {
146 EXPECT_EQ(static_cast<int16_t>(i + 100 * channel), vec1[channel][i]);
147 }
148 }
149 }
150
151 // Test the PushBackFromIndex method.
TEST_P(AudioMultiVectorTest,PushBackFromIndex)152 TEST_P(AudioMultiVectorTest, PushBackFromIndex) {
153 AudioMultiVector vec1(num_channels_);
154 vec1.PushBackInterleaved(array_interleaved_);
155 AudioMultiVector vec2(num_channels_);
156
157 // Append vec1 to the back of vec2 (which is empty). Read vec1 from the second
158 // last element.
159 vec2.PushBackFromIndex(vec1, array_length() - 2);
160 ASSERT_EQ(2u, vec2.Size());
161 for (size_t channel = 0; channel < num_channels_; ++channel) {
162 for (size_t i = 0; i < 2; ++i) {
163 EXPECT_EQ(array_interleaved_[channel +
164 num_channels_ * (array_length() - 2 + i)],
165 vec2[channel][i]);
166 }
167 }
168 }
169
170 // Starts with pushing some values to the vector, then test the Zeros method.
TEST_P(AudioMultiVectorTest,Zeros)171 TEST_P(AudioMultiVectorTest, Zeros) {
172 AudioMultiVector vec(num_channels_);
173 vec.PushBackInterleaved(array_interleaved_);
174 vec.Zeros(2 * array_length());
175 ASSERT_EQ(num_channels_, vec.Channels());
176 ASSERT_EQ(2u * array_length(), vec.Size());
177 for (size_t channel = 0; channel < num_channels_; ++channel) {
178 for (size_t i = 0; i < 2 * array_length(); ++i) {
179 EXPECT_EQ(0, vec[channel][i]);
180 }
181 }
182 }
183
184 // Test the ReadInterleaved method
TEST_P(AudioMultiVectorTest,ReadInterleaved)185 TEST_P(AudioMultiVectorTest, ReadInterleaved) {
186 AudioMultiVector vec(num_channels_);
187 vec.PushBackInterleaved(array_interleaved_);
188 int16_t* output = new int16_t[array_interleaved_.size()];
189 // Read 5 samples.
190 size_t read_samples = 5;
191 EXPECT_EQ(num_channels_ * read_samples,
192 vec.ReadInterleaved(read_samples, output));
193 EXPECT_EQ(0, memcmp(array_interleaved_.data(), output,
194 read_samples * sizeof(int16_t)));
195
196 // Read too many samples. Expect to get all samples from the vector.
197 EXPECT_EQ(array_interleaved_.size(),
198 vec.ReadInterleaved(array_length() + 1, output));
199 EXPECT_EQ(0, memcmp(array_interleaved_.data(), output,
200 read_samples * sizeof(int16_t)));
201
202 delete[] output;
203 }
204
205 // Test the PopFront method.
TEST_P(AudioMultiVectorTest,PopFront)206 TEST_P(AudioMultiVectorTest, PopFront) {
207 AudioMultiVector vec(num_channels_);
208 vec.PushBackInterleaved(array_interleaved_);
209 vec.PopFront(1); // Remove one element from each channel.
210 ASSERT_EQ(array_length() - 1u, vec.Size());
211 // Let `ptr` point to the second element of the first channel in the
212 // interleaved array.
213 int16_t* ptr = &array_interleaved_[num_channels_];
214 for (size_t i = 0; i < array_length() - 1; ++i) {
215 for (size_t channel = 0; channel < num_channels_; ++channel) {
216 EXPECT_EQ(*ptr, vec[channel][i]);
217 ++ptr;
218 }
219 }
220 vec.PopFront(array_length()); // Remove more elements than vector size.
221 EXPECT_EQ(0u, vec.Size());
222 }
223
224 // Test the PopBack method.
TEST_P(AudioMultiVectorTest,PopBack)225 TEST_P(AudioMultiVectorTest, PopBack) {
226 AudioMultiVector vec(num_channels_);
227 vec.PushBackInterleaved(array_interleaved_);
228 vec.PopBack(1); // Remove one element from each channel.
229 ASSERT_EQ(array_length() - 1u, vec.Size());
230 // Let `ptr` point to the first element of the first channel in the
231 // interleaved array.
232 int16_t* ptr = array_interleaved_.data();
233 for (size_t i = 0; i < array_length() - 1; ++i) {
234 for (size_t channel = 0; channel < num_channels_; ++channel) {
235 EXPECT_EQ(*ptr, vec[channel][i]);
236 ++ptr;
237 }
238 }
239 vec.PopBack(array_length()); // Remove more elements than vector size.
240 EXPECT_EQ(0u, vec.Size());
241 }
242
243 // Test the AssertSize method.
TEST_P(AudioMultiVectorTest,AssertSize)244 TEST_P(AudioMultiVectorTest, AssertSize) {
245 AudioMultiVector vec(num_channels_, array_length());
246 EXPECT_EQ(array_length(), vec.Size());
247 // Start with asserting with smaller sizes than already allocated.
248 vec.AssertSize(0);
249 vec.AssertSize(array_length() - 1);
250 // Nothing should have changed.
251 EXPECT_EQ(array_length(), vec.Size());
252 // Assert with one element longer than already allocated.
253 vec.AssertSize(array_length() + 1);
254 // Expect vector to have grown.
255 EXPECT_EQ(array_length() + 1, vec.Size());
256 // Also check the individual AudioVectors.
257 for (size_t channel = 0; channel < vec.Channels(); ++channel) {
258 EXPECT_EQ(array_length() + 1u, vec[channel].Size());
259 }
260 }
261
262 // Test the PushBack method with another AudioMultiVector as input argument.
TEST_P(AudioMultiVectorTest,OverwriteAt)263 TEST_P(AudioMultiVectorTest, OverwriteAt) {
264 AudioMultiVector vec1(num_channels_);
265 vec1.PushBackInterleaved(array_interleaved_);
266 AudioMultiVector vec2(num_channels_);
267 vec2.Zeros(3); // 3 zeros in each channel.
268 // Overwrite vec2 at position 5.
269 vec1.OverwriteAt(vec2, 3, 5);
270 // Verify result.
271 // Length remains the same.
272 ASSERT_EQ(array_length(), vec1.Size());
273 int16_t* ptr = array_interleaved_.data();
274 for (size_t i = 0; i < array_length() - 1; ++i) {
275 for (size_t channel = 0; channel < num_channels_; ++channel) {
276 if (i >= 5 && i <= 7) {
277 // Elements 5, 6, 7 should have been replaced with zeros.
278 EXPECT_EQ(0, vec1[channel][i]);
279 } else {
280 EXPECT_EQ(*ptr, vec1[channel][i]);
281 }
282 ++ptr;
283 }
284 }
285 }
286
287 // Test the CopyChannel method, when the test is instantiated with at least two
288 // channels.
TEST_P(AudioMultiVectorTest,CopyChannel)289 TEST_P(AudioMultiVectorTest, CopyChannel) {
290 if (num_channels_ < 2)
291 return;
292
293 AudioMultiVector vec(num_channels_);
294 vec.PushBackInterleaved(array_interleaved_);
295 // Create a reference copy.
296 AudioMultiVector ref(num_channels_);
297 ref.PushBack(vec);
298 // Copy from first to last channel.
299 vec.CopyChannel(0, num_channels_ - 1);
300 // Verify that the first and last channels are identical; the others should
301 // be left untouched.
302 for (size_t i = 0; i < array_length(); ++i) {
303 // Verify that all but the last channel are untouched.
304 for (size_t channel = 0; channel < num_channels_ - 1; ++channel) {
305 EXPECT_EQ(ref[channel][i], vec[channel][i]);
306 }
307 // Verify that the last and the first channels are identical.
308 EXPECT_EQ(vec[0][i], vec[num_channels_ - 1][i]);
309 }
310 }
311
TEST_P(AudioMultiVectorTest,PushBackEmptyArray)312 TEST_P(AudioMultiVectorTest, PushBackEmptyArray) {
313 AudioMultiVector vec(num_channels_);
314 vec.PushBackInterleaved({});
315 EXPECT_TRUE(vec.Empty());
316 }
317
318 INSTANTIATE_TEST_SUITE_P(TestNumChannels,
319 AudioMultiVectorTest,
320 ::testing::Values(static_cast<size_t>(1),
321 static_cast<size_t>(2),
322 static_cast<size_t>(5)));
323 } // namespace webrtc
324