Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Unified Diff: media/blink/webmediaplayer_impl.cc

Issue 2490783002: Refactor WebMediaPlayerDelegate interface. (Closed)
Patch Set: Update WMPA properly. Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/blink/webmediaplayer_impl.cc
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
index 578f7ede2799893f4ea63ba1b0b3006fefdff25e..7b761c23a6bc64b5baec5b6d55ae6df7757ab883 100644
--- a/media/blink/webmediaplayer_impl.cc
+++ b/media/blink/webmediaplayer_impl.cc
@@ -181,9 +181,6 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
linked_ptr<UrlIndex> url_index,
const WebMediaPlayerParams& params)
: frame_(frame),
- delegate_state_(DelegateState::GONE),
- is_idle_(false),
- must_suspend_(false),
network_state_(WebMediaPlayer::NetworkStateEmpty),
ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
highest_ready_state_(WebMediaPlayer::ReadyStateHaveNothing),
@@ -240,6 +237,7 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
use_fallback_path_(false),
is_encrypted_(false),
underflow_count_(0),
+ preroll_attempt_pending_(false),
observer_(params.media_observer()) {
DCHECK(!adjust_allocated_memory_cb_.is_null());
DCHECK(renderer_factory_);
@@ -253,8 +251,10 @@ WebMediaPlayerImpl::WebMediaPlayerImpl(
disable_fullscreen_video_overlays_ =
!base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo);
- if (delegate_)
+ if (delegate_) {
delegate_id_ = delegate_->AddObserver(this);
+ delegate_->SetIdle(delegate_id_, true);
+ }
media_log_->AddEvent(
media_log_->CreateEvent(MediaLogEvent::WEBMEDIAPLAYER_CREATED));
@@ -421,8 +421,10 @@ void WebMediaPlayerImpl::play() {
return;
}
#endif
+ // TODO(sandersd): Do we want to reset the idle timer here?
+ if (delegate_)
+ delegate_->SetIdle(delegate_id_, false);
paused_ = false;
- is_idle_ = false;
pipeline_.SetPlaybackRate(playback_rate_);
background_pause_timer_.Stop();
@@ -517,11 +519,11 @@ void WebMediaPlayerImpl::DoSeek(base::TimeDelta time, bool time_updated) {
if (watch_time_reporter_)
watch_time_reporter_->OnSeeking();
- // TODO(sandersd): Ideally we would not clear the idle state if
- // |pipeline_controller_| can elide the seek.
- is_idle_ = false;
+ // TODO(sandersd): Move |seeking_| to PipelineController.
+ // TODO(sandersd): Do we want to reset the idle timer here?
+ if (delegate_)
+ delegate_->SetIdle(delegate_id_, false);
ended_ = false;
-
seeking_ = true;
seek_time_ = time;
if (paused_)
@@ -788,6 +790,25 @@ blink::WebTimeRanges WebMediaPlayerImpl::seekable() const {
return blink::WebTimeRanges(&seekable_range, 1);
}
+bool WebMediaPlayerImpl::IsPrerollAttemptNeeded() {
+ // TODO(sandersd): Replace with |highest_ready_state_since_seek_| if we need
+ // to ensure that preroll always gets a chance to complete.
+ if (highest_ready_state_ >= ReadyState::ReadyStateHaveFutureData)
+ return false;
+
+ if (preroll_attempt_pending_)
+ return true;
+
+ // Freshly initialized; there has never been any loading progress. (Otherwise
+ // |preroll_attempt_pending_| would be true when the start time is null.)
+ if (preroll_attempt_start_time_.is_null())
+ return false;
+
+ base::TimeDelta preroll_attempt_duration =
+ tick_clock_->NowTicks() - preroll_attempt_start_time_;
+ return preroll_attempt_duration < kLoadingToIdleTimeout;
+}
+
bool WebMediaPlayerImpl::didLoadingProgress() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
@@ -796,19 +817,22 @@ bool WebMediaPlayerImpl::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;
+ if (did_loading_progress &&
+ highest_ready_state_ < ReadyState::ReadyStateHaveFutureData) {
+ // Reset the preroll attempt clock.
+ preroll_attempt_pending_ = true;
+ preroll_attempt_start_time_ = base::TimeTicks();
+
+ // Clear any 'stale' flag and give the pipeline a chance to resume. If we
+ // are already resumed, this will cause |preroll_attempt_start_time_| to be
+ // set.
+ // TODO(sandersd): Should this be on the same stack? It might be surprsing
tguilbert 2016/12/15 22:01:06 Typo: surprising
sandersd (OOO until July 31) 2017/01/05 23:12:21 Done.
+ // that didLoadingProgress() can synchronously change state.
+ if (delegate_)
+ delegate_->ClearStaleFlag(delegate_id_);
UpdatePlayState();
}
- if (did_loading_progress)
- last_time_loading_progressed_ = tick_clock_->NowTicks();
-
return did_loading_progress;
}
@@ -1201,8 +1225,10 @@ void WebMediaPlayerImpl::OnBufferingStateChange(BufferingState state) {
data_source_->OnBufferingHaveEnough(false);
// Blink expects a timeChanged() in response to a seek().
- if (should_notify_time_changed_)
+ if (should_notify_time_changed_) {
+ should_notify_time_changed_ = false;
client_->timeChanged();
+ }
// Once we have enough, start reporting the total memory usage. We'll also
// report once playback starts.
@@ -1318,7 +1344,7 @@ void WebMediaPlayerImpl::OnVideoOpacityChange(bool opaque) {
video_weblayer_->layer()->SetContentsOpaque(opaque_);
}
-void WebMediaPlayerImpl::OnHidden() {
+void WebMediaPlayerImpl::OnFrameHidden() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
if (IsBackgroundVideoTrackOptimizationEnabled())
@@ -1334,8 +1360,15 @@ void WebMediaPlayerImpl::OnHidden() {
ScheduleIdlePauseTimer();
}
-void WebMediaPlayerImpl::OnShown() {
+void WebMediaPlayerImpl::OnFrameClosed() {
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
+ UpdatePlayState();
+}
+
+void WebMediaPlayerImpl::OnFrameShown() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
+ background_pause_timer_.Stop();
+
if (watch_time_reporter_)
watch_time_reporter_->OnShown();
@@ -1345,43 +1378,21 @@ void WebMediaPlayerImpl::OnShown() {
selectedVideoTrackChanged(&trackId);
}
- must_suspend_ = false;
- background_pause_timer_.Stop();
-
UpdatePlayState();
}
-bool WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) {
+bool WebMediaPlayerImpl::OnIdleTimeout() {
DCHECK(main_task_runner_->BelongsToCurrentThread());
+ if (IsPrerollAttemptNeeded())
+ return false;
- if (must_suspend) {
- must_suspend_ = true;
- UpdatePlayState();
- return true;
- }
-
- // If we're beyond HaveFutureData, we can safely suspend at any time.
- if (highest_ready_state_ >= WebMediaPlayer::ReadyStateHaveFutureData) {
- is_idle_ = true;
- UpdatePlayState();
- return true;
- }
-
- // Before HaveFutureData blink will not call play(), so we must be careful to
- // only suspend if we'll eventually receive an event that will trigger a
- // resume. If the last time loading progressed was a while ago, and we still
- // haven't reached HaveFutureData, we assume that we're waiting on more data
- // to continue pre-rolling. When that data is loaded the pipeline will be
- // resumed by didLoadingProgress().
- if (last_time_loading_progressed_.is_null() ||
- (tick_clock_->NowTicks() - last_time_loading_progressed_) >
- kLoadingToIdleTimeout) {
- is_idle_ = true;
- UpdatePlayState();
- return true;
- }
+ // Post the update as a task so that:
+ // 1) IsStale() returns true in UpdatePlayState().
+ // 2) We don't have to worry if we call SetIdle(false).
+ main_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&WebMediaPlayerImpl::UpdatePlayState, AsWeakPtr()));
- return false;
+ return true;
}
void WebMediaPlayerImpl::OnPlay() {
@@ -1724,43 +1735,33 @@ void WebMediaPlayerImpl::UpdatePlayState() {
bool is_backgrounded = IsBackgroundedSuspendEnabled() && IsHidden();
PlayState state = UpdatePlayState_ComputePlayState(
is_remote, is_streaming, is_suspended, is_backgrounded);
- SetDelegateState(state.delegate_state);
+ SetDelegateState(state.delegate_state, state.is_idle);
SetMemoryReportingState(state.is_memory_reporting_enabled);
SetSuspendState(state.is_suspended || pending_suspend_resume_cycle_);
}
-void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state) {
+void WebMediaPlayerImpl::SetDelegateState(DelegateState new_state,
+ bool is_idle) {
if (!delegate_)
return;
- if (delegate_state_ == new_state) {
- if (delegate_state_ != DelegateState::PLAYING ||
- autoplay_muted_ == client_->isAutoplayingMuted()) {
- return;
- }
- }
-
- delegate_state_ = new_state;
-
- switch (delegate_state_) {
+ switch (new_state) {
case DelegateState::GONE:
delegate_->PlayerGone(delegate_id_);
break;
case DelegateState::PLAYING: {
- autoplay_muted_ = client_->isAutoplayingMuted();
- bool has_audio = autoplay_muted_ ? false : hasAudio();
+ bool has_audio = hasAudio() && !client_->isAutoplayingMuted();
delegate_->DidPlay(
- delegate_id_, hasVideo(), has_audio, false,
+ delegate_id_, has_audio, hasVideo(),
media::DurationToMediaContentType(pipeline_.GetMediaDuration()));
break;
}
case DelegateState::PAUSED:
- delegate_->DidPause(delegate_id_, false);
- break;
- case DelegateState::ENDED:
- delegate_->DidPause(delegate_id_, true);
+ delegate_->DidPause(delegate_id_);
break;
}
+
+ delegate_->SetIdle(delegate_id_, is_idle);
}
void WebMediaPlayerImpl::SetMemoryReportingState(
@@ -1806,12 +1807,20 @@ void WebMediaPlayerImpl::SetSuspendState(bool is_suspended) {
can_suspend_state_ = CanSuspendState::YES;
#endif
- if (can_suspend_state_ == CanSuspendState::NO)
- return;
-
- if (is_suspended) {
+ if (is_suspended && can_suspend_state_ != CanSuspendState::NO) {
+ // If we were not resumed for long enough to satisfy the preroll attempt,
+ // reset the clock.
+ if (!preroll_attempt_pending_ && IsPrerollAttemptNeeded()) {
+ preroll_attempt_pending_ = true;
+ preroll_attempt_start_time_ = base::TimeTicks();
+ }
pipeline_controller_.Suspend();
} else {
+ // When resuming, start the preroll attempt clock.
+ if (preroll_attempt_pending_) {
+ preroll_attempt_pending_ = false;
+ preroll_attempt_start_time_ = tick_clock_->NowTicks();
+ }
pipeline_controller_.Resume();
}
}
@@ -1823,6 +1832,9 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
bool is_backgrounded) {
PlayState result;
+ bool must_suspend = delegate_->IsFrameClosed();
+ bool is_stale = delegate_->IsStale(delegate_id_);
+
// This includes both data source (before pipeline startup) and pipeline
// errors.
bool has_error = IsNetworkStateError(network_state_);
@@ -1841,11 +1853,11 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_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_ && delegate_->IsPlayingBackgroundVideo();
- bool background_suspended = !is_streaming && is_backgrounded_video &&
- !(can_play_backgrounded && is_background_playing);
+ hasAudio() &&
+ IsResumeBackgroundVideosEnabled() && delegate_ &&
+ delegate_->IsBackgroundVideoPlaybackAllowed();
+ bool background_suspended =
+ !is_streaming && is_backgrounded_video && !can_play_backgrounded;
bool background_pause_suspended =
!is_streaming && is_backgrounded && paused_ && have_future_data;
@@ -1856,16 +1868,16 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
// TODO(sandersd): Make the delegate suspend idle players immediately when
// hidden.
bool idle_suspended =
- !is_streaming && is_idle_ && paused_ && !seeking_ && !overlay_enabled_;
+ !is_streaming && is_stale && 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_|
+ // to HaveFutureData, we require |is_stale| to remain suspended. |is_stale|
// 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_;
+ (is_stale || have_future_data) && is_suspended && paused_ && !seeking_;
// Combined suspend state.
- result.is_suspended = is_remote || must_suspend_ || idle_suspended ||
+ result.is_suspended = is_remote || must_suspend || idle_suspended ||
background_suspended || background_pause_suspended ||
can_stay_suspended;
@@ -1889,30 +1901,34 @@ WebMediaPlayerImpl::UpdatePlayState_ComputePlayState(bool is_remote,
// TODO(sandersd): If Blink told us the paused state sooner, we could create
// the media session sooner.
bool can_play = !has_error && !is_remote && have_future_data;
- bool has_session_playing =
- can_play && !must_suspend_ && !background_suspended;
+ bool has_session_playing = can_play && !must_suspend && !background_suspended;
// |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_ &&
+ bool has_session_suspended = can_play && !must_suspend &&
background_suspended && can_play_backgrounded;
whywhat 2016/12/12 18:11:23 hm, I don't think background_suspended will ever b
sandersd (OOO until July 31) 2017/01/05 23:12:21 Original computation restored.
bool has_session = has_session_playing || has_session_suspended;
if (!has_session) {
result.delegate_state = DelegateState::GONE;
+ result.is_idle = delegate_ && delegate_->IsIdle(delegate_id_);
} else if (paused_ || has_session_suspended) {
+ // 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 =
- ended_ ? DelegateState::ENDED : DelegateState::PAUSED;
+ ended_ ? DelegateState::GONE : DelegateState::PAUSED;
+ result.is_idle = !seeking_;
} else {
result.delegate_state = DelegateState::PLAYING;
+ result.is_idle = false;
}
// It's not critical if some cases where memory usage can change are missed,
// since media memory changes are usually gradual.
result.is_memory_reporting_enabled =
- can_play && !result.is_suspended && !paused_;
+ can_play && !result.is_suspended && (!paused_ || seeking_);
return result;
}
@@ -1980,7 +1996,7 @@ void WebMediaPlayerImpl::CreateWatchTimeReporter() {
pipeline_metadata_.natural_size,
base::Bind(&GetCurrentTimeInternal, this)));
watch_time_reporter_->OnVolumeChange(volume_);
- if (IsHidden())
+ if (delegate_ && delegate_->IsFrameHidden())
watch_time_reporter_->OnHidden();
else
watch_time_reporter_->OnShown();
@@ -1989,7 +2005,7 @@ void WebMediaPlayerImpl::CreateWatchTimeReporter() {
bool WebMediaPlayerImpl::IsHidden() const {
DCHECK(main_task_runner_->BelongsToCurrentThread());
- return delegate_ && delegate_->IsHidden();
+ return delegate_ && delegate_->IsFrameHidden() && !delegate_->IsFrameClosed();
}
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698