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_impl.h" | 5 #include "media/filters/audio_renderer_impl.h" |
| 6 | 6 |
| 7 #include <math.h> | 7 #include <math.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 | 10 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 audio_buffer_stream_.set_config_change_observer(base::Bind( | 65 audio_buffer_stream_.set_config_change_observer(base::Bind( |
| 66 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); | 66 &AudioRendererImpl::OnConfigChange, weak_factory_.GetWeakPtr())); |
| 67 } | 67 } |
| 68 | 68 |
| 69 AudioRendererImpl::~AudioRendererImpl() { | 69 AudioRendererImpl::~AudioRendererImpl() { |
| 70 // Stop() should have been called and |algorithm_| should have been destroyed. | 70 // Stop() should have been called and |algorithm_| should have been destroyed. |
| 71 DCHECK(state_ == kUninitialized || state_ == kStopped); | 71 DCHECK(state_ == kUninitialized || state_ == kStopped); |
| 72 DCHECK(!algorithm_.get()); | 72 DCHECK(!algorithm_.get()); |
| 73 } | 73 } |
| 74 | 74 |
| 75 void AudioRendererImpl::StartRendering() { | 75 void AudioRendererImpl::StartTicking() { |
| 76 DVLOG(1) << __FUNCTION__; | 76 DVLOG(1) << __FUNCTION__; |
| 77 DCHECK(task_runner_->BelongsToCurrentThread()); | 77 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 78 DCHECK(!rendering_); | 78 DCHECK(!rendering_); |
| 79 rendering_ = true; | 79 rendering_ = true; |
| 80 | 80 |
| 81 base::AutoLock auto_lock(lock_); | 81 base::AutoLock auto_lock(lock_); |
| 82 // Wait for an eventual call to SetPlaybackRate() to start rendering. | 82 // Wait for an eventual call to SetPlaybackRate() to start rendering. |
| 83 if (algorithm_->playback_rate() == 0) { | 83 if (algorithm_->playback_rate() == 0) { |
| 84 DCHECK(!sink_playing_); | 84 DCHECK(!sink_playing_); |
| 85 return; | 85 return; |
| 86 } | 86 } |
| 87 | 87 |
| 88 StartRendering_Locked(); | 88 StartRendering_Locked(); |
| 89 } | 89 } |
| 90 | 90 |
| 91 void AudioRendererImpl::StartRendering_Locked() { | 91 void AudioRendererImpl::StartRendering_Locked() { |
| 92 DVLOG(1) << __FUNCTION__; | 92 DVLOG(1) << __FUNCTION__; |
| 93 DCHECK(task_runner_->BelongsToCurrentThread()); | 93 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 94 DCHECK_EQ(state_, kPlaying); | 94 DCHECK_EQ(state_, kPlaying); |
| 95 DCHECK(!sink_playing_); | 95 DCHECK(!sink_playing_); |
| 96 DCHECK_NE(algorithm_->playback_rate(), 0); | 96 DCHECK_NE(algorithm_->playback_rate(), 0); |
| 97 lock_.AssertAcquired(); | 97 lock_.AssertAcquired(); |
| 98 | 98 |
| 99 sink_playing_ = true; | 99 sink_playing_ = true; |
| 100 | 100 |
| 101 base::AutoUnlock auto_unlock(lock_); | 101 base::AutoUnlock auto_unlock(lock_); |
| 102 sink_->Play(); | 102 sink_->Play(); |
| 103 } | 103 } |
| 104 | 104 |
| 105 void AudioRendererImpl::StopRendering() { | 105 void AudioRendererImpl::StopTicking() { |
| 106 DVLOG(1) << __FUNCTION__; | 106 DVLOG(1) << __FUNCTION__; |
| 107 DCHECK(task_runner_->BelongsToCurrentThread()); | 107 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 108 DCHECK(rendering_); | 108 DCHECK(rendering_); |
| 109 rendering_ = false; | 109 rendering_ = false; |
| 110 | 110 |
| 111 base::AutoLock auto_lock(lock_); | 111 base::AutoLock auto_lock(lock_); |
| 112 // Rendering should have already been stopped with a zero playback rate. | 112 // Rendering should have already been stopped with a zero playback rate. |
| 113 if (algorithm_->playback_rate() == 0) { | 113 if (algorithm_->playback_rate() == 0) { |
| 114 DCHECK(!sink_playing_); | 114 DCHECK(!sink_playing_); |
| 115 return; | 115 return; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 199 { | 199 { |
| 200 base::AutoLock auto_lock(lock_); | 200 base::AutoLock auto_lock(lock_); |
| 201 | 201 |
| 202 if (state_ == kStopped) { | 202 if (state_ == kStopped) { |
| 203 task_runner_->PostTask(FROM_HERE, callback); | 203 task_runner_->PostTask(FROM_HERE, callback); |
| 204 return; | 204 return; |
| 205 } | 205 } |
| 206 | 206 |
| 207 ChangeState_Locked(kStopped); | 207 ChangeState_Locked(kStopped); |
| 208 algorithm_.reset(); | 208 algorithm_.reset(); |
| 209 time_cb_.Reset(); | |
| 210 flush_cb_.Reset(); | 209 flush_cb_.Reset(); |
| 211 } | 210 } |
| 212 | 211 |
| 213 if (sink_) { | 212 if (sink_) { |
| 214 sink_->Stop(); | 213 sink_->Stop(); |
| 215 sink_ = NULL; | 214 sink_ = NULL; |
| 216 } | 215 } |
| 217 | 216 |
| 218 audio_buffer_stream_.Stop(callback); | 217 audio_buffer_stream_.Stop(callback); |
| 219 } | 218 } |
| 220 | 219 |
| 221 void AudioRendererImpl::StartPlayingFrom(base::TimeDelta timestamp) { | 220 void AudioRendererImpl::StartPlaying() { |
| 222 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; | 221 DVLOG(1) << __FUNCTION__; |
| 223 DCHECK(task_runner_->BelongsToCurrentThread()); | 222 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 224 | 223 |
| 225 base::AutoLock auto_lock(lock_); | 224 base::AutoLock auto_lock(lock_); |
| 226 DCHECK(!sink_playing_); | 225 DCHECK(!sink_playing_); |
| 227 DCHECK_EQ(state_, kFlushed); | 226 DCHECK_EQ(state_, kFlushed); |
| 228 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); | 227 DCHECK_EQ(buffering_state_, BUFFERING_HAVE_NOTHING); |
| 229 DCHECK(!pending_read_) << "Pending read must complete before seeking"; | 228 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
| 230 | 229 |
| 231 ChangeState_Locked(kPlaying); | 230 ChangeState_Locked(kPlaying); |
| 231 AttemptRead_Locked(); | |
| 232 } | |
| 233 | |
| 234 void AudioRendererImpl::SetMediaTimestamp(base::TimeDelta timestamp) { | |
| 235 DVLOG(1) << __FUNCTION__ << "(" << timestamp.InMicroseconds() << ")"; | |
| 236 DCHECK(!rendering_); | |
| 232 start_timestamp_ = timestamp; | 237 start_timestamp_ = timestamp; |
| 238 } | |
| 233 | 239 |
| 234 AttemptRead_Locked(); | 240 base::TimeDelta AudioRendererImpl::CurrentMediaTimestamp() { |
| 241 DVLOG(1) << __FUNCTION__; | |
| 242 DCHECK(task_runner_->BelongsToCurrentThread()); | |
| 243 | |
| 244 // TODO(scherkus): Take time since last updating |audio_clock_| into account. | |
|
xhwang
2014/07/12 06:36:44
Yeah, this will improve time accuracy, also solve
| |
| 245 base::AutoLock auto_lock(lock_); | |
| 246 base::TimeDelta timestamp = audio_clock_->CurrentMediaTimestamp(); | |
| 247 if (timestamp == kNoTimestamp()) | |
| 248 return start_timestamp_; | |
| 249 return timestamp; | |
| 235 } | 250 } |
| 236 | 251 |
| 237 void AudioRendererImpl::Initialize(DemuxerStream* stream, | 252 void AudioRendererImpl::Initialize(DemuxerStream* stream, |
| 238 const PipelineStatusCB& init_cb, | 253 const PipelineStatusCB& init_cb, |
| 239 const StatisticsCB& statistics_cb, | 254 const StatisticsCB& statistics_cb, |
| 240 const TimeCB& time_cb, | |
| 241 const BufferingStateCB& buffering_state_cb, | 255 const BufferingStateCB& buffering_state_cb, |
| 242 const base::Closure& ended_cb, | 256 const base::Closure& ended_cb, |
| 243 const PipelineStatusCB& error_cb) { | 257 const PipelineStatusCB& error_cb) { |
| 244 DCHECK(task_runner_->BelongsToCurrentThread()); | 258 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 245 DCHECK(stream); | 259 DCHECK(stream); |
| 246 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); | 260 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO); |
| 247 DCHECK(!init_cb.is_null()); | 261 DCHECK(!init_cb.is_null()); |
| 248 DCHECK(!statistics_cb.is_null()); | 262 DCHECK(!statistics_cb.is_null()); |
| 249 DCHECK(!time_cb.is_null()); | |
| 250 DCHECK(!buffering_state_cb.is_null()); | 263 DCHECK(!buffering_state_cb.is_null()); |
| 251 DCHECK(!ended_cb.is_null()); | 264 DCHECK(!ended_cb.is_null()); |
| 252 DCHECK(!error_cb.is_null()); | 265 DCHECK(!error_cb.is_null()); |
| 253 DCHECK_EQ(kUninitialized, state_); | 266 DCHECK_EQ(kUninitialized, state_); |
| 254 DCHECK(sink_); | 267 DCHECK(sink_); |
| 255 | 268 |
| 256 state_ = kInitializing; | 269 state_ = kInitializing; |
| 257 | 270 |
| 258 init_cb_ = init_cb; | 271 init_cb_ = init_cb; |
| 259 time_cb_ = time_cb; | |
| 260 buffering_state_cb_ = buffering_state_cb; | 272 buffering_state_cb_ = buffering_state_cb; |
| 261 ended_cb_ = ended_cb; | 273 ended_cb_ = ended_cb; |
| 262 error_cb_ = error_cb; | 274 error_cb_ = error_cb; |
| 263 | 275 |
| 264 expecting_config_changes_ = stream->SupportsConfigChanges(); | 276 expecting_config_changes_ = stream->SupportsConfigChanges(); |
| 265 if (!expecting_config_changes_) { | 277 if (!expecting_config_changes_) { |
| 266 // The actual buffer size is controlled via the size of the AudioBus | 278 // The actual buffer size is controlled via the size of the AudioBus |
| 267 // provided to Render(), so just choose something reasonable here for looks. | 279 // provided to Render(), so just choose something reasonable here for looks. |
| 268 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; | 280 int buffer_size = stream->audio_decoder_config().samples_per_second() / 100; |
| 269 audio_parameters_.Reset( | 281 audio_parameters_.Reset( |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 } | 557 } |
| 546 | 558 |
| 547 int AudioRendererImpl::Render(AudioBus* audio_bus, | 559 int AudioRendererImpl::Render(AudioBus* audio_bus, |
| 548 int audio_delay_milliseconds) { | 560 int audio_delay_milliseconds) { |
| 549 const int requested_frames = audio_bus->frames(); | 561 const int requested_frames = audio_bus->frames(); |
| 550 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( | 562 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds( |
| 551 audio_delay_milliseconds); | 563 audio_delay_milliseconds); |
| 552 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * | 564 const int delay_frames = static_cast<int>(playback_delay.InSecondsF() * |
| 553 audio_parameters_.sample_rate()); | 565 audio_parameters_.sample_rate()); |
| 554 int frames_written = 0; | 566 int frames_written = 0; |
| 555 base::Closure time_cb; | |
| 556 { | 567 { |
| 557 base::AutoLock auto_lock(lock_); | 568 base::AutoLock auto_lock(lock_); |
| 558 | 569 |
| 559 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. | 570 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread. |
| 560 if (!algorithm_) { | 571 if (!algorithm_) { |
| 561 audio_clock_->WroteSilence(requested_frames, delay_frames); | 572 audio_clock_->WroteSilence(requested_frames, delay_frames); |
| 562 return 0; | 573 return 0; |
| 563 } | 574 } |
| 564 | 575 |
| 565 float playback_rate = algorithm_->playback_rate(); | 576 float playback_rate = algorithm_->playback_rate(); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 579 // 2) We received an end of stream buffer | 590 // 2) We received an end of stream buffer |
| 580 // 3) We haven't already signalled that we've ended | 591 // 3) We haven't already signalled that we've ended |
| 581 // 4) We've played all known audio data sent to hardware | 592 // 4) We've played all known audio data sent to hardware |
| 582 // | 593 // |
| 583 // We use the following conditions to determine underflow: | 594 // We use the following conditions to determine underflow: |
| 584 // 1) Algorithm can not fill the audio callback buffer | 595 // 1) Algorithm can not fill the audio callback buffer |
| 585 // 2) We have NOT received an end of stream buffer | 596 // 2) We have NOT received an end of stream buffer |
| 586 // 3) We are in the kPlaying state | 597 // 3) We are in the kPlaying state |
| 587 // | 598 // |
| 588 // Otherwise the buffer has data we can send to the device. | 599 // Otherwise the buffer has data we can send to the device. |
| 589 const base::TimeDelta media_timestamp_before_filling = | |
| 590 audio_clock_->CurrentMediaTimestamp(); | |
| 591 if (algorithm_->frames_buffered() > 0) { | 600 if (algorithm_->frames_buffered() > 0) { |
| 592 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); | 601 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames); |
| 593 audio_clock_->WroteAudio( | 602 audio_clock_->WroteAudio( |
| 594 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); | 603 frames_written, delay_frames, playback_rate, algorithm_->GetTime()); |
| 595 } | 604 } |
| 596 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); | 605 audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames); |
| 597 | 606 |
| 598 if (frames_written == 0) { | 607 if (frames_written == 0) { |
| 599 if (received_end_of_stream_ && !rendered_end_of_stream_ && | 608 if (received_end_of_stream_ && !rendered_end_of_stream_ && |
| 600 audio_clock_->CurrentMediaTimestamp() == | 609 audio_clock_->CurrentMediaTimestamp() == |
| 601 audio_clock_->last_endpoint_timestamp()) { | 610 audio_clock_->last_endpoint_timestamp()) { |
| 602 rendered_end_of_stream_ = true; | 611 rendered_end_of_stream_ = true; |
| 603 ended_cb_.Run(); | 612 ended_cb_.Run(); |
| 604 } else if (!received_end_of_stream_ && state_ == kPlaying) { | 613 } else if (!received_end_of_stream_ && state_ == kPlaying) { |
| 605 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { | 614 if (buffering_state_ != BUFFERING_HAVE_NOTHING) { |
| 606 algorithm_->IncreaseQueueCapacity(); | 615 algorithm_->IncreaseQueueCapacity(); |
| 607 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); | 616 SetBufferingState_Locked(BUFFERING_HAVE_NOTHING); |
| 608 } | 617 } |
| 609 } | 618 } |
| 610 } | 619 } |
| 611 | 620 |
| 612 if (CanRead_Locked()) { | 621 if (CanRead_Locked()) { |
| 613 task_runner_->PostTask(FROM_HERE, | 622 task_runner_->PostTask(FROM_HERE, |
| 614 base::Bind(&AudioRendererImpl::AttemptRead, | 623 base::Bind(&AudioRendererImpl::AttemptRead, |
| 615 weak_factory_.GetWeakPtr())); | 624 weak_factory_.GetWeakPtr())); |
| 616 } | 625 } |
| 617 | |
| 618 // We only want to execute |time_cb_| if time has progressed and we haven't | |
| 619 // signaled end of stream yet. | |
| 620 if (media_timestamp_before_filling != | |
| 621 audio_clock_->CurrentMediaTimestamp() && | |
| 622 !rendered_end_of_stream_) { | |
| 623 time_cb = base::Bind(time_cb_, | |
| 624 audio_clock_->CurrentMediaTimestamp(), | |
| 625 audio_clock_->last_endpoint_timestamp()); | |
| 626 } | |
| 627 } | 626 } |
| 628 | 627 |
| 629 if (!time_cb.is_null()) | |
| 630 task_runner_->PostTask(FROM_HERE, time_cb); | |
| 631 | |
| 632 DCHECK_LE(frames_written, requested_frames); | 628 DCHECK_LE(frames_written, requested_frames); |
| 633 return frames_written; | 629 return frames_written; |
| 634 } | 630 } |
| 635 | 631 |
| 636 void AudioRendererImpl::OnRenderError() { | 632 void AudioRendererImpl::OnRenderError() { |
| 637 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead | 633 // UMA data tells us this happens ~0.01% of the time. Trigger an error instead |
| 638 // of trying to gracefully fall back to a fake sink. It's very likely | 634 // of trying to gracefully fall back to a fake sink. It's very likely |
| 639 // OnRenderError() should be removed and the audio stack handle errors without | 635 // OnRenderError() should be removed and the audio stack handle errors without |
| 640 // notifying clients. See http://crbug.com/234708 for details. | 636 // notifying clients. See http://crbug.com/234708 for details. |
| 641 HistogramRendererEvent(RENDER_ERROR); | 637 HistogramRendererEvent(RENDER_ERROR); |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 << buffering_state; | 695 << buffering_state; |
| 700 DCHECK_NE(buffering_state_, buffering_state); | 696 DCHECK_NE(buffering_state_, buffering_state); |
| 701 lock_.AssertAcquired(); | 697 lock_.AssertAcquired(); |
| 702 buffering_state_ = buffering_state; | 698 buffering_state_ = buffering_state; |
| 703 | 699 |
| 704 task_runner_->PostTask(FROM_HERE, | 700 task_runner_->PostTask(FROM_HERE, |
| 705 base::Bind(buffering_state_cb_, buffering_state_)); | 701 base::Bind(buffering_state_cb_, buffering_state_)); |
| 706 } | 702 } |
| 707 | 703 |
| 708 } // namespace media | 704 } // namespace media |
| OLD | NEW |