| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |