| 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 "services/media/factory_service/media_player_impl.h" | 6 #include "services/media/factory_service/media_player_impl.h" |
| 7 #include "services/media/factory_service/watched.h" | 7 #include "services/media/factory_service/watched.h" |
| 8 #include "services/media/framework/parts/reader.h" | 8 #include "services/media/framework/parts/reader.h" |
| 9 #include "url/gurl.h" | 9 #include "url/gurl.h" |
| 10 | 10 |
| 11 namespace mojo { | 11 namespace mojo { |
| 12 namespace media { | 12 namespace media { |
| 13 | 13 |
| 14 // static | 14 // static |
| 15 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create( | 15 std::shared_ptr<MediaPlayerImpl> MediaPlayerImpl::Create( |
| 16 const String& origin_url, | 16 const String& origin_url, |
| 17 InterfaceRequest<MediaPlayer> request, | 17 InterfaceRequest<MediaPlayer> request, |
| 18 MediaFactoryService* owner) { | 18 MediaFactoryService* owner) { |
| 19 return std::shared_ptr<MediaPlayerImpl>( | 19 return std::shared_ptr<MediaPlayerImpl>( |
| 20 new MediaPlayerImpl(origin_url, request.Pass(), owner)); | 20 new MediaPlayerImpl(origin_url, request.Pass(), owner)); |
| 21 } | 21 } |
| 22 | 22 |
| 23 MediaPlayerImpl::MediaPlayerImpl( | 23 MediaPlayerImpl::MediaPlayerImpl(const String& origin_url, |
| 24 const String& origin_url, | 24 InterfaceRequest<MediaPlayer> request, |
| 25 InterfaceRequest<MediaPlayer> request, | 25 MediaFactoryService* owner) |
| 26 MediaFactoryService* owner) | 26 : MediaFactoryService::Product(owner), binding_(this, request.Pass()) { |
| 27 : MediaFactoryService::Product(owner), | |
| 28 binding_(this, request.Pass()) { | |
| 29 DCHECK(origin_url); | 27 DCHECK(origin_url); |
| 30 | 28 |
| 31 target_state_.SetWithConsequences(MediaState::PAUSED); | 29 target_state_.SetWithConsequences(MediaState::PAUSED); |
| 32 target_position_.SetWithConsequences(kNotSeeking); | 30 target_position_.SetWithConsequences(kNotSeeking); |
| 33 | 31 |
| 34 // Go away when the client is no longer connected. | 32 // Go away when the client is no longer connected. |
| 35 binding_.set_connection_error_handler([this]() { | 33 binding_.set_connection_error_handler([this]() { ReleaseFromOwner(); }); |
| 36 ReleaseFromOwner(); | |
| 37 }); | |
| 38 | 34 |
| 39 app()->ConnectToService("mojo:media_factory", &factory_); | 35 app()->ConnectToService("mojo:media_factory", &factory_); |
| 40 | 36 |
| 41 factory_->CreateSource( | 37 factory_->CreateSource(origin_url, |
| 42 origin_url, | 38 nullptr, // allowed_media_types |
| 43 nullptr, // allowed_media_types | 39 GetProxy(&source_)); |
| 44 GetProxy(&source_)); | |
| 45 | 40 |
| 46 HandleSourceStatusUpdates(); | 41 HandleSourceStatusUpdates(); |
| 47 | 42 |
| 48 source_->GetStreams( | 43 source_->GetStreams( |
| 49 [this](mojo::Array<MediaSourceStreamDescriptorPtr> descriptors) { | 44 [this](mojo::Array<MediaSourceStreamDescriptorPtr> descriptors) { |
| 50 // Populate streams_ and enable the streams we want. | 45 // Populate streams_ and enable the streams we want. |
| 51 std::vector<Event> stream_prepared_events; | 46 std::vector<Event> stream_prepared_events; |
| 52 | 47 |
| 53 for (MediaSourceStreamDescriptorPtr& descriptor : descriptors) { | 48 for (MediaSourceStreamDescriptorPtr& descriptor : descriptors) { |
| 54 streams_.push_back(std::unique_ptr<Stream>(new Stream())); | 49 streams_.push_back(std::unique_ptr<Stream>(new Stream())); |
| 55 Stream& stream = *streams_.back(); | 50 Stream& stream = *streams_.back(); |
| 56 stream.descriptor_ = descriptor.Pass(); | 51 stream.descriptor_ = descriptor.Pass(); |
| 57 switch (stream.descriptor_->media_type->scheme) { | 52 switch (stream.descriptor_->media_type->scheme) { |
| 58 case MediaTypeScheme::COMPRESSED_AUDIO: | 53 case MediaTypeScheme::COMPRESSED_AUDIO: |
| 59 case MediaTypeScheme::LPCM: | 54 case MediaTypeScheme::LPCM: |
| 60 stream.enabled_ = true; | 55 stream.enabled_ = true; |
| 61 stream_prepared_events.push_back( | 56 stream_prepared_events.push_back( |
| 62 PrepareStream(streams_.back(), "mojo:audio_server")); | 57 PrepareStream(streams_.back(), "mojo:audio_server")); |
| 63 break; | 58 break; |
| 64 // TODO(dalesat): Enable other stream types. | 59 // TODO(dalesat): Enable other stream types. |
| 65 default: | 60 default: |
| 66 break; | 61 break; |
| 67 } | 62 } |
| 68 } | 63 } |
| 69 | 64 |
| 70 event_ = Event::All(stream_prepared_events).When([this]() { | 65 event_ = Event::All(stream_prepared_events).When([this]() { |
| 71 // The enabled streams are prepared. Prepare the source. | 66 // The enabled streams are prepared. Prepare the source. |
| 72 factory_.reset(); | 67 factory_.reset(); |
| 73 source_->Prepare([this]() { | 68 source_->Prepare([this]() { |
| 74 SetReportedMediaState(MediaState::PAUSED); | 69 SetReportedMediaState(MediaState::PAUSED); |
| 75 WhenPaused(); | 70 WhenPaused(); |
| 71 }); |
| 72 }); |
| 76 }); | 73 }); |
| 77 }); | |
| 78 }); | |
| 79 } | 74 } |
| 80 | 75 |
| 81 MediaPlayerImpl::~MediaPlayerImpl() { | 76 MediaPlayerImpl::~MediaPlayerImpl() { |
| 82 event_.Cancel(); | 77 event_.Cancel(); |
| 83 } | 78 } |
| 84 | 79 |
| 85 void MediaPlayerImpl::WhenPaused() { | 80 void MediaPlayerImpl::WhenPaused() { |
| 86 Event seek_requested = target_position_.BecomesOtherThan(kNotSeeking); | 81 Event seek_requested = target_position_.BecomesOtherThan(kNotSeeking); |
| 87 Event play_requested = target_state_.Becomes(MediaState::PLAYING); | 82 Event play_requested = target_state_.Becomes(MediaState::PLAYING); |
| 88 | 83 |
| 89 event_ = Event::First({ seek_requested, play_requested }); | 84 event_ = Event::First({seek_requested, play_requested}); |
| 90 | 85 |
| 91 seek_requested.When([this]() { | 86 seek_requested.When([this]() { WhenPausedAndSeeking(); }); |
| 92 WhenPausedAndSeeking(); | |
| 93 }); | |
| 94 | 87 |
| 95 play_requested.When([this]() { | 88 play_requested.When([this]() { |
| 96 flushed_ = false; | 89 flushed_ = false; |
| 97 | 90 |
| 98 source_->Prime([this]() { | 91 source_->Prime([this]() { |
| 99 event_ = ChangeSinkStates(MediaState::PLAYING).When([this]() { | 92 event_ = ChangeSinkStates(MediaState::PLAYING).When([this]() { |
| 100 WhenPlaying(); | 93 WhenPlaying(); |
| 101 }); | 94 }); |
| 102 }); | 95 }); |
| 103 }); | 96 }); |
| 104 } | 97 } |
| 105 | 98 |
| 106 void MediaPlayerImpl::WhenPlaying() { | 99 void MediaPlayerImpl::WhenPlaying() { |
| 107 SetReportedMediaState(MediaState::PLAYING); | 100 SetReportedMediaState(MediaState::PLAYING); |
| 108 | 101 |
| 109 Event seek_requested = target_position_.BecomesOtherThan(kNotSeeking); | 102 Event seek_requested = target_position_.BecomesOtherThan(kNotSeeking); |
| 110 Event pause_requested = target_state_.Becomes(MediaState::PAUSED); | 103 Event pause_requested = target_state_.Becomes(MediaState::PAUSED); |
| 111 Event sinks_ended = AllSinkStatesBecome(MediaState::ENDED); | 104 Event sinks_ended = AllSinkStatesBecome(MediaState::ENDED); |
| 112 | 105 |
| 113 event_ = Event::First({ seek_requested, pause_requested, sinks_ended }); | 106 event_ = Event::First({seek_requested, pause_requested, sinks_ended}); |
| 114 | 107 |
| 115 seek_requested.When([this]() { | 108 seek_requested.When([this]() { |
| 116 event_ = ChangeSinkStates(MediaState::PAUSED).When([this]() { | 109 event_ = ChangeSinkStates(MediaState::PAUSED).When([this]() { |
| 117 WhenPausedAndSeeking(); | 110 WhenPausedAndSeeking(); |
| 118 }); | 111 }); |
| 119 }); | 112 }); |
| 120 | 113 |
| 121 pause_requested.When([this]() { | 114 pause_requested.When([this]() { |
| 122 event_ = ChangeSinkStates(MediaState::PAUSED).When([this]() { | 115 event_ = ChangeSinkStates(MediaState::PAUSED).When([this]() { |
| 123 SetReportedMediaState(MediaState::PAUSED); | 116 SetReportedMediaState(MediaState::PAUSED); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 176 return Event::All(precursors); | 169 return Event::All(precursors); |
| 177 } | 170 } |
| 178 | 171 |
| 179 void MediaPlayerImpl::SetReportedMediaState(MediaState media_state) { | 172 void MediaPlayerImpl::SetReportedMediaState(MediaState media_state) { |
| 180 if (reported_media_state_ != media_state) { | 173 if (reported_media_state_ != media_state) { |
| 181 reported_media_state_ = media_state; | 174 reported_media_state_ = media_state; |
| 182 StatusUpdated(); | 175 StatusUpdated(); |
| 183 } | 176 } |
| 184 } | 177 } |
| 185 | 178 |
| 186 void MediaPlayerImpl::GetStatus( | 179 void MediaPlayerImpl::GetStatus(uint64_t version_last_seen, |
| 187 uint64_t version_last_seen, | 180 const GetStatusCallback& callback) { |
| 188 const GetStatusCallback& callback) { | |
| 189 if (version_last_seen < status_version_) { | 181 if (version_last_seen < status_version_) { |
| 190 RunStatusCallback(callback); | 182 RunStatusCallback(callback); |
| 191 } else { | 183 } else { |
| 192 pending_status_requests_.push_back(callback); | 184 pending_status_requests_.push_back(callback); |
| 193 } | 185 } |
| 194 } | 186 } |
| 195 | 187 |
| 196 void MediaPlayerImpl::Play() { | 188 void MediaPlayerImpl::Play() { |
| 197 target_state_.SetWithConsequences(MediaState::PLAYING); | 189 target_state_.SetWithConsequences(MediaState::PLAYING); |
| 198 } | 190 } |
| 199 | 191 |
| 200 void MediaPlayerImpl::Pause() { | 192 void MediaPlayerImpl::Pause() { |
| 201 target_state_.SetWithConsequences(MediaState::PAUSED); | 193 target_state_.SetWithConsequences(MediaState::PAUSED); |
| 202 } | 194 } |
| 203 | 195 |
| 204 void MediaPlayerImpl::Seek(int64_t position) { | 196 void MediaPlayerImpl::Seek(int64_t position) { |
| 205 DCHECK(position != kNotSeeking); | 197 DCHECK(position != kNotSeeking); |
| 206 target_position_.SetWithConsequences(position); | 198 target_position_.SetWithConsequences(position); |
| 207 } | 199 } |
| 208 | 200 |
| 209 Event MediaPlayerImpl::PrepareStream( | 201 Event MediaPlayerImpl::PrepareStream(const std::unique_ptr<Stream>& stream, |
| 210 const std::unique_ptr<Stream>& stream, | 202 const String& url) { |
| 211 const String& url) { | |
| 212 DCHECK(factory_); | 203 DCHECK(factory_); |
| 213 | 204 |
| 214 Event event = Event::Create(); | 205 Event event = Event::Create(); |
| 215 | 206 |
| 216 source_->GetProducer( | 207 source_->GetProducer(stream->descriptor_->index, |
| 217 stream->descriptor_->index, | 208 GetProxy(&stream->encoded_producer_)); |
| 218 GetProxy(&stream->encoded_producer_)); | |
| 219 | 209 |
| 220 if (stream->descriptor_->media_type->scheme == | 210 if (stream->descriptor_->media_type->scheme == |
| 221 MediaTypeScheme::COMPRESSED_AUDIO) { | 211 MediaTypeScheme::COMPRESSED_AUDIO) { |
| 222 // Compressed audio. Insert a decoder in front of the sink. The sink would | 212 // Compressed audio. Insert a decoder in front of the sink. The sink would |
| 223 // add its own internal decoder, but we want to test the decoder. | 213 // add its own internal decoder, but we want to test the decoder. |
| 224 factory_->CreateDecoder( | 214 factory_->CreateDecoder(stream->descriptor_->media_type.Clone(), |
| 225 stream->descriptor_->media_type.Clone(), | 215 GetProxy(&stream->decoder_)); |
| 226 GetProxy(&stream->decoder_)); | |
| 227 | 216 |
| 228 MediaConsumerPtr decoder_consumer; | 217 MediaConsumerPtr decoder_consumer; |
| 229 stream->decoder_->GetConsumer(GetProxy(&decoder_consumer)); | 218 stream->decoder_->GetConsumer(GetProxy(&decoder_consumer)); |
| 230 | 219 |
| 231 Event connect_complete = Event::Create(); | 220 Event connect_complete = Event::Create(); |
| 232 stream->encoded_producer_->Connect( | 221 stream->encoded_producer_->Connect(decoder_consumer.Pass(), |
| 233 decoder_consumer.Pass(), | 222 [&stream, connect_complete]() { |
| 234 [&stream, connect_complete]() { | 223 stream->encoded_producer_.reset(); |
| 235 stream->encoded_producer_.reset(); | 224 connect_complete.Occur(); |
| 236 connect_complete.Occur(); | 225 }); |
| 237 }); | |
| 238 | 226 |
| 239 stream->decoder_->GetOutputType( | 227 stream->decoder_->GetOutputType( |
| 240 [this, &stream, url, event](MediaTypePtr output_type) { | 228 [this, &stream, url, event](MediaTypePtr output_type) { |
| 241 stream->decoder_->GetProducer(GetProxy(&stream->decoded_producer_)); | 229 stream->decoder_->GetProducer(GetProxy(&stream->decoded_producer_)); |
| 242 | 230 |
| 243 CreateSink( | 231 CreateSink(stream, output_type, url, event); |
| 244 stream, | |
| 245 output_type, | |
| 246 url, | |
| 247 event); | |
| 248 }); | 232 }); |
| 249 | 233 |
| 250 return Event::All({ connect_complete, event }); | 234 return Event::All({connect_complete, event}); |
| 251 } else { | 235 } else { |
| 252 // Uncompressed audio. Connect the source stream directly to the sink. This | 236 // Uncompressed audio. Connect the source stream directly to the sink. This |
| 253 // would work for compressed audio as well (the sink would decode), but we | 237 // would work for compressed audio as well (the sink would decode), but we |
| 254 // want to test the decoder. | 238 // want to test the decoder. |
| 255 DCHECK(stream->descriptor_->media_type->scheme == MediaTypeScheme::LPCM); | 239 DCHECK(stream->descriptor_->media_type->scheme == MediaTypeScheme::LPCM); |
| 256 stream->decoded_producer_ = stream->encoded_producer_.Pass(); | 240 stream->decoded_producer_ = stream->encoded_producer_.Pass(); |
| 257 CreateSink( | 241 CreateSink(stream, stream->descriptor_->media_type, url, event); |
| 258 stream, | |
| 259 stream->descriptor_->media_type, | |
| 260 url, | |
| 261 event); | |
| 262 return event; | 242 return event; |
| 263 } | 243 } |
| 264 } | 244 } |
| 265 | 245 |
| 266 void MediaPlayerImpl::CreateSink( | 246 void MediaPlayerImpl::CreateSink(const std::unique_ptr<Stream>& stream, |
| 267 const std::unique_ptr<Stream>& stream, | 247 const MediaTypePtr& input_media_type, |
| 268 const MediaTypePtr& input_media_type, | 248 const String& url, |
| 269 const String& url, | 249 Event event) { |
| 270 Event event) { | |
| 271 DCHECK(input_media_type); | 250 DCHECK(input_media_type); |
| 272 DCHECK(stream->decoded_producer_); | 251 DCHECK(stream->decoded_producer_); |
| 273 DCHECK(factory_); | 252 DCHECK(factory_); |
| 274 | 253 |
| 275 factory_->CreateSink( | 254 factory_->CreateSink(url, input_media_type.Clone(), GetProxy(&stream->sink_)); |
| 276 url, | |
| 277 input_media_type.Clone(), | |
| 278 GetProxy(&stream->sink_)); | |
| 279 | 255 |
| 280 MediaConsumerPtr consumer; | 256 MediaConsumerPtr consumer; |
| 281 stream->sink_->GetConsumer(GetProxy(&consumer)); | 257 stream->sink_->GetConsumer(GetProxy(&consumer)); |
| 282 | 258 |
| 283 stream->decoded_producer_->Connect( | 259 stream->decoded_producer_->Connect(consumer.Pass(), [this, event, &stream]() { |
| 284 consumer.Pass(), | 260 stream->decoded_producer_.reset(); |
| 285 [this, event, &stream]() { | |
| 286 stream->decoded_producer_.reset(); | |
| 287 | 261 |
| 288 DCHECK(stream->state_ == MediaState::UNPREPARED); | 262 DCHECK(stream->state_ == MediaState::UNPREPARED); |
| 289 DCHECK(reported_media_state_ == MediaState::UNPREPARED || | 263 DCHECK(reported_media_state_ == MediaState::UNPREPARED || |
| 290 reported_media_state_ == MediaState::FAULT); | 264 reported_media_state_ == MediaState::FAULT); |
| 291 | 265 |
| 292 stream->state_.SetWithConsequences(MediaState::PAUSED); | 266 stream->state_.SetWithConsequences(MediaState::PAUSED); |
| 293 | 267 |
| 294 HandleSinkStatusUpdates(stream); | 268 HandleSinkStatusUpdates(stream); |
| 295 | 269 |
| 296 event.Occur(); | 270 event.Occur(); |
| 297 }); | 271 }); |
| 298 } | 272 } |
| 299 | 273 |
| 300 void MediaPlayerImpl::StatusUpdated() { | 274 void MediaPlayerImpl::StatusUpdated() { |
| 301 ++status_version_; | 275 ++status_version_; |
| 302 while (!pending_status_requests_.empty()) { | 276 while (!pending_status_requests_.empty()) { |
| 303 RunStatusCallback(pending_status_requests_.front()); | 277 RunStatusCallback(pending_status_requests_.front()); |
| 304 pending_status_requests_.pop_front(); | 278 pending_status_requests_.pop_front(); |
| 305 } | 279 } |
| 306 } | 280 } |
| 307 | 281 |
| 308 void MediaPlayerImpl::RunStatusCallback(const GetStatusCallback& callback) | 282 void MediaPlayerImpl::RunStatusCallback( |
| 309 const { | 283 const GetStatusCallback& callback) const { |
| 310 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); | 284 MediaPlayerStatusPtr status = MediaPlayerStatus::New(); |
| 311 status->state = reported_media_state_; | 285 status->state = reported_media_state_; |
| 312 status->timeline_transform = transform_.Clone(); | 286 status->timeline_transform = transform_.Clone(); |
| 313 status->metadata = metadata_.Clone(); | 287 status->metadata = metadata_.Clone(); |
| 314 callback.Run(status_version_, status.Pass()); | 288 callback.Run(status_version_, status.Pass()); |
| 315 } | 289 } |
| 316 | 290 |
| 317 void MediaPlayerImpl::HandleSourceStatusUpdates( | 291 void MediaPlayerImpl::HandleSourceStatusUpdates(uint64_t version, |
| 318 uint64_t version, | 292 MediaSourceStatusPtr status) { |
| 319 MediaSourceStatusPtr status) { | |
| 320 if (status) { | 293 if (status) { |
| 321 metadata_ = status->metadata.Pass(); | 294 metadata_ = status->metadata.Pass(); |
| 322 StatusUpdated(); | 295 StatusUpdated(); |
| 323 } | 296 } |
| 324 | 297 |
| 325 source_->GetStatus( | 298 source_->GetStatus(version, |
| 326 version, | 299 [this](uint64_t version, MediaSourceStatusPtr status) { |
| 327 [this](uint64_t version, MediaSourceStatusPtr status) { | 300 HandleSourceStatusUpdates(version, status.Pass()); |
| 328 HandleSourceStatusUpdates(version, status.Pass()); | 301 }); |
| 329 }); | |
| 330 } | 302 } |
| 331 | 303 |
| 332 void MediaPlayerImpl::HandleSinkStatusUpdates( | 304 void MediaPlayerImpl::HandleSinkStatusUpdates( |
| 333 const std::unique_ptr<Stream>& stream, | 305 const std::unique_ptr<Stream>& stream, |
| 334 uint64_t version, | 306 uint64_t version, |
| 335 MediaSinkStatusPtr status) { | 307 MediaSinkStatusPtr status) { |
| 336 if (status && status->state > MediaState::UNPREPARED) { | 308 if (status && status->state > MediaState::UNPREPARED) { |
| 337 // We transition to PAUSED when Connect completes. | 309 // We transition to PAUSED when Connect completes. |
| 338 DCHECK(stream->state_ > MediaState::UNPREPARED); | 310 DCHECK(stream->state_ > MediaState::UNPREPARED); |
| 339 stream->state_.SetWithConsequences(status->state); | 311 stream->state_.SetWithConsequences(status->state); |
| 340 transform_ = status->timeline_transform.Pass(); | 312 transform_ = status->timeline_transform.Pass(); |
| 341 StatusUpdated(); | 313 StatusUpdated(); |
| 342 } | 314 } |
| 343 | 315 |
| 344 stream->sink_->GetStatus( | 316 stream->sink_->GetStatus( |
| 345 version, | 317 version, [this, &stream](uint64_t version, MediaSinkStatusPtr status) { |
| 346 [this, &stream](uint64_t version, MediaSinkStatusPtr status) { | |
| 347 HandleSinkStatusUpdates(stream, version, status.Pass()); | 318 HandleSinkStatusUpdates(stream, version, status.Pass()); |
| 348 }); | 319 }); |
| 349 } | 320 } |
| 350 | 321 |
| 351 MediaPlayerImpl::Stream::Stream() { | 322 MediaPlayerImpl::Stream::Stream() { |
| 352 state_.SetWithConsequences(MediaState::UNPREPARED); | 323 state_.SetWithConsequences(MediaState::UNPREPARED); |
| 353 } | 324 } |
| 354 | 325 |
| 355 MediaPlayerImpl::Stream::~Stream() {} | 326 MediaPlayerImpl::Stream::~Stream() {} |
| 356 | 327 |
| 357 } // namespace media | 328 } // namespace media |
| 358 } // namespace mojo | 329 } // namespace mojo |
| OLD | NEW |