• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/strings/stringprintf.h"
6 #include "base/time/time.h"
7 #include "build/build_config.h"
8 #include "media/audio/audio_parameters.h"
9 #include "media/base/audio_bus.h"
10 #include "media/base/channel_layout.h"
11 #include "media/base/fake_audio_render_callback.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace media {
15 
16 static const int kChannels = 6;
17 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1;
18 // Use a buffer size which is intentionally not a multiple of kChannelAlignment.
19 static const int kFrameCount = media::AudioBus::kChannelAlignment * 32 - 1;
20 static const int kSampleRate = 48000;
21 
22 class AudioBusTest : public testing::Test {
23  public:
AudioBusTest()24   AudioBusTest() {}
~AudioBusTest()25   virtual ~AudioBusTest() {
26     for (size_t i = 0; i < data_.size(); ++i)
27       base::AlignedFree(data_[i]);
28   }
29 
30   // Validate parameters returned by AudioBus v.s. the constructed parameters.
VerifyParams(AudioBus * bus)31   void VerifyParams(AudioBus* bus) {
32     EXPECT_EQ(kChannels, bus->channels());
33     EXPECT_EQ(kFrameCount, bus->frames());
34   }
35 
VerifyValue(const float data[],int size,float value)36   void VerifyValue(const float data[], int size, float value) {
37     for (int i = 0; i < size; ++i)
38       ASSERT_FLOAT_EQ(value, data[i]) << "i=" << i;
39   }
40 
41   // Verify values for each channel in |result| are within |epsilon| of
42   // |expected|.  If |epsilon| exactly equals 0, uses FLOAT_EQ macro.
VerifyBusWithEpsilon(const AudioBus * result,const AudioBus * expected,float epsilon)43   void VerifyBusWithEpsilon(const AudioBus* result, const AudioBus* expected,
44                             float epsilon) {
45     ASSERT_EQ(expected->channels(), result->channels());
46     ASSERT_EQ(expected->frames(), result->frames());
47     for (int ch = 0; ch < result->channels(); ++ch) {
48       for (int i = 0; i < result->frames(); ++i) {
49         SCOPED_TRACE(base::StringPrintf("ch=%d, i=%d", ch, i));
50         if (epsilon == 0) {
51           ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]);
52         } else {
53           ASSERT_NEAR(expected->channel(ch)[i], result->channel(ch)[i],
54                       epsilon);
55         }
56       }
57     }
58   }
59 
60   // Verify values for each channel in |result| against |expected|.
VerifyBus(const AudioBus * result,const AudioBus * expected)61   void VerifyBus(const AudioBus* result, const AudioBus* expected) {
62     VerifyBusWithEpsilon(result, expected, 0);
63   }
64 
65   // Read and write to the full extent of the allocated channel data.  Also test
66   // the Zero() method and verify it does as advertised.  Also test data if data
67   // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.h).
VerifyChannelData(AudioBus * bus)68   void VerifyChannelData(AudioBus* bus) {
69     for (int i = 0; i < bus->channels(); ++i) {
70       ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(
71           bus->channel(i)) & (AudioBus::kChannelAlignment - 1));
72       std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i);
73     }
74 
75     for (int i = 0; i < bus->channels(); ++i)
76       VerifyValue(bus->channel(i), bus->frames(), i);
77 
78     bus->Zero();
79     for (int i = 0; i < bus->channels(); ++i)
80       VerifyValue(bus->channel(i), bus->frames(), 0);
81   }
82 
83   // Verify copying to and from |bus1| and |bus2|.
CopyTest(AudioBus * bus1,AudioBus * bus2)84   void CopyTest(AudioBus* bus1, AudioBus* bus2) {
85     // Fill |bus1| with dummy data.
86     for (int i = 0; i < bus1->channels(); ++i)
87       std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i);
88 
89     // Verify copy from |bus1| to |bus2|.
90     bus2->Zero();
91     bus1->CopyTo(bus2);
92     VerifyBus(bus1, bus2);
93 
94     // Verify copy from |bus2| to |bus1|.
95     bus1->Zero();
96     bus2->CopyTo(bus1);
97     VerifyBus(bus2, bus1);
98   }
99 
100  protected:
101   std::vector<float*> data_;
102 
103   DISALLOW_COPY_AND_ASSIGN(AudioBusTest);
104 };
105 
106 // Verify basic Create(...) method works as advertised.
TEST_F(AudioBusTest,Create)107 TEST_F(AudioBusTest, Create) {
108   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
109   VerifyParams(bus.get());
110   VerifyChannelData(bus.get());
111 }
112 
113 // Verify Create(...) using AudioParameters works as advertised.
TEST_F(AudioBusTest,CreateUsingAudioParameters)114 TEST_F(AudioBusTest, CreateUsingAudioParameters) {
115   scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters(
116       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
117       kFrameCount));
118   VerifyParams(bus.get());
119   VerifyChannelData(bus.get());
120 }
121 
122 // Verify an AudioBus created via wrapping a vector works as advertised.
TEST_F(AudioBusTest,WrapVector)123 TEST_F(AudioBusTest, WrapVector) {
124   data_.reserve(kChannels);
125   for (int i = 0; i < kChannels; ++i) {
126     data_.push_back(static_cast<float*>(base::AlignedAlloc(
127         sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
128   }
129 
130   scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_);
131   VerifyParams(bus.get());
132   VerifyChannelData(bus.get());
133 }
134 
135 // Verify an AudioBus created via wrapping a memory block works as advertised.
TEST_F(AudioBusTest,WrapMemory)136 TEST_F(AudioBusTest, WrapMemory) {
137   AudioParameters params(
138       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
139       kFrameCount);
140   int data_size = AudioBus::CalculateMemorySize(params);
141   scoped_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>(
142       base::AlignedAlloc(data_size, AudioBus::kChannelAlignment)));
143 
144   // Fill the memory with a test value we can check for after wrapping.
145   static const float kTestValue = 3;
146   std::fill(
147       data.get(), data.get() + data_size / sizeof(*data.get()), kTestValue);
148 
149   scoped_ptr<AudioBus> bus = AudioBus::WrapMemory(params, data.get());
150   // Verify the test value we filled prior to wrapping.
151   for (int i = 0; i < bus->channels(); ++i)
152     VerifyValue(bus->channel(i), bus->frames(), kTestValue);
153   VerifyParams(bus.get());
154   VerifyChannelData(bus.get());
155 
156   // Verify the channel vectors lie within the provided memory block.
157   EXPECT_GE(bus->channel(0), data.get());
158   EXPECT_LT(bus->channel(bus->channels() - 1) + bus->frames(),
159             data.get() + data_size / sizeof(*data.get()));
160 }
161 
162 // Simulate a shared memory transfer and verify results.
TEST_F(AudioBusTest,CopyTo)163 TEST_F(AudioBusTest, CopyTo) {
164   // Create one bus with AudioParameters and the other through direct values to
165   // test for parity between the Create() functions.
166   AudioParameters params(
167       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
168       kFrameCount);
169   scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount);
170   scoped_ptr<AudioBus> bus2 = AudioBus::Create(params);
171 
172   {
173     SCOPED_TRACE("Created");
174     CopyTest(bus1.get(), bus2.get());
175   }
176   {
177     SCOPED_TRACE("Wrapped Vector");
178     // Try a copy to an AudioBus wrapping a vector.
179     data_.reserve(kChannels);
180     for (int i = 0; i < kChannels; ++i) {
181       data_.push_back(static_cast<float*>(base::AlignedAlloc(
182           sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
183     }
184 
185     bus2 = AudioBus::WrapVector(kFrameCount, data_);
186     CopyTest(bus1.get(), bus2.get());
187   }
188   {
189     SCOPED_TRACE("Wrapped Memory");
190     // Try a copy to an AudioBus wrapping a memory block.
191     scoped_ptr<float, base::AlignedFreeDeleter> data(
192         static_cast<float*>(base::AlignedAlloc(
193             AudioBus::CalculateMemorySize(params),
194             AudioBus::kChannelAlignment)));
195 
196     bus2 = AudioBus::WrapMemory(params, data.get());
197     CopyTest(bus1.get(), bus2.get());
198   }
199 }
200 
201 // Verify Zero() and ZeroFrames(...) utility methods work as advertised.
TEST_F(AudioBusTest,Zero)202 TEST_F(AudioBusTest, Zero) {
203   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
204 
205   // Fill the bus with dummy data.
206   for (int i = 0; i < bus->channels(); ++i)
207     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
208 
209   // Zero first half the frames of each channel.
210   bus->ZeroFrames(kFrameCount / 2);
211   for (int i = 0; i < bus->channels(); ++i) {
212     SCOPED_TRACE("First Half Zero");
213     VerifyValue(bus->channel(i), kFrameCount / 2, 0);
214     VerifyValue(bus->channel(i) + kFrameCount / 2,
215                 kFrameCount - kFrameCount / 2, i + 1);
216   }
217 
218   // Fill the bus with dummy data.
219   for (int i = 0; i < bus->channels(); ++i)
220     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
221 
222   // Zero the last half of the frames.
223   bus->ZeroFramesPartial(kFrameCount / 2, kFrameCount - kFrameCount / 2);
224   for (int i = 0; i < bus->channels(); ++i) {
225     SCOPED_TRACE("Last Half Zero");
226     VerifyValue(bus->channel(i) + kFrameCount / 2,
227                 kFrameCount - kFrameCount / 2, 0);
228     VerifyValue(bus->channel(i), kFrameCount / 2, i + 1);
229   }
230 
231   // Fill the bus with dummy data.
232   for (int i = 0; i < bus->channels(); ++i)
233     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
234 
235   // Zero all the frames of each channel.
236   bus->Zero();
237   for (int i = 0; i < bus->channels(); ++i) {
238     SCOPED_TRACE("All Zero");
239     VerifyValue(bus->channel(i), bus->frames(), 0);
240   }
241 }
242 
243 // Each test vector represents two channels of data in the following arbitrary
244 // layout: <min, zero, max, min, max / 2, min / 2, zero, max, zero, zero>.
245 static const int kTestVectorSize = 10;
246 static const uint8 kTestVectorUint8[kTestVectorSize] = {
247     0, -kint8min, kuint8max, 0, kint8max / 2 + 128, kint8min / 2 + 128,
248     -kint8min, kuint8max, -kint8min, -kint8min };
249 static const int16 kTestVectorInt16[kTestVectorSize] = {
250     kint16min, 0, kint16max, kint16min, kint16max / 2, kint16min / 2,
251     0, kint16max, 0, 0 };
252 static const int32 kTestVectorInt32[kTestVectorSize] = {
253     kint32min, 0, kint32max, kint32min, kint32max / 2, kint32min / 2,
254     0, kint32max, 0, 0 };
255 
256 // Expected results.
257 static const int kTestVectorFrames = kTestVectorSize / 2;
258 static const float kTestVectorResult[][kTestVectorFrames] = {
259     { -1, 1, 0.5, 0, 0 }, { 0, -1, -0.5, 1, 0 }};
260 static const int kTestVectorChannels = arraysize(kTestVectorResult);
261 
262 // Verify FromInterleaved() deinterleaves audio in supported formats correctly.
TEST_F(AudioBusTest,FromInterleaved)263 TEST_F(AudioBusTest, FromInterleaved) {
264   scoped_ptr<AudioBus> bus = AudioBus::Create(
265       kTestVectorChannels, kTestVectorFrames);
266   scoped_ptr<AudioBus> expected = AudioBus::Create(
267       kTestVectorChannels, kTestVectorFrames);
268   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
269     memcpy(expected->channel(ch), kTestVectorResult[ch],
270            kTestVectorFrames * sizeof(*expected->channel(ch)));
271   }
272   {
273     SCOPED_TRACE("uint8");
274     bus->Zero();
275     bus->FromInterleaved(
276         kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8));
277     // Biased uint8 calculations have poor precision, so the epsilon here is
278     // slightly more permissive than int16 and int32 calculations.
279     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint8max - 1));
280   }
281   {
282     SCOPED_TRACE("int16");
283     bus->Zero();
284     bus->FromInterleaved(
285         kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16));
286     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint16max + 1.0f));
287   }
288   {
289     SCOPED_TRACE("int32");
290     bus->Zero();
291     bus->FromInterleaved(
292         kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32));
293     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint32max + 1.0f));
294   }
295 }
296 
297 // Verify FromInterleavedPartial() deinterleaves audio correctly.
TEST_F(AudioBusTest,FromInterleavedPartial)298 TEST_F(AudioBusTest, FromInterleavedPartial) {
299   // Only deinterleave the middle two frames in each channel.
300   static const int kPartialStart = 1;
301   static const int kPartialFrames = 2;
302   ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames);
303 
304   scoped_ptr<AudioBus> bus = AudioBus::Create(
305       kTestVectorChannels, kTestVectorFrames);
306   scoped_ptr<AudioBus> expected = AudioBus::Create(
307       kTestVectorChannels, kTestVectorFrames);
308   expected->Zero();
309   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
310     memcpy(expected->channel(ch) + kPartialStart,
311            kTestVectorResult[ch] + kPartialStart,
312            kPartialFrames * sizeof(*expected->channel(ch)));
313   }
314 
315   bus->Zero();
316   bus->FromInterleavedPartial(
317       kTestVectorInt32 + kPartialStart * bus->channels(), kPartialStart,
318       kPartialFrames, sizeof(*kTestVectorInt32));
319   VerifyBus(bus.get(), expected.get());
320 }
321 
322 // Verify ToInterleaved() interleaves audio in suported formats correctly.
TEST_F(AudioBusTest,ToInterleaved)323 TEST_F(AudioBusTest, ToInterleaved) {
324   scoped_ptr<AudioBus> bus = AudioBus::Create(
325       kTestVectorChannels, kTestVectorFrames);
326   // Fill the bus with our test vector.
327   for (int ch = 0; ch < bus->channels(); ++ch) {
328     memcpy(bus->channel(ch), kTestVectorResult[ch],
329            kTestVectorFrames * sizeof(*bus->channel(ch)));
330   }
331   {
332     SCOPED_TRACE("uint8");
333     uint8 test_array[arraysize(kTestVectorUint8)];
334     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array);
335     ASSERT_EQ(memcmp(
336         test_array, kTestVectorUint8, sizeof(kTestVectorUint8)), 0);
337   }
338   {
339     SCOPED_TRACE("int16");
340     int16 test_array[arraysize(kTestVectorInt16)];
341     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array);
342     ASSERT_EQ(memcmp(
343         test_array, kTestVectorInt16, sizeof(kTestVectorInt16)), 0);
344   }
345   {
346     SCOPED_TRACE("int32");
347     int32 test_array[arraysize(kTestVectorInt32)];
348     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array);
349 
350     // Some compilers get better precision than others on the half-max test, so
351     // let the test pass with an off by one check on the half-max.
352     int32 fixed_test_array[arraysize(kTestVectorInt32)];
353     memcpy(fixed_test_array, kTestVectorInt32, sizeof(kTestVectorInt32));
354     ASSERT_EQ(fixed_test_array[4], kint32max / 2);
355     fixed_test_array[4]++;
356 
357     ASSERT_TRUE(
358        memcmp(test_array, kTestVectorInt32, sizeof(kTestVectorInt32)) == 0 ||
359        memcmp(test_array, fixed_test_array, sizeof(fixed_test_array)) == 0);
360   }
361 }
362 
363 // Verify ToInterleavedPartial() interleaves audio correctly.
TEST_F(AudioBusTest,ToInterleavedPartial)364 TEST_F(AudioBusTest, ToInterleavedPartial) {
365   // Only interleave the middle two frames in each channel.
366   static const int kPartialStart = 1;
367   static const int kPartialFrames = 2;
368   ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames);
369 
370   scoped_ptr<AudioBus> expected = AudioBus::Create(
371       kTestVectorChannels, kTestVectorFrames);
372   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
373     memcpy(expected->channel(ch), kTestVectorResult[ch],
374            kTestVectorFrames * sizeof(*expected->channel(ch)));
375   }
376 
377   int16 test_array[arraysize(kTestVectorInt16)];
378   expected->ToInterleavedPartial(
379       kPartialStart, kPartialFrames, sizeof(*kTestVectorInt16), test_array);
380   ASSERT_EQ(memcmp(
381       test_array, kTestVectorInt16 + kPartialStart * kTestVectorChannels,
382       kPartialFrames * sizeof(*kTestVectorInt16) * kTestVectorChannels), 0);
383 }
384 
TEST_F(AudioBusTest,Scale)385 TEST_F(AudioBusTest, Scale) {
386   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
387 
388   // Fill the bus with dummy data.
389   static const float kFillValue = 1;
390   for (int i = 0; i < bus->channels(); ++i)
391     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), kFillValue);
392 
393   // Adjust by an invalid volume and ensure volume is unchanged.
394   bus->Scale(-1);
395   for (int i = 0; i < bus->channels(); ++i) {
396     SCOPED_TRACE("Invalid Scale");
397     VerifyValue(bus->channel(i), bus->frames(), kFillValue);
398   }
399 
400   // Verify correct volume adjustment.
401   static const float kVolume = 0.5;
402   bus->Scale(kVolume);
403   for (int i = 0; i < bus->channels(); ++i) {
404     SCOPED_TRACE("Half Scale");
405     VerifyValue(bus->channel(i), bus->frames(), kFillValue * kVolume);
406   }
407 
408   // Verify zero volume case.
409   bus->Scale(0);
410   for (int i = 0; i < bus->channels(); ++i) {
411     SCOPED_TRACE("Zero Scale");
412     VerifyValue(bus->channel(i), bus->frames(), 0);
413   }
414 }
415 
416 }  // namespace media
417