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