summaryrefslogtreecommitdiff
path: root/media/base/audio_bus_unittest.cc
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2012-11-14 11:43:16 +0000
committerTorne (Richard Coles) <torne@google.com>2012-11-14 11:43:16 +0000
commit5821806d5e7f356e8fa4b058a389a808ea183019 (patch)
treee19f4793aac92e2c0d9a01087019a60d6657d838 /media/base/audio_bus_unittest.cc
parent8e79a8efe247f109aafd917a69e8a392961b3687 (diff)
downloadchromium_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.cc337
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