| Index: media/blink/webmediaplayer_impl.cc
|
| diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
|
| index 1f3c5ee6e0ce8cf9e3fcf0c394bc33268d3ac46d..f8136f5e7c5c4853f762dd5ae8283231d9c6e1fd 100644
|
| --- a/media/blink/webmediaplayer_impl.cc
|
| +++ b/media/blink/webmediaplayer_impl.cc
|
| @@ -754,9 +754,23 @@ blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
|
|
|
| bool WebMediaPlayerImpl::didLoadingProgress() {
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
| - bool pipeline_progress = pipeline_.DidLoadingProgress();
|
| - bool data_progress = buffered_data_source_host_.DidLoadingProgress();
|
| - return pipeline_progress || data_progress;
|
| +
|
| + // Note: Separate variables used to ensure both methods are called every time.
|
| + const bool pipeline_progress = pipeline_.DidLoadingProgress();
|
| + const bool data_progress = buffered_data_source_host_.DidLoadingProgress();
|
| + const bool did_loading_progress = pipeline_progress || data_progress;
|
| +
|
| + // If we've idle suspended before reaching kHaveFutureData and loading has
|
| + // progressed we need to spin up the renderer and figure out if we have enough
|
| + // data yet; |client_| may be waiting on this signal to trigger playback. The
|
| + // idle timeout is long enough that this is a low-cost operation.
|
| + if (highest_ready_state_ < ReadyState::ReadyStateHaveFutureData &&
|
| + pipeline_controller_.IsSuspended() && did_loading_progress && is_idle_) {
|
| + is_idle_ = false;
|
| + UpdatePlayState();
|
| + }
|
| +
|
| + return did_loading_progress;
|
| }
|
|
|
| void WebMediaPlayerImpl::paint(blink::WebCanvas* canvas,
|
| @@ -1240,14 +1254,10 @@ void WebMediaPlayerImpl::OnShown() {
|
| void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
|
|
| - if (must_suspend) {
|
| + if (must_suspend)
|
| must_suspend_ = true;
|
| - } else {
|
| - // TODO(sandersd): Remove this when idleness is separate from play state.
|
| - if (delegate_state_ == DelegateState::PAUSED_BUT_NOT_IDLE)
|
| - return;
|
| + else
|
| is_idle_ = true;
|
| - }
|
|
|
| UpdatePlayState();
|
| }
|
| @@ -1567,7 +1577,13 @@ void WebMediaPlayerImpl::UpdatePlayState() {
|
| }
|
|
|
| void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
|
| - if (!delegate_ || delegate_state_ == new_state)
|
| + if (!delegate_)
|
| + return;
|
| +
|
| + // Dedupe state changes in the general case, but make an exception for gone
|
| + // since the delegate will use that information to decide when the idle timer
|
| + // should be fired.
|
| + if (delegate_state_ == new_state && new_state != DelegateState::GONE)
|
| return;
|
|
|
| delegate_state_ = new_state;
|
| @@ -1584,14 +1600,6 @@ void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
|
| case DelegateState::PAUSED:
|
| delegate_->DidPause(delegate_id_, false);
|
| break;
|
| - case DelegateState::PAUSED_BUT_NOT_IDLE:
|
| - // It doesn't really matter what happens when we enter this state, only
|
| - // that we reset the idle timer when leaving it.
|
| - //
|
| - // TODO(sandersd): Ideally the delegate would consider idleness and play
|
| - // state as orthogonal properties so that we could avoid this.
|
| - delegate_->DidPause(delegate_id_, false);
|
| - break;
|
| case DelegateState::ENDED:
|
| delegate_->DidPause(delegate_id_, true);
|
| break;
|
| @@ -1678,29 +1686,22 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
|
| delegate_ && delegate_->IsPlayingBackgroundVideo();
|
| bool background_suspended = is_backgrounded_video &&
|
| !(can_play_backgrounded && is_background_playing);
|
| + bool background_pause_suspended = is_backgrounded && paused_;
|
|
|
| - // The |paused_| state is not reliable until we |have_future_data|.
|
| - bool background_pause_suspended =
|
| - is_backgrounded && have_future_data && paused_;
|
| -
|
| - // Idle suspend is enabled once there is future data. We don't want to idle
|
| - // suspend before that because play() may never be triggered to leave the idle
|
| - // state. There could be other theoretical problems if the page is waiting for
|
| - // other events before actually calling play(), but at least we don't break
|
| - // Blink.
|
| - //
|
| // TODO(sandersd): Make the delegate suspend idle players immediately when
|
| // hidden.
|
| - // TODO(sandersd): If Blink told us the paused state sooner, we could
|
| - // idle suspend sooner.
|
| - bool idle_suspended = is_idle_ && have_future_data;
|
| + bool idle_suspended = is_idle_ && paused_ && !seeking_ && !overlay_enabled_;
|
| +
|
| + // If we're already suspended, see if we can wait for user interaction. Prior
|
| + // to HaveFutureData, we require |is_idle_| to remain suspended. |is_idle_|
|
| + // will be cleared when we receive data which may take us to HaveFutureData.
|
| + bool can_stay_suspended =
|
| + (is_idle_ || have_future_data) && is_suspended && paused_ && !seeking_;
|
|
|
| // Combined suspend state.
|
| - result.is_suspended =
|
| - is_remote || must_suspend_ || idle_suspended || background_suspended ||
|
| - background_pause_suspended ||
|
| - // If we're already suspended, see if we can wait for user interaction.
|
| - (is_suspended && have_future_data && paused_ && !seeking_);
|
| + result.is_suspended = is_remote || must_suspend_ || idle_suspended ||
|
| + background_suspended || background_pause_suspended ||
|
| + can_stay_suspended;
|
|
|
| // We do not treat |playback_rate_| == 0 as paused. For the media session,
|
| // being paused implies displaying a play button, which is incorrect in this
|
| @@ -1736,13 +1737,8 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
|
| if (!has_session) {
|
| result.delegate_state = DelegateState::GONE;
|
| } else if (paused_ || has_session_suspended) {
|
| - if (seeking() || overlay_enabled_) {
|
| - result.delegate_state = DelegateState::PAUSED_BUT_NOT_IDLE;
|
| - } else if (ended_) {
|
| - result.delegate_state = DelegateState::ENDED;
|
| - } else {
|
| - result.delegate_state = DelegateState::PAUSED;
|
| - }
|
| + result.delegate_state =
|
| + ended_ ? DelegateState::ENDED : DelegateState::PAUSED;
|
| } else {
|
| result.delegate_state = DelegateState::PLAYING;
|
| }
|
| @@ -1796,10 +1792,8 @@ void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
|
| }
|
|
|
| void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
|
| - // Only schedule the pause timer if we're playing and are suspended. We use
|
| - // delegate state as a proxy for suspended here since the suspension may be in
|
| - // flight at the time of this call.
|
| - if (paused_ || delegate_state_ != DelegateState::GONE)
|
| + // Only schedule the pause timer if we're playing and are suspended.
|
| + if (paused_ || !pipeline_controller_.IsSuspended())
|
| return;
|
|
|
| #if defined(OS_ANDROID)
|
|
|