OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "config.h" |
| 6 #include "core/html/AutoplayExperimentHelper.h" |
| 7 |
| 8 #include "core/dom/Document.h" |
| 9 #include "core/frame/Settings.h" |
| 10 #include "core/html/HTMLMediaElement.h" |
| 11 #include "core/layout/LayoutBox.h" |
| 12 #include "core/layout/LayoutObject.h" |
| 13 #include "core/layout/LayoutVideo.h" |
| 14 #include "core/layout/LayoutView.h" |
| 15 #include "core/page/Page.h" |
| 16 #include "platform/Logging.h" |
| 17 #include "platform/UserGestureIndicator.h" |
| 18 #include "platform/geometry/IntRect.h" |
| 19 |
| 20 namespace blink { |
| 21 |
| 22 using namespace HTMLNames; |
| 23 |
| 24 AutoplayExperimentHelper::AutoplayExperimentHelper(HTMLMediaElement& element) |
| 25 : m_element(element) |
| 26 , m_mode(AutoplayExperimentConfig::Mode::Off) |
| 27 , m_playPending(false) |
| 28 { |
| 29 if (document().settings()) { |
| 30 m_mode = AutoplayExperimentConfig::fromString(document().settings()->aut
oplayExperimentMode()); |
| 31 |
| 32 if (m_mode != AutoplayExperimentConfig::Mode::Off) { |
| 33 WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to %d", |
| 34 m_mode); |
| 35 } |
| 36 } |
| 37 } |
| 38 |
| 39 AutoplayExperimentHelper::~AutoplayExperimentHelper() |
| 40 { |
| 41 } |
| 42 |
| 43 void AutoplayExperimentHelper::becameReadyToPlay() |
| 44 { |
| 45 // Assuming that we're eligible to override the user gesture requirement, |
| 46 // then play. |
| 47 if (isEligible()) { |
| 48 prepareToPlay(GesturelessPlaybackStartedByAutoplayFlagImmediately); |
| 49 } |
| 50 } |
| 51 |
| 52 void AutoplayExperimentHelper::playMethodCalled() |
| 53 { |
| 54 // Set the pending state, even if the play isn't going to be pending. |
| 55 // Eligibility can change if, for example, the mute status changes. |
| 56 // Having this set is okay. |
| 57 m_playPending = true; |
| 58 |
| 59 if (!UserGestureIndicator::processingUserGesture()) { |
| 60 |
| 61 if (isEligible()) { |
| 62 // Remember that userGestureRequiredForPlay is required for |
| 63 // us to be eligible for the experiment. |
| 64 // We are able to override the gesture requirement now, so |
| 65 // do so. |
| 66 prepareToPlay(GesturelessPlaybackStartedByPlayMethodImmediately); |
| 67 } |
| 68 |
| 69 } |
| 70 } |
| 71 |
| 72 void AutoplayExperimentHelper::pauseMethodCalled() |
| 73 { |
| 74 // Don't try to autoplay, if we would have. |
| 75 m_playPending = false; |
| 76 } |
| 77 |
| 78 void AutoplayExperimentHelper::mutedChanged() |
| 79 { |
| 80 // In other words, start playing if we just needed 'mute' to autoplay. |
| 81 maybeStartPlaying(); |
| 82 } |
| 83 |
| 84 bool AutoplayExperimentHelper::maybeStartPlaying() |
| 85 { |
| 86 // See if we're allowed to autoplay now. |
| 87 if (!isEligible()) { |
| 88 return false; |
| 89 } |
| 90 |
| 91 // Start playing! |
| 92 prepareToPlay(m_element.shouldAutoplay() |
| 93 ? GesturelessPlaybackStartedByAutoplayFlagAfterScroll |
| 94 : GesturelessPlaybackStartedByPlayMethodAfterScroll); |
| 95 m_element.playInternal(); |
| 96 |
| 97 return true; |
| 98 } |
| 99 |
| 100 bool AutoplayExperimentHelper::isEligible() const |
| 101 { |
| 102 // If no user gesture is required, then the experiment doesn't apply. |
| 103 // This is what prevents us from starting playback more than once. |
| 104 // Since this flag is never set to true once it's cleared, it will block |
| 105 // the autoplay experiment forever. |
| 106 if (!m_element.isUserGestureRequiredForPlay()) |
| 107 return false; |
| 108 |
| 109 if (m_mode == AutoplayExperimentConfig::Mode::Off) |
| 110 return false; |
| 111 |
| 112 // Make sure that this is an element of the right type. |
| 113 if (!enabled(AutoplayExperimentConfig::Mode::ForVideo) |
| 114 && isHTMLVideoElement(m_element)) |
| 115 return false; |
| 116 |
| 117 if (!enabled(AutoplayExperimentConfig::Mode::ForAudio) |
| 118 && isHTMLAudioElement(m_element)) |
| 119 return false; |
| 120 |
| 121 // If nobody has requested playback, either by the autoplay attribute or |
| 122 // a play() call, then do nothing. |
| 123 if (!m_playPending && !m_element.shouldAutoplay()) |
| 124 return false; |
| 125 |
| 126 // If the video is already playing, then do nothing. Note that there |
| 127 // is not a path where a user gesture is required but the video is |
| 128 // playing. However, we check for completeness. |
| 129 if (!m_element.paused()) |
| 130 return false; |
| 131 |
| 132 // Note that the viewport test always returns false on desktop, which is |
| 133 // why video-autoplay-experiment.html doesn't check -ifmobile . |
| 134 if (enabled(AutoplayExperimentConfig::Mode::IfMobile) |
| 135 && !document().viewportDescription().isLegacyViewportType()) |
| 136 return false; |
| 137 |
| 138 // If media is muted, then autoplay when it comes into view. |
| 139 if (enabled(AutoplayExperimentConfig::Mode::IfMuted)) |
| 140 return m_element.muted(); |
| 141 |
| 142 // Autoplay when it comes into view (if needed), maybe muted. |
| 143 return true; |
| 144 } |
| 145 |
| 146 void AutoplayExperimentHelper::muteIfNeeded() |
| 147 { |
| 148 if (enabled(AutoplayExperimentConfig::Mode::PlayMuted)) { |
| 149 ASSERT(!isEligible()); |
| 150 // If we are actually changing the muted state, then this will call |
| 151 // mutedChanged(). If isEligible(), then mutedChanged() will try |
| 152 // to start playback, which we should not do here. |
| 153 m_element.setMuted(true); |
| 154 } |
| 155 } |
| 156 |
| 157 void AutoplayExperimentHelper::prepareToPlay(AutoplayMetrics metric) |
| 158 { |
| 159 m_element.recordAutoplayMetric(metric); |
| 160 |
| 161 // This also causes !isEligible, so that we don't allow autoplay more than |
| 162 // once. Be sure to do this before muteIfNeeded(). |
| 163 m_element.removeUserGestureRequirement(); |
| 164 |
| 165 muteIfNeeded(); |
| 166 |
| 167 // Record that this autoplayed without a user gesture. This is normally |
| 168 // set when we discover an autoplay attribute, but we include all cases |
| 169 // where playback started without a user gesture, e.g., play(). |
| 170 m_element.setInitialPlayWithoutUserGestures(true); |
| 171 |
| 172 // Do not actually start playback here. |
| 173 } |
| 174 |
| 175 Document& AutoplayExperimentHelper::document() const |
| 176 { |
| 177 return m_element.document(); |
| 178 } |
| 179 |
| 180 } |
OLD | NEW |