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

Side by Side Diff: third_party/WebKit/Source/core/html/HTMLMediaElement.cpp

Issue 2101613002: Record the offscreen playing duration of autoplaying muted videos (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 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
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 275 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698