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

Side by Side 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: Rebased. Created 5 years, 5 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 unified diff | Download patch
« no previous file with comments | « Source/core/html/HTMLMediaElement.h ('k') | Source/core/testing/Internals.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 121
122 #ifndef LOG_CACHED_TIME_WARNINGS 122 #ifndef LOG_CACHED_TIME_WARNINGS
123 // Default to not logging warnings about excessive drift in the cached media tim e because it adds a 123 // Default to not logging warnings about excessive drift in the cached media tim e because it adds a
124 // fair amount of overhead and logging. 124 // fair amount of overhead and logging.
125 #define LOG_CACHED_TIME_WARNINGS 0 125 #define LOG_CACHED_TIME_WARNINGS 0
126 #endif 126 #endif
127 127
128 // URL protocol used to signal that the media source API is being used. 128 // URL protocol used to signal that the media source API is being used.
129 static const char mediaSourceBlobProtocol[] = "blob"; 129 static const char mediaSourceBlobProtocol[] = "blob";
130 130
131 // How often do we poll for scrolling stopped during a visibility check?
132 static const double visibilityTimerPollDelay = 0.5;
133 // How long do we repeat visibility checks? We will poll once every PollDelay.
134 // Note that we will stop checking if we don't detect scrolling, also.
135 static const double visibilityCheckDuration = 5;
136
131 using namespace HTMLNames; 137 using namespace HTMLNames;
132 138
133 typedef WillBeHeapHashSet<RawPtrWillBeWeakMember<HTMLMediaElement>> WeakMediaEle mentSet; 139 typedef WillBeHeapHashSet<RawPtrWillBeWeakMember<HTMLMediaElement>> WeakMediaEle mentSet;
134 typedef WillBeHeapHashMap<RawPtrWillBeWeakMember<Document>, WeakMediaElementSet> DocumentElementSetMap; 140 typedef WillBeHeapHashMap<RawPtrWillBeWeakMember<Document>, WeakMediaElementSet> DocumentElementSetMap;
135 static DocumentElementSetMap& documentToElementSetMap() 141 static DocumentElementSetMap& documentToElementSetMap()
136 { 142 {
137 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<DocumentElementSetMap>, map, (ado ptPtrWillBeNoop(new DocumentElementSetMap()))); 143 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<DocumentElementSetMap>, map, (ado ptPtrWillBeNoop(new DocumentElementSetMap())));
138 return *map; 144 return *map;
139 } 145 }
140 146
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows 252 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows
247 // it cannot render. 253 // it cannot render.
248 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) { 254 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) {
249 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ()); 255 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ());
250 return supported > WebMimeRegistry::IsNotSupported; 256 return supported > WebMimeRegistry::IsNotSupported;
251 } 257 }
252 258
253 return false; 259 return false;
254 } 260 }
255 261
256 // These values are used for a histogram. Do not reorder. 262 void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric)
257 enum AutoplayMetrics {
258 // Media element with autoplay seen.
259 AutoplayMediaFound = 0,
260 // Autoplay enabled and user stopped media play at any point.
261 AutoplayStopped = 1,
262 // Autoplay enabled but user bailed out on media play early.
263 AutoplayBailout = 2,
264 // Autoplay disabled but user manually started media.
265 AutoplayManualStart = 3,
266 // Autoplay was (re)enabled through a user-gesture triggered load()
267 AutoplayEnabledThroughLoad = 4,
268 // Autoplay disabled by sandbox flags.
269 AutoplayDisabledBySandbox = 5,
270 // This enum value must be last.
271 NumberOfAutoplayMetrics,
272 };
273
274 static void recordAutoplayMetric(AutoplayMetrics metric)
275 { 263 {
276 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics); 264 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics);
277 } 265 }
278 266
279 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem) 267 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem)
280 { 268 {
281 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); 269 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs"));
282 270
283 if (!RuntimeEnabledFeatures::mediaEnabled()) 271 if (!RuntimeEnabledFeatures::mediaEnabled())
284 return WebMimeRegistry::IsNotSupported; 272 return WebMimeRegistry::IsNotSupported;
(...skipping 10 matching lines...) Expand all
295 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the 283 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the
296 // user agent knows it cannot render or is the type "application/octet-strea m" 284 // user agent knows it cannot render or is the type "application/octet-strea m"
297 if (type == "application/octet-stream") 285 if (type == "application/octet-stream")
298 return WebMimeRegistry::IsNotSupported; 286 return WebMimeRegistry::IsNotSupported;
299 287
300 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system); 288 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system);
301 } 289 }
302 290
303 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0; 291 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0;
304 292
293 class HTMLMediaElement::AutoplayExperimentTouchListener : public EventListener {
294 public:
295 AutoplayExperimentTouchListener(HTMLMediaElement* element) : EventListen er(CPPEventListenerType), m_element(element) { }
296 virtual bool operator==(const EventListener& them)
297 {
298 return &them == this;
299 }
300
301 void handleEvent(ExecutionContext*, Event*) override
302 {
303 if (m_element)
304 m_element->beginPeriodicVisibilityCheck();
305 }
306
307 private:
308 HTMLMediaElement* m_element;
309 };
310
305 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry) 311 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry)
306 { 312 {
307 ASSERT(!s_mediaStreamRegistry); 313 ASSERT(!s_mediaStreamRegistry);
308 s_mediaStreamRegistry = registry; 314 s_mediaStreamRegistry = registry;
309 } 315 }
310 316
311 bool HTMLMediaElement::isMediaStreamURL(const String& url) 317 bool HTMLMediaElement::isMediaStreamURL(const String& url)
312 { 318 {
313 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false; 319 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false;
314 } 320 }
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 , m_completelyLoaded(false) 362 , m_completelyLoaded(false)
357 , m_havePreparedToPlay(false) 363 , m_havePreparedToPlay(false)
358 , m_tracksAreReady(true) 364 , m_tracksAreReady(true)
359 , m_haveVisibleTextTrack(false) 365 , m_haveVisibleTextTrack(false)
360 , m_processingPreferenceChange(false) 366 , m_processingPreferenceChange(false)
361 , m_remoteRoutesAvailable(false) 367 , m_remoteRoutesAvailable(false)
362 , m_playingRemotely(false) 368 , m_playingRemotely(false)
363 , m_isFinalizing(false) 369 , m_isFinalizing(false)
364 , m_initialPlayWithoutUserGestures(false) 370 , m_initialPlayWithoutUserGestures(false)
365 , m_autoplayMediaCounted(false) 371 , m_autoplayMediaCounted(false)
372 , m_autoplayExperimentPlayPending(false)
373 , m_autoplayExperimentStartedByExperiment(false)
374 , m_autoplayExperimentMode(ExperimentOff)
366 , m_audioTracks(AudioTrackList::create(*this)) 375 , m_audioTracks(AudioTrackList::create(*this))
367 , m_videoTracks(VideoTrackList::create(*this)) 376 , m_videoTracks(VideoTrackList::create(*this))
368 , m_textTracks(nullptr) 377 , m_textTracks(nullptr)
369 #if ENABLE(WEB_AUDIO) 378 #if ENABLE(WEB_AUDIO)
370 , m_audioSourceNode(nullptr) 379 , m_audioSourceNode(nullptr)
371 #endif 380 #endif
381 , m_autoplayVisibilityTimer(this, &HTMLMediaElement::visibilityTimerFired)
382 , m_autoplayLastScrollX(std::numeric_limits<double>::quiet_NaN())
383 , m_autoplayLastScrollY(std::numeric_limits<double>::quiet_NaN())
384 , m_autoplayVisibilityTimerSpan(0)
372 { 385 {
373 #if ENABLE(OILPAN) 386 #if ENABLE(OILPAN)
374 ThreadState::current()->registerPreFinalizer(this); 387 ThreadState::current()->registerPreFinalizer(this);
375 #endif 388 #endif
376 ASSERT(RuntimeEnabledFeatures::mediaEnabled()); 389 ASSERT(RuntimeEnabledFeatures::mediaEnabled());
377 390
378 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this); 391 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this);
379 392
380 if (document.settings() && document.settings()->mediaPlaybackRequiresUserGes ture()) 393 if (document.settings()) {
381 m_userGestureRequiredForPlay = true; 394 if (document.settings()->mediaPlaybackRequiresUserGesture())
395 m_userGestureRequiredForPlay = true;
396
397 const String& autoplayMode = document.settings()->autoplayExperimentMode ();
398 if (autoplayMode == "always") {
399 m_autoplayExperimentMode = ExperimentAlways;
400 } else if (autoplayMode == "if-muted") {
401 m_autoplayExperimentMode = ExperimentIfMuted;
402 } else if (autoplayMode == "play-muted") {
403 m_autoplayExperimentMode = ExperimentPlayMuted;
404 }
405
406 if (m_autoplayExperimentMode != ExperimentOff) {
407 WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to '%s'",
408 autoplayMode.ascii().data());
409 }
410 }
382 411
383 setHasCustomStyleCallbacks(); 412 setHasCustomStyleCallbacks();
384 addElementToDocumentMap(this, &document); 413 addElementToDocumentMap(this, &document);
385 } 414 }
386 415
387 HTMLMediaElement::~HTMLMediaElement() 416 HTMLMediaElement::~HTMLMediaElement()
388 { 417 {
389 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this); 418 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
419
420 autoplayExperimentClearEventListenerIfNeeded();
421
390 #if !ENABLE(OILPAN) 422 #if !ENABLE(OILPAN)
391 // HTMLMediaElement and m_asyncEventQueue always become unreachable 423 // HTMLMediaElement and m_asyncEventQueue always become unreachable
392 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in 424 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in
393 // the same GC. We don't need to close it explicitly in Oilpan. 425 // the same GC. We don't need to close it explicitly in Oilpan.
394 m_asyncEventQueue->close(); 426 m_asyncEventQueue->close();
395 427
396 setShouldDelayLoadEvent(false); 428 setShouldDelayLoadEvent(false);
397 429
398 if (m_textTracks) 430 if (m_textTracks)
399 m_textTracks->clearOwner(); 431 m_textTracks->clearOwner();
(...skipping 1150 matching lines...) Expand 10 before | Expand all | Expand 10 after
1550 scheduleEvent(EventTypeNames::canplay); 1582 scheduleEvent(EventTypeNames::canplay);
1551 if (isPotentiallyPlaying) 1583 if (isPotentiallyPlaying)
1552 scheduleEvent(EventTypeNames::playing); 1584 scheduleEvent(EventTypeNames::playing);
1553 } 1585 }
1554 1586
1555 if (m_autoplaying && m_paused && autoplay()) { 1587 if (m_autoplaying && m_paused && autoplay()) {
1556 autoplayMediaEncountered(); 1588 autoplayMediaEncountered();
1557 1589
1558 if (document().isSandboxed(SandboxAutomaticFeatures)) { 1590 if (document().isSandboxed(SandboxAutomaticFeatures)) {
1559 recordAutoplayMetric(AutoplayDisabledBySandbox); 1591 recordAutoplayMetric(AutoplayDisabledBySandbox);
1560 } else if (!m_userGestureRequiredForPlay) { 1592 } else {
1561 m_paused = false; 1593 // If the autoplay experiment says that it's okay to play now,
1562 invalidateCachedTime(); 1594 // then don't require a user gesture.
1563 scheduleEvent(EventTypeNames::play); 1595 if (autoplayExperimentIsEligible()) {
1564 scheduleEvent(EventTypeNames::playing); 1596 if (autoplayExperimentIsVisible()) {
1597 autoplayExperimentPrepareToPlay(AutoplayExperimentStarte dByLoad);
1598 // Will play below.
1599 } else {
1600 // Wait for visibility checks to pass.
1601 autoplayExperimentInstallEventListenerIfNeeded();
1602 }
1603 }
1604
1605 if (!m_userGestureRequiredForPlay) {
1606 m_paused = false;
1607 invalidateCachedTime();
1608 scheduleEvent(EventTypeNames::play);
1609 scheduleEvent(EventTypeNames::playing);
1610 }
1565 } 1611 }
1566 } 1612 }
1567 1613
1568 scheduleEvent(EventTypeNames::canplaythrough); 1614 scheduleEvent(EventTypeNames::canplaythrough);
1569 1615
1570 shouldUpdateDisplayState = true; 1616 shouldUpdateDisplayState = true;
1571 } 1617 }
1572 1618
1573 if (shouldUpdateDisplayState) { 1619 if (shouldUpdateDisplayState) {
1574 updateDisplayState(); 1620 updateDisplayState();
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after
1955 2001
1956 WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const 2002 WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const
1957 { 2003 {
1958 return autoplay() ? WebMediaPlayer::PreloadAuto : preloadType(); 2004 return autoplay() ? WebMediaPlayer::PreloadAuto : preloadType();
1959 } 2005 }
1960 2006
1961 void HTMLMediaElement::play() 2007 void HTMLMediaElement::play()
1962 { 2008 {
1963 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this); 2009 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this);
1964 2010
2011 // Set the pending state, even if the play isn't going to be pending.
2012 // Eligibility can change if, for example, the mute status changes.
2013 // Having this set is okay.
2014 m_autoplayExperimentPlayPending = true;
2015
1965 if (!UserGestureIndicator::processingUserGesture()) { 2016 if (!UserGestureIndicator::processingUserGesture()) {
1966 autoplayMediaEncountered(); 2017 autoplayMediaEncountered();
2018
2019 if (autoplayExperimentIsEligible()) {
2020 // Remember that m_userGestureRequiredForPlay is required for
2021 // us to be eligible for the experiment.
2022 // If we are able to override the gesture requirement now, then
2023 // do so. Otherwise, install an event listener if we need one.
2024 if (autoplayExperimentIsVisible()) {
2025 // Override the gesture and play.
2026 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByPlay) ;
2027 } else {
2028 // Wait for visibility.
2029 autoplayExperimentInstallEventListenerIfNeeded();
2030 }
2031 }
2032
1967 if (m_userGestureRequiredForPlay) { 2033 if (m_userGestureRequiredForPlay) {
1968 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture."); 2034 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture.");
1969 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message)); 2035 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message));
1970 return; 2036 return;
1971 } 2037 }
1972 } else if (m_userGestureRequiredForPlay) { 2038 } else if (m_userGestureRequiredForPlay) {
1973 if (m_autoplayMediaCounted) 2039 if (m_autoplayMediaCounted)
1974 recordAutoplayMetric(AutoplayManualStart); 2040 recordAutoplayMetric(AutoplayManualStart);
1975 m_userGestureRequiredForPlay = false; 2041 m_userGestureRequiredForPlay = false;
2042 autoplayExperimentClearEventListenerIfNeeded();
1976 } 2043 }
1977 2044
1978 playInternal(); 2045 playInternal();
1979 } 2046 }
1980 2047
1981 void HTMLMediaElement::playInternal() 2048 void HTMLMediaElement::playInternal()
1982 { 2049 {
1983 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this); 2050 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this);
1984 2051
1985 // 4.8.10.9. Playing the media resource 2052 // 4.8.10.9. Playing the media resource
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2022 } 2089 }
2023 } 2090 }
2024 2091
2025 void HTMLMediaElement::gesturelessInitialPlayHalted() 2092 void HTMLMediaElement::gesturelessInitialPlayHalted()
2026 { 2093 {
2027 ASSERT(m_initialPlayWithoutUserGestures); 2094 ASSERT(m_initialPlayWithoutUserGestures);
2028 m_initialPlayWithoutUserGestures = false; 2095 m_initialPlayWithoutUserGestures = false;
2029 2096
2030 recordAutoplayMetric(AutoplayStopped); 2097 recordAutoplayMetric(AutoplayStopped);
2031 2098
2099 if (m_autoplayExperimentStartedByExperiment)
2100 recordAutoplayMetric(AutoplayExperimentStopped);
2101
2032 // We count the user as having bailed-out on the video if they watched 2102 // We count the user as having bailed-out on the video if they watched
2033 // less than one minute and less than 50% of it. 2103 // less than one minute and less than 50% of it.
2034 double playedTime = currentTime(); 2104 double playedTime = currentTime();
2035 if (playedTime < 60) { 2105 if (playedTime < 60) {
2036 double progress = playedTime / duration(); 2106 double progress = playedTime / duration();
2037 if (progress < 0.5) 2107 if (progress < 0.5) {
2038 recordAutoplayMetric(AutoplayBailout); 2108 recordAutoplayMetric(AutoplayBailout);
2109 // If this autoplay was started by the experiment, then record
2110 // that separately.
2111 if (m_autoplayExperimentStartedByExperiment)
2112 recordAutoplayMetric(AutoplayExperimentBailout);
2113 }
2039 } 2114 }
2040 } 2115 }
2041 2116
2042 void HTMLMediaElement::pause() 2117 void HTMLMediaElement::pause()
2043 { 2118 {
2044 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this); 2119 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this);
2045 2120
2046 if (m_networkState == NETWORK_EMPTY) 2121 if (m_networkState == NETWORK_EMPTY)
2047 scheduleDelayedAction(LoadMediaResource); 2122 scheduleDelayedAction(LoadMediaResource);
2048 2123
2124 // Don't try to autoplay, if we would have.
2125 m_autoplayExperimentPlayPending = false;
2126 autoplayExperimentClearEventListenerIfNeeded();
2127
2049 m_autoplaying = false; 2128 m_autoplaying = false;
2050 2129
2051 if (!m_paused) { 2130 if (!m_paused) {
2052 if (m_initialPlayWithoutUserGestures) 2131 if (m_initialPlayWithoutUserGestures)
2053 gesturelessInitialPlayHalted(); 2132 gesturelessInitialPlayHalted();
2054 2133
2055 m_paused = true; 2134 m_paused = true;
2056 scheduleTimeupdateEvent(false); 2135 scheduleTimeupdateEvent(false);
2057 scheduleEvent(EventTypeNames::pause); 2136 scheduleEvent(EventTypeNames::pause);
2058 } 2137 }
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
2134 return m_muted; 2213 return m_muted;
2135 } 2214 }
2136 2215
2137 void HTMLMediaElement::setMuted(bool muted) 2216 void HTMLMediaElement::setMuted(bool muted)
2138 { 2217 {
2139 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) ); 2218 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) );
2140 2219
2141 if (m_muted == muted) 2220 if (m_muted == muted)
2142 return; 2221 return;
2143 2222
2144 m_muted = muted; 2223 m_muted = muted;
liberato (no reviews please) 2015/07/27 06:03:09 @philipj: you are correct that we don't stop JS fr
2145 2224
2225 // If we are no longer eligible for the autoplay experiment, then also
2226 // quit listening for events. If we are eligible, and if we should be
2227 // playing, then start playing. In other words, start playing if
2228 // we just needed 'mute' to autoplay.
2229 if (!autoplayExperimentIsEligible()) {
2230 autoplayExperimentClearEventListenerIfNeeded();
2231 } else {
2232 // Try to play. If we can't, then install a visibility listener.
2233 if (!autoplayExperimentMaybeStartPlaying())
2234 autoplayExperimentInstallEventListenerIfNeeded();
2235 }
2236
2146 updateVolume(); 2237 updateVolume();
2147 2238
2148 scheduleEvent(EventTypeNames::volumechange); 2239 scheduleEvent(EventTypeNames::volumechange);
2149 } 2240 }
2150 2241
2151 void HTMLMediaElement::updateVolume() 2242 void HTMLMediaElement::updateVolume()
2152 { 2243 {
2153 if (webMediaPlayer()) 2244 if (webMediaPlayer())
2154 webMediaPlayer()->setVolume(effectiveMediaVolume()); 2245 webMediaPlayer()->setVolume(effectiveMediaVolume());
2155 2246
(...skipping 1632 matching lines...) Expand 10 before | Expand all | Expand 10 after
3788 { 3879 {
3789 visitor->trace(m_client); 3880 visitor->trace(m_client);
3790 } 3881 }
3791 3882
3792 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl) 3883 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl)
3793 { 3884 {
3794 visitor->trace(m_client); 3885 visitor->trace(m_client);
3795 } 3886 }
3796 #endif 3887 #endif
3797 3888
3889 void HTMLMediaElement::autoplayExperimentInstallEventListenerIfNeeded()
3890 {
3891 if (document().domWindow() && !m_autoplayExperimentTouchListener) {
3892 m_autoplayExperimentTouchListener = adoptRef(new AutoplayExperimentTouch Listener(this));
3893 // Listen for events that might show a user-initiated scroll. We
3894 // don't try to catch programmatic scrolls right now.
3895 document().domWindow()->addEventListener("touchend", m_autoplayExperimen tTouchListener, false);
3896 document().domWindow()->addEventListener("touchcancel", m_autoplayExperi mentTouchListener, false);
3897 }
3798 } 3898 }
3899
3900 void HTMLMediaElement::autoplayExperimentClearEventListenerIfNeeded()
3901 {
3902 if (m_autoplayExperimentTouchListener) {
3903 LocalDOMWindow* domWindow = document().domWindow();
3904 if (domWindow) {
3905 domWindow->removeEventListener("touchend", m_autoplayExperimentTouch Listener, false);
3906 domWindow->removeEventListener("touchcancel", m_autoplayExperimentTo uchListener, false);
3907 }
3908 // Either way, clear our ref.
3909 m_autoplayExperimentTouchListener.clear();
3910 }
3911 }
3912
3913 void HTMLMediaElement::beginPeriodicVisibilityCheck()
3914 {
3915 // Note that a visibility check might already be in progress.
3916 // Always reset the span of the checks to maximum.
3917 m_autoplayVisibilityTimerSpan = visibilityCheckDuration;
3918
3919 // If the timer isn't active, then fire the timer immediately to reset
3920 // it. We might just setOneShot(0).
3921 if (!m_autoplayVisibilityTimer.isActive()) {
3922 visibilityTimerFired(0);
3923 }
3924 }
3925
3926 void HTMLMediaElement::visibilityTimerFired(Timer<HTMLMediaElement>*)
3927 {
3928 const LocalDOMWindow* domWindow = document().domWindow();
3929 if (!domWindow)
3930 return;
3931
3932 const int currentScrollX = domWindow->scrollX();
3933 const int currentScrollY = domWindow->scrollY();
3934
3935 if (currentScrollX != m_autoplayLastScrollX
3936 || currentScrollY != m_autoplayLastScrollY) {
3937 // Still scrolling, so wait a bit more.
3938 m_autoplayLastScrollX = currentScrollX;
3939 m_autoplayLastScrollY = currentScrollY;
3940
3941 // Reset the timer to check again if we haven't tried for long enough.
3942 m_autoplayVisibilityTimerSpan -= visibilityTimerPollDelay;
3943 if (m_autoplayVisibilityTimerSpan >= 0) {
3944 m_autoplayVisibilityTimer.startOneShot(visibilityTimerPollDelay, FRO M_HERE);
3945 }
3946 } else {
3947 // No longer scrolling, so check visibility and stop.
3948 autoplayExperimentMaybeStartPlaying();
3949 }
3950 }
3951
3952 bool HTMLMediaElement::autoplayExperimentIsVisible()
3953 {
3954 // We could check for eligibility here, but we skip it. Some of our
3955 // callers need to do it separately, and we don't want to check more
3956 // than we need to.
3957
3958 // Autoplay is requested, and we're willing to override if the visibility
3959 // requirements are met.
3960
3961 // Check visibility.
3962 const LocalDOMWindow* domWindow = document().domWindow();
3963 if (!domWindow)
3964 return false;
3965
3966 FloatRect us(offsetLeft(), offsetTop(), clientWidth(), clientHeight());
3967 FloatRect screen(domWindow->scrollX(), domWindow->scrollY(), domWindow->inne rWidth(), domWindow->innerHeight());
3968
3969 return screen.contains(us);
3970 }
3971
3972 bool HTMLMediaElement::autoplayExperimentMaybeStartPlaying()
3973 {
3974 // Make sure that we're eligible and visible.
3975 if (!autoplayExperimentIsEligible() || !autoplayExperimentIsVisible()) {
3976 return false;
3977 }
3978
3979 // Start playing!
3980 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByScroll);
3981 // Why are we always preparing? Just go!
3982 playInternal();
3983
3984 return true;
3985 }
3986
3987 bool HTMLMediaElement::autoplayExperimentIsEligible() const
3988 {
3989 // If no user gesture is required, then the experiment doesn't apply.
3990 // This is what prevents us from starting playback more than once.
3991 // Since this flag is never set to true once it's cleared, it will block
3992 // the autoplay experiment forever.
3993 if (!m_userGestureRequiredForPlay)
3994 return false;
3995
3996 if (m_autoplayExperimentMode == ExperimentOff)
3997 return false;
3998
3999 // If nobody has requested playback, either by the autoplay attribute or
4000 // a play() call, then do nothing.
4001 if (!m_autoplayExperimentPlayPending && !autoplay())
4002 return false;
4003
4004 // If the video is already playing, then do nothing. Note that there
4005 // is not a path where a user gesture is required but the video is
4006 // playing. However, we check for completeness.
4007 if (!m_paused)
4008 return false;
4009
4010 // Note that the viewport test always returns false on desktop. For
4011 // tests, we allow an override.
4012 const bool optimizedForMobile = document().viewportDescription().isLegacyVie wportType()
4013 || (document().settings() && document().settings()->overrideOptimizedFor MobileCheck());
4014
4015 if (!optimizedForMobile)
4016 return false;
4017
4018 if (m_autoplayExperimentMode == ExperimentIfMuted) {
4019 // If media is muted, then autoplay when it comes into view.
4020 return fastHasAttribute(mutedAttr) || m_muted;
4021 }
4022
4023 // Autoplay when it comes into view, maybe muted.
4024 return true;
4025 }
4026
4027 void HTMLMediaElement::autoplayExperimentMuteIfNeeded()
4028 {
4029 if (m_autoplayExperimentMode == ExperimentPlayMuted) {
4030 m_muted = true;
4031 updateVolume();
4032 }
4033 }
4034
4035 void HTMLMediaElement::autoplayExperimentPrepareToPlay(AutoplayMetrics metric)
4036 {
4037 recordAutoplayMetric(metric);
4038
4039 // This also causes !autoplayExperimentIsEligible, so that we don't
4040 // allow autoplay more than once.
4041 m_userGestureRequiredForPlay = false;
4042
4043 m_autoplayExperimentStartedByExperiment = true;
4044 autoplayExperimentClearEventListenerIfNeeded();
4045 autoplayExperimentMuteIfNeeded();
4046
4047 // Record that this autoplayed without a user gesture. This is normally
4048 // set when we discover an autoplay attribute, but we include all cases
4049 // where playback started without a user gesture, e.g., play().
4050 m_initialPlayWithoutUserGestures = true;
4051 }
4052
4053 }
OLDNEW
« no previous file with comments | « Source/core/html/HTMLMediaElement.h ('k') | Source/core/testing/Internals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698