Home | History | Annotate | Download | only in base
      1 // Copyright 2013 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/logging.h"
      6 #include "media/base/audio_bus.h"
      7 #include "media/base/audio_hash.h"
      8 #include "media/base/fake_audio_render_callback.h"
      9 #include "testing/gtest/include/gtest/gtest.h"
     10 
     11 namespace media {
     12 
     13 static const int kChannelCount = 2;
     14 static const int kFrameCount = 1024;
     15 
     16 class AudioHashTest : public testing::Test {
     17  public:
     18   AudioHashTest()
     19       : bus_one_(AudioBus::Create(kChannelCount, kFrameCount)),
     20         bus_two_(AudioBus::Create(kChannelCount, kFrameCount)),
     21         fake_callback_(0.01) {
     22 
     23     // Fill each channel in each bus with unique data.
     24     GenerateUniqueChannels(bus_one_.get());
     25     GenerateUniqueChannels(bus_two_.get());
     26   }
     27 
     28   void GenerateUniqueChannels(AudioBus* audio_bus) {
     29     // Use an AudioBus wrapper to avoid an extra memcpy when filling channels.
     30     scoped_ptr<AudioBus> wrapped_bus = AudioBus::CreateWrapper(1);
     31     wrapped_bus->set_frames(audio_bus->frames());
     32 
     33     // Since FakeAudioRenderCallback generates only a single channel of unique
     34     // audio data, we need to fill each channel manually.
     35     for (int ch = 0; ch < audio_bus->channels(); ++ch) {
     36       wrapped_bus->SetChannelData(0, audio_bus->channel(ch));
     37       fake_callback_.Render(wrapped_bus.get(), 0);
     38     }
     39   }
     40 
     41   virtual ~AudioHashTest() {}
     42 
     43  protected:
     44   scoped_ptr<AudioBus> bus_one_;
     45   scoped_ptr<AudioBus> bus_two_;
     46   FakeAudioRenderCallback fake_callback_;
     47 
     48   DISALLOW_COPY_AND_ASSIGN(AudioHashTest);
     49 };
     50 
     51 // Ensure the same data hashes the same.
     52 TEST_F(AudioHashTest, Equivalence) {
     53   AudioHash hash_one;
     54   hash_one.Update(bus_one_.get(), bus_one_->frames());
     55 
     56   AudioHash hash_two;
     57   hash_two.Update(bus_one_.get(), bus_one_->frames());
     58 
     59   EXPECT_EQ(hash_one.ToString(), hash_two.ToString());
     60 }
     61 
     62 // Ensure sample order matters to the hash.
     63 TEST_F(AudioHashTest, SampleOrder) {
     64   AudioHash original_hash;
     65   original_hash.Update(bus_one_.get(), bus_one_->frames());
     66 
     67   // Swap a sample in the bus.
     68   std::swap(bus_one_->channel(0)[0], bus_one_->channel(0)[1]);
     69 
     70   AudioHash swapped_hash;
     71   swapped_hash.Update(bus_one_.get(), bus_one_->frames());
     72 
     73   EXPECT_NE(original_hash.ToString(), swapped_hash.ToString());
     74 }
     75 
     76 // Ensure channel order matters to the hash.
     77 TEST_F(AudioHashTest, ChannelOrder) {
     78   AudioHash original_hash;
     79   original_hash.Update(bus_one_.get(), bus_one_->frames());
     80 
     81   // Reverse channel order for the same sample data.
     82   const int channels = bus_one_->channels();
     83   scoped_ptr<AudioBus> swapped_ch_bus = AudioBus::CreateWrapper(channels);
     84   swapped_ch_bus->set_frames(bus_one_->frames());
     85   for (int i = channels - 1; i >= 0; --i)
     86     swapped_ch_bus->SetChannelData(channels - (i + 1), bus_one_->channel(i));
     87 
     88   AudioHash swapped_hash;
     89   swapped_hash.Update(swapped_ch_bus.get(), swapped_ch_bus->frames());
     90 
     91   EXPECT_NE(original_hash.ToString(), swapped_hash.ToString());
     92 }
     93 
     94 // Ensure bus order matters to the hash.
     95 TEST_F(AudioHashTest, BusOrder) {
     96   AudioHash original_hash;
     97   original_hash.Update(bus_one_.get(), bus_one_->frames());
     98   original_hash.Update(bus_two_.get(), bus_two_->frames());
     99 
    100   AudioHash reordered_hash;
    101   reordered_hash.Update(bus_two_.get(), bus_two_->frames());
    102   reordered_hash.Update(bus_one_.get(), bus_one_->frames());
    103 
    104   EXPECT_NE(original_hash.ToString(), reordered_hash.ToString());
    105 }
    106 
    107 // Ensure bus order matters to the hash even with empty buses.
    108 TEST_F(AudioHashTest, EmptyBusOrder) {
    109   bus_one_->Zero();
    110   bus_two_->Zero();
    111 
    112   AudioHash one_bus_hash;
    113   one_bus_hash.Update(bus_one_.get(), bus_one_->frames());
    114 
    115   AudioHash two_bus_hash;
    116   two_bus_hash.Update(bus_one_.get(), bus_one_->frames());
    117   two_bus_hash.Update(bus_two_.get(), bus_two_->frames());
    118 
    119   EXPECT_NE(one_bus_hash.ToString(), two_bus_hash.ToString());
    120 }
    121 
    122 // Where A = [0, n], ensure hash(A[0:n/2]), hash(A[n/2:n]) and hash(A) result
    123 // in the same value.
    124 TEST_F(AudioHashTest, HashIgnoresUpdateOrder) {
    125   AudioHash full_hash;
    126   full_hash.Update(bus_one_.get(), bus_one_->frames());
    127 
    128   AudioHash half_hash;
    129   half_hash.Update(bus_one_.get(), bus_one_->frames() / 2);
    130 
    131   // Create a new bus representing the second half of |bus_one_|.
    132   const int half_frames = bus_one_->frames() / 2;
    133   const int channels = bus_one_->channels();
    134   scoped_ptr<AudioBus> half_bus = AudioBus::CreateWrapper(channels);
    135   half_bus->set_frames(half_frames);
    136   for (int i = 0; i < channels; ++i)
    137     half_bus->SetChannelData(i, bus_one_->channel(i) + half_frames);
    138 
    139   half_hash.Update(half_bus.get(), half_bus->frames());
    140   EXPECT_EQ(full_hash.ToString(), half_hash.ToString());
    141 }
    142 
    143 // Ensure approximate hashes pass verification.
    144 TEST_F(AudioHashTest, VerifySimilarHash) {
    145   AudioHash hash_one;
    146   hash_one.Update(bus_one_.get(), bus_one_->frames());
    147 
    148   // Twiddle the values inside the first bus.
    149   float* channel = bus_one_->channel(0);
    150   for (int i = 0; i < bus_one_->frames(); i += bus_one_->frames() / 64)
    151     channel[i] += 0.0001f;
    152 
    153   AudioHash hash_two;
    154   hash_two.Update(bus_one_.get(), bus_one_->frames());
    155 
    156   EXPECT_EQ(hash_one.ToString(), hash_two.ToString());
    157 
    158   // Twiddle the values too much...
    159   for (int i = 0; i < bus_one_->frames(); ++i)
    160     channel[i] += 0.0001f;
    161 
    162   AudioHash hash_three;
    163   hash_three.Update(bus_one_.get(), bus_one_->frames());
    164   EXPECT_NE(hash_one.ToString(), hash_three.ToString());
    165 }
    166 
    167 }  // namespace media
    168