OLD | NEW |
---|---|
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 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
119 | 119 |
120 #ifndef LOG_CACHED_TIME_WARNINGS | 120 #ifndef LOG_CACHED_TIME_WARNINGS |
121 // Default to not logging warnings about excessive drift in the cached media tim e because it adds a | 121 // Default to not logging warnings about excessive drift in the cached media tim e because it adds a |
122 // fair amount of overhead and logging. | 122 // fair amount of overhead and logging. |
123 #define LOG_CACHED_TIME_WARNINGS 0 | 123 #define LOG_CACHED_TIME_WARNINGS 0 |
124 #endif | 124 #endif |
125 | 125 |
126 // URL protocol used to signal that the media source API is being used. | 126 // URL protocol used to signal that the media source API is being used. |
127 static const char mediaSourceBlobProtocol[] = "blob"; | 127 static const char mediaSourceBlobProtocol[] = "blob"; |
128 | 128 |
129 // How often do we poll for scrolling stopped during a visibility check? | |
130 static const double visibilityTimerPollDelay = 0.5; | |
131 // How long do we repeat visibility checks? We will poll once every PollDelay. | |
132 // Note that we will stop checking if we don't detect scrolling, also. | |
133 static const double visibilityCheckDuration = 5; | |
134 | |
129 using namespace HTMLNames; | 135 using namespace HTMLNames; |
130 | 136 |
131 typedef WillBeHeapHashSet<RawPtrWillBeWeakMember<HTMLMediaElement>> WeakMediaEle mentSet; | 137 typedef WillBeHeapHashSet<RawPtrWillBeWeakMember<HTMLMediaElement>> WeakMediaEle mentSet; |
132 typedef WillBeHeapHashMap<RawPtrWillBeWeakMember<Document>, WeakMediaElementSet> DocumentElementSetMap; | 138 typedef WillBeHeapHashMap<RawPtrWillBeWeakMember<Document>, WeakMediaElementSet> DocumentElementSetMap; |
133 static DocumentElementSetMap& documentToElementSetMap() | 139 static DocumentElementSetMap& documentToElementSetMap() |
134 { | 140 { |
135 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<DocumentElementSetMap>, map, (ado ptPtrWillBeNoop(new DocumentElementSetMap()))); | 141 DEFINE_STATIC_LOCAL(OwnPtrWillBePersistent<DocumentElementSetMap>, map, (ado ptPtrWillBeNoop(new DocumentElementSetMap()))); |
136 return *map; | 142 return *map; |
137 } | 143 } |
138 | 144 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows | 250 // when used with parameters, e.g. "application/octet-stream;codecs=theora", is a type that the user agent knows |
245 // it cannot render. | 251 // it cannot render. |
246 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) { | 252 if (contentMIMEType != "application/octet-stream" || contentTypeCodecs.isEmp ty()) { |
247 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ()); | 253 WebMimeRegistry::SupportsType supported = Platform::current()->mimeRegis try()->supportsMediaMIMEType(contentMIMEType, contentTypeCodecs, keySystem.lower ()); |
248 return supported > WebMimeRegistry::IsNotSupported; | 254 return supported > WebMimeRegistry::IsNotSupported; |
249 } | 255 } |
250 | 256 |
251 return false; | 257 return false; |
252 } | 258 } |
253 | 259 |
254 // These values are used for a histogram. Do not reorder. | 260 void HTMLMediaElement::recordAutoplayMetric(AutoplayMetrics metric) |
255 enum AutoplayMetrics { | |
256 // Media element with autoplay seen. | |
257 AutoplayMediaFound = 0, | |
258 // Autoplay enabled and user stopped media play at any point. | |
259 AutoplayStopped = 1, | |
260 // Autoplay enabled but user bailed out on media play early. | |
261 AutoplayBailout = 2, | |
262 // Autoplay disabled but user manually started media. | |
263 AutoplayManualStart = 3, | |
264 // Autoplay was (re)enabled through a user-gesture triggered load() | |
265 AutoplayEnabledThroughLoad = 4, | |
266 // Autoplay disabled by sandbox flags. | |
267 AutoplayDisabledBySandbox = 5, | |
268 // This enum value must be last. | |
269 NumberOfAutoplayMetrics, | |
270 }; | |
271 | |
272 static void recordAutoplayMetric(AutoplayMetrics metric) | |
273 { | 261 { |
274 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics); | 262 Platform::current()->histogramEnumeration("Blink.MediaElement.Autoplay", met ric, NumberOfAutoplayMetrics); |
275 } | 263 } |
276 | 264 |
277 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem) | 265 WebMimeRegistry::SupportsType HTMLMediaElement::supportsType(const ContentType& contentType, const String& keySystem) |
278 { | 266 { |
279 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); | 267 DEFINE_STATIC_LOCAL(const String, codecs, ("codecs")); |
280 | 268 |
281 if (!RuntimeEnabledFeatures::mediaEnabled()) | 269 if (!RuntimeEnabledFeatures::mediaEnabled()) |
282 return WebMimeRegistry::IsNotSupported; | 270 return WebMimeRegistry::IsNotSupported; |
(...skipping 10 matching lines...) Expand all Loading... | |
293 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the | 281 // 4.8.10.3 MIME types - The canPlayType(type) method must return the empty string if type is a type that the |
294 // user agent knows it cannot render or is the type "application/octet-strea m" | 282 // user agent knows it cannot render or is the type "application/octet-strea m" |
295 if (type == "application/octet-stream") | 283 if (type == "application/octet-stream") |
296 return WebMimeRegistry::IsNotSupported; | 284 return WebMimeRegistry::IsNotSupported; |
297 | 285 |
298 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system); | 286 return Platform::current()->mimeRegistry()->supportsMediaMIMEType(type, type Codecs, system); |
299 } | 287 } |
300 | 288 |
301 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0; | 289 URLRegistry* HTMLMediaElement::s_mediaStreamRegistry = 0; |
302 | 290 |
291 class HTMLMediaElement::AutoplayExperimentTouchListener : public EventListener { | |
292 public: | |
293 AutoplayExperimentTouchListener(HTMLMediaElement* element) : EventListen er(CPPEventListenerType), m_element(element) { } | |
294 virtual bool operator==(const EventListener& them) | |
295 { | |
296 return &them == this; | |
297 } | |
298 | |
299 void handleEvent(ExecutionContext*, Event*) override | |
300 { | |
301 if (m_element) | |
302 m_element->beginPeriodicVisibilityCheck(); | |
303 } | |
304 | |
305 private: | |
306 HTMLMediaElement* m_element; | |
307 }; | |
308 | |
303 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry) | 309 void HTMLMediaElement::setMediaStreamRegistry(URLRegistry* registry) |
304 { | 310 { |
305 ASSERT(!s_mediaStreamRegistry); | 311 ASSERT(!s_mediaStreamRegistry); |
306 s_mediaStreamRegistry = registry; | 312 s_mediaStreamRegistry = registry; |
307 } | 313 } |
308 | 314 |
309 bool HTMLMediaElement::isMediaStreamURL(const String& url) | 315 bool HTMLMediaElement::isMediaStreamURL(const String& url) |
310 { | 316 { |
311 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false; | 317 return s_mediaStreamRegistry ? s_mediaStreamRegistry->contains(url) : false; |
312 } | 318 } |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
357 , m_haveVisibleTextTrack(false) | 363 , m_haveVisibleTextTrack(false) |
358 , m_processingPreferenceChange(false) | 364 , m_processingPreferenceChange(false) |
359 , m_remoteRoutesAvailable(false) | 365 , m_remoteRoutesAvailable(false) |
360 , m_playingRemotely(false) | 366 , m_playingRemotely(false) |
361 , m_isFinalizing(false) | 367 , m_isFinalizing(false) |
362 , m_initialPlayWithoutUserGestures(false) | 368 , m_initialPlayWithoutUserGestures(false) |
363 , m_autoplayMediaCounted(false) | 369 , m_autoplayMediaCounted(false) |
364 , m_audioTracks(AudioTrackList::create(*this)) | 370 , m_audioTracks(AudioTrackList::create(*this)) |
365 , m_videoTracks(VideoTrackList::create(*this)) | 371 , m_videoTracks(VideoTrackList::create(*this)) |
366 , m_textTracks(nullptr) | 372 , m_textTracks(nullptr) |
373 , m_autoplayExperimentPlayPending(false) | |
374 , m_autoplayExperimentStartedByExperiment(false) | |
375 , m_autoplayExperimentMode(ExperimentOff) | |
367 #if ENABLE(WEB_AUDIO) | 376 #if ENABLE(WEB_AUDIO) |
368 , m_audioSourceNode(nullptr) | 377 , m_audioSourceNode(nullptr) |
369 #endif | 378 #endif |
379 , m_autoplayVisibilityTimer(this, &HTMLMediaElement::visibilityTimerFired) | |
380 , m_autoplayLastScrollX(std::numeric_limits<double>::quiet_NaN()) | |
381 , m_autoplayLastScrollY(std::numeric_limits<double>::quiet_NaN()) | |
382 , m_autoplayVisibilityTimerSpan(0) | |
370 { | 383 { |
371 #if ENABLE(OILPAN) | 384 #if ENABLE(OILPAN) |
372 ThreadState::current()->registerPreFinalizer(this); | 385 ThreadState::current()->registerPreFinalizer(this); |
373 #endif | 386 #endif |
374 ASSERT(RuntimeEnabledFeatures::mediaEnabled()); | 387 ASSERT(RuntimeEnabledFeatures::mediaEnabled()); |
375 | 388 |
376 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this); | 389 WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this); |
377 | 390 |
378 if (document.settings() && document.settings()->mediaPlaybackRequiresUserGes ture()) | 391 if (document.settings()) { |
philipj_slow
2015/08/05 10:03:11
Wow, this has actually been broken the whole time,
liberato (no reviews please)
2015/08/06 06:37:58
i'm glad you're one of the good guys.
| |
379 m_userGestureRequiredForPlay = true; | 392 if (document.settings()->mediaPlaybackRequiresUserGesture()) |
393 m_userGestureRequiredForPlay = true; | |
394 | |
395 const String& autoplayMode = document.settings()->autoplayExperimentMode (); | |
396 if (autoplayMode.contains("enabled")) { | |
397 // Autoplay with no gesture requirement. | |
398 m_autoplayExperimentMode |= ExperimentEnabled; | |
399 } | |
400 if (autoplayMode.contains("-ifvisible")) { | |
401 // Override gesture requirement only if the player is visible. | |
402 m_autoplayExperimentMode |= ExperimentIfVisible; | |
403 } | |
404 if (autoplayMode.contains("-ifmuted")) { | |
405 // Override gesture requirement only if the media is muted or has | |
406 // no audio track. | |
407 m_autoplayExperimentMode |= ExperimentIfMuted; | |
408 } | |
409 if (autoplayMode.contains("-ifmobile")) { | |
410 // Override gesture requirement only if the page is optimized | |
411 // for mobile. | |
412 m_autoplayExperimentMode |= ExperimentIfMobile; | |
413 } | |
414 if (autoplayMode.contains("-playmuted")) { | |
415 m_autoplayExperimentMode |= ExperimentPlayMuted; | |
416 } | |
417 | |
418 if (m_autoplayExperimentMode != ExperimentOff) { | |
419 WTF_LOG(Media, "HTMLMediaElement: autoplay experiment set to '%s' (% d)", | |
420 autoplayMode.ascii().data(), m_autoplayExperimentMode); | |
421 } | |
422 } | |
380 | 423 |
381 setHasCustomStyleCallbacks(); | 424 setHasCustomStyleCallbacks(); |
382 addElementToDocumentMap(this, &document); | 425 addElementToDocumentMap(this, &document); |
383 } | 426 } |
384 | 427 |
385 HTMLMediaElement::~HTMLMediaElement() | 428 HTMLMediaElement::~HTMLMediaElement() |
386 { | 429 { |
387 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this); | 430 WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this); |
431 | |
432 autoplayExperimentClearEventListenerIfNeeded(); | |
433 | |
388 #if !ENABLE(OILPAN) | 434 #if !ENABLE(OILPAN) |
389 // HTMLMediaElement and m_asyncEventQueue always become unreachable | 435 // HTMLMediaElement and m_asyncEventQueue always become unreachable |
390 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in | 436 // together. So HTMLMediaElement and m_asyncEventQueue are destructed in |
391 // the same GC. We don't need to close it explicitly in Oilpan. | 437 // the same GC. We don't need to close it explicitly in Oilpan. |
392 m_asyncEventQueue->close(); | 438 m_asyncEventQueue->close(); |
393 | 439 |
394 setShouldDelayLoadEvent(false); | 440 setShouldDelayLoadEvent(false); |
395 | 441 |
396 if (m_textTracks) | 442 if (m_textTracks) |
397 m_textTracks->clearOwner(); | 443 m_textTracks->clearOwner(); |
(...skipping 1150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1548 scheduleEvent(EventTypeNames::canplay); | 1594 scheduleEvent(EventTypeNames::canplay); |
1549 if (isPotentiallyPlaying) | 1595 if (isPotentiallyPlaying) |
1550 scheduleEvent(EventTypeNames::playing); | 1596 scheduleEvent(EventTypeNames::playing); |
1551 } | 1597 } |
1552 | 1598 |
1553 if (m_autoplaying && m_paused && autoplay()) { | 1599 if (m_autoplaying && m_paused && autoplay()) { |
1554 autoplayMediaEncountered(); | 1600 autoplayMediaEncountered(); |
1555 | 1601 |
1556 if (document().isSandboxed(SandboxAutomaticFeatures)) { | 1602 if (document().isSandboxed(SandboxAutomaticFeatures)) { |
1557 recordAutoplayMetric(AutoplayDisabledBySandbox); | 1603 recordAutoplayMetric(AutoplayDisabledBySandbox); |
1558 } else if (!m_userGestureRequiredForPlay) { | 1604 } else { |
1559 m_paused = false; | 1605 // If the autoplay experiment says that it's okay to play now, |
1560 invalidateCachedTime(); | 1606 // then don't require a user gesture. |
1561 scheduleEvent(EventTypeNames::play); | 1607 if (autoplayExperimentIsEligible()) { |
1562 scheduleEvent(EventTypeNames::playing); | 1608 if (autoplayExperimentIsVisible()) { |
philipj_slow
2015/08/05 10:03:11
Perhaps rename this so that it's clear that it alw
liberato (no reviews please)
2015/08/06 06:37:57
Done.
| |
1609 autoplayExperimentPrepareToPlay(AutoplayExperimentStarte dByLoad); | |
1610 // Will play below. | |
1611 } else { | |
1612 // Wait for visibility checks to pass. | |
1613 autoplayExperimentInstallEventListenerIfNeeded(); | |
1614 } | |
1615 } | |
1616 | |
1617 if (!m_userGestureRequiredForPlay) { | |
1618 m_paused = false; | |
philipj_slow
2015/08/05 10:03:11
This branch was previously predicated on the sandb
liberato (no reviews please)
2015/08/06 06:37:57
it still is, though it's virtually impossible to t
| |
1619 invalidateCachedTime(); | |
1620 scheduleEvent(EventTypeNames::play); | |
1621 scheduleEvent(EventTypeNames::playing); | |
1622 } | |
1563 } | 1623 } |
1564 } | 1624 } |
1565 | 1625 |
1566 scheduleEvent(EventTypeNames::canplaythrough); | 1626 scheduleEvent(EventTypeNames::canplaythrough); |
1567 | 1627 |
1568 shouldUpdateDisplayState = true; | 1628 shouldUpdateDisplayState = true; |
1569 } | 1629 } |
1570 | 1630 |
1571 if (shouldUpdateDisplayState) { | 1631 if (shouldUpdateDisplayState) { |
1572 updateDisplayState(); | 1632 updateDisplayState(); |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1953 | 2013 |
1954 WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const | 2014 WebMediaPlayer::Preload HTMLMediaElement::effectivePreloadType() const |
1955 { | 2015 { |
1956 return autoplay() ? WebMediaPlayer::PreloadAuto : preloadType(); | 2016 return autoplay() ? WebMediaPlayer::PreloadAuto : preloadType(); |
1957 } | 2017 } |
1958 | 2018 |
1959 void HTMLMediaElement::play() | 2019 void HTMLMediaElement::play() |
1960 { | 2020 { |
1961 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this); | 2021 WTF_LOG(Media, "HTMLMediaElement::play(%p)", this); |
1962 | 2022 |
2023 // Set the pending state, even if the play isn't going to be pending. | |
2024 // Eligibility can change if, for example, the mute status changes. | |
2025 // Having this set is okay. | |
2026 m_autoplayExperimentPlayPending = true; | |
2027 | |
1963 if (!UserGestureIndicator::processingUserGesture()) { | 2028 if (!UserGestureIndicator::processingUserGesture()) { |
1964 autoplayMediaEncountered(); | 2029 autoplayMediaEncountered(); |
2030 | |
2031 if (autoplayExperimentIsEligible()) { | |
2032 // Remember that m_userGestureRequiredForPlay is required for | |
2033 // us to be eligible for the experiment. | |
2034 // If we are able to override the gesture requirement now, then | |
2035 // do so. Otherwise, install an event listener if we need one. | |
2036 if (autoplayExperimentIsVisible()) { | |
2037 // Override the gesture and play. | |
2038 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByPlay) ; | |
2039 } else { | |
2040 // Wait for visibility. | |
2041 autoplayExperimentInstallEventListenerIfNeeded(); | |
2042 } | |
2043 } | |
2044 | |
1965 if (m_userGestureRequiredForPlay) { | 2045 if (m_userGestureRequiredForPlay) { |
2046 recordAutoplayMetric(AutoplayPlayFailed); | |
1966 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture."); | 2047 String message = ExceptionMessages::failedToExecute("play", "HTMLMed iaElement", "API can only be initiated by a user gesture."); |
1967 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message)); | 2048 document().executionContext()->addConsoleMessage(ConsoleMessage::cre ate(JSMessageSource, WarningMessageLevel, message)); |
1968 return; | 2049 return; |
1969 } | 2050 } |
1970 } else if (m_userGestureRequiredForPlay) { | 2051 } else if (m_userGestureRequiredForPlay) { |
1971 if (m_autoplayMediaCounted) | 2052 if (m_autoplayMediaCounted) |
1972 recordAutoplayMetric(AutoplayManualStart); | 2053 recordAutoplayMetric(AutoplayManualStart); |
1973 m_userGestureRequiredForPlay = false; | 2054 m_userGestureRequiredForPlay = false; |
2055 autoplayExperimentClearEventListenerIfNeeded(); | |
1974 } | 2056 } |
1975 | 2057 |
1976 playInternal(); | 2058 playInternal(); |
1977 } | 2059 } |
1978 | 2060 |
1979 void HTMLMediaElement::playInternal() | 2061 void HTMLMediaElement::playInternal() |
1980 { | 2062 { |
1981 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this); | 2063 WTF_LOG(Media, "HTMLMediaElement::playInternal(%p)", this); |
1982 | 2064 |
1983 // 4.8.10.9. Playing the media resource | 2065 // 4.8.10.9. Playing the media resource |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2025 ASSERT(m_initialPlayWithoutUserGestures); | 2107 ASSERT(m_initialPlayWithoutUserGestures); |
2026 m_initialPlayWithoutUserGestures = false; | 2108 m_initialPlayWithoutUserGestures = false; |
2027 | 2109 |
2028 recordAutoplayMetric(AutoplayStopped); | 2110 recordAutoplayMetric(AutoplayStopped); |
2029 | 2111 |
2030 // We count the user as having bailed-out on the video if they watched | 2112 // We count the user as having bailed-out on the video if they watched |
2031 // less than one minute and less than 50% of it. | 2113 // less than one minute and less than 50% of it. |
2032 double playedTime = currentTime(); | 2114 double playedTime = currentTime(); |
2033 if (playedTime < 60) { | 2115 if (playedTime < 60) { |
2034 double progress = playedTime / duration(); | 2116 double progress = playedTime / duration(); |
2035 if (progress < 0.5) | 2117 if (progress < 0.5) { |
philipj_slow
2015/08/05 10:03:11
Why the added {}?
liberato (no reviews please)
2015/08/06 06:37:57
whoops, thanks -- i had more code in there and for
| |
2036 recordAutoplayMetric(AutoplayBailout); | 2118 recordAutoplayMetric(AutoplayBailout); |
2119 } | |
2037 } | 2120 } |
2038 } | 2121 } |
2039 | 2122 |
2040 void HTMLMediaElement::pause() | 2123 void HTMLMediaElement::pause() |
2041 { | 2124 { |
2042 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this); | 2125 WTF_LOG(Media, "HTMLMediaElement::pause(%p)", this); |
2043 | 2126 |
2044 if (m_networkState == NETWORK_EMPTY) | 2127 if (m_networkState == NETWORK_EMPTY) |
2045 scheduleDelayedAction(LoadMediaResource); | 2128 scheduleDelayedAction(LoadMediaResource); |
2046 | 2129 |
2130 // Don't try to autoplay, if we would have. | |
2131 m_autoplayExperimentPlayPending = false; | |
2132 autoplayExperimentClearEventListenerIfNeeded(); | |
2133 | |
2047 m_autoplaying = false; | 2134 m_autoplaying = false; |
2048 | 2135 |
2049 if (!m_paused) { | 2136 if (!m_paused) { |
2050 if (m_initialPlayWithoutUserGestures) | 2137 if (m_initialPlayWithoutUserGestures) |
2051 gesturelessInitialPlayHalted(); | 2138 gesturelessInitialPlayHalted(); |
2052 | 2139 |
2053 m_paused = true; | 2140 m_paused = true; |
2054 scheduleTimeupdateEvent(false); | 2141 scheduleTimeupdateEvent(false); |
2055 scheduleEvent(EventTypeNames::pause); | 2142 scheduleEvent(EventTypeNames::pause); |
2056 } | 2143 } |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2134 | 2221 |
2135 void HTMLMediaElement::setMuted(bool muted) | 2222 void HTMLMediaElement::setMuted(bool muted) |
2136 { | 2223 { |
2137 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) ); | 2224 WTF_LOG(Media, "HTMLMediaElement::setMuted(%p, %s)", this, boolString(muted) ); |
2138 | 2225 |
2139 if (m_muted == muted) | 2226 if (m_muted == muted) |
2140 return; | 2227 return; |
2141 | 2228 |
2142 m_muted = muted; | 2229 m_muted = muted; |
2143 | 2230 |
2231 // If we are no longer eligible for the autoplay experiment, then also | |
2232 // quit listening for events. If we are eligible, and if we should be | |
2233 // playing, then start playing. In other words, start playing if | |
philipj_slow
2015/08/05 10:03:11
Really start playing by setting the muted attribut
liberato (no reviews please)
2015/08/06 06:37:57
there was interest in this from one of the origina
philipj_slow
2015/08/13 09:27:53
Acknowledged.
| |
2234 // we just needed 'mute' to autoplay. | |
2235 if (!autoplayExperimentIsEligible()) { | |
2236 autoplayExperimentClearEventListenerIfNeeded(); | |
2237 } else { | |
2238 // Try to play. If we can't, then install a visibility listener. | |
2239 if (!autoplayExperimentMaybeStartPlaying()) | |
2240 autoplayExperimentInstallEventListenerIfNeeded(); | |
2241 } | |
2242 | |
2144 updateVolume(); | 2243 updateVolume(); |
2145 | 2244 |
2146 scheduleEvent(EventTypeNames::volumechange); | 2245 scheduleEvent(EventTypeNames::volumechange); |
2147 } | 2246 } |
2148 | 2247 |
2149 void HTMLMediaElement::updateVolume() | 2248 void HTMLMediaElement::updateVolume() |
2150 { | 2249 { |
2151 if (webMediaPlayer()) | 2250 if (webMediaPlayer()) |
2152 webMediaPlayer()->setVolume(effectiveMediaVolume()); | 2251 webMediaPlayer()->setVolume(effectiveMediaVolume()); |
2153 | 2252 |
(...skipping 1628 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3782 { | 3881 { |
3783 visitor->trace(m_client); | 3882 visitor->trace(m_client); |
3784 } | 3883 } |
3785 | 3884 |
3786 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl) | 3885 DEFINE_TRACE(HTMLMediaElement::AudioSourceProviderImpl) |
3787 { | 3886 { |
3788 visitor->trace(m_client); | 3887 visitor->trace(m_client); |
3789 } | 3888 } |
3790 #endif | 3889 #endif |
3791 | 3890 |
3891 void HTMLMediaElement::autoplayExperimentInstallEventListenerIfNeeded() | |
3892 { | |
3893 // If we don't require visibility, then we don't need the listener. | |
3894 if (!(m_autoplayExperimentMode & ExperimentIfVisible)) | |
3895 return; | |
3896 | |
3897 if (document().domWindow() && !m_autoplayExperimentTouchListener) { | |
3898 m_autoplayExperimentTouchListener = adoptRef(new AutoplayExperimentTouch Listener(this)); | |
3899 // Listen for events that might show a user-initiated scroll. We | |
3900 // don't try to catch programmatic scrolls right now. | |
3901 document().domWindow()->addEventListener("touchend", m_autoplayExperimen tTouchListener, false); | |
3902 document().domWindow()->addEventListener("touchcancel", m_autoplayExperi mentTouchListener, false); | |
3903 } | |
3792 } | 3904 } |
3905 | |
3906 void HTMLMediaElement::autoplayExperimentClearEventListenerIfNeeded() | |
3907 { | |
3908 if (m_autoplayExperimentTouchListener) { | |
3909 LocalDOMWindow* domWindow = document().domWindow(); | |
3910 if (domWindow) { | |
3911 domWindow->removeEventListener("touchend", m_autoplayExperimentTouch Listener, false); | |
3912 domWindow->removeEventListener("touchcancel", m_autoplayExperimentTo uchListener, false); | |
3913 } | |
3914 // Either way, clear our ref. | |
3915 m_autoplayExperimentTouchListener.clear(); | |
3916 } | |
3917 } | |
3918 | |
3919 void HTMLMediaElement::beginPeriodicVisibilityCheck() | |
3920 { | |
3921 // Note that a visibility check might already be in progress. | |
3922 // Always reset the span of the checks to maximum. | |
3923 m_autoplayVisibilityTimerSpan = visibilityCheckDuration; | |
3924 | |
3925 // If the timer isn't active, then fire the timer immediately to reset | |
3926 // it. We might just setOneShot(0). | |
3927 if (!m_autoplayVisibilityTimer.isActive()) { | |
3928 visibilityTimerFired(0); | |
3929 } | |
3930 } | |
3931 | |
3932 void HTMLMediaElement::visibilityTimerFired(Timer<HTMLMediaElement>*) | |
3933 { | |
3934 const LocalDOMWindow* domWindow = document().domWindow(); | |
3935 if (!domWindow) | |
3936 return; | |
3937 | |
3938 const int currentScrollX = domWindow->scrollX(); | |
3939 const int currentScrollY = domWindow->scrollY(); | |
3940 | |
3941 if (currentScrollX != m_autoplayLastScrollX | |
3942 || currentScrollY != m_autoplayLastScrollY) { | |
3943 // Still scrolling, so wait a bit more. | |
3944 m_autoplayLastScrollX = currentScrollX; | |
3945 m_autoplayLastScrollY = currentScrollY; | |
3946 | |
3947 // Reset the timer to check again if we haven't tried for long enough. | |
3948 m_autoplayVisibilityTimerSpan -= visibilityTimerPollDelay; | |
3949 if (m_autoplayVisibilityTimerSpan >= 0) { | |
3950 m_autoplayVisibilityTimer.startOneShot(visibilityTimerPollDelay, FRO M_HERE); | |
3951 } | |
3952 } else { | |
3953 // No longer scrolling, so check visibility and stop. | |
3954 autoplayExperimentMaybeStartPlaying(); | |
3955 } | |
3956 } | |
3957 | |
3958 bool HTMLMediaElement::autoplayExperimentIsVisible() | |
3959 { | |
3960 // We could check for eligibility here, but we skip it. Some of our | |
3961 // callers need to do it separately, and we don't want to check more | |
3962 // than we need to. | |
3963 | |
3964 // If visibility isn't required, then it's visible enough. | |
3965 if (!(m_autoplayExperimentMode & ExperimentIfVisible)) | |
3966 return true; | |
3967 | |
3968 // Autoplay is requested, and we're willing to override if the visibility | |
3969 // requirements are met. | |
3970 | |
3971 // Check visibility. | |
philipj_slow
2015/08/05 10:03:11
A page visibility check is missing, this ought to
liberato (no reviews please)
2015/08/06 06:37:57
i don't think it'll ever play unless in the foregr
philipj_slow
2015/08/13 09:27:53
What is it that would prevent playback when not in
liberato (no reviews please)
2015/09/01 06:54:19
Done.
| |
3972 const LocalDOMWindow* domWindow = document().domWindow(); | |
3973 if (!domWindow) | |
3974 return false; | |
3975 | |
3976 FloatRect us(offsetLeft(), offsetTop(), clientWidth(), clientHeight()); | |
3977 FloatRect screen(domWindow->scrollX(), domWindow->scrollY(), domWindow->inne rWidth(), domWindow->innerHeight()); | |
3978 | |
3979 return screen.contains(us); | |
3980 } | |
3981 | |
3982 bool HTMLMediaElement::autoplayExperimentMaybeStartPlaying() | |
3983 { | |
3984 // Make sure that we're eligible and visible. | |
3985 if (!autoplayExperimentIsEligible() || !autoplayExperimentIsVisible()) { | |
3986 return false; | |
3987 } | |
3988 | |
3989 // Start playing! | |
3990 autoplayExperimentPrepareToPlay(AutoplayExperimentStartedByScroll); | |
3991 // Why are we always preparing? Just go! | |
philipj_slow
2015/08/05 10:03:12
Is this a question to the reviewer, or a rhetorica
liberato (no reviews please)
2015/08/06 06:37:57
random movie quotes make reviewing more fun!
but
philipj_slow
2015/08/13 09:27:53
Ah, Spaceballs :)
| |
3992 playInternal(); | |
3993 | |
3994 return true; | |
3995 } | |
3996 | |
3997 bool HTMLMediaElement::autoplayExperimentIsEligible() const | |
3998 { | |
3999 // If no user gesture is required, then the experiment doesn't apply. | |
4000 // This is what prevents us from starting playback more than once. | |
4001 // Since this flag is never set to true once it's cleared, it will block | |
4002 // the autoplay experiment forever. | |
4003 if (!m_userGestureRequiredForPlay) | |
4004 return false; | |
4005 | |
4006 if (m_autoplayExperimentMode == ExperimentOff) | |
4007 return false; | |
4008 | |
4009 // If nobody has requested playback, either by the autoplay attribute or | |
4010 // a play() call, then do nothing. | |
4011 if (!m_autoplayExperimentPlayPending && !autoplay()) | |
4012 return false; | |
4013 | |
4014 // If the video is already playing, then do nothing. Note that there | |
4015 // is not a path where a user gesture is required but the video is | |
4016 // playing. However, we check for completeness. | |
4017 if (!m_paused) | |
4018 return false; | |
4019 | |
4020 // Note that the viewport test always returns false on desktop, which is | |
4021 // why video-autoplay-experiment.html doesn't check -ifmobile . | |
4022 if (m_autoplayExperimentMode & ExperimentIfMobile) { | |
4023 if (!document().viewportDescription().isLegacyViewportType()) | |
4024 return false; | |
4025 } | |
4026 | |
4027 if (m_autoplayExperimentMode & ExperimentIfMuted) { | |
4028 // If media is muted, then autoplay when it comes into view. | |
4029 return fastHasAttribute(mutedAttr) || m_muted; | |
4030 } | |
4031 | |
4032 // Autoplay when it comes into view (if needed), maybe muted. | |
4033 return true; | |
4034 } | |
4035 | |
4036 void HTMLMediaElement::autoplayExperimentMuteIfNeeded() | |
4037 { | |
4038 if (m_autoplayExperimentMode & ExperimentPlayMuted) { | |
4039 m_muted = true; | |
4040 updateVolume(); | |
4041 } | |
4042 } | |
4043 | |
4044 void HTMLMediaElement::autoplayExperimentPrepareToPlay(AutoplayMetrics metric) | |
4045 { | |
4046 recordAutoplayMetric(metric); | |
4047 | |
4048 // This also causes !autoplayExperimentIsEligible, so that we don't | |
4049 // allow autoplay more than once. | |
4050 m_userGestureRequiredForPlay = false; | |
4051 | |
4052 m_autoplayExperimentStartedByExperiment = true; | |
4053 autoplayExperimentClearEventListenerIfNeeded(); | |
4054 autoplayExperimentMuteIfNeeded(); | |
4055 | |
4056 // Record that this autoplayed without a user gesture. This is normally | |
4057 // set when we discover an autoplay attribute, but we include all cases | |
4058 // where playback started without a user gesture, e.g., play(). | |
4059 m_initialPlayWithoutUserGestures = true; | |
4060 } | |
4061 | |
4062 } | |
OLD | NEW |