audio_bus_unittest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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
14namespace media {
15
16static const int kChannels = 6;
17static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1;
18// Use a buffer size which is intentionally not a multiple of kChannelAlignment.
19static const int kFrameCount = media::AudioBus::kChannelAlignment * 32 - 1;
20static const int kSampleRate = 48000;
21
22class AudioBusTest : public testing::Test {
23 public:
24  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.
31  void VerifyParams(AudioBus* bus) {
32    EXPECT_EQ(kChannels, bus->channels());
33    EXPECT_EQ(kFrameCount, bus->frames());
34  }
35
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.
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|.
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).
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|.
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.
107TEST_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.
114TEST_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.
123TEST_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.
136TEST_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.
163TEST_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.
202TEST_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>.
245static const int kTestVectorSize = 10;
246static const uint8 kTestVectorUint8[kTestVectorSize] = {
247    0, -kint8min, kuint8max, 0, kint8max / 2 + 128, kint8min / 2 + 128,
248    -kint8min, kuint8max, -kint8min, -kint8min };
249static const int16 kTestVectorInt16[kTestVectorSize] = {
250    kint16min, 0, kint16max, kint16min, kint16max / 2, kint16min / 2,
251    0, kint16max, 0, 0 };
252static const int32 kTestVectorInt32[kTestVectorSize] = {
253    kint32min, 0, kint32max, kint32min, kint32max / 2, kint32min / 2,
254    0, kint32max, 0, 0 };
255
256// Expected results.
257static const int kTestVectorFrames = kTestVectorSize / 2;
258static const float kTestVectorResult[][kTestVectorFrames] = {
259    { -1, 1, 0.5, 0, 0 }, { 0, -1, -0.5, 1, 0 }};
260static const int kTestVectorChannels = arraysize(kTestVectorResult);
261
262// Verify FromInterleaved() deinterleaves audio in supported formats correctly.
263TEST_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.
298TEST_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.
323TEST_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.
364TEST_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
385TEST_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