Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / media / base / audio_bus_unittest.cc
blobea06f0a19d77bee38ee20849559c0b4146b60068
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"
14 namespace media {
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 {
23 public:
24 AudioBusTest() {}
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,
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);
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);
78 bus->Zero();
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|.
90 bus2->Zero();
91 bus1->CopyTo(bus2);
92 VerifyBus(bus1, bus2);
94 // Verify copy from |bus2| to |bus1|.
95 bus1->Zero();
96 bus2->CopyTo(bus1);
97 VerifyBus(bus2, bus1);
100 protected:
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,
117 kFrameCount));
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,
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)));
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);
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,
168 kFrameCount);
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.
239 bus->Zero();
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 };
260 // Expected results.
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");
278 bus->Zero();
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");
287 bus->Zero();
288 bus->FromInterleaved(
289 kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16));
290 VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint16max + 1.0f));
293 SCOPED_TRACE("int32");
294 bus->Zero();
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);
312 expected->Zero();
313 for (int ch = 0; ch < kTestVectorChannels; ++ch) {
314 memcpy(expected->channel(ch) + kPartialStart,
315 kTestVectorResult[ch] + kPartialStart,
316 kPartialFrames * sizeof(*expected->channel(ch)));
319 bus->Zero();
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);
339 ASSERT_EQ(memcmp(
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);
346 ASSERT_EQ(memcmp(
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]++;
361 ASSERT_TRUE(
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);
384 ASSERT_EQ(memcmp(
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.
398 bus->Scale(-1);
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;
406 bus->Scale(kVolume);
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.
413 bus->Scale(0);
414 for (int i = 0; i < bus->channels(); ++i) {
415 SCOPED_TRACE("Zero Scale");
416 VerifyValue(bus->channel(i), bus->frames(), 0);
420 } // namespace media