• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AudioHashTest()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 
GenerateUniqueChannels(AudioBus * audio_bus)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 
~AudioHashTest()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.
TEST_F(AudioHashTest,Equivalence)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.
TEST_F(AudioHashTest,SampleOrder)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.
TEST_F(AudioHashTest,ChannelOrder)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.
TEST_F(AudioHashTest,BusOrder)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.
TEST_F(AudioHashTest,EmptyBusOrder)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.
TEST_F(AudioHashTest,HashIgnoresUpdateOrder)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.
TEST_F(AudioHashTest,VerifySimilarHash)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