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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « services/media/factory_service/media_player_impl.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/logging.h" 5 #include "base/logging.h"
6 #include "mojo/public/cpp/application/connect.h" 6 #include "mojo/public/cpp/application/connect.h"
7 #include "mojo/services/media/common/cpp/timeline.h" 7 #include "mojo/services/media/common/cpp/timeline.h"
8 #include "services/media/factory_service/media_player_impl.h" 8 #include "services/media/factory_service/media_player_impl.h"
9 #include "services/media/framework/parts/reader.h" 9 #include "services/media/framework/parts/reader.h"
10 #include "services/media/framework/util/callback_joiner.h" 10 #include "services/media/framework/util/callback_joiner.h"
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 break; 76 break;
77 // TODO(dalesat): Enable other stream types. 77 // TODO(dalesat): Enable other stream types.
78 default: 78 default:
79 break; 79 break;
80 } 80 }
81 } 81 }
82 82
83 callback_joiner->WhenJoined([this]() { 83 callback_joiner->WhenJoined([this]() {
84 // The enabled streams are prepared. 84 // The enabled streams are prepared.
85 factory_.reset(); 85 factory_.reset();
86 state_ = State::kPaused; 86 state_ = State::kFlushed;
87 Update(); 87 Update();
88 }); 88 });
89 }); 89 });
90 } 90 }
91 91
92 MediaPlayerImpl::~MediaPlayerImpl() {} 92 MediaPlayerImpl::~MediaPlayerImpl() {}
93 93
94 void MediaPlayerImpl::Update() { 94 void MediaPlayerImpl::Update() {
95 // This method is called whenever we might want to take action based on the
96 // current state and recent events. The current state is in |state_|. Recent
97 // events are recorded in |target_state_|, which indicates what state we'd
98 // like to transition to, |target_position_|, which can indicate a position
99 // we'd like to stream to, and |end_of_stream_| which tells us we've reached
100 // end of stream.
101 //
102 // The states are as follows:
103 //
104 // |kWaiting| - Indicates that we've done something asynchronous, and no
105 // further action should be taken by the state machine until that
106 // something completes (at which point the callback will change
107 // the state and call |Update|).
108 // |kFlushed| - Indicates that presentation time is not progressing and that
109 // the pipeline is not primed with packets. This is the initial
110 // state and the state we transition to in preparation for
111 // seeking. A seek is currently only done when when the pipeline
112 // is clear of packets.
113 // |kPrimed| - Indicates that presentation time is not progressing and that
114 // the pipeline is primed with packets. We transition to this
115 // state when the client calls |Pause|, either from |kFlushed| or
116 // |kPlaying| state.
117 // |kPlaying| - Indicates that presentation time is progressing and there are
118 // packets in the pipeline. We transition to this state when the
119 // client calls |Play|. If we're in |kFlushed| when |Play| is
120 // called, we transition through |kPrimed| state.
121 //
122 // The while loop that surrounds all the logic below is there because, after
123 // taking some action and transitioning to a new state, we may want to check
124 // to see if there's more to do in the new state. You'll also notice that
125 // the callback lambdas generally call |Update|.
95 while (true) { 126 while (true) {
96 switch (state_) { 127 switch (state_) {
97 case State::kPaused: 128 case State::kFlushed:
129 // Presentation time is not progressing, and the pipeline is clear of
130 // packets.
98 if (target_position_ != kUnspecifiedTime) { 131 if (target_position_ != kUnspecifiedTime) {
99 WhenPausedAndSeeking(); 132 // We want to seek. Enter |kWaiting| state until the operation is
133 // complete.
134 state_ = State::kWaiting;
135 demux_->Seek(target_position_, [this]() {
136 transform_subject_time_ = target_position_;
137 target_position_ = kUnspecifiedTime;
138 state_ = State::kFlushed;
139 // Back in |kFlushed|. Call |Update| to see if there's further
140 // action to be taken.
141 Update();
142 });
143
144 // Done for now. We're in kWaiting, and the callback will call Update
145 // when the Seek call is complete.
146 return;
147 }
148
149 if (target_state_ == State::kPlaying ||
150 target_state_ == State::kPrimed) {
151 // We want to transition to |kPrimed| or to |kPlaying|, for which
152 // |kPrimed| is a prerequisite. We enter |kWaiting| state, issue the
153 // |Prime| request and transition to |kPrimed| when the operation is
154 // complete.
155 state_ = State::kWaiting;
156 demux_->Prime([this]() {
157 state_ = State::kPrimed;
158 // Now we're in |kPrimed|. Call |Update| to see if there's further
159 // action to be taken.
160 Update();
161 });
162
163 // Done for now. We're in |kWaiting|, and the callback will call
164 // |Update| when the prime is complete.
165 return;
166 }
167
168 // No interesting events to respond to. Done for now.
169 return;
170
171 case State::kPrimed:
172 // Presentation time is not progressing, and the pipeline is primed with
173 // packets.
174 if (target_position_ != kUnspecifiedTime ||
175 target_state_ == State::kFlushed) {
176 // Either we want to seek or just want to transition to |kFlushed|.
177 // We transition to |kWaiting|, issue the |Flush| request and
178 // transition to |kFlushed| when the operation is complete.
179 state_ = State::kWaiting;
180 demux_->Flush([this]() {
181 state_ = State::kFlushed;
182 // Now we're in |kFlushed|. Call |Update| to see if there's further
183 // action to be taken.
184 Update();
185 });
186
187 // Done for now. We're in |kWaiting|, and the callback will call
188 // |Update| when the flush is complete.
189 return;
190 }
191
192 if (target_state_ == State::kPlaying) {
193 // We want to transition to |kPlaying|. Enter |kWaiting|, start the
194 // presentation timeline and transition to |kPlaying| when the
195 // operation completes.
196 state_ = State::kWaiting;
197 timeline_consumer_->SetTimelineTransform(
198 transform_subject_time_, 1, 1,
199 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
200 [this](bool completed) {
201 state_ = State::kPlaying;
202 // Now we're in |kPlaying|. Call |Update| to see if there's
203 // further
204 // action to be taken.
205 Update();
206 });
207
208 transform_subject_time_ = kUnspecifiedTime;
209 return;
210 }
211
212 // No interesting events to respond to. Done for now.
213 return;
214
215 case State::kPlaying:
216 // Presentation time is progressing, and packets are moving through
217 // the pipeline.
218 if (target_position_ != kUnspecifiedTime ||
219 target_state_ == State::kFlushed ||
220 target_state_ == State::kPrimed) {
221 // Either we want to seek or we want to stop playback. In either case,
222 // we need to enter |kWaiting|, stop the presentation timeline and
223 // transition to |kPrimed| when the operation completes.
224 state_ = State::kWaiting;
225 timeline_consumer_->SetTimelineTransform(
226 transform_subject_time_, 1, 0,
227 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
228 [this](bool completed) {
229 state_ = State::kPrimed;
230 // Now we're in |kPrimed|. Call |Update| to see if there's
231 // further
232 // action to be taken.
233 Update();
234 });
235
236 transform_subject_time_ = kUnspecifiedTime;
237 return;
238 }
239
240 if (end_of_stream_) {
241 // We've reached end of stream. The presentation timeline stops by
242 // itself, so we just need to transition to |kPrimed|.
243 target_state_ = State::kPrimed;
244 state_ = State::kPrimed;
245 // Loop around to check if there's more work to do.
100 break; 246 break;
101 } 247 }
102 248
103 if (target_state_ == State::kPlaying) { 249 // No interesting events to respond to. Done for now.
104 if (!flushed_) {
105 SetTimelineTransform(1, 1);
106 state_ = State::kWaiting;
107 break;
108 }
109
110 flushed_ = false;
111 state_ = State::kWaiting;
112 demux_->Prime([this]() {
113 SetTimelineTransform(1, 1);
114 state_ = State::kWaiting;
115 Update();
116 });
117 }
118 return;
119
120 case State::kPlaying:
121 if (target_position_ != kUnspecifiedTime ||
122 target_state_ == State::kPaused) {
123 SetTimelineTransform(1, 0);
124 state_ = State::kWaiting;
125 break;
126 }
127
128 if (end_of_stream_) {
129 target_state_ = State::kPaused;
130 state_ = State::kPaused;
131 break;
132 }
133 return; 250 return;
134 251
135 case State::kWaiting: 252 case State::kWaiting:
253 // Waiting for some async operation. Nothing to do until it completes.
136 return; 254 return;
137 } 255 }
138 } 256 }
139 } 257 }
140 258
141 void MediaPlayerImpl::WhenPausedAndSeeking() {
142 if (!flushed_) {
143 state_ = State::kWaiting;
144 demux_->Flush([this]() {
145 flushed_ = true;
146 WhenFlushedAndSeeking();
147 });
148 } else {
149 WhenFlushedAndSeeking();
150 }
151 }
152
153 void MediaPlayerImpl::WhenFlushedAndSeeking() {
154 state_ = State::kWaiting;
155 DCHECK(target_position_ != kUnspecifiedTime);
156 demux_->Seek(target_position_, [this]() {
157 transform_subject_time_ = target_position_;
158 target_position_ = kUnspecifiedTime;
159 state_ = State::kPaused;
160 Update();
161 });
162 }
163
164 void MediaPlayerImpl::SetTimelineTransform(uint32_t reference_delta,
165 uint32_t subject_delta) {
166 timeline_consumer_->SetTimelineTransform(
167 transform_subject_time_, reference_delta, subject_delta,
168 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime,
169 [this, subject_delta](bool completed) {
170 RCHECK(state_ == State::kWaiting);
171
172 if (subject_delta == 0) {
173 state_ = State::kPaused;
174 } else {
175 state_ = State::kPlaying;
176 }
177
178 Update();
179 });
180 }
181
182 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, 259 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen,
183 const GetStatusCallback& callback) { 260 const GetStatusCallback& callback) {
184 status_publisher_.Get(version_last_seen, callback); 261 status_publisher_.Get(version_last_seen, callback);
185 } 262 }
186 263
187 void MediaPlayerImpl::Play() { 264 void MediaPlayerImpl::Play() {
188 target_state_ = State::kPlaying; 265 target_state_ = State::kPlaying;
189 Update(); 266 Update();
190 } 267 }
191 268
192 void MediaPlayerImpl::Pause() { 269 void MediaPlayerImpl::Pause() {
193 target_state_ = State::kPaused; 270 target_state_ = State::kPrimed;
194 Update(); 271 Update();
195 } 272 }
196 273
197 void MediaPlayerImpl::Seek(int64_t position) { 274 void MediaPlayerImpl::Seek(int64_t position) {
198 target_position_ = position; 275 target_position_ = position;
199 Update(); 276 Update();
200 } 277 }
201 278
202 void MediaPlayerImpl::PrepareStream(Stream* stream, 279 void MediaPlayerImpl::PrepareStream(Stream* stream,
203 size_t index, 280 size_t index,
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 HandleTimelineControlSiteStatusUpdates(version, status.Pass()); 375 HandleTimelineControlSiteStatusUpdates(version, status.Pass());
299 }); 376 });
300 } 377 }
301 378
302 MediaPlayerImpl::Stream::Stream() {} 379 MediaPlayerImpl::Stream::Stream() {}
303 380
304 MediaPlayerImpl::Stream::~Stream() {} 381 MediaPlayerImpl::Stream::~Stream() {}
305 382
306 } // namespace media 383 } // namespace media
307 } // namespace mojo 384 } // namespace mojo
OLDNEW
« 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