Index: media/base/pipeline_impl.cc |
diff --git a/media/base/pipeline_impl.cc b/media/base/pipeline_impl.cc |
index d071d58db9a08feb4f21669bafc07fa608117188..022198cc9c7b163bbe56fdd7e3cc342f35144095 100644 |
--- a/media/base/pipeline_impl.cc |
+++ b/media/base/pipeline_impl.cc |
@@ -300,6 +300,7 @@ void PipelineImpl::ResetState() { |
stop_pending_ = false; |
seek_pending_ = false; |
tearing_down_ = false; |
+ error_caused_teardown_ = false; |
duration_ = kZero; |
buffered_time_ = kZero; |
buffered_bytes_ = 0; |
@@ -325,16 +326,6 @@ bool PipelineImpl::IsPipelineOk() { |
return PIPELINE_OK == GetError(); |
} |
-bool PipelineImpl::IsPipelineInitializing() { |
- DCHECK_EQ(MessageLoop::current(), message_loop_); |
- return state_ == kInitDataSource || |
- state_ == kInitDemuxer || |
- state_ == kInitAudioDecoder || |
- state_ == kInitAudioRenderer || |
- state_ == kInitVideoDecoder || |
- state_ == kInitVideoRenderer; |
-} |
- |
bool PipelineImpl::IsPipelineStopped() { |
DCHECK_EQ(MessageLoop::current(), message_loop_); |
return state_ == kStopped || state_ == kError; |
@@ -393,7 +384,7 @@ PipelineImpl::State PipelineImpl::FindNextState(State current) { |
} else if (current == kStarting) { |
return kStarted; |
} else if (current == kStopping) { |
- return kStopped; |
+ return error_caused_teardown_ ? kError : kStopped; |
} else { |
return current; |
} |
@@ -572,7 +563,13 @@ void PipelineImpl::InitializeTask() { |
return; |
} |
- DCHECK(state_ == kCreated || IsPipelineInitializing()); |
+ DCHECK(state_ == kCreated || |
+ state_ == kInitDataSource || |
+ state_ == kInitDemuxer || |
+ state_ == kInitAudioDecoder || |
+ state_ == kInitAudioRenderer || |
+ state_ == kInitVideoDecoder || |
+ state_ == kInitVideoRenderer); |
// Just created, create data source. |
if (state_ == kCreated) { |
@@ -670,28 +667,33 @@ void PipelineImpl::InitializeTask() { |
// additional calls, however most of this logic will be changing. |
void PipelineImpl::StopTask(PipelineCallback* stop_callback) { |
DCHECK_EQ(MessageLoop::current(), message_loop_); |
- PipelineError error = GetError(); |
+ DCHECK(!IsPipelineStopPending()); |
+ DCHECK_NE(state_, kStopped); |
- if (state_ == kStopped || (IsPipelineStopPending() && error == PIPELINE_OK)) { |
- // If we are already stopped or stopping normally, return immediately. |
+ if (state_ == kStopped) { |
+ // Already stopped so just run callback. |
+ stop_callback->Run(); |
delete stop_callback; |
return; |
- } else if (state_ == kError || |
- (IsPipelineStopPending() && error != PIPELINE_OK)) { |
+ } |
+ |
+ if (IsPipelineTearingDown() && error_caused_teardown_) { |
// If we are stopping due to SetError(), stop normally instead of |
- // going to error state. |
+ // going to error state and calling |error_callback_|. This converts |
+ // the teardown in progress from an error teardown into one that acts |
+ // like the error never occurred. |
AutoLock auto_lock(lock_); |
error_ = PIPELINE_OK; |
+ error_caused_teardown_ = false; |
} |
stop_callback_.reset(stop_callback); |
stop_pending_ = true; |
- if (!IsPipelineSeeking()) { |
+ if (!IsPipelineSeeking() && !IsPipelineTearingDown()) { |
// We will tear down pipeline immediately when there is no seek operation |
- // pending. This should include the case where we are partially initialized. |
- // Ideally this case should use SetError() rather than Stop() to tear down. |
- DCHECK(!IsPipelineTearingDown()); |
+ // pending and no teardown in progress. This should include the case where |
+ // we are partially initialized. |
TearDownPipeline(); |
} |
} |
@@ -710,6 +712,7 @@ void PipelineImpl::ErrorChangedTask(PipelineError error) { |
AutoLock auto_lock(lock_); |
error_ = error; |
+ error_caused_teardown_ = true; |
TearDownPipeline(); |
} |
@@ -915,11 +918,12 @@ void PipelineImpl::FinishDestroyingFiltersTask() { |
pipeline_filter_ = NULL; |
- stop_pending_ = false; |
- tearing_down_ = false; |
+ if (error_caused_teardown_ && GetError() != PIPELINE_OK && |
+ error_callback_.get()) { |
+ error_callback_->Run(); |
+ } |
- if (PIPELINE_OK == GetError()) { |
- // Destroying filters due to Stop(). |
+ if (stop_pending_) { |
ResetState(); |
// Notify the client that stopping has finished. |
@@ -927,14 +931,11 @@ void PipelineImpl::FinishDestroyingFiltersTask() { |
stop_callback_->Run(); |
stop_callback_.reset(); |
} |
- } else { |
- // Destroying filters due to SetError(). |
- set_state(kError); |
- // If our owner has requested to be notified of an error. |
- if (error_callback_.get()) { |
- error_callback_->Run(); |
- } |
} |
+ |
+ stop_pending_ = false; |
+ tearing_down_ = false; |
+ error_caused_teardown_ = false; |
} |
bool PipelineImpl::PrepareFilter(scoped_refptr<Filter> filter) { |
@@ -1119,25 +1120,54 @@ void PipelineImpl::TearDownPipeline() { |
// Mark that we already start tearing down operation. |
tearing_down_ = true; |
- if (IsPipelineInitializing()) { |
- // Make it look like initialization was successful. |
- pipeline_filter_ = pipeline_init_state_->composite_; |
- pipeline_init_state_.reset(); |
+ switch(state_) { |
+ case kCreated: |
+ case kError: |
+ set_state(kStopped); |
+ message_loop_->PostTask(FROM_HERE, |
+ NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); |
+ break; |
- set_state(kStopping); |
- pipeline_filter_->Stop(NewCallback( |
- this, &PipelineImpl::OnFilterStateTransition)); |
+ case kInitDataSource: |
+ case kInitDemuxer: |
+ case kInitAudioDecoder: |
+ case kInitAudioRenderer: |
+ case kInitVideoDecoder: |
+ case kInitVideoRenderer: |
+ // Make it look like initialization was successful. |
+ pipeline_filter_ = pipeline_init_state_->composite_; |
+ pipeline_init_state_.reset(); |
+ |
+ set_state(kStopping); |
+ pipeline_filter_->Stop( |
+ NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
- FinishInitialization(); |
- } else if (pipeline_filter_.get()) { |
- set_state(kPausing); |
- pipeline_filter_->Pause(NewCallback( |
- this, &PipelineImpl::OnFilterStateTransition)); |
- } else { |
- set_state(kStopped); |
- message_loop_->PostTask(FROM_HERE, |
- NewRunnableMethod(this, &PipelineImpl::FinishDestroyingFiltersTask)); |
- } |
+ FinishInitialization(); |
+ break; |
+ |
+ case kPausing: |
+ case kSeeking: |
+ case kFlushing: |
+ case kStarting: |
+ set_state(kStopping); |
+ pipeline_filter_->Stop( |
+ NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
+ break; |
+ |
+ case kStarted: |
+ case kEnded: |
+ set_state(kPausing); |
+ pipeline_filter_->Pause( |
+ NewCallback(this, &PipelineImpl::OnFilterStateTransition)); |
+ break; |
+ |
+ case kStopping: |
+ case kStopped: |
+ NOTREACHED() << "Unexpected state for teardown: " << state_; |
+ break; |
+ // default: intentionally left out to force new states to cause compiler |
+ // errors. |
+ }; |
} |
} // namespace media |