summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/base/pipeline.cc66
-rw-r--r--media/base/pipeline.h34
-rw-r--r--media/base/pipeline_unittest.cc26
3 files changed, 44 insertions, 82 deletions
diff --git a/media/base/pipeline.cc b/media/base/pipeline.cc
index c1f63c4..44ffdf6 100644
--- a/media/base/pipeline.cc
+++ b/media/base/pipeline.cc
@@ -71,7 +71,6 @@ 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),
@@ -100,7 +99,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(
@@ -142,23 +141,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_;
@@ -256,6 +238,21 @@ PipelineStatistics Pipeline::GetStatistics() const {
return statistics_;
}
+bool Pipeline::IsInitializedForTesting() {
+ DCHECK(message_loop_->BelongsToCurrentThread())
+ << "Tests should run on the same thread as Pipeline";
+ switch (state_) {
+ case kPausing:
+ case kFlushing:
+ case kSeeking:
+ case kStarting:
+ case kStarted:
+ return true;
+ default:
+ return false;
+ }
+}
+
void Pipeline::SetClockForTesting(Clock* clock) {
clock_.reset(clock);
}
@@ -290,11 +287,6 @@ bool Pipeline::IsPipelineTearingDown() {
return tearing_down_;
}
-bool Pipeline::IsPipelineStopPending() {
- DCHECK(message_loop_->BelongsToCurrentThread());
- return stop_pending_;
-}
-
bool Pipeline::IsPipelineSeeking() {
DCHECK(message_loop_->BelongsToCurrentThread());
if (!seek_pending_)
@@ -342,7 +334,7 @@ Pipeline::State Pipeline::FindNextState(State current) {
// We will always honor Seek() before Stop(). This is based on the
// assumption that we never accept Seek() after Stop().
DCHECK(IsPipelineSeeking() ||
- IsPipelineStopPending() ||
+ !stop_cb_.is_null() ||
IsPipelineTearingDown());
return IsPipelineSeeking() ? kSeeking : kStopping;
} else if (current == kSeeking) {
@@ -632,7 +624,7 @@ void Pipeline::InitializeTask(PipelineStatus last_stage_status) {
}
// If we have received the stop or error signal, return immediately.
- if (IsPipelineStopPending() || IsPipelineStopped() || !IsPipelineOk())
+ if (!stop_cb_.is_null() || IsPipelineStopped() || !IsPipelineOk())
return;
DCHECK(state_ == kInitDemuxer ||
@@ -713,7 +705,7 @@ void Pipeline::InitializeTask(PipelineStatus last_stage_status) {
// 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(stop_cb_.is_null());
DCHECK_NE(state_, kStopped);
if (video_decoder_) {
@@ -733,7 +725,6 @@ void Pipeline::StopTask(const base::Closure& stop_cb) {
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
@@ -806,7 +797,7 @@ void Pipeline::VolumeChangedTask(float volume) {
void Pipeline::SeekTask(TimeDelta time, const PipelineStatusCB& seek_cb) {
DCHECK(message_loop_->BelongsToCurrentThread());
- DCHECK(!IsPipelineStopPending());
+ DCHECK(stop_cb_.is_null());
// Suppress seeking if we're not fully started.
if (state_ != kStarted) {
@@ -976,8 +967,8 @@ void Pipeline::FilterStateTransitionTask() {
StartClockIfWaitingForTimeUpdate_Locked();
}
- if (IsPipelineStopPending()) {
- // We had a pending stop request need to be honored right now.
+ // Check if we have a pending stop request that needs to be honored.
+ if (!stop_cb_.is_null()) {
TearDownPipeline();
}
} else {
@@ -1034,8 +1025,7 @@ void Pipeline::FinishDestroyingFiltersTask() {
if (error_caused_teardown_ && !IsPipelineOk() && !error_cb_.is_null())
error_cb_.Run(status_);
- if (stop_pending_) {
- stop_pending_ = false;
+ if (!stop_cb_.is_null()) {
{
base::AutoLock l(lock_);
running_ = false;
@@ -1194,9 +1184,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 during that time
+ DCHECK(!tearing_down_ ||
+ (tearing_down_ && error_caused_teardown_) ||
+ (tearing_down_ && !stop_cb_.is_null()));
// Mark that we already start tearing down operation.
tearing_down_ = true;
diff --git a/media/base/pipeline.h b/media/base/pipeline.h
index 330cc35..af62c23 100644
--- a/media/base/pipeline.h
+++ b/media/base/pipeline.h
@@ -83,7 +83,6 @@ class MEDIA_EXPORT PipelineStatusNotification {
// ^ SetError()
// |
// [ Any State Other Than InitXXX ]
-
//
// Initialization is a series of state transitions from "Created" through each
// filter initialization state. When all filter initialization states have
@@ -103,24 +102,15 @@ class MEDIA_EXPORT Pipeline
Pipeline(MessageLoop* message_loop, MediaLog* media_log);
// Build a pipeline to using the given filter collection to construct a filter
- // chain.
- //
- // Pipeline initialization is an inherently asynchronous process. Clients can
- // either poll the IsInitialized() method (discouraged) or optionally pass in
- // |start_cb|, which will be executed when initialization completes.
+ // chain, executing |start_cb| when initialization has completed.
//
- // The following permanent callbacks will be executed as follows:
- // |start_cb_| will be executed when Start is done (successfully or not).
+ // The following permanent callbacks will be executed as follows up until
+ // Stop() has completed:
// |ended_cb| will be executed whenever the media reaches the end.
- // |error_cb_| will be executed whenever an error occurs but hasn't
- // been reported already through another callback.
- //
- // These callbacks are only executed after Start() has been called and until
- // Stop() has completed.
+ // |error_cb| will be executed whenever an error occurs but hasn't
+ // been reported already through another callback.
//
// It is an error to call this method after the pipeline has already started.
- //
- // TODO(scherkus): remove IsInitialized() and force clients to use callbacks.
void Start(scoped_ptr<FilterCollection> filter_collection,
const PipelineStatusCB& ended_cb,
const PipelineStatusCB& error_cb,
@@ -155,11 +145,6 @@ class MEDIA_EXPORT Pipeline
// the pipeline.
bool IsRunning() const;
- // Returns true if the pipeline has been started and fully initialized to a
- // point where playback controls will be respected. Note that it is possible
- // for a pipeline to be started but not initialized (i.e., an error occurred).
- bool IsInitialized() const;
-
// Returns true if the media has audio.
bool HasAudio() const;
@@ -216,6 +201,9 @@ class MEDIA_EXPORT Pipeline
// Gets the current pipeline statistics.
PipelineStatistics GetStatistics() const;
+ // TODO(scherkus): Remove IsInitializedForTesting() after stop/error teardown
+ // paths are sane, see http://crbug.com/110228
+ bool IsInitializedForTesting();
void SetClockForTesting(Clock* clock);
void SetErrorForTesting(PipelineStatus status);
@@ -261,9 +249,6 @@ class MEDIA_EXPORT Pipeline
// Helper method to tell whether we are in transition to stop state.
bool IsPipelineTearingDown();
- // We could also be delayed by a transition during seek is performed.
- bool IsPipelineStopPending();
-
// Helper method to tell whether we are in transition to seek state.
bool IsPipelineSeeking();
@@ -447,9 +432,6 @@ class MEDIA_EXPORT Pipeline
// Whether or not the pipeline is in transition for a seek operation.
bool seek_pending_;
- // Whether or not the pipeline is pending a stop operation.
- bool stop_pending_;
-
// Whether or not the pipeline is perform a stop operation.
bool tearing_down_;
diff --git a/media/base/pipeline_unittest.cc b/media/base/pipeline_unittest.cc
index 36b4257..bff1afe 100644
--- a/media/base/pipeline_unittest.cc
+++ b/media/base/pipeline_unittest.cc
@@ -103,7 +103,12 @@ class PipelineTest : public ::testing::Test {
}
// Shutdown sequence.
- if (pipeline_->IsInitialized()) {
+ //
+ // TODO(scherkus): This check is required because in certain teardown
+ // cases the pipeline is still "running" but has already stopped due to
+ // errors. In an ideal world we stop running when we teardown, but that
+ // requires cleaning up shutdown path, see http://crbug.com/110228
+ if (pipeline_->IsInitializedForTesting()) {
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
@@ -319,7 +324,6 @@ TEST_F(PipelineTest, NotStarted) {
const base::TimeDelta kZero;
EXPECT_FALSE(pipeline_->IsRunning());
- EXPECT_FALSE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
EXPECT_FALSE(pipeline_->HasVideo());
@@ -366,7 +370,6 @@ TEST_F(PipelineTest, NeverInitializes) {
base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)));
message_loop_.RunAllPending();
- EXPECT_FALSE(pipeline_->IsInitialized());
// Because our callback will get executed when the test tears down, we'll
// verify that nothing has been called, then set our expectation for the call
@@ -387,7 +390,6 @@ TEST_F(PipelineTest, RequiredFilterMissing) {
base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
base::Bind(&CallbackHelper::OnStart, base::Unretained(&callbacks_)));
message_loop_.RunAllPending();
- EXPECT_FALSE(pipeline_->IsInitialized());
}
TEST_F(PipelineTest, URLNotFound) {
@@ -397,7 +399,6 @@ TEST_F(PipelineTest, URLNotFound) {
.WillOnce(RunClosure());
InitializePipeline(PIPELINE_ERROR_URL_NOT_FOUND);
- EXPECT_FALSE(pipeline_->IsInitialized());
}
TEST_F(PipelineTest, NoStreams) {
@@ -407,7 +408,6 @@ TEST_F(PipelineTest, NoStreams) {
.WillOnce(RunClosure());
InitializePipeline(PIPELINE_ERROR_COULD_NOT_RENDER);
- EXPECT_FALSE(pipeline_->IsInitialized());
}
TEST_F(PipelineTest, AudioStream) {
@@ -420,7 +420,6 @@ TEST_F(PipelineTest, AudioStream) {
InitializeAudioRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
EXPECT_FALSE(pipeline_->HasVideo());
}
@@ -435,7 +434,6 @@ TEST_F(PipelineTest, VideoStream) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
}
@@ -454,7 +452,6 @@ TEST_F(PipelineTest, AudioVideoStream) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
}
@@ -510,7 +507,6 @@ TEST_F(PipelineTest, Properties) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_EQ(kDuration.ToInternalValue(),
pipeline_->GetMediaDuration().ToInternalValue());
EXPECT_EQ(kTotalBytes, pipeline_->GetTotalBytes());
@@ -528,7 +524,6 @@ TEST_F(PipelineTest, GetBufferedTimeRanges) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_EQ(0u, pipeline_->GetBufferedTimeRanges().size());
@@ -584,7 +579,6 @@ TEST_F(PipelineTest, DisableAudioRenderer) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
@@ -613,7 +607,6 @@ TEST_F(PipelineTest, DisableAudioRendererDuringInit) {
OnAudioRendererDisabled());
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
@@ -808,7 +801,6 @@ TEST_F(PipelineTest, StartTimeIsZero) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
@@ -831,7 +823,6 @@ TEST_F(PipelineTest, StartTimeIsNonZero) {
InitializeVideoRenderer();
InitializePipeline(PIPELINE_OK);
- EXPECT_TRUE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
@@ -905,7 +896,6 @@ TEST_F(PipelineTest, InitFailure_Demuxer) {
EXPECT_CALL(*mocks_->demuxer(), Stop(_))
.WillOnce(RunClosure());
InitializePipeline(expected_status);
- EXPECT_FALSE(pipeline_->IsInitialized());
}
TEST_F(PipelineTest, InitFailure_AudioDecoder) {
@@ -924,7 +914,6 @@ TEST_F(PipelineTest, InitFailure_AudioDecoder) {
.WillOnce(RunClosure());
InitializePipeline(expected_status);
- EXPECT_FALSE(pipeline_->IsInitialized());
EXPECT_FALSE(pipeline_->HasAudio());
}
@@ -948,7 +937,6 @@ TEST_F(PipelineTest, InitFailure_AudioRenderer) {
.WillOnce(RunClosure());
InitializePipeline(expected_status);
- EXPECT_FALSE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
}
@@ -975,7 +963,6 @@ TEST_F(PipelineTest, InitFailure_VideoDecoder) {
.WillOnce(RunClosure());
InitializePipeline(expected_status);
- EXPECT_FALSE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
EXPECT_FALSE(pipeline_->HasVideo());
}
@@ -1006,7 +993,6 @@ TEST_F(PipelineTest, InitFailure_VideoRenderer) {
.WillOnce(RunClosure());
InitializePipeline(expected_status);
- EXPECT_FALSE(pipeline_->IsInitialized());
EXPECT_TRUE(pipeline_->HasAudio());
EXPECT_TRUE(pipeline_->HasVideo());
}