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

Unified Diff: third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp

Issue 1470153004: Autoplay experiment metric fixes and additions. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cl feedback Created 5 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: third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
index a06dc57a0eb3315f58a5bc6205000bc07364cb48..5f6a3a15545bf002c20257d65e8d66cb317f5962 100644
--- a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
@@ -31,8 +31,12 @@ AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element)
, m_playPending(false)
, m_registeredWithLayoutObject(false)
, m_wasInViewport(false)
+ , m_autoplayMediaCounted(false)
+ , m_initialPlayWithoutUserGesture(false)
+ , m_recordedElement(false)
, m_lastLocationUpdateTime(-std::numeric_limits<double>::infinity())
, m_viewportTimer(this, &AutoplayExperimentHelper::viewportTimerFired)
+ , m_autoplayDeferredMetric(GesturelessPlaybackUnknownReason)
{
if (document().settings()) {
m_mode = fromString(document().settings()->autoplayExperimentMode());
@@ -53,13 +57,16 @@ void AutoplayExperimentHelper::becameReadyToPlay()
{
// Assuming that we're eligible to override the user gesture requirement,
// either play if we meet the visibility checks, or install a listener
- // to wait for them to pass.
+ // to wait for them to pass. We do not actually start playback; our
+ // caller must do that.
if (isEligible()) {
if (meetsVisibilityRequirements())
- prepareToPlay(GesturelessPlaybackStartedByAutoplayFlagImmediately);
+ prepareToAutoplay(GesturelessPlaybackStartedByAutoplayFlagImmediately);
else
registerForPositionUpdatesIfNeeded();
}
+
+ autoplayMediaEncountered();
}
void AutoplayExperimentHelper::playMethodCalled()
@@ -70,22 +77,29 @@ void AutoplayExperimentHelper::playMethodCalled()
m_playPending = true;
if (!UserGestureIndicator::processingUserGesture()) {
-
if (isEligible()) {
// Remember that userGestureRequiredForPlay is required for
// us to be eligible for the experiment.
// If we are able to override the gesture requirement now, then
// do so. Otherwise, install an event listener if we need one.
if (meetsVisibilityRequirements()) {
- // Override the gesture and play.
- prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately);
+ // Override the gesture and assume that play() will succeed.
+ prepareToAutoplay(GesturelessPlaybackStartedByPlayMethodImmediately);
} else {
// Wait for viewport visibility.
registerForPositionUpdatesIfNeeded();
}
}
- } else if (element().isUserGestureRequiredForPlay()) {
+ // Now that we might have also overridden the gesture requirement,
+ // record the autoplay attempt.
+ autoplayMediaEncountered();
+ } else if (isUserGestureRequiredForPlay()) {
+ if (m_autoplayMediaCounted)
+ recordAutoplayMetric(AutoplayManualStart);
+ // Don't let future gestureless playbacks affect metrics.
+ m_autoplayMediaCounted = true;
+
unregisterForPositionUpdatesIfNeeded();
}
}
@@ -95,6 +109,24 @@ void AutoplayExperimentHelper::pauseMethodCalled()
// Don't try to autoplay, if we would have.
m_playPending = false;
unregisterForPositionUpdatesIfNeeded();
+
+ if (!element().paused())
+ recordMetricsBeforePause();
+}
+
+void AutoplayExperimentHelper::loadMethodCalled()
+{
+ if (!element().paused())
+ recordMetricsBeforePause();
+
+ if (UserGestureIndicator::processingUserGesture() && isUserGestureRequiredForPlay()) {
+ recordAutoplayMetric(AutoplayEnabledThroughLoad);
+ element().removeUserGestureRequirement(GesturelessPlaybackEnabledByLoad);
+ // While usergesture-initiated load()s technically count as autoplayed,
+ // they don't feel like such to the users and hence we don't want to
+ // count them for the purposes of metrics.
+ m_autoplayMediaCounted = true;
+ }
}
void AutoplayExperimentHelper::mutedChanged()
@@ -255,9 +287,13 @@ bool AutoplayExperimentHelper::maybeStartPlaying()
}
// Start playing!
- prepareToPlay(element().shouldAutoplay()
+ prepareToAutoplay(element().shouldAutoplay()
? GesturelessPlaybackStartedByAutoplayFlagAfterScroll
: GesturelessPlaybackStartedByPlayMethodAfterScroll);
+
+ // Record that this played without a user gesture.
+ autoplayMediaEncountered();
+
element().playInternal();
return true;
@@ -272,7 +308,7 @@ bool AutoplayExperimentHelper::isEligible() const
// This is what prevents us from starting playback more than once.
// Since this flag is never set to true once it's cleared, it will block
// the autoplay experiment forever.
- if (!element().isUserGestureRequiredForPlay())
+ if (!isUserGestureRequiredForPlay())
return false;
// Make sure that this is an element of the right type.
@@ -313,22 +349,21 @@ void AutoplayExperimentHelper::muteIfNeeded()
}
}
-void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric)
+void AutoplayExperimentHelper::prepareToAutoplay(AutoplayMetrics metric)
{
- element().recordAutoplayMetric(metric);
-
// This also causes !isEligible, so that we don't allow autoplay more than
// once. Be sure to do this before muteIfNeeded().
- element().removeUserGestureRequirement();
+ // Also note that, at this point, we know that we're goint to start
+ // playback. However, we still don't record the metric here. Instead,
+ // we let autoplayMediaEncountered() do that later.
+ element().removeUserGestureRequirement(metric);
+
+ // Don't bother to call autoplayMediaEncountered, since whoever initiates
+ // playback has do it anyway, in case we don't allow autoplay.
unregisterForPositionUpdatesIfNeeded();
muteIfNeeded();
- // Record that this autoplayed without a user gesture. This is normally
- // set when we discover an autoplay attribute, but we include all cases
- // where playback started without a user gesture, e.g., play().
- element().setInitialPlayWithoutUserGestures(true);
-
// Do not actually start playback here.
}
@@ -364,4 +399,104 @@ AutoplayExperimentHelper::Mode AutoplayExperimentHelper::fromString(const String
return value;
}
+void AutoplayExperimentHelper::autoplayMediaEncountered()
+{
+ if (!m_autoplayMediaCounted) {
+ m_autoplayMediaCounted = true;
+ recordAutoplayMetric(AutoplayMediaFound);
+
+ // If no user gesture was required, then assume that playback will
+ // actually start.
+ if (!isUserGestureRequiredForPlay()) {
+ m_initialPlayWithoutUserGesture = true;
+ recordAutoplayMetric(m_autoplayDeferredMetric);
+ }
+ }
+}
+
+void AutoplayExperimentHelper::initialPlayWithUserGesture()
+{
+ m_initialPlayWithoutUserGesture = false;
+}
+
+bool AutoplayExperimentHelper::isUserGestureRequiredForPlay() const
+{
+ return element().isUserGestureRequiredForPlay();
+}
+
+void AutoplayExperimentHelper::recordMetricsBeforePause()
+{
+ ASSERT(!element().paused());
+
+ 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 AutoplayExperimentHelper::playbackStarted()
+{
+ recordAutoplayMetric(AnyPlaybackStarted);
+}
+
+void AutoplayExperimentHelper::playbackEnded()
+{
+ recordAutoplayMetric(AnyPlaybackComplete);
+ if (m_initialPlayWithoutUserGesture) {
+ m_initialPlayWithoutUserGesture = false;
+ recordAutoplayMetric(AutoplayComplete);
+ }
+}
+
+void AutoplayExperimentHelper::recordAutoplayMetric(AutoplayMetrics metric)
+{
+ element().recordAutoplayMetric(metric);
+}
+
+bool AutoplayExperimentHelper::isBailout() const
+{
+ // We count the user as having bailed-out on the video if they watched
+ // less than one minute and less than 50% of it.
+ const double playedTime = element().currentTime();
+ const double progress = playedTime / element().duration();
+ return (playedTime < 60) && (progress < 0.5);
+}
+
+void AutoplayExperimentHelper::recordSandboxFailure()
+{
+ // We record autoplayMediaEncountered here because we know
+ // that the autoplay attempt will fail.
+ autoplayMediaEncountered();
+ recordAutoplayMetric(AutoplayDisabledBySandbox);
+}
+
+void AutoplayExperimentHelper::loadingStarted()
+{
+ if (m_recordedElement)
+ return;
+
+ m_recordedElement = true;
+ recordAutoplayMetric(element().isHTMLVideoElement()
+ ? AnyVideoElement : AnyAudioElement);
+}
+
+void AutoplayExperimentHelper::setGestureRemovalReason(AutoplayMetrics deferredMetric)
+{
+ m_autoplayDeferredMetric = deferredMetric;
+}
+
}

Powered by Google App Engine
This is Rietveld 408576698