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 ~AudioBusTest() override
{
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
<float, base::AlignedFreeDeleter
> 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
<float, base::AlignedFreeDeleter
> 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);
208 EXPECT_FALSE(bus
->AreFramesZero());
210 // Zero first half the frames of each channel.
211 bus
->ZeroFrames(kFrameCount
/ 2);
212 for (int i
= 0; i
< bus
->channels(); ++i
) {
213 SCOPED_TRACE("First Half Zero");
214 VerifyValue(bus
->channel(i
), kFrameCount
/ 2, 0);
215 VerifyValue(bus
->channel(i
) + kFrameCount
/ 2,
216 kFrameCount
- kFrameCount
/ 2, i
+ 1);
218 EXPECT_FALSE(bus
->AreFramesZero());
220 // Fill the bus with dummy data.
221 for (int i
= 0; i
< bus
->channels(); ++i
)
222 std::fill(bus
->channel(i
), bus
->channel(i
) + bus
->frames(), i
+ 1);
224 // Zero the last half of the frames.
225 bus
->ZeroFramesPartial(kFrameCount
/ 2, kFrameCount
- kFrameCount
/ 2);
226 for (int i
= 0; i
< bus
->channels(); ++i
) {
227 SCOPED_TRACE("Last Half Zero");
228 VerifyValue(bus
->channel(i
) + kFrameCount
/ 2,
229 kFrameCount
- kFrameCount
/ 2, 0);
230 VerifyValue(bus
->channel(i
), kFrameCount
/ 2, i
+ 1);
232 EXPECT_FALSE(bus
->AreFramesZero());
234 // Fill the bus with dummy data.
235 for (int i
= 0; i
< bus
->channels(); ++i
)
236 std::fill(bus
->channel(i
), bus
->channel(i
) + bus
->frames(), i
+ 1);
238 // Zero all the frames of each channel.
240 for (int i
= 0; i
< bus
->channels(); ++i
) {
241 SCOPED_TRACE("All Zero");
242 VerifyValue(bus
->channel(i
), bus
->frames(), 0);
244 EXPECT_TRUE(bus
->AreFramesZero());
247 // Each test vector represents two channels of data in the following arbitrary
248 // layout: <min, zero, max, min, max / 2, min / 2, zero, max, zero, zero>.
249 static const int kTestVectorSize
= 10;
250 static const uint8 kTestVectorUint8
[kTestVectorSize
] = {
251 0, -kint8min
, kuint8max
, 0, kint8max
/ 2 + 128, kint8min
/ 2 + 128,
252 -kint8min
, kuint8max
, -kint8min
, -kint8min
};
253 static const int16 kTestVectorInt16
[kTestVectorSize
] = {
254 kint16min
, 0, kint16max
, kint16min
, kint16max
/ 2, kint16min
/ 2,
255 0, kint16max
, 0, 0 };
256 static const int32 kTestVectorInt32
[kTestVectorSize
] = {
257 kint32min
, 0, kint32max
, kint32min
, kint32max
/ 2, kint32min
/ 2,
258 0, kint32max
, 0, 0 };
261 static const int kTestVectorFrames
= kTestVectorSize
/ 2;
262 static const float kTestVectorResult
[][kTestVectorFrames
] = {
263 { -1, 1, 0.5, 0, 0 }, { 0, -1, -0.5, 1, 0 }};
264 static const int kTestVectorChannels
= arraysize(kTestVectorResult
);
266 // Verify FromInterleaved() deinterleaves audio in supported formats correctly.
267 TEST_F(AudioBusTest
, FromInterleaved
) {
268 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(
269 kTestVectorChannels
, kTestVectorFrames
);
270 scoped_ptr
<AudioBus
> expected
= AudioBus::Create(
271 kTestVectorChannels
, kTestVectorFrames
);
272 for (int ch
= 0; ch
< kTestVectorChannels
; ++ch
) {
273 memcpy(expected
->channel(ch
), kTestVectorResult
[ch
],
274 kTestVectorFrames
* sizeof(*expected
->channel(ch
)));
277 SCOPED_TRACE("uint8");
279 bus
->FromInterleaved(
280 kTestVectorUint8
, kTestVectorFrames
, sizeof(*kTestVectorUint8
));
281 // Biased uint8 calculations have poor precision, so the epsilon here is
282 // slightly more permissive than int16 and int32 calculations.
283 VerifyBusWithEpsilon(bus
.get(), expected
.get(), 1.0f
/ (kuint8max
- 1));
286 SCOPED_TRACE("int16");
288 bus
->FromInterleaved(
289 kTestVectorInt16
, kTestVectorFrames
, sizeof(*kTestVectorInt16
));
290 VerifyBusWithEpsilon(bus
.get(), expected
.get(), 1.0f
/ (kuint16max
+ 1.0f
));
293 SCOPED_TRACE("int32");
295 bus
->FromInterleaved(
296 kTestVectorInt32
, kTestVectorFrames
, sizeof(*kTestVectorInt32
));
297 VerifyBusWithEpsilon(bus
.get(), expected
.get(), 1.0f
/ (kuint32max
+ 1.0f
));
301 // Verify FromInterleavedPartial() deinterleaves audio correctly.
302 TEST_F(AudioBusTest
, FromInterleavedPartial
) {
303 // Only deinterleave the middle two frames in each channel.
304 static const int kPartialStart
= 1;
305 static const int kPartialFrames
= 2;
306 ASSERT_LE(kPartialStart
+ kPartialFrames
, kTestVectorFrames
);
308 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(
309 kTestVectorChannels
, kTestVectorFrames
);
310 scoped_ptr
<AudioBus
> expected
= AudioBus::Create(
311 kTestVectorChannels
, kTestVectorFrames
);
313 for (int ch
= 0; ch
< kTestVectorChannels
; ++ch
) {
314 memcpy(expected
->channel(ch
) + kPartialStart
,
315 kTestVectorResult
[ch
] + kPartialStart
,
316 kPartialFrames
* sizeof(*expected
->channel(ch
)));
320 bus
->FromInterleavedPartial(
321 kTestVectorInt32
+ kPartialStart
* bus
->channels(), kPartialStart
,
322 kPartialFrames
, sizeof(*kTestVectorInt32
));
323 VerifyBus(bus
.get(), expected
.get());
326 // Verify ToInterleaved() interleaves audio in suported formats correctly.
327 TEST_F(AudioBusTest
, ToInterleaved
) {
328 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(
329 kTestVectorChannels
, kTestVectorFrames
);
330 // Fill the bus with our test vector.
331 for (int ch
= 0; ch
< bus
->channels(); ++ch
) {
332 memcpy(bus
->channel(ch
), kTestVectorResult
[ch
],
333 kTestVectorFrames
* sizeof(*bus
->channel(ch
)));
336 SCOPED_TRACE("uint8");
337 uint8 test_array
[arraysize(kTestVectorUint8
)];
338 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorUint8
), test_array
);
340 test_array
, kTestVectorUint8
, sizeof(kTestVectorUint8
)), 0);
343 SCOPED_TRACE("int16");
344 int16 test_array
[arraysize(kTestVectorInt16
)];
345 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorInt16
), test_array
);
347 test_array
, kTestVectorInt16
, sizeof(kTestVectorInt16
)), 0);
350 SCOPED_TRACE("int32");
351 int32 test_array
[arraysize(kTestVectorInt32
)];
352 bus
->ToInterleaved(bus
->frames(), sizeof(*kTestVectorInt32
), test_array
);
354 // Some compilers get better precision than others on the half-max test, so
355 // let the test pass with an off by one check on the half-max.
356 int32 fixed_test_array
[arraysize(kTestVectorInt32
)];
357 memcpy(fixed_test_array
, kTestVectorInt32
, sizeof(kTestVectorInt32
));
358 ASSERT_EQ(fixed_test_array
[4], kint32max
/ 2);
359 fixed_test_array
[4]++;
362 memcmp(test_array
, kTestVectorInt32
, sizeof(kTestVectorInt32
)) == 0 ||
363 memcmp(test_array
, fixed_test_array
, sizeof(fixed_test_array
)) == 0);
367 // Verify ToInterleavedPartial() interleaves audio correctly.
368 TEST_F(AudioBusTest
, ToInterleavedPartial
) {
369 // Only interleave the middle two frames in each channel.
370 static const int kPartialStart
= 1;
371 static const int kPartialFrames
= 2;
372 ASSERT_LE(kPartialStart
+ kPartialFrames
, kTestVectorFrames
);
374 scoped_ptr
<AudioBus
> expected
= AudioBus::Create(
375 kTestVectorChannels
, kTestVectorFrames
);
376 for (int ch
= 0; ch
< kTestVectorChannels
; ++ch
) {
377 memcpy(expected
->channel(ch
), kTestVectorResult
[ch
],
378 kTestVectorFrames
* sizeof(*expected
->channel(ch
)));
381 int16 test_array
[arraysize(kTestVectorInt16
)];
382 expected
->ToInterleavedPartial(
383 kPartialStart
, kPartialFrames
, sizeof(*kTestVectorInt16
), test_array
);
385 test_array
, kTestVectorInt16
+ kPartialStart
* kTestVectorChannels
,
386 kPartialFrames
* sizeof(*kTestVectorInt16
) * kTestVectorChannels
), 0);
389 TEST_F(AudioBusTest
, Scale
) {
390 scoped_ptr
<AudioBus
> bus
= AudioBus::Create(kChannels
, kFrameCount
);
392 // Fill the bus with dummy data.
393 static const float kFillValue
= 1;
394 for (int i
= 0; i
< bus
->channels(); ++i
)
395 std::fill(bus
->channel(i
), bus
->channel(i
) + bus
->frames(), kFillValue
);
397 // Adjust by an invalid volume and ensure volume is unchanged.
399 for (int i
= 0; i
< bus
->channels(); ++i
) {
400 SCOPED_TRACE("Invalid Scale");
401 VerifyValue(bus
->channel(i
), bus
->frames(), kFillValue
);
404 // Verify correct volume adjustment.
405 static const float kVolume
= 0.5;
407 for (int i
= 0; i
< bus
->channels(); ++i
) {
408 SCOPED_TRACE("Half Scale");
409 VerifyValue(bus
->channel(i
), bus
->frames(), kFillValue
* kVolume
);
412 // Verify zero volume case.
414 for (int i
= 0; i
< bus
->channels(); ++i
) {
415 SCOPED_TRACE("Zero Scale");
416 VerifyValue(bus
->channel(i
), bus
->frames(), 0);