diff options
author | Torne (Richard Coles) <torne@google.com> | 2012-11-14 11:43:16 +0000 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2012-11-14 11:43:16 +0000 |
commit | 5821806d5e7f356e8fa4b058a389a808ea183019 (patch) | |
tree | e19f4793aac92e2c0d9a01087019a60d6657d838 /media/base/audio_bus_unittest.cc | |
parent | 8e79a8efe247f109aafd917a69e8a392961b3687 (diff) | |
download | chromium_org-5821806d5e7f356e8fa4b058a389a808ea183019.tar.gz |
Merge from Chromium at DEPS revision r167172
This commit was generated by merge_to_master.py.
Change-Id: Ib8d56fd5ae39a2d7e8c91dcd76cc6d13f25f2aab
Diffstat (limited to 'media/base/audio_bus_unittest.cc')
-rw-r--r-- | media/base/audio_bus_unittest.cc | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/media/base/audio_bus_unittest.cc b/media/base/audio_bus_unittest.cc new file mode 100644 index 0000000000..476c82ed15 --- /dev/null +++ b/media/base/audio_bus_unittest.cc @@ -0,0 +1,337 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <limits> + +#include "base/stringprintf.h" +#include "base/time.h" +#include "media/audio/audio_parameters.h" +#include "media/base/audio_bus.h" +#include "media/base/channel_layout.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace media { + +static const int kChannels = 6; +static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1; +// Use a buffer size which is intentionally not a multiple of kChannelAlignment. +static const int kFrameCount = media::AudioBus::kChannelAlignment * 32 - 1; +static const int kSampleRate = 48000; + +class AudioBusTest : public testing::Test { + public: + AudioBusTest() {} + ~AudioBusTest() { + for (size_t i = 0; i < data_.size(); ++i) + base::AlignedFree(data_[i]); + } + + // Validate parameters returned by AudioBus v.s. the constructed parameters. + void VerifyParams(AudioBus* bus) { + EXPECT_EQ(kChannels, bus->channels()); + EXPECT_EQ(kFrameCount, bus->frames()); + } + + void VerifyValue(const float data[], int size, float value) { + for (int i = 0; i < size; ++i) + ASSERT_FLOAT_EQ(value, data[i]) << "i=" << i; + } + + // Verify values for each channel in |result| against |expected|. + void VerifyBus(const AudioBus* result, const AudioBus* expected) { + ASSERT_EQ(expected->channels(), result->channels()); + ASSERT_EQ(expected->frames(), result->frames()); + for (int ch = 0; ch < result->channels(); ++ch) { + for (int i = 0; i < result->frames(); ++i) { + SCOPED_TRACE(base::StringPrintf("ch=%d, i=%d", ch, i)); + ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]); + } + } + } + + // Read and write to the full extent of the allocated channel data. Also test + // the Zero() method and verify it does as advertised. Also test data if data + // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.h). + void VerifyChannelData(AudioBus* bus) { + for (int i = 0; i < bus->channels(); ++i) { + ASSERT_EQ(0U, reinterpret_cast<uintptr_t>( + bus->channel(i)) & (AudioBus::kChannelAlignment - 1)); + std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i); + } + + for (int i = 0; i < bus->channels(); ++i) + VerifyValue(bus->channel(i), bus->frames(), i); + + bus->Zero(); + for (int i = 0; i < bus->channels(); ++i) + VerifyValue(bus->channel(i), bus->frames(), 0); + } + + // Verify copying to and from |bus1| and |bus2|. + void CopyTest(AudioBus* bus1, AudioBus* bus2) { + // Fill |bus1| with dummy data. + for (int i = 0; i < bus1->channels(); ++i) + std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i); + + // Verify copy from |bus1| to |bus2|. + bus2->Zero(); + bus1->CopyTo(bus2); + VerifyBus(bus1, bus2); + + // Verify copy from |bus2| to |bus1|. + bus1->Zero(); + bus2->CopyTo(bus1); + VerifyBus(bus2, bus1); + } + + protected: + std::vector<float*> data_; + + DISALLOW_COPY_AND_ASSIGN(AudioBusTest); +}; + +// Verify basic Create(...) method works as advertised. +TEST_F(AudioBusTest, Create) { + scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); + VerifyParams(bus.get()); + VerifyChannelData(bus.get()); +} + +// Verify Create(...) using AudioParameters works as advertised. +TEST_F(AudioBusTest, CreateUsingAudioParameters) { + scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters( + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, + kFrameCount)); + VerifyParams(bus.get()); + VerifyChannelData(bus.get()); +} + +// Verify an AudioBus created via wrapping a vector works as advertised. +TEST_F(AudioBusTest, WrapVector) { + data_.reserve(kChannels); + for (int i = 0; i < kChannels; ++i) { + data_.push_back(static_cast<float*>(base::AlignedAlloc( + sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment))); + } + + scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_); + VerifyParams(bus.get()); + VerifyChannelData(bus.get()); +} + +// Verify an AudioBus created via wrapping a memory block works as advertised. +TEST_F(AudioBusTest, WrapMemory) { + AudioParameters params( + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, + kFrameCount); + int data_size = AudioBus::CalculateMemorySize(params); + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data(static_cast<float*>( + base::AlignedAlloc(data_size, AudioBus::kChannelAlignment))); + + // Fill the memory with a test value we can check for after wrapping. + static const float kTestValue = 3; + std::fill( + data.get(), data.get() + data_size / sizeof(*data.get()), kTestValue); + + scoped_ptr<AudioBus> bus = AudioBus::WrapMemory(params, data.get()); + // Verify the test value we filled prior to wrapping. + for (int i = 0; i < bus->channels(); ++i) + VerifyValue(bus->channel(i), bus->frames(), kTestValue); + VerifyParams(bus.get()); + VerifyChannelData(bus.get()); + + // Verify the channel vectors lie within the provided memory block. + EXPECT_GE(bus->channel(0), data.get()); + EXPECT_LT(bus->channel(bus->channels() - 1) + bus->frames(), + data.get() + data_size / sizeof(*data.get())); +} + +// Simulate a shared memory transfer and verify results. +TEST_F(AudioBusTest, CopyTo) { + // Create one bus with AudioParameters and the other through direct values to + // test for parity between the Create() functions. + AudioParameters params( + AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32, + kFrameCount); + scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount); + scoped_ptr<AudioBus> bus2 = AudioBus::Create(params); + + { + SCOPED_TRACE("Created"); + CopyTest(bus1.get(), bus2.get()); + } + { + SCOPED_TRACE("Wrapped Vector"); + // Try a copy to an AudioBus wrapping a vector. + data_.reserve(kChannels); + for (int i = 0; i < kChannels; ++i) { + data_.push_back(static_cast<float*>(base::AlignedAlloc( + sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment))); + } + + bus2 = AudioBus::WrapVector(kFrameCount, data_); + CopyTest(bus1.get(), bus2.get()); + } + { + SCOPED_TRACE("Wrapped Memory"); + // Try a copy to an AudioBus wrapping a memory block. + scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data( + static_cast<float*>(base::AlignedAlloc( + AudioBus::CalculateMemorySize(params), + AudioBus::kChannelAlignment))); + + bus2 = AudioBus::WrapMemory(params, data.get()); + CopyTest(bus1.get(), bus2.get()); + } +} + +// Verify Zero() and ZeroFrames(...) utility methods work as advertised. +TEST_F(AudioBusTest, Zero) { + scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount); + + // Fill the bus with dummy data. + for (int i = 0; i < bus->channels(); ++i) + std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); + + // Zero first half the frames of each channel. + bus->ZeroFrames(kFrameCount / 2); + for (int i = 0; i < bus->channels(); ++i) { + SCOPED_TRACE("First Half Zero"); + VerifyValue(bus->channel(i), kFrameCount / 2, 0); + VerifyValue(bus->channel(i) + kFrameCount / 2, + kFrameCount - kFrameCount / 2, i + 1); + } + + // Fill the bus with dummy data. + for (int i = 0; i < bus->channels(); ++i) + std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); + + // Zero the last half of the frames. + bus->ZeroFramesPartial(kFrameCount / 2, kFrameCount - kFrameCount / 2); + for (int i = 0; i < bus->channels(); ++i) { + SCOPED_TRACE("Last Half Zero"); + VerifyValue(bus->channel(i) + kFrameCount / 2, + kFrameCount - kFrameCount / 2, 0); + VerifyValue(bus->channel(i), kFrameCount / 2, i + 1); + } + + // Fill the bus with dummy data. + for (int i = 0; i < bus->channels(); ++i) + std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1); + + // Zero all the frames of each channel. + bus->Zero(); + for (int i = 0; i < bus->channels(); ++i) { + SCOPED_TRACE("All Zero"); + VerifyValue(bus->channel(i), bus->frames(), 0); + } +} + +// Each test vector represents two channels of data in the following arbitrary +// layout: <min, zero, max, min, zero, max, zero, zero>. +static const int kTestVectorSize = 8; +static const uint8 kTestVectorUint8[kTestVectorSize] = { + 0, -kint8min, kuint8max, 0, -kint8min, kuint8max, -kint8min, -kint8min }; +static const int16 kTestVectorInt16[kTestVectorSize] = { + kint16min, 0, kint16max, kint16min, 0, kint16max, 0, 0 }; +static const int32 kTestVectorInt32[kTestVectorSize] = { + kint32min, 0, kint32max, kint32min, 0, kint32max, 0, 0 }; + +// Expected results. +static const int kTestVectorFrames = kTestVectorSize / 2; +static const float kTestVectorResult[][kTestVectorFrames] = { + { -1, 1, 0, 0 }, { 0, -1, 1, 0 }}; +static const int kTestVectorChannels = arraysize(kTestVectorResult); + +// Verify FromInterleaved() deinterleaves audio in supported formats correctly. +TEST_F(AudioBusTest, FromInterleaved) { + scoped_ptr<AudioBus> bus = AudioBus::Create( + kTestVectorChannels, kTestVectorFrames); + scoped_ptr<AudioBus> expected = AudioBus::Create( + kTestVectorChannels, kTestVectorFrames); + for (int ch = 0; ch < kTestVectorChannels; ++ch) { + memcpy(expected->channel(ch), kTestVectorResult[ch], + kTestVectorFrames * sizeof(*expected->channel(ch))); + } + { + SCOPED_TRACE("uint8"); + bus->Zero(); + bus->FromInterleaved( + kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8)); + VerifyBus(bus.get(), expected.get()); + } + { + SCOPED_TRACE("int16"); + bus->Zero(); + bus->FromInterleaved( + kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16)); + VerifyBus(bus.get(), expected.get()); + } + { + SCOPED_TRACE("int32"); + bus->Zero(); + bus->FromInterleaved( + kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32)); + VerifyBus(bus.get(), expected.get()); + } +} + +// Verify FromInterleavedPartial() deinterleaves audio correctly. +TEST_F(AudioBusTest, FromInterleavedPartial) { + // Only deinterleave the middle two frames in each channel. + static const int kPartialStart = 1; + static const int kPartialFrames = 2; + ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames); + + scoped_ptr<AudioBus> bus = AudioBus::Create( + kTestVectorChannels, kTestVectorFrames); + scoped_ptr<AudioBus> expected = AudioBus::Create( + kTestVectorChannels, kTestVectorFrames); + expected->Zero(); + for (int ch = 0; ch < kTestVectorChannels; ++ch) { + memcpy(expected->channel(ch) + kPartialStart, + kTestVectorResult[ch] + kPartialStart, + kPartialFrames * sizeof(*expected->channel(ch))); + } + + bus->Zero(); + bus->FromInterleavedPartial( + kTestVectorInt32 + kPartialStart * bus->channels(), kPartialStart, + kPartialFrames, sizeof(*kTestVectorInt32)); + VerifyBus(bus.get(), expected.get()); +} + +// Verify ToInterleaved() interleaves audio in suported formats correctly. +TEST_F(AudioBusTest, ToInterleaved) { + scoped_ptr<AudioBus> bus = AudioBus::Create( + kTestVectorChannels, kTestVectorFrames); + // Fill the bus with our test vector. + for (int ch = 0; ch < kTestVectorChannels; ++ch) { + memcpy(bus->channel(ch), kTestVectorResult[ch], + kTestVectorFrames * sizeof(*bus->channel(ch))); + } + { + SCOPED_TRACE("uint8"); + uint8 test_array[arraysize(kTestVectorUint8)]; + bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array); + ASSERT_EQ(memcmp( + test_array, kTestVectorUint8, arraysize(kTestVectorUint8)), 0); + } + { + SCOPED_TRACE("int16"); + int16 test_array[arraysize(kTestVectorInt16)]; + bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array); + ASSERT_EQ(memcmp( + test_array, kTestVectorInt16, arraysize(kTestVectorInt16)), 0); + } + { + SCOPED_TRACE("int32"); + int32 test_array[arraysize(kTestVectorInt32)]; + bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array); + ASSERT_EQ(memcmp( + test_array, kTestVectorInt32, arraysize(kTestVectorInt32)), 0); + } +} + +} // namespace media |