Chromium Code Reviews| 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" | |
| 5 #include "media/audio/audio_parameters.h" | 8 #include "media/audio/audio_parameters.h" |
| 6 #include "media/base/audio_bus.h" | 9 #include "media/base/audio_bus.h" |
| 7 #include "media/base/channel_layout.h" | 10 #include "media/base/channel_layout.h" |
| 8 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
| 9 | 12 |
| 10 static const int kChannels = 6; | 13 static const int kChannels = 6; |
| 11 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1; | 14 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1; |
| 12 // Use a buffer size which is intentionally not a multiple of 16; see | 15 // Use a buffer size which is intentionally not a multiple of 16; see |
| 13 // kChannelAlignment in audio_bus.cc. | 16 // kChannelAlignment in audio_bus.cc. |
| 14 static const int kFrameCount = 1234; | 17 static const int kFrameCount = 1234; |
| 18 static const int kSampleRate = 48000; | |
| 15 | 19 |
| 16 namespace media { | 20 namespace media { |
| 17 | 21 |
| 18 class AudioBusTest : public testing::Test { | 22 class AudioBusTest : public testing::Test { |
| 19 public: | 23 public: |
| 20 AudioBusTest() {} | 24 AudioBusTest() {} |
| 21 ~AudioBusTest() { | 25 ~AudioBusTest() { |
| 22 for (size_t i = 0; i < data_.size(); ++i) | 26 for (size_t i = 0; i < data_.size(); ++i) |
| 23 base::AlignedFree(data_[i]); | 27 base::AlignedFree(data_[i]); |
| 24 } | 28 } |
| 25 | 29 |
| 26 // Validate parameters returned by AudioBus v.s. the constructed parameters. | 30 // Validate parameters returned by AudioBus v.s. the constructed parameters. |
| 27 void VerifyParams(AudioBus* bus) { | 31 void VerifyParams(AudioBus* bus) { |
| 28 EXPECT_EQ(kChannels, bus->channels()); | 32 EXPECT_EQ(kChannels, bus->channels()); |
| 29 EXPECT_EQ(kFrameCount, bus->frames()); | 33 EXPECT_EQ(kFrameCount, bus->frames()); |
| 30 } | 34 } |
| 31 | 35 |
| 32 void VerifyValue(const float data[], int size, float value) { | 36 void VerifyValue(const float data[], int size, float value) { |
| 33 for (int i = 0; i < size; ++i) | 37 for (int i = 0; i < size; ++i) |
| 34 ASSERT_FLOAT_EQ(value, data[i]); | 38 ASSERT_FLOAT_EQ(value, data[i]); |
| 35 } | 39 } |
| 36 | 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)); | |
|
henrika (OOO until Aug 14)
2012/08/15 09:59:37
Cool. I have never seen this before. Thanks.
| |
| 48 ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]); | |
| 49 } | |
| 50 } | |
| 51 } | |
| 52 | |
| 37 // Read and write to the full extent of the allocated channel data. Also test | 53 // 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 | 54 // 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). | 55 // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.cc). |
| 40 void VerifyChannelData(AudioBus* bus) { | 56 void VerifyChannelData(AudioBus* bus) { |
| 41 for (int i = 0; i < bus->channels(); ++i) { | 57 for (int i = 0; i < bus->channels(); ++i) { |
| 42 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(bus->channel(i)) & 0x0F); | 58 ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(bus->channel(i)) & 0x0F); |
| 43 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i); | 59 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i); |
| 44 } | 60 } |
| 45 | 61 |
| 46 for (int i = 0; i < bus->channels(); ++i) | 62 for (int i = 0; i < bus->channels(); ++i) |
| 47 VerifyValue(bus->channel(i), bus->frames(), i); | 63 VerifyValue(bus->channel(i), bus->frames(), i); |
| 48 | 64 |
| 49 bus->Zero(); | 65 bus->Zero(); |
| 50 for (int i = 0; i < bus->channels(); ++i) | 66 for (int i = 0; i < bus->channels(); ++i) |
| 51 VerifyValue(bus->channel(i), bus->frames(), 0); | 67 VerifyValue(bus->channel(i), bus->frames(), 0); |
| 52 } | 68 } |
| 53 | 69 |
| 54 | |
| 55 protected: | 70 protected: |
| 56 std::vector<float*> data_; | 71 std::vector<float*> data_; |
| 57 | 72 |
| 58 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); | 73 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); |
| 59 }; | 74 }; |
| 60 | 75 |
| 61 // Verify basic Create(...) method works as advertised. | 76 // Verify basic Create(...) method works as advertised. |
| 62 TEST_F(AudioBusTest, Create) { | 77 TEST_F(AudioBusTest, Create) { |
| 63 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 78 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 64 VerifyParams(bus.get()); | 79 VerifyParams(bus.get()); |
| 65 VerifyChannelData(bus.get()); | 80 VerifyChannelData(bus.get()); |
| 66 } | 81 } |
| 67 | 82 |
| 68 // Verify Create(...) using AudioParameters works as advertised. | 83 // Verify Create(...) using AudioParameters works as advertised. |
| 69 TEST_F(AudioBusTest, CreateUsingAudioParameters) { | 84 TEST_F(AudioBusTest, CreateUsingAudioParameters) { |
| 70 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( | 85 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( |
| 71 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 48000, 32, | 86 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 72 kFrameCount)); | 87 kFrameCount)); |
| 73 VerifyParams(bus.get()); | 88 VerifyParams(bus.get()); |
| 74 VerifyChannelData(bus.get()); | 89 VerifyChannelData(bus.get()); |
| 90 EXPECT_EQ(bus->sample_rate(), kSampleRate); | |
| 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. | |
|
henrika (OOO until Aug 14)
2012/08/15 09:59:37
Strange sentence. Please read it again ;-)
DaleCurtis
2012/08/16 01:54:14
Not sure what's strange about it? :)
| |
| 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::ExpectedDataSize(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 EXPECT_EQ(bus->sample_rate(), kSampleRate); | |
| 138 | |
| 139 // Try with an unaligned pointer. | |
| 140 bus = AudioBus::WrapBlock(params, data.get()); | |
| 141 VerifyParams(bus.get()); | |
| 142 VerifyChannelData(bus.get()); | |
| 143 EXPECT_EQ(bus->sample_rate(), kSampleRate); | |
| 144 } | |
| 145 | |
| 90 // Simulate a shared memory transfer and verify results. | 146 // Simulate a shared memory transfer and verify results. |
| 91 TEST_F(AudioBusTest, AudioData) { | 147 TEST_F(AudioBusTest, AudioData) { |
| 148 // Create one bus with AudioParameters and the other through direct values to | |
| 149 // test for parity between the functions. | |
| 150 AudioParameters params( | |
| 151 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, | |
| 152 kFrameCount); | |
| 92 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); | 153 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); |
| 93 scoped_ptr<AudioBus> bus2 = AudioBus::Create(kChannels, kFrameCount); | 154 scoped_ptr<AudioBus> bus2 = AudioBus::Create(params); |
| 155 // Flip the order of which bus checks using params vs created with for parity. | |
| 156 ASSERT_EQ(bus1->data_size(), AudioBus::ExpectedDataSize(params)); | |
| 157 ASSERT_EQ(bus2->data_size(), | |
| 158 AudioBus::ExpectedDataSize(kChannels, kFrameCount)); | |
| 94 | 159 |
| 95 // Fill |bus1| with dummy data and zero out |bus2|. | 160 // Fill |bus1| with dummy data and zero out |bus2|. |
| 96 for (int i = 0; i < bus1->channels(); ++i) | 161 for (int i = 0; i < bus1->channels(); ++i) |
| 97 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); | 162 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); |
| 98 bus2->Zero(); | 163 bus2->Zero(); |
| 99 | 164 |
| 100 // Transfer audio data from |bus1| to |bus2|. | 165 // Transfer audio data from |bus1| to |bus2|. |
| 101 ASSERT_EQ(bus1->data_size(), bus2->data_size()); | 166 ASSERT_EQ(bus1->data_size(), bus2->data_size()); |
| 102 memcpy(bus2->data(), bus1->data(), bus1->data_size()); | 167 memcpy(bus2->data(), bus1->data(), bus1->data_size()); |
| 103 | 168 |
| 104 for (int i = 0; i < bus2->channels(); ++i) | 169 for (int i = 0; i < bus2->channels(); ++i) |
| 105 VerifyValue(bus2->channel(i), bus2->frames(), i); | 170 VerifyValue(bus2->channel(i), bus2->frames(), i); |
| 106 } | 171 } |
| 107 | 172 |
| 173 // Simulate a shared memory transfer from a wrapped to unwrapped AudioBus. | |
| 174 TEST_F(AudioBusTest, AudioDataWrapped) { | |
| 175 // Create one bus with AudioParameters and the other through direct values to | |
| 176 // test for parity between the functions. | |
| 177 AudioParameters params( | |
| 178 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, | |
| 179 kFrameCount); | |
| 180 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); | |
| 181 ASSERT_EQ(bus1->data_size(), AudioBus::ExpectedDataSize(params)); | |
| 182 scoped_ptr<AudioBus> bus2 = AudioBus::WrapBlock(params, bus1->data()); | |
| 183 | |
| 184 // Fill |bus1| with dummy data. | |
| 185 for (int i = 0; i < bus1->channels(); ++i) | |
| 186 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); | |
| 187 | |
| 188 // Verify the data is correct inside of |bus2|. | |
| 189 for (int i = 0; i < bus2->channels(); ++i) | |
| 190 VerifyValue(bus2->channel(i), bus2->frames(), i); | |
| 191 | |
| 192 // Zero |bus2| and ensure |bus1| is zero'd | |
| 193 bus2->Zero(); | |
| 194 for (int i = 0; i < bus1->channels(); ++i) | |
| 195 VerifyValue(bus1->channel(i), bus1->frames(), 0); | |
| 196 | |
| 197 // Fill |bus2| with dummy data. | |
| 198 for (int i = 0; i < bus2->channels(); ++i) | |
| 199 std::fill(bus2->channel(i), bus2->channel(i) + bus2->frames(), i); | |
| 200 | |
| 201 // Verify the data is correct inside of |bus1|. | |
| 202 for (int i = 0; i < bus1->channels(); ++i) | |
| 203 VerifyValue(bus1->channel(i), bus1->frames(), i); | |
| 204 } | |
| 205 | |
| 108 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. | 206 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. |
| 109 TEST_F(AudioBusTest, Zero) { | 207 TEST_F(AudioBusTest, Zero) { |
| 110 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 208 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 111 | 209 |
| 112 // First fill the bus with dummy data. | 210 // First fill the bus with dummy data. |
| 113 for (int i = 0; i < bus->channels(); ++i) | 211 for (int i = 0; i < bus->channels(); ++i) |
| 114 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); | 212 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); |
| 115 | 213 |
| 116 // Zero half the frames of each channel. | 214 // Zero half the frames of each channel. |
| 117 bus->ZeroFrames(kFrameCount / 2); | 215 bus->ZeroFrames(kFrameCount / 2); |
| 118 for (int i = 0; i < bus->channels(); ++i) | 216 for (int i = 0; i < bus->channels(); ++i) |
| 119 VerifyValue(bus->channel(i), kFrameCount / 2, 0); | 217 VerifyValue(bus->channel(i), kFrameCount / 2, 0); |
| 120 | 218 |
| 121 // Zero all the frames of each channel. | 219 // Zero all the frames of each channel. |
| 122 bus->Zero(); | 220 bus->Zero(); |
| 123 for (int i = 0; i < bus->channels(); ++i) | 221 for (int i = 0; i < bus->channels(); ++i) |
| 124 VerifyValue(bus->channel(i), bus->frames(), 0); | 222 VerifyValue(bus->channel(i), bus->frames(), 0); |
| 125 } | 223 } |
| 126 | 224 |
| 225 // Each test vector represents two channels of data in the following arbitrary | |
| 226 // layout: <min, zero, max, min, zero, max, zero, zero>. | |
| 227 static const int kTestVectorSize = 8; | |
| 228 static const uint8 kTestVectorUint8[kTestVectorSize] = { | |
| 229 0, -kint8min, kuint8max, 0, -kint8min, kuint8max, -kint8min, -kint8min }; | |
| 230 static const int16 kTestVectorInt16[kTestVectorSize] = { | |
| 231 kint16min, 0, kint16max, kint16min, 0, kint16max, 0, 0 }; | |
| 232 static const int32 kTestVectorInt32[kTestVectorSize] = { | |
| 233 kint32min, 0, kint32max, kint32min, 0, kint32max, 0, 0 }; | |
| 234 | |
| 235 // Expected results, the last value is unused. | |
| 236 static const int kTestVectorFrames = kTestVectorSize / 2; | |
| 237 static const float kTestVectorResult[][kTestVectorFrames] = { | |
| 238 { -1, 1, 0, 0 }, { 0, -1, 1, 0 }}; | |
| 239 static const int kTestVectorChannels = arraysize(kTestVectorResult); | |
| 240 | |
| 241 TEST_F(AudioBusTest, FromInterleaved) { | |
| 242 scoped_ptr<AudioBus> bus = AudioBus::Create( | |
| 243 kTestVectorChannels, kTestVectorFrames); | |
| 244 scoped_ptr<AudioBus> expected = AudioBus::Create( | |
| 245 kTestVectorChannels, kTestVectorFrames); | |
| 246 for (int ch = 0; ch < kTestVectorChannels; ++ch) { | |
| 247 memcpy(expected->channel(ch), kTestVectorResult[ch], | |
| 248 kTestVectorFrames * sizeof(*expected->channel(ch))); | |
| 249 } | |
| 250 { | |
| 251 SCOPED_TRACE("uint8"); | |
| 252 bus->FromInterleaved( | |
| 253 kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8)); | |
| 254 VerifyBus(bus.get(), expected.get()); | |
| 255 } | |
| 256 { | |
| 257 SCOPED_TRACE("int16"); | |
| 258 bus->FromInterleaved( | |
| 259 kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16)); | |
| 260 VerifyBus(bus.get(), expected.get()); | |
| 261 } | |
| 262 { | |
| 263 SCOPED_TRACE("int32"); | |
| 264 bus->FromInterleaved( | |
| 265 kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32)); | |
| 266 VerifyBus(bus.get(), expected.get()); | |
| 267 } | |
| 268 } | |
| 269 | |
| 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(test_array, bus->frames(), sizeof(*kTestVectorUint8)); | |
| 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(test_array, bus->frames(), sizeof(*kTestVectorInt16)); | |
| 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(test_array, bus->frames(), sizeof(*kTestVectorInt32)); | |
| 296 ASSERT_EQ(memcmp( | |
| 297 test_array, kTestVectorInt32, arraysize(kTestVectorInt32)), 0); | |
| 298 } | |
| 299 } | |
| 300 | |
| 127 } // namespace media | 301 } // namespace media |
| OLD | NEW |