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

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, 10 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 "base/bind.h" 11 #include "base/bind.h"
12 #include "base/callback.h" 12 #include "base/callback.h"
13 #include "media/base/data_buffer.h" 13 #include "media/base/data_buffer.h"
14 #include "media/filters/audio_renderer_algorithm_base.h" 14 #include "media/filters/audio_renderer_algorithm_base.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h" 15 #include "testing/gtest/include/gtest/gtest.h"
17 16
18 using ::testing::AnyNumber; 17 static const size_t kRawDataSize = 1024;
18 static const int kSamplesPerSecond = 1234;
19 19
20 namespace media { 20 namespace media {
21 21
22 static const int kChannels = 1; 22 class AudioRendererAlgorithmBaseTest : public testing::Test {
23 static const int kSampleRate = 1000; 23 public:
24 static const int kSampleBits = 8; 24 AudioRendererAlgorithmBaseTest()
25 25 : bytes_enqueued_(0),
26 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) { 26 bytes_per_frame_(0) {
27 // When playback rate == 1.0f: straight copy of whatever is in |queue_|. 27 }
28 AudioRendererAlgorithmBase algorithm; 28
29 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 1.0f, 29 ~AudioRendererAlgorithmBaseTest() {}
30 base::Bind(&base::DoNothing)); 30
31 31 void Initialize() {
32 // Enqueue a buffer of any size since it doesn't matter. 32 static const int kDefaultChannels = 2;
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Any reason not to put these up with the const
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Nah, I just figured I'd put them close to where th
33 const size_t kDataSize = 1024; 33 static const int kDefaultSampleBits = 16;
34 algorithm.EnqueueBuffer(new DataBuffer( 34
35 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); 35 Initialize(kDefaultChannels, kDefaultSampleBits);
36 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); 36 }
37 37
38 // Read the same sized amount. 38 void Initialize(int channels, int bits_per_sample) {
39 scoped_array<uint8> data(new uint8[kDataSize]); 39 bytes_per_frame_ = channels * (bits_per_sample / 8);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Perhaps add a protected accessor method to al
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
40 EXPECT_EQ(kDataSize, algorithm.FillBuffer(data.get(), kDataSize)); 40 algorithm_.Initialize(
41 EXPECT_EQ(0u, algorithm.bytes_buffered()); 41 channels, kSamplesPerSecond, bits_per_sample, 1.0f,
42 } 42 base::Bind(&AudioRendererAlgorithmBaseTest::EnqueueData,
43 43 base::Unretained(this)));
44 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) { 44 EnqueueData();
45 // When playback rate > 1.0f: input is read faster than output is written. 45 }
46 AudioRendererAlgorithmBase algorithm; 46
47 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 2.0f, 47 void EnqueueData() {
48 base::Bind(&base::DoNothing)); 48 algorithm_.EnqueueBuffer(new DataBuffer(
49 49 scoped_array<uint8>(new uint8[kRawDataSize]), kRawDataSize));
50 // First parameter is the input buffer size, second parameter is how much data 50 bytes_enqueued_ += kRawDataSize;
51 // we expect to consume in order to have no data left in the |algorithm|. 51 }
52 // 52
53 // For rate == 0.5f, reading half the input size should consume all enqueued 53 int ComputeConsumedBytes(int initial_bytes_enqueued,
54 // data. 54 int initial_bytes_buffered) {
55 const size_t kBufferSize = 16 * 1024; 55 int byte_delta = bytes_enqueued_ - initial_bytes_enqueued;
56 scoped_array<uint8> data(new uint8[kBufferSize]); 56 int buffered_delta = algorithm_.bytes_buffered() - initial_bytes_buffered;
57 const size_t kTestData[][2] = { 57 int consumed = byte_delta - buffered_delta;
58 { algorithm.window_size(), algorithm.window_size() / 2}, 58 CHECK_GE(consumed, 0);
59 { algorithm.window_size() / 2, algorithm.window_size() / 4}, 59 return consumed;
60 { 4u, 2u }, 60 }
61 { 0u, 0u }, 61
62 }; 62 void TestPlaybackRate(float playback_rate) {
63 63 algorithm_.SetPlaybackRate(playback_rate);
64 for (size_t i = 0u; i < arraysize(kTestData); ++i) { 64 static const int kDefaultBufferSize = kSamplesPerSecond / 2;
65 const size_t kDataSize = kTestData[i][0]; 65 static const int kDefaultFramesRequested = 10 * kSamplesPerSecond;
66 algorithm.EnqueueBuffer(new DataBuffer( 66
67 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); 67 TestPlaybackRate(
68 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); 68 playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
69 69 }
70 const size_t kExpectedSize = kTestData[i][1]; 70
71 ASSERT_LE(kExpectedSize, kBufferSize); 71 void TestPlaybackRate(float playback_rate,
72 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); 72 int buffer_size_in_frames,
73 EXPECT_EQ(0u, algorithm.bytes_buffered()); 73 int total_frames_requested) {
74 } 74 int initial_bytes_enqueued = bytes_enqueued_;
75 } 75 int initial_bytes_buffered = algorithm_.bytes_buffered();
76 76
77 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) { 77 algorithm_.SetPlaybackRate(playback_rate);
78 // When playback rate < 1.0f: input is read slower than output is written. 78
79 AudioRendererAlgorithmBase algorithm; 79 scoped_array<uint8> buffer(
80 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.5f, 80 new uint8[buffer_size_in_frames * bytes_per_frame_]);
81 base::Bind(&base::DoNothing)); 81 int frames_remaining = total_frames_requested;
82 82
83 // First parameter is the input buffer size, second parameter is how much data 83 while (frames_remaining > 0) {
84 // we expect to consume in order to have no data left in the |algorithm|. 84 int frames_requested = std::min(buffer_size_in_frames, frames_remaining);
85 // 85 int frames_written =
86 // For rate == 0.5f, reading double the input size should consume all enqueued 86 algorithm_.FillBuffer(buffer.get(), frames_requested);
87 // data. 87 if (playback_rate == 0.0) {
88 const size_t kBufferSize = 16 * 1024; 88 EXPECT_EQ(0, frames_written);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: I think it might be clearer to just move this
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
89 scoped_array<uint8> data(new uint8[kBufferSize]); 89 return;
90 const size_t kTestData[][2] = { 90 }
91 { algorithm.window_size(), algorithm.window_size() * 2 }, 91 frames_remaining -= frames_written;
92 { algorithm.window_size() / 2, algorithm.window_size() }, 92 }
93 { 2u, 4u }, 93
94 { 0u, 0u }, 94 int bytes_requested = total_frames_requested * bytes_per_frame_;
95 }; 95 int bytes_consumed = ComputeConsumedBytes(initial_bytes_enqueued,
96 96 initial_bytes_buffered);
97 for (size_t i = 0u; i < arraysize(kTestData); ++i) { 97
98 const size_t kDataSize = kTestData[i][0]; 98 // If playing back at normal speed, we should always get back the same
99 algorithm.EnqueueBuffer(new DataBuffer( 99 // number of bytes requested.
100 scoped_array<uint8>(new uint8[kDataSize]), kDataSize)); 100 if (playback_rate == 1.0) {
101 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); 101 EXPECT_EQ(bytes_requested, bytes_consumed);
102 102 return;
103 const size_t kExpectedSize = kTestData[i][1]; 103 }
104 ASSERT_LE(kExpectedSize, kBufferSize); 104
105 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); 105 // Otherwise, allow |kMaxAcceptableDelta| difference between the target and
106 EXPECT_EQ(0u, algorithm.bytes_buffered()); 106 // actual playback rate.
107 } 107 static const float kMaxAcceptableDelta = 0.05;
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Is the error bound really constant? I thought
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
108 } 108 float actual_playback_rate = 1.0 * bytes_consumed / bytes_requested;
109 109
110 TEST(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) { 110 // Calculate the percentage difference from the target |playback_rate| as a
111 // When playback rate is very low the audio is simply muted. 111 // fraction from 0.0 to 1.0.
112 AudioRendererAlgorithmBase algorithm; 112 float delta = 1.0 - (actual_playback_rate / playback_rate);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: std::abs() instead of if below?
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Ooh d'oh! Originally I tried this and it converted
113 algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.25f, 113 if (delta < 0.0)
114 base::Bind(&base::DoNothing)); 114 delta *= -1.0;
115 115
116 // First parameter is the input buffer size, second parameter is how much data 116 EXPECT_LE(delta, kMaxAcceptableDelta);
117 // we expect to consume in order to have no data left in the |algorithm|. 117 }
118 // 118
119 // For rate == 0.25f, reading four times the input size should consume all 119 protected:
120 // enqueued data but without executing OLA. 120 AudioRendererAlgorithmBase algorithm_;
121 const size_t kBufferSize = 16 * 1024; 121 int bytes_enqueued_;
122 scoped_array<uint8> data(new uint8[kBufferSize]); 122 int bytes_per_frame_;
123 const size_t kTestData[][2] = { 123 };
124 { algorithm.window_size(), algorithm.window_size() * 4}, 124
125 { algorithm.window_size() / 2, algorithm.window_size() * 2}, 125 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) {
126 { 1u, 4u }, 126 Initialize();
127 { 0u, 0u }, 127 TestPlaybackRate(1.0);
128 }; 128 }
129 129
130 for (size_t i = 0u; i < arraysize(kTestData); ++i) { 130 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAQuarterRate) {
131 const size_t kDataSize = kTestData[i][0]; 131 Initialize();
132 algorithm.EnqueueBuffer(new DataBuffer(scoped_array<uint8>( 132 TestPlaybackRate(1.25);
133 new uint8[kDataSize]), kDataSize)); 133 }
134 EXPECT_EQ(kDataSize, algorithm.bytes_buffered()); 134
135 135 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAHalfRate) {
136 const size_t kExpectedSize = kTestData[i][1]; 136 Initialize();
137 ASSERT_LE(kExpectedSize, kBufferSize); 137 TestPlaybackRate(1.5);
138 EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize)); 138 }
139 EXPECT_EQ(0u, algorithm.bytes_buffered()); 139
140 } 140 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) {
141 Initialize();
142 TestPlaybackRate(2.0);
143 }
144
145 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_ThreeQuartersRate) {
146 Initialize();
147 TestPlaybackRate(0.75);
148 }
149
150 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) {
151 Initialize();
152 TestPlaybackRate(0.5);
153 }
154
155 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) {
156 Initialize();
157 TestPlaybackRate(0.25);
158 }
159
160 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_Pause) {
161 Initialize();
162 TestPlaybackRate(0.0);
163 }
164
165 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SlowDown) {
166 Initialize();
167 TestPlaybackRate(3.0);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Should add a case above kMaxPlaybackRate (ie
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
168 TestPlaybackRate(2.0);
169 TestPlaybackRate(1.0);
170 TestPlaybackRate(0.5);
171 TestPlaybackRate(0.25);
172 }
173
174 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SpeedUp) {
175 Initialize();
176 TestPlaybackRate(0.25);
177 TestPlaybackRate(0.5);
178 TestPlaybackRate(1.0);
179 TestPlaybackRate(2.0);
180 TestPlaybackRate(3.0);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Should add a case above kMaxPlaybackRate (ie
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
181 }
182
183 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_JumpAroundSpeeds) {
184 Initialize();
185 TestPlaybackRate(2.1);
186 TestPlaybackRate(0.9);
187 TestPlaybackRate(0.6);
188 TestPlaybackRate(1.4);
189 TestPlaybackRate(0.3);
190 }
191
192 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SmallBufferSize) {
193 Initialize();
194 static const int kBufferSizeInFrames = 1;
195 static const int kFramesRequested= kSamplesPerSecond;
196
197 TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
198 TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
199 TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
200 }
201
202 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_LowerQualityAudio) {
203 static const int kChannels = 1;
204 static const int kSampleBits = 8;
205 Initialize(kChannels, kSampleBits);
206 TestPlaybackRate(1.0);
207 TestPlaybackRate(0.5);
208 TestPlaybackRate(1.5);
209 }
210
211 TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HigherQualityAudio) {
212 static const int kChannels = 2;
213 static const int kSampleBits = 32;
214 Initialize(kChannels, kSampleBits);
215 TestPlaybackRate(1.0);
216 TestPlaybackRate(0.5);
217 TestPlaybackRate(1.5);
141 } 218 }
142 219
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 Should we add tests to verify sound is output betw
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done - but it took more code than I thought! I had
143 } // namespace media 220 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698