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

Side by Side Diff: third_party/WebKit/Source/core/html/AutoplayUmaHelper.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: rebased and addressed Mounir's comments Created 4 years, 4 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 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/html/AutoplayUmaHelper.h" 5 #include "core/html/AutoplayUmaHelper.h"
6 6
7 #include "core/dom/Document.h" 7 #include "core/dom/Document.h"
8 #include "core/dom/ElementVisibilityObserver.h" 8 #include "core/dom/ElementVisibilityObserver.h"
9 #include "core/events/Event.h" 9 #include "core/events/Event.h"
10 #include "core/frame/LocalDOMWindow.h" 10 #include "core/frame/LocalDOMWindow.h"
11 #include "core/html/HTMLMediaElement.h" 11 #include "core/html/HTMLMediaElement.h"
12 #include "platform/Histogram.h" 12 #include "platform/Histogram.h"
13 #include "wtf/CurrentTime.h"
13 14
14 namespace blink { 15 namespace blink {
15 16
16 namespace { 17 namespace {
17 18
18 void recordVideoAutoplayMutedPlayMethodBecomesVisibleUma(bool visible) 19 static const double maxUmaDurationMS = 1e6;
19 { 20 static const double umaBucketCount = 20;
mlamouri (slow - plz ping) 2016/08/18 14:15:14 nit: no need for static if in anonymous namespace.
Zhiqiang Zhang (Slow) 2016/08/18 15:11:02 Done.
20 DEFINE_STATIC_LOCAL(BooleanHistogram, histogram, ("Media.Video.Autoplay.Mute d.PlayMethod.BecomesVisible"));
21 histogram.count(visible);
22 }
23 21
24 } // namespace 22 } // namespace
25 23
26 AutoplayUmaHelper* AutoplayUmaHelper::create(HTMLMediaElement* element) 24 AutoplayUmaHelper* AutoplayUmaHelper::create(HTMLMediaElement* element)
27 { 25 {
28 return new AutoplayUmaHelper(element); 26 return new AutoplayUmaHelper(element);
29 } 27 }
30 28
31 AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element) 29 AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element)
32 : EventListener(CPPEventListenerType) 30 : EventListener(CPPEventListenerType)
33 , m_source(AutoplaySource::NumberOfSources) 31 , m_source(AutoplaySource::NumberOfSources)
34 , m_element(element) 32 , m_element(element)
35 , m_videoMutedPlayMethodVisibilityObserver(nullptr) { } 33 , m_mutedVideoPlayMethodVisibilityObserver(nullptr)
34 , m_mutedVideoAutoplayOffscreenStartTimeMS(0)
35 , m_mutedVideoAutoplayOffscreenDurationMS(0)
36 , m_isVisible(false)
37 , m_mutedVideoOffscreenDurationVisibilityObserver(nullptr) { }
36 38
37 AutoplayUmaHelper::~AutoplayUmaHelper() = default; 39 AutoplayUmaHelper::~AutoplayUmaHelper() = default;
38 40
39 bool AutoplayUmaHelper::operator==(const EventListener& other) const 41 bool AutoplayUmaHelper::operator==(const EventListener& other) const
40 { 42 {
41 return this == &other; 43 return this == &other;
42 } 44 }
43 45
44 void AutoplayUmaHelper::onAutoplayInitiated(AutoplaySource source) 46 void AutoplayUmaHelper::onAutoplayInitiated(AutoplaySource source)
45 { 47 {
46 DEFINE_STATIC_LOCAL(EnumerationHistogram, videoHistogram, ("Media.Video.Auto play", static_cast<int>(AutoplaySource::NumberOfSources))); 48 DEFINE_STATIC_LOCAL(EnumerationHistogram, videoHistogram, ("Media.Video.Auto play", static_cast<int>(AutoplaySource::NumberOfSources)));
47 DEFINE_STATIC_LOCAL(EnumerationHistogram, mutedVideoHistogram, ("Media.Video .Autoplay.Muted", static_cast<int>(AutoplaySource::NumberOfSources))); 49 DEFINE_STATIC_LOCAL(EnumerationHistogram, mutedVideoHistogram, ("Media.Video .Autoplay.Muted", static_cast<int>(AutoplaySource::NumberOfSources)));
48 DEFINE_STATIC_LOCAL(EnumerationHistogram, audioHistogram, ("Media.Audio.Auto play", static_cast<int>(AutoplaySource::NumberOfSources))); 50 DEFINE_STATIC_LOCAL(EnumerationHistogram, audioHistogram, ("Media.Audio.Auto play", static_cast<int>(AutoplaySource::NumberOfSources)));
49 51
52 // Autoplay already initiated
53 // TODO(zqzhang): how about having autoplay attribute and calling `play()` i n the script?
54 if (m_source != AutoplaySource::NumberOfSources)
55 return;
56
50 m_source = source; 57 m_source = source;
51 58
52 if (m_element->isHTMLVideoElement()) { 59 if (m_element->isHTMLVideoElement()) {
53 videoHistogram.count(static_cast<int>(m_source)); 60 videoHistogram.count(static_cast<int>(m_source));
54 if (m_element->muted()) 61 if (m_element->muted())
55 mutedVideoHistogram.count(static_cast<int>(m_source)); 62 mutedVideoHistogram.count(static_cast<int>(m_source));
56 } else { 63 } else {
57 audioHistogram.count(static_cast<int>(m_source)); 64 audioHistogram.count(static_cast<int>(m_source));
58 } 65 }
59 66
60 if (m_source == AutoplaySource::Method && m_element->isHTMLVideoElement() && m_element->muted()) 67 m_element->addEventListener(EventTypeNames::playing, this, false);
61 m_element->addEventListener(EventTypeNames::playing, this, false);
62 } 68 }
63 69
64 void AutoplayUmaHelper::recordAutoplayUnmuteStatus(AutoplayUnmuteActionStatus st atus) 70 void AutoplayUmaHelper::recordAutoplayUnmuteStatus(AutoplayUnmuteActionStatus st atus)
65 { 71 {
66 DEFINE_STATIC_LOCAL(EnumerationHistogram, autoplayUnmuteHistogram, ("Media.V ideo.Autoplay.Muted.UnmuteAction", static_cast<int>(AutoplayUnmuteActionStatus:: NumberOfStatus))); 72 DEFINE_STATIC_LOCAL(EnumerationHistogram, autoplayUnmuteHistogram, ("Media.V ideo.Autoplay.Muted.UnmuteAction", static_cast<int>(AutoplayUnmuteActionStatus:: NumberOfStatus)));
67 73
68 autoplayUnmuteHistogram.count(static_cast<int>(status)); 74 autoplayUnmuteHistogram.count(static_cast<int>(status));
69 } 75 }
70 76
71 void AutoplayUmaHelper::didMoveToNewDocument(Document& oldDocument) 77 void AutoplayUmaHelper::didMoveToNewDocument(Document& oldDocument)
72 { 78 {
73 if (!m_videoMutedPlayMethodVisibilityObserver) 79 if (!shouldListenToUnloadEvent())
74 return; 80 return;
75 81
76 if (oldDocument.domWindow()) 82 if (oldDocument.domWindow())
77 oldDocument.domWindow()->removeEventListener(EventTypeNames::unload, thi s, false); 83 oldDocument.domWindow()->removeEventListener(EventTypeNames::unload, thi s, false);
78 if (m_element && m_element->document().domWindow()) 84 if (m_element && m_element->document().domWindow())
79 m_element->document().domWindow()->addEventListener(EventTypeNames::unlo ad, this, false); 85 m_element->document().domWindow()->addEventListener(EventTypeNames::unlo ad, this, false);
80 } 86 }
81 87
82 void AutoplayUmaHelper::onVisibilityChangedForVideoMutedPlayMethod(bool isVisibl e) 88 void AutoplayUmaHelper::onVisibilityChangedForMutedVideoPlayMethodBecomeVisible( bool isVisible)
83 { 89 {
84 if (!isVisible || !m_videoMutedPlayMethodVisibilityObserver) 90 if (!isVisible || !m_mutedVideoPlayMethodVisibilityObserver)
85 return; 91 return;
86 92
87 recordVideoAutoplayMutedPlayMethodBecomesVisibleUma(true); 93 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(true);
88 m_videoMutedPlayMethodVisibilityObserver->stop(); 94 }
89 m_videoMutedPlayMethodVisibilityObserver = nullptr; 95
90 if (m_element && m_element->document().domWindow()) 96 void AutoplayUmaHelper::onVisibilityChangedForMutedVideoOffscreenDuration(bool i sVisible)
91 m_element->document().domWindow()->removeEventListener(EventTypeNames::u nload, this, false); 97 {
98 if (isVisible == m_isVisible)
99 return;
100
101 if (isVisible)
102 m_mutedVideoAutoplayOffscreenDurationMS += monotonicallyIncreasingTimeMS () - m_mutedVideoAutoplayOffscreenStartTimeMS;
103 else
104 m_mutedVideoAutoplayOffscreenStartTimeMS = monotonicallyIncreasingTimeMS ();
105
106 m_isVisible = isVisible;
92 } 107 }
93 108
94 void AutoplayUmaHelper::handleEvent(ExecutionContext* executionContext, Event* e vent) 109 void AutoplayUmaHelper::handleEvent(ExecutionContext* executionContext, Event* e vent)
95 { 110 {
96 if (event->type() == EventTypeNames::playing) 111 if (event->type() == EventTypeNames::playing)
97 handlePlayingEvent(); 112 handlePlayingEvent();
113 else if (event->type() == EventTypeNames::pause)
114 handlePauseEvent();
98 else if (event->type() == EventTypeNames::unload) 115 else if (event->type() == EventTypeNames::unload)
99 handleUnloadEvent(); 116 handleUnloadEvent();
100 else 117 else
101 NOTREACHED(); 118 NOTREACHED();
102 } 119 }
103 120
121 void AutoplayUmaHelper::handlePlayingEvent()
122 {
123 maybeStartRecordingMutedVideoPlayMethodBecomeVisible();
124 maybeStartRecordingMutedVideoOffscreenDuration();
125
126 m_element->removeEventListener(EventTypeNames::playing, this, false);
127 }
128
129 void AutoplayUmaHelper::handlePauseEvent()
130 {
131 if (!m_isVisible)
132 m_mutedVideoAutoplayOffscreenDurationMS += monotonicallyIncreasingTimeMS () - m_mutedVideoAutoplayOffscreenStartTimeMS;
Zhiqiang Zhang (Slow) 2016/08/18 10:52:43 This is new. Accumulating the offscreen time when
mlamouri (slow - plz ping) 2016/08/18 14:15:14 Could you increment on unload if !m_IsVisible? May
Zhiqiang Zhang (Slow) 2016/08/18 15:11:02 Done, moved the final incrementing logic in maybeS
133
134 maybeStopRecordingMutedVideoOffscreenDuration(false);
135 }
136
104 void AutoplayUmaHelper::handleUnloadEvent() 137 void AutoplayUmaHelper::handleUnloadEvent()
105 { 138 {
106 if (m_videoMutedPlayMethodVisibilityObserver) { 139 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(false);
107 recordVideoAutoplayMutedPlayMethodBecomesVisibleUma(false); 140 maybeStopRecordingMutedVideoOffscreenDuration(true);
mlamouri (slow - plz ping) 2016/08/18 14:15:14 Instead of passing isInfinite=true here, could you
Zhiqiang Zhang (Slow) 2016/08/18 15:11:02 Done, moved the final incrementing logic in maybeS
108 m_videoMutedPlayMethodVisibilityObserver->stop();
109 m_videoMutedPlayMethodVisibilityObserver = nullptr;
110 m_element->document().domWindow()->removeEventListener(EventTypeNames::u nload, this, false);
111 }
112 } 141 }
113 142
114 void AutoplayUmaHelper::handlePlayingEvent() 143 void AutoplayUmaHelper::maybeStartRecordingMutedVideoPlayMethodBecomeVisible()
115 { 144 {
116 if (m_source == AutoplaySource::Method && m_element->isHTMLVideoElement() && m_element->muted()) { 145 if (m_source != AutoplaySource::Method || !m_element->isHTMLVideoElement() | | !m_element->muted())
117 if (!m_videoMutedPlayMethodVisibilityObserver) { 146 return;
118 m_videoMutedPlayMethodVisibilityObserver = new ElementVisibilityObse rver(m_element, WTF::bind(&AutoplayUmaHelper::onVisibilityChangedForVideoMutedPl ayMethod, wrapWeakPersistent(this))); 147
119 m_videoMutedPlayMethodVisibilityObserver->start(); 148 m_mutedVideoPlayMethodVisibilityObserver = new ElementVisibilityObserver(m_e lement, WTF::bind(&AutoplayUmaHelper::onVisibilityChangedForMutedVideoPlayMethod BecomeVisible, wrapWeakPersistent(this)));
120 m_element->document().domWindow()->addEventListener(EventTypeNames:: unload, this, false); 149 m_mutedVideoPlayMethodVisibilityObserver->start();
121 } 150 m_element->document().domWindow()->addEventListener(EventTypeNames::unload, this, false);
151 }
152
153 void AutoplayUmaHelper::maybeStopRecordingMutedVideoPlayMethodBecomeVisible(bool visible)
154 {
155 DEFINE_STATIC_LOCAL(BooleanHistogram, histogram, ("Media.Video.Autoplay.Mute d.PlayMethod.BecomesVisible"));
156
157 if (!m_mutedVideoPlayMethodVisibilityObserver)
mlamouri (slow - plz ping) 2016/08/18 14:15:14 nit: to make sure the metric is properly recorded,
Zhiqiang Zhang (Slow) 2016/08/18 15:11:02 Won't fix as we discussed offline.
158 return;
159
160 histogram.count(visible);
161 m_mutedVideoPlayMethodVisibilityObserver->stop();
162 m_mutedVideoPlayMethodVisibilityObserver = nullptr;
163 maybeUnregisterUnloadListener();
164 }
165
166 void AutoplayUmaHelper::maybeStartRecordingMutedVideoOffscreenDuration()
167 {
168 if (!m_element->isHTMLVideoElement() || !m_element->muted())
169 return;
170
171 // Start recording muted video playing offscreen duration.
172 m_mutedVideoAutoplayOffscreenStartTimeMS = monotonicallyIncreasingTimeMS();
173 m_isVisible = false;
174 m_mutedVideoOffscreenDurationVisibilityObserver = new ElementVisibilityObser ver(m_element, WTF::bind(&AutoplayUmaHelper::onVisibilityChangedForMutedVideoOff screenDuration, wrapWeakPersistent(this)));
175 m_mutedVideoOffscreenDurationVisibilityObserver->start();
176 m_element->addEventListener(EventTypeNames::pause, this, false);
177 m_element->document().domWindow()->addEventListener(EventTypeNames::unload, this, false);
178 }
179
180 void AutoplayUmaHelper::maybeStopRecordingMutedVideoOffscreenDuration(bool isInf inite)
181 {
182 if (!m_mutedVideoOffscreenDurationVisibilityObserver)
183 return;
mlamouri (slow - plz ping) 2016/08/18 14:15:14 ditto, see above
Zhiqiang Zhang (Slow) 2016/08/18 15:11:01 ditto.
184
185 double timeDeltaMS = isInfinite ? std::numeric_limits<int32_t>::max() : m_mu tedVideoAutoplayOffscreenDurationMS;
mlamouri (slow - plz ping) 2016/08/18 14:15:14 I'm really confused in how you use this. m_mutedVi
Zhiqiang Zhang (Slow) 2016/08/18 15:11:02 Only using m_mutedVideoAutoplayOffscreenDurationMS
186
187 if (m_source == AutoplaySource::Attribute) {
188 DEFINE_STATIC_LOCAL(CustomCountHistogram, durationHistogram, ("Media.Vid eo.Autoplay.Muted.Attribute.OffscreenDuration", 1, maxUmaDurationMS, umaBucketCo unt));
189 durationHistogram.count(timeDeltaMS);
190 } else {
191 DEFINE_STATIC_LOCAL(CustomCountHistogram, durationHistogram, ("Media.Vid eo.Autoplay.Muted.PlayMethod.OffscreenDuration", 1, maxUmaDurationMS, umaBucketC ount));
192 durationHistogram.count(timeDeltaMS);
122 } 193 }
123 m_element->removeEventListener(EventTypeNames::playing, this, false); 194 m_mutedVideoOffscreenDurationVisibilityObserver->stop();
195 m_mutedVideoOffscreenDurationVisibilityObserver = nullptr;
196 m_mutedVideoAutoplayOffscreenDurationMS = 0;
197 m_element->removeEventListener(EventTypeNames::pause, this, false);
198 maybeUnregisterUnloadListener();
199 }
200
201 void AutoplayUmaHelper::maybeUnregisterUnloadListener()
202 {
203 if (!shouldListenToUnloadEvent() && m_element && m_element->document().domWi ndow())
204 m_element->document().domWindow()->removeEventListener(EventTypeNames::u nload, this, false);
205 }
206
207 bool AutoplayUmaHelper::shouldListenToUnloadEvent() const
208 {
209 return m_mutedVideoPlayMethodVisibilityObserver || m_mutedVideoOffscreenDura tionVisibilityObserver;
124 } 210 }
125 211
126 DEFINE_TRACE(AutoplayUmaHelper) 212 DEFINE_TRACE(AutoplayUmaHelper)
127 { 213 {
128 EventListener::trace(visitor); 214 EventListener::trace(visitor);
129 visitor->trace(m_element); 215 visitor->trace(m_element);
130 visitor->trace(m_videoMutedPlayMethodVisibilityObserver); 216 visitor->trace(m_mutedVideoPlayMethodVisibilityObserver);
217 visitor->trace(m_mutedVideoOffscreenDurationVisibilityObserver);
131 } 218 }
132 219
133 } // namespace blink 220 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/html/AutoplayUmaHelper.h ('k') | tools/metrics/histograms/histograms.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698