Chromium Code Reviews| 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 #include "media/filters/audio_renderer_algorithm_base.h" | 5 #include "media/filters/audio_renderer_algorithm_base.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 34 // Audio at these speeds would sound better under a frequency domain algorithm. | 34 // Audio at these speeds would sound better under a frequency domain algorithm. |
| 35 static const float kMinPlaybackRate = 0.5f; | 35 static const float kMinPlaybackRate = 0.5f; |
| 36 static const float kMaxPlaybackRate = 4.0f; | 36 static const float kMaxPlaybackRate = 4.0f; |
| 37 | 37 |
| 38 AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() | 38 AudioRendererAlgorithmBase::AudioRendererAlgorithmBase() |
| 39 : channels_(0), | 39 : channels_(0), |
| 40 samples_per_second_(0), | 40 samples_per_second_(0), |
| 41 bytes_per_channel_(0), | 41 bytes_per_channel_(0), |
| 42 playback_rate_(0.0f), | 42 playback_rate_(0.0f), |
| 43 audio_buffer_(0, kStartingBufferSizeInBytes), | 43 audio_buffer_(0, kStartingBufferSizeInBytes), |
| 44 crossfade_size_(0), | 44 bytes_in_crossfade_(0), |
| 45 bytes_per_frame_(0), | |
| 46 index_into_window_(0), | |
| 47 crossfade_frame_number_(0), | |
| 48 muted_(false), | |
| 49 needs_more_data_(false), | |
| 45 window_size_(0) { | 50 window_size_(0) { |
| 46 } | 51 } |
| 47 | 52 |
| 48 AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {} | 53 AudioRendererAlgorithmBase::~AudioRendererAlgorithmBase() {} |
| 49 | 54 |
| 50 bool AudioRendererAlgorithmBase::ValidateConfig( | 55 bool AudioRendererAlgorithmBase::ValidateConfig( |
| 51 int channels, | 56 int channels, |
| 52 int samples_per_second, | 57 int samples_per_second, |
| 53 int bits_per_channel) { | 58 int bits_per_channel) { |
| 54 bool status = true; | 59 bool status = true; |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 77 int samples_per_second, | 82 int samples_per_second, |
| 78 int bits_per_channel, | 83 int bits_per_channel, |
| 79 float initial_playback_rate, | 84 float initial_playback_rate, |
| 80 const base::Closure& callback) { | 85 const base::Closure& callback) { |
| 81 DCHECK(!callback.is_null()); | 86 DCHECK(!callback.is_null()); |
| 82 DCHECK(ValidateConfig(channels, samples_per_second, bits_per_channel)); | 87 DCHECK(ValidateConfig(channels, samples_per_second, bits_per_channel)); |
| 83 | 88 |
| 84 channels_ = channels; | 89 channels_ = channels; |
| 85 samples_per_second_ = samples_per_second; | 90 samples_per_second_ = samples_per_second; |
| 86 bytes_per_channel_ = bits_per_channel / 8; | 91 bytes_per_channel_ = bits_per_channel / 8; |
| 92 bytes_per_frame_ = bytes_per_channel_ * channels_; | |
| 87 request_read_cb_ = callback; | 93 request_read_cb_ = callback; |
| 88 SetPlaybackRate(initial_playback_rate); | 94 SetPlaybackRate(initial_playback_rate); |
| 89 | 95 |
| 90 window_size_ = | 96 window_size_ = |
| 91 samples_per_second_ * bytes_per_channel_ * channels_ * kWindowDuration; | 97 samples_per_second_ * bytes_per_channel_ * channels_ * kWindowDuration; |
| 92 AlignToSampleBoundary(&window_size_); | 98 AlignToFrameBoundary(&window_size_); |
| 93 | 99 |
| 94 crossfade_size_ = | 100 bytes_in_crossfade_ = |
| 95 samples_per_second_ * bytes_per_channel_ * channels_ * kCrossfadeDuration; | 101 samples_per_second_ * bytes_per_channel_ * channels_ * kCrossfadeDuration; |
| 96 AlignToSampleBoundary(&crossfade_size_); | 102 AlignToFrameBoundary(&bytes_in_crossfade_); |
| 97 } | 103 |
| 98 | 104 crossfade_buffer_.reset(new uint8[bytes_in_crossfade_]); |
| 99 uint32 AudioRendererAlgorithmBase::FillBuffer(uint8* dest, uint32 length) { | 105 } |
| 100 if (IsQueueEmpty() || playback_rate_ == 0.0f) | 106 |
| 107 uint32 AudioRendererAlgorithmBase::FillBuffer( | |
| 108 uint8* dest, uint32 requested_frames) { | |
| 109 if (playback_rate_ == 0.0f || bytes_per_frame_ == 0) | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
Is "bytes_per_frame == 0" necessary because Initia
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Oops, it's not necessary! This should be a DCHECK,
| |
| 101 return 0; | 110 return 0; |
| 102 | 111 |
| 103 // Handle the simple case of normal playback. | 112 uint32 total_frames_rendered = 0; |
| 104 if (playback_rate_ == 1.0f) { | 113 uint8* output_ptr = dest; |
| 105 uint32 bytes_written = | 114 while(total_frames_rendered < requested_frames) { |
| 106 CopyFromAudioBuffer(dest, std::min(length, bytes_buffered())); | 115 if (index_into_window_ == window_size_) |
| 107 AdvanceBufferPosition(bytes_written); | 116 ResetWindow(); |
| 108 return bytes_written; | 117 |
| 109 } | 118 bool renders_frame = true; |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
nit: rendered_frame?
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done.
| |
| 110 | 119 if (playback_rate_ > 1.0) |
| 111 // Output muted data when out of acceptable quality range. | 120 renders_frame = OutputFasterPlayback(output_ptr); |
| 112 if (playback_rate_ < kMinPlaybackRate || playback_rate_ > kMaxPlaybackRate) | 121 else if (playback_rate_ < 1.0) |
| 113 return MuteBuffer(dest, length); | 122 renders_frame = OutputSlowerPlayback(output_ptr); |
| 114 | 123 else |
| 124 renders_frame = OutputNormalPlayback(output_ptr); | |
| 125 | |
| 126 if (!renders_frame) { | |
| 127 needs_more_data_ = true; | |
| 128 break; | |
| 129 } | |
| 130 | |
| 131 output_ptr += bytes_per_frame_; | |
| 132 total_frames_rendered++; | |
| 133 } | |
| 134 return total_frames_rendered; | |
| 135 } | |
| 136 | |
| 137 void AudioRendererAlgorithmBase::ResetWindow() { | |
| 138 DCHECK_EQ(index_into_window_, window_size_); | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
Should this methods get called on FlushBuffers()?
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Good catch! Yes, this should get called then. Adde
| |
| 139 index_into_window_ = 0; | |
| 140 crossfade_frame_number_ = 0; | |
| 141 muted_ = false; | |
| 142 } | |
| 143 | |
| 144 bool AudioRendererAlgorithmBase::OutputFasterPlayback(uint8* dest) { | |
| 145 DCHECK_LT(index_into_window_, window_size_); | |
| 146 DCHECK_GT(playback_rate_, 1.0); | |
| 147 | |
| 148 if (audio_buffer_.forward_bytes() < bytes_per_frame_) | |
| 149 return false; | |
| 150 | |
| 151 if (playback_rate_ > kMaxPlaybackRate) | |
| 152 muted_ = true; | |
| 153 | |
| 154 // The audio data is output in a series of windows. For sped-up playback, | |
| 155 // window is comprised of the following phases: | |
| 156 // | |
| 157 // a) Output raw data. | |
| 158 // b) Save bytes for crossfade in |crossfade_buffer_|. | |
| 159 // c) Drop data. | |
| 160 // d) Output crossfaded audio leading up to the next window. | |
| 161 // | |
| 162 // The duration of each phase is computed below based on the |window_size_| | |
| 163 // and |playback_rate_|. | |
| 115 uint32 input_step = window_size_; | 164 uint32 input_step = window_size_; |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
I'm assuming we have to use uint32 everywhere beca
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done at top of header file.
| |
| 165 uint32 output_step = ceil(window_size_ / playback_rate_); | |
| 166 AlignToFrameBoundary(&output_step); | |
| 167 DCHECK_GT(input_step, output_step); | |
| 168 | |
| 169 uint32 bytes_to_crossfade = bytes_in_crossfade_; | |
| 170 if (muted_ || bytes_to_crossfade > output_step) | |
| 171 bytes_to_crossfade = 0; | |
| 172 | |
| 173 // This is the index of the end of phase a, beginning of phase b. | |
| 174 uint32 outtro_crossfade_begin = output_step - bytes_to_crossfade; | |
| 175 | |
| 176 // This is the index of the end of phase b, beginning of phase c. | |
| 177 uint32 outtro_crossfade_end = output_step; | |
| 178 | |
| 179 // This is the index of the end of phase c, beginning of phase d. | |
| 180 // This phase continues until |index_into_window_| reaches |window_size_|, at | |
| 181 // which point the window restarts. | |
| 182 uint32 intro_crossfade_begin = input_step - bytes_to_crossfade; | |
| 183 | |
| 184 // a) Output a raw frame if we haven't reached the crossfade section. | |
| 185 if (index_into_window_ < outtro_crossfade_begin) { | |
| 186 ReadRawFrame(dest); | |
| 187 index_into_window_ += bytes_per_frame_; | |
| 188 return true; | |
| 189 } | |
| 190 | |
| 191 // b) Drop frames until we reach the intro crossfade section. | |
| 192 while (audio_buffer_.forward_bytes() >= bytes_per_frame_ && | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
I think just having a loop for b) and one for c) w
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Arrghhh I also mislabeled these comments! (Logic i
| |
| 193 index_into_window_ < intro_crossfade_begin) { | |
| 194 if (index_into_window_ < outtro_crossfade_end) { | |
| 195 // c) Save crossfade frame into intermediate buffer. | |
| 196 uint8* place_to_copy = crossfade_buffer_.get() + | |
| 197 (index_into_window_ - outtro_crossfade_begin); | |
| 198 ReadRawFrame(place_to_copy); | |
| 199 } else { | |
| 200 DropFrame(); | |
| 201 } | |
| 202 index_into_window_ += bytes_per_frame_; | |
| 203 } | |
| 204 | |
| 205 // d) Crossfade and output frames. | |
| 206 if (index_into_window_ < window_size_ && | |
| 207 index_into_window_ >= intro_crossfade_begin && | |
| 208 audio_buffer_.forward_bytes() >= bytes_per_frame_) { | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
Reverse condition and return early to reduce inden
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done.
| |
| 209 uint32 offset_into_buffer = index_into_window_ - intro_crossfade_begin; | |
| 210 memcpy(dest, crossfade_buffer_.get() + offset_into_buffer, | |
| 211 bytes_per_frame_); | |
| 212 scoped_array<uint8> intro_frame_ptr(new uint8[bytes_per_frame_]); | |
| 213 audio_buffer_.Read(intro_frame_ptr.get(), bytes_per_frame_); | |
| 214 OutputCrossfadedFrame(dest, intro_frame_ptr.get()); | |
| 215 index_into_window_ += bytes_per_frame_; | |
| 216 return true; | |
| 217 } | |
| 218 | |
| 219 return false; | |
| 220 } | |
| 221 | |
| 222 bool AudioRendererAlgorithmBase::OutputSlowerPlayback(uint8* dest) { | |
| 223 DCHECK_LT(index_into_window_, window_size_); | |
| 224 DCHECK_LT(playback_rate_, 1.0); | |
| 225 DCHECK_NE(playback_rate_, 0.0); | |
| 226 | |
| 227 if (audio_buffer_.forward_bytes() < bytes_per_frame_) | |
| 228 return false; | |
| 229 | |
| 230 if (playback_rate_ < kMinPlaybackRate) | |
| 231 muted_ = true; | |
| 232 | |
| 233 // The audio data is output in a series of windows. For slowed down playback, | |
| 234 // window is comprised of the following phases: | |
| 235 // | |
| 236 // a) Output raw data. | |
| 237 // b) Output and save bytes for crossfade in |crossfade_buffer_|. | |
| 238 // c) Output raw data. | |
| 239 // d) Output crossfaded audio leading up to the next window. | |
| 240 // | |
| 241 // Phases c) and d) do not progress |audio_buffer_|'s cursor so that the | |
| 242 // |audio_buffer_|'s cursor is in the correct place for the next window. | |
| 243 // | |
| 244 // The duration of each phase is computed below based on the |window_size_| | |
| 245 // and |playback_rate_|. | |
| 246 uint32 input_step = ceil(window_size_ * playback_rate_); | |
| 247 AlignToFrameBoundary(&input_step); | |
| 116 uint32 output_step = window_size_; | 248 uint32 output_step = window_size_; |
| 117 | 249 DCHECK_LT(input_step, output_step); |
| 118 if (playback_rate_ > 1.0f) { | 250 |
| 119 // Playback is faster than normal; need to squish output! | 251 uint32 bytes_to_crossfade = bytes_in_crossfade_; |
| 120 output_step = ceil(window_size_ / playback_rate_); | 252 if (muted_ || bytes_to_crossfade > input_step) |
| 253 bytes_to_crossfade = 0; | |
| 254 | |
| 255 // This is the index of the end of phase a, beginning of phase b. | |
| 256 uint32 intro_crossfade_begin = input_step - bytes_to_crossfade; | |
| 257 | |
| 258 // This is the index of the end of phase b, beginning of phase c. | |
| 259 uint32 intro_crossfade_end = input_step; | |
| 260 | |
| 261 // This is the index of the end of phase c, beginning of phase d. | |
| 262 // This phase continues until |index_into_window_| reaches |window_size_|, at | |
| 263 // which point the window restarts. | |
| 264 uint32 outtro_crossfade_begin = output_step - bytes_to_crossfade; | |
| 265 | |
| 266 // a) Output raw frame. | |
| 267 if (index_into_window_ < intro_crossfade_begin) { | |
| 268 ReadRawFrame(dest); | |
| 269 index_into_window_ += bytes_per_frame_; | |
| 270 return true; | |
| 271 } | |
| 272 | |
| 273 // b) Output and save raw frames that will make up the intro crossfade | |
| 274 // section. | |
| 275 if (index_into_window_ < intro_crossfade_end) { | |
| 276 uint32 offset = index_into_window_ - intro_crossfade_begin; | |
| 277 uint8* place_to_copy = crossfade_buffer_.get() + offset; | |
| 278 PeekRawFrame(place_to_copy); | |
| 279 ReadRawFrame(dest); | |
| 280 index_into_window_ += bytes_per_frame_; | |
| 281 return true; | |
| 282 } | |
| 283 | |
| 284 uint32 audio_buffer_offset = index_into_window_ - intro_crossfade_end; | |
| 285 | |
| 286 // c) Output more raw frames. | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
nit: Perhaps " Output more raw frames w/o advancin
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done, and also added asterisks to the function-lev
| |
| 287 if (audio_buffer_.forward_bytes() >= audio_buffer_offset + bytes_per_frame_) { | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
Reverse test and return early to reduce indenting.
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done.
| |
| 288 DCHECK_GE(index_into_window_, intro_crossfade_end); | |
| 289 PeekRawFrame(dest, audio_buffer_offset); | |
| 290 | |
| 291 // d) Crossfade the next frame of |crossfade_buffer_| into |dest|. | |
| 292 if (index_into_window_ >= outtro_crossfade_begin) { | |
| 293 uint32 offset_into_crossfade_buffer = | |
| 294 index_into_window_ - outtro_crossfade_begin; | |
| 295 uint8* intro_frame_ptr = | |
| 296 crossfade_buffer_.get() + offset_into_crossfade_buffer; | |
| 297 OutputCrossfadedFrame(dest, intro_frame_ptr); | |
| 298 } | |
| 299 | |
| 300 index_into_window_ += bytes_per_frame_; | |
| 301 return true; | |
| 302 } | |
| 303 | |
| 304 return false; | |
| 305 } | |
| 306 | |
| 307 bool AudioRendererAlgorithmBase::OutputNormalPlayback(uint8* dest) { | |
| 308 if (audio_buffer_.forward_bytes() >= bytes_per_frame_) { | |
| 309 ReadRawFrame(dest); | |
| 310 index_into_window_ += bytes_per_frame_; | |
| 311 return true; | |
| 312 } | |
| 313 return false; | |
| 314 } | |
| 315 | |
| 316 void AudioRendererAlgorithmBase::ReadRawFrame(uint8* dest) { | |
| 317 PeekRawFrame(dest); | |
| 318 DropFrame(); | |
| 319 } | |
| 320 | |
| 321 void AudioRendererAlgorithmBase::PeekRawFrame(uint8* dest) { | |
| 322 PeekRawFrame(dest, 0); | |
| 323 } | |
| 324 | |
| 325 void AudioRendererAlgorithmBase::PeekRawFrame(uint8* dest, uint32 offset) { | |
| 326 if (!muted_) { | |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
nit: Reverse test, do memset, & return early. Unin
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
Done.
| |
| 327 uint32 copied = audio_buffer_.Peek(dest, bytes_per_frame_, offset); | |
| 328 DCHECK_EQ(bytes_per_frame_, copied); | |
| 121 } else { | 329 } else { |
| 122 // Playback is slower than normal; need to stretch input! | 330 memset(dest, 0, bytes_per_frame_); |
| 123 input_step = ceil(window_size_ * playback_rate_); | 331 } |
| 124 } | 332 } |
| 125 | 333 |
| 126 AlignToSampleBoundary(&input_step); | 334 void AudioRendererAlgorithmBase::DropFrame() { |
| 127 AlignToSampleBoundary(&output_step); | 335 audio_buffer_.Seek(bytes_per_frame_); |
| 128 DCHECK_LE(crossfade_size_, input_step); | 336 |
| 129 DCHECK_LE(crossfade_size_, output_step); | 337 if (!IsQueueFull()) |
| 130 | 338 request_read_cb_.Run(); |
| 131 uint32 bytes_written = 0; | 339 } |
| 132 uint32 bytes_left_to_output = length; | 340 |
| 133 uint8* output_ptr = dest; | 341 void AudioRendererAlgorithmBase::OutputCrossfadedFrame( |
| 134 | 342 uint8* outtro, const uint8* intro) { |
| 135 // TODO(vrk): The while loop and if test below are lame! We are requiring the | 343 DCHECK_LE(index_into_window_, window_size_); |
| 136 // client to provide us with enough data to output only complete crossfaded | 344 DCHECK(!muted_); |
| 137 // windows. Instead, we should output as much data as we can, and add state to | 345 |
| 138 // keep track of what point in the crossfade we are at. | 346 switch (bytes_per_channel_) { |
| 139 // This is also the cause of crbug.com/108239. | 347 case 4: |
| 140 while (bytes_left_to_output >= output_step) { | 348 CrossfadeFrame(reinterpret_cast<int32*>(outtro), |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
You can change this to CrossfadeFrame<int32>(outtr
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
I tried and failed at this! It compiles, it looks
| |
| 141 // If there is not enough data buffered to complete an iteration of the | 349 reinterpret_cast<const int32*>(intro)); |
| 142 // loop, mute the remaining and break. | 350 break; |
| 143 if (bytes_buffered() < window_size_) { | 351 case 2: |
| 144 bytes_written += MuteBuffer(output_ptr, bytes_left_to_output); | 352 CrossfadeFrame(reinterpret_cast<int16*>(outtro), |
| 145 break; | 353 reinterpret_cast<const int16*>(intro)); |
| 146 } | 354 break; |
| 147 | 355 case 1: |
| 148 // Copy |output_step| bytes into destination buffer. | 356 CrossfadeFrame(outtro, intro); |
| 149 uint32 copied = CopyFromAudioBuffer(output_ptr, output_step); | 357 break; |
| 150 DCHECK_EQ(copied, output_step); | 358 default: |
| 151 output_ptr += output_step; | 359 NOTREACHED() << "Unsupported audio bit depth in crossfade."; |
| 152 bytes_written += copied; | 360 } |
| 153 bytes_left_to_output -= copied; | 361 } |
| 154 | 362 |
| 155 // Copy the |crossfade_size_| bytes leading up to the next window that will | 363 template <class Type> |
| 156 // be played into an intermediate buffer. This will be used to crossfade | 364 void AudioRendererAlgorithmBase::CrossfadeFrame( |
| 157 // from the current window to the next. | 365 Type* outtro, const Type* intro) { |
| 158 AdvanceBufferPosition(input_step - crossfade_size_); | 366 uint32 frames_in_crossfade = bytes_in_crossfade_ / bytes_per_frame_; |
| 159 scoped_array<uint8> next_window_intro(new uint8[crossfade_size_]); | 367 float crossfade_ratio = |
| 160 uint32 bytes_copied = | 368 static_cast<float>(crossfade_frame_number_) / frames_in_crossfade; |
| 161 CopyFromAudioBuffer(next_window_intro.get(), crossfade_size_); | 369 for (int channel = 0; channel < channels_; ++channel) { |
| 162 DCHECK_EQ(bytes_copied, crossfade_size_); | 370 *outtro = (*outtro) * (1.0 - crossfade_ratio) + (*intro) * crossfade_ratio; |
| 163 AdvanceBufferPosition(crossfade_size_); | 371 outtro++; |
|
acolwell GONE FROM CHROMIUM
2012/02/22 07:51:40
nit: *outtro++ = ... *intro++
vrk (LEFT CHROMIUM)
2012/02/23 20:33:06
I don't think I can do that, since I want to incre
| |
| 164 | 372 intro++; |
| 165 // Prepare pointers to end of the current window and the start of the next | 373 } |
| 166 // window. | 374 crossfade_frame_number_++; |
| 167 uint8* start_of_outro = output_ptr - crossfade_size_; | |
| 168 const uint8* start_of_intro = next_window_intro.get(); | |
| 169 | |
| 170 // Do crossfade! | |
| 171 Crossfade(crossfade_size_, channels_, bytes_per_channel_, | |
| 172 start_of_intro, start_of_outro); | |
| 173 } | |
| 174 | |
| 175 return bytes_written; | |
| 176 } | |
| 177 | |
| 178 uint32 AudioRendererAlgorithmBase::MuteBuffer(uint8* dest, uint32 length) { | |
| 179 DCHECK_NE(playback_rate_, 0.0); | |
| 180 // Note: This may not play at the speed requested as we can only consume as | |
| 181 // much data as we have, and audio timestamps drive the pipeline clock. | |
| 182 // | |
| 183 // Furthermore, we won't end up scaling the very last bit of audio, but | |
| 184 // we're talking about <8ms of audio data. | |
| 185 | |
| 186 // Cap the |input_step| by the amount of bytes buffered. | |
| 187 uint32 input_step = | |
| 188 std::min(static_cast<uint32>(length * playback_rate_), bytes_buffered()); | |
| 189 uint32 output_step = input_step / playback_rate_; | |
| 190 AlignToSampleBoundary(&input_step); | |
| 191 AlignToSampleBoundary(&output_step); | |
| 192 | |
| 193 DCHECK_LE(output_step, length); | |
| 194 if (output_step > length) { | |
| 195 LOG(ERROR) << "OLA: output_step (" << output_step << ") calculated to " | |
| 196 << "be larger than destination length (" << length << ")"; | |
| 197 output_step = length; | |
| 198 } | |
| 199 | |
| 200 memset(dest, 0, output_step); | |
| 201 AdvanceBufferPosition(input_step); | |
| 202 return output_step; | |
| 203 } | 375 } |
| 204 | 376 |
| 205 void AudioRendererAlgorithmBase::SetPlaybackRate(float new_rate) { | 377 void AudioRendererAlgorithmBase::SetPlaybackRate(float new_rate) { |
| 206 DCHECK_GE(new_rate, 0.0); | 378 DCHECK_GE(new_rate, 0.0); |
| 207 playback_rate_ = new_rate; | 379 playback_rate_ = new_rate; |
| 208 } | 380 } |
| 209 | 381 |
| 210 void AudioRendererAlgorithmBase::AlignToSampleBoundary(uint32* value) { | 382 void AudioRendererAlgorithmBase::AlignToFrameBoundary(uint32* value) { |
| 211 (*value) -= ((*value) % (channels_ * bytes_per_channel_)); | 383 (*value) -= ((*value) % bytes_per_frame_); |
| 212 } | 384 } |
| 213 | 385 |
| 214 void AudioRendererAlgorithmBase::FlushBuffers() { | 386 void AudioRendererAlgorithmBase::FlushBuffers() { |
| 215 // Clear the queue of decoded packets (releasing the buffers). | 387 // Clear the queue of decoded packets (releasing the buffers). |
| 216 audio_buffer_.Clear(); | 388 audio_buffer_.Clear(); |
| 217 request_read_cb_.Run(); | 389 request_read_cb_.Run(); |
| 218 } | 390 } |
| 219 | 391 |
| 220 base::TimeDelta AudioRendererAlgorithmBase::GetTime() { | 392 base::TimeDelta AudioRendererAlgorithmBase::GetTime() { |
| 221 return audio_buffer_.current_time(); | 393 return audio_buffer_.current_time(); |
| 222 } | 394 } |
| 223 | 395 |
| 224 void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) { | 396 void AudioRendererAlgorithmBase::EnqueueBuffer(Buffer* buffer_in) { |
| 225 // If we're at end of stream, |buffer_in| contains no data. | 397 DCHECK(!buffer_in->IsEndOfStream()); |
| 226 if (!buffer_in->IsEndOfStream()) | 398 audio_buffer_.Append(buffer_in); |
| 227 audio_buffer_.Append(buffer_in); | 399 needs_more_data_ = false; |
| 228 | 400 |
| 229 // If we still don't have enough data, request more. | 401 // If we still don't have enough data, request more. |
| 230 if (!IsQueueFull()) | 402 if (!IsQueueFull()) |
| 231 request_read_cb_.Run(); | 403 request_read_cb_.Run(); |
| 232 } | 404 } |
| 233 | 405 |
| 406 bool AudioRendererAlgorithmBase::NeedsMoreData() { | |
| 407 return needs_more_data_; | |
| 408 } | |
| 409 | |
| 234 bool AudioRendererAlgorithmBase::IsQueueEmpty() { | 410 bool AudioRendererAlgorithmBase::IsQueueEmpty() { |
| 235 return audio_buffer_.forward_bytes() == 0; | 411 return audio_buffer_.forward_bytes() == 0; |
| 236 } | 412 } |
| 237 | 413 |
| 238 bool AudioRendererAlgorithmBase::IsQueueFull() { | 414 bool AudioRendererAlgorithmBase::IsQueueFull() { |
| 239 return audio_buffer_.forward_bytes() >= audio_buffer_.forward_capacity(); | 415 return audio_buffer_.forward_bytes() >= audio_buffer_.forward_capacity(); |
| 240 } | 416 } |
| 241 | 417 |
| 242 uint32 AudioRendererAlgorithmBase::QueueCapacity() { | 418 uint32 AudioRendererAlgorithmBase::QueueCapacity() { |
| 243 return audio_buffer_.forward_capacity(); | 419 return audio_buffer_.forward_capacity(); |
| 244 } | 420 } |
| 245 | 421 |
| 246 void AudioRendererAlgorithmBase::IncreaseQueueCapacity() { | 422 void AudioRendererAlgorithmBase::IncreaseQueueCapacity() { |
| 247 audio_buffer_.set_forward_capacity( | 423 audio_buffer_.set_forward_capacity( |
| 248 std::min(2 * audio_buffer_.forward_capacity(), kMaxBufferSizeInBytes)); | 424 std::min(2 * audio_buffer_.forward_capacity(), kMaxBufferSizeInBytes)); |
| 249 } | 425 } |
| 250 | 426 |
| 251 void AudioRendererAlgorithmBase::AdvanceBufferPosition(uint32 bytes) { | |
| 252 audio_buffer_.Seek(bytes); | |
| 253 | |
| 254 if (!IsQueueFull()) | |
| 255 request_read_cb_.Run(); | |
| 256 } | |
| 257 | |
| 258 uint32 AudioRendererAlgorithmBase::CopyFromAudioBuffer( | |
| 259 uint8* dest, uint32 bytes) { | |
| 260 return audio_buffer_.Peek(dest, bytes); | |
| 261 } | |
| 262 | |
| 263 } // namespace media | 427 } // namespace media |
| OLD | NEW |