OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef AutoplayExperimentHelper_h | 5 #ifndef AutoplayExperimentHelper_h |
6 #define AutoplayExperimentHelper_h | 6 #define AutoplayExperimentHelper_h |
7 | 7 |
8 #include "core/page/Page.h" | 8 #include "core/page/Page.h" |
9 #include "platform/Timer.h" | 9 #include "platform/Timer.h" |
10 #include "platform/geometry/IntRect.h" | 10 #include "platform/geometry/IntRect.h" |
11 | 11 |
12 namespace blink { | 12 namespace blink { |
13 class Document; | 13 class Document; |
14 class HTMLMediaElement; | 14 class HTMLMediaElement; |
15 class EventListener; | 15 class EventListener; |
| 16 class LayoutObject; |
| 17 class AutoplayExperimentTest; |
16 | 18 |
17 // These values are used for a histogram. Do not reorder. | 19 // These values are used for a histogram. Do not reorder. |
18 enum AutoplayMetrics { | 20 enum AutoplayMetrics { |
19 // Media element with autoplay seen. | 21 // Media element with autoplay seen. |
20 AutoplayMediaFound = 0, | 22 AutoplayMediaFound = 0, |
21 // Autoplay enabled and user stopped media play at any point. | 23 // Autoplay enabled and user stopped media play at any point. |
22 AutoplayPaused = 1, | 24 AutoplayPaused = 1, |
23 // Autoplay enabled but user bailed out on media play early. | 25 // Autoplay enabled but user bailed out on media play early. |
24 AutoplayBailout = 2, | 26 AutoplayBailout = 2, |
25 // Autoplay disabled but user manually started media. | 27 // Autoplay disabled but user manually started media. |
(...skipping 29 matching lines...) Expand all Loading... |
55 | 57 |
56 // play() failed to play due to gesture requirement. | 58 // play() failed to play due to gesture requirement. |
57 PlayMethodFailed = 10, | 59 PlayMethodFailed = 10, |
58 | 60 |
59 // Some play, whether user initiated or not, started. | 61 // Some play, whether user initiated or not, started. |
60 AnyPlaybackStarted = 11, | 62 AnyPlaybackStarted = 11, |
61 // Some play, whether user initiated or not, paused. | 63 // Some play, whether user initiated or not, paused. |
62 AnyPlaybackPaused = 12, | 64 AnyPlaybackPaused = 12, |
63 // Some playback, whether user initiated or not, bailed out early. | 65 // Some playback, whether user initiated or not, bailed out early. |
64 AnyPlaybackBailout = 13, | 66 AnyPlaybackBailout = 13, |
| 67 // Some playback, whether user initiated or not, played to completion. |
| 68 AnyPlaybackComplete = 14, |
| 69 |
| 70 // Number of audio elements detected that reach the resource fetch algorithm
. |
| 71 AnyAudioElement = 15, |
| 72 // Numer of video elements detected that reach the resource fetch algorithm. |
| 73 AnyVideoElement = 16, |
| 74 |
| 75 // User gesture was bypassed, and playback started, and media played to |
| 76 // completion without a user-initiated pause. |
| 77 AutoplayComplete = 17, |
| 78 |
| 79 // Autoplay started after the gesture requirement was removed by a |
| 80 // user gesture load(). |
| 81 GesturelessPlaybackEnabledByLoad = 18, |
| 82 |
| 83 // Gestureless playback started after the gesture requirement was removed |
| 84 // because src is media stream. |
| 85 GesturelessPlaybackEnabledByStream = 19, |
| 86 |
| 87 // Gestureless playback was started, but was never overridden. This |
| 88 // includes the case in which no gesture was ever required. |
| 89 GesturelessPlaybackNotOverridden = 20, |
| 90 |
| 91 // Gestureless playback was enabled by a user gesture play() call. |
| 92 GesturelessPlaybackEnabledByPlayMethod = 21, |
65 | 93 |
66 // This enum value must be last. | 94 // This enum value must be last. |
67 NumberOfAutoplayMetrics, | 95 NumberOfAutoplayMetrics, |
68 }; | 96 }; |
69 | 97 |
70 class AutoplayExperimentHelper final { | 98 class CORE_EXPORT AutoplayExperimentHelper final : |
71 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); | 99 public NoBaseWillBeGarbageCollectedFinalized<AutoplayExperimentHelper> { |
| 100 friend class AutoplayExperimentTest; |
| 101 |
72 public: | 102 public: |
73 explicit AutoplayExperimentHelper(HTMLMediaElement&); | 103 // For easier testing, collect all the things we care about here. |
| 104 class Client : public NoBaseWillBeGarbageCollectedFinalized<Client> { |
| 105 public: |
| 106 virtual ~Client() {} |
| 107 |
| 108 // HTMLMediaElement |
| 109 virtual double currentTime() const = 0; |
| 110 virtual double duration() const = 0; |
| 111 virtual bool ended() const = 0; |
| 112 virtual bool muted() const = 0; |
| 113 virtual void setMuted(bool) = 0; |
| 114 virtual void playInternal() = 0; |
| 115 virtual bool isUserGestureRequiredForPlay() const = 0; |
| 116 virtual void removeUserGestureRequirement() = 0; |
| 117 virtual void recordAutoplayMetric(AutoplayMetrics) = 0; |
| 118 virtual bool shouldAutoplay() = 0; |
| 119 virtual bool isHTMLVideoElement() const = 0; |
| 120 virtual bool isHTMLAudioElement() const = 0; |
| 121 |
| 122 // Document |
| 123 virtual bool isLegacyViewportType() = 0; |
| 124 virtual PageVisibilityState pageVisibilityState() const = 0; |
| 125 virtual String autoplayExperimentMode() const = 0; |
| 126 |
| 127 // LayoutObject |
| 128 virtual void setRequestPositionUpdates(bool) = 0; |
| 129 virtual IntRect absoluteBoundingBoxRect() const = 0; |
| 130 |
| 131 DEFINE_INLINE_VIRTUAL_TRACE() { } |
| 132 }; |
| 133 |
| 134 static PassOwnPtrWillBeRawPtr<AutoplayExperimentHelper> create(Client* clien
t) |
| 135 { |
| 136 return adoptPtrWillBeNoop(new AutoplayExperimentHelper(client)); |
| 137 } |
| 138 |
74 ~AutoplayExperimentHelper(); | 139 ~AutoplayExperimentHelper(); |
75 | 140 |
76 void becameReadyToPlay(); | 141 void becameReadyToPlay(); |
77 void playMethodCalled(); | 142 void playMethodCalled(); |
78 void pauseMethodCalled(); | 143 void pauseMethodCalled(); |
| 144 void loadMethodCalled(); |
79 void mutedChanged(); | 145 void mutedChanged(); |
80 void positionChanged(const IntRect&); | 146 void positionChanged(const IntRect&); |
81 void updatePositionNotificationRegistration(); | 147 void updatePositionNotificationRegistration(); |
| 148 void recordSandboxFailure(); |
| 149 void loadingStarted(); |
| 150 void playbackStarted(); |
| 151 void playbackStopped(); |
| 152 void initialPlayWithUserGesture(); |
82 | 153 |
| 154 // Clean up. For Oilpan, this means "early in HTMLMediaElement's dispose". |
| 155 // For non-Oilpan, just delete the object. |
| 156 void dispose(); |
| 157 |
| 158 // Remove the user gesture requirement, and record why. If there is no |
| 159 // gesture requirement, then this does nothing. |
| 160 void removeUserGestureRequirement(AutoplayMetrics); |
| 161 |
| 162 // Set the position to the current view's position, and |
83 void triggerAutoplayViewportCheckForTesting(); | 163 void triggerAutoplayViewportCheckForTesting(); |
84 | 164 |
85 enum Mode { | 165 enum Mode { |
86 // Do not enable the autoplay experiment. | 166 // Do not enable the autoplay experiment. |
87 ExperimentOff = 0, | 167 ExperimentOff = 0, |
88 // Enable gestureless autoplay for video elements. | 168 // Enable gestureless autoplay for video elements. |
89 ForVideo = 1 << 0, | 169 ForVideo = 1 << 0, |
90 // Enable gestureless autoplay for audio elements. | 170 // Enable gestureless autoplay for audio elements. |
91 ForAudio = 1 << 1, | 171 ForAudio = 1 << 1, |
92 // Restrict gestureless autoplay to media that is in a visible page. | 172 // Restrict gestureless autoplay to media that is in a visible page. |
93 IfPageVisible = 1 << 2, | 173 IfPageVisible = 1 << 2, |
94 // Restrict gestureless autoplay to media that is visible in | 174 // Restrict gestureless autoplay to media that is visible in |
95 // the viewport. | 175 // the viewport. |
96 IfViewport = 1 << 3, | 176 IfViewport = 1 << 3, |
97 // Restrict gestureless autoplay to audio-less or muted media. | 177 // Restrict gestureless autoplay to audio-less or muted media. |
98 IfMuted = 1 << 4, | 178 IfMuted = 1 << 4, |
99 // Restrict gestureless autoplay to sites which contain the | 179 // Restrict gestureless autoplay to sites which contain the |
100 // viewport tag. | 180 // viewport tag. |
101 IfMobile = 1 << 5, | 181 IfMobile = 1 << 5, |
102 // If gestureless autoplay is allowed, then mute the media before | 182 // If gestureless autoplay is allowed, then mute the media before |
103 // starting to play. | 183 // starting to play. |
104 PlayMuted = 1 << 6, | 184 PlayMuted = 1 << 6, |
105 }; | 185 }; |
106 | 186 |
107 DEFINE_INLINE_TRACE() | 187 DEFINE_INLINE_TRACE() { visitor->trace(m_client); } |
108 { | |
109 visitor->trace(m_element); | |
110 } | |
111 | 188 |
112 private: | 189 private: |
| 190 explicit AutoplayExperimentHelper(Client*); |
| 191 |
113 // Register to receive position updates, if we haven't already. If we | 192 // Register to receive position updates, if we haven't already. If we |
114 // have, then this does nothing. | 193 // have, then this does nothing. |
115 void registerForPositionUpdatesIfNeeded(); | 194 void registerForPositionUpdatesIfNeeded(); |
116 | 195 |
117 // Un-register for position updates, if we are currently registered. | 196 // Un-register for position updates, if we are currently registered. |
118 void unregisterForPositionUpdatesIfNeeded(); | 197 void unregisterForPositionUpdatesIfNeeded(); |
119 | 198 |
120 // Return true if any only if this player meets (most) of the eligibility | 199 // Return true if any only if this player meets (most) of the eligibility |
121 // requirements for the experiment to override the need for a user | 200 // requirements for the experiment to override the need for a user |
122 // gesture. This includes everything except the visibility test. | 201 // gesture. This includes everything except the visibility test. |
123 bool isEligible() const; | 202 bool isEligible() const; |
124 | 203 |
125 // Return false if and only if m_element is not visible, and we care | 204 // Return false if and only if m_element is not visible, and we care |
126 // that it must be visible. | 205 // that it must be visible. |
127 bool meetsVisibilityRequirements() const; | 206 bool meetsVisibilityRequirements() const; |
128 | 207 |
129 // Set the muted flag on the media if we're in an experiment mode that | 208 // Set the muted flag on the media if we're in an experiment mode that |
130 // requires it, else do nothing. | 209 // requires it, else do nothing. |
131 void muteIfNeeded(); | 210 void muteIfNeeded(); |
132 | 211 |
133 // Maybe override the requirement for a user gesture, and start playing | 212 // Maybe override the requirement for a user gesture, and start playing |
134 // autoplay media. Returns true if only if it starts playback. | 213 // autoplay media. Returns true if only if it starts playback. |
135 bool maybeStartPlaying(); | 214 bool maybeStartPlaying(); |
136 | 215 |
137 // Configure internal state to record that the autoplay experiment is | 216 // Configure internal state to record that the autoplay experiment is |
138 // going to start playback. This doesn't actually start playback, since | 217 // going to start playback. This doesn't actually start playback, since |
139 // there are several different cases. | 218 // there are several different cases. |
140 void prepareToPlay(AutoplayMetrics); | 219 void prepareToAutoplay(AutoplayMetrics); |
| 220 |
| 221 // Record that an attempt to play without a user gesture has happened. |
| 222 // This does not assume whether or not the play attempt will succeed. |
| 223 // This method takes no action after it is called once. |
| 224 void autoplayMediaEncountered(); |
| 225 |
| 226 // If we are about to enter a paused state, call this to record |
| 227 // autoplay metrics. |
| 228 void recordMetricsBeforePause(); |
141 | 229 |
142 // Process a timer for checking visibility. | 230 // Process a timer for checking visibility. |
143 void viewportTimerFired(Timer<AutoplayExperimentHelper>*); | 231 void viewportTimerFired(Timer<AutoplayExperimentHelper>*); |
144 | 232 |
145 // Return our media element's document. | 233 // Return our media element's document. |
146 Document& document() const; | 234 Document& document() const; |
147 | 235 |
148 HTMLMediaElement& element() const; | 236 Client& client() const; |
| 237 |
| 238 bool isUserGestureRequiredForPlay() const; |
149 | 239 |
150 inline bool enabled(Mode mode) const | 240 inline bool enabled(Mode mode) const |
151 { | 241 { |
152 return ((int)m_mode) & ((int)mode); | 242 return ((int)m_mode) & ((int)mode); |
153 } | 243 } |
154 | 244 |
155 Mode fromString(const String& mode); | 245 Mode fromString(const String& mode); |
156 | 246 |
157 RawPtrWillBeMember<HTMLMediaElement> m_element; | 247 void recordAutoplayMetric(AutoplayMetrics); |
| 248 |
| 249 // Could stopping at this point be considered a bailout of playback? |
| 250 // (as in, "The user really didn't want to play this"). |
| 251 bool isBailout() const; |
| 252 |
| 253 RawPtrWillBeMember<Client> m_client; |
158 | 254 |
159 Mode m_mode; | 255 Mode m_mode; |
160 | 256 |
161 // Autoplay experiment state. | 257 // Autoplay experiment state. |
162 // True if we've received a play() without a pause(). | 258 // True if we've received a play() without a pause(). |
163 bool m_playPending : 1; | 259 bool m_playPending : 1; |
164 | 260 |
165 // Are we registered with the view for position updates? | 261 // Are we registered with the view for position updates? |
166 bool m_registeredWithLayoutObject : 1; | 262 bool m_registeredWithLayoutObject : 1; |
167 | 263 |
168 // According to our last position update, are we in the viewport? | 264 // According to our last position update, are we in the viewport? |
169 bool m_wasInViewport : 1; | 265 bool m_wasInViewport : 1; |
170 | 266 |
| 267 // Have we counted this autoplay media in the metrics yet? This is set when |
| 268 // a media element tries to autoplay, and we record that via the |
| 269 // AutoplayMediaFound metric. |
| 270 bool m_autoplayMediaEncountered : 1; |
| 271 |
| 272 // Have we recorded a metric about the cause of the initial playback of |
| 273 // this media yet? |
| 274 bool m_playbackStartedMetricRecorded : 1; |
| 275 |
| 276 // Is the current playback the result of autoplay? If so, then this flag |
| 277 // records that the pause / stop should be counted in the autoplay metrics. |
| 278 bool m_waitingForAutoplayPlaybackEnd : 1; |
| 279 |
| 280 // Did we record that this media element exists in the metrics yet? This is |
| 281 // independent of whether it autoplays; we just want to know how many |
| 282 // elements exist for the Any{Audio|Video}Element metrics. |
| 283 bool m_recordedElement : 1; |
| 284 |
171 // According to our last position update, where was our element? | 285 // According to our last position update, where was our element? |
172 IntRect m_lastLocation; | 286 IntRect m_lastLocation; |
173 IntRect m_lastVisibleRect; | 287 IntRect m_lastVisibleRect; |
174 | 288 |
175 // When was m_lastLocation set? | 289 // When was m_lastLocation set? |
176 double m_lastLocationUpdateTime; | 290 double m_lastLocationUpdateTime; |
177 | 291 |
178 Timer<AutoplayExperimentHelper> m_viewportTimer; | 292 Timer<AutoplayExperimentHelper> m_viewportTimer; |
| 293 |
| 294 // Reason that autoplay would be allowed to proceed without a user gesture. |
| 295 AutoplayMetrics m_autoplayDeferredMetric; |
179 }; | 296 }; |
180 | 297 |
181 inline AutoplayExperimentHelper::Mode& operator|=(AutoplayExperimentHelper::Mode
& a, | 298 inline AutoplayExperimentHelper::Mode& operator|=(AutoplayExperimentHelper::Mode
& a, |
182 const AutoplayExperimentHelper::Mode& b) | 299 const AutoplayExperimentHelper::Mode& b) |
183 { | 300 { |
184 a = static_cast<AutoplayExperimentHelper::Mode>(static_cast<int>(a) | static
_cast<int>(b)); | 301 a = static_cast<AutoplayExperimentHelper::Mode>(static_cast<int>(a) | static
_cast<int>(b)); |
185 return a; | 302 return a; |
186 } | 303 } |
187 | 304 |
188 | |
189 } // namespace blink | 305 } // namespace blink |
190 | 306 |
191 #endif // AutoplayExperimentHelper_h | 307 #endif // AutoplayExperimentHelper_h |
OLD | NEW |