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), |
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_; |
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 frames_remaining -= frames_written; |
| 151 CheckFakeData(buffer.get(), frames_written, playback_rate); |
| 152 CHECK_GT(frames_written, 0); |
| 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 |