OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 // | 4 // |
5 // The format of these tests are to enqueue a known amount of data and then | 5 // The format of these tests are to enqueue a known amount of data and then |
6 // request the exact amount we expect in order to dequeue the known amount of | 6 // request the exact amount we expect in order to dequeue the known amount of |
7 // data. This ensures that for any rate we are consuming input data at the | 7 // data. This ensures that for any rate we are consuming input data at the |
8 // correct rate. We always pass in a very large destination buffer with the | 8 // correct rate. We always pass in a very large destination buffer with the |
9 // expectation that FillBuffer() will fill as much as it can but no more. | 9 // expectation that FillBuffer() will fill as much as it can but no more. |
10 | 10 |
11 #include <cmath> | |
12 | |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/callback.h" | 14 #include "base/callback.h" |
13 #include "media/base/data_buffer.h" | 15 #include "media/base/data_buffer.h" |
14 #include "media/filters/audio_renderer_algorithm_base.h" | 16 #include "media/filters/audio_renderer_algorithm_base.h" |
15 #include "testing/gmock/include/gmock/gmock.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
17 | 18 |
18 using ::testing::AnyNumber; | 19 static const size_t kRawDataSize = 10 * 1024; |
20 static const int kSamplesPerSecond = 44100; | |
21 static const int kDefaultChannels = 2; | |
22 static const int kDefaultSampleBits = 16; | |
19 | 23 |
20 namespace media { | 24 namespace media { |
21 | 25 |
22 static const int kChannels = 1; | 26 class AudioRendererAlgorithmBaseTest : public testing::Test { |
23 static const int kSampleRate = 1000; | 27 public: |
24 static const int kSampleBits = 8; | 28 AudioRendererAlgorithmBaseTest() |
25 | 29 : bytes_enqueued_(0), |
26 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) { | 30 bytes_per_frame_(0), |
acolwell GONE FROM CHROMIUM
2012/02/29 00:31:38
nit: Do we really need these? How about just calli
vrk (LEFT CHROMIUM)
2012/02/29 20:41:39
Done.
| |
27 // When playback rate == 1.0f: straight copy of whatever is in |queue_|. | 31 bytes_per_channel_(0) { |
28 AudioRendererAlgorithmBase algorithm; | 32 } |
29 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 1.0f, | 33 |
30 base::Bind(&base::DoNothing)); | 34 ~AudioRendererAlgorithmBaseTest() {} |
31 | 35 |
32 // Enqueue a buffer of any size since it doesn't matter. | 36 void Initialize() { |
33 const size_t kDataSize = 1024; | 37 Initialize(kDefaultChannels, kDefaultSampleBits); |
34 algorithm.EnqueueBuffer(new DataBuffer( | 38 } |
35 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); | 39 |
36 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); | 40 void Initialize(int channels, int bits_per_channel) { |
37 | 41 algorithm_.Initialize( |
38 // Read the same sized amount. | 42 channels, kSamplesPerSecond, bits_per_channel, 1.0f, |
39 scoped_array<uint8> data(new uint8[kDataSize]); | 43 base::Bind(&AudioRendererAlgorithmBaseTest::EnqueueData, |
40 EXPECT_EQ(kDataSize, algorithm.FillBuffer(data.get(), kDataSize)); | 44 base::Unretained(this))); |
41 EXPECT_EQ(0u, algorithm.bytes_buffered()); | 45 bytes_per_frame_ = algorithm_.bytes_per_frame(); |
42 } | 46 bytes_per_channel_ = algorithm_.bytes_per_channel(); |
43 | 47 EnqueueData(); |
44 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) { | 48 } |
45 // When playback rate > 1.0f: input is read faster than output is written. | 49 |
46 AudioRendererAlgorithmBase algorithm; | 50 void EnqueueData() { |
47 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 2.0f, | 51 scoped_array<uint8> audio_data(new uint8[kRawDataSize]); |
48 base::Bind(&base::DoNothing)); | 52 size_t length = kRawDataSize / bytes_per_channel_; |
acolwell GONE FROM CHROMIUM
2012/02/29 00:31:38
I think this might break if kRawDataSize isn't an
vrk (LEFT CHROMIUM)
2012/02/29 20:41:39
Done.
| |
49 | 53 switch (bytes_per_channel_) { |
50 // First parameter is the input buffer size, second parameter is how much data | 54 case 4: |
51 // we expect to consume in order to have no data left in the |algorithm|. | 55 WriteFakeData<int32>(audio_data.get(), length); |
52 // | 56 break; |
53 // For rate == 0.5f, reading half the input size should consume all enqueued | 57 case 2: |
54 // data. | 58 WriteFakeData<int16>(audio_data.get(), length); |
55 const size_t kBufferSize = 16 * 1024; | 59 break; |
56 scoped_array<uint8> data(new uint8[kBufferSize]); | 60 case 1: |
57 const size_t kTestData[][2] = { | 61 WriteFakeData<uint8>(audio_data.get(), length); |
58 { algorithm.window_size(), algorithm.window_size() / 2}, | 62 break; |
59 { algorithm.window_size() / 2, algorithm.window_size() / 4}, | 63 default: |
60 { 4u, 2u }, | 64 NOTREACHED() << "Unsupported audio bit depth in crossfade."; |
61 { 0u, 0u }, | 65 } |
62 }; | 66 algorithm_.EnqueueBuffer(new DataBuffer(audio_data.Pass(), kRawDataSize)); |
63 | 67 bytes_enqueued_ += kRawDataSize; |
64 for (size_t i = 0u; i < arraysize(kTestData); ++i) { | 68 } |
65 const size_t kDataSize = kTestData[i][0]; | 69 |
66 algorithm.EnqueueBuffer(new DataBuffer( | 70 template <class Type> |
67 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); | 71 void WriteFakeData(uint8* audio_data, size_t length) { |
68 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); | 72 Type* output = reinterpret_cast<Type*>(audio_data); |
69 | 73 for (size_t i = 0; i < length; i++) { |
70 const size_t kExpectedSize = kTestData[i][1]; | 74 // The value of the data is meaningless; we just want non-zero data to |
71 ASSERT_LE(kExpectedSize, kBufferSize); | 75 // differentiate it from muted data. |
72 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); | 76 output[i] = i % 5 + 10; |
73 EXPECT_EQ(0u, algorithm.bytes_buffered()); | 77 } |
74 } | 78 } |
75 } | 79 |
76 | 80 void CheckFakeData(uint8* audio_data, int frames_written, |
77 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) { | 81 float playback_rate) { |
78 // When playback rate < 1.0f: input is read slower than output is written. | 82 // Check to see if the audio data was muted. |
79 AudioRendererAlgorithmBase algorithm; | 83 bool expect_muted = playback_rate < media::kMinPlaybackRate || |
80 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.5f, | 84 playback_rate > media::kMaxPlaybackRate; |
81 base::Bind(&base::DoNothing)); | 85 |
82 | 86 size_t length = (frames_written * bytes_per_frame_) / bytes_per_channel_; |
83 // First parameter is the input buffer size, second parameter is how much data | 87 switch (bytes_per_channel_) { |
84 // we expect to consume in order to have no data left in the |algorithm|. | 88 case 4: |
85 // | 89 DoCheckFakeData<int32>(audio_data, length, expect_muted); |
86 // For rate == 0.5f, reading double the input size should consume all enqueued | 90 break; |
87 // data. | 91 case 2: |
88 const size_t kBufferSize = 16 * 1024; | 92 DoCheckFakeData<int16>(audio_data, length, expect_muted); |
89 scoped_array<uint8> data(new uint8[kBufferSize]); | 93 break; |
90 const size_t kTestData[][2] = { | 94 case 1: |
91 { algorithm.window_size(), algorithm.window_size() * 2 }, | 95 DoCheckFakeData<uint8>(audio_data, length, expect_muted); |
92 { algorithm.window_size() / 2, algorithm.window_size() }, | 96 break; |
93 { 2u, 4u }, | 97 default: |
94 { 0u, 0u }, | 98 NOTREACHED() << "Unsupported audio bit depth in crossfade."; |
95 }; | 99 } |
96 | 100 } |
97 for (size_t i = 0u; i < arraysize(kTestData); ++i) { | 101 |
98 const size_t kDataSize = kTestData[i][0]; | 102 template <class Type> |
99 algorithm.EnqueueBuffer(new DataBuffer( | 103 void DoCheckFakeData(uint8* audio_data, size_t length, bool expect_muted) { |
100 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); | 104 Type* output = reinterpret_cast<Type*>(audio_data); |
101 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); | 105 for (size_t i = 0; i < length; i++) { |
102 | 106 EXPECT_TRUE(expect_muted || output[i] != 0); |
103 const size_t kExpectedSize = kTestData[i][1]; | 107 } |
104 ASSERT_LE(kExpectedSize, kBufferSize); | 108 } |
105 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); | 109 |
106 EXPECT_EQ(0u, algorithm.bytes_buffered()); | 110 int ComputeConsumedBytes(int initial_bytes_enqueued, |
107 } | 111 int initial_bytes_buffered) { |
108 } | 112 int byte_delta = bytes_enqueued_ - initial_bytes_enqueued; |
109 | 113 int buffered_delta = algorithm_.bytes_buffered() - initial_bytes_buffered; |
110 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) { | 114 int consumed = byte_delta - buffered_delta; |
111 // When playback rate is very low the audio is simply muted. | 115 CHECK_GE(consumed, 0); |
112 AudioRendererAlgorithmBase algorithm; | 116 return consumed; |
113 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.25f, | 117 } |
114 base::Bind(&base::DoNothing)); | 118 |
115 | 119 void TestPlaybackRate(float playback_rate) { |
116 // First parameter is the input buffer size, second parameter is how much data | 120 static const int kDefaultBufferSize = kSamplesPerSecond / 10; |
117 // we expect to consume in order to have no data left in the |algorithm|. | 121 static const int kDefaultFramesRequested = 5 * kSamplesPerSecond; |
118 // | 122 |
119 // For rate == 0.25f, reading four times the input size should consume all | 123 TestPlaybackRate(playback_rate, kDefaultBufferSize, |
120 // enqueued data but without executing OLA. | 124 kDefaultFramesRequested); |
121 const size_t kBufferSize = 16 * 1024; | 125 } |
122 scoped_array<uint8> data(new uint8[kBufferSize]); | 126 |
123 const size_t kTestData[][2] = { | 127 void TestPlaybackRate(float playback_rate, |
124 { algorithm.window_size(), algorithm.window_size() * 4}, | 128 int buffer_size_in_frames, |
125 { algorithm.window_size() / 2, algorithm.window_size() * 2}, | 129 int total_frames_requested) { |
126 { 1u, 4u }, | 130 int initial_bytes_enqueued = bytes_enqueued_; |
127 { 0u, 0u }, | 131 int initial_bytes_buffered = algorithm_.bytes_buffered(); |
128 }; | 132 |
129 | 133 algorithm_.SetPlaybackRate(playback_rate); |
130 for (size_t i = 0u; i < arraysize(kTestData); ++i) { | 134 |
131 const size_t kDataSize = kTestData[i][0]; | 135 scoped_array<uint8> buffer( |
132 algorithm.EnqueueBuffer(new DataBuffer(scoped_array<uint8>( | 136 new uint8[buffer_size_in_frames * bytes_per_frame_]); |
133 new uint8[kDataSize]), kDataSize)); | 137 |
134 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); | 138 if (playback_rate == 0.0) { |
135 | 139 int frames_written = |
136 const size_t kExpectedSize = kTestData[i][1]; | 140 algorithm_.FillBuffer(buffer.get(), buffer_size_in_frames); |
137 ASSERT_LE(kExpectedSize, kBufferSize); | 141 EXPECT_EQ(0, frames_written); |
138 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); | 142 return; |
139 EXPECT_EQ(0u, algorithm.bytes_buffered()); | 143 } |
140 } | 144 |
145 int frames_remaining = total_frames_requested; | |
146 while (frames_remaining > 0) { | |
147 int frames_requested = std::min(buffer_size_in_frames, frames_remaining); | |
148 int frames_written = | |
149 algorithm_.FillBuffer(buffer.get(), frames_requested); | |
150 CHECK_GT(frames_written, 0); | |
151 CheckFakeData(buffer.get(), frames_written, playback_rate); | |
152 frames_remaining -= frames_written; | |
153 } | |
154 | |
155 int bytes_requested = total_frames_requested * bytes_per_frame_; | |
156 int bytes_consumed = ComputeConsumedBytes(initial_bytes_enqueued, | |
157 initial_bytes_buffered); | |
158 | |
159 // If playing back at normal speed, we should always get back the same | |
160 // number of bytes requested. | |
161 if (playback_rate == 1.0) { | |
162 EXPECT_EQ(bytes_requested, bytes_consumed); | |
163 return; | |
164 } | |
165 | |
166 // Otherwise, allow |kMaxAcceptableDelta| difference between the target and | |
167 // actual playback rate. | |
168 // When |kSamplesPerSecond| and |total_frames_requested| are reasonably | |
169 // large, one can expect less than a 1% difference in most cases. In our | |
170 // current implementation, sped up playback is less accurate than slowed | |
171 // down playback, and for playback_rate > 1, playback rate generally gets | |
172 // less and less accurate the farther it drifts from 1 (though this is | |
173 // nonlinear). | |
174 static const float kMaxAcceptableDelta = 0.01; | |
175 float actual_playback_rate = 1.0 * bytes_consumed / bytes_requested; | |
176 | |
177 // Calculate the percentage difference from the target |playback_rate| as a | |
178 // fraction from 0.0 to 1.0. | |
179 float delta = std::abs(1.0 - (actual_playback_rate / playback_rate)); | |
180 | |
181 EXPECT_LE(delta, kMaxAcceptableDelta); | |
182 } | |
183 | |
184 protected: | |
185 AudioRendererAlgorithmBase algorithm_; | |
186 int bytes_enqueued_; | |
187 int bytes_per_frame_; | |
188 int bytes_per_channel_; | |
189 }; | |
190 | |
191 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) { | |
192 Initialize(); | |
193 TestPlaybackRate(1.0); | |
194 } | |
195 | |
196 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAQuarterRate) { | |
197 Initialize(); | |
198 TestPlaybackRate(1.25); | |
199 } | |
200 | |
201 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAHalfRate) { | |
202 Initialize(); | |
203 TestPlaybackRate(1.5); | |
204 } | |
205 | |
206 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) { | |
207 Initialize(); | |
208 TestPlaybackRate(2.0); | |
209 } | |
210 | |
211 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_EightTimesRate) { | |
212 Initialize(); | |
213 TestPlaybackRate(8.0); | |
214 } | |
215 | |
216 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_ThreeQuartersRate) { | |
217 Initialize(); | |
218 TestPlaybackRate(0.75); | |
219 } | |
220 | |
221 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) { | |
222 Initialize(); | |
223 TestPlaybackRate(0.5); | |
224 } | |
225 | |
226 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) { | |
227 Initialize(); | |
228 TestPlaybackRate(0.25); | |
229 } | |
230 | |
231 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_Pause) { | |
232 Initialize(); | |
233 TestPlaybackRate(0.0); | |
234 } | |
235 | |
236 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SlowDown) { | |
237 Initialize(); | |
238 TestPlaybackRate(4.5); | |
239 TestPlaybackRate(3.0); | |
240 TestPlaybackRate(2.0); | |
241 TestPlaybackRate(1.0); | |
242 TestPlaybackRate(0.5); | |
243 TestPlaybackRate(0.25); | |
244 } | |
245 | |
246 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SpeedUp) { | |
247 Initialize(); | |
248 TestPlaybackRate(0.25); | |
249 TestPlaybackRate(0.5); | |
250 TestPlaybackRate(1.0); | |
251 TestPlaybackRate(2.0); | |
252 TestPlaybackRate(3.0); | |
253 TestPlaybackRate(4.5); | |
254 } | |
255 | |
256 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_JumpAroundSpeeds) { | |
257 Initialize(); | |
258 TestPlaybackRate(2.1); | |
259 TestPlaybackRate(0.9); | |
260 TestPlaybackRate(0.6); | |
261 TestPlaybackRate(1.4); | |
262 TestPlaybackRate(0.3); | |
263 } | |
264 | |
265 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SmallBufferSize) { | |
266 Initialize(); | |
267 static const int kBufferSizeInFrames = 1; | |
268 static const int kFramesRequested = 2 * kSamplesPerSecond; | |
269 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested); | |
270 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested); | |
271 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested); | |
272 } | |
273 | |
274 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_LowerQualityAudio) { | |
275 static const int kChannels = 1; | |
276 static const int kSampleBits = 8; | |
277 Initialize(kChannels, kSampleBits); | |
278 TestPlaybackRate(1.0); | |
279 TestPlaybackRate(0.5); | |
280 TestPlaybackRate(1.5); | |
281 } | |
282 | |
283 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HigherQualityAudio) { | |
284 static const int kChannels = 2; | |
285 static const int kSampleBits = 32; | |
286 Initialize(kChannels, kSampleBits); | |
287 TestPlaybackRate(1.0); | |
288 TestPlaybackRate(0.5); | |
289 TestPlaybackRate(1.5); | |
141 } | 290 } |
142 | 291 |
143 } // namespace media | 292 } // namespace media |
OLD | NEW |