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