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

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

Issue 2780403004: Create core/html/media/ and move auxiliary media files in it. (Closed)
Patch Set: actually add autoplay files Created 3 years, 8 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "core/html/AutoplayUmaHelper.h"
6
7 #include "core/dom/Document.h"
8 #include "core/dom/ElementVisibilityObserver.h"
9 #include "core/events/Event.h"
10 #include "core/frame/Settings.h"
11 #include "core/html/HTMLMediaElement.h"
12 #include "platform/Histogram.h"
13 #include "public/platform/Platform.h"
14 #include "wtf/CurrentTime.h"
15
16 namespace blink {
17
18 namespace {
19
20 const int32_t maxOffscreenDurationUmaMS = 60 * 60 * 1000;
21 const int32_t offscreenDurationUmaBucketCount = 50;
22
23 } // namespace
24
25 AutoplayUmaHelper* AutoplayUmaHelper::create(HTMLMediaElement* element) {
26 return new AutoplayUmaHelper(element);
27 }
28
29 AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element)
30 : EventListener(CPPEventListenerType),
31 ContextLifecycleObserver(nullptr),
32 m_element(element),
33 m_mutedVideoPlayMethodVisibilityObserver(nullptr),
34 m_mutedVideoAutoplayOffscreenStartTimeMS(0),
35 m_mutedVideoAutoplayOffscreenDurationMS(0),
36 m_isVisible(false),
37 m_mutedVideoOffscreenDurationVisibilityObserver(nullptr) {}
38
39 AutoplayUmaHelper::~AutoplayUmaHelper() = default;
40
41 bool AutoplayUmaHelper::operator==(const EventListener& other) const {
42 return this == &other;
43 }
44
45 void AutoplayUmaHelper::onAutoplayInitiated(AutoplaySource source) {
46 DEFINE_STATIC_LOCAL(EnumerationHistogram, videoHistogram,
47 ("Media.Video.Autoplay",
48 static_cast<int>(AutoplaySource::NumberOfUmaSources)));
49 DEFINE_STATIC_LOCAL(EnumerationHistogram, mutedVideoHistogram,
50 ("Media.Video.Autoplay.Muted",
51 static_cast<int>(AutoplaySource::NumberOfUmaSources)));
52 DEFINE_STATIC_LOCAL(EnumerationHistogram, audioHistogram,
53 ("Media.Audio.Autoplay",
54 static_cast<int>(AutoplaySource::NumberOfUmaSources)));
55 DEFINE_STATIC_LOCAL(
56 EnumerationHistogram, blockedMutedVideoHistogram,
57 ("Media.Video.Autoplay.Muted.Blocked", AutoplayBlockedReasonMax));
58
59 // Autoplay already initiated
60 if (m_sources.count(source))
61 return;
62
63 m_sources.insert(source);
64
65 // Record the source.
66 if (m_element->isHTMLVideoElement()) {
67 videoHistogram.count(static_cast<int>(source));
68 if (m_element->muted())
69 mutedVideoHistogram.count(static_cast<int>(source));
70 } else {
71 audioHistogram.count(static_cast<int>(source));
72 }
73
74 // Record dual source.
75 if (m_sources.size() ==
76 static_cast<size_t>(AutoplaySource::NumberOfSources)) {
77 if (m_element->isHTMLVideoElement()) {
78 videoHistogram.count(static_cast<int>(AutoplaySource::DualSource));
79 if (m_element->muted())
80 mutedVideoHistogram.count(static_cast<int>(AutoplaySource::DualSource));
81 } else {
82 audioHistogram.count(static_cast<int>(AutoplaySource::DualSource));
83 }
84 }
85
86 // Record the child frame and top-level frame URLs for autoplay muted videos
87 // by attribute.
88 if (m_element->isHTMLVideoElement() && m_element->muted()) {
89 if (m_sources.size() ==
90 static_cast<size_t>(AutoplaySource::NumberOfSources)) {
91 Platform::current()->recordRapporURL(
92 "Media.Video.Autoplay.Muted.DualSource.Frame",
93 m_element->document().url());
94 } else if (source == AutoplaySource::Attribute) {
95 Platform::current()->recordRapporURL(
96 "Media.Video.Autoplay.Muted.Attribute.Frame",
97 m_element->document().url());
98 } else {
99 DCHECK(source == AutoplaySource::Method);
100 Platform::current()->recordRapporURL(
101 "Media.Video.Autoplay.Muted.PlayMethod.Frame",
102 m_element->document().url());
103 }
104 }
105
106 // Record if it will be blocked by Data Saver or Autoplay setting.
107 if (m_element->isHTMLVideoElement() && m_element->muted() &&
108 RuntimeEnabledFeatures::autoplayMutedVideosEnabled()) {
109 bool dataSaverEnabled =
110 m_element->document().settings() &&
111 m_element->document().settings()->getDataSaverEnabled();
112 bool blockedBySetting = !m_element->isAutoplayAllowedPerSettings();
113
114 if (dataSaverEnabled && blockedBySetting) {
115 blockedMutedVideoHistogram.count(
116 AutoplayBlockedReasonDataSaverAndSetting);
117 } else if (dataSaverEnabled) {
118 blockedMutedVideoHistogram.count(AutoplayBlockedReasonDataSaver);
119 } else if (blockedBySetting) {
120 blockedMutedVideoHistogram.count(AutoplayBlockedReasonSetting);
121 }
122 }
123
124 m_element->addEventListener(EventTypeNames::playing, this, false);
125 }
126
127 void AutoplayUmaHelper::recordCrossOriginAutoplayResult(
128 CrossOriginAutoplayResult result) {
129 DEFINE_STATIC_LOCAL(
130 EnumerationHistogram, autoplayResultHistogram,
131 ("Media.Autoplay.CrossOrigin.Result",
132 static_cast<int>(CrossOriginAutoplayResult::NumberOfResults)));
133
134 if (!m_element->isHTMLVideoElement())
135 return;
136 if (!m_element->isInCrossOriginFrame())
137 return;
138
139 // Record each metric only once per element, since the metric focuses on the
140 // site distribution. If a page calls play() multiple times, it will be
141 // recorded only once.
142 if (m_recordedCrossOriginAutoplayResults.count(result))
143 return;
144
145 switch (result) {
146 case CrossOriginAutoplayResult::AutoplayAllowed:
147 // Record metric
148 Platform::current()->recordRapporURL(
149 "Media.Autoplay.CrossOrigin.Allowed.ChildFrame",
150 m_element->document().url());
151 Platform::current()->recordRapporURL(
152 "Media.Autoplay.CrossOrigin.Allowed.TopLevelFrame",
153 m_element->document().topDocument().url());
154 autoplayResultHistogram.count(static_cast<int>(result));
155 m_recordedCrossOriginAutoplayResults.insert(result);
156 break;
157 case CrossOriginAutoplayResult::AutoplayBlocked:
158 Platform::current()->recordRapporURL(
159 "Media.Autoplay.CrossOrigin.Blocked.ChildFrame",
160 m_element->document().url());
161 Platform::current()->recordRapporURL(
162 "Media.Autoplay.CrossOrigin.Blocked.TopLevelFrame",
163 m_element->document().topDocument().url());
164 autoplayResultHistogram.count(static_cast<int>(result));
165 m_recordedCrossOriginAutoplayResults.insert(result);
166 break;
167 case CrossOriginAutoplayResult::PlayedWithGesture:
168 // Record this metric only when the video has been blocked from autoplay
169 // previously. This is to record the sites having videos that are blocked
170 // to autoplay but the user starts the playback by gesture.
171 if (!m_recordedCrossOriginAutoplayResults.count(
172 CrossOriginAutoplayResult::AutoplayBlocked)) {
173 return;
174 }
175 Platform::current()->recordRapporURL(
176 "Media.Autoplay.CrossOrigin.PlayedWithGestureAfterBlock.ChildFrame",
177 m_element->document().url());
178 Platform::current()->recordRapporURL(
179 "Media.Autoplay.CrossOrigin.PlayedWithGestureAfterBlock."
180 "TopLevelFrame",
181 m_element->document().topDocument().url());
182 autoplayResultHistogram.count(static_cast<int>(result));
183 m_recordedCrossOriginAutoplayResults.insert(result);
184 break;
185 case CrossOriginAutoplayResult::UserPaused:
186 if (!shouldRecordUserPausedAutoplayingCrossOriginVideo())
187 return;
188 if (m_element->ended() || m_element->seeking())
189 return;
190 Platform::current()->recordRapporURL(
191 "Media.Autoplay.CrossOrigin.UserPausedAutoplayingVideo.ChildFrame",
192 m_element->document().url());
193 Platform::current()->recordRapporURL(
194 "Media.Autoplay.CrossOrigin.UserPausedAutoplayingVideo."
195 "TopLevelFrame",
196 m_element->document().topDocument().url());
197 autoplayResultHistogram.count(static_cast<int>(result));
198 m_recordedCrossOriginAutoplayResults.insert(result);
199 break;
200 default:
201 NOTREACHED();
202 }
203 }
204
205 void AutoplayUmaHelper::recordAutoplayUnmuteStatus(
206 AutoplayUnmuteActionStatus status) {
207 DEFINE_STATIC_LOCAL(
208 EnumerationHistogram, autoplayUnmuteHistogram,
209 ("Media.Video.Autoplay.Muted.UnmuteAction",
210 static_cast<int>(AutoplayUnmuteActionStatus::NumberOfStatus)));
211
212 autoplayUnmuteHistogram.count(static_cast<int>(status));
213 }
214
215 void AutoplayUmaHelper::didMoveToNewDocument(Document& oldDocument) {
216 if (!shouldListenToContextDestroyed())
217 return;
218
219 setContext(&m_element->document());
220 }
221
222 void AutoplayUmaHelper::onVisibilityChangedForMutedVideoPlayMethodBecomeVisible(
223 bool isVisible) {
224 if (!isVisible || !m_mutedVideoPlayMethodVisibilityObserver)
225 return;
226
227 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(true);
228 }
229
230 void AutoplayUmaHelper::onVisibilityChangedForMutedVideoOffscreenDuration(
231 bool isVisible) {
232 if (isVisible == m_isVisible)
233 return;
234
235 if (isVisible)
236 m_mutedVideoAutoplayOffscreenDurationMS +=
237 static_cast<int64_t>(monotonicallyIncreasingTimeMS()) -
238 m_mutedVideoAutoplayOffscreenStartTimeMS;
239 else
240 m_mutedVideoAutoplayOffscreenStartTimeMS =
241 static_cast<int64_t>(monotonicallyIncreasingTimeMS());
242
243 m_isVisible = isVisible;
244 }
245
246 void AutoplayUmaHelper::handleEvent(ExecutionContext* executionContext,
247 Event* event) {
248 if (event->type() == EventTypeNames::playing)
249 handlePlayingEvent();
250 else if (event->type() == EventTypeNames::pause)
251 handlePauseEvent();
252 else
253 NOTREACHED();
254 }
255
256 void AutoplayUmaHelper::handlePlayingEvent() {
257 maybeStartRecordingMutedVideoPlayMethodBecomeVisible();
258 maybeStartRecordingMutedVideoOffscreenDuration();
259
260 m_element->removeEventListener(EventTypeNames::playing, this, false);
261 }
262
263 void AutoplayUmaHelper::handlePauseEvent() {
264 maybeStopRecordingMutedVideoOffscreenDuration();
265 maybeRecordUserPausedAutoplayingCrossOriginVideo();
266 }
267
268 void AutoplayUmaHelper::contextDestroyed(ExecutionContext*) {
269 handleContextDestroyed();
270 }
271
272 void AutoplayUmaHelper::handleContextDestroyed() {
273 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(false);
274 maybeStopRecordingMutedVideoOffscreenDuration();
275 }
276
277 void AutoplayUmaHelper::maybeStartRecordingMutedVideoPlayMethodBecomeVisible() {
278 if (!m_sources.count(AutoplaySource::Method) ||
279 !m_element->isHTMLVideoElement() || !m_element->muted())
280 return;
281
282 m_mutedVideoPlayMethodVisibilityObserver = new ElementVisibilityObserver(
283 m_element,
284 WTF::bind(&AutoplayUmaHelper::
285 onVisibilityChangedForMutedVideoPlayMethodBecomeVisible,
286 wrapWeakPersistent(this)));
287 m_mutedVideoPlayMethodVisibilityObserver->start();
288 setContext(&m_element->document());
289 }
290
291 void AutoplayUmaHelper::maybeStopRecordingMutedVideoPlayMethodBecomeVisible(
292 bool visible) {
293 if (!m_mutedVideoPlayMethodVisibilityObserver)
294 return;
295
296 DEFINE_STATIC_LOCAL(BooleanHistogram, histogram,
297 ("Media.Video.Autoplay.Muted.PlayMethod.BecomesVisible"));
298
299 histogram.count(visible);
300 m_mutedVideoPlayMethodVisibilityObserver->stop();
301 m_mutedVideoPlayMethodVisibilityObserver = nullptr;
302 maybeUnregisterContextDestroyedObserver();
303 }
304
305 void AutoplayUmaHelper::maybeStartRecordingMutedVideoOffscreenDuration() {
306 if (!m_element->isHTMLVideoElement() || !m_element->muted() ||
307 !m_sources.count(AutoplaySource::Method))
308 return;
309
310 // Start recording muted video playing offscreen duration.
311 m_mutedVideoAutoplayOffscreenStartTimeMS =
312 static_cast<int64_t>(monotonicallyIncreasingTimeMS());
313 m_isVisible = false;
314 m_mutedVideoOffscreenDurationVisibilityObserver =
315 new ElementVisibilityObserver(
316 m_element,
317 WTF::bind(&AutoplayUmaHelper::
318 onVisibilityChangedForMutedVideoOffscreenDuration,
319 wrapWeakPersistent(this)));
320 m_mutedVideoOffscreenDurationVisibilityObserver->start();
321 m_element->addEventListener(EventTypeNames::pause, this, false);
322 setContext(&m_element->document());
323 }
324
325 void AutoplayUmaHelper::maybeStopRecordingMutedVideoOffscreenDuration() {
326 if (!m_mutedVideoOffscreenDurationVisibilityObserver)
327 return;
328
329 if (!m_isVisible)
330 m_mutedVideoAutoplayOffscreenDurationMS +=
331 static_cast<int64_t>(monotonicallyIncreasingTimeMS()) -
332 m_mutedVideoAutoplayOffscreenStartTimeMS;
333
334 // Since histograms uses int32_t, the duration needs to be limited to
335 // std::numeric_limits<int32_t>::max().
336 int32_t boundedTime = static_cast<int32_t>(
337 std::min<int64_t>(m_mutedVideoAutoplayOffscreenDurationMS,
338 std::numeric_limits<int32_t>::max()));
339
340 DCHECK(m_sources.count(AutoplaySource::Method));
341
342 DEFINE_STATIC_LOCAL(
343 CustomCountHistogram, durationHistogram,
344 ("Media.Video.Autoplay.Muted.PlayMethod.OffscreenDuration", 1,
345 maxOffscreenDurationUmaMS, offscreenDurationUmaBucketCount));
346 durationHistogram.count(boundedTime);
347
348 m_mutedVideoOffscreenDurationVisibilityObserver->stop();
349 m_mutedVideoOffscreenDurationVisibilityObserver = nullptr;
350 m_mutedVideoAutoplayOffscreenDurationMS = 0;
351 maybeUnregisterMediaElementPauseListener();
352 maybeUnregisterContextDestroyedObserver();
353 }
354
355 void AutoplayUmaHelper::maybeRecordUserPausedAutoplayingCrossOriginVideo() {
356 recordCrossOriginAutoplayResult(CrossOriginAutoplayResult::UserPaused);
357 maybeUnregisterMediaElementPauseListener();
358 }
359
360 void AutoplayUmaHelper::maybeUnregisterContextDestroyedObserver() {
361 if (!shouldListenToContextDestroyed()) {
362 setContext(nullptr);
363 }
364 }
365
366 void AutoplayUmaHelper::maybeUnregisterMediaElementPauseListener() {
367 if (m_mutedVideoOffscreenDurationVisibilityObserver)
368 return;
369 if (shouldRecordUserPausedAutoplayingCrossOriginVideo())
370 return;
371 m_element->removeEventListener(EventTypeNames::pause, this, false);
372 }
373
374 bool AutoplayUmaHelper::shouldListenToContextDestroyed() const {
375 return m_mutedVideoPlayMethodVisibilityObserver ||
376 m_mutedVideoOffscreenDurationVisibilityObserver;
377 }
378
379 bool AutoplayUmaHelper::shouldRecordUserPausedAutoplayingCrossOriginVideo()
380 const {
381 return m_element->isInCrossOriginFrame() && m_element->isHTMLVideoElement() &&
382 !m_sources.empty() &&
383 !m_recordedCrossOriginAutoplayResults.count(
384 CrossOriginAutoplayResult::UserPaused);
385 }
386
387 DEFINE_TRACE(AutoplayUmaHelper) {
388 EventListener::trace(visitor);
389 ContextLifecycleObserver::trace(visitor);
390 visitor->trace(m_element);
391 visitor->trace(m_mutedVideoPlayMethodVisibilityObserver);
392 visitor->trace(m_mutedVideoOffscreenDurationVisibilityObserver);
393 }
394
395 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698