| 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 kChannelAlignment. |
| 13 // kChannelAlignment in audio_bus.cc. | 17 static const int kFrameCount = media::AudioBus::kChannelAlignment * 128 - 1; |
| 14 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)); |
| 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.h). |
| 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>( |
| 59 bus->channel(i)) & (AudioBus::kChannelAlignment - 1)); |
| 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 |
| 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 } |
| 54 | 87 |
| 55 protected: | 88 protected: |
| 56 std::vector<float*> data_; | 89 std::vector<float*> data_; |
| 57 | 90 |
| 58 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); | 91 DISALLOW_COPY_AND_ASSIGN(AudioBusTest); |
| 59 }; | 92 }; |
| 60 | 93 |
| 61 // Verify basic Create(...) method works as advertised. | 94 // Verify basic Create(...) method works as advertised. |
| 62 TEST_F(AudioBusTest, Create) { | 95 TEST_F(AudioBusTest, Create) { |
| 63 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 96 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 64 VerifyParams(bus.get()); | 97 VerifyParams(bus.get()); |
| 65 VerifyChannelData(bus.get()); | 98 VerifyChannelData(bus.get()); |
| 66 } | 99 } |
| 67 | 100 |
| 68 // Verify Create(...) using AudioParameters works as advertised. | 101 // Verify Create(...) using AudioParameters works as advertised. |
| 69 TEST_F(AudioBusTest, CreateUsingAudioParameters) { | 102 TEST_F(AudioBusTest, CreateUsingAudioParameters) { |
| 70 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( | 103 scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( |
| 71 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, 48000, 32, | 104 AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, |
| 72 kFrameCount)); | 105 kFrameCount)); |
| 73 VerifyParams(bus.get()); | 106 VerifyParams(bus.get()); |
| 74 VerifyChannelData(bus.get()); | 107 VerifyChannelData(bus.get()); |
| 75 } | 108 } |
| 76 | 109 |
| 77 // Verify an AudioBus created via wrapping works as advertised. | 110 // Verify an AudioBus created via wrapping a vector works as advertised. |
| 78 TEST_F(AudioBusTest, Wrap) { | 111 TEST_F(AudioBusTest, WrapVector) { |
| 79 data_.reserve(kChannels); | 112 data_.reserve(kChannels); |
| 80 for (int i = 0; i < kChannels; ++i) { | 113 for (int i = 0; i < kChannels; ++i) { |
| 81 data_.push_back(static_cast<float*>(base::AlignedAlloc( | 114 data_.push_back(static_cast<float*>(base::AlignedAlloc( |
| 82 sizeof(*data_[i]) * kFrameCount, 16))); | 115 sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment))); |
| 83 } | 116 } |
| 84 | 117 |
| 85 scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_); | 118 scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_); |
| 86 VerifyParams(bus.get()); | 119 VerifyParams(bus.get()); |
| 87 VerifyChannelData(bus.get()); | 120 VerifyChannelData(bus.get()); |
| 88 } | 121 } |
| 89 | 122 |
| 123 // Verify an AudioBus created via wrapping a memory block works as advertised. |
| 124 TEST_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 |
| 90 // Simulate a shared memory transfer and verify results. | 150 // Simulate a shared memory transfer and verify results. |
| 91 TEST_F(AudioBusTest, AudioData) { | 151 TEST_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); |
| 92 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); | 157 scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); |
| 93 scoped_ptr<AudioBus> bus2 = AudioBus::Create(kChannels, kFrameCount); | 158 scoped_ptr<AudioBus> bus2 = AudioBus::Create(params); |
| 94 | 159 |
| 95 // Fill |bus1| with dummy data and zero out |bus2|. | 160 { |
| 96 for (int i = 0; i < bus1->channels(); ++i) | 161 SCOPED_TRACE("Created"); |
| 97 std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); | 162 CopyTest(bus1.get(), bus2.get()); |
| 98 bus2->Zero(); | 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 } |
| 99 | 172 |
| 100 // Transfer audio data from |bus1| to |bus2|. | 173 bus2 = AudioBus::WrapVector(kFrameCount, data_); |
| 101 ASSERT_EQ(bus1->data_size(), bus2->data_size()); | 174 CopyTest(bus1.get(), bus2.get()); |
| 102 memcpy(bus2->data(), bus1->data(), bus1->data_size()); | 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))); |
| 103 | 183 |
| 104 for (int i = 0; i < bus2->channels(); ++i) | 184 bus2 = AudioBus::WrapMemory(params, data.get()); |
| 105 VerifyValue(bus2->channel(i), bus2->frames(), i); | 185 CopyTest(bus1.get(), bus2.get()); |
| 186 } |
| 106 } | 187 } |
| 107 | 188 |
| 108 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. | 189 // Verify Zero() and ZeroFrames(...) utility methods work as advertised. |
| 109 TEST_F(AudioBusTest, Zero) { | 190 TEST_F(AudioBusTest, Zero) { |
| 110 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); | 191 scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); |
| 111 | 192 |
| 112 // First fill the bus with dummy data. | 193 // First fill the bus with dummy data. |
| 113 for (int i = 0; i < bus->channels(); ++i) | 194 for (int i = 0; i < bus->channels(); ++i) |
| 114 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); | 195 std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); |
| 115 | 196 |
| 116 // Zero half the frames of each channel. | 197 // Zero half the frames of each channel. |
| 117 bus->ZeroFrames(kFrameCount / 2); | 198 bus->ZeroFrames(kFrameCount / 2); |
| 118 for (int i = 0; i < bus->channels(); ++i) | 199 for (int i = 0; i < bus->channels(); ++i) |
| 119 VerifyValue(bus->channel(i), kFrameCount / 2, 0); | 200 VerifyValue(bus->channel(i), kFrameCount / 2, 0); |
| 120 | 201 |
| 121 // Zero all the frames of each channel. | 202 // Zero all the frames of each channel. |
| 122 bus->Zero(); | 203 bus->Zero(); |
| 123 for (int i = 0; i < bus->channels(); ++i) | 204 for (int i = 0; i < bus->channels(); ++i) |
| 124 VerifyValue(bus->channel(i), bus->frames(), 0); | 205 VerifyValue(bus->channel(i), bus->frames(), 0); |
| 125 } | 206 } |
| 126 | 207 |
| 208 // Each test vector represents two channels of data in the following arbitrary |
| 209 // layout: <min, zero, max, min, zero, max, zero, zero>. |
| 210 static const int kTestVectorSize = 8; |
| 211 static const uint8 kTestVectorUint8[kTestVectorSize] = { |
| 212 0, -kint8min, kuint8max, 0, -kint8min, kuint8max, -kint8min, -kint8min }; |
| 213 static const int16 kTestVectorInt16[kTestVectorSize] = { |
| 214 kint16min, 0, kint16max, kint16min, 0, kint16max, 0, 0 }; |
| 215 static const int32 kTestVectorInt32[kTestVectorSize] = { |
| 216 kint32min, 0, kint32max, kint32min, 0, kint32max, 0, 0 }; |
| 217 |
| 218 // Expected results. |
| 219 static const int kTestVectorFrames = kTestVectorSize / 2; |
| 220 static const float kTestVectorResult[][kTestVectorFrames] = { |
| 221 { -1, 1, 0, 0 }, { 0, -1, 1, 0 }}; |
| 222 static const int kTestVectorChannels = arraysize(kTestVectorResult); |
| 223 |
| 224 // Verify FromInterleaved() deinterleaves audio in supported formats correctly. |
| 225 TEST_F(AudioBusTest, FromInterleaved) { |
| 226 scoped_ptr<AudioBus> bus = AudioBus::Create( |
| 227 kTestVectorChannels, kTestVectorFrames); |
| 228 scoped_ptr<AudioBus> expected = AudioBus::Create( |
| 229 kTestVectorChannels, kTestVectorFrames); |
| 230 for (int ch = 0; ch < kTestVectorChannels; ++ch) { |
| 231 memcpy(expected->channel(ch), kTestVectorResult[ch], |
| 232 kTestVectorFrames * sizeof(*expected->channel(ch))); |
| 233 } |
| 234 { |
| 235 SCOPED_TRACE("uint8"); |
| 236 bus->FromInterleaved( |
| 237 kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8)); |
| 238 VerifyBus(bus.get(), expected.get()); |
| 239 } |
| 240 { |
| 241 SCOPED_TRACE("int16"); |
| 242 bus->FromInterleaved( |
| 243 kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16)); |
| 244 VerifyBus(bus.get(), expected.get()); |
| 245 } |
| 246 { |
| 247 SCOPED_TRACE("int32"); |
| 248 bus->FromInterleaved( |
| 249 kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32)); |
| 250 VerifyBus(bus.get(), expected.get()); |
| 251 } |
| 252 } |
| 253 |
| 254 // Verify ToInterleaved() interleaves audio in suported formats correctly. |
| 255 TEST_F(AudioBusTest, ToInterleaved) { |
| 256 scoped_ptr<AudioBus> bus = AudioBus::Create( |
| 257 kTestVectorChannels, kTestVectorFrames); |
| 258 // Fill the bus with our test vector. |
| 259 for (int ch = 0; ch < kTestVectorChannels; ++ch) { |
| 260 memcpy(bus->channel(ch), kTestVectorResult[ch], |
| 261 kTestVectorFrames * sizeof(*bus->channel(ch))); |
| 262 } |
| 263 { |
| 264 SCOPED_TRACE("uint8"); |
| 265 uint8 test_array[arraysize(kTestVectorUint8)]; |
| 266 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array); |
| 267 ASSERT_EQ(memcmp( |
| 268 test_array, kTestVectorUint8, arraysize(kTestVectorUint8)), 0); |
| 269 } |
| 270 { |
| 271 SCOPED_TRACE("int16"); |
| 272 int16 test_array[arraysize(kTestVectorInt16)]; |
| 273 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array); |
| 274 ASSERT_EQ(memcmp( |
| 275 test_array, kTestVectorInt16, arraysize(kTestVectorInt16)), 0); |
| 276 } |
| 277 { |
| 278 SCOPED_TRACE("int32"); |
| 279 int32 test_array[arraysize(kTestVectorInt32)]; |
| 280 bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array); |
| 281 ASSERT_EQ(memcmp( |
| 282 test_array, kTestVectorInt32, arraysize(kTestVectorInt32)), 0); |
| 283 } |
| 284 } |
| 285 |
| 127 } // namespace media | 286 } // namespace media |
| OLD | NEW |