Chromium Code Reviews| 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) |
| { |