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.
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"
13 static const int kChannelCount
= 2;
14 static const int kFrameCount
= 1024;
16 class AudioHashTest
: public testing::Test
{
19 : bus_one_(AudioBus::Create(kChannelCount
, kFrameCount
)),
20 bus_two_(AudioBus::Create(kChannelCount
, kFrameCount
)),
21 fake_callback_(0.01) {
23 // Fill each channel in each bus with unique data.
24 GenerateUniqueChannels(bus_one_
.get());
25 GenerateUniqueChannels(bus_two_
.get());
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());
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);
41 virtual ~AudioHashTest() {}
44 scoped_ptr
<AudioBus
> bus_one_
;
45 scoped_ptr
<AudioBus
> bus_two_
;
46 FakeAudioRenderCallback fake_callback_
;
48 DISALLOW_COPY_AND_ASSIGN(AudioHashTest
);
51 // Ensure the same data hashes the same.
52 TEST_F(AudioHashTest
, Equivalence
) {
54 hash_one
.Update(bus_one_
.get(), bus_one_
->frames());
57 hash_two
.Update(bus_one_
.get(), bus_one_
->frames());
59 EXPECT_EQ(hash_one
.ToString(), hash_two
.ToString());
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());
67 // Swap a sample in the bus.
68 std::swap(bus_one_
->channel(0)[0], bus_one_
->channel(0)[1]);
70 AudioHash swapped_hash
;
71 swapped_hash
.Update(bus_one_
.get(), bus_one_
->frames());
73 EXPECT_NE(original_hash
.ToString(), swapped_hash
.ToString());
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());
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
));
88 AudioHash swapped_hash
;
89 swapped_hash
.Update(swapped_ch_bus
.get(), swapped_ch_bus
->frames());
91 EXPECT_NE(original_hash
.ToString(), swapped_hash
.ToString());
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());
100 AudioHash reordered_hash
;
101 reordered_hash
.Update(bus_two_
.get(), bus_two_
->frames());
102 reordered_hash
.Update(bus_one_
.get(), bus_one_
->frames());
104 EXPECT_NE(original_hash
.ToString(), reordered_hash
.ToString());
107 // Ensure bus order matters to the hash even with empty buses.
108 TEST_F(AudioHashTest
, EmptyBusOrder
) {
112 AudioHash one_bus_hash
;
113 one_bus_hash
.Update(bus_one_
.get(), bus_one_
->frames());
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());
119 EXPECT_NE(one_bus_hash
.ToString(), two_bus_hash
.ToString());
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
) {
126 full_hash
.Update(bus_one_
.get(), bus_one_
->frames());
129 half_hash
.Update(bus_one_
.get(), bus_one_
->frames() / 2);
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
);
139 half_hash
.Update(half_bus
.get(), half_bus
->frames());
140 EXPECT_EQ(full_hash
.ToString(), half_hash
.ToString());
143 // Ensure approximate hashes pass verification.
144 TEST_F(AudioHashTest
, VerifySimilarHash
) {
146 hash_one
.Update(bus_one_
.get(), bus_one_
->frames());
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
;
154 hash_two
.Update(bus_one_
.get(), bus_one_
->frames());
156 EXPECT_EQ(hash_one
.ToString(), hash_two
.ToString());
158 // Twiddle the values too much...
159 for (int i
= 0; i
< bus_one_
->frames(); ++i
)
160 channel
[i
] += 0.0001f
;
162 AudioHash hash_three
;
163 hash_three
.Update(bus_one_
.get(), bus_one_
->frames());
164 EXPECT_NE(hash_one
.ToString(), hash_three
.ToString());