audio_buffer_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
1// Copyright 2013 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/string_util.h"
6#include "base/strings/stringprintf.h"
7#include "media/base/audio_buffer.h"
8#include "media/base/audio_bus.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace media {
12
13template <class T>
14static scoped_refptr<AudioBuffer> MakeInterleavedBuffer(
15    SampleFormat format,
16    int channels,
17    T start,
18    T increment,
19    int frames,
20    const base::TimeDelta start_time) {
21  DCHECK(format == kSampleFormatU8 || format == kSampleFormatS16 ||
22         format == kSampleFormatS32 || format == kSampleFormatF32);
23
24  // Create a block of memory with values:
25  //   start
26  //   start + increment
27  //   start + 2 * increment, ...
28  // Since this is interleaved data, channel 0 data will be:
29  //   start
30  //   start + channels * increment
31  //   start + 2 * channels * increment, ...
32  int buffer_size = frames * channels * sizeof(T);
33  uint8* memory = new uint8[buffer_size];
34  uint8* data[] = { memory };
35  T* buffer = reinterpret_cast<T*>(memory);
36  for (int i = 0; i < frames * channels; ++i) {
37    buffer[i] = start;
38    start += increment;
39  }
40  // Duration is 1 second per frame (for simplicity).
41  base::TimeDelta duration = base::TimeDelta::FromSeconds(frames);
42  return AudioBuffer::CopyFrom(
43      format, channels, frames, data, start_time, duration);
44}
45
46template <class T>
47static scoped_refptr<AudioBuffer> MakePlanarBuffer(
48    SampleFormat format,
49    int channels,
50    T start,
51    T increment,
52    int frames,
53    const base::TimeDelta start_time) {
54  DCHECK(format == kSampleFormatPlanarF32 || format == kSampleFormatPlanarS16);
55
56  // Create multiple blocks of data, once for each channel.
57  // Values in channel 0 will be:
58  //   start
59  //   start + increment
60  //   start + 2 * increment, ...
61  // Values in channel 1 will be:
62  //   start + frames * increment
63  //   start + (frames + 1) * increment
64  //   start + (frames + 2) * increment, ...
65  uint8** data = new uint8*[channels];
66  int buffer_size = frames * sizeof(T);
67  for (int i = 0; i < channels; ++i) {
68    uint8* memory = new uint8[buffer_size];
69    data[i] = memory;
70    T* buffer = reinterpret_cast<T*>(memory);
71    for (int j = 0; j < frames; ++j) {
72      buffer[j] = start;
73      start += increment;
74    }
75  }
76  // Duration is 1 second per frame (for simplicity).
77  base::TimeDelta duration = base::TimeDelta::FromSeconds(frames);
78  return AudioBuffer::CopyFrom(
79      format, channels, frames, data, start_time, duration);
80}
81
82static void VerifyResult(float* channel_data,
83                         int frames,
84                         float start,
85                         float increment) {
86  for (int i = 0; i < frames; ++i) {
87    SCOPED_TRACE(base::StringPrintf(
88        "i=%d/%d start=%f, increment=%f", i, frames, start, increment));
89    ASSERT_EQ(channel_data[i], start);
90    start += increment;
91  }
92}
93
94TEST(AudioBufferTest, CopyFrom) {
95  const int channels = 1;
96  const int frames = 8;
97  const base::TimeDelta start_time;
98  scoped_refptr<AudioBuffer> buffer = MakeInterleavedBuffer<uint8>(
99      kSampleFormatU8, channels, 1, 1, frames, start_time);
100  EXPECT_EQ(frames, buffer->frame_count());
101  EXPECT_EQ(buffer->timestamp(), start_time);
102  EXPECT_EQ(buffer->duration().InSeconds(), frames);
103  EXPECT_FALSE(buffer->end_of_stream());
104}
105
106TEST(AudioBufferTest, CreateEOSBuffer) {
107  scoped_refptr<AudioBuffer> buffer = AudioBuffer::CreateEOSBuffer();
108  EXPECT_TRUE(buffer->end_of_stream());
109}
110
111TEST(AudioBufferTest, FrameSize) {
112  const uint8 kTestData[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
113                              15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
114                              27, 28, 29, 30, 31 };
115  const base::TimeDelta kTimestampA = base::TimeDelta::FromMicroseconds(1337);
116  const base::TimeDelta kTimestampB = base::TimeDelta::FromMicroseconds(1234);
117
118  const uint8* const data[] = { kTestData };
119  scoped_refptr<AudioBuffer> buffer = AudioBuffer::CopyFrom(
120      kSampleFormatU8, 2, 16, data, kTimestampA, kTimestampB);
121  EXPECT_EQ(16, buffer->frame_count());  // 2 channels of 8-bit data
122
123  buffer = AudioBuffer::CopyFrom(
124      kSampleFormatF32, 4, 2, data, kTimestampA, kTimestampB);
125  EXPECT_EQ(2, buffer->frame_count());  // now 4 channels of 32-bit data
126}
127
128TEST(AudioBufferTest, ReadU8) {
129  const int channels = 4;
130  const int frames = 4;
131  const base::TimeDelta start_time;
132  scoped_refptr<AudioBuffer> buffer = MakeInterleavedBuffer<uint8>(
133      kSampleFormatU8, channels, 128, 1, frames, start_time);
134
135  // Read all 4 frames from the buffer. Data is interleaved, so ch[0] should be
136  // 128, 132, 136, 140, other channels similar. However, values are converted
137  // from [0, 255] to [-1.0, 1.0] with a bias of 128. Thus the first buffer
138  // value should be 0.0, then 1/127, 2/127, etc.
139  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
140  buffer->ReadFrames(frames, 0, 0, bus.get());
141  VerifyResult(bus->channel(0), frames, 0.0f, 4.0f / 127.0f);
142  VerifyResult(bus->channel(1), frames, 1.0f / 127.0f, 4.0f / 127.0f);
143  VerifyResult(bus->channel(2), frames, 2.0f / 127.0f, 4.0f / 127.0f);
144  VerifyResult(bus->channel(3), frames, 3.0f / 127.0f, 4.0f / 127.0f);
145}
146
147TEST(AudioBufferTest, ReadS16) {
148  const int channels = 2;
149  const int frames = 10;
150  const base::TimeDelta start_time;
151  scoped_refptr<AudioBuffer> buffer = MakeInterleavedBuffer<int16>(
152      kSampleFormatS16, channels, 1, 1, frames, start_time);
153
154  // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be 1,
155  // 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12. Data is converted
156  // to float from -1.0 to 1.0 based on int16 range.
157  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
158  buffer->ReadFrames(6, 0, 0, bus.get());
159  VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 2.0f / kint16max);
160  VerifyResult(bus->channel(1), 6, 2.0f / kint16max, 2.0f / kint16max);
161
162  // Now read the same data one frame at a time.
163  bus = AudioBus::Create(channels, 100);
164  for (int i = 0; i < frames; ++i) {
165    buffer->ReadFrames(1, i, i, bus.get());
166  }
167  VerifyResult(bus->channel(0), frames, 1.0f / kint16max, 2.0f / kint16max);
168  VerifyResult(bus->channel(1), frames, 2.0f / kint16max, 2.0f / kint16max);
169}
170
171TEST(AudioBufferTest, ReadS32) {
172  const int channels = 2;
173  const int frames = 6;
174  const base::TimeDelta start_time;
175  scoped_refptr<AudioBuffer> buffer = MakeInterleavedBuffer<int32>(
176      kSampleFormatS32, channels, 1, 1, frames, start_time);
177
178  // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be 1,
179  // 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12. Data is converted
180  // to float from -1.0 to 1.0 based on int32 range.
181  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
182  buffer->ReadFrames(frames, 0, 0, bus.get());
183  VerifyResult(bus->channel(0), frames, 1.0f / kint32max, 2.0f / kint32max);
184  VerifyResult(bus->channel(1), frames, 2.0f / kint32max, 2.0f / kint32max);
185
186  // Now read 2 frames starting at frame offset 3. ch[0] should be 7, 9, and
187  // ch[1] should be 8, 10.
188  buffer->ReadFrames(2, 3, 0, bus.get());
189  VerifyResult(bus->channel(0), 2, 7.0f / kint32max, 2.0f / kint32max);
190  VerifyResult(bus->channel(1), 2, 8.0f / kint32max, 2.0f / kint32max);
191}
192
193TEST(AudioBufferTest, ReadF32) {
194  const int channels = 2;
195  const int frames = 20;
196  const base::TimeDelta start_time;
197  scoped_refptr<AudioBuffer> buffer = MakeInterleavedBuffer<float>(
198      kSampleFormatF32, channels, 1.0f, 1.0f, frames, start_time);
199
200  // Read first 10 frames from the buffer. F32 is interleaved, so ch[0] should
201  // be 1, 3, 5, ... and ch[1] should be 2, 4, 6, ...
202  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
203  buffer->ReadFrames(10, 0, 0, bus.get());
204  VerifyResult(bus->channel(0), 10, 1.0f, 2.0f);
205  VerifyResult(bus->channel(1), 10, 2.0f, 2.0f);
206
207  // Read second 10 frames.
208  bus = AudioBus::Create(channels, 100);
209  buffer->ReadFrames(10, 10, 0, bus.get());
210  VerifyResult(bus->channel(0), 10, 21.0f, 2.0f);
211  VerifyResult(bus->channel(1), 10, 22.0f, 2.0f);
212}
213
214TEST(AudioBufferTest, ReadS16Planar) {
215  const int channels = 2;
216  const int frames = 20;
217  const base::TimeDelta start_time;
218  scoped_refptr<AudioBuffer> buffer = MakePlanarBuffer<int16>(
219      kSampleFormatPlanarS16, channels, 1, 1, frames, start_time);
220
221  // Read 6 frames from the buffer. Data is planar, so ch[0] should be 1, 2, 3,
222  // 4, 5, 6, and ch[1] should be 21, 22, 23, 24, 25, 26. Data is converted to
223  // float from -1.0 to 1.0 based on int16 range.
224  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
225  buffer->ReadFrames(6, 0, 0, bus.get());
226  VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 1.0f / kint16max);
227  VerifyResult(bus->channel(1), 6, 21.0f / kint16max, 1.0f / kint16max);
228
229  // Read all the frames backwards, one by one. ch[0] should be 20, 19, ...
230  bus = AudioBus::Create(channels, 100);
231  for (int i = 0; i < frames; ++i) {
232    buffer->ReadFrames(1, frames - i - 1, i, bus.get());
233  }
234  VerifyResult(bus->channel(0), frames, 20.0f / kint16max, -1.0f / kint16max);
235  VerifyResult(bus->channel(1), frames, 40.0f / kint16max, -1.0f / kint16max);
236
237  // Read 0 frames with different offsets. Existing data in AudioBus should be
238  // unchanged.
239  buffer->ReadFrames(0, 0, 0, bus.get());
240  buffer->ReadFrames(0, 0, 10, bus.get());
241  buffer->ReadFrames(0, 10, 0, bus.get());
242  VerifyResult(bus->channel(0), frames, 20.0f / kint16max, -1.0f / kint16max);
243  VerifyResult(bus->channel(1), frames, 40.0f / kint16max, -1.0f / kint16max);
244}
245
246TEST(AudioBufferTest, ReadF32Planar) {
247  const int channels = 4;
248  const int frames = 100;
249  const base::TimeDelta start_time;
250  scoped_refptr<AudioBuffer> buffer = MakePlanarBuffer<float>(
251      kSampleFormatPlanarF32, channels, 1.0f, 1.0f, frames, start_time);
252
253  // Read all 100 frames from the buffer. F32 is planar, so ch[0] should be 1,
254  // 2, 3, 4, ..., ch[1] should be 101, 102, 103, ..., and so on for all 4
255  // channels.
256  scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100);
257  buffer->ReadFrames(frames, 0, 0, bus.get());
258  VerifyResult(bus->channel(0), frames, 1.0f, 1.0f);
259  VerifyResult(bus->channel(1), frames, 101.0f, 1.0f);
260  VerifyResult(bus->channel(2), frames, 201.0f, 1.0f);
261  VerifyResult(bus->channel(3), frames, 301.0f, 1.0f);
262
263  // Now read 20 frames from the middle of the buffer.
264  bus = AudioBus::Create(channels, 100);
265  buffer->ReadFrames(20, 50, 0, bus.get());
266  VerifyResult(bus->channel(0), 20, 51.0f, 1.0f);
267  VerifyResult(bus->channel(1), 20, 151.0f, 1.0f);
268  VerifyResult(bus->channel(2), 20, 251.0f, 1.0f);
269  VerifyResult(bus->channel(3), 20, 351.0f, 1.0f);
270}
271
272}  // namespace media
273