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

Unified Diff: Source/core/html/HTMLMediaElement.cpp

Issue 1179223002: Implement autoplay gesture override experiment. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: fixed !autoplaying behavior + test. Created 5 years, 3 months 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: Source/core/html/HTMLMediaElement.cpp
diff --git a/Source/core/html/HTMLMediaElement.cpp b/Source/core/html/HTMLMediaElement.cpp
index ef4a05ad0d62be0329b56a7988629cce0241fb62..29a86fab5d351a6259f51afc3281ff921a8d588e 100644
--- a/Source/core/html/HTMLMediaElement.cpp
+++ b/Source/core/html/HTMLMediaElement.cpp
@@ -247,25 +247,7 @@ static bool canLoadURL(const KURL& url, const ContentType& contentType, const St
return false;
}
-// These values are used for a histogram. Do not reorder.
-enum AutoplayMetrics {
- // Media element with autoplay seen.
- AutoplayMediaFound = 0,
- // Autoplay enabled and user stopped media play at any point.
- AutoplayStopped = 1,
- // Autoplay enabled but user bailed out on media play early.
- AutoplayBailout = 2,
- // Autoplay disabled but user manually started media.
- AutoplayManualStart = 3,
- // Autoplay was (re)enabled through a user-gesture triggered load()
- AutoplayEnabledThroughLoad = 4,
- // Autoplay disabled by sandbox flags.
- AutoplayDisabledBySandbox = 5,
- // This enum value must be last.
- NumberOfAutoplayMetrics,
-};
-
-static void recordAutoplayMetric(AutoplayMetrics metric)
+void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric)
{
Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", metric, NumberOfAutoplayMetrics);
}
@@ -355,7 +337,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
, m_remoteRoutesAvailable(false)
, m_playingRemotely(false)
, m_isFinalizing(false)
- , m_initialPlayWithoutUserGestures(false)
+ , m_initialPlayWithoutUserGesture(false)
, m_autoplayMediaCounted(false)
, m_inOverlayFullscreenVideo(false)
, m_audioTracks(AudioTrackList::create(*this))
@@ -364,6 +346,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
#if ENABLE(WEB_AUDIO)
, m_audioSourceNode(nullptr)
#endif
+ , m_autoplayHelper(*this)
{
#if ENABLE(OILPAN)
ThreadState::current()->registerPreFinalizer(this);
@@ -382,6 +365,7 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
HTMLMediaElement::~HTMLMediaElement()
{
WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
+
#if !ENABLE(OILPAN)
// HTMLMediaElement and m_asyncEventQueue always become unreachable
// together. So HTMLMediaElement and m_asyncEventQueue are destructed in
@@ -691,12 +675,38 @@ String HTMLMediaElement::canPlayType(const String& mimeType, const String& keySy
return canPlay;
}
+void HTMLMediaElement::recordMetricsIfPausing()
+{
+ // If not playing, then nothing to record.
+ // TODO(liberato): test metrics. this was m_paused.
+ if (m_paused)
+ return;
+
+ const bool bailout = isBailout();
+
+ // Record that play was paused. We don't care if it was autoplay,
+ // play(), or the user manually started it.
+ recordAutoplayMetric(AnyPlaybackPaused);
+ if (bailout)
+ recordAutoplayMetric(AnyPlaybackBailout);
+
+ // If this was a gestureless play, then record that separately.
+ // These cover attr and play() gestureless starts.
+ if (m_initialPlayWithoutUserGesture) {
+ m_initialPlayWithoutUserGesture = false;
+
+ recordAutoplayMetric(AutoplayPaused);
+
+ if (bailout)
+ recordAutoplayMetric(AutoplayBailout);
+ }
+}
+
void HTMLMediaElement::load()
{
WTF_LOG(Media, "HTMLMediaElement::load(%p)", this);
- if (m_initialPlayWithoutUserGestures && m_playing)
- gesturelessInitialPlayHalted();
+ recordMetricsIfPausing();
if (UserGestureIndicator::processingUserGesture() && m_userGestureRequiredForPlay) {
recordAutoplayMetric(AutoplayEnabledThroughLoad);
@@ -1555,11 +1565,17 @@ void HTMLMediaElement::setReadyState(ReadyState state)
if (document().isSandboxed(SandboxAutomaticFeatures)) {
recordAutoplayMetric(AutoplayDisabledBySandbox);
- } else if (!m_userGestureRequiredForPlay) {
- m_paused = false;
- invalidateCachedTime();
- scheduleEvent(EventTypeNames::play);
- scheduleEvent(EventTypeNames::playing);
+ } else {
+ // If the autoplay experiment says that it's okay to play now,
+ // then don't require a user gesture.
+ m_autoplayHelper.becameReadyToPlay();
+
+ if (!m_userGestureRequiredForPlay) {
+ m_paused = false;
+ invalidateCachedTime();
+ scheduleEvent(EventTypeNames::play);
+ scheduleEvent(EventTypeNames::playing);
+ }
}
}
@@ -1692,7 +1708,7 @@ void HTMLMediaElement::seek(double time)
// 11 - Set the current playback position to the given new playback position.
webMediaPlayer()->seek(time);
- m_initialPlayWithoutUserGestures = false;
+ m_initialPlayWithoutUserGesture = false;
// 14-17 are handled, if necessary, when the engine signals a readystate change or otherwise
// satisfies seek completion and signals a time change.
@@ -1883,6 +1899,11 @@ bool HTMLMediaElement::autoplay() const
return fastHasAttribute(autoplayAttr);
}
+bool HTMLMediaElement::shouldAutoplay() const
+{
+ return m_autoplaying && autoplay();
philipj_slow 2015/09/04 09:24:27 Can you also add m_paused and the sandbox requirem
liberato (no reviews please) 2015/09/08 21:58:01 done. i just moved the metrics recording into sho
philipj_slow 2015/09/10 10:05:13 Did you forget to upload some changes? I can't see
liberato (no reviews please) 2015/09/10 14:52:27 this was applied to the branch with visibility che
+}
+
String HTMLMediaElement::preload() const
{
switch (preloadType()) {
@@ -1942,9 +1963,13 @@ void HTMLMediaElement::play()
{
WTF_LOG(Media, "HTMLMediaElement::play(%p)", this);
+ m_autoplayHelper.playMethodCalled();
+
if (!UserGestureIndicator::processingUserGesture()) {
autoplayMediaEncountered();
+
if (m_userGestureRequiredForPlay) {
+ recordAutoplayMetric(PlayMethodFailed);
String message = ExceptionMessages::failedToExecute("play", "HTMLMediaElement", "API can only be initiated by a user gesture.");
document().executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
return;
@@ -1998,25 +2023,17 @@ void HTMLMediaElement::autoplayMediaEncountered()
recordAutoplayMetric(AutoplayMediaFound);
if (!m_userGestureRequiredForPlay)
- m_initialPlayWithoutUserGestures = true;
+ m_initialPlayWithoutUserGesture = true;
}
}
-void HTMLMediaElement::gesturelessInitialPlayHalted()
+bool HTMLMediaElement::isBailout() const
{
- ASSERT(m_initialPlayWithoutUserGestures);
- m_initialPlayWithoutUserGestures = false;
-
- recordAutoplayMetric(AutoplayStopped);
-
// We count the user as having bailed-out on the video if they watched
// less than one minute and less than 50% of it.
- double playedTime = currentTime();
- if (playedTime < 60) {
- double progress = playedTime / duration();
- if (progress < 0.5)
- recordAutoplayMetric(AutoplayBailout);
- }
+ const double playedTime = currentTime();
+ const double progress = playedTime / duration();
+ return (playedTime < 60) && (progress < 0.5);
}
void HTMLMediaElement::pause()
@@ -2026,11 +2043,12 @@ void HTMLMediaElement::pause()
if (m_networkState == NETWORK_EMPTY)
scheduleDelayedAction(LoadMediaResource);
+ m_autoplayHelper.pauseMethodCalled();
+
m_autoplaying = false;
if (!m_paused) {
- if (m_initialPlayWithoutUserGestures)
- gesturelessInitialPlayHalted();
+ recordMetricsIfPausing();
m_paused = true;
scheduleTimeupdateEvent(false);
@@ -2123,6 +2141,8 @@ void HTMLMediaElement::setMuted(bool muted)
m_muted = muted;
+ m_autoplayHelper.mutedChanged();
+
updateVolume();
scheduleEvent(EventTypeNames::volumechange);
@@ -2754,6 +2774,7 @@ void HTMLMediaElement::timeChanged()
m_sentEndEvent = true;
scheduleEvent(EventTypeNames::ended);
}
+ recordMetricsIfPausing();
// If the media element has a current media controller, then report the controller state
// for the media element's current media controller.
updateMediaController();
@@ -2974,6 +2995,7 @@ void HTMLMediaElement::updatePlayState()
mediaControls()->playbackStarted();
startPlaybackProgressTimer();
m_playing = true;
+ recordAutoplayMetric(AnyPlaybackStarted);
} else { // Should not be playing right now
if (isPlaying)
@@ -3093,8 +3115,7 @@ void HTMLMediaElement::stop()
{
WTF_LOG(Media, "HTMLMediaElement::stop(%p)", this);
- if (m_playing && m_initialPlayWithoutUserGestures)
- gesturelessInitialPlayHalted();
+ recordMetricsIfPausing();
// Close the async event queue so that no events are enqueued by userCancelledLoad.
cancelPendingEventsAndCallbacks();
@@ -3708,6 +3729,21 @@ void HTMLMediaElement::selectInitialTracksIfNecessary()
videoTracks().anonymousIndexedGetter(0)->setSelected(true);
}
+bool HTMLMediaElement::isUserGestureRequiredForPlay() const
+{
+ return m_userGestureRequiredForPlay;
+}
+
+void HTMLMediaElement::removeUserGestureRequirement()
+{
+ m_userGestureRequiredForPlay = false;
+}
+
+void HTMLMediaElement::setInitialPlayWithoutUserGestures(bool value)
+{
+ m_initialPlayWithoutUserGesture = value;
+}
+
#if ENABLE(WEB_AUDIO)
void HTMLMediaElement::clearWeakMembers(Visitor* visitor)
{

Powered by Google App Engine
This is Rietveld 408576698