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 
312 INSTANTIATE_TEST_SUITE_P(TestNumChannels,
313                          AudioMultiVectorTest,
314                          ::testing::Values(static_cast<size_t>(1),
315                                            static_cast<size_t>(2),
316                                            static_cast<size_t>(5)));
317 }  // namespace webrtc
318