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 "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 |
OLD | NEW |