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.
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"
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;
22 class AudioBusTest
: public testing::Test
{
25 virtual ~AudioBusTest() {
26 for (size_t i
= 0; i
< data_
.size(); ++i
)
27 base::AlignedFree(data_
[i
]);
30 // Validate parameters returned by AudioBus v.s. the constructed parameters.
31 void VerifyParams(AudioBus
* bus
) {
32 EXPECT_EQ(kChannels
, bus
->channels());
33 EXPECT_EQ(kFrameCount
, bus
->frames());
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
;
41 // Verify values for each channel in |result| are within |epsilon| of
42 // |expected|. If |epsilon| exactly equals 0, uses FLOAT_EQ macro.
43 void VerifyBusWithEpsilon(const AudioBus
* result
, const AudioBus
* expected
,
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
));
51 ASSERT_FLOAT_EQ(expected
->channel(ch
)[i
], result
->channel(ch
)[i
]);
53 ASSERT_NEAR(expected
->channel(ch
)[i
], result
->channel(ch
)[i
],
60 // Verify values for each channel in |result| against |expected|.
61 void VerifyBus(const AudioBus
* result
, const AudioBus
* expected
) {
62 VerifyBusWithEpsilon(result
, expected
, 0);
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).
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
);
75 for (int i
= 0; i
< bus
->channels(); ++i
)
76 VerifyValue(bus
->channel(i
), bus
->frames(), i
);
79 for (int i
= 0; i
< bus
->channels(); ++i
)
80 VerifyValue(bus
->channel(i
), bus
->frames(), 0);
83 // Verify copying to and from |bus1| and |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
);
89 // Verify copy from |bus1| to |bus2|.
92 VerifyBus(bus1
, bus2
);
94 // Verify copy from |bus2| to |bus1|.
97 VerifyBus(bus2
, bus1
);
101 std::vector
<float*> data_
;
103 DISALLOW_COPY_AND_ASSIGN(AudioBusTest
);
106 // Verify basic Create(...) method works as advertised.
107 TEST_F(AudioBusTest
, Create
) {
108 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(kChannels
, kFrameCount
);
109 VerifyParams(bus
.get());
110 VerifyChannelData(bus
.get());
113 // Verify Create(...) using AudioParameters works as advertised.
114 TEST_F(AudioBusTest
, CreateUsingAudioParameters
) {
115 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(AudioParameters(
116 AudioParameters::AUDIO_PCM_LINEAR
, kChannelLayout
, kSampleRate
, 32,
118 VerifyParams(bus
.get());
119 VerifyChannelData(bus
.get());
122 // Verify an AudioBus created via wrapping a vector works as advertised.
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
)));
130 scoped_ptr
<AudioBus
> bus
= AudioBus::WrapVector(kFrameCount
, data_
);
131 VerifyParams(bus
.get());
132 VerifyChannelData(bus
.get());
135 // Verify an AudioBus created via wrapping a memory block works as advertised.
136 TEST_F(AudioBusTest
, WrapMemory
) {
137 AudioParameters
params(
138 AudioParameters::AUDIO_PCM_LINEAR
, kChannelLayout
, kSampleRate
, 32,
140 int data_size
= AudioBus::CalculateMemorySize(params
);
141 scoped_ptr_malloc
<float, base::ScopedPtrAlignedFree
> data(static_cast<float*>(
142 base::AlignedAlloc(data_size
, AudioBus::kChannelAlignment
)));
144 // Fill the memory with a test value we can check for after wrapping.
145 static const float kTestValue
= 3;
147 data
.get(), data
.get() + data_size
/ sizeof(*data
.get()), kTestValue
);
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());
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()));
162 // Simulate a shared memory transfer and verify results.
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,
169 scoped_ptr
<AudioBus
> bus1
= AudioBus::Create(kChannels
, kFrameCount
);
170 scoped_ptr
<AudioBus
> bus2
= AudioBus::Create(params
);
173 SCOPED_TRACE("Created");
174 CopyTest(bus1
.get(), bus2
.get());
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
)));
185 bus2
= AudioBus::WrapVector(kFrameCount
, data_
);
186 CopyTest(bus1
.get(), bus2
.get());
189 SCOPED_TRACE("Wrapped Memory");
190 // Try a copy to an AudioBus wrapping a memory block.
191 scoped_ptr_malloc
<float, base::ScopedPtrAlignedFree
> data(
192 static_cast<float*>(base::AlignedAlloc(
193 AudioBus::CalculateMemorySize(params
),
194 AudioBus::kChannelAlignment
)));
196 bus2
= AudioBus::WrapMemory(params
, data
.get());
197 CopyTest(bus1
.get(), bus2
.get());
201 // Verify Zero() and ZeroFrames(...) utility methods work as advertised.
202 TEST_F(AudioBusTest
, Zero
) {
203 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(kChannels
, kFrameCount
);
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);
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);
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);
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);
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);
235 // Zero all the frames of each channel.
237 for (int i
= 0; i
< bus
->channels(); ++i
) {
238 SCOPED_TRACE("All Zero");
239 VerifyValue(bus
->channel(i
), bus
->frames(), 0);
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 };
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
);
262 // Verify FromInterleaved() deinterleaves audio in supported formats correctly.
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
)));
273 SCOPED_TRACE("uint8");
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));
282 SCOPED_TRACE("int16");
284 bus
->FromInterleaved(
285 kTestVectorInt16
, kTestVectorFrames
, sizeof(*kTestVectorInt16
));
286 VerifyBusWithEpsilon(bus
.get(), expected
.get(), 1.0f
/ (kuint16max
+ 1.0f
));
289 SCOPED_TRACE("int32");
291 bus
->FromInterleaved(
292 kTestVectorInt32
, kTestVectorFrames
, sizeof(*kTestVectorInt32
));
293 VerifyBusWithEpsilon(bus
.get(), expected
.get(), 1.0f
/ (kuint32max
+ 1.0f
));
297 // Verify FromInterleavedPartial() deinterleaves audio correctly.
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
);
304 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(
305 kTestVectorChannels
, kTestVectorFrames
);
306 scoped_ptr
<AudioBus
> expected
= AudioBus::Create(
307 kTestVectorChannels
, kTestVectorFrames
);
309 for (int ch
= 0; ch
< kTestVectorChannels
; ++ch
) {
310 memcpy(expected
->channel(ch
) + kPartialStart
,
311 kTestVectorResult
[ch
] + kPartialStart
,
312 kPartialFrames
* sizeof(*expected
->channel(ch
)));
316 bus
->FromInterleavedPartial(
317 kTestVectorInt32
+ kPartialStart
* bus
->channels(), kPartialStart
,
318 kPartialFrames
, sizeof(*kTestVectorInt32
));
319 VerifyBus(bus
.get(), expected
.get());
322 // Verify ToInterleaved() interleaves audio in suported formats correctly.
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
)));
332 SCOPED_TRACE("uint8");
333 uint8 test_array
[arraysize(kTestVectorUint8
)];
334 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorUint8
), test_array
);
336 test_array
, kTestVectorUint8
, sizeof(kTestVectorUint8
)), 0);
339 SCOPED_TRACE("int16");
340 int16 test_array
[arraysize(kTestVectorInt16
)];
341 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorInt16
), test_array
);
343 test_array
, kTestVectorInt16
, sizeof(kTestVectorInt16
)), 0);
346 SCOPED_TRACE("int32");
347 int32 test_array
[arraysize(kTestVectorInt32
)];
348 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorInt32
), test_array
);
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]++;
358 memcmp(test_array
, kTestVectorInt32
, sizeof(kTestVectorInt32
)) == 0 ||
359 memcmp(test_array
, fixed_test_array
, sizeof(fixed_test_array
)) == 0);
363 // Verify ToInterleavedPartial() interleaves audio correctly.
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
);
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
)));
377 int16 test_array
[arraysize(kTestVectorInt16
)];
378 expected
->ToInterleavedPartial(
379 kPartialStart
, kPartialFrames
, sizeof(*kTestVectorInt16
), test_array
);
381 test_array
, kTestVectorInt16
+ kPartialStart
* kTestVectorChannels
,
382 kPartialFrames
* sizeof(*kTestVectorInt16
) * kTestVectorChannels
), 0);
385 TEST_F(AudioBusTest
, Scale
) {
386 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(kChannels
, kFrameCount
);
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
);
393 // Adjust by an invalid volume and ensure volume is unchanged.
395 for (int i
= 0; i
< bus
->channels(); ++i
) {
396 SCOPED_TRACE("Invalid Scale");
397 VerifyValue(bus
->channel(i
), bus
->frames(), kFillValue
);
400 // Verify correct volume adjustment.
401 static const float kVolume
= 0.5;
403 for (int i
= 0; i
< bus
->channels(); ++i
) {
404 SCOPED_TRACE("Half Scale");
405 VerifyValue(bus
->channel(i
), bus
->frames(), kFillValue
* kVolume
);
408 // Verify zero volume case.
410 for (int i
= 0; i
< bus
->channels(); ++i
) {
411 SCOPED_TRACE("Zero Scale");
412 VerifyValue(bus
->channel(i
), bus
->frames(), 0);