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