Home | History | Annotate | Download | only in base
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/strings/stringprintf.h"
      6 #include "base/time/time.h"
      7 #include "build/build_config.h"
      8 #include "media/audio/audio_parameters.h"
      9 #include "media/base/audio_bus.h"
     10 #include "media/base/channel_layout.h"
     11 #include "media/base/fake_audio_render_callback.h"
     12 #include "testing/gtest/include/gtest/gtest.h"
     13 
     14 namespace media {
     15 
     16 static const int kChannels = 6;
     17 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_5_1;
     18 // Use a buffer size which is intentionally not a multiple of kChannelAlignment.
     19 static const int kFrameCount = media::AudioBus::kChannelAlignment * 32 - 1;
     20 static const int kSampleRate = 48000;
     21 
     22 class AudioBusTest : public testing::Test {
     23  public:
     24   AudioBusTest() {}
     25   virtual ~AudioBusTest() {
     26     for (size_t i = 0; i < data_.size(); ++i)
     27       base::AlignedFree(data_[i]);
     28   }
     29 
     30   // Validate parameters returned by AudioBus v.s. the constructed parameters.
     31   void VerifyParams(AudioBus* bus) {
     32     EXPECT_EQ(kChannels, bus->channels());
     33     EXPECT_EQ(kFrameCount, bus->frames());
     34   }
     35 
     36   void VerifyValue(const float data[], int size, float value) {
     37     for (int i = 0; i < size; ++i)
     38       ASSERT_FLOAT_EQ(value, data[i]) << "i=" << i;
     39   }
     40 
     41   // Verify values for each channel in |result| are within |epsilon| of
     42   // |expected|.  If |epsilon| exactly equals 0, uses FLOAT_EQ macro.
     43   void VerifyBusWithEpsilon(const AudioBus* result, const AudioBus* expected,
     44                             float epsilon) {
     45     ASSERT_EQ(expected->channels(), result->channels());
     46     ASSERT_EQ(expected->frames(), result->frames());
     47     for (int ch = 0; ch < result->channels(); ++ch) {
     48       for (int i = 0; i < result->frames(); ++i) {
     49         SCOPED_TRACE(base::StringPrintf("ch=%d, i=%d", ch, i));
     50         if (epsilon == 0) {
     51           ASSERT_FLOAT_EQ(expected->channel(ch)[i], result->channel(ch)[i]);
     52         } else {
     53           ASSERT_NEAR(expected->channel(ch)[i], result->channel(ch)[i],
     54                       epsilon);
     55         }
     56       }
     57     }
     58   }
     59 
     60   // Verify values for each channel in |result| against |expected|.
     61   void VerifyBus(const AudioBus* result, const AudioBus* expected) {
     62     VerifyBusWithEpsilon(result, expected, 0);
     63   }
     64 
     65   // Read and write to the full extent of the allocated channel data.  Also test
     66   // the Zero() method and verify it does as advertised.  Also test data if data
     67   // is 16-byte aligned as advertised (see kChannelAlignment in audio_bus.h).
     68   void VerifyChannelData(AudioBus* bus) {
     69     for (int i = 0; i < bus->channels(); ++i) {
     70       ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(
     71           bus->channel(i)) & (AudioBus::kChannelAlignment - 1));
     72       std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i);
     73     }
     74 
     75     for (int i = 0; i < bus->channels(); ++i)
     76       VerifyValue(bus->channel(i), bus->frames(), i);
     77 
     78     bus->Zero();
     79     for (int i = 0; i < bus->channels(); ++i)
     80       VerifyValue(bus->channel(i), bus->frames(), 0);
     81   }
     82 
     83   // Verify copying to and from |bus1| and |bus2|.
     84   void CopyTest(AudioBus* bus1, AudioBus* bus2) {
     85     // Fill |bus1| with dummy data.
     86     for (int i = 0; i < bus1->channels(); ++i)
     87       std::fill(bus1->channel(i), bus1->channel(i) + bus1->frames(), i);
     88 
     89     // Verify copy from |bus1| to |bus2|.
     90     bus2->Zero();
     91     bus1->CopyTo(bus2);
     92     VerifyBus(bus1, bus2);
     93 
     94     // Verify copy from |bus2| to |bus1|.
     95     bus1->Zero();
     96     bus2->CopyTo(bus1);
     97     VerifyBus(bus2, bus1);
     98   }
     99 
    100  protected:
    101   std::vector<float*> data_;
    102 
    103   DISALLOW_COPY_AND_ASSIGN(AudioBusTest);
    104 };
    105 
    106 // Verify basic Create(...) method works as advertised.
    107 TEST_F(AudioBusTest, Create) {
    108   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
    109   VerifyParams(bus.get());
    110   VerifyChannelData(bus.get());
    111 }
    112 
    113 // Verify Create(...) using AudioParameters works as advertised.
    114 TEST_F(AudioBusTest, CreateUsingAudioParameters) {
    115   scoped_ptr<AudioBus> bus = AudioBus::Create(AudioParameters(
    116       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
    117       kFrameCount));
    118   VerifyParams(bus.get());
    119   VerifyChannelData(bus.get());
    120 }
    121 
    122 // Verify an AudioBus created via wrapping a vector works as advertised.
    123 TEST_F(AudioBusTest, WrapVector) {
    124   data_.reserve(kChannels);
    125   for (int i = 0; i < kChannels; ++i) {
    126     data_.push_back(static_cast<float*>(base::AlignedAlloc(
    127         sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
    128   }
    129 
    130   scoped_ptr<AudioBus> bus = AudioBus::WrapVector(kFrameCount, data_);
    131   VerifyParams(bus.get());
    132   VerifyChannelData(bus.get());
    133 }
    134 
    135 // Verify an AudioBus created via wrapping a memory block works as advertised.
    136 TEST_F(AudioBusTest, WrapMemory) {
    137   AudioParameters params(
    138       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
    139       kFrameCount);
    140   int data_size = AudioBus::CalculateMemorySize(params);
    141   scoped_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>(
    142       base::AlignedAlloc(data_size, AudioBus::kChannelAlignment)));
    143 
    144   // Fill the memory with a test value we can check for after wrapping.
    145   static const float kTestValue = 3;
    146   std::fill(
    147       data.get(), data.get() + data_size / sizeof(*data.get()), kTestValue);
    148 
    149   scoped_ptr<AudioBus> bus = AudioBus::WrapMemory(params, data.get());
    150   // Verify the test value we filled prior to wrapping.
    151   for (int i = 0; i < bus->channels(); ++i)
    152     VerifyValue(bus->channel(i), bus->frames(), kTestValue);
    153   VerifyParams(bus.get());
    154   VerifyChannelData(bus.get());
    155 
    156   // Verify the channel vectors lie within the provided memory block.
    157   EXPECT_GE(bus->channel(0), data.get());
    158   EXPECT_LT(bus->channel(bus->channels() - 1) + bus->frames(),
    159             data.get() + data_size / sizeof(*data.get()));
    160 }
    161 
    162 // Simulate a shared memory transfer and verify results.
    163 TEST_F(AudioBusTest, CopyTo) {
    164   // Create one bus with AudioParameters and the other through direct values to
    165   // test for parity between the Create() functions.
    166   AudioParameters params(
    167       AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout, kSampleRate, 32,
    168       kFrameCount);
    169   scoped_ptr<AudioBus> bus1 = AudioBus::Create(kChannels, kFrameCount);
    170   scoped_ptr<AudioBus> bus2 = AudioBus::Create(params);
    171 
    172   {
    173     SCOPED_TRACE("Created");
    174     CopyTest(bus1.get(), bus2.get());
    175   }
    176   {
    177     SCOPED_TRACE("Wrapped Vector");
    178     // Try a copy to an AudioBus wrapping a vector.
    179     data_.reserve(kChannels);
    180     for (int i = 0; i < kChannels; ++i) {
    181       data_.push_back(static_cast<float*>(base::AlignedAlloc(
    182           sizeof(*data_[i]) * kFrameCount, AudioBus::kChannelAlignment)));
    183     }
    184 
    185     bus2 = AudioBus::WrapVector(kFrameCount, data_);
    186     CopyTest(bus1.get(), bus2.get());
    187   }
    188   {
    189     SCOPED_TRACE("Wrapped Memory");
    190     // Try a copy to an AudioBus wrapping a memory block.
    191     scoped_ptr<float, base::AlignedFreeDeleter> data(
    192         static_cast<float*>(base::AlignedAlloc(
    193             AudioBus::CalculateMemorySize(params),
    194             AudioBus::kChannelAlignment)));
    195 
    196     bus2 = AudioBus::WrapMemory(params, data.get());
    197     CopyTest(bus1.get(), bus2.get());
    198   }
    199 }
    200 
    201 // Verify Zero() and ZeroFrames(...) utility methods work as advertised.
    202 TEST_F(AudioBusTest, Zero) {
    203   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
    204 
    205   // Fill the bus with dummy data.
    206   for (int i = 0; i < bus->channels(); ++i)
    207     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
    208 
    209   // Zero first half the frames of each channel.
    210   bus->ZeroFrames(kFrameCount / 2);
    211   for (int i = 0; i < bus->channels(); ++i) {
    212     SCOPED_TRACE("First Half Zero");
    213     VerifyValue(bus->channel(i), kFrameCount / 2, 0);
    214     VerifyValue(bus->channel(i) + kFrameCount / 2,
    215                 kFrameCount - kFrameCount / 2, i + 1);
    216   }
    217 
    218   // Fill the bus with dummy data.
    219   for (int i = 0; i < bus->channels(); ++i)
    220     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
    221 
    222   // Zero the last half of the frames.
    223   bus->ZeroFramesPartial(kFrameCount / 2, kFrameCount - kFrameCount / 2);
    224   for (int i = 0; i < bus->channels(); ++i) {
    225     SCOPED_TRACE("Last Half Zero");
    226     VerifyValue(bus->channel(i) + kFrameCount / 2,
    227                 kFrameCount - kFrameCount / 2, 0);
    228     VerifyValue(bus->channel(i), kFrameCount / 2, i + 1);
    229   }
    230 
    231   // Fill the bus with dummy data.
    232   for (int i = 0; i < bus->channels(); ++i)
    233     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), i + 1);
    234 
    235   // Zero all the frames of each channel.
    236   bus->Zero();
    237   for (int i = 0; i < bus->channels(); ++i) {
    238     SCOPED_TRACE("All Zero");
    239     VerifyValue(bus->channel(i), bus->frames(), 0);
    240   }
    241 }
    242 
    243 // Each test vector represents two channels of data in the following arbitrary
    244 // layout: <min, zero, max, min, max / 2, min / 2, zero, max, zero, zero>.
    245 static const int kTestVectorSize = 10;
    246 static const uint8 kTestVectorUint8[kTestVectorSize] = {
    247     0, -kint8min, kuint8max, 0, kint8max / 2 + 128, kint8min / 2 + 128,
    248     -kint8min, kuint8max, -kint8min, -kint8min };
    249 static const int16 kTestVectorInt16[kTestVectorSize] = {
    250     kint16min, 0, kint16max, kint16min, kint16max / 2, kint16min / 2,
    251     0, kint16max, 0, 0 };
    252 static const int32 kTestVectorInt32[kTestVectorSize] = {
    253     kint32min, 0, kint32max, kint32min, kint32max / 2, kint32min / 2,
    254     0, kint32max, 0, 0 };
    255 
    256 // Expected results.
    257 static const int kTestVectorFrames = kTestVectorSize / 2;
    258 static const float kTestVectorResult[][kTestVectorFrames] = {
    259     { -1, 1, 0.5, 0, 0 }, { 0, -1, -0.5, 1, 0 }};
    260 static const int kTestVectorChannels = arraysize(kTestVectorResult);
    261 
    262 // Verify FromInterleaved() deinterleaves audio in supported formats correctly.
    263 TEST_F(AudioBusTest, FromInterleaved) {
    264   scoped_ptr<AudioBus> bus = AudioBus::Create(
    265       kTestVectorChannels, kTestVectorFrames);
    266   scoped_ptr<AudioBus> expected = AudioBus::Create(
    267       kTestVectorChannels, kTestVectorFrames);
    268   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
    269     memcpy(expected->channel(ch), kTestVectorResult[ch],
    270            kTestVectorFrames * sizeof(*expected->channel(ch)));
    271   }
    272   {
    273     SCOPED_TRACE("uint8");
    274     bus->Zero();
    275     bus->FromInterleaved(
    276         kTestVectorUint8, kTestVectorFrames, sizeof(*kTestVectorUint8));
    277     // Biased uint8 calculations have poor precision, so the epsilon here is
    278     // slightly more permissive than int16 and int32 calculations.
    279     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint8max - 1));
    280   }
    281   {
    282     SCOPED_TRACE("int16");
    283     bus->Zero();
    284     bus->FromInterleaved(
    285         kTestVectorInt16, kTestVectorFrames, sizeof(*kTestVectorInt16));
    286     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint16max + 1.0f));
    287   }
    288   {
    289     SCOPED_TRACE("int32");
    290     bus->Zero();
    291     bus->FromInterleaved(
    292         kTestVectorInt32, kTestVectorFrames, sizeof(*kTestVectorInt32));
    293     VerifyBusWithEpsilon(bus.get(), expected.get(), 1.0f / (kuint32max + 1.0f));
    294   }
    295 }
    296 
    297 // Verify FromInterleavedPartial() deinterleaves audio correctly.
    298 TEST_F(AudioBusTest, FromInterleavedPartial) {
    299   // Only deinterleave the middle two frames in each channel.
    300   static const int kPartialStart = 1;
    301   static const int kPartialFrames = 2;
    302   ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames);
    303 
    304   scoped_ptr<AudioBus> bus = AudioBus::Create(
    305       kTestVectorChannels, kTestVectorFrames);
    306   scoped_ptr<AudioBus> expected = AudioBus::Create(
    307       kTestVectorChannels, kTestVectorFrames);
    308   expected->Zero();
    309   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
    310     memcpy(expected->channel(ch) + kPartialStart,
    311            kTestVectorResult[ch] + kPartialStart,
    312            kPartialFrames * sizeof(*expected->channel(ch)));
    313   }
    314 
    315   bus->Zero();
    316   bus->FromInterleavedPartial(
    317       kTestVectorInt32 + kPartialStart * bus->channels(), kPartialStart,
    318       kPartialFrames, sizeof(*kTestVectorInt32));
    319   VerifyBus(bus.get(), expected.get());
    320 }
    321 
    322 // Verify ToInterleaved() interleaves audio in suported formats correctly.
    323 TEST_F(AudioBusTest, ToInterleaved) {
    324   scoped_ptr<AudioBus> bus = AudioBus::Create(
    325       kTestVectorChannels, kTestVectorFrames);
    326   // Fill the bus with our test vector.
    327   for (int ch = 0; ch < bus->channels(); ++ch) {
    328     memcpy(bus->channel(ch), kTestVectorResult[ch],
    329            kTestVectorFrames * sizeof(*bus->channel(ch)));
    330   }
    331   {
    332     SCOPED_TRACE("uint8");
    333     uint8 test_array[arraysize(kTestVectorUint8)];
    334     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorUint8), test_array);
    335     ASSERT_EQ(memcmp(
    336         test_array, kTestVectorUint8, sizeof(kTestVectorUint8)), 0);
    337   }
    338   {
    339     SCOPED_TRACE("int16");
    340     int16 test_array[arraysize(kTestVectorInt16)];
    341     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt16), test_array);
    342     ASSERT_EQ(memcmp(
    343         test_array, kTestVectorInt16, sizeof(kTestVectorInt16)), 0);
    344   }
    345   {
    346     SCOPED_TRACE("int32");
    347     int32 test_array[arraysize(kTestVectorInt32)];
    348     bus->ToInterleaved(bus->frames(), sizeof(*kTestVectorInt32), test_array);
    349 
    350     // Some compilers get better precision than others on the half-max test, so
    351     // let the test pass with an off by one check on the half-max.
    352     int32 fixed_test_array[arraysize(kTestVectorInt32)];
    353     memcpy(fixed_test_array, kTestVectorInt32, sizeof(kTestVectorInt32));
    354     ASSERT_EQ(fixed_test_array[4], kint32max / 2);
    355     fixed_test_array[4]++;
    356 
    357     ASSERT_TRUE(
    358        memcmp(test_array, kTestVectorInt32, sizeof(kTestVectorInt32)) == 0 ||
    359        memcmp(test_array, fixed_test_array, sizeof(fixed_test_array)) == 0);
    360   }
    361 }
    362 
    363 // Verify ToInterleavedPartial() interleaves audio correctly.
    364 TEST_F(AudioBusTest, ToInterleavedPartial) {
    365   // Only interleave the middle two frames in each channel.
    366   static const int kPartialStart = 1;
    367   static const int kPartialFrames = 2;
    368   ASSERT_LE(kPartialStart + kPartialFrames, kTestVectorFrames);
    369 
    370   scoped_ptr<AudioBus> expected = AudioBus::Create(
    371       kTestVectorChannels, kTestVectorFrames);
    372   for (int ch = 0; ch < kTestVectorChannels; ++ch) {
    373     memcpy(expected->channel(ch), kTestVectorResult[ch],
    374            kTestVectorFrames * sizeof(*expected->channel(ch)));
    375   }
    376 
    377   int16 test_array[arraysize(kTestVectorInt16)];
    378   expected->ToInterleavedPartial(
    379       kPartialStart, kPartialFrames, sizeof(*kTestVectorInt16), test_array);
    380   ASSERT_EQ(memcmp(
    381       test_array, kTestVectorInt16 + kPartialStart * kTestVectorChannels,
    382       kPartialFrames * sizeof(*kTestVectorInt16) * kTestVectorChannels), 0);
    383 }
    384 
    385 TEST_F(AudioBusTest, Scale) {
    386   scoped_ptr<AudioBus> bus = AudioBus::Create(kChannels, kFrameCount);
    387 
    388   // Fill the bus with dummy data.
    389   static const float kFillValue = 1;
    390   for (int i = 0; i < bus->channels(); ++i)
    391     std::fill(bus->channel(i), bus->channel(i) + bus->frames(), kFillValue);
    392 
    393   // Adjust by an invalid volume and ensure volume is unchanged.
    394   bus->Scale(-1);
    395   for (int i = 0; i < bus->channels(); ++i) {
    396     SCOPED_TRACE("Invalid Scale");
    397     VerifyValue(bus->channel(i), bus->frames(), kFillValue);
    398   }
    399 
    400   // Verify correct volume adjustment.
    401   static const float kVolume = 0.5;
    402   bus->Scale(kVolume);
    403   for (int i = 0; i < bus->channels(); ++i) {
    404     SCOPED_TRACE("Half Scale");
    405     VerifyValue(bus->channel(i), bus->frames(), kFillValue * kVolume);
    406   }
    407 
    408   // Verify zero volume case.
    409   bus->Scale(0);
    410   for (int i = 0; i < bus->channels(); ++i) {
    411     SCOPED_TRACE("Zero Scale");
    412     VerifyValue(bus->channel(i), bus->frames(), 0);
    413   }
    414 }
    415 
    416 }  // namespace media
    417