Bug 1382574 - part1 : create new class AutoplayPolicy to handle autoplay logic. draft
authorAlastor Wu <alwu@mozilla.com>
Wed, 22 Nov 2017 00:33:16 +0800
changeset 701425 e6008ef41ec195a563ccaad4964b43a6a00405a4
parent 701250 72ee4800d4156931c89b58bd807af4a3083702bb
child 701426 9313505821b056bf7c1eb5dae758b3e4a2baf102
push id90150
push useralwu@mozilla.com
push dateTue, 21 Nov 2017 16:37:52 +0000
bugs1382574
milestone59.0a1
Bug 1382574 - part1 : create new class AutoplayPolicy to handle autoplay logic. AutoplayPolicy is used to manage autoplay logic for all kinds of media, including MediaElement, Web Audio and Web Speech. MozReview-Commit-ID: R1TxMkarIw
dom/html/HTMLMediaElement.cpp
dom/media/AutoplayPolicy.cpp
dom/media/AutoplayPolicy.h
dom/media/moz.build
modules/libpref/init/all.js
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -5,23 +5,25 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/HTMLMediaElementBinding.h"
 #include "mozilla/dom/HTMLSourceElement.h"
 #include "mozilla/dom/ElementInlines.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/ArrayUtils.h"
+#include "mozilla/NotNull.h"
 #include "mozilla/MathAlgorithms.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/dom/MediaEncryptedEvent.h"
 #include "mozilla/EMEUtils.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/Sprintf.h"
 
+#include "AutoplayPolicy.h"
 #include "base/basictypes.h"
 #include "nsIDOMHTMLMediaElement.h"
 #include "TimeRanges.h"
 #include "nsGenericHTMLElement.h"
 #include "nsAttrValueInlines.h"
 #include "nsDocShellLoadTypes.h"
 #include "nsPresContext.h"
 #include "nsIClassOfService.h"
@@ -7026,21 +7028,17 @@ HTMLMediaElement::UpdateAudioChannelPlay
   if (mAudioChannelWrapper) {
     mAudioChannelWrapper->UpdateAudioChannelPlayingState(aForcePlaying);
   }
 }
 
 bool
 HTMLMediaElement::IsAllowedToPlay()
 {
-  // Prevent media element from being auto-started by a script when
-  // media.autoplay.enabled=false
-  if (!mHasUserInteraction &&
-      !IsAutoplayEnabled() &&
-      !EventStateManager::IsHandlingUserInput()) {
+  if (!AutoplayPolicy::IsMediaElementAllowedToPlay(WrapNotNull(this))) {
 #if defined(MOZ_WIDGET_ANDROID)
     nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
                                          static_cast<nsIContent*>(this),
                                          NS_LITERAL_STRING("MozAutoplayMediaBlocked"),
                                          false,
                                          false);
 #endif
     return false;
new file mode 100644
--- /dev/null
+++ b/dom/media/AutoplayPolicy.cpp
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "AutoplayPolicy.h"
+
+#include "mozilla/EventStateManager.h"
+#include "mozilla/NotNull.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/dom/HTMLMediaElement.h"
+#include "nsIDocument.h"
+
+namespace mozilla {
+namespace dom {
+
+/* static */ bool
+AutoplayPolicy::IsDocumentAllowedToPlay(nsIDocument* aDoc)
+{
+  if (!Preferences::GetBool("media.autoplay.enabled.user-gestures-needed")) {
+    return true;
+  }
+
+  return aDoc ? aDoc->HasBeenUserActivated() : false;
+}
+
+/* static */ bool
+AutoplayPolicy::IsMediaElementAllowedToPlay(NotNull<HTMLMediaElement*> aElement)
+{
+  if (Preferences::GetBool("media.autoplay.enabled")) {
+    return true;
+  }
+
+  if (Preferences::GetBool("media.autoplay.enabled.user-gestures-needed")) {
+    return AutoplayPolicy::IsDocumentAllowedToPlay(aElement->OwnerDoc());
+  }
+
+  // TODO : this old way would be removed when user-gestures-needed becomes
+  // as a default option to block autoplay.
+  return EventStateManager::IsHandlingUserInput();
+}
+
+} // namespace dom
+} // namespace mozilla
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/media/AutoplayPolicy.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#if !defined(AutoplayPolicy_h_)
+#define AutoplayPolicy_h_
+
+#include "mozilla/NotNull.h"
+
+class nsIDocument;
+
+namespace mozilla {
+namespace dom {
+
+class HTMLMediaElement;
+
+/**
+ * AutoplayPolicy is used to manage autoplay logic for all kinds of media,
+ * including MediaElement, Web Audio and Web Speech.
+ *
+ * Autoplay could be disable by turn off the pref "media.autoplay.enabled".
+ * Once user disable autoplay, media could only be played if one of following
+ * conditions is true.
+ * 1) Owner document is activated by user gestures
+ *    We restrict user gestures to "mouse click", "keyboard press" and "touch".
+ * 2) TODO...
+ */
+class AutoplayPolicy
+{
+public:
+  static bool IsDocumentAllowedToPlay(nsIDocument* aDoc);
+  static bool IsMediaElementAllowedToPlay(NotNull<HTMLMediaElement*> aElement);
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
\ No newline at end of file
--- a/dom/media/moz.build
+++ b/dom/media/moz.build
@@ -93,16 +93,17 @@ EXPORTS += [
     'AudioChannelFormat.h',
     'AudioCompactor.h',
     'AudioConverter.h',
     'AudioMixer.h',
     'AudioPacketizer.h',
     'AudioSampleFormat.h',
     'AudioSegment.h',
     'AudioStream.h',
+    'AutoplayPolicy.h',
     'Benchmark.h',
     'BitReader.h',
     'BufferMediaResource.h',
     'BufferReader.h',
     'ByteWriter.h',
     'ChannelMediaDecoder.h',
     'CubebUtils.h',
     'DecoderTraits.h',
@@ -208,16 +209,17 @@ UNIFIED_SOURCES += [
     'AudioCompactor.cpp',
     'AudioConverter.cpp',
     'AudioDeviceInfo.cpp',
     'AudioSegment.cpp',
     'AudioStream.cpp',
     'AudioStreamTrack.cpp',
     'AudioTrack.cpp',
     'AudioTrackList.cpp',
+    'AutoplayPolicy.cpp',
     'BaseMediaResource.cpp',
     'Benchmark.cpp',
     'BitReader.cpp',
     'CanvasCaptureMediaStream.cpp',
     'ChannelMediaDecoder.cpp',
     'ChannelMediaResource.cpp',
     'CloneableWithRangeMediaResource.cpp',
     'DOMMediaStream.cpp',
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -607,16 +607,19 @@ pref("media.encoder.webm.enabled", true)
 pref("media.recorder.audio_node.enabled", false);
 
 // Whether MediaRecorder's video encoder should allow dropping frames in order
 // to keep up under load. Useful for tests but beware of memory consumption!
 pref("media.recorder.video.frame_drops", true);
 
 // Whether to autostart a media element with an |autoplay| attribute
 pref("media.autoplay.enabled", true);
+// If "media.autoplay.enabled" is off, and this pref is on, then autoplay could
+// be executed after website has been activated by specific user gestures.
+pref("media.autoplay.enabled.user-gestures-needed", false);
 
 // The default number of decoded video frames that are enqueued in
 // MediaDecoderReader's mVideoQueue.
 pref("media.video-queue.default-size", 10);
 
 // The maximum number of queued frames to send to the compositor.
 // By default, send all of them.
 pref("media.video-queue.send-to-compositor-size", 9999);