| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <limits> |
| 6 |
| 7 #include "base/stringprintf.h" |
| 8 #include "base/time.h" |
| 5 #include "media/audio/audio_parameters.h" | 9 #include "media/audio/audio_parameters.h" |
| 6 #include "media/base/audio_bus.h" | 10 #include "media/base/audio_bus.h" |
| 7 #include "media/base/channel_layout.h" | 11 #include "media/base/channel_layout.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 12 #include "testing/gtest/include/gtest/gtest.h" |
| 9 | 13 |
| 10 static const int kChannels = 6; | 14 static const int kChannels = 6; |
| 11 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1; | 15 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1; |
| 12 // Use a buffer size which is intentionally not a multiple of 16; see | 16 // Use a buffer size which is intentionally not a multiple of 16; see |
| 13 // kChannelAlignment in audio_bus.cc. | 17 // kChannelAlignment in audio_bus.cc. |
| 14 static const int kFrameCount = 1234; | 18 static const int kFrameCount = 1234; |
| 19 static const int kSampleRate = 48000; |
| 15 | 20 |
| 16 namespace media { | 21 namespace media { |
| 17 | 22 |
| 18 class AudioBusTest : public testing::Test { | 23 class AudioBusTest : public testing::Test { |
| 19 public: | 24 public: |
| 20 AudioBusTest() {} | 25 AudioBusTest() {} |
| 21 ~AudioBusTest() { | 26 ~AudioBusTest() { |
| 22 for (size_t i = 0; i < data_.size(); ++i) | 27 for (size_t i = 0; i < data_.size(); ++i) |
| 23 base::AlignedFree(data_[i]); | 28 base::AlignedFree(data_[i]); |
| 24 } | 29 } |
| 25 | 30 |
| 26 // Validate parameters returned by AudioBus v.s. the constructed parameters. | 31 // Validate parameters returned by AudioBus v.s. the constructed parameters. |
| 27 void VerifyParams(AudioBus* bus) { | 32 void VerifyParams(AudioBus* bus) { |
| 28 EXPECT_EQ(kChannels, bus->channels()); | 33 EXPECT_EQ(kChannels, bus->channels()); |
| 29 EXPECT_EQ(kFrameCount, bus->frames()); | 34 EXPECT_EQ(kFrameCount, bus->frames()); |
| 30 } | 35 } |
| 31 | 36 |
| 32 void VerifyValue(const float data[], int size, float value) { | 37 void VerifyValue(const float data[], int size, float value) { |
| 33 for (int i = 0; i < size; ++i) | 38 for (int i = 0; i < size; ++i) |
| 34 ASSERT_FLOAT_EQ(value, data[i]); | 39 ASSERT_FLOAT_EQ(value, data[i]); |
| 35 } | 40 } |
| 36 | 41 |
| 42 // Verify values for each channel in |result| against |expected|. |
| 43 void VerifyBus(const AudioBus* result, const AudioBus* expected) { |
| 44 ASSERT_EQ(expected->channels(), result->channels()); |
| 45 ASSERT_EQ(expected->frames(), result->frames()); |
| 46 for (int ch = 0; ch < result->channels(); ++ch) { |
| 47 for (int i = 0; i < result->frames(); ++i) { |
| 48 SCOPED_TRACE(base::StringPrintf("ch=%d, i=%d", ch, i)); |
| 49 ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]); |
| 50 } |
| 51 } |
| 52 } |
| 53 |
| 37 // Read and write to the full extent of the allocated channel data. Also test | 54 // Read and write to the full extent of the allocated channel data. Also test |
| 38 // the Zero() method and verify it does as advertised. Also test data if data | 55 // the Zero() method and verify it does as advertised. Also test data if data |
| 39 // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.cc). | 56 // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.cc). |
| 40 void VerifyChannelData(AudioBus* bus) { | 57 void VerifyChannelData(AudioBus* bus) { |
| 41 for (int i = 0; i < bus->channels(); ++i) { | 58 for (int i = 0; i < bus->channels(); ++i) { |
| 42 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(bus->channel(i)) & 0x0F); | 59 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(bus->channel(i)) & 0x0F); |
| 43 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i); | 60 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i); |
| 44 } | 61 } |
| 45 | 62 |
| 46 for (int i = 0; i < bus->channels(); ++i) | 63 for (int i = 0; i < bus->channels(); ++i) |
| 47 VerifyValue(bus->channel(i), bus->frames(), i); | 64 VerifyValue(bus->channel(i), bus->frames(), i); |
| 48 | 65 |
| 49 bus->Zero(); | 66 bus->Zero(); |
| 50 for (int i = 0; i < bus->channels(); ++i) | 67 for (int i = 0; i < bus->channels(); ++i) |
| 51 VerifyValue(bus->channel(i), bus->frames(), 0); | 68 VerifyValue(bus->channel(i), bus->frames(), 0); |
| 52 } | 69 } |
| 53 | 70 |
| 54 | |
| 55 protected: | 71 protected: |
| 56 std::vector<float*> data_; | 72 std::vector<float*> data_; |
| 57 | 73 |
| 58 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); | 74 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); |
| 59 }; | 75 }; |
| 60 | 76 |
| 61 // Verify basic Create(...) method works as advertised. | 77 // Verify basic Create(...) method works as advertised. |
| 62 TEST_F(AudioBusTest, Create) { | 78 TEST_F(AudioBusTest, Create) { |
| 63 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 79 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 64 VerifyParams(bus.get()); | 80 VerifyParams(bus.get()); |
| 65 VerifyChannelData(bus.get()); | 81 VerifyChannelData(bus.get()); |
| 66 } | 82 } |
| 67 | 83 |
| 68 // Verify Create(...) using AudioParameters works as advertised. | 84 // Verify Create(...) using AudioParameters works as advertised. |
| 69 TEST_F(AudioBusTest, CreateUsingAudioParameters) { | 85 TEST_F(AudioBusTest, CreateUsingAudioParameters) { |
| 70 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( | 86 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( |
| 71 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 48000, 32, | 87 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 72 kFrameCount)); | 88 kFrameCount)); |
| 73 VerifyParams(bus.get()); | 89 VerifyParams(bus.get()); |
| 74 VerifyChannelData(bus.get()); | 90 VerifyChannelData(bus.get()); |
| 75 } | 91 } |
| 76 | 92 |
| 77 // Verify an AudioBus created via wrapping works as advertised. | 93 // Verify an AudioBus created via wrapping a vector works as advertised. |
| 78 TEST_F(AudioBusTest, Wrap) { | 94 TEST_F(AudioBusTest, WrapVector) { |
| 79 data_.reserve(kChannels); | 95 data_.reserve(kChannels); |
| 80 for (int i = 0; i < kChannels; ++i) { | 96 for (int i = 0; i < kChannels; ++i) { |
| 81 data_.push_back(static_cast<float*>(base::AlignedAlloc( | 97 data_.push_back(static_cast<float*>(base::AlignedAlloc( |
| 82 sizeof(*data_[i]) * kFrameCount, 16))); | 98 sizeof(*data_[i]) * kFrameCount, 16))); |
| 83 } | 99 } |
| 84 | 100 |
| 85 scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_); | 101 scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_); |
| 86 VerifyParams(bus.get()); | 102 VerifyParams(bus.get()); |
| 87 VerifyChannelData(bus.get()); | 103 VerifyChannelData(bus.get()); |
| 88 } | 104 } |
| 89 | 105 |
| 106 // Verify an AudioBus created via wrapping a memory block works as advertised. |
| 107 TEST_F(AudioBusTest, WrapBlock) { |
| 108 // Choose a data size that allows us to slide |data| to be 16-byte unaligned. |
| 109 int data_size = AudioBus::BlockSize(kChannels, kFrameCount) + 16; |
| 110 scoped_ptr<uint8> data(new uint8[data_size]); |
| 111 |
| 112 // Slide our pointer until it's unaligned. |
| 113 uint8* data_unaligned = data.get(); |
| 114 while ((reinterpret_cast<uintptr_t>(data_unaligned) & 0x0F) == 0U) |
| 115 data_unaligned++; |
| 116 |
| 117 // Try with an aligned pointer. |
| 118 scoped_ptr<AudioBus> bus = AudioBus::WrapBlock( |
| 119 kChannels, kFrameCount, data.get()); |
| 120 VerifyParams(bus.get()); |
| 121 VerifyChannelData(bus.get()); |
| 122 |
| 123 // Try with an unaligned pointer. |
| 124 bus = AudioBus::WrapBlock(kChannels, kFrameCount, data_unaligned); |
| 125 VerifyParams(bus.get()); |
| 126 VerifyChannelData(bus.get()); |
| 127 |
| 128 // Repeat using AudioParameters. |
| 129 AudioParameters params( |
| 130 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 131 kFrameCount); |
| 132 |
| 133 // Try with an aligned pointer. |
| 134 bus = AudioBus::WrapBlock(params, data.get()); |
| 135 VerifyParams(bus.get()); |
| 136 VerifyChannelData(bus.get()); |
| 137 |
| 138 // Try with an unaligned pointer. |
| 139 bus = AudioBus::WrapBlock(params, data.get()); |
| 140 VerifyParams(bus.get()); |
| 141 VerifyChannelData(bus.get()); |
| 142 } |
| 143 |
| 90 // Simulate a shared memory transfer and verify results. | 144 // Simulate a shared memory transfer and verify results. |
| 91 TEST_F(AudioBusTest, AudioData) { | 145 TEST_F(AudioBusTest, AudioData) { |
| 146 // Create one bus with AudioParameters and the other through direct values to |
| 147 // test for parity between the functions. |
| 148 AudioParameters params( |
| 149 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 150 kFrameCount); |
| 92 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); | 151 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); |
| 93 scoped_ptr<AudioBus> bus2 = AudioBus::Create(kChannels, kFrameCount); | 152 scoped_ptr<AudioBus> bus2 = AudioBus::Create(params); |
| 153 // Flip the order of which bus checks using params vs created with for parity. |
| 154 ASSERT_EQ(bus1->data_size(), AudioBus::BlockSize(params)); |
| 155 ASSERT_EQ(bus2->data_size(), |
| 156 AudioBus::BlockSize(kChannels, kFrameCount)); |
| 94 | 157 |
| 95 // Fill |bus1| with dummy data and zero out |bus2|. | 158 // Fill |bus1| with dummy data and zero out |bus2|. |
| 96 for (int i = 0; i < bus1->channels(); ++i) | 159 for (int i = 0; i < bus1->channels(); ++i) |
| 97 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); | 160 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); |
| 98 bus2->Zero(); | 161 bus2->Zero(); |
| 99 | 162 |
| 100 // Transfer audio data from |bus1| to |bus2|. | 163 // Transfer audio data from |bus1| to |bus2|. |
| 101 ASSERT_EQ(bus1->data_size(), bus2->data_size()); | 164 ASSERT_EQ(bus1->data_size(), bus2->data_size()); |
| 102 memcpy(bus2->data(), bus1->data(), bus1->data_size()); | 165 memcpy(bus2->data(), bus1->data(), bus1->data_size()); |
| 103 | 166 |
| 104 for (int i = 0; i < bus2->channels(); ++i) | 167 for (int i = 0; i < bus2->channels(); ++i) |
| 105 VerifyValue(bus2->channel(i), bus2->frames(), i); | 168 VerifyValue(bus2->channel(i), bus2->frames(), i); |
| 106 } | 169 } |
| 107 | 170 |
| 171 // Simulate a shared memory transfer from a wrapped to unwrapped AudioBus. |
| 172 TEST_F(AudioBusTest, AudioDataWrapped) { |
| 173 // Create one bus with AudioParameters and the other through direct values to |
| 174 // test for parity between the functions. |
| 175 AudioParameters params( |
| 176 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 177 kFrameCount); |
| 178 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); |
| 179 ASSERT_EQ(bus1->data_size(), AudioBus::BlockSize(params)); |
| 180 scoped_ptr<AudioBus> bus2 = AudioBus::WrapBlock(params, bus1->data()); |
| 181 |
| 182 // Fill |bus1| with dummy data. |
| 183 for (int i = 0; i < bus1->channels(); ++i) |
| 184 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); |
| 185 |
| 186 // Verify the data is correct inside of |bus2|. |
| 187 for (int i = 0; i < bus2->channels(); ++i) |
| 188 VerifyValue(bus2->channel(i), bus2->frames(), i); |
| 189 |
| 190 // Zero |bus2| and ensure |bus1| is zero'd |
| 191 bus2->Zero(); |
| 192 for (int i = 0; i < bus1->channels(); ++i) |
| 193 VerifyValue(bus1->channel(i), bus1->frames(), 0); |
| 194 |
| 195 // Fill |bus2| with dummy data. |
| 196 for (int i = 0; i < bus2->channels(); ++i) |
| 197 std::fill(bus2->channel(i), bus2->channel(i) + bus2->frames(), i); |
| 198 |
| 199 // Verify the data is correct inside of |bus1|. |
| 200 for (int i = 0; i < bus1->channels(); ++i) |
| 201 VerifyValue(bus1->channel(i), bus1->frames(), i); |
| 202 } |
| 203 |
| 108 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. | 204 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. |
| 109 TEST_F(AudioBusTest, Zero) { | 205 TEST_F(AudioBusTest, Zero) { |
| 110 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 206 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 111 | 207 |
| 112 // First fill the bus with dummy data. | 208 // First fill the bus with dummy data. |
| 113 for (int i = 0; i < bus->channels(); ++i) | 209 for (int i = 0; i < bus->channels(); ++i) |
| 114 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); | 210 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); |
| 115 | 211 |
| 116 // Zero half the frames of each channel. | 212 // Zero half the frames of each channel. |
| 117 bus->ZeroFrames(kFrameCount / 2); | 213 bus->ZeroFrames(kFrameCount / 2); |
| 118 for (int i = 0; i < bus->channels(); ++i) | 214 for (int i = 0; i < bus->channels(); ++i) |
| 119 VerifyValue(bus->channel(i), kFrameCount / 2, 0); | 215 VerifyValue(bus->channel(i), kFrameCount / 2, 0); |
| 120 | 216 |
| 121 // Zero all the frames of each channel. | 217 // Zero all the frames of each channel. |
| 122 bus->Zero(); | 218 bus->Zero(); |
| 123 for (int i = 0; i < bus->channels(); ++i) | 219 for (int i = 0; i < bus->channels(); ++i) |
| 124 VerifyValue(bus->channel(i), bus->frames(), 0); | 220 VerifyValue(bus->channel(i), bus->frames(), 0); |
| 125 } | 221 } |
| 126 | 222 |
| 223 // Each test vector represents two channels of data in the following arbitrary |
| 224 // layout: <min, zero, max, min, zero, max, zero, zero>. |
| 225 static const int kTestVectorSize = 8; |
| 226 static const uint8 kTestVectorUint8[kTestVectorSize] = { |
| 227 0, -kint8min, kuint8max, 0, -kint8min, kuint8max, -kint8min, -kint8min }; |
| 228 static const int16 kTestVectorInt16[kTestVectorSize] = { |
| 229 kint16min, 0, kint16max, kint16min, 0, kint16max, 0, 0 }; |
| 230 static const int32 kTestVectorInt32[kTestVectorSize] = { |
| 231 kint32min, 0, kint32max, kint32min, 0, kint32max, 0, 0 }; |
| 232 |
| 233 // Expected results. |
| 234 static const int kTestVectorFrames = kTestVectorSize / 2; |
| 235 static const float kTestVectorResult[][kTestVectorFrames] = { |
| 236 { -1, 1, 0, 0 }, { 0, -1, 1, 0 }}; |
| 237 static const int kTestVectorChannels = arraysize(kTestVectorResult); |
| 238 |
| 239 // Verify FromInterleaved() deinterleaves audio in suported formats correctly. |
| 240 TEST_F(AudioBusTest, FromInterleaved) { |
| 241 scoped_ptr<AudioBus> bus = AudioBus::Create( |
| 242 kTestVectorChannels, kTestVectorFrames); |
| 243 scoped_ptr<AudioBus> expected = AudioBus::Create( |
| 244 kTestVectorChannels, kTestVectorFrames); |
| 245 for (int ch = 0; ch < kTestVectorChannels; ++ch) { |
| 246 memcpy(expected->channel(ch), kTestVectorResult[ch], |
| 247 kTestVectorFrames * sizeof(*expected->channel(ch))); |
| 248 } |
| 249 { |
| 250 SCOPED_TRACE("uint8"); |
| 251 bus->FromInterleaved( |
| 252 kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8)); |
| 253 VerifyBus(bus.get(), expected.get()); |
| 254 } |
| 255 { |
| 256 SCOPED_TRACE("int16"); |
| 257 bus->FromInterleaved( |
| 258 kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16)); |
| 259 VerifyBus(bus.get(), expected.get()); |
| 260 } |
| 261 { |
| 262 SCOPED_TRACE("int32"); |
| 263 bus->FromInterleaved( |
| 264 kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32)); |
| 265 VerifyBus(bus.get(), expected.get()); |
| 266 } |
| 267 } |
| 268 |
| 269 // Verify ToInterleaved() interleaves audio in suported formats correctly. |
| 270 TEST_F(AudioBusTest, ToInterleaved) { |
| 271 scoped_ptr<AudioBus> bus = AudioBus::Create( |
| 272 kTestVectorChannels, kTestVectorFrames); |
| 273 // Fill the bus with our test vector. |
| 274 for (int ch = 0; ch < kTestVectorChannels; ++ch) { |
| 275 memcpy(bus->channel(ch), kTestVectorResult[ch], |
| 276 kTestVectorFrames * sizeof(*bus->channel(ch))); |
| 277 } |
| 278 { |
| 279 SCOPED_TRACE("uint8"); |
| 280 uint8 test_array[arraysize(kTestVectorUint8)]; |
| 281 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array); |
| 282 ASSERT_EQ(memcmp( |
| 283 test_array, kTestVectorUint8, arraysize(kTestVectorUint8)), 0); |
| 284 } |
| 285 { |
| 286 SCOPED_TRACE("int16"); |
| 287 int16 test_array[arraysize(kTestVectorInt16)]; |
| 288 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array); |
| 289 ASSERT_EQ(memcmp( |
| 290 test_array, kTestVectorInt16, arraysize(kTestVectorInt16)), 0); |
| 291 } |
| 292 { |
| 293 SCOPED_TRACE("int32"); |
| 294 int32 test_array[arraysize(kTestVectorInt32)]; |
| 295 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array); |
| 296 ASSERT_EQ(memcmp( |
| 297 test_array, kTestVectorInt32, arraysize(kTestVectorInt32)), 0); |
| 298 } |
| 299 } |
| 300 |
| 127 } // namespace media | 301 } // namespace media |
| OLD | NEW |