Index: media/base/pipeline.cc |
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc |
index cb4469bf893ff0934d6dd4e25b176072a1321d6d..11e8e8d40a5b1f2958ea1a42b5b92336809902a8 100644 |
--- a/media/base/pipeline.cc |
+++ b/media/base/pipeline.cc |
@@ -19,6 +19,7 @@ |
#include "base/synchronization/condition_variable.h" |
#include "media/base/audio_decoder.h" |
#include "media/base/audio_renderer.h" |
+#include "media/base/bind_to_current_loop.h" |
#include "media/base/clock.h" |
#include "media/base/filter_collection.h" |
#include "media/base/media_log.h" |
@@ -412,6 +413,10 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { |
PlaybackRateChangedTask(GetPlaybackRate()); |
VolumeChangedTask(GetVolume()); |
+ // Handle renderers that immediately signal they have enough data. |
+ if (!WaitingForEnoughData()) |
+ TransitionToNonWaiting(); |
+ |
// We enter this state from either kInitPrerolling or kSeeking. As of now |
// both those states call Preroll(), which means by time we enter this |
// state we've already buffered enough data. Forcefully update the |
@@ -420,11 +425,10 @@ void Pipeline::StateTransitionTask(PipelineStatus status) { |
// |
// TODO(scherkus): Remove after renderers are taught to fire buffering |
// state callbacks http://crbug.com/144683 |
- DCHECK(WaitingForEnoughData()); |
- if (audio_renderer_) |
- BufferingStateChanged(&audio_buffering_state_, BUFFERING_HAVE_ENOUGH); |
- if (video_renderer_) |
+ if (video_renderer_) { |
+ DCHECK(WaitingForEnoughData()); |
BufferingStateChanged(&video_buffering_state_, BUFFERING_HAVE_ENOUGH); |
+ } |
return; |
case kStopping: |
@@ -451,9 +455,9 @@ void Pipeline::DoInitialPreroll(const PipelineStatusCB& done_cb) { |
// Preroll renderers. |
if (audio_renderer_) { |
- bound_fns.Push(base::Bind( |
- &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), |
- seek_timestamp)); |
+ bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, |
+ base::Unretained(audio_renderer_.get()), |
+ seek_timestamp)); |
} |
if (video_renderer_) { |
@@ -522,9 +526,9 @@ void Pipeline::DoSeek( |
// Preroll renderers. |
if (audio_renderer_) { |
- bound_fns.Push(base::Bind( |
- &AudioRenderer::Preroll, base::Unretained(audio_renderer_.get()), |
- seek_timestamp)); |
+ bound_fns.Push(base::Bind(&AudioRenderer::StartPlayingFrom, |
+ base::Unretained(audio_renderer_.get()), |
+ seek_timestamp)); |
} |
if (video_renderer_) { |
@@ -857,8 +861,11 @@ void Pipeline::InitializeAudioRenderer(const PipelineStatusCB& done_cb) { |
demuxer_->GetStream(DemuxerStream::AUDIO), |
done_cb, |
base::Bind(&Pipeline::OnUpdateStatistics, base::Unretained(this)), |
- base::Bind(&Pipeline::OnAudioUnderflow, base::Unretained(this)), |
base::Bind(&Pipeline::OnAudioTimeUpdate, base::Unretained(this)), |
+ // TODO(scherkus): Enforce AudioRendererImpl to call on right thread. |
+ BindToCurrentLoop(base::Bind(&Pipeline::BufferingStateChanged, |
acolwell GONE FROM CHROMIUM
2014/05/13 20:44:27
nit: Shouldn't we hide this wrapping in the AudioR
scherkus (not reviewing)
2014/05/15 23:28:43
Done.
|
+ base::Unretained(this), |
+ &audio_buffering_state_)), |
base::Bind(&Pipeline::OnAudioRendererEnded, base::Unretained(this)), |
base::Bind(&Pipeline::SetError, base::Unretained(this))); |
} |
@@ -879,20 +886,6 @@ void Pipeline::InitializeVideoRenderer(const PipelineStatusCB& done_cb) { |
base::Bind(&Pipeline::GetMediaDuration, base::Unretained(this))); |
} |
-void Pipeline::OnAudioUnderflow() { |
- if (!task_runner_->BelongsToCurrentThread()) { |
acolwell GONE FROM CHROMIUM
2014/05/13 20:44:27
\o/ I'm happy to see this method die. It lived WAY
|
- task_runner_->PostTask(FROM_HERE, base::Bind( |
- &Pipeline::OnAudioUnderflow, base::Unretained(this))); |
- return; |
- } |
- |
- if (state_ != kPlaying) |
- return; |
- |
- if (audio_renderer_) |
- audio_renderer_->ResumeAfterUnderflow(); |
-} |
- |
void Pipeline::BufferingStateChanged(BufferingState* buffering_state, |
BufferingState new_buffering_state) { |
DVLOG(1) << __FUNCTION__ << "(" << *buffering_state << ", " |
@@ -904,13 +897,13 @@ void Pipeline::BufferingStateChanged(BufferingState* buffering_state, |
// Renderer underflowed. |
if (!was_waiting_for_enough_data && WaitingForEnoughData()) { |
- StartWaitingForEnoughData(); |
+ TransitionToWaiting(); |
return; |
} |
// Renderer prerolled. |
if (was_waiting_for_enough_data && !WaitingForEnoughData()) { |
- StartPlayback(); |
+ TransitionToNonWaiting(); |
return; |
} |
} |
@@ -926,10 +919,25 @@ bool Pipeline::WaitingForEnoughData() const { |
return false; |
} |
-void Pipeline::StartWaitingForEnoughData() { |
+void Pipeline::TransitionToWaiting() { |
DVLOG(1) << __FUNCTION__; |
DCHECK_EQ(state_, kPlaying); |
DCHECK(WaitingForEnoughData()); |
+ task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&Pipeline::PausePlayback, base::Unretained(this))); |
+} |
+ |
+void Pipeline::TransitionToNonWaiting() { |
+ DVLOG(1) << __FUNCTION__; |
+ DCHECK_EQ(state_, kPlaying); |
+ DCHECK(!WaitingForEnoughData()); |
+ task_runner_->PostTask( |
acolwell GONE FROM CHROMIUM
2014/05/13 20:44:27
Why do you need to PostTask() here and above now?
scherkus (not reviewing)
2014/05/15 23:28:43
it's to avoid reentrancy into renderers ... but I
|
+ FROM_HERE, base::Bind(&Pipeline::StartPlayback, base::Unretained(this))); |
+} |
+ |
+void Pipeline::PausePlayback() { |
+ DVLOG(1) << __FUNCTION__; |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
if (audio_renderer_) |
audio_renderer_->StopRendering(); |
@@ -940,8 +948,7 @@ void Pipeline::StartWaitingForEnoughData() { |
void Pipeline::StartPlayback() { |
DVLOG(1) << __FUNCTION__; |
- DCHECK_EQ(state_, kPlaying); |
- DCHECK(!WaitingForEnoughData()); |
+ DCHECK(task_runner_->BelongsToCurrentThread()); |
if (audio_renderer_) { |
// We use audio stream to update the clock. So if there is such a |