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

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

Powered by Google App Engine
This is Rietveld 408576698