| Index: media/blink/webmediaplayer_impl.cc
|
| diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
|
| index f8c8d24f13ce728929938606f35f67c547e7243d..a74a40db449f8c21587bad17f793e3d893eae07e 100644
|
| --- a/media/blink/webmediaplayer_impl.cc
|
| +++ b/media/blink/webmediaplayer_impl.cc
|
| @@ -63,6 +63,7 @@
|
| #include "third_party/WebKit/public/web/WebDocument.h"
|
| #include "third_party/WebKit/public/web/WebFrame.h"
|
| #include "third_party/WebKit/public/web/WebLocalFrame.h"
|
| +#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
|
| #include "third_party/WebKit/public/web/WebView.h"
|
|
|
| #if defined(OS_ANDROID)
|
| @@ -417,6 +418,10 @@ void WebMediaPlayerImpl::play() {
|
| DVLOG(1) << __func__;
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
|
|
| + // User initiated play unlocks background video playback.
|
| + if (blink::WebUserGestureIndicator::isProcessingUserGesture())
|
| + video_locked_when_paused_when_hidden_ = false;
|
| +
|
| #if defined(OS_ANDROID) // WMPI_CAST
|
| if (isRemote()) {
|
| cast_impl_.play();
|
| @@ -453,6 +458,10 @@ void WebMediaPlayerImpl::pause() {
|
| // No longer paused because it was hidden.
|
| paused_when_hidden_ = false;
|
|
|
| + // User initiated pause locks background videos.
|
| + if (blink::WebUserGestureIndicator::isProcessingUserGesture())
|
| + video_locked_when_paused_when_hidden_ = true;
|
| +
|
| #if defined(OS_ANDROID) // WMPI_CAST
|
| if (isRemote()) {
|
| cast_impl_.pause();
|
| @@ -1427,20 +1436,14 @@ void WebMediaPlayerImpl::OnVideoAverageKeyframeDistanceUpdate() {
|
| void WebMediaPlayerImpl::OnFrameHidden() {
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
|
|
| + // Backgrounding a video requires a user gesture to resume playback.
|
| + if (IsHidden())
|
| + video_locked_when_paused_when_hidden_ = true;
|
| +
|
| if (watch_time_reporter_)
|
| watch_time_reporter_->OnHidden();
|
|
|
| - // OnFrameHidden() can be called when frame is closed, then IsHidden() will
|
| - // return false, so check explicitly.
|
| - if (IsHidden()) {
|
| - if (ShouldPauseVideoWhenHidden()) {
|
| - PauseVideoIfNeeded();
|
| - return;
|
| - } else {
|
| - DisableVideoTrackIfNeeded();
|
| - }
|
| - }
|
| -
|
| + UpdateBackgroundVideoOptimizationState();
|
| UpdatePlayState();
|
|
|
| // Schedule suspended playing media to be paused if the user doesn't come back
|
| @@ -1457,6 +1460,9 @@ void WebMediaPlayerImpl::OnFrameShown() {
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
| background_pause_timer_.Stop();
|
|
|
| + // Foreground videos don't require user gesture to continue playback.
|
| + video_locked_when_paused_when_hidden_ = false;
|
| +
|
| if (watch_time_reporter_)
|
| watch_time_reporter_->OnShown();
|
|
|
| @@ -1475,14 +1481,14 @@ void WebMediaPlayerImpl::OnFrameShown() {
|
| base::Unretained(compositor_), new_processed_frame_cb));
|
| }
|
|
|
| + EnableVideoTrackIfNeeded();
|
| +
|
| if (paused_when_hidden_) {
|
| paused_when_hidden_ = false;
|
| OnPlay(); // Calls UpdatePlayState() so return afterwards.
|
| return;
|
| }
|
|
|
| - EnableVideoTrackIfNeeded();
|
| -
|
| UpdatePlayState();
|
| }
|
|
|
| @@ -1947,25 +1953,14 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
|
| // errors.
|
| bool has_error = IsNetworkStateError(network_state_);
|
|
|
| - // After HaveMetadata, we know which tracks are present and the duration.
|
| - bool have_metadata = ready_state_ >= WebMediaPlayer::ReadyStateHaveMetadata;
|
| -
|
| // After HaveFutureData, Blink will call play() if the state is not paused;
|
| // prior to this point |paused_| is not accurate.
|
| bool have_future_data =
|
| highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData;
|
|
|
| - // Background suspend is not enabled for audio-only players unless paused,
|
| - // though in the case of audio-only the session should be kept.
|
| - // Videos are not suspended if the user resumed the playback via the remote
|
| - // controls earlier and it's still playing.
|
| - bool is_backgrounded_video = is_backgrounded && have_metadata && hasVideo();
|
| - bool can_play_backgrounded = is_backgrounded_video && !is_remote &&
|
| - hasAudio() && IsResumeBackgroundVideosEnabled();
|
| - bool is_background_playing = delegate_->IsBackgroundVideoPlaybackUnlocked();
|
| - bool background_suspended = can_auto_suspend && is_backgrounded_video &&
|
| - !(can_play_backgrounded && is_background_playing);
|
| - bool background_pause_suspended =
|
| + // Background suspend is only enabled for paused players.
|
| + // In the case of players with audio the session should be kept.
|
| + bool background_suspended =
|
| can_auto_suspend && is_backgrounded && paused_ && have_future_data;
|
|
|
| // Idle suspension is allowed prior to have future data since there exist
|
| @@ -1985,8 +1980,7 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
|
|
|
| // Combined suspend state.
|
| result.is_suspended = is_remote || must_suspend || idle_suspended ||
|
| - background_suspended || background_pause_suspended ||
|
| - can_stay_suspended;
|
| + background_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
|
| @@ -1998,30 +1992,35 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
|
| // Despite that, |ended_| does result in a separate paused state, to simplfy
|
| // the contract for SetDelegateState().
|
| //
|
| - // |has_session| is used to decide when to create a media session. Idle
|
| + // |has_remote_controls| indicates if the player can be controlled outside the
|
| + // page (e.g. via the notification controls or by audio focus events). Idle
|
| // suspension does not destroy the media session, because we expect that the
|
| - // notification controls (and audio focus) remain. We also require:
|
| - // - |have_metadata|, since the tracks and duration are passed to DidPlay().
|
| + // notification controls (and audio focus) remain. The following must be true
|
| + // for the player to have remote controls:
|
| // - |have_future_data|, since we need to know whether we are paused to
|
| - // correctly configure the session.
|
| + // correctly configure the session and also because the tracks and
|
| + // duration are passed to DidPlay()
|
| + // - |is_remote| is false as remote players have their own controls
|
| + // - |has_error| is false player should have no errors
|
| + // - hasAudio() (requires |have_future_data|)
|
| //
|
| - // TODO(sandersd): If Blink told us the paused state sooner, we could create
|
| - // the media session sooner.
|
| + // TODO(sandersd): If Blink told us the paused state sooner, we could detect
|
| + // if the remote controls are available sooner.
|
| +
|
| + // Background videos with audio don't have remote controls if background
|
| + // suspend is enabled and resuming background videos is not (original Android
|
| + // behavior).
|
| + bool backgrounded_video_has_no_remote_controls =
|
| + IsBackgroundedSuspendEnabled() && !IsResumeBackgroundVideosEnabled() &&
|
| + is_backgrounded && hasVideo();
|
| bool can_play = !has_error && !is_remote && have_future_data;
|
| - bool has_session_playing = can_play && !must_suspend && !background_suspended;
|
| + bool has_remote_controls = can_play && !must_suspend && hasAudio() &&
|
| + !backgrounded_video_has_no_remote_controls;
|
|
|
| - // |has_session_suspended| means the player is suspended from the media
|
| - // element point of view but paused and can be resumed from the delegate point
|
| - // of view. Therefore it behaves like |paused_| for the delegate.
|
| - bool has_session_suspended = can_play && !must_suspend &&
|
| - background_suspended && can_play_backgrounded;
|
| -
|
| - bool has_session = has_session_playing || has_session_suspended;
|
| -
|
| - if (!has_session) {
|
| + if (!has_remote_controls) {
|
| result.delegate_state = DelegateState::GONE;
|
| result.is_idle = delegate_->IsIdle(delegate_id_);
|
| - } else if (paused_ || has_session_suspended) {
|
| + } else if (paused_) {
|
| // TODO(sandersd): Is it possible to have a suspended session, be ended,
|
| // and not be paused? If so we should be in a PLAYING state.
|
| result.delegate_state =
|
| @@ -2099,8 +2098,9 @@ void WebMediaPlayerImpl::FinishMemoryUsageReport(int64_t demuxer_memory_usage) {
|
| }
|
|
|
| void WebMediaPlayerImpl::ScheduleIdlePauseTimer() {
|
| - // Only schedule the pause timer if we're playing and are suspended.
|
| - if (paused_ || !pipeline_controller_.IsSuspended())
|
| + // Only schedule the pause timer if we're not paused or paused but going to
|
| + // resume when foregrounded, and are suspended.
|
| + if ((paused_ && !paused_when_hidden_) || !pipeline_controller_.IsSuspended())
|
| return;
|
|
|
| #if defined(OS_ANDROID)
|
| @@ -2148,14 +2148,26 @@ void WebMediaPlayerImpl::ActivateViewportIntersectionMonitoring(bool activate) {
|
| }
|
|
|
| bool WebMediaPlayerImpl::ShouldPauseVideoWhenHidden() const {
|
| -#if !defined(OS_ANDROID)
|
| - // On desktop, this behavior is behind the feature flag.
|
| - if (!IsBackgroundVideoTrackOptimizationEnabled())
|
| - return false;
|
| + // If suspending background video, pause any video that's not remoted or
|
| + // not unlocked to play in the background.
|
| + if (IsBackgroundedSuspendEnabled()) {
|
| + if (!hasVideo())
|
| + return false;
|
| +
|
| +#if defined(OS_ANDROID)
|
| + if (isRemote())
|
| + return false;
|
| #endif
|
|
|
| - // Pause video-only players that match the criteria for being optimized.
|
| - return !hasAudio() && IsBackgroundOptimizationCandidate();
|
| + return !hasAudio() ||
|
| + (IsResumeBackgroundVideosEnabled() &&
|
| + video_locked_when_paused_when_hidden_);
|
| + }
|
| +
|
| + // Otherwise only pause if the optimization is on and it's a video-only
|
| + // optimization candidate.
|
| + return IsBackgroundVideoTrackOptimizationEnabled() && !hasAudio() &&
|
| + IsBackgroundOptimizationCandidate();
|
| }
|
|
|
| bool WebMediaPlayerImpl::ShouldDisableVideoWhenHidden() const {
|
| @@ -2286,7 +2298,6 @@ void WebMediaPlayerImpl::ReportTimeFromForegroundToFirstFrame(
|
| time_to_first_frame);
|
| }
|
| }
|
| -
|
| void WebMediaPlayerImpl::SwitchRenderer(bool disable_pipeline_auto_suspend) {
|
| DCHECK(main_task_runner_->BelongsToCurrentThread());
|
| disable_pipeline_auto_suspend_ = disable_pipeline_auto_suspend;
|
|
|