| OLD | NEW |
| 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/Settings.h" | 10 #include "core/frame/Settings.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 | 22 |
| 23 } // namespace | 23 } // namespace |
| 24 | 24 |
| 25 AutoplayUmaHelper* AutoplayUmaHelper::create(HTMLMediaElement* element) { | 25 AutoplayUmaHelper* AutoplayUmaHelper::create(HTMLMediaElement* element) { |
| 26 return new AutoplayUmaHelper(element); | 26 return new AutoplayUmaHelper(element); |
| 27 } | 27 } |
| 28 | 28 |
| 29 AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element) | 29 AutoplayUmaHelper::AutoplayUmaHelper(HTMLMediaElement* element) |
| 30 : EventListener(CPPEventListenerType), | 30 : EventListener(CPPEventListenerType), |
| 31 ContextLifecycleObserver(nullptr), | 31 ContextLifecycleObserver(nullptr), |
| 32 m_source(AutoplaySource::NumberOfSources), | |
| 33 m_element(element), | 32 m_element(element), |
| 34 m_mutedVideoPlayMethodVisibilityObserver(nullptr), | 33 m_mutedVideoPlayMethodVisibilityObserver(nullptr), |
| 35 m_mutedVideoAutoplayOffscreenStartTimeMS(0), | 34 m_mutedVideoAutoplayOffscreenStartTimeMS(0), |
| 36 m_mutedVideoAutoplayOffscreenDurationMS(0), | 35 m_mutedVideoAutoplayOffscreenDurationMS(0), |
| 37 m_isVisible(false), | 36 m_isVisible(false), |
| 38 m_mutedVideoOffscreenDurationVisibilityObserver(nullptr) {} | 37 m_mutedVideoOffscreenDurationVisibilityObserver(nullptr) {} |
| 39 | 38 |
| 40 AutoplayUmaHelper::~AutoplayUmaHelper() = default; | 39 AutoplayUmaHelper::~AutoplayUmaHelper() = default; |
| 41 | 40 |
| 42 bool AutoplayUmaHelper::operator==(const EventListener& other) const { | 41 bool AutoplayUmaHelper::operator==(const EventListener& other) const { |
| 43 return this == &other; | 42 return this == &other; |
| 44 } | 43 } |
| 45 | 44 |
| 46 void AutoplayUmaHelper::onAutoplayInitiated(AutoplaySource source) { | 45 void AutoplayUmaHelper::onAutoplayInitiated(AutoplaySource source) { |
| 47 DEFINE_STATIC_LOCAL(EnumerationHistogram, videoHistogram, | 46 DEFINE_STATIC_LOCAL(EnumerationHistogram, videoHistogram, |
| 48 ("Media.Video.Autoplay", | 47 ("Media.Video.Autoplay", |
| 49 static_cast<int>(AutoplaySource::NumberOfSources))); | 48 static_cast<int>(AutoplaySource::NumberOfUmaSources))); |
| 50 DEFINE_STATIC_LOCAL(EnumerationHistogram, mutedVideoHistogram, | 49 DEFINE_STATIC_LOCAL(EnumerationHistogram, mutedVideoHistogram, |
| 51 ("Media.Video.Autoplay.Muted", | 50 ("Media.Video.Autoplay.Muted", |
| 52 static_cast<int>(AutoplaySource::NumberOfSources))); | 51 static_cast<int>(AutoplaySource::NumberOfUmaSources))); |
| 53 DEFINE_STATIC_LOCAL(EnumerationHistogram, audioHistogram, | 52 DEFINE_STATIC_LOCAL(EnumerationHistogram, audioHistogram, |
| 54 ("Media.Audio.Autoplay", | 53 ("Media.Audio.Autoplay", |
| 55 static_cast<int>(AutoplaySource::NumberOfSources))); | 54 static_cast<int>(AutoplaySource::NumberOfUmaSources))); |
| 56 DEFINE_STATIC_LOCAL( | 55 DEFINE_STATIC_LOCAL( |
| 57 EnumerationHistogram, blockedMutedVideoHistogram, | 56 EnumerationHistogram, blockedMutedVideoHistogram, |
| 58 ("Media.Video.Autoplay.Muted.Blocked", AutoplayBlockedReasonMax)); | 57 ("Media.Video.Autoplay.Muted.Blocked", AutoplayBlockedReasonMax)); |
| 59 | 58 |
| 60 // Autoplay already initiated | 59 // Autoplay already initiated |
| 61 // TODO(zqzhang): how about having autoplay attribute and calling `play()` in | 60 if (m_sources.count(source)) |
| 62 // the script? | |
| 63 if (hasSource()) | |
| 64 return; | 61 return; |
| 65 | 62 |
| 66 m_source = source; | 63 m_sources.insert(source); |
| 67 | 64 |
| 68 // Record the source. | 65 // Record the source. |
| 69 if (m_element->isHTMLVideoElement()) { | 66 if (m_element->isHTMLVideoElement()) { |
| 70 videoHistogram.count(static_cast<int>(m_source)); | 67 videoHistogram.count(static_cast<int>(source)); |
| 71 if (m_element->muted()) | 68 if (m_element->muted()) |
| 72 mutedVideoHistogram.count(static_cast<int>(m_source)); | 69 mutedVideoHistogram.count(static_cast<int>(source)); |
| 73 } else { | 70 } else { |
| 74 audioHistogram.count(static_cast<int>(m_source)); | 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 } |
| 75 } | 84 } |
| 76 | 85 |
| 77 // Record the child frame and top-level frame URLs for autoplay muted videos | 86 // Record the child frame and top-level frame URLs for autoplay muted videos |
| 78 // by attribute. | 87 // by attribute. |
| 79 if (m_element->isHTMLVideoElement() && m_element->muted()) { | 88 if (m_element->isHTMLVideoElement() && m_element->muted()) { |
| 80 if (source == AutoplaySource::Attribute) { | 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) { |
| 81 Platform::current()->recordRapporURL( | 95 Platform::current()->recordRapporURL( |
| 82 "Media.Video.Autoplay.Muted.Attribute.Frame", | 96 "Media.Video.Autoplay.Muted.Attribute.Frame", |
| 83 m_element->document().url()); | 97 m_element->document().url()); |
| 84 } else { | 98 } else { |
| 85 DCHECK(source == AutoplaySource::Method); | 99 DCHECK(source == AutoplaySource::Method); |
| 86 Platform::current()->recordRapporURL( | 100 Platform::current()->recordRapporURL( |
| 87 "Media.Video.Autoplay.Muted.PlayMethod.Frame", | 101 "Media.Video.Autoplay.Muted.PlayMethod.Frame", |
| 88 m_element->document().url()); | 102 m_element->document().url()); |
| 89 } | 103 } |
| 90 } | 104 } |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 void AutoplayUmaHelper::contextDestroyed(ExecutionContext*) { | 268 void AutoplayUmaHelper::contextDestroyed(ExecutionContext*) { |
| 255 handleContextDestroyed(); | 269 handleContextDestroyed(); |
| 256 } | 270 } |
| 257 | 271 |
| 258 void AutoplayUmaHelper::handleContextDestroyed() { | 272 void AutoplayUmaHelper::handleContextDestroyed() { |
| 259 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(false); | 273 maybeStopRecordingMutedVideoPlayMethodBecomeVisible(false); |
| 260 maybeStopRecordingMutedVideoOffscreenDuration(); | 274 maybeStopRecordingMutedVideoOffscreenDuration(); |
| 261 } | 275 } |
| 262 | 276 |
| 263 void AutoplayUmaHelper::maybeStartRecordingMutedVideoPlayMethodBecomeVisible() { | 277 void AutoplayUmaHelper::maybeStartRecordingMutedVideoPlayMethodBecomeVisible() { |
| 264 if (m_source != AutoplaySource::Method || !m_element->isHTMLVideoElement() || | 278 if (!m_sources.count(AutoplaySource::Method) || |
| 265 !m_element->muted()) | 279 !m_element->isHTMLVideoElement() || !m_element->muted()) |
| 266 return; | 280 return; |
| 267 | 281 |
| 268 m_mutedVideoPlayMethodVisibilityObserver = new ElementVisibilityObserver( | 282 m_mutedVideoPlayMethodVisibilityObserver = new ElementVisibilityObserver( |
| 269 m_element, | 283 m_element, |
| 270 WTF::bind(&AutoplayUmaHelper:: | 284 WTF::bind(&AutoplayUmaHelper:: |
| 271 onVisibilityChangedForMutedVideoPlayMethodBecomeVisible, | 285 onVisibilityChangedForMutedVideoPlayMethodBecomeVisible, |
| 272 wrapWeakPersistent(this))); | 286 wrapWeakPersistent(this))); |
| 273 m_mutedVideoPlayMethodVisibilityObserver->start(); | 287 m_mutedVideoPlayMethodVisibilityObserver->start(); |
| 274 setContext(&m_element->document()); | 288 setContext(&m_element->document()); |
| 275 } | 289 } |
| 276 | 290 |
| 277 void AutoplayUmaHelper::maybeStopRecordingMutedVideoPlayMethodBecomeVisible( | 291 void AutoplayUmaHelper::maybeStopRecordingMutedVideoPlayMethodBecomeVisible( |
| 278 bool visible) { | 292 bool visible) { |
| 279 if (!m_mutedVideoPlayMethodVisibilityObserver) | 293 if (!m_mutedVideoPlayMethodVisibilityObserver) |
| 280 return; | 294 return; |
| 281 | 295 |
| 282 DEFINE_STATIC_LOCAL(BooleanHistogram, histogram, | 296 DEFINE_STATIC_LOCAL(BooleanHistogram, histogram, |
| 283 ("Media.Video.Autoplay.Muted.PlayMethod.BecomesVisible")); | 297 ("Media.Video.Autoplay.Muted.PlayMethod.BecomesVisible")); |
| 284 | 298 |
| 285 histogram.count(visible); | 299 histogram.count(visible); |
| 286 m_mutedVideoPlayMethodVisibilityObserver->stop(); | 300 m_mutedVideoPlayMethodVisibilityObserver->stop(); |
| 287 m_mutedVideoPlayMethodVisibilityObserver = nullptr; | 301 m_mutedVideoPlayMethodVisibilityObserver = nullptr; |
| 288 maybeUnregisterContextDestroyedObserver(); | 302 maybeUnregisterContextDestroyedObserver(); |
| 289 } | 303 } |
| 290 | 304 |
| 291 void AutoplayUmaHelper::maybeStartRecordingMutedVideoOffscreenDuration() { | 305 void AutoplayUmaHelper::maybeStartRecordingMutedVideoOffscreenDuration() { |
| 292 if (!m_element->isHTMLVideoElement() || !m_element->muted()) | 306 if (!m_element->isHTMLVideoElement() || !m_element->muted() || |
| 307 !m_sources.count(AutoplaySource::Method)) |
| 293 return; | 308 return; |
| 294 | 309 |
| 295 // Start recording muted video playing offscreen duration. | 310 // Start recording muted video playing offscreen duration. |
| 296 m_mutedVideoAutoplayOffscreenStartTimeMS = | 311 m_mutedVideoAutoplayOffscreenStartTimeMS = |
| 297 static_cast<int64_t>(monotonicallyIncreasingTimeMS()); | 312 static_cast<int64_t>(monotonicallyIncreasingTimeMS()); |
| 298 m_isVisible = false; | 313 m_isVisible = false; |
| 299 m_mutedVideoOffscreenDurationVisibilityObserver = | 314 m_mutedVideoOffscreenDurationVisibilityObserver = |
| 300 new ElementVisibilityObserver( | 315 new ElementVisibilityObserver( |
| 301 m_element, | 316 m_element, |
| 302 WTF::bind(&AutoplayUmaHelper:: | 317 WTF::bind(&AutoplayUmaHelper:: |
| (...skipping 12 matching lines...) Expand all Loading... |
| 315 m_mutedVideoAutoplayOffscreenDurationMS += | 330 m_mutedVideoAutoplayOffscreenDurationMS += |
| 316 static_cast<int64_t>(monotonicallyIncreasingTimeMS()) - | 331 static_cast<int64_t>(monotonicallyIncreasingTimeMS()) - |
| 317 m_mutedVideoAutoplayOffscreenStartTimeMS; | 332 m_mutedVideoAutoplayOffscreenStartTimeMS; |
| 318 | 333 |
| 319 // Since histograms uses int32_t, the duration needs to be limited to | 334 // Since histograms uses int32_t, the duration needs to be limited to |
| 320 // std::numeric_limits<int32_t>::max(). | 335 // std::numeric_limits<int32_t>::max(). |
| 321 int32_t boundedTime = static_cast<int32_t>( | 336 int32_t boundedTime = static_cast<int32_t>( |
| 322 std::min<int64_t>(m_mutedVideoAutoplayOffscreenDurationMS, | 337 std::min<int64_t>(m_mutedVideoAutoplayOffscreenDurationMS, |
| 323 std::numeric_limits<int32_t>::max())); | 338 std::numeric_limits<int32_t>::max())); |
| 324 | 339 |
| 325 if (m_source == AutoplaySource::Method) { | 340 DCHECK(m_sources.count(AutoplaySource::Method)); |
| 326 DEFINE_STATIC_LOCAL( | 341 |
| 327 CustomCountHistogram, durationHistogram, | 342 DEFINE_STATIC_LOCAL( |
| 328 ("Media.Video.Autoplay.Muted.PlayMethod.OffscreenDuration", 1, | 343 CustomCountHistogram, durationHistogram, |
| 329 maxOffscreenDurationUmaMS, offscreenDurationUmaBucketCount)); | 344 ("Media.Video.Autoplay.Muted.PlayMethod.OffscreenDuration", 1, |
| 330 durationHistogram.count(boundedTime); | 345 maxOffscreenDurationUmaMS, offscreenDurationUmaBucketCount)); |
| 331 } | 346 durationHistogram.count(boundedTime); |
| 347 |
| 332 m_mutedVideoOffscreenDurationVisibilityObserver->stop(); | 348 m_mutedVideoOffscreenDurationVisibilityObserver->stop(); |
| 333 m_mutedVideoOffscreenDurationVisibilityObserver = nullptr; | 349 m_mutedVideoOffscreenDurationVisibilityObserver = nullptr; |
| 334 m_mutedVideoAutoplayOffscreenDurationMS = 0; | 350 m_mutedVideoAutoplayOffscreenDurationMS = 0; |
| 335 maybeUnregisterMediaElementPauseListener(); | 351 maybeUnregisterMediaElementPauseListener(); |
| 336 maybeUnregisterContextDestroyedObserver(); | 352 maybeUnregisterContextDestroyedObserver(); |
| 337 } | 353 } |
| 338 | 354 |
| 339 void AutoplayUmaHelper::maybeRecordUserPausedAutoplayingCrossOriginVideo() { | 355 void AutoplayUmaHelper::maybeRecordUserPausedAutoplayingCrossOriginVideo() { |
| 340 recordCrossOriginAutoplayResult(CrossOriginAutoplayResult::UserPaused); | 356 recordCrossOriginAutoplayResult(CrossOriginAutoplayResult::UserPaused); |
| 341 maybeUnregisterMediaElementPauseListener(); | 357 maybeUnregisterMediaElementPauseListener(); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 356 } | 372 } |
| 357 | 373 |
| 358 bool AutoplayUmaHelper::shouldListenToContextDestroyed() const { | 374 bool AutoplayUmaHelper::shouldListenToContextDestroyed() const { |
| 359 return m_mutedVideoPlayMethodVisibilityObserver || | 375 return m_mutedVideoPlayMethodVisibilityObserver || |
| 360 m_mutedVideoOffscreenDurationVisibilityObserver; | 376 m_mutedVideoOffscreenDurationVisibilityObserver; |
| 361 } | 377 } |
| 362 | 378 |
| 363 bool AutoplayUmaHelper::shouldRecordUserPausedAutoplayingCrossOriginVideo() | 379 bool AutoplayUmaHelper::shouldRecordUserPausedAutoplayingCrossOriginVideo() |
| 364 const { | 380 const { |
| 365 return m_element->isInCrossOriginFrame() && m_element->isHTMLVideoElement() && | 381 return m_element->isInCrossOriginFrame() && m_element->isHTMLVideoElement() && |
| 366 m_source != AutoplaySource::NumberOfSources && | 382 !m_sources.empty() && |
| 367 !m_recordedCrossOriginAutoplayResults.count( | 383 !m_recordedCrossOriginAutoplayResults.count( |
| 368 CrossOriginAutoplayResult::UserPaused); | 384 CrossOriginAutoplayResult::UserPaused); |
| 369 } | 385 } |
| 370 | 386 |
| 371 DEFINE_TRACE(AutoplayUmaHelper) { | 387 DEFINE_TRACE(AutoplayUmaHelper) { |
| 372 EventListener::trace(visitor); | 388 EventListener::trace(visitor); |
| 373 ContextLifecycleObserver::trace(visitor); | 389 ContextLifecycleObserver::trace(visitor); |
| 374 visitor->trace(m_element); | 390 visitor->trace(m_element); |
| 375 visitor->trace(m_mutedVideoPlayMethodVisibilityObserver); | 391 visitor->trace(m_mutedVideoPlayMethodVisibilityObserver); |
| 376 visitor->trace(m_mutedVideoOffscreenDurationVisibilityObserver); | 392 visitor->trace(m_mutedVideoOffscreenDurationVisibilityObserver); |
| 377 } | 393 } |
| 378 | 394 |
| 379 } // namespace blink | 395 } // namespace blink |
| OLD | NEW |