| 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 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 286 // These values are used for histograms. Do not reorder. | 286 // These values are used for histograms. Do not reorder. |
| 287 enum AutoplaySource { | 287 enum AutoplaySource { |
| 288 // Autoplay comes from HTMLMediaElement `autoplay` attribute. | 288 // Autoplay comes from HTMLMediaElement `autoplay` attribute. |
| 289 AutoplaySourceAttribute = 0, | 289 AutoplaySourceAttribute = 0, |
| 290 // Autoplay comes from `play()` method. | 290 // Autoplay comes from `play()` method. |
| 291 AutoplaySourceMethod = 1, | 291 AutoplaySourceMethod = 1, |
| 292 // This enum value must be last. | 292 // This enum value must be last. |
| 293 NumberOfAutoplaySources = 2, | 293 NumberOfAutoplaySources = 2, |
| 294 }; | 294 }; |
| 295 | 295 |
| 296 static const double maxUmaDuration = 10000; |
| 297 static const double umaBucketCount = 50; |
| 298 |
| 296 } // anonymous namespace | 299 } // anonymous namespace |
| 297 | 300 |
| 298 class HTMLMediaElement::AutoplayHelperClientImpl : | 301 class HTMLMediaElement::AutoplayHelperClientImpl : |
| 299 public AutoplayExperimentHelper::Client { | 302 public AutoplayExperimentHelper::Client { |
| 300 | 303 |
| 301 public: | 304 public: |
| 302 static AutoplayHelperClientImpl* create(HTMLMediaElement* element) | 305 static AutoplayHelperClientImpl* create(HTMLMediaElement* element) |
| 303 { | 306 { |
| 304 return new AutoplayHelperClientImpl(element); | 307 return new AutoplayHelperClientImpl(element); |
| 305 } | 308 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 , m_processingPreferenceChange(false) | 444 , m_processingPreferenceChange(false) |
| 442 , m_remoteRoutesAvailable(false) | 445 , m_remoteRoutesAvailable(false) |
| 443 , m_playingRemotely(false) | 446 , m_playingRemotely(false) |
| 444 , m_inOverlayFullscreenVideo(false) | 447 , m_inOverlayFullscreenVideo(false) |
| 445 , m_audioTracks(AudioTrackList::create(*this)) | 448 , m_audioTracks(AudioTrackList::create(*this)) |
| 446 , m_videoTracks(VideoTrackList::create(*this)) | 449 , m_videoTracks(VideoTrackList::create(*this)) |
| 447 , m_textTracks(nullptr) | 450 , m_textTracks(nullptr) |
| 448 , m_playPromiseResolveTask(CancellableTaskFactory::create(this, &HTMLMediaEl
ement::resolveScheduledPlayPromises)) | 451 , m_playPromiseResolveTask(CancellableTaskFactory::create(this, &HTMLMediaEl
ement::resolveScheduledPlayPromises)) |
| 449 , m_playPromiseRejectTask(CancellableTaskFactory::create(this, &HTMLMediaEle
ment::rejectScheduledPlayPromises)) | 452 , m_playPromiseRejectTask(CancellableTaskFactory::create(this, &HTMLMediaEle
ment::rejectScheduledPlayPromises)) |
| 450 , m_audioSourceNode(nullptr) | 453 , m_audioSourceNode(nullptr) |
| 454 , m_mutedVideoAutoplayStartTimeMS(0) |
| 455 , m_mutedVideoAutoplayOffscreenDurationMS(0) |
| 456 , m_isVisible(false) |
| 457 , m_isAutoplayFromAttribute(false) |
| 458 , m_autoplayOffscreenVisibilityObserver(nullptr) |
| 451 , m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)) | 459 , m_autoplayHelperClient(AutoplayHelperClientImpl::create(this)) |
| 452 , m_autoplayHelper(AutoplayExperimentHelper::create(m_autoplayHelperClient.g
et())) | 460 , m_autoplayHelper(AutoplayExperimentHelper::create(m_autoplayHelperClient.g
et())) |
| 453 , m_remotePlaybackClient(nullptr) | 461 , m_remotePlaybackClient(nullptr) |
| 454 , m_autoplayVisibilityObserver(nullptr) | 462 , m_autoplayVisibilityObserver(nullptr) |
| 455 { | 463 { |
| 456 ThreadState::current()->registerPreFinalizer(this); | 464 ThreadState::current()->registerPreFinalizer(this); |
| 457 | 465 |
| 458 MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; | 466 MEDIA_LOG << "HTMLMediaElement(" << (void*)this << ")"; |
| 459 | 467 |
| 460 // If any experiment is enabled, then we want to enable a user gesture by | 468 // If any experiment is enabled, then we want to enable a user gesture by |
| 461 // default, otherwise the experiment does nothing. | 469 // default, otherwise the experiment does nothing. |
| 462 if ((document.settings() && document.settings()->mediaPlaybackRequiresUserGe
sture()) | 470 if ((document.settings() && document.settings()->mediaPlaybackRequiresUserGe
sture()) |
| 463 || m_autoplayHelper->isExperimentEnabled()) { | 471 || m_autoplayHelper->isExperimentEnabled()) { |
| 464 m_lockedPendingUserGesture = true; | 472 m_lockedPendingUserGesture = true; |
| 465 } | 473 } |
| 466 | 474 |
| 467 setHasCustomStyleCallbacks(); | 475 setHasCustomStyleCallbacks(); |
| 468 addElementToDocumentMap(this, &document); | 476 addElementToDocumentMap(this, &document); |
| 469 | 477 |
| 470 UseCounter::count(document, UseCounter::HTMLMediaElement); | 478 UseCounter::count(document, UseCounter::HTMLMediaElement); |
| 471 } | 479 } |
| 472 | 480 |
| 473 HTMLMediaElement::~HTMLMediaElement() | 481 HTMLMediaElement::~HTMLMediaElement() |
| 474 { | 482 { |
| 483 maybeRecordMutedVideoAutoplayOffscreenDuration(); |
| 475 MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")"; | 484 MEDIA_LOG << "~HTMLMediaElement(" << (void*)this << ")"; |
| 476 | 485 |
| 477 // m_audioSourceNode is explicitly cleared by AudioNode::dispose(). | 486 // m_audioSourceNode is explicitly cleared by AudioNode::dispose(). |
| 478 // Since AudioNode::dispose() is guaranteed to be always called before | 487 // Since AudioNode::dispose() is guaranteed to be always called before |
| 479 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared | 488 // the AudioNode is destructed, m_audioSourceNode is explicitly cleared |
| 480 // even if the AudioNode and the HTMLMediaElement die together. | 489 // even if the AudioNode and the HTMLMediaElement die together. |
| 481 DCHECK(!m_audioSourceNode); | 490 DCHECK(!m_audioSourceNode); |
| 482 } | 491 } |
| 483 | 492 |
| 484 void HTMLMediaElement::dispose() | 493 void HTMLMediaElement::dispose() |
| (...skipping 1148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1633 | 1642 |
| 1634 if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && track
sAreReady) { | 1643 if (m_readyState == HAVE_ENOUGH_DATA && oldState < HAVE_ENOUGH_DATA && track
sAreReady) { |
| 1635 if (oldState <= HAVE_CURRENT_DATA) { | 1644 if (oldState <= HAVE_CURRENT_DATA) { |
| 1636 scheduleEvent(EventTypeNames::canplay); | 1645 scheduleEvent(EventTypeNames::canplay); |
| 1637 if (isPotentiallyPlaying) | 1646 if (isPotentiallyPlaying) |
| 1638 scheduleNotifyPlaying(); | 1647 scheduleNotifyPlaying(); |
| 1639 } | 1648 } |
| 1640 | 1649 |
| 1641 // Check for autoplay, and record metrics about it if needed. | 1650 // Check for autoplay, and record metrics about it if needed. |
| 1642 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { | 1651 if (shouldAutoplay(RecordMetricsBehavior::DoRecord)) { |
| 1652 m_isAutoplayFromAttribute = true; |
| 1643 recordAutoplaySourceMetric(AutoplaySourceAttribute); | 1653 recordAutoplaySourceMetric(AutoplaySourceAttribute); |
| 1644 | 1654 |
| 1645 // If the autoplay experiment says that it's okay to play now, | 1655 // If the autoplay experiment says that it's okay to play now, |
| 1646 // then don't require a user gesture. | 1656 // then don't require a user gesture. |
| 1647 m_autoplayHelper->becameReadyToPlay(); | 1657 m_autoplayHelper->becameReadyToPlay(); |
| 1648 | 1658 |
| 1649 if (!isGestureNeededForPlayback()) { | 1659 if (!isGestureNeededForPlayback()) { |
| 1650 if (isHTMLVideoElement() && muted() && RuntimeEnabledFeatures::a
utoplayMutedVideosEnabled()) { | 1660 if (isHTMLVideoElement() && muted() && RuntimeEnabledFeatures::a
utoplayMutedVideosEnabled()) { |
| 1651 m_autoplayVisibilityObserver = new ElementVisibilityObserver
(this, WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, wrapPersiste
nt(this))); | 1661 m_autoplayVisibilityObserver = new ElementVisibilityObserver
(this, WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplay, wrapPersiste
nt(this))); |
| 1652 m_autoplayVisibilityObserver->start(); | 1662 m_autoplayVisibilityObserver->start(); |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2083 return promise; | 2093 return promise; |
| 2084 } | 2094 } |
| 2085 | 2095 |
| 2086 Nullable<ExceptionCode> HTMLMediaElement::play() | 2096 Nullable<ExceptionCode> HTMLMediaElement::play() |
| 2087 { | 2097 { |
| 2088 MEDIA_LOG << "play(" << (void*)this << ")"; | 2098 MEDIA_LOG << "play(" << (void*)this << ")"; |
| 2089 | 2099 |
| 2090 m_autoplayHelper->playMethodCalled(); | 2100 m_autoplayHelper->playMethodCalled(); |
| 2091 | 2101 |
| 2092 if (!UserGestureIndicator::processingUserGesture()) { | 2102 if (!UserGestureIndicator::processingUserGesture()) { |
| 2103 m_isAutoplayFromAttribute = false; |
| 2093 recordAutoplaySourceMetric(AutoplaySourceMethod); | 2104 recordAutoplaySourceMetric(AutoplaySourceMethod); |
| 2094 if (isGestureNeededForPlayback()) { | 2105 if (isGestureNeededForPlayback()) { |
| 2095 // If playback is deferred, then don't start playback but don't | 2106 // If playback is deferred, then don't start playback but don't |
| 2096 // fail yet either. | 2107 // fail yet either. |
| 2097 if (m_autoplayHelper->isPlaybackDeferred()) | 2108 if (m_autoplayHelper->isPlaybackDeferred()) |
| 2098 return nullptr; | 2109 return nullptr; |
| 2099 | 2110 |
| 2100 // If we're already playing, then this play would do nothing anyway. | 2111 // If we're already playing, then this play would do nothing anyway. |
| 2101 // Call playInternal to handle scheduling the promise resolution. | 2112 // Call playInternal to handle scheduling the promise resolution. |
| 2102 if (!m_paused) { | 2113 if (!m_paused) { |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2185 | 2196 |
| 2186 m_autoplayHelper->pauseMethodCalled(); | 2197 m_autoplayHelper->pauseMethodCalled(); |
| 2187 | 2198 |
| 2188 m_autoplaying = false; | 2199 m_autoplaying = false; |
| 2189 | 2200 |
| 2190 if (!m_paused) { | 2201 if (!m_paused) { |
| 2191 m_paused = true; | 2202 m_paused = true; |
| 2192 scheduleTimeupdateEvent(false); | 2203 scheduleTimeupdateEvent(false); |
| 2193 scheduleEvent(EventTypeNames::pause); | 2204 scheduleEvent(EventTypeNames::pause); |
| 2194 scheduleRejectPlayPromises(AbortError); | 2205 scheduleRejectPlayPromises(AbortError); |
| 2206 maybeRecordMutedVideoAutoplayOffscreenDuration(); |
| 2195 } | 2207 } |
| 2196 | 2208 |
| 2197 updatePlayState(); | 2209 updatePlayState(); |
| 2198 } | 2210 } |
| 2199 | 2211 |
| 2200 void HTMLMediaElement::requestRemotePlayback() | 2212 void HTMLMediaElement::requestRemotePlayback() |
| 2201 { | 2213 { |
| 2202 DCHECK(m_remoteRoutesAvailable); | 2214 DCHECK(m_remoteRoutesAvailable); |
| 2203 webMediaPlayer()->requestRemotePlayback(); | 2215 webMediaPlayer()->requestRemotePlayback(); |
| 2204 Platform::current()->recordAction(UserMetricsAction("Media_RequestRemotePlay
back")); | 2216 Platform::current()->recordAction(UserMetricsAction("Media_RequestRemotePlay
back")); |
| (...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2898 if (loop()) { | 2910 if (loop()) { |
| 2899 // then seek to the earliest possible position of the media resourc
e and abort these steps. | 2911 // then seek to the earliest possible position of the media resourc
e and abort these steps. |
| 2900 seek(0); | 2912 seek(0); |
| 2901 } else { | 2913 } else { |
| 2902 // If the media element has still ended playback, and the direction
of playback is still | 2914 // If the media element has still ended playback, and the direction
of playback is still |
| 2903 // forwards, and paused is false, | 2915 // forwards, and paused is false, |
| 2904 if (!m_paused) { | 2916 if (!m_paused) { |
| 2905 // changes paused to true and fires a simple event named pause a
t the media element. | 2917 // changes paused to true and fires a simple event named pause a
t the media element. |
| 2906 m_paused = true; | 2918 m_paused = true; |
| 2907 scheduleEvent(EventTypeNames::pause); | 2919 scheduleEvent(EventTypeNames::pause); |
| 2920 maybeRecordMutedVideoAutoplayOffscreenDuration(); |
| 2908 } | 2921 } |
| 2909 // Queue a task to fire a simple event named ended at the media elem
ent. | 2922 // Queue a task to fire a simple event named ended at the media elem
ent. |
| 2910 scheduleEvent(EventTypeNames::ended); | 2923 scheduleEvent(EventTypeNames::ended); |
| 2911 Platform::current()->recordAction(UserMetricsAction("Media_Playback_
Ended")); | 2924 Platform::current()->recordAction(UserMetricsAction("Media_Playback_
Ended")); |
| 2912 } | 2925 } |
| 2913 } | 2926 } |
| 2914 updatePlayState(); | 2927 updatePlayState(); |
| 2915 } | 2928 } |
| 2916 | 2929 |
| 2917 void HTMLMediaElement::durationChanged() | 2930 void HTMLMediaElement::durationChanged() |
| (...skipping 743 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3661 visitor->trace(m_textTracks); | 3674 visitor->trace(m_textTracks); |
| 3662 visitor->trace(m_textTracksWhenResourceSelectionBegan); | 3675 visitor->trace(m_textTracksWhenResourceSelectionBegan); |
| 3663 visitor->trace(m_playPromiseResolvers); | 3676 visitor->trace(m_playPromiseResolvers); |
| 3664 visitor->trace(m_playPromiseResolveList); | 3677 visitor->trace(m_playPromiseResolveList); |
| 3665 visitor->trace(m_playPromiseRejectList); | 3678 visitor->trace(m_playPromiseRejectList); |
| 3666 visitor->trace(m_audioSourceProvider); | 3679 visitor->trace(m_audioSourceProvider); |
| 3667 visitor->trace(m_autoplayHelperClient); | 3680 visitor->trace(m_autoplayHelperClient); |
| 3668 visitor->trace(m_autoplayHelper); | 3681 visitor->trace(m_autoplayHelper); |
| 3669 visitor->trace(m_srcObject); | 3682 visitor->trace(m_srcObject); |
| 3670 visitor->trace(m_autoplayVisibilityObserver); | 3683 visitor->trace(m_autoplayVisibilityObserver); |
| 3684 visitor->trace(m_autoplayOffscreenVisibilityObserver); |
| 3671 visitor->template registerWeakMembers<HTMLMediaElement, &HTMLMediaElement::c
learWeakMembers>(this); | 3685 visitor->template registerWeakMembers<HTMLMediaElement, &HTMLMediaElement::c
learWeakMembers>(this); |
| 3672 Supplementable<HTMLMediaElement>::trace(visitor); | 3686 Supplementable<HTMLMediaElement>::trace(visitor); |
| 3673 HTMLElement::trace(visitor); | 3687 HTMLElement::trace(visitor); |
| 3674 ActiveDOMObject::trace(visitor); | 3688 ActiveDOMObject::trace(visitor); |
| 3675 } | 3689 } |
| 3676 | 3690 |
| 3677 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) | 3691 DEFINE_TRACE_WRAPPERS(HTMLMediaElement) |
| 3678 { | 3692 { |
| 3679 visitor->traceWrappers(m_videoTracks); | 3693 visitor->traceWrappers(m_videoTracks); |
| 3680 visitor->traceWrappers(m_audioTracks); | 3694 visitor->traceWrappers(m_audioTracks); |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3908 invalidateCachedTime(); | 3922 invalidateCachedTime(); |
| 3909 scheduleEvent(EventTypeNames::play); | 3923 scheduleEvent(EventTypeNames::play); |
| 3910 scheduleNotifyPlaying(); | 3924 scheduleNotifyPlaying(); |
| 3911 m_autoplaying = false; | 3925 m_autoplaying = false; |
| 3912 | 3926 |
| 3913 updatePlayState(); | 3927 updatePlayState(); |
| 3914 } | 3928 } |
| 3915 | 3929 |
| 3916 m_autoplayVisibilityObserver->stop(); | 3930 m_autoplayVisibilityObserver->stop(); |
| 3917 m_autoplayVisibilityObserver = nullptr; | 3931 m_autoplayVisibilityObserver = nullptr; |
| 3932 m_mutedVideoAutoplayStartTimeMS = monotonicallyIncreasingTimeMS(); |
| 3933 m_isVisible = true; |
| 3934 m_autoplayOffscreenVisibilityObserver = new ElementVisibilityObserver(this,
WTF::bind(&HTMLMediaElement::onVisibilityChangedForAutoplayOffscreen, wrapPersis
tent(this))); |
| 3935 } |
| 3936 |
| 3937 void HTMLMediaElement::onVisibilityChangedForAutoplayOffscreen(bool isVisible) |
| 3938 { |
| 3939 if (isVisible == m_isVisible) |
| 3940 return; |
| 3941 |
| 3942 if (isVisible) |
| 3943 m_mutedVideoAutoplayStartTimeMS = monotonicallyIncreasingTimeMS(); |
| 3944 else |
| 3945 m_mutedVideoAutoplayOffscreenDurationMS += monotonicallyIncreasingTimeMS
() - m_mutedVideoAutoplayStartTimeMS; |
| 3946 |
| 3947 m_isVisible = isVisible; |
| 3948 } |
| 3949 |
| 3950 void HTMLMediaElement::maybeRecordMutedVideoAutoplayOffscreenDuration() |
| 3951 { |
| 3952 if (!m_autoplayOffscreenVisibilityObserver) |
| 3953 return; |
| 3954 |
| 3955 double timeDeltaMS = m_mutedVideoAutoplayOffscreenDurationMS; |
| 3956 if (timeDeltaMS < 0) |
| 3957 timeDeltaMS = 0; |
| 3958 if (timeDeltaMS > maxUmaDuration) |
| 3959 timeDeltaMS = maxUmaDuration; |
| 3960 |
| 3961 if (m_isAutoplayFromAttribute) { |
| 3962 DEFINE_STATIC_LOCAL(CustomCountHistogram, durationHistogram, ("Media.Vid
eo.Autoplay.Muted.FromAttribute.OffscreenDuration", 0, maxUmaDuration, umaBucket
Count)); |
| 3963 durationHistogram.count(timeDeltaMS); |
| 3964 } else { |
| 3965 DEFINE_STATIC_LOCAL(CustomCountHistogram, durationHistogram, ("Media.Vid
eo.Autoplay.Muted.FromMethod.OffscreenDuration", 0, maxUmaDuration, umaBucketCou
nt)); |
| 3966 durationHistogram.count(timeDeltaMS); |
| 3967 } |
| 3968 m_autoplayOffscreenVisibilityObserver->stop(); |
| 3969 m_autoplayOffscreenVisibilityObserver = nullptr; |
| 3970 m_mutedVideoAutoplayOffscreenDurationMS = 0; |
| 3918 } | 3971 } |
| 3919 | 3972 |
| 3920 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) | 3973 void HTMLMediaElement::clearWeakMembers(Visitor* visitor) |
| 3921 { | 3974 { |
| 3922 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) { | 3975 if (!ThreadHeap::isHeapObjectAlive(m_audioSourceNode)) { |
| 3923 getAudioSourceProvider().setClient(nullptr); | 3976 getAudioSourceProvider().setClient(nullptr); |
| 3924 m_audioSourceNode = nullptr; | 3977 m_audioSourceNode = nullptr; |
| 3925 } | 3978 } |
| 3926 } | 3979 } |
| 3927 | 3980 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4023 | 4076 |
| 4024 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() co
nst | 4077 IntRect HTMLMediaElement::AutoplayHelperClientImpl::absoluteBoundingBoxRect() co
nst |
| 4025 { | 4078 { |
| 4026 IntRect result; | 4079 IntRect result; |
| 4027 if (LayoutObject* object = m_element->layoutObject()) | 4080 if (LayoutObject* object = m_element->layoutObject()) |
| 4028 result = object->absoluteBoundingBoxRect(); | 4081 result = object->absoluteBoundingBoxRect(); |
| 4029 return result; | 4082 return result; |
| 4030 } | 4083 } |
| 4031 | 4084 |
| 4032 } // namespace blink | 4085 } // namespace blink |
| OLD | NEW |