audio_bus_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 <limits>
6
7#include "base/stringprintf.h"
8#include "base/time.h"
9#include "media/audio/audio_parameters.h"
10#include "media/base/audio_bus.h"
11#include "media/base/channel_layout.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  ~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| against |expected|.
42  void VerifyBus(const AudioBus* result, const AudioBus* expected) {
43    ASSERT_EQ(expected->channels(), result->channels());
44    ASSERT_EQ(expected->frames(), result->frames());
45    for (int ch = 0; ch < result->channels(); ++ch) {
46      for (int i = 0; i < result->frames(); ++i) {
47        SCOPED_TRACE(base::StringPrintf("ch=%d, i=%d", ch, i));
48        ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]);
49      }
50    }
51  }
52
53  // Read and write to the full extent of the allocated channel data.  Also test
54  // the Zero() method and verify it does as advertised.  Also test data if data
55  // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.h).
56  void VerifyChannelData(AudioBus* bus) {
57    for (int i = 0; i < bus->channels(); ++i) {
58      ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(
59          bus->channel(i)) & (AudioBus::kChannelAlignment - 1));
60      std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i);
61    }
62
63    for (int i = 0; i < bus->channels(); ++i)
64      VerifyValue(bus->channel(i), bus->frames(), i);
65
66    bus->Zero();
67    for (int i = 0; i < bus->channels(); ++i)
68      VerifyValue(bus->channel(i), bus->frames(), 0);
69  }
70
71  // Verify copying to and from |bus1| and |bus2|.
72  void CopyTest(AudioBus* bus1, AudioBus* bus2) {
73    // Fill |bus1| with dummy data.
74    for (int i = 0; i < bus1->channels(); ++i)
75      std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i);
76
77    // Verify copy from |bus1| to |bus2|.
78    bus2->Zero();
79    bus1->CopyTo(bus2);
80    VerifyBus(bus1, bus2);
81
82    // Verify copy from |bus2| to |bus1|.
83    bus1->Zero();
84    bus2->CopyTo(bus1);
85    VerifyBus(bus2, bus1);
86  }
87
88 protected:
89  std::vector<float*> data_;
90
91  DISALLOW_COPY_AND_ASSIGN(AudioBusTest);
92};
93
94// Verify basic Create(...) method works as advertised.
95TEST_F(AudioBusTest, Create) {
96  scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
97  VerifyParams(bus.get());
98  VerifyChannelData(bus.get());
99}
100
101// Verify Create(...) using AudioParameters works as advertised.
102TEST_F(AudioBusTest, CreateUsingAudioParameters) {
103  scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters(
104      AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
105      kFrameCount));
106  VerifyParams(bus.get());
107  VerifyChannelData(bus.get());
108}
109
110// Verify an AudioBus created via wrapping a vector works as advertised.
111TEST_F(AudioBusTest, WrapVector) {
112  data_.reserve(kChannels);
113  for (int i = 0; i < kChannels; ++i) {
114    data_.push_back(static_cast<float*>(base::AlignedAlloc(
115        sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
116  }
117
118  scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_);
119  VerifyParams(bus.get());
120  VerifyChannelData(bus.get());
121}
122
123// Verify an AudioBus created via wrapping a memory block works as advertised.
124TEST_F(AudioBusTest, WrapMemory) {
125  AudioParameters params(
126      AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
127      kFrameCount);
128  int data_size = AudioBus::CalculateMemorySize(params);
129  scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>(
130      base::AlignedAlloc(data_size, AudioBus::kChannelAlignment)));
131
132  // Fill the memory with a test value we can check for after wrapping.
133  static const float kTestValue = 3;
134  std::fill(
135      data.get(), data.get() + data_size / sizeof(*data.get()), kTestValue);
136
137  scoped_ptr<AudioBus> bus = AudioBus::WrapMemory(params, data.get());
138  // Verify the test value we filled prior to wrapping.
139  for (int i = 0; i < bus->channels(); ++i)
140    VerifyValue(bus->channel(i), bus->frames(), kTestValue);
141  VerifyParams(bus.get());
142  VerifyChannelData(bus.get());
143
144  // Verify the channel vectors lie within the provided memory block.
145  EXPECT_GE(bus->channel(0), data.get());
146  EXPECT_LT(bus->channel(bus->channels() - 1) + bus->frames(),
147            data.get() + data_size / sizeof(*data.get()));
148}
149
150// Simulate a shared memory transfer and verify results.
151TEST_F(AudioBusTest, CopyTo) {
152  // Create one bus with AudioParameters and the other through direct values to
153  // test for parity between the Create() functions.
154  AudioParameters params(
155      AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
156      kFrameCount);
157  scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount);
158  scoped_ptr<AudioBus> bus2 = AudioBus::Create(params);
159
160  {
161    SCOPED_TRACE("Created");
162    CopyTest(bus1.get(), bus2.get());
163  }
164  {
165    SCOPED_TRACE("Wrapped Vector");
166    // Try a copy to an AudioBus wrapping a vector.
167    data_.reserve(kChannels);
168    for (int i = 0; i < kChannels; ++i) {
169      data_.push_back(static_cast<float*>(base::AlignedAlloc(
170          sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
171    }
172
173    bus2 = AudioBus::WrapVector(kFrameCount, data_);
174    CopyTest(bus1.get(), bus2.get());
175  }
176  {
177    SCOPED_TRACE("Wrapped Memory");
178    // Try a copy to an AudioBus wrapping a memory block.
179    scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(
180        static_cast<float*>(base::AlignedAlloc(
181            AudioBus::CalculateMemorySize(params),
182            AudioBus::kChannelAlignment)));
183
184    bus2 = AudioBus::WrapMemory(params, data.get());
185    CopyTest(bus1.get(), bus2.get());
186  }
187}
188
189// Verify Zero() and ZeroFrames(...) utility methods work as advertised.
190TEST_F(AudioBusTest, Zero) {
191  scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
192
193  // Fill the bus with dummy data.
194  for (int i = 0; i < bus->channels(); ++i)
195    std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
196
197  // Zero first half the frames of each channel.
198  bus->ZeroFrames(kFrameCount / 2);
199  for (int i = 0; i < bus->channels(); ++i) {
200    SCOPED_TRACE("First Half Zero");
201    VerifyValue(bus->channel(i), kFrameCount / 2, 0);
202    VerifyValue(bus->channel(i) + kFrameCount / 2,
203                kFrameCount - kFrameCount / 2, i + 1);
204  }
205
206  // Fill the bus with dummy data.
207  for (int i = 0; i < bus->channels(); ++i)
208    std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
209
210  // Zero the last half of the frames.
211  bus->ZeroFramesPartial(kFrameCount / 2, kFrameCount - kFrameCount / 2);
212  for (int i = 0; i < bus->channels(); ++i) {
213    SCOPED_TRACE("Last Half Zero");
214    VerifyValue(bus->channel(i) + kFrameCount / 2,
215                kFrameCount - kFrameCount / 2, 0);
216    VerifyValue(bus->channel(i), kFrameCount / 2, i + 1);
217  }
218
219  // Fill the bus with dummy data.
220  for (int i = 0; i < bus->channels(); ++i)
221    std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
222
223  // Zero all the frames of each channel.
224  bus->Zero();
225  for (int i = 0; i < bus->channels(); ++i) {
226    SCOPED_TRACE("All Zero");
227    VerifyValue(bus->channel(i), bus->frames(), 0);
228  }
229}
230
231// Each test vector represents two channels of data in the following arbitrary
232// layout: <min, zero, max, min, zero, max, zero, zero>.
233static const int kTestVectorSize = 8;
234static const uint8 kTestVectorUint8[kTestVectorSize] = {
235    0, -kint8min, kuint8max, 0, -kint8min, kuint8max, -kint8min, -kint8min };
236static const int16 kTestVectorInt16[kTestVectorSize] = {
237    kint16min, 0, kint16max, kint16min, 0, kint16max, 0, 0 };
238static const int32 kTestVectorInt32[kTestVectorSize] = {
239    kint32min, 0, kint32max, kint32min, 0, kint32max, 0, 0 };
240
241// Expected results.
242static const int kTestVectorFrames = kTestVectorSize / 2;
243static const float kTestVectorResult[][kTestVectorFrames] = {
244    { -1, 1, 0, 0 }, { 0, -1, 1, 0 }};
245static const int kTestVectorChannels = arraysize(kTestVectorResult);
246
247// Verify FromInterleaved() deinterleaves audio in supported formats correctly.
248TEST_F(AudioBusTest, FromInterleaved) {
249  scoped_ptr<AudioBus> bus = AudioBus::Create(
250      kTestVectorChannels, kTestVectorFrames);
251  scoped_ptr<AudioBus> expected = AudioBus::Create(
252      kTestVectorChannels, kTestVectorFrames);
253  for (int ch = 0; ch < kTestVectorChannels; ++ch) {
254    memcpy(expected->channel(ch), kTestVectorResult[ch],
255           kTestVectorFrames * sizeof(*expected->channel(ch)));
256  }
257  {
258    SCOPED_TRACE("uint8");
259    bus->Zero();
260    bus->FromInterleaved(
261        kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8));
262    VerifyBus(bus.get(), expected.get());
263  }
264  {
265    SCOPED_TRACE("int16");
266    bus->Zero();
267    bus->FromInterleaved(
268        kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16));
269    VerifyBus(bus.get(), expected.get());
270  }
271  {
272    SCOPED_TRACE("int32");
273    bus->Zero();
274    bus->FromInterleaved(
275        kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32));
276    VerifyBus(bus.get(), expected.get());
277  }
278}
279
280// Verify FromInterleavedPartial() deinterleaves audio correctly.
281TEST_F(AudioBusTest, FromInterleavedPartial) {
282  // Only deinterleave the middle two frames in each channel.
283  static const int kPartialStart = 1;
284  static const int kPartialFrames = 2;
285  ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames);
286
287  scoped_ptr<AudioBus> bus = AudioBus::Create(
288      kTestVectorChannels, kTestVectorFrames);
289  scoped_ptr<AudioBus> expected = AudioBus::Create(
290      kTestVectorChannels, kTestVectorFrames);
291  expected->Zero();
292  for (int ch = 0; ch < kTestVectorChannels; ++ch) {
293    memcpy(expected->channel(ch) + kPartialStart,
294           kTestVectorResult[ch] + kPartialStart,
295           kPartialFrames * sizeof(*expected->channel(ch)));
296  }
297
298  bus->Zero();
299  bus->FromInterleavedPartial(
300      kTestVectorInt32 + kPartialStart * bus->channels(), kPartialStart,
301      kPartialFrames, sizeof(*kTestVectorInt32));
302  VerifyBus(bus.get(), expected.get());
303}
304
305// Verify ToInterleaved() interleaves audio in suported formats correctly.
306TEST_F(AudioBusTest, ToInterleaved) {
307  scoped_ptr<AudioBus> bus = AudioBus::Create(
308      kTestVectorChannels, kTestVectorFrames);
309  // Fill the bus with our test vector.
310  for (int ch = 0; ch < kTestVectorChannels; ++ch) {
311    memcpy(bus->channel(ch), kTestVectorResult[ch],
312           kTestVectorFrames * sizeof(*bus->channel(ch)));
313  }
314  {
315    SCOPED_TRACE("uint8");
316    uint8 test_array[arraysize(kTestVectorUint8)];
317    bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array);
318    ASSERT_EQ(memcmp(
319        test_array, kTestVectorUint8, arraysize(kTestVectorUint8)), 0);
320  }
321  {
322    SCOPED_TRACE("int16");
323    int16 test_array[arraysize(kTestVectorInt16)];
324    bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array);
325    ASSERT_EQ(memcmp(
326        test_array, kTestVectorInt16, arraysize(kTestVectorInt16)), 0);
327  }
328  {
329    SCOPED_TRACE("int32");
330    int32 test_array[arraysize(kTestVectorInt32)];
331    bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array);
332    ASSERT_EQ(memcmp(
333        test_array, kTestVectorInt32, arraysize(kTestVectorInt32)), 0);
334  }
335}
336
337}  // namespace media
338