| 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 "services/media/factory_service/media_player_impl.h" | 8 #include "services/media/factory_service/media_player_impl.h" |
| 8 #include "services/media/framework/parts/reader.h" | 9 #include "services/media/framework/parts/reader.h" |
| 9 #include "services/media/framework/util/callback_joiner.h" | 10 #include "services/media/framework/util/callback_joiner.h" |
| 10 | 11 |
| 11 namespace mojo { | 12 namespace mojo { |
| 12 namespace media { | 13 namespace media { |
| 13 | 14 |
| 14 // static | 15 // static |
| 15 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create( | 16 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create( |
| 16 InterfaceHandle<SeekingReader> reader, | 17 InterfaceHandle<SeekingReader> reader, |
| 17 InterfaceRequest<MediaPlayer> request, | 18 InterfaceRequest<MediaPlayer> request, |
| 18 MediaFactoryService* owner) { | 19 MediaFactoryService* owner) { |
| 19 return std::shared_ptr<MediaPlayerImpl>( | 20 return std::shared_ptr<MediaPlayerImpl>( |
| 20 new MediaPlayerImpl(reader.Pass(), request.Pass(), owner)); | 21 new MediaPlayerImpl(reader.Pass(), request.Pass(), owner)); |
| 21 } | 22 } |
| 22 | 23 |
| 23 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader, | 24 MediaPlayerImpl::MediaPlayerImpl(InterfaceHandle<SeekingReader> reader, |
| 24 InterfaceRequest<MediaPlayer> request, | 25 InterfaceRequest<MediaPlayer> request, |
| 25 MediaFactoryService* owner) | 26 MediaFactoryService* owner) |
| 26 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) { | 27 : MediaFactoryService::Product<MediaPlayer>(this, request.Pass(), owner) { |
| 27 DCHECK(reader); | 28 DCHECK(reader); |
| 28 | 29 |
| 29 status_publisher_.SetCallbackRunner( | 30 status_publisher_.SetCallbackRunner([this](const GetStatusCallback& callback, |
| 30 [this](const GetStatusCallback& callback, uint64_t version) { | 31 uint64_t version) { |
| 31 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); | 32 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); |
| 32 status->state = reported_media_state_; | 33 status->timeline_transform = TimelineTransform::From(timeline_function_); |
| 33 status->timeline_transform = transform_.Clone(); | 34 status->end_of_stream = AllSinksAtEndOfStream(); |
| 34 status->metadata = metadata_.Clone(); | 35 status->metadata = metadata_.Clone(); |
| 35 callback.Run(version, status.Pass()); | 36 callback.Run(version, status.Pass()); |
| 36 }); | 37 }); |
| 37 | 38 |
| 38 state_ = State::kWaiting; | 39 state_ = State::kWaiting; |
| 39 | 40 |
| 40 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_)); | 41 ConnectToService(app()->shell(), "mojo:media_factory", GetProxy(&factory_)); |
| 41 | 42 |
| 42 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_)); | 43 factory_->CreateDemux(reader.Pass(), GetProxy(&demux_)); |
| 43 | 44 |
| 44 HandleDemuxMetadataUpdates(); | 45 HandleDemuxMetadataUpdates(); |
| 45 | 46 |
| 46 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) { | 47 demux_->Describe([this](mojo::Array<MediaTypePtr> stream_types) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 64 break; | 65 break; |
| 65 // TODO(dalesat): Enable other stream types. | 66 // TODO(dalesat): Enable other stream types. |
| 66 default: | 67 default: |
| 67 break; | 68 break; |
| 68 } | 69 } |
| 69 } | 70 } |
| 70 | 71 |
| 71 callback_joiner->WhenJoined([this]() { | 72 callback_joiner->WhenJoined([this]() { |
| 72 // The enabled streams are prepared. | 73 // The enabled streams are prepared. |
| 73 factory_.reset(); | 74 factory_.reset(); |
| 74 SetReportedMediaState(MediaState::PAUSED); | |
| 75 state_ = State::kPaused; | 75 state_ = State::kPaused; |
| 76 Update(); | 76 Update(); |
| 77 }); | 77 }); |
| 78 }); | 78 }); |
| 79 } | 79 } |
| 80 | 80 |
| 81 MediaPlayerImpl::~MediaPlayerImpl() {} | 81 MediaPlayerImpl::~MediaPlayerImpl() {} |
| 82 | 82 |
| 83 void MediaPlayerImpl::Update() { | 83 void MediaPlayerImpl::Update() { |
| 84 while (true) { | 84 while (true) { |
| 85 switch (state_) { | 85 switch (state_) { |
| 86 case State::kPaused: | 86 case State::kPaused: |
| 87 if (target_position_ != kNotSeeking) { | 87 if (target_position_ != kUnspecifiedTime) { |
| 88 WhenPausedAndSeeking(); | 88 WhenPausedAndSeeking(); |
| 89 break; | 89 break; |
| 90 } | 90 } |
| 91 | 91 |
| 92 if (target_state_ == MediaState::PLAYING) { | 92 if (target_state_ == State::kPlaying) { |
| 93 if (!flushed_) { | 93 if (!flushed_) { |
| 94 ChangeSinkStates(MediaState::PLAYING); | 94 SetSinkTimelineTransforms(1, 1); |
| 95 state_ = State::kWaitingForSinksToPlay; | 95 state_ = State::kWaiting; |
| 96 break; | 96 break; |
| 97 } | 97 } |
| 98 | 98 |
| 99 flushed_ = false; | 99 flushed_ = false; |
| 100 state_ = State::kWaiting; | 100 state_ = State::kWaiting; |
| 101 demux_->Prime([this]() { | 101 demux_->Prime([this]() { |
| 102 ChangeSinkStates(MediaState::PLAYING); | 102 SetSinkTimelineTransforms(1, 1); |
| 103 state_ = State::kWaitingForSinksToPlay; | 103 state_ = State::kWaiting; |
| 104 Update(); | 104 Update(); |
| 105 }); | 105 }); |
| 106 } | 106 } |
| 107 return; | 107 return; |
| 108 | 108 |
| 109 case State::kWaitingForSinksToPlay: | |
| 110 if (AllSinksAre(SinkState::kPlayingOrEnded)) { | |
| 111 state_ = State::kPlaying; | |
| 112 if (target_state_ == MediaState::PLAYING) { | |
| 113 SetReportedMediaState(MediaState::PLAYING); | |
| 114 } | |
| 115 } | |
| 116 return; | |
| 117 | |
| 118 case State::kPlaying: | 109 case State::kPlaying: |
| 119 if (target_position_ != kNotSeeking || | 110 if (target_position_ != kUnspecifiedTime || |
| 120 target_state_ == MediaState::PAUSED) { | 111 target_state_ == State::kPaused) { |
| 121 ChangeSinkStates(MediaState::PAUSED); | 112 SetSinkTimelineTransforms(1, 0); |
| 122 state_ = State::kWaitingForSinksToPause; | 113 state_ = State::kWaiting; |
| 123 break; | 114 break; |
| 124 } | 115 } |
| 125 | 116 |
| 126 if (AllSinksAre(SinkState::kEnded)) { | 117 if (AllSinksAtEndOfStream()) { |
| 127 target_state_ = MediaState::ENDED; | 118 target_state_ = State::kPaused; |
| 128 SetReportedMediaState(MediaState::ENDED); | |
| 129 state_ = State::kPaused; | 119 state_ = State::kPaused; |
| 130 break; | 120 break; |
| 131 } | 121 } |
| 132 return; | |
| 133 | |
| 134 case State::kWaitingForSinksToPause: | |
| 135 if (AllSinksAre(SinkState::kPausedOrEnded)) { | |
| 136 if (target_state_ == MediaState::PAUSED) { | |
| 137 if (AllSinksAre(SinkState::kEnded)) { | |
| 138 SetReportedMediaState(MediaState::ENDED); | |
| 139 } else { | |
| 140 SetReportedMediaState(MediaState::PAUSED); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 state_ = State::kPaused; | |
| 145 break; | |
| 146 } | |
| 147 return; | 122 return; |
| 148 | 123 |
| 149 case State::kWaiting: | 124 case State::kWaiting: |
| 150 return; | 125 return; |
| 151 } | 126 } |
| 152 } | 127 } |
| 153 } | 128 } |
| 154 | 129 |
| 155 void MediaPlayerImpl::WhenPausedAndSeeking() { | 130 void MediaPlayerImpl::WhenPausedAndSeeking() { |
| 156 if (!flushed_) { | 131 if (!flushed_) { |
| 157 state_ = State::kWaiting; | 132 state_ = State::kWaiting; |
| 158 demux_->Flush([this]() { | 133 demux_->Flush([this]() { |
| 159 flushed_ = true; | 134 flushed_ = true; |
| 160 WhenFlushedAndSeeking(); | 135 WhenFlushedAndSeeking(); |
| 161 }); | 136 }); |
| 162 } else { | 137 } else { |
| 163 WhenFlushedAndSeeking(); | 138 WhenFlushedAndSeeking(); |
| 164 } | 139 } |
| 165 } | 140 } |
| 166 | 141 |
| 167 void MediaPlayerImpl::WhenFlushedAndSeeking() { | 142 void MediaPlayerImpl::WhenFlushedAndSeeking() { |
| 168 state_ = State::kWaiting; | 143 state_ = State::kWaiting; |
| 169 DCHECK(target_position_ != kNotSeeking); | 144 DCHECK(target_position_ != kUnspecifiedTime); |
| 170 demux_->Seek(target_position_, [this]() { | 145 demux_->Seek(target_position_, [this]() { |
| 171 target_position_ = kNotSeeking; | 146 transform_subject_time_ = target_position_; |
| 147 target_position_ = kUnspecifiedTime; |
| 172 state_ = State::kPaused; | 148 state_ = State::kPaused; |
| 173 Update(); | 149 Update(); |
| 174 }); | 150 }); |
| 175 } | 151 } |
| 176 | 152 |
| 177 void MediaPlayerImpl::ChangeSinkStates(MediaState media_state) { | 153 void MediaPlayerImpl::SetSinkTimelineTransforms(uint32_t reference_delta, |
| 154 uint32_t subject_delta) { |
| 155 SetSinkTimelineTransforms( |
| 156 transform_subject_time_, reference_delta, subject_delta, |
| 157 Timeline::local_now() + kMinimumLeadTime, kUnspecifiedTime); |
| 158 } |
| 159 |
| 160 void MediaPlayerImpl::SetSinkTimelineTransforms( |
| 161 int64_t subject_time, |
| 162 uint32_t reference_delta, |
| 163 uint32_t subject_delta, |
| 164 int64_t effective_reference_time, |
| 165 int64_t effective_subject_time) { |
| 166 std::shared_ptr<CallbackJoiner> callback_joiner = CallbackJoiner::Create(); |
| 167 |
| 178 for (auto& stream : streams_) { | 168 for (auto& stream : streams_) { |
| 179 if (stream->enabled_) { | 169 if (stream->enabled_) { |
| 180 if (media_state == MediaState::PAUSED) { | 170 DCHECK(stream->timeline_consumer_); |
| 181 stream->sink_->Pause(); | 171 callback_joiner->Spawn(); |
| 182 } else { | 172 stream->timeline_consumer_->SetTimelineTransform( |
| 183 stream->sink_->Play(); | 173 subject_time, reference_delta, subject_delta, |
| 184 } | 174 effective_reference_time, effective_subject_time, |
| 175 [this, callback_joiner](bool completed) { |
| 176 callback_joiner->Complete(); |
| 177 }); |
| 185 } | 178 } |
| 186 } | 179 } |
| 180 |
| 181 transform_subject_time_ = kUnspecifiedTime; |
| 182 |
| 183 callback_joiner->WhenJoined([this, subject_delta]() { |
| 184 RCHECK(state_ == State::kWaiting); |
| 185 |
| 186 if (subject_delta == 0) { |
| 187 state_ = State::kPaused; |
| 188 } else { |
| 189 state_ = State::kPlaying; |
| 190 } |
| 191 |
| 192 Update(); |
| 193 }); |
| 187 } | 194 } |
| 188 | 195 |
| 189 bool MediaPlayerImpl::AllSinksAre(SinkState sink_state) { | 196 bool MediaPlayerImpl::AllSinksAtEndOfStream() { |
| 197 int result = false; |
| 198 |
| 190 for (auto& stream : streams_) { | 199 for (auto& stream : streams_) { |
| 191 if (stream->enabled_) { | 200 if (stream->enabled_) { |
| 192 switch (sink_state) { | 201 result = stream->end_of_stream_; |
| 193 case SinkState::kPaused: | 202 if (!result) { |
| 194 if (stream->state_ != MediaState::PAUSED) { | 203 break; |
| 195 return false; | |
| 196 } | |
| 197 break; | |
| 198 case SinkState::kPlaying: | |
| 199 if (stream->state_ != MediaState::PLAYING) { | |
| 200 return false; | |
| 201 } | |
| 202 break; | |
| 203 case SinkState::kEnded: | |
| 204 if (stream->state_ != MediaState::ENDED) { | |
| 205 return false; | |
| 206 } | |
| 207 break; | |
| 208 case SinkState::kPausedOrEnded: | |
| 209 if (stream->state_ != MediaState::PAUSED && | |
| 210 stream->state_ != MediaState::ENDED) { | |
| 211 return false; | |
| 212 } | |
| 213 break; | |
| 214 case SinkState::kPlayingOrEnded: | |
| 215 if (stream->state_ != MediaState::PLAYING && | |
| 216 stream->state_ != MediaState::ENDED) { | |
| 217 return false; | |
| 218 } | |
| 219 break; | |
| 220 } | 204 } |
| 221 } | 205 } |
| 222 } | 206 } |
| 223 | 207 |
| 224 return true; | 208 return result; |
| 225 } | |
| 226 | |
| 227 void MediaPlayerImpl::SetReportedMediaState(MediaState media_state) { | |
| 228 if (reported_media_state_ != media_state) { | |
| 229 reported_media_state_ = media_state; | |
| 230 status_publisher_.SendUpdates(); | |
| 231 } | |
| 232 } | 209 } |
| 233 | 210 |
| 234 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, | 211 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, |
| 235 const GetStatusCallback& callback) { | 212 const GetStatusCallback& callback) { |
| 236 status_publisher_.Get(version_last_seen, callback); | 213 status_publisher_.Get(version_last_seen, callback); |
| 237 } | 214 } |
| 238 | 215 |
| 239 void MediaPlayerImpl::Play() { | 216 void MediaPlayerImpl::Play() { |
| 240 target_state_ = MediaState::PLAYING; | 217 target_state_ = State::kPlaying; |
| 241 Update(); | 218 Update(); |
| 242 } | 219 } |
| 243 | 220 |
| 244 void MediaPlayerImpl::Pause() { | 221 void MediaPlayerImpl::Pause() { |
| 245 target_state_ = MediaState::PAUSED; | 222 target_state_ = State::kPaused; |
| 246 Update(); | 223 Update(); |
| 247 } | 224 } |
| 248 | 225 |
| 249 void MediaPlayerImpl::Seek(int64_t position) { | 226 void MediaPlayerImpl::Seek(int64_t position) { |
| 250 target_position_ = position; | 227 target_position_ = position; |
| 251 Update(); | 228 Update(); |
| 252 } | 229 } |
| 253 | 230 |
| 254 void MediaPlayerImpl::PrepareStream(Stream* stream, | 231 void MediaPlayerImpl::PrepareStream(Stream* stream, |
| 255 const String& url, | 232 const String& url, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 297 | 274 |
| 298 void MediaPlayerImpl::CreateSink(Stream* stream, | 275 void MediaPlayerImpl::CreateSink(Stream* stream, |
| 299 const MediaTypePtr& input_media_type, | 276 const MediaTypePtr& input_media_type, |
| 300 const String& url, | 277 const String& url, |
| 301 const std::function<void()>& callback) { | 278 const std::function<void()>& callback) { |
| 302 DCHECK(input_media_type); | 279 DCHECK(input_media_type); |
| 303 DCHECK(stream->decoded_producer_); | 280 DCHECK(stream->decoded_producer_); |
| 304 DCHECK(factory_); | 281 DCHECK(factory_); |
| 305 | 282 |
| 306 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_)); | 283 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_)); |
| 284 stream->sink_->GetTimelineControlSite( |
| 285 GetProxy(&stream->timeline_control_site_)); |
| 286 |
| 287 HandleTimelineControlSiteStatusUpdates(stream); |
| 288 |
| 289 stream->timeline_control_site_->GetTimelineConsumer( |
| 290 GetProxy(&stream->timeline_consumer_)); |
| 307 | 291 |
| 308 MediaConsumerPtr consumer; | 292 MediaConsumerPtr consumer; |
| 309 stream->sink_->GetConsumer(GetProxy(&consumer)); | 293 stream->sink_->GetConsumer(GetProxy(&consumer)); |
| 310 | 294 |
| 311 stream->decoded_producer_->Connect( | 295 stream->decoded_producer_->Connect(consumer.Pass(), |
| 312 consumer.Pass(), [this, callback, stream]() { | 296 [this, callback, stream]() { |
| 313 stream->decoded_producer_.reset(); | 297 stream->decoded_producer_.reset(); |
| 314 | 298 callback(); |
| 315 DCHECK(stream->state_ == MediaState::UNPREPARED); | 299 }); |
| 316 DCHECK(reported_media_state_ == MediaState::UNPREPARED || | |
| 317 reported_media_state_ == MediaState::FAULT); | |
| 318 | |
| 319 stream->state_ = MediaState::PAUSED; | |
| 320 | |
| 321 HandleSinkStatusUpdates(stream); | |
| 322 | |
| 323 callback(); | |
| 324 }); | |
| 325 } | 300 } |
| 326 | 301 |
| 327 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version, | 302 void MediaPlayerImpl::HandleDemuxMetadataUpdates(uint64_t version, |
| 328 MediaMetadataPtr metadata) { | 303 MediaMetadataPtr metadata) { |
| 329 if (metadata) { | 304 if (metadata) { |
| 330 metadata_ = metadata.Pass(); | 305 metadata_ = metadata.Pass(); |
| 331 status_publisher_.SendUpdates(); | 306 status_publisher_.SendUpdates(); |
| 332 } | 307 } |
| 333 | 308 |
| 334 demux_->GetMetadata(version, | 309 demux_->GetMetadata(version, |
| 335 [this](uint64_t version, MediaMetadataPtr metadata) { | 310 [this](uint64_t version, MediaMetadataPtr metadata) { |
| 336 HandleDemuxMetadataUpdates(version, metadata.Pass()); | 311 HandleDemuxMetadataUpdates(version, metadata.Pass()); |
| 337 }); | 312 }); |
| 338 } | 313 } |
| 339 | 314 |
| 340 void MediaPlayerImpl::HandleSinkStatusUpdates(Stream* stream, | 315 void MediaPlayerImpl::HandleTimelineControlSiteStatusUpdates( |
| 341 uint64_t version, | 316 Stream* stream, |
| 342 MediaSinkStatusPtr status) { | 317 uint64_t version, |
| 343 if (status && status->state > MediaState::UNPREPARED) { | 318 MediaTimelineControlSiteStatusPtr status) { |
| 344 // We transition to PAUSED when Connect completes. | 319 if (status) { |
| 345 DCHECK(stream->state_ > MediaState::UNPREPARED); | 320 // TODO(dalesat): Why does one sink determine timeline_function_? |
| 346 stream->state_ = status->state; | 321 timeline_function_ = status->timeline_transform.To<TimelineFunction>(); |
| 347 transform_ = status->timeline_transform.Pass(); | 322 stream->end_of_stream_ = status->end_of_stream; |
| 348 status_publisher_.SendUpdates(); | 323 status_publisher_.SendUpdates(); |
| 349 Update(); | 324 Update(); |
| 350 } | 325 } |
| 351 | 326 |
| 352 stream->sink_->GetStatus( | 327 stream->timeline_control_site_->GetStatus( |
| 353 version, [this, stream](uint64_t version, MediaSinkStatusPtr status) { | 328 version, [this, stream](uint64_t version, |
| 354 HandleSinkStatusUpdates(stream, version, status.Pass()); | 329 MediaTimelineControlSiteStatusPtr status) { |
| 330 HandleTimelineControlSiteStatusUpdates(stream, version, status.Pass()); |
| 355 }); | 331 }); |
| 356 } | 332 } |
| 357 | 333 |
| 358 MediaPlayerImpl::Stream::Stream(size_t index, MediaTypePtr media_type) | 334 MediaPlayerImpl::Stream::Stream(size_t index, MediaTypePtr media_type) |
| 359 : index_(index), media_type_(media_type.Pass()) {} | 335 : index_(index), media_type_(media_type.Pass()) {} |
| 360 | 336 |
| 361 MediaPlayerImpl::Stream::~Stream() {} | 337 MediaPlayerImpl::Stream::~Stream() {} |
| 362 | 338 |
| 363 } // namespace media | 339 } // namespace media |
| 364 } // namespace mojo | 340 } // namespace mojo |
| OLD | NEW |