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_impl.h" | 5 #include "media/filters/audio_renderer_impl.h" |
6 | 6 |
7 #include <math.h> | 7 #include <math.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback.h" | 10 #include "base/callback.h" |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 sink_->Start(); | 192 sink_->Start(); |
193 is_initialized_ = true; | 193 is_initialized_ = true; |
194 | 194 |
195 // Finally, execute the start callback. | 195 // Finally, execute the start callback. |
196 state_ = kPaused; | 196 state_ = kPaused; |
197 init_cb.Run(PIPELINE_OK); | 197 init_cb.Run(PIPELINE_OK); |
198 } | 198 } |
199 | 199 |
200 bool AudioRendererImpl::HasEnded() { | 200 bool AudioRendererImpl::HasEnded() { |
201 base::AutoLock auto_lock(lock_); | 201 base::AutoLock auto_lock(lock_); |
202 DCHECK(!rendered_end_of_stream_ || algorithm_->NeedsMoreData()); | 202 DCHECK(!rendered_end_of_stream_ || !algorithm_->CanFillBuffer()); |
203 | 203 |
204 return received_end_of_stream_ && rendered_end_of_stream_; | 204 return received_end_of_stream_ && rendered_end_of_stream_; |
205 } | 205 } |
206 | 206 |
207 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { | 207 void AudioRendererImpl::ResumeAfterUnderflow(bool buffer_more_audio) { |
208 base::AutoLock auto_lock(lock_); | 208 base::AutoLock auto_lock(lock_); |
209 if (state_ == kUnderflow) { | 209 if (state_ == kUnderflow) { |
210 if (buffer_more_audio) | 210 if (buffer_more_audio) |
211 algorithm_->IncreaseQueueCapacity(); | 211 algorithm_->IncreaseQueueCapacity(); |
212 | 212 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 case kUnderflow: | 270 case kUnderflow: |
271 case kRebuffering: | 271 case kRebuffering: |
272 if (buffer && !buffer->IsEndOfStream()) | 272 if (buffer && !buffer->IsEndOfStream()) |
273 algorithm_->EnqueueBuffer(buffer); | 273 algorithm_->EnqueueBuffer(buffer); |
274 return; | 274 return; |
275 case kStopped: | 275 case kStopped: |
276 return; | 276 return; |
277 } | 277 } |
278 } | 278 } |
279 | 279 |
280 void AudioRendererImpl::SignalEndOfStream() { | |
281 DCHECK(received_end_of_stream_); | |
282 if (!rendered_end_of_stream_) { | |
283 rendered_end_of_stream_ = true; | |
284 host()->NotifyEnded(); | |
285 } | |
286 } | |
287 | |
288 void AudioRendererImpl::ScheduleRead_Locked() { | 280 void AudioRendererImpl::ScheduleRead_Locked() { |
289 lock_.AssertAcquired(); | 281 lock_.AssertAcquired(); |
290 if (pending_read_ || state_ == kPaused) | 282 if (pending_read_ || state_ == kPaused) |
291 return; | 283 return; |
292 pending_read_ = true; | 284 pending_read_ = true; |
293 decoder_->Read(read_cb_); | 285 decoder_->Read(read_cb_); |
294 } | 286 } |
295 | 287 |
296 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { | 288 void AudioRendererImpl::SetPlaybackRate(float playback_rate) { |
297 DCHECK_LE(0.0f, playback_rate); | 289 DCHECK_LE(0.0f, playback_rate); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 // the subclass can restart the conversation. | 391 // the subclass can restart the conversation. |
400 // | 392 // |
401 // This should get handled by the subclass http://crbug.com/106600 | 393 // This should get handled by the subclass http://crbug.com/106600 |
402 const uint32 kZeroLength = 8192; | 394 const uint32 kZeroLength = 8192; |
403 size_t zeros_to_write = | 395 size_t zeros_to_write = |
404 std::min(kZeroLength, requested_frames * bytes_per_frame_); | 396 std::min(kZeroLength, requested_frames * bytes_per_frame_); |
405 memset(dest, 0, zeros_to_write); | 397 memset(dest, 0, zeros_to_write); |
406 return zeros_to_write / bytes_per_frame_; | 398 return zeros_to_write / bytes_per_frame_; |
407 } | 399 } |
408 | 400 |
409 // Use three conditions to determine the end of playback: | 401 // We use the following conditions to determine end of playback: |
410 // 1. Algorithm needs more audio data. | 402 // 1) Algorithm can not fill the audio callback buffer |
411 // 2. We've received an end of stream buffer. | 403 // 2) We received an end of stream buffer |
412 // (received_end_of_stream_ == true) | 404 // 3) We haven't already signalled that we've ended |
413 // 3. Browser process has no audio data being played. | 405 // 4) Our estimated earliest end time has expired |
414 // There is no way to check that condition that would work for all | |
415 // derived classes, so call virtual method that would either render | |
416 // end of stream or schedule such rendering. | |
417 // | 406 // |
418 // Three conditions determine when an underflow occurs: | 407 // TODO(enal): we should replace (4) with a check that the browser has no |
419 // 1. Algorithm has no audio data. | 408 // more audio data or at least use a delayed callback. |
420 // 2. Currently in the kPlaying state. | 409 // |
421 // 3. Have not received an end of stream buffer. | 410 // We use the following conditions to determine underflow: |
422 if (algorithm_->NeedsMoreData()) { | 411 // 1) Algorithm can not fill the audio callback buffer |
423 if (received_end_of_stream_) { | 412 // 2) We have NOT received an end of stream buffer |
424 // TODO(enal): schedule callback instead of polling. | 413 // 3) We are in the kPlaying state |
425 if (base::Time::Now() >= earliest_end_time_) | 414 // |
426 SignalEndOfStream(); | 415 // Otherwise fill the buffer with whatever data we can send to the device. |
427 } else if (state_ == kPlaying) { | 416 if (!algorithm_->CanFillBuffer() && received_end_of_stream_ && |
428 state_ = kUnderflow; | 417 !rendered_end_of_stream_ && base::Time::Now() >= earliest_end_time_) { |
429 underflow_cb = underflow_cb_; | 418 rendered_end_of_stream_ = true; |
430 } | 419 host()->NotifyEnded(); |
| 420 } else if (!algorithm_->CanFillBuffer() && !received_end_of_stream_ && |
| 421 state_ == kPlaying) { |
| 422 state_ = kUnderflow; |
| 423 underflow_cb = underflow_cb_; |
| 424 } else if (algorithm_->CanFillBuffer()) { |
| 425 frames_written = algorithm_->FillBuffer(dest, requested_frames); |
| 426 DCHECK_GT(frames_written, 0u); |
431 } else { | 427 } else { |
432 // Otherwise fill the buffer. | 428 // We can't write any data this cycle. For example, we may have |
433 frames_written = algorithm_->FillBuffer(dest, requested_frames); | 429 // sent all available data to the audio device while not reaching |
| 430 // |earliest_end_time_|. |
434 } | 431 } |
435 | 432 |
436 // The |audio_time_buffered_| is the ending timestamp of the last frame | 433 // The |audio_time_buffered_| is the ending timestamp of the last frame |
437 // buffered at the audio device. |playback_delay| is the amount of time | 434 // buffered at the audio device. |playback_delay| is the amount of time |
438 // buffered at the audio device. The current time can be computed by their | 435 // buffered at the audio device. The current time can be computed by their |
439 // difference. | 436 // difference. |
440 if (audio_time_buffered_ != kNoTimestamp()) { | 437 if (audio_time_buffered_ != kNoTimestamp()) { |
441 base::TimeDelta previous_time = current_time_; | 438 base::TimeDelta previous_time = current_time_; |
442 current_time_ = audio_time_buffered_ - playback_delay; | 439 current_time_ = audio_time_buffered_ - playback_delay; |
443 | 440 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
499 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); | 496 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); |
500 } | 497 } |
501 return base::TimeDelta(); | 498 return base::TimeDelta(); |
502 } | 499 } |
503 | 500 |
504 void AudioRendererImpl::OnRenderError() { | 501 void AudioRendererImpl::OnRenderError() { |
505 host()->DisableAudioRenderer(); | 502 host()->DisableAudioRenderer(); |
506 } | 503 } |
507 | 504 |
508 } // namespace media | 505 } // namespace media |
OLD | NEW |