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