Index: media/base/pipeline.cc |
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc |
index 92f0199bd6a675b10b8956ef2aab8f0e7e73ce38..7ba148c4a7ec8318e69b3cd7c2634fd9ed21059e 100644 |
--- a/media/base/pipeline.cc |
+++ b/media/base/pipeline.cc |
@@ -71,9 +71,7 @@ Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
media_log_(media_log), |
running_(false), |
seek_pending_(false), |
- stop_pending_(false), |
tearing_down_(false), |
- error_caused_teardown_(false), |
playback_rate_change_pending_(false), |
did_loading_progress_(false), |
total_bytes_(0), |
@@ -98,7 +96,7 @@ Pipeline::Pipeline(MessageLoop* message_loop, MediaLog* media_log) |
Pipeline::~Pipeline() { |
base::AutoLock auto_lock(lock_); |
DCHECK(!running_) << "Stop() must complete before destroying object"; |
- DCHECK(!stop_pending_); |
+ DCHECK(stop_cb_.is_null()); |
DCHECK(!seek_pending_); |
media_log_->AddEvent( |
@@ -119,10 +117,6 @@ void Pipeline::Start(scoped_ptr<FilterCollection> collection, |
} |
void Pipeline::Stop(const base::Closure& stop_cb) { |
- base::AutoLock auto_lock(lock_); |
- CHECK(running_) << "Media pipeline isn't running"; |
- |
- // Stop the pipeline, which will set |running_| to false on our behalf. |
message_loop_->PostTask(FROM_HERE, base::Bind( |
&Pipeline::StopTask, this, stop_cb)); |
} |
@@ -140,23 +134,6 @@ bool Pipeline::IsRunning() const { |
return running_; |
} |
-bool Pipeline::IsInitialized() const { |
- // TODO(scherkus): perhaps replace this with a bool that is set/get under the |
- // lock, because this is breaching the contract that |state_| is only accessed |
- // on |message_loop_|. |
- base::AutoLock auto_lock(lock_); |
- switch (state_) { |
- case kPausing: |
- case kFlushing: |
- case kSeeking: |
- case kStarting: |
- case kStarted: |
- return true; |
- default: |
- return false; |
- } |
-} |
- |
bool Pipeline::HasAudio() const { |
base::AutoLock auto_lock(lock_); |
return has_audio_; |
@@ -276,7 +253,7 @@ bool Pipeline::IsPipelineOk() { |
bool Pipeline::IsPipelineStopped() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
- return state_ == kStopped || state_ == kError; |
+ return state_ == kStopped; |
} |
bool Pipeline::IsPipelineTearingDown() { |
@@ -286,7 +263,7 @@ bool Pipeline::IsPipelineTearingDown() { |
bool Pipeline::IsPipelineStopPending() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
- return stop_pending_; |
+ return !stop_cb_.is_null(); |
} |
bool Pipeline::IsPipelineSeeking() { |
@@ -343,7 +320,7 @@ Pipeline::State Pipeline::FindNextState(State current) { |
} else if (current == kStarting) { |
return kStarted; |
} else if (current == kStopping) { |
- return error_caused_teardown_ ? kError : kStopped; |
+ return kStopped; |
} else { |
return current; |
} |
@@ -689,36 +666,32 @@ void Pipeline::InitializeTask(PipelineStatus last_stage_status) { |
} |
} |
-// This method is called as a result of the client calling Pipeline::Stop() or |
-// as the result of an error condition. |
-// We stop the filters in the reverse order. |
-// |
-// TODO(scherkus): beware! this can get posted multiple times since we post |
-// Stop() tasks even if we've already stopped. Perhaps this should no-op for |
-// additional calls, however most of this logic will be changing. |
void Pipeline::StopTask(const base::Closure& stop_cb) { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
DCHECK(!IsPipelineStopPending()); |
- DCHECK_NE(state_, kStopped); |
+ DCHECK(!stop_cb.is_null()); |
+ |
+ if (state_ == kStopped) { |
+ stop_cb.Run(); |
+ return; |
+ } |
if (video_decoder_) { |
video_decoder_->PrepareForShutdownHack(); |
video_decoder_ = NULL; |
} |
- if (IsPipelineTearingDown() && error_caused_teardown_) { |
+ if (IsPipelineTearingDown() && status_ != PIPELINE_OK) { |
// If we are stopping due to SetError(), stop normally instead of |
// going to error state and calling |error_cb_|. This converts |
// the teardown in progress from an error teardown into one that acts |
// like the error never occurred. |
base::AutoLock auto_lock(lock_); |
status_ = PIPELINE_OK; |
- error_caused_teardown_ = false; |
} |
stop_cb_ = stop_cb; |
- stop_pending_ = true; |
if (!IsPipelineSeeking() && !IsPipelineTearingDown()) { |
// We will tear down pipeline immediately when there is no seek operation |
// pending and no teardown in progress. This should include the case where |
@@ -741,8 +714,6 @@ void Pipeline::ErrorChangedTask(PipelineStatus error) { |
base::AutoLock auto_lock(lock_); |
status_ = error; |
- error_caused_teardown_ = true; |
- |
// Posting TearDownPipeline() to message loop so that we can make sure |
// it runs after any pending callbacks that are already queued. |
// |tearing_down_| is set early here to make sure that pending callbacks |
@@ -962,7 +933,7 @@ void Pipeline::TeardownStateTransitionTask() { |
switch (state_) { |
case kStopping: |
- SetState(error_caused_teardown_ ? kError : kStopped); |
+ SetState(kStopped); |
FinishDestroyingFiltersTask(); |
break; |
case kPausing: |
@@ -975,7 +946,6 @@ void Pipeline::TeardownStateTransitionTask() { |
break; |
case kCreated: |
- case kError: |
case kInitDemuxer: |
case kInitAudioDecoder: |
case kInitAudioRenderer: |
@@ -999,23 +969,20 @@ void Pipeline::FinishDestroyingFiltersTask() { |
audio_renderer_ = NULL; |
video_renderer_ = NULL; |
demuxer_ = NULL; |
+ { |
+ base::AutoLock l(lock_); |
+ running_ = false; |
+ } |
- if (error_caused_teardown_ && !IsPipelineOk() && !error_cb_.is_null()) |
- error_cb_.Run(status_); |
- |
- if (stop_pending_) { |
- stop_pending_ = false; |
- { |
- base::AutoLock l(lock_); |
- running_ = false; |
- } |
- |
- // Notify the client that stopping has finished. |
+ // We prioritize executing stop callbacks over error callbacks if they're |
+ // present. |
+ if (!stop_cb_.is_null()) { |
base::ResetAndReturn(&stop_cb_).Run(); |
+ } else if (!error_cb_.is_null() && status_ != PIPELINE_OK) { |
+ error_cb_.Run(status_); |
} |
tearing_down_ = false; |
- error_caused_teardown_ = false; |
} |
void Pipeline::InitializeDemuxer() { |
@@ -1163,9 +1130,13 @@ void Pipeline::TearDownPipeline() { |
DCHECK(message_loop_->BelongsToCurrentThread()); |
DCHECK_NE(kStopped, state_); |
- DCHECK(!tearing_down_ || // Teardown on Stop(). |
- (tearing_down_ && error_caused_teardown_) || // Teardown on error. |
- (tearing_down_ && stop_pending_)); // Stop during teardown by error. |
+ // We're either... |
+ // 1) ...tearing down due to Stop() (it doesn't set tearing_down_) |
+ // 2) ...tearing down due to an error (it does set tearing_down_) |
+ // 3) ...tearing down due to an error and Stop() was called |
+ DCHECK(!tearing_down_ && !stop_cb_.is_null() || |
+ (tearing_down_ && status_ != PIPELINE_OK) || |
+ (tearing_down_ && !stop_cb_.is_null())); |
// Mark that we already start tearing down operation. |
tearing_down_ = true; |
@@ -1175,7 +1146,6 @@ void Pipeline::TearDownPipeline() { |
switch (state_) { |
case kCreated: |
- case kError: |
SetState(kStopped); |
// Need to put this in the message loop to make sure that it comes |
// after any pending callback tasks that are already queued. |