Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(329)

Unified Diff: services/media/factory_service/media_player_impl.cc

Issue 2085593002: Motown: Change player state machine to support preroll (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Make SetTimelineTransform calls more uniform with respect to other operations affecting the state m… Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « services/media/factory_service/media_player_impl.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: services/media/factory_service/media_player_impl.cc
diff --git a/services/media/factory_service/media_player_impl.cc b/services/media/factory_service/media_player_impl.cc
index e174c2f90dcd219f930ab7b4d656e67b04682e2a..ee33b06a47359f9d292026e2d6539b96872fbf73 100644
--- a/services/media/factory_service/media_player_impl.cc
+++ b/services/media/factory_service/media_player_impl.cc
@@ -83,7 +83,7 @@ MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader,
callback_joiner->WhenJoined([this]() {
// The enabled streams are prepared.
factory_.reset();
- state_ = State::kPaused;
+ state_ = State::kFlushed;
Update();
});
});
@@ -92,93 +92,170 @@ MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader,
MediaPlayerImpl::~MediaPlayerImpl() {}
void MediaPlayerImpl::Update() {
+ // This method is called whenever we might want to take action based on the
+ // current state and recent events. The current state is in |state_|. Recent
+ // events are recorded in |target_state_|, which indicates what state we'd
+ // like to transition to, |target_position_|, which can indicate a position
+ // we'd like to stream to, and |end_of_stream_| which tells us we've reached
+ // end of stream.
+ //
+ // The states are as follows:
+ //
+ // |kWaiting| - Indicates that we've done something asynchronous, and no
+ // further action should be taken by the state machine until that
+ // something completes (at which point the callback will change
+ // the state and call |Update|).
+ // |kFlushed| - Indicates that presentation time is not progressing and that
+ // the pipeline is not primed with packets. This is the initial
+ // state and the state we transition to in preparation for
+ // seeking. A seek is currently only done when when the pipeline
+ // is clear of packets.
+ // |kPrimed| - Indicates that presentation time is not progressing and that
+ // the pipeline is primed with packets. We transition to this
+ // state when the client calls |Pause|, either from |kFlushed| or
+ // |kPlaying| state.
+ // |kPlaying| - Indicates that presentation time is progressing and there are
+ // packets in the pipeline. We transition to this state when the
+ // client calls |Play|. If we're in |kFlushed| when |Play| is
+ // called, we transition through |kPrimed| state.
+ //
+ // The while loop that surrounds all the logic below is there because, after
+ // taking some action and transitioning to a new state, we may want to check
+ // to see if there's more to do in the new state. You'll also notice that
+ // the callback lambdas generally call |Update|.
while (true) {
switch (state_) {
- case State::kPaused:
+ case State::kFlushed:
+ // Presentation time is not progressing, and the pipeline is clear of
+ // packets.
if (target_position_ != kUnspecifiedTime) {
- WhenPausedAndSeeking();
- break;
- }
+ // We want to seek. Enter |kWaiting| state until the operation is
+ // complete.
+ state_ = State::kWaiting;
+ demux_->Seek(target_position_, [this]() {
+ transform_subject_time_ = target_position_;
+ target_position_ = kUnspecifiedTime;
+ state_ = State::kFlushed;
+ // Back in |kFlushed|. Call |Update| to see if there's further
+ // action to be taken.
+ Update();
+ });
- if (target_state_ == State::kPlaying) {
- if (!flushed_) {
- SetTimelineTransform(1, 1);
- state_ = State::kWaiting;
- break;
- }
+ // Done for now. We're in kWaiting, and the callback will call Update
+ // when the Seek call is complete.
+ return;
+ }
- flushed_ = false;
+ if (target_state_ == State::kPlaying ||
+ target_state_ == State::kPrimed) {
+ // We want to transition to |kPrimed| or to |kPlaying|, for which
+ // |kPrimed| is a prerequisite. We enter |kWaiting| state, issue the
+ // |Prime| request and transition to |kPrimed| when the operation is
+ // complete.
state_ = State::kWaiting;
demux_->Prime([this]() {
- SetTimelineTransform(1, 1);
- state_ = State::kWaiting;
+ state_ = State::kPrimed;
+ // Now we're in |kPrimed|. Call |Update| to see if there's further
+ // action to be taken.
Update();
});
+
+ // Done for now. We're in |kWaiting|, and the callback will call
+ // |Update| when the prime is complete.
+ return;
}
+
+ // No interesting events to respond to. Done for now.
+ return;
+
+ case State::kPrimed:
+ // Presentation time is not progressing, and the pipeline is primed with
+ // packets.
+ if (target_position_ != kUnspecifiedTime ||
+ target_state_ == State::kFlushed) {
+ // Either we want to seek or just want to transition to |kFlushed|.
+ // We transition to |kWaiting|, issue the |Flush| request and
+ // transition to |kFlushed| when the operation is complete.
+ state_ = State::kWaiting;
+ demux_->Flush([this]() {
+ state_ = State::kFlushed;
+ // Now we're in |kFlushed|. Call |Update| to see if there's further
+ // action to be taken.
+ Update();
+ });
+
+ // Done for now. We're in |kWaiting|, and the callback will call
+ // |Update| when the flush is complete.
+ return;
+ }
+
+ if (target_state_ == State::kPlaying) {
+ // We want to transition to |kPlaying|. Enter |kWaiting|, start the
+ // presentation timeline and transition to |kPlaying| when the
+ // operation completes.
+ state_ = State::kWaiting;
+ timeline_consumer_->SetTimelineTransform(
+ transform_subject_time_, 1, 1,
+ Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
+ [this](bool completed) {
+ state_ = State::kPlaying;
+ // Now we're in |kPlaying|. Call |Update| to see if there's
+ // further
+ // action to be taken.
+ Update();
+ });
+
+ transform_subject_time_ = kUnspecifiedTime;
+ return;
+ }
+
+ // No interesting events to respond to. Done for now.
return;
case State::kPlaying:
+ // Presentation time is progressing, and packets are moving through
+ // the pipeline.
if (target_position_ != kUnspecifiedTime ||
- target_state_ == State::kPaused) {
- SetTimelineTransform(1, 0);
+ target_state_ == State::kFlushed ||
+ target_state_ == State::kPrimed) {
+ // Either we want to seek or we want to stop playback. In either case,
+ // we need to enter |kWaiting|, stop the presentation timeline and
+ // transition to |kPrimed| when the operation completes.
state_ = State::kWaiting;
- break;
+ timeline_consumer_->SetTimelineTransform(
+ transform_subject_time_, 1, 0,
+ Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
+ [this](bool completed) {
+ state_ = State::kPrimed;
+ // Now we're in |kPrimed|. Call |Update| to see if there's
+ // further
+ // action to be taken.
+ Update();
+ });
+
+ transform_subject_time_ = kUnspecifiedTime;
+ return;
}
if (end_of_stream_) {
- target_state_ = State::kPaused;
- state_ = State::kPaused;
+ // We've reached end of stream. The presentation timeline stops by
+ // itself, so we just need to transition to |kPrimed|.
+ target_state_ = State::kPrimed;
+ state_ = State::kPrimed;
+ // Loop around to check if there's more work to do.
break;
}
+
+ // No interesting events to respond to. Done for now.
return;
case State::kWaiting:
+ // Waiting for some async operation. Nothing to do until it completes.
return;
}
}
}
-void MediaPlayerImpl::WhenPausedAndSeeking() {
- if (!flushed_) {
- state_ = State::kWaiting;
- demux_->Flush([this]() {
- flushed_ = true;
- WhenFlushedAndSeeking();
- });
- } else {
- WhenFlushedAndSeeking();
- }
-}
-
-void MediaPlayerImpl::WhenFlushedAndSeeking() {
- state_ = State::kWaiting;
- DCHECK(target_position_ != kUnspecifiedTime);
- demux_->Seek(target_position_, [this]() {
- transform_subject_time_ = target_position_;
- target_position_ = kUnspecifiedTime;
- state_ = State::kPaused;
- Update();
- });
-}
-
-void MediaPlayerImpl::SetTimelineTransform(uint32_t reference_delta,
- uint32_t subject_delta) {
- timeline_consumer_->SetTimelineTransform(
- transform_subject_time_, reference_delta, subject_delta,
- Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
- [this, subject_delta](bool completed) {
- RCHECK(state_ == State::kWaiting);
-
- if (subject_delta == 0) {
- state_ = State::kPaused;
- } else {
- state_ = State::kPlaying;
- }
-
- Update();
- });
-}
-
void MediaPlayerImpl::GetStatus(uint64_t version_last_seen,
const GetStatusCallback& callback) {
status_publisher_.Get(version_last_seen, callback);
@@ -190,7 +267,7 @@ void MediaPlayerImpl::Play() {
}
void MediaPlayerImpl::Pause() {
- target_state_ = State::kPaused;
+ target_state_ = State::kPrimed;
Update();
}
« no previous file with comments | « services/media/factory_service/media_player_impl.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698