| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "media/blink/webmediaplayer_impl.h" | 5 #include "media/blink/webmediaplayer_impl.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cmath> | 8 #include <cmath> |
| 9 #include <limits> | 9 #include <limits> |
| 10 #include <string> | 10 #include <string> |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 94 const double kMinRate = 0.0625; | 94 const double kMinRate = 0.0625; |
| 95 const double kMaxRate = 16.0; | 95 const double kMaxRate = 16.0; |
| 96 | 96 |
| 97 void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink, | 97 void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink, |
| 98 const std::string& device_id, | 98 const std::string& device_id, |
| 99 const url::Origin& security_origin, | 99 const url::Origin& security_origin, |
| 100 const OutputDeviceStatusCB& callback) { | 100 const OutputDeviceStatusCB& callback) { |
| 101 sink->SwitchOutputDevice(device_id, security_origin, callback); | 101 sink->SwitchOutputDevice(device_id, security_origin, callback); |
| 102 } | 102 } |
| 103 | 103 |
| 104 bool IsSuspendUponHiddenEnabled() { | 104 bool IsBackgroundedSuspendEnabled() { |
| 105 #if !defined(OS_ANDROID) | 105 #if !defined(OS_ANDROID) |
| 106 // Suspend/Resume is only enabled by default on Android. | 106 // Suspend/Resume is only enabled by default on Android. |
| 107 return base::CommandLine::ForCurrentProcess()->HasSwitch( | 107 return base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 108 switches::kEnableMediaSuspend); | 108 switches::kEnableMediaSuspend); |
| 109 #else | 109 #else |
| 110 return !base::CommandLine::ForCurrentProcess()->HasSwitch( | 110 return !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 111 switches::kDisableMediaSuspend); | 111 switches::kDisableMediaSuspend); |
| 112 #endif | 112 #endif |
| 113 } | 113 } |
| 114 | 114 |
| 115 bool IsNetworkStateError(blink::WebMediaPlayer::NetworkState state) { |
| 116 bool result = state == blink::WebMediaPlayer::NetworkStateFormatError || |
| 117 state == blink::WebMediaPlayer::NetworkStateNetworkError || |
| 118 state == blink::WebMediaPlayer::NetworkStateDecodeError; |
| 119 DCHECK_EQ(state > blink::WebMediaPlayer::NetworkStateLoaded, result); |
| 120 return result; |
| 121 } |
| 122 |
| 115 } // namespace | 123 } // namespace |
| 116 | 124 |
| 117 class BufferedDataSourceHostImpl; | 125 class BufferedDataSourceHostImpl; |
| 118 | 126 |
| 119 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, | 127 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUnspecified, |
| 120 UrlData::CORS_UNSPECIFIED); | 128 UrlData::CORS_UNSPECIFIED); |
| 121 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); | 129 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeAnonymous, UrlData::CORS_ANONYMOUS); |
| 122 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, | 130 STATIC_ASSERT_ENUM(WebMediaPlayer::CORSModeUseCredentials, |
| 123 UrlData::CORS_USE_CREDENTIALS); | 131 UrlData::CORS_USE_CREDENTIALS); |
| 124 | 132 |
| 125 #define BIND_TO_RENDER_LOOP(function) \ | 133 #define BIND_TO_RENDER_LOOP(function) \ |
| 126 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ | 134 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ |
| 127 BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) | 135 BindToCurrentLoop(base::Bind(function, AsWeakPtr()))) |
| 128 | 136 |
| 129 #define BIND_TO_RENDER_LOOP1(function, arg1) \ | 137 #define BIND_TO_RENDER_LOOP1(function, arg1) \ |
| 130 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ | 138 (DCHECK(main_task_runner_->BelongsToCurrentThread()), \ |
| 131 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) | 139 BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1))) |
| 132 | 140 |
| 133 WebMediaPlayerImpl::WebMediaPlayerImpl( | 141 WebMediaPlayerImpl::WebMediaPlayerImpl( |
| 134 blink::WebLocalFrame* frame, | 142 blink::WebLocalFrame* frame, |
| 135 blink::WebMediaPlayerClient* client, | 143 blink::WebMediaPlayerClient* client, |
| 136 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, | 144 blink::WebMediaPlayerEncryptedMediaClient* encrypted_client, |
| 137 base::WeakPtr<WebMediaPlayerDelegate> delegate, | 145 base::WeakPtr<WebMediaPlayerDelegate> delegate, |
| 138 scoped_ptr<RendererFactory> renderer_factory, | 146 scoped_ptr<RendererFactory> renderer_factory, |
| 139 linked_ptr<UrlIndex> url_index, | 147 linked_ptr<UrlIndex> url_index, |
| 140 const WebMediaPlayerParams& params) | 148 const WebMediaPlayerParams& params) |
| 141 : frame_(frame), | 149 : frame_(frame), |
| 150 delegate_state_(DelegateState::GONE), |
| 151 is_idle_(false), |
| 152 must_suspend_(false), |
| 142 network_state_(WebMediaPlayer::NetworkStateEmpty), | 153 network_state_(WebMediaPlayer::NetworkStateEmpty), |
| 143 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), | 154 ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 155 highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing), |
| 144 preload_(BufferedDataSource::AUTO), | 156 preload_(BufferedDataSource::AUTO), |
| 145 buffering_strategy_( | 157 buffering_strategy_( |
| 146 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), | 158 BufferedDataSourceInterface::BUFFERING_STRATEGY_NORMAL), |
| 147 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 159 main_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 148 media_task_runner_(params.media_task_runner()), | 160 media_task_runner_(params.media_task_runner()), |
| 149 worker_task_runner_(params.worker_task_runner()), | 161 worker_task_runner_(params.worker_task_runner()), |
| 150 media_log_(params.media_log()), | 162 media_log_(params.media_log()), |
| 151 pipeline_(media_task_runner_, media_log_.get()), | 163 pipeline_(media_task_runner_, media_log_.get()), |
| 152 pipeline_controller_( | 164 pipeline_controller_( |
| 153 &pipeline_, | 165 &pipeline_, |
| 154 base::Bind(&WebMediaPlayerImpl::CreateRenderer, | 166 base::Bind(&WebMediaPlayerImpl::CreateRenderer, |
| 155 base::Unretained(this)), | 167 base::Unretained(this)), |
| 156 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), | 168 base::Bind(&WebMediaPlayerImpl::OnPipelineSeeked, AsWeakPtr()), |
| 157 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), | 169 base::Bind(&WebMediaPlayerImpl::OnPipelineSuspended, AsWeakPtr()), |
| 158 base::Bind(&WebMediaPlayerImpl::OnPipelineResumed, AsWeakPtr()), | |
| 159 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), | 170 base::Bind(&WebMediaPlayerImpl::OnPipelineError, AsWeakPtr())), |
| 160 load_type_(LoadTypeURL), | 171 load_type_(LoadTypeURL), |
| 161 opaque_(false), | 172 opaque_(false), |
| 162 playback_rate_(0.0), | 173 playback_rate_(0.0), |
| 163 paused_(true), | 174 paused_(true), |
| 164 seeking_(false), | 175 seeking_(false), |
| 165 pending_suspend_resume_cycle_(false), | 176 pending_suspend_resume_cycle_(false), |
| 166 ended_(false), | 177 ended_(false), |
| 167 should_notify_time_changed_(false), | 178 should_notify_time_changed_(false), |
| 168 fullscreen_(false), | 179 fullscreen_(false), |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 339 DVLOG(1) << __FUNCTION__; | 350 DVLOG(1) << __FUNCTION__; |
| 340 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 351 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 341 | 352 |
| 342 #if defined(OS_ANDROID) // WMPI_CAST | 353 #if defined(OS_ANDROID) // WMPI_CAST |
| 343 if (isRemote()) { | 354 if (isRemote()) { |
| 344 cast_impl_.play(); | 355 cast_impl_.play(); |
| 345 return; | 356 return; |
| 346 } | 357 } |
| 347 #endif | 358 #endif |
| 348 | 359 |
| 349 const bool was_paused = paused_; | |
| 350 paused_ = false; | 360 paused_ = false; |
| 361 is_idle_ = false; |
| 351 pipeline_.SetPlaybackRate(playback_rate_); | 362 pipeline_.SetPlaybackRate(playback_rate_); |
| 352 | 363 |
| 353 if (data_source_) | 364 if (data_source_) |
| 354 data_source_->MediaIsPlaying(); | 365 data_source_->MediaIsPlaying(); |
| 355 | 366 |
| 356 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); | 367 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); |
| 357 | 368 UpdatePlayState(); |
| 358 if (playback_rate_ > 0 && was_paused) { | |
| 359 NotifyPlaybackStarted(); | |
| 360 | |
| 361 // Resume the player if allowed. We always call Resume() in case there is a | |
| 362 // pending suspend that should be aborted. If the pipeline is not suspended, | |
| 363 // Resume() will have no effect. | |
| 364 if (IsAutomaticResumeAllowed()) | |
| 365 pipeline_controller_.Resume(); | |
| 366 } | |
| 367 } | 369 } |
| 368 | 370 |
| 369 void WebMediaPlayerImpl::pause() { | 371 void WebMediaPlayerImpl::pause() { |
| 370 DVLOG(1) << __FUNCTION__; | 372 DVLOG(1) << __FUNCTION__; |
| 371 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 373 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 372 | 374 |
| 373 const bool was_already_paused = paused_ || playback_rate_ == 0; | 375 // We update the paused state even when casting, since we expect pause() to be |
| 376 // called when casting begins, and when we exit casting we should end up in a |
| 377 // paused state. |
| 374 paused_ = true; | 378 paused_ = true; |
| 375 | 379 |
| 376 #if defined(OS_ANDROID) // WMPI_CAST | 380 #if defined(OS_ANDROID) // WMPI_CAST |
| 377 if (isRemote()) { | 381 if (isRemote()) { |
| 378 cast_impl_.pause(); | 382 cast_impl_.pause(); |
| 379 return; | 383 return; |
| 380 } | 384 } |
| 381 #endif | 385 #endif |
| 382 | 386 |
| 383 pipeline_.SetPlaybackRate(0.0); | 387 pipeline_.SetPlaybackRate(0.0); |
| 384 | 388 |
| 385 // pause() may be called after playback has ended and the HTMLMediaElement | 389 // pause() may be called after playback has ended and the HTMLMediaElement |
| 386 // requires that currentTime() == duration() after ending. We want to ensure | 390 // requires that currentTime() == duration() after ending. We want to ensure |
| 387 // |paused_time_| matches currentTime() in this case or a future seek() may | 391 // |paused_time_| matches currentTime() in this case or a future seek() may |
| 388 // incorrectly discard what it thinks is a seek to the existing time. | 392 // incorrectly discard what it thinks is a seek to the existing time. |
| 389 paused_time_ = | 393 paused_time_ = |
| 390 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); | 394 ended_ ? pipeline_.GetMediaDuration() : pipeline_.GetMediaTime(); |
| 391 | 395 |
| 392 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); | 396 media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PAUSE)); |
| 393 | 397 UpdatePlayState(); |
| 394 if (!was_already_paused) | |
| 395 NotifyPlaybackPaused(); | |
| 396 } | 398 } |
| 397 | 399 |
| 398 bool WebMediaPlayerImpl::supportsSave() const { | 400 bool WebMediaPlayerImpl::supportsSave() const { |
| 399 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 401 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 400 return supports_save_; | 402 return supports_save_; |
| 401 } | 403 } |
| 402 | 404 |
| 403 void WebMediaPlayerImpl::seek(double seconds) { | 405 void WebMediaPlayerImpl::seek(double seconds) { |
| 404 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; | 406 DVLOG(1) << __FUNCTION__ << "(" << seconds << "s)"; |
| 405 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 407 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 406 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); | 408 DoSeek(base::TimeDelta::FromSecondsD(seconds), true); |
| 407 } | 409 } |
| 408 | 410 |
| 409 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { | 411 void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) { |
| 410 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 412 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 411 | 413 |
| 412 ended_ = false; | |
| 413 | |
| 414 #if defined(OS_ANDROID) // WMPI_CAST | 414 #if defined(OS_ANDROID) // WMPI_CAST |
| 415 if (isRemote()) { | 415 if (isRemote()) { |
| 416 cast_impl_.seek(time); | 416 cast_impl_.seek(time); |
| 417 return; | 417 return; |
| 418 } | 418 } |
| 419 #endif | 419 #endif |
| 420 | 420 |
| 421 ReadyState old_state = ready_state_; | 421 ReadyState old_state = ready_state_; |
| 422 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) | 422 if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) |
| 423 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 423 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 437 // ready state change to eventually happen. | 437 // ready state change to eventually happen. |
| 438 if (old_state == ReadyStateHaveEnoughData) { | 438 if (old_state == ReadyStateHaveEnoughData) { |
| 439 main_task_runner_->PostTask( | 439 main_task_runner_->PostTask( |
| 440 FROM_HERE, | 440 FROM_HERE, |
| 441 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, | 441 base::Bind(&WebMediaPlayerImpl::OnPipelineBufferingStateChanged, |
| 442 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); | 442 AsWeakPtr(), BUFFERING_HAVE_ENOUGH)); |
| 443 } | 443 } |
| 444 return; | 444 return; |
| 445 } | 445 } |
| 446 | 446 |
| 447 // TODO(sandersd): Ideally we would not clear the idle state if |
| 448 // |pipeline_controller_| can elide the seek. |
| 449 is_idle_ = false; |
| 450 ended_ = false; |
| 451 |
| 447 seeking_ = true; | 452 seeking_ = true; |
| 448 seek_time_ = time; | 453 seek_time_ = time; |
| 449 if (paused_) | 454 if (paused_) |
| 450 paused_time_ = time; | 455 paused_time_ = time; |
| 451 pipeline_controller_.Seek(time, time_updated); | 456 pipeline_controller_.Seek(time, time_updated); |
| 452 | 457 |
| 453 // Resume the pipeline if allowed so that the correct frame is displayed. We | 458 // This needs to be called after Seek() so that if a resume is triggered, it |
| 454 // always call Resume() in case there is a pending suspend that should be | 459 // is to the correct time. |
| 455 // aborted. If the pipeline is not suspended, Resume() will have no effect. | 460 UpdatePlayState(); |
| 456 if (IsAutomaticResumeAllowed()) | |
| 457 pipeline_controller_.Resume(); | |
| 458 } | 461 } |
| 459 | 462 |
| 460 void WebMediaPlayerImpl::setRate(double rate) { | 463 void WebMediaPlayerImpl::setRate(double rate) { |
| 461 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; | 464 DVLOG(1) << __FUNCTION__ << "(" << rate << ")"; |
| 462 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 465 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 463 | 466 |
| 464 // TODO(kylep): Remove when support for negatives is added. Also, modify the | 467 // TODO(kylep): Remove when support for negatives is added. Also, modify the |
| 465 // following checks so rewind uses reasonable values also. | 468 // following checks so rewind uses reasonable values also. |
| 466 if (rate < 0.0) | 469 if (rate < 0.0) |
| 467 return; | 470 return; |
| 468 | 471 |
| 469 // Limit rates to reasonable values by clamping. | 472 // Limit rates to reasonable values by clamping. |
| 470 if (rate != 0.0) { | 473 if (rate != 0.0) { |
| 471 if (rate < kMinRate) | 474 if (rate < kMinRate) |
| 472 rate = kMinRate; | 475 rate = kMinRate; |
| 473 else if (rate > kMaxRate) | 476 else if (rate > kMaxRate) |
| 474 rate = kMaxRate; | 477 rate = kMaxRate; |
| 475 if (playback_rate_ == 0 && !paused_) | |
| 476 NotifyPlaybackStarted(); | |
| 477 } else if (playback_rate_ != 0 && !paused_) { | |
| 478 NotifyPlaybackPaused(); | |
| 479 } | 478 } |
| 480 | 479 |
| 481 playback_rate_ = rate; | 480 playback_rate_ = rate; |
| 482 if (!paused_) { | 481 if (!paused_) { |
| 483 pipeline_.SetPlaybackRate(rate); | 482 pipeline_.SetPlaybackRate(rate); |
| 484 if (data_source_) | 483 if (data_source_) |
| 485 data_source_->MediaPlaybackRateChanged(rate); | 484 data_source_->MediaPlaybackRateChanged(rate); |
| 486 } | 485 } |
| 487 } | 486 } |
| 488 | 487 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 566 return blink::WebSize(pipeline_metadata_.natural_size); | 565 return blink::WebSize(pipeline_metadata_.natural_size); |
| 567 } | 566 } |
| 568 | 567 |
| 569 bool WebMediaPlayerImpl::paused() const { | 568 bool WebMediaPlayerImpl::paused() const { |
| 570 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 569 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 571 | 570 |
| 572 #if defined(OS_ANDROID) // WMPI_CAST | 571 #if defined(OS_ANDROID) // WMPI_CAST |
| 573 if (isRemote()) | 572 if (isRemote()) |
| 574 return cast_impl_.paused(); | 573 return cast_impl_.paused(); |
| 575 #endif | 574 #endif |
| 575 |
| 576 return pipeline_.GetPlaybackRate() == 0.0f; | 576 return pipeline_.GetPlaybackRate() == 0.0f; |
| 577 } | 577 } |
| 578 | 578 |
| 579 bool WebMediaPlayerImpl::seeking() const { | 579 bool WebMediaPlayerImpl::seeking() const { |
| 580 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 580 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 581 | 581 |
| 582 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) | 582 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
| 583 return false; | 583 return false; |
| 584 | 584 |
| 585 return seeking_; | 585 return seeking_; |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 889 paused_time_ = pipeline_.GetMediaTime(); | 889 paused_time_ = pipeline_.GetMediaTime(); |
| 890 #endif | 890 #endif |
| 891 } | 891 } |
| 892 if (time_updated) | 892 if (time_updated) |
| 893 should_notify_time_changed_ = true; | 893 should_notify_time_changed_ = true; |
| 894 } | 894 } |
| 895 | 895 |
| 896 void WebMediaPlayerImpl::OnPipelineSuspended() { | 896 void WebMediaPlayerImpl::OnPipelineSuspended() { |
| 897 #if defined(OS_ANDROID) | 897 #if defined(OS_ANDROID) |
| 898 if (isRemote()) { | 898 if (isRemote()) { |
| 899 if (delegate_) | |
| 900 delegate_->PlayerGone(delegate_id_); | |
| 901 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 899 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 902 if (frame) { | 900 if (frame) |
| 903 compositor_->PaintFrameUsingOldRenderingPath(frame); | 901 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 904 } | |
| 905 } | 902 } |
| 906 #endif | 903 #endif |
| 907 | 904 |
| 908 memory_usage_reporting_timer_.Stop(); | |
| 909 ReportMemoryUsage(); | |
| 910 | |
| 911 // If we're not in an aggressive buffering state, tell the data source we have | 905 // If we're not in an aggressive buffering state, tell the data source we have |
| 912 // enough data so that it may release the connection. | 906 // enough data so that it may release the connection. |
| 913 if (buffering_strategy_ != | 907 if (buffering_strategy_ != |
| 914 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { | 908 BufferedDataSource::BUFFERING_STRATEGY_AGGRESSIVE) { |
| 915 if (data_source_) | 909 if (data_source_) |
| 916 data_source_->OnBufferingHaveEnough(true); | 910 data_source_->OnBufferingHaveEnough(true); |
| 917 } | 911 } |
| 918 | 912 |
| 913 ReportMemoryUsage(); |
| 914 |
| 919 if (pending_suspend_resume_cycle_) { | 915 if (pending_suspend_resume_cycle_) { |
| 920 pending_suspend_resume_cycle_ = false; | 916 pending_suspend_resume_cycle_ = false; |
| 921 pipeline_controller_.Resume(); | 917 UpdatePlayState(); |
| 922 return; | |
| 923 } | 918 } |
| 924 } | 919 } |
| 925 | 920 |
| 926 void WebMediaPlayerImpl::OnPipelineResumed() { | |
| 927 if (playback_rate_ > 0 && !paused_) { | |
| 928 NotifyPlaybackStarted(); | |
| 929 } else if (!playback_rate_ || paused_ || ended_) { | |
| 930 // Resend our paused notification so the pipeline is considered for idle | |
| 931 // resource reclamation; duplicate pause notifications are ignored. | |
| 932 NotifyPlaybackPaused(); | |
| 933 } | |
| 934 } | |
| 935 | |
| 936 void WebMediaPlayerImpl::OnPipelineEnded() { | 921 void WebMediaPlayerImpl::OnPipelineEnded() { |
| 937 DVLOG(1) << __FUNCTION__; | 922 DVLOG(1) << __FUNCTION__; |
| 938 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 923 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 939 | 924 |
| 940 // Ignore state changes until we've completed all outstanding operations. | 925 // Ignore state changes until we've completed all outstanding operations. |
| 941 if (!pipeline_controller_.IsStable()) | 926 if (!pipeline_controller_.IsStable()) |
| 942 return; | 927 return; |
| 943 | 928 |
| 944 ended_ = true; | 929 ended_ = true; |
| 945 client_->timeChanged(); | 930 client_->timeChanged(); |
| 931 |
| 932 // We don't actually want this to run until |client_| calls seek() or pause(), |
| 933 // but that should have already happened in timeChanged() and so this is |
| 934 // expected to be a no-op. |
| 935 UpdatePlayState(); |
| 946 } | 936 } |
| 947 | 937 |
| 948 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { | 938 void WebMediaPlayerImpl::OnPipelineError(PipelineStatus error) { |
| 949 DVLOG(1) << __FUNCTION__; | 939 DVLOG(1) << __FUNCTION__; |
| 950 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 940 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 951 DCHECK_NE(error, PIPELINE_OK); | 941 DCHECK_NE(error, PIPELINE_OK); |
| 952 | 942 |
| 953 if (suppress_destruction_errors_) | 943 if (suppress_destruction_errors_) |
| 954 return; | 944 return; |
| 955 | 945 |
| 956 // Release the delegate for player errors; this drops the media session and | |
| 957 // avoids idle suspension from ticking. | |
| 958 if (delegate_) | |
| 959 delegate_->PlayerGone(delegate_id_); | |
| 960 | |
| 961 #if defined(OS_ANDROID) | 946 #if defined(OS_ANDROID) |
| 962 // For 10% of pipeline decode failures log the playback URL. The URL is set | 947 // For 10% of pipeline decode failures log the playback URL. The URL is set |
| 963 // as the crash-key 'subresource_url' during DoLoad(). | 948 // as the crash-key 'subresource_url' during DoLoad(). |
| 964 // | 949 // |
| 965 // TODO(dalecurtis): This is temporary to track down higher than average | 950 // TODO(dalecurtis): This is temporary to track down higher than average |
| 966 // decode failure rates for video-only content. See http://crbug.com/595076. | 951 // decode failure rates for video-only content. See http://crbug.com/595076. |
| 967 if (base::RandDouble() <= 0.1 && error == PIPELINE_ERROR_DECODE) | 952 if (base::RandDouble() <= 0.1 && error == PIPELINE_ERROR_DECODE) |
| 968 base::debug::DumpWithoutCrashing(); | 953 base::debug::DumpWithoutCrashing(); |
| 969 #endif | 954 #endif |
| 970 | 955 |
| 971 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); | 956 media_log_->AddEvent(media_log_->CreatePipelineErrorEvent(error)); |
| 972 | 957 |
| 973 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) { | 958 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) { |
| 974 // Any error that occurs before reaching ReadyStateHaveMetadata should | 959 // Any error that occurs before reaching ReadyStateHaveMetadata should |
| 975 // be considered a format error. | 960 // be considered a format error. |
| 976 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); | 961 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 977 return; | 962 } else { |
| 963 SetNetworkState(PipelineErrorToNetworkState(error)); |
| 978 } | 964 } |
| 979 | 965 |
| 980 SetNetworkState(PipelineErrorToNetworkState(error)); | 966 UpdatePlayState(); |
| 981 } | 967 } |
| 982 | 968 |
| 983 void WebMediaPlayerImpl::OnPipelineMetadata( | 969 void WebMediaPlayerImpl::OnPipelineMetadata( |
| 984 PipelineMetadata metadata) { | 970 PipelineMetadata metadata) { |
| 985 DVLOG(1) << __FUNCTION__; | 971 DVLOG(1) << __FUNCTION__; |
| 986 | 972 |
| 987 pipeline_metadata_ = metadata; | 973 pipeline_metadata_ = metadata; |
| 988 | 974 |
| 989 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation, | 975 UMA_HISTOGRAM_ENUMERATION("Media.VideoRotation", metadata.video_rotation, |
| 990 VIDEO_ROTATION_MAX + 1); | 976 VIDEO_ROTATION_MAX + 1); |
| 991 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); | 977 SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); |
| 992 | 978 |
| 993 if (hasVideo()) { | 979 if (hasVideo()) { |
| 994 DCHECK(!video_weblayer_); | 980 DCHECK(!video_weblayer_); |
| 995 scoped_refptr<cc::VideoLayer> layer = | 981 scoped_refptr<cc::VideoLayer> layer = |
| 996 cc::VideoLayer::Create(compositor_, pipeline_metadata_.video_rotation); | 982 cc::VideoLayer::Create(compositor_, pipeline_metadata_.video_rotation); |
| 997 | 983 |
| 998 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 || | 984 if (pipeline_metadata_.video_rotation == VIDEO_ROTATION_90 || |
| 999 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) { | 985 pipeline_metadata_.video_rotation == VIDEO_ROTATION_270) { |
| 1000 gfx::Size size = pipeline_metadata_.natural_size; | 986 gfx::Size size = pipeline_metadata_.natural_size; |
| 1001 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width()); | 987 pipeline_metadata_.natural_size = gfx::Size(size.height(), size.width()); |
| 1002 } | 988 } |
| 1003 | 989 |
| 1004 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer)); | 990 video_weblayer_.reset(new cc_blink::WebLayerImpl(layer)); |
| 1005 video_weblayer_->layer()->SetContentsOpaque(opaque_); | 991 video_weblayer_->layer()->SetContentsOpaque(opaque_); |
| 1006 video_weblayer_->SetContentsOpaqueIsFixed(true); | 992 video_weblayer_->SetContentsOpaqueIsFixed(true); |
| 1007 client_->setWebLayer(video_weblayer_.get()); | 993 client_->setWebLayer(video_weblayer_.get()); |
| 1008 } | 994 } |
| 1009 | 995 |
| 1010 // Tell the delegate we can now be safely suspended due to inactivity if a | 996 UpdatePlayState(); |
| 1011 // subsequent play event does not occur. | |
| 1012 if (paused_) | |
| 1013 NotifyPlaybackPaused(); | |
| 1014 | |
| 1015 // If the frame is hidden, it may be time to suspend playback. | |
| 1016 if (delegate_ && delegate_->IsHidden()) | |
| 1017 OnHidden(); | |
| 1018 } | 997 } |
| 1019 | 998 |
| 1020 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( | 999 void WebMediaPlayerImpl::OnPipelineBufferingStateChanged( |
| 1021 BufferingState buffering_state) { | 1000 BufferingState buffering_state) { |
| 1022 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; | 1001 DVLOG(1) << __FUNCTION__ << "(" << buffering_state << ")"; |
| 1023 | 1002 |
| 1024 // Ignore buffering state changes until we've completed all outstanding | 1003 // Ignore buffering state changes until we've completed all outstanding |
| 1025 // operations. | 1004 // operations. |
| 1026 if (!pipeline_controller_.IsStable()) | 1005 if (!pipeline_controller_.IsStable()) |
| 1027 return; | 1006 return; |
| 1028 | 1007 |
| 1029 // TODO(scherkus): Handle other buffering states when Pipeline starts using | 1008 // TODO(scherkus): Handle other buffering states when Pipeline starts using |
| 1030 // them and translate them ready state changes http://crbug.com/144683 | 1009 // them and translate them ready state changes http://crbug.com/144683 |
| 1031 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); | 1010 DCHECK_EQ(buffering_state, BUFFERING_HAVE_ENOUGH); |
| 1032 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); | 1011 SetReadyState(WebMediaPlayer::ReadyStateHaveEnoughData); |
| 1033 | 1012 |
| 1034 // Let the DataSource know we have enough data. It may use this information to | 1013 // Let the DataSource know we have enough data. It may use this information to |
| 1035 // release unused network connections. | 1014 // release unused network connections. |
| 1036 if (data_source_) | 1015 if (data_source_) |
| 1037 data_source_->OnBufferingHaveEnough(false); | 1016 data_source_->OnBufferingHaveEnough(false); |
| 1038 | 1017 |
| 1039 // Blink expects a timeChanged() in response to a seek(). | 1018 // Blink expects a timeChanged() in response to a seek(). |
| 1040 if (should_notify_time_changed_) | 1019 if (should_notify_time_changed_) |
| 1041 client_->timeChanged(); | 1020 client_->timeChanged(); |
| 1042 | 1021 |
| 1043 // Once we have enough, start reporting the total memory usage. We'll also | 1022 // Once we have enough, start reporting the total memory usage. We'll also |
| 1044 // report once playback starts. | 1023 // report once playback starts. |
| 1045 ReportMemoryUsage(); | 1024 ReportMemoryUsage(); |
| 1025 |
| 1026 UpdatePlayState(); |
| 1046 } | 1027 } |
| 1047 | 1028 |
| 1048 void WebMediaPlayerImpl::OnDemuxerOpened() { | 1029 void WebMediaPlayerImpl::OnDemuxerOpened() { |
| 1049 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1030 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1050 client_->mediaSourceOpened( | 1031 client_->mediaSourceOpened( |
| 1051 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); | 1032 new WebMediaSourceImpl(chunk_demuxer_, media_log_)); |
| 1052 } | 1033 } |
| 1053 | 1034 |
| 1054 void WebMediaPlayerImpl::OnAddTextTrack( | 1035 void WebMediaPlayerImpl::OnAddTextTrack( |
| 1055 const TextTrackConfig& config, | 1036 const TextTrackConfig& config, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1069 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id)); | 1050 new WebInbandTextTrackImpl(web_kind, web_label, web_language, web_id)); |
| 1070 | 1051 |
| 1071 scoped_ptr<media::TextTrack> text_track(new TextTrackImpl( | 1052 scoped_ptr<media::TextTrack> text_track(new TextTrackImpl( |
| 1072 main_task_runner_, client_, std::move(web_inband_text_track))); | 1053 main_task_runner_, client_, std::move(web_inband_text_track))); |
| 1073 | 1054 |
| 1074 done_cb.Run(std::move(text_track)); | 1055 done_cb.Run(std::move(text_track)); |
| 1075 } | 1056 } |
| 1076 | 1057 |
| 1077 void WebMediaPlayerImpl::OnHidden() { | 1058 void WebMediaPlayerImpl::OnHidden() { |
| 1078 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1059 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1079 if (!IsSuspendUponHiddenEnabled()) | 1060 UpdatePlayState(); |
| 1080 return; | |
| 1081 | |
| 1082 #if defined(OS_ANDROID) // WMPI_CAST | |
| 1083 // If we're remote, the pipeline should already be suspended. | |
| 1084 if (isRemote()) | |
| 1085 return; | |
| 1086 #endif | |
| 1087 | |
| 1088 // Don't suspend before metadata is available, as we don't know if there is a | |
| 1089 // video track yet. | |
| 1090 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata) | |
| 1091 return; | |
| 1092 | |
| 1093 // Don't suspend players which only have audio and have not completed | |
| 1094 // playback. The user can still control these players via the MediaSession UI. | |
| 1095 // If the player has never started playback, OnSuspendRequested() will handle | |
| 1096 // release of any idle resources. | |
| 1097 if (!hasVideo() && !paused_ && !ended_) | |
| 1098 return; | |
| 1099 | |
| 1100 // Always reset the buffering strategy to normal when suspending for hidden to | |
| 1101 // prevent an idle network connection from lingering. | |
| 1102 setBufferingStrategy(WebMediaPlayer::BufferingStrategy::Normal); | |
| 1103 pipeline_controller_.Suspend(); | |
| 1104 // If we're in the middle of a suspend/resume cycle we no longer want to | |
| 1105 // resume when the suspend completes. | |
| 1106 pending_suspend_resume_cycle_ = false; | |
| 1107 if (delegate_) | |
| 1108 delegate_->PlayerGone(delegate_id_); | |
| 1109 } | 1061 } |
| 1110 | 1062 |
| 1111 void WebMediaPlayerImpl::OnShown() { | 1063 void WebMediaPlayerImpl::OnShown() { |
| 1112 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1064 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1113 if (!IsSuspendUponHiddenEnabled()) | 1065 must_suspend_ = false; |
| 1114 return; | 1066 UpdatePlayState(); |
| 1115 | |
| 1116 #if defined(OS_ANDROID) // WMPI_CAST | |
| 1117 // If we're remote, the pipeline should stay suspended. | |
| 1118 if (isRemote()) | |
| 1119 return; | |
| 1120 #endif | |
| 1121 | |
| 1122 // If we do not yet have metadata, the only way we could have been suspended | |
| 1123 // is by a OnSuspendRequested() with |must_suspend| set. In that case we need | |
| 1124 // to resume, otherwise playback will be broken. | |
| 1125 // | |
| 1126 // Otherwise, resume if we should be playing. | |
| 1127 if (ready_state_ < WebMediaPlayer::ReadyStateHaveMetadata || | |
| 1128 (!ended_ && !paused_)) { | |
| 1129 pipeline_controller_.Resume(); | |
| 1130 } | |
| 1131 } | 1067 } |
| 1132 | 1068 |
| 1133 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { | 1069 void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { |
| 1134 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1070 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1135 | 1071 |
| 1136 #if defined(OS_ANDROID) // WMPI_CAST | |
| 1137 // If we're remote, the pipeline should already be suspended. | |
| 1138 if (isRemote()) | |
| 1139 return; | |
| 1140 #endif | |
| 1141 | |
| 1142 #if defined(OS_MACOSX) | 1072 #if defined(OS_MACOSX) |
| 1143 // TODO(sandersd): Idle suspend is disabled on OSX since hardware decoded | 1073 // TODO(sandersd): Idle suspend is disabled on OSX since hardware decoded |
| 1144 // frames are owned by the video decoder in the GPU process. A mechanism for | 1074 // frames are owned by the video decoder in the GPU process. A mechanism for |
| 1145 // detaching ownership from the decoder is needed. http://crbug.com/595716. | 1075 // detaching ownership from the decoder is needed. http://crbug.com/595716. |
| 1146 return; | 1076 return; |
| 1147 #else | 1077 #endif |
| 1148 // Suspend should never be requested unless required or we're already in an | |
| 1149 // idle state (paused or ended). | |
| 1150 DCHECK(must_suspend || paused_ || ended_); | |
| 1151 | 1078 |
| 1152 // Always suspend, but only notify the delegate if we must; this allows any | 1079 if (must_suspend) { |
| 1153 // exposed UI for player controls to continue to function even though the | 1080 must_suspend_ = true; |
| 1154 // player has now been suspended. | 1081 } else { |
| 1155 pipeline_controller_.Suspend(); | 1082 is_idle_ = true; |
| 1156 if (must_suspend && delegate_) | 1083 } |
| 1157 delegate_->PlayerGone(delegate_id_); | 1084 |
| 1158 #endif | 1085 UpdatePlayState(); |
| 1159 } | 1086 } |
| 1160 | 1087 |
| 1161 void WebMediaPlayerImpl::OnPlay() { | 1088 void WebMediaPlayerImpl::OnPlay() { |
| 1162 play(); | 1089 play(); |
| 1163 client_->playbackStateChanged(); | 1090 client_->playbackStateChanged(); |
| 1164 } | 1091 } |
| 1165 | 1092 |
| 1166 void WebMediaPlayerImpl::OnPause() { | 1093 void WebMediaPlayerImpl::OnPause() { |
| 1167 pause(); | 1094 pause(); |
| 1168 client_->playbackStateChanged(); | 1095 client_->playbackStateChanged(); |
| 1169 } | 1096 } |
| 1170 | 1097 |
| 1171 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { | 1098 void WebMediaPlayerImpl::OnVolumeMultiplierUpdate(double multiplier) { |
| 1172 volume_multiplier_ = multiplier; | 1099 volume_multiplier_ = multiplier; |
| 1173 setVolume(volume_); | 1100 setVolume(volume_); |
| 1174 } | 1101 } |
| 1175 | 1102 |
| 1176 void WebMediaPlayerImpl::ScheduleRestart() { | 1103 void WebMediaPlayerImpl::ScheduleRestart() { |
| 1177 if (!pipeline_controller_.IsSuspended()) { | 1104 // TODO(watk): All restart logic should be moved into PipelineController. |
| 1105 if (pipeline_.IsRunning() && !pipeline_controller_.IsPipelineSuspended()) { |
| 1178 pending_suspend_resume_cycle_ = true; | 1106 pending_suspend_resume_cycle_ = true; |
| 1179 pipeline_controller_.Suspend(); | 1107 UpdatePlayState(); |
| 1180 } | 1108 } |
| 1181 } | 1109 } |
| 1182 | 1110 |
| 1183 #if defined(OS_ANDROID) // WMPI_CAST | 1111 #if defined(OS_ANDROID) // WMPI_CAST |
| 1184 bool WebMediaPlayerImpl::isRemote() const { | 1112 bool WebMediaPlayerImpl::isRemote() const { |
| 1185 return cast_impl_.isRemote(); | 1113 return cast_impl_.isRemote(); |
| 1186 } | 1114 } |
| 1187 | 1115 |
| 1188 void WebMediaPlayerImpl::SetMediaPlayerManager( | 1116 void WebMediaPlayerImpl::SetMediaPlayerManager( |
| 1189 RendererMediaPlayerManagerInterface* media_player_manager) { | 1117 RendererMediaPlayerManagerInterface* media_player_manager) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1201 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { | 1129 void WebMediaPlayerImpl::OnRemotePlaybackEnded() { |
| 1202 DVLOG(1) << __FUNCTION__; | 1130 DVLOG(1) << __FUNCTION__; |
| 1203 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1131 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1204 | 1132 |
| 1205 ended_ = true; | 1133 ended_ = true; |
| 1206 client_->timeChanged(); | 1134 client_->timeChanged(); |
| 1207 } | 1135 } |
| 1208 | 1136 |
| 1209 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { | 1137 void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { |
| 1210 DoSeek(base::TimeDelta::FromSecondsD(t), false); | 1138 DoSeek(base::TimeDelta::FromSecondsD(t), false); |
| 1211 if (delegate_ && !delegate_->IsHidden()) | |
| 1212 pipeline_controller_.Resume(); | |
| 1213 | 1139 |
| 1214 // We already told the delegate we're paused when remoting started. | 1140 // We already told the delegate we're paused when remoting started. |
| 1215 client_->playbackStateChanged(); | 1141 client_->playbackStateChanged(); |
| 1216 client_->disconnectedFromRemoteDevice(); | 1142 client_->disconnectedFromRemoteDevice(); |
| 1143 |
| 1144 UpdatePlayState(); |
| 1217 } | 1145 } |
| 1218 | 1146 |
| 1219 void WebMediaPlayerImpl::SuspendForRemote() { | 1147 void WebMediaPlayerImpl::SuspendForRemote() { |
| 1220 if (!pipeline_controller_.IsSuspended()) { | 1148 if (pipeline_controller_.IsPipelineSuspended()) { |
| 1221 pipeline_controller_.Suspend(); | |
| 1222 } else { | |
| 1223 // TODO(sandersd): If PipelineController::Suspend() called |suspended_cb| | |
| 1224 // when already suspended, we wouldn't need this case. | |
| 1225 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); | 1149 scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); |
| 1226 if (frame) { | 1150 if (frame) |
| 1227 compositor_->PaintFrameUsingOldRenderingPath(frame); | 1151 compositor_->PaintFrameUsingOldRenderingPath(frame); |
| 1228 } | |
| 1229 } | 1152 } |
| 1153 |
| 1154 UpdatePlayState(); |
| 1230 } | 1155 } |
| 1231 | 1156 |
| 1232 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { | 1157 gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { |
| 1233 if (!video_weblayer_) | 1158 if (!video_weblayer_) |
| 1234 return pipeline_metadata_.natural_size; | 1159 return pipeline_metadata_.natural_size; |
| 1235 | 1160 |
| 1236 return video_weblayer_->bounds(); | 1161 return video_weblayer_->bounds(); |
| 1237 } | 1162 } |
| 1238 | 1163 |
| 1239 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { | 1164 void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { |
| 1240 cast_impl_.SetDeviceScaleFactor(scale_factor); | 1165 cast_impl_.SetDeviceScaleFactor(scale_factor); |
| 1241 } | 1166 } |
| 1242 #endif // defined(OS_ANDROID) // WMPI_CAST | 1167 #endif // defined(OS_ANDROID) // WMPI_CAST |
| 1243 | 1168 |
| 1244 void WebMediaPlayerImpl::DataSourceInitialized(bool success) { | 1169 void WebMediaPlayerImpl::DataSourceInitialized(bool success) { |
| 1245 DVLOG(1) << __FUNCTION__; | 1170 DVLOG(1) << __FUNCTION__; |
| 1246 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1171 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1247 | 1172 |
| 1248 if (!success) { | 1173 if (!success) { |
| 1249 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); | 1174 SetNetworkState(WebMediaPlayer::NetworkStateFormatError); |
| 1175 |
| 1176 // Not really necessary, since the pipeline was never started, but it at |
| 1177 // least this makes sure that the error handling code is in sync. |
| 1178 UpdatePlayState(); |
| 1179 |
| 1250 return; | 1180 return; |
| 1251 } | 1181 } |
| 1252 | 1182 |
| 1253 StartPipeline(); | 1183 StartPipeline(); |
| 1254 } | 1184 } |
| 1255 | 1185 |
| 1256 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) { | 1186 void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) { |
| 1257 DVLOG(1) << __FUNCTION__; | 1187 DVLOG(1) << __FUNCTION__; |
| 1258 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading) | 1188 if (!is_downloading && network_state_ == WebMediaPlayer::NetworkStateLoading) |
| 1259 SetNetworkState(WebMediaPlayer::NetworkStateIdle); | 1189 SetNetworkState(WebMediaPlayer::NetworkStateIdle); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1367 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) { | 1297 void WebMediaPlayerImpl::SetReadyState(WebMediaPlayer::ReadyState state) { |
| 1368 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; | 1298 DVLOG(1) << __FUNCTION__ << "(" << state << ")"; |
| 1369 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1299 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1370 | 1300 |
| 1371 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ && | 1301 if (state == WebMediaPlayer::ReadyStateHaveEnoughData && data_source_ && |
| 1372 data_source_->assume_fully_buffered() && | 1302 data_source_->assume_fully_buffered() && |
| 1373 network_state_ == WebMediaPlayer::NetworkStateLoading) | 1303 network_state_ == WebMediaPlayer::NetworkStateLoading) |
| 1374 SetNetworkState(WebMediaPlayer::NetworkStateLoaded); | 1304 SetNetworkState(WebMediaPlayer::NetworkStateLoaded); |
| 1375 | 1305 |
| 1376 ready_state_ = state; | 1306 ready_state_ = state; |
| 1307 highest_ready_state_ = std::max(highest_ready_state_, ready_state_); |
| 1308 |
| 1377 // Always notify to ensure client has the latest value. | 1309 // Always notify to ensure client has the latest value. |
| 1378 client_->readyStateChanged(); | 1310 client_->readyStateChanged(); |
| 1379 } | 1311 } |
| 1380 | 1312 |
| 1381 blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() { | 1313 blink::WebAudioSourceProvider* WebMediaPlayerImpl::getAudioSourceProvider() { |
| 1382 return audio_source_provider_.get(); | 1314 return audio_source_provider_.get(); |
| 1383 } | 1315 } |
| 1384 | 1316 |
| 1385 double WebMediaPlayerImpl::GetPipelineDuration() const { | 1317 double WebMediaPlayerImpl::GetPipelineDuration() const { |
| 1386 base::TimeDelta duration = pipeline_.GetMediaDuration(); | 1318 base::TimeDelta duration = pipeline_.GetMediaDuration(); |
| 1387 | 1319 |
| 1388 // Return positive infinity if the resource is unbounded. | 1320 // Return positive infinity if the resource is unbounded. |
| 1389 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-
media-duration | 1321 // http://www.whatwg.org/specs/web-apps/current-work/multipage/video.html#dom-
media-duration |
| 1390 if (duration == kInfiniteDuration()) | 1322 if (duration == kInfiniteDuration()) |
| 1391 return std::numeric_limits<double>::infinity(); | 1323 return std::numeric_limits<double>::infinity(); |
| 1392 | 1324 |
| 1393 return duration.InSecondsF(); | 1325 return duration.InSecondsF(); |
| 1394 } | 1326 } |
| 1395 | 1327 |
| 1396 void WebMediaPlayerImpl::OnDurationChanged() { | 1328 void WebMediaPlayerImpl::OnDurationChanged() { |
| 1329 // TODO(sandersd): We should call delegate_->DidPlay() with the new duration, |
| 1330 // especially if it changed from <5s to >5s. |
| 1397 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) | 1331 if (ready_state_ == WebMediaPlayer::ReadyStateHaveNothing) |
| 1398 return; | 1332 return; |
| 1399 | 1333 |
| 1400 client_->durationChanged(); | 1334 client_->durationChanged(); |
| 1401 } | 1335 } |
| 1402 | 1336 |
| 1403 void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) { | 1337 void WebMediaPlayerImpl::OnNaturalSizeChanged(gfx::Size size) { |
| 1404 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1338 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1405 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); | 1339 DCHECK_NE(ready_state_, WebMediaPlayer::ReadyStateHaveNothing); |
| 1406 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged"); | 1340 TRACE_EVENT0("media", "WebMediaPlayerImpl::OnNaturalSizeChanged"); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1449 base::WaitableEvent event(false, false); | 1383 base::WaitableEvent event(false, false); |
| 1450 compositor_task_runner_->PostTask(FROM_HERE, | 1384 compositor_task_runner_->PostTask(FROM_HERE, |
| 1451 base::Bind(&GetCurrentFrameAndSignal, | 1385 base::Bind(&GetCurrentFrameAndSignal, |
| 1452 base::Unretained(compositor_), | 1386 base::Unretained(compositor_), |
| 1453 &video_frame, | 1387 &video_frame, |
| 1454 &event)); | 1388 &event)); |
| 1455 event.Wait(); | 1389 event.Wait(); |
| 1456 return video_frame; | 1390 return video_frame; |
| 1457 } | 1391 } |
| 1458 | 1392 |
| 1459 void WebMediaPlayerImpl::NotifyPlaybackStarted() { | 1393 void WebMediaPlayerImpl::UpdatePlayState() { |
| 1460 #if defined(OS_ANDROID) // WMPI_CAST | 1394 #if defined(OS_ANDROID) // WMPI_CAST |
| 1461 // We do not tell our delegates about remote playback, because that would | 1395 bool is_remote = isRemote(); |
| 1462 // keep the device awake, which is not what we want. | 1396 #else |
| 1463 if (isRemote()) | 1397 bool is_remote = false; |
| 1464 return; | |
| 1465 #endif | 1398 #endif |
| 1399 bool is_backgrounded = |
| 1400 IsBackgroundedSuspendEnabled() && delegate_ && delegate_->IsHidden(); |
| 1401 PlayState state = |
| 1402 UpdatePlayState_ComputePlayState(is_remote, is_backgrounded); |
| 1403 SetDelegateState(state.delegate_state); |
| 1404 SetMemoryReportingState(state.is_memory_reporting_enabled); |
| 1405 SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_); |
| 1406 } |
| 1466 | 1407 |
| 1467 // NotifyPlaybackStarted() may be called by interactions while suspended, | 1408 void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) { |
| 1468 // (play/pause in particular). Those actions won't have any effect until the | 1409 if (!delegate_ || delegate_state_ == new_state) |
| 1469 // pipeline is resumed. | |
| 1470 // TODO(dalecurtis): Should these be dropped at the call sites instead? | |
| 1471 // Alternatively, rename this method to include Maybe or Changed, and handle | |
| 1472 // multiple calls safely. | |
| 1473 if (pipeline_controller_.IsSuspended()) | |
| 1474 return; | 1410 return; |
| 1475 | 1411 |
| 1476 if (delegate_) { | 1412 delegate_state_ = new_state; |
| 1477 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, | 1413 |
| 1478 pipeline_.GetMediaDuration()); | 1414 switch (delegate_state_) { |
| 1415 case DelegateState::GONE: |
| 1416 delegate_->PlayerGone(delegate_id_); |
| 1417 break; |
| 1418 case DelegateState::PLAYING: |
| 1419 delegate_->DidPlay(delegate_id_, hasVideo(), hasAudio(), false, |
| 1420 pipeline_.GetMediaDuration()); |
| 1421 break; |
| 1422 case DelegateState::PAUSED: |
| 1423 delegate_->DidPause(delegate_id_, false); |
| 1424 break; |
| 1425 case DelegateState::ENDED: |
| 1426 delegate_->DidPause(delegate_id_, true); |
| 1427 break; |
| 1479 } | 1428 } |
| 1480 if (!memory_usage_reporting_timer_.IsRunning()) { | 1429 } |
| 1430 |
| 1431 void WebMediaPlayerImpl::SetMemoryReportingState( |
| 1432 bool is_memory_reporting_enabled) { |
| 1433 if (memory_usage_reporting_timer_.IsRunning() == |
| 1434 is_memory_reporting_enabled) { |
| 1435 return; |
| 1436 } |
| 1437 |
| 1438 if (is_memory_reporting_enabled) { |
| 1481 memory_usage_reporting_timer_.Start(FROM_HERE, | 1439 memory_usage_reporting_timer_.Start(FROM_HERE, |
| 1482 base::TimeDelta::FromSeconds(2), this, | 1440 base::TimeDelta::FromSeconds(2), this, |
| 1483 &WebMediaPlayerImpl::ReportMemoryUsage); | 1441 &WebMediaPlayerImpl::ReportMemoryUsage); |
| 1442 } else { |
| 1443 memory_usage_reporting_timer_.Stop(); |
| 1444 ReportMemoryUsage(); |
| 1484 } | 1445 } |
| 1485 } | 1446 } |
| 1486 | 1447 |
| 1487 void WebMediaPlayerImpl::NotifyPlaybackPaused() { | 1448 void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) { |
| 1488 #if defined(OS_ANDROID) // WMPI_CAST | 1449 // Do not change the state after an error has occurred. |
| 1489 if (isRemote()) | 1450 // TODO(sandersd): Update PipelineController to remove the need for this. |
| 1490 return; | 1451 if (IsNetworkStateError(network_state_)) |
| 1491 #endif | |
| 1492 | |
| 1493 // Same as above, NotifyPlaybackPaused() may be called by interactions while | |
| 1494 // suspended, but those actions won't have any effect until the pipeline is | |
| 1495 // resumed. | |
| 1496 if (pipeline_controller_.IsSuspended()) | |
| 1497 return; | 1452 return; |
| 1498 | 1453 |
| 1499 if (delegate_) | 1454 if (is_suspended) { |
| 1500 delegate_->DidPause(delegate_id_, ended_); | 1455 pipeline_controller_.Suspend(); |
| 1501 memory_usage_reporting_timer_.Stop(); | 1456 } else { |
| 1502 ReportMemoryUsage(); | 1457 pipeline_controller_.Resume(); |
| 1458 } |
| 1459 } |
| 1460 |
| 1461 WebMediaPlayerImpl::PlayState |
| 1462 WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote, |
| 1463 bool is_backgrounded) { |
| 1464 PlayState result; |
| 1465 |
| 1466 // This includes both data source (before pipeline startup) and pipeline |
| 1467 // errors. |
| 1468 bool has_error = IsNetworkStateError(network_state_); |
| 1469 |
| 1470 // After HaveMetadata, we know which tracks are present and the duration. |
| 1471 bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata; |
| 1472 |
| 1473 // After HaveFutureData, Blink will call play() if the state is not paused. |
| 1474 bool have_future_data = |
| 1475 highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData; |
| 1476 |
| 1477 // Background suspend is not enabled for audio-only players. |
| 1478 bool background_suspended = is_backgrounded && have_metadata && hasVideo(); |
| 1479 |
| 1480 // Idle suspend is enabled once there is future data. We don't want to idle |
| 1481 // suspend before that because play() may never be triggered to leave the idle |
| 1482 // state. There could be other theoretical problems if the page is waiting for |
| 1483 // other events before actually calling play(), but at least we don't break |
| 1484 // Blink. |
| 1485 // |
| 1486 // TODO(sandersd): Make the delegate suspend idle players immediately when |
| 1487 // hidden. |
| 1488 // TODO(sandersd): If Blink told us the paused state sooner, we could |
| 1489 // idle suspend sooner. |
| 1490 bool idle_suspended = is_idle_ && have_future_data; |
| 1491 |
| 1492 // Combined suspend state. |
| 1493 result.is_suspended = |
| 1494 is_remote || must_suspend_ || idle_suspended || background_suspended; |
| 1495 |
| 1496 // We do not treat |playback_rate_| == 0 as paused. For the media session, |
| 1497 // being paused implies displaying a play button, which is incorrect in this |
| 1498 // case. For memory usage reporting, we just use the same definition (but we |
| 1499 // don't have to). |
| 1500 // |
| 1501 // Similarly, we don't consider |ended_| to be paused. Blink will immediately |
| 1502 // call pause() or seek(), so |ended_| should not affect the computation. |
| 1503 // Despite that, |ended_| does result in a separate paused state, to simplfy |
| 1504 // the contract for SetDelegateState(). |
| 1505 // |
| 1506 // |has_session| is used to decide when to create a media session. Idle |
| 1507 // suspension does not destroy the media session, because we expect that the |
| 1508 // notification controls (and audio focus) remain. We also require: |
| 1509 // - |have_metadata|, since the tracks and duration are passed to DidPlay(). |
| 1510 // - |have_future_data|, since we need to know whether we are paused to |
| 1511 // correctly configure the session. |
| 1512 // |
| 1513 // TODO(sandersd): If Blink told us the paused state sooner, we could create |
| 1514 // the media session sooner. |
| 1515 bool can_play = !has_error && !is_remote && have_future_data; |
| 1516 bool has_session = can_play && !must_suspend_ && !background_suspended; |
| 1517 |
| 1518 if (!has_session) { |
| 1519 result.delegate_state = DelegateState::GONE; |
| 1520 } else if (paused_) { |
| 1521 // TODO(sandersd): There should be a paused+seeking state, during which |
| 1522 // the idle timer is disabled. Without that, idle suspending before or |
| 1523 // during seeking will have bad results. |
| 1524 result.delegate_state = |
| 1525 ended_ ? DelegateState::ENDED : DelegateState::PAUSED; |
| 1526 } else { |
| 1527 result.delegate_state = DelegateState::PLAYING; |
| 1528 } |
| 1529 |
| 1530 // It's not critical if some cases where memory usage can change are missed, |
| 1531 // since media memory changes are usually gradual. |
| 1532 result.is_memory_reporting_enabled = |
| 1533 can_play && !result.is_suspended && !paused_; |
| 1534 |
| 1535 return result; |
| 1503 } | 1536 } |
| 1504 | 1537 |
| 1505 void WebMediaPlayerImpl::ReportMemoryUsage() { | 1538 void WebMediaPlayerImpl::ReportMemoryUsage() { |
| 1506 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 1539 DCHECK(main_task_runner_->BelongsToCurrentThread()); |
| 1507 | 1540 |
| 1508 // About base::Unretained() usage below: We destroy |demuxer_| on the main | 1541 // About base::Unretained() usage below: We destroy |demuxer_| on the main |
| 1509 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the | 1542 // thread. Before that, however, ~WebMediaPlayerImpl() posts a task to the |
| 1510 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task | 1543 // media thread and waits for it to finish. Hence, the GetMemoryUsage() task |
| 1511 // posted here must finish earlier. | 1544 // posted here must finish earlier. |
| 1512 | 1545 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1535 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage | 1568 DVLOG(2) << "Memory Usage -- Audio: " << stats.audio_memory_usage |
| 1536 << ", Video: " << stats.video_memory_usage << ", DataSource: " | 1569 << ", Video: " << stats.video_memory_usage << ", DataSource: " |
| 1537 << (data_source_ ? data_source_->GetMemoryUsage() : 0) | 1570 << (data_source_ ? data_source_->GetMemoryUsage() : 0) |
| 1538 << ", Demuxer: " << demuxer_memory_usage; | 1571 << ", Demuxer: " << demuxer_memory_usage; |
| 1539 | 1572 |
| 1540 const int64_t delta = current_memory_usage - last_reported_memory_usage_; | 1573 const int64_t delta = current_memory_usage - last_reported_memory_usage_; |
| 1541 last_reported_memory_usage_ = current_memory_usage; | 1574 last_reported_memory_usage_ = current_memory_usage; |
| 1542 adjust_allocated_memory_cb_.Run(delta); | 1575 adjust_allocated_memory_cb_.Run(delta); |
| 1543 } | 1576 } |
| 1544 | 1577 |
| 1545 bool WebMediaPlayerImpl::IsAutomaticResumeAllowed() { | |
| 1546 #if defined(OS_ANDROID) | |
| 1547 return !hasVideo() || (delegate_ && !delegate_->IsHidden()); | |
| 1548 #else | |
| 1549 // On non-Android platforms Resume() is always allowed. | |
| 1550 return true; | |
| 1551 #endif | |
| 1552 } | |
| 1553 | |
| 1554 } // namespace media | 1578 } // namespace media |
| OLD | NEW |