Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(24)

Side by Side Diff: media/filters/audio_renderer_algorithm_base_unittest.cc

Issue 9395057: Fix muted audio when playback rate != 1.0 or 0.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698