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