Bug 1565689 - part5 : control media from chrome process. r=farre,baku
authoralwu <alwu@mozilla.com>
Wed, 07 Aug 2019 01:46:03 +0000
changeset 547606 d138720d49a9ca30198d6afcb36eac2f83019623
parent 547605 5790ef015c5bb5ef6a2fb15cfb3ea38d8bc04dfd
child 547607 bd22cb43dc5966bdd1d4156ede3e073d4d761b6e
push id11848
push userffxbld-merge
push dateMon, 26 Aug 2019 19:26:25 +0000
treeherdermozilla-beta@9b31bfdfac10 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfarre, baku
bugs1565689
milestone70.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1565689 - part5 : control media from chrome process. r=farre,baku This patch implements how to use MediaController to control corresponding media in content processes. Differential Revision: https://phabricator.services.mozilla.com/D38145
docshell/base/CanonicalBrowsingContext.cpp
docshell/base/CanonicalBrowsingContext.h
dom/base/nsGlobalWindowOuter.cpp
dom/base/nsPIDOMWindow.h
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
dom/media/mediacontrol/MediaControlIPC.h
dom/media/mediacontrol/MediaController.cpp
dom/media/mediacontrol/MediaController.h
dom/media/mediacontrol/moz.build
--- a/docshell/base/CanonicalBrowsingContext.cpp
+++ b/docshell/base/CanonicalBrowsingContext.cpp
@@ -204,16 +204,26 @@ void CanonicalBrowsingContext::NotifyMed
   if (window) {
     window->SetAudioMuted(aMuted);
   }
   Group()->EachParent([&](ContentParent* aParent) {
     Unused << aParent->SendSetMediaMuted(this, aMuted);
   });
 }
 
+void CanonicalBrowsingContext::UpdateMediaAction(MediaControlActions aAction) {
+  nsPIDOMWindowOuter* window = GetDOMWindow();
+  if (window) {
+    window->UpdateMediaAction(aAction);
+  }
+  Group()->EachParent([&](ContentParent* aParent) {
+    Unused << aParent->SendUpdateMediaAction(this, aAction);
+  });
+}
+
 void CanonicalBrowsingContext::SetFieldEpochsForChild(
     ContentParent* aChild, const BrowsingContext::FieldEpochs& aEpochs) {
   mChildFieldEpochs.Put(aChild->ChildID(), aEpochs);
 }
 
 const BrowsingContext::FieldEpochs&
 CanonicalBrowsingContext::GetFieldEpochsForChild(ContentParent* aChild) {
   static const BrowsingContext::FieldEpochs sDefaultFieldEpochs;
--- a/docshell/base/CanonicalBrowsingContext.h
+++ b/docshell/base/CanonicalBrowsingContext.h
@@ -3,16 +3,17 @@
 /* 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/. */
 
 #ifndef mozilla_dom_CanonicalBrowsingContext_h
 #define mozilla_dom_CanonicalBrowsingContext_h
 
 #include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/MediaController.h"
 #include "mozilla/RefPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsWrapperCache.h"
 #include "nsTHashtable.h"
 #include "nsHashKeys.h"
 
 class nsIDocShell;
 
@@ -73,16 +74,20 @@ class CanonicalBrowsingContext final : p
   // autoplay media.
   void NotifyStartDelayedAutoplayMedia();
 
   // This function is used to mute or unmute all media within a tab. It would
   // set the media mute property for the top level window and propagate it to
   // other top level windows in other processes.
   void NotifyMediaMutedChanged(bool aMuted);
 
+  // This function would update the media action for the current outer window
+  // and propogate the action to other browsing contexts in content processes.
+  void UpdateMediaAction(MediaControlActions aAction);
+
   // Validate that the given process is allowed to perform the given
   // transaction. aSource is |nullptr| if set in the parent process.
   bool ValidateTransaction(const Transaction& aTransaction,
                            ContentParent* aSource);
 
   void SetFieldEpochsForChild(ContentParent* aChild,
                               const FieldEpochs& aEpochs);
   const FieldEpochs& GetFieldEpochsForChild(ContentParent* aChild);
--- a/dom/base/nsGlobalWindowOuter.cpp
+++ b/dom/base/nsGlobalWindowOuter.cpp
@@ -25,16 +25,18 @@
 #include "nsIWebProgressListener.h"
 #include "mozilla/AntiTrackingCommon.h"
 #include "mozilla/dom/ContentFrameMessageManager.h"
 #include "mozilla/dom/EventTarget.h"
 #include "mozilla/dom/LocalStorage.h"
 #include "mozilla/dom/LSObject.h"
 #include "mozilla/dom/Storage.h"
 #include "mozilla/dom/MaybeCrossOriginObject.h"
+#include "mozilla/dom/MediaController.h"
+#include "mozilla/dom/MediaControlUtils.h"
 #include "mozilla/dom/Performance.h"
 #include "mozilla/dom/StorageEvent.h"
 #include "mozilla/dom/StorageEventBinding.h"
 #include "mozilla/dom/StorageNotifierService.h"
 #include "mozilla/dom/StorageUtils.h"
 #include "mozilla/dom/Timeout.h"
 #include "mozilla/dom/TimeoutHandler.h"
 #include "mozilla/dom/TimeoutManager.h"
@@ -265,16 +267,22 @@ class nsIScriptTimeoutHandler;
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using mozilla::BasePrincipal;
 using mozilla::OriginAttributes;
 using mozilla::TimeStamp;
 
+extern mozilla::LazyLogModule gMediaControlLog;
+
+#define MC_LOG(msg, ...)                     \
+  MOZ_LOG(gMediaControlLog, LogLevel::Debug, \
+          ("WindowOuter=%p, " msg, this, ##__VA_ARGS__))
+
 #define FORWARD_TO_INNER(method, args, err_rval)       \
   PR_BEGIN_MACRO                                       \
   if (!mInnerWindow) {                                 \
     NS_WARNING("No inner window available!");          \
     return err_rval;                                   \
   }                                                    \
   return GetCurrentInnerWindowInternal()->method args; \
   PR_END_MACRO
@@ -2872,16 +2880,36 @@ void nsPIDOMWindowOuter::MaybeActiveMedi
 
   SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
 }
 
 SuspendTypes nsPIDOMWindowOuter::GetMediaSuspend() const {
   return mMediaSuspend;
 }
 
+void nsPIDOMWindowOuter::UpdateMediaAction(const MediaControlActions aAction) {
+  // TODO : we now temporarily map MediaControlActions to nsISuspendedTypes in
+  // order to control media, but for long term goal in which we should not rely
+  // on nsISuspendedTypes and completely decouple them. See bug1571493.
+  MC_LOG("UpdateMediaAction %s", ToMediaControlActionsStr(aAction));
+  switch (aAction) {
+    case MediaControlActions::ePlay:
+      SetMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED);
+      break;
+    case MediaControlActions::ePause:
+      SetMediaSuspend(nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE);
+      break;
+    case MediaControlActions::eStop:
+      SetMediaSuspend(nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE);
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Invalid action.");
+  };
+}
+
 void nsPIDOMWindowOuter::SetMediaSuspend(SuspendTypes aSuspend) {
   if (!IsDisposableSuspend(aSuspend)) {
     MaybeNotifyMediaResumedFromBlock(aSuspend);
     mMediaSuspend = aSuspend;
   }
 
   RefreshMediaElementsSuspend(aSuspend);
 }
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -65,16 +65,17 @@ class ReportingObserver;
 class Selection;
 class ServiceWorker;
 class ServiceWorkerDescriptor;
 class Timeout;
 class TimeoutManager;
 class WindowGlobalChild;
 class CustomElementRegistry;
 enum class CallerType : uint32_t;
+enum class MediaControlActions : uint32_t;
 }  // namespace dom
 }  // namespace mozilla
 
 enum UIStateChangeType {
   UIStateChangeType_NoChange,
   UIStateChangeType_Set,
   UIStateChangeType_Clear,
   UIStateChangeType_Invalid  // used for serialization only
@@ -752,16 +753,18 @@ class nsPIDOMWindowOuter : public mozIDO
   bool GetAudioMuted() const;
   void SetAudioMuted(bool aMuted);
 
   float GetAudioVolume() const;
   nsresult SetAudioVolume(float aVolume);
 
   void MaybeActiveMediaComponents();
 
+  void UpdateMediaAction(const mozilla::dom::MediaControlActions aAction);
+
   void SetServiceWorkersTestingEnabled(bool aEnabled);
   bool GetServiceWorkersTestingEnabled();
 
   float GetDevicePixelRatio(mozilla::dom::CallerType aCallerType);
 
   void SetLargeAllocStatus(mozilla::dom::LargeAllocStatus aStatus);
 
   bool IsTopLevelWindow();
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -224,16 +224,17 @@
 #    include "mozilla/a11y/AccessibleWrap.h"
 #  endif
 #  include "mozilla/a11y/DocAccessible.h"
 #  include "mozilla/a11y/DocManager.h"
 #  include "mozilla/a11y/OuterDocAccessible.h"
 #endif
 
 #include "mozilla/dom/File.h"
+#include "mozilla/dom/MediaController.h"
 #include "mozilla/dom/PPresentationChild.h"
 #include "mozilla/dom/PresentationIPCService.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 #include "mozilla/ipc/IPCStreamAlloc.h"
 #include "mozilla/ipc/IPCStreamDestination.h"
 #include "mozilla/ipc/IPCStreamSource.h"
 
 #ifdef MOZ_WEBSPEECH
@@ -3743,16 +3744,26 @@ mozilla::ipc::IPCResult ContentChild::Re
   MOZ_ASSERT(aContext);
   nsCOMPtr<nsPIDOMWindowOuter> window = aContext->GetDOMWindow();
   if (window) {
     window->SetAudioMuted(aMuted);
   }
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult ContentChild::RecvUpdateMediaAction(
+    BrowsingContext* aContext, MediaControlActions aAction) {
+  MOZ_ASSERT(aContext);
+  nsCOMPtr<nsPIDOMWindowOuter> window = aContext->GetDOMWindow();
+  if (window) {
+    window->UpdateMediaAction(aAction);
+  }
+  return IPC_OK();
+}
+
 already_AddRefed<nsIEventTarget> ContentChild::GetSpecificMessageEventTarget(
     const Message& aMsg) {
   switch (aMsg.type()) {
     // Javascript
     case PJavaScript::Msg_DropTemporaryStrongReferences__ID:
     case PJavaScript::Msg_DropObject__ID:
 
     // Navigation
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -69,16 +69,17 @@ class SharedMap;
 }
 
 class AlertObserver;
 class ConsoleListener;
 class ClonedMessageData;
 class BrowserChild;
 class GetFilesHelperChild;
 class TabContext;
+enum class MediaControlActions : uint32_t;
 
 class ContentChild final : public PContentChild,
                            public nsIWindowProvider,
                            public CPOWManagerGetter,
                            public mozilla::ipc::IShmemAllocator {
   typedef mozilla::dom::ClonedMessageData ClonedMessageData;
   typedef mozilla::ipc::FileDescriptor FileDescriptor;
   typedef mozilla::ipc::PFileDescriptorSetChild PFileDescriptorSetChild;
@@ -689,16 +690,19 @@ class ContentChild final : public PConte
       const uint32_t& aRedirectMode);
 
   mozilla::ipc::IPCResult RecvStartDelayedAutoplayMediaComponents(
       BrowsingContext* aContext);
 
   mozilla::ipc::IPCResult RecvSetMediaMuted(BrowsingContext* aContext,
                                             bool aMuted);
 
+  mozilla::ipc::IPCResult RecvUpdateMediaAction(BrowsingContext* aContext,
+                                                MediaControlActions aAction);
+
   void HoldBrowsingContextGroup(BrowsingContextGroup* aBCG);
   void ReleaseBrowsingContextGroup(BrowsingContextGroup* aBCG);
 
 #ifdef NIGHTLY_BUILD
   // Fetch the current number of pending input events.
   //
   // NOTE: This method performs an atomic read, and is safe to call from all
   // threads.
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -101,16 +101,17 @@ using refcounted class nsIInputStream fr
 using refcounted class mozilla::dom::BrowsingContext from "mozilla/dom/BrowsingContext.h";
 using mozilla::dom::BrowsingContextTransaction from "mozilla/dom/BrowsingContext.h";
 using mozilla::dom::BrowsingContextFieldEpochs from "mozilla/dom/BrowsingContext.h";
 using mozilla::dom::BrowsingContextInitializer from "mozilla/dom/BrowsingContext.h";
 using base::SharedMemoryHandle from "base/shared_memory.h";
 using mozilla::ipc::SharedMemoryBasic::Handle from "mozilla/ipc/SharedMemoryBasic.h";
 using mozilla::fontlist::Pointer from "SharedFontList.h";
 using gfxSparseBitSet from "gfxFontUtils.h";
+using mozilla::dom::MediaControlActions from "ipc/MediaControlIPC.h";
 
 union ChromeRegistryItem
 {
     ChromePackage;
     OverrideMapping;
     SubstitutionMapping;
 };
 
@@ -807,16 +808,22 @@ child:
     */
     async StartDelayedAutoplayMediaComponents(BrowsingContext aContext);
 
     /**
     * This method is used to notifty content process to mute or unmute media.
     */
     async SetMediaMuted(BrowsingContext aContext, bool aMuted);
 
+    /**
+     * This method is used to apply the media action to outer window in the
+     * content process, such as play, pause, stop ..e.t.c.
+     */
+    async UpdateMediaAction(BrowsingContext aContext, MediaControlActions aAction);
+
     // Begin subscribing to a new BrowsingContextGroup, sending down the current
     // value for every individual BrowsingContext.
     async RegisterBrowsingContextGroup(BrowsingContextInitializer[] aInits);
 
 parent:
     async InitBackground(Endpoint<PBackgroundParent> aEndpoint);
 
     sync OpenRecordReplayChannel(uint32_t channelId)
new file mode 100644
--- /dev/null
+++ b/dom/media/mediacontrol/MediaControlIPC.h
@@ -0,0 +1,24 @@
+/* -*- 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/. */
+
+#ifndef ipc_MediaControlIPC_h
+#define ipc_MediaControlIPC_h
+
+#include "ipc/IPCMessageUtils.h"
+
+#include "mozilla/dom/MediaController.h"
+
+namespace IPC {
+template <>
+struct ParamTraits<mozilla::dom::MediaControlActions>
+    : public ContiguousEnumSerializer<
+          mozilla::dom::MediaControlActions,
+          mozilla::dom::MediaControlActions::ePlay,
+          mozilla::dom::MediaControlActions(
+              mozilla::dom::MediaControlActions::eActionsNum)> {};
+}  // namespace IPC
+
+#endif  // mozilla_MediaControlIPC_hh
\ No newline at end of file
--- a/dom/media/mediacontrol/MediaController.cpp
+++ b/dom/media/mediacontrol/MediaController.cpp
@@ -3,16 +3,17 @@
 /* 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 "MediaController.h"
 
 #include "MediaControlService.h"
 #include "mozilla/dom/BrowsingContext.h"
+#include "mozilla/dom/CanonicalBrowsingContext.h"
 
 extern mozilla::LazyLogModule gMediaControlLog;
 
 // avoid redefined macro in unified build
 #undef LOG
 #define LOG(msg, ...)                                                       \
   MOZ_LOG(gMediaControlLog, LogLevel::Debug,                                \
           ("TabMediaController=%p, Id=%" PRId64 ", " msg, this, this->Id(), \
@@ -35,26 +36,38 @@ TabMediaController::TabMediaController(u
 TabMediaController::~TabMediaController() {
   LOG("Destroy controller %" PRId64, Id());
   MOZ_DIAGNOSTIC_ASSERT(!mControlledMediaNum);
 };
 
 void TabMediaController::Play() {
   LOG("Play");
   mIsPlaying = true;
+  RefPtr<BrowsingContext> context = GetContext();
+  if (context) {
+    context->Canonical()->UpdateMediaAction(MediaControlActions::ePlay);
+  }
 }
 
 void TabMediaController::Pause() {
   LOG("Pause");
   mIsPlaying = false;
+  RefPtr<BrowsingContext> context = GetContext();
+  if (context) {
+    context->Canonical()->UpdateMediaAction(MediaControlActions::ePause);
+  }
 }
 
 void TabMediaController::Stop() {
   LOG("Stop");
   mIsPlaying = false;
+  RefPtr<BrowsingContext> context = GetContext();
+  if (context) {
+    context->Canonical()->UpdateMediaAction(MediaControlActions::eStop);
+  }
 }
 
 void TabMediaController::Shutdown() {
   mIsPlaying = false;
   mControlledMediaNum = 0;
   RefPtr<MediaControlService> service = MediaControlService::GetService();
   MOZ_ASSERT(service);
   service->GetAudioFocusManager().RevokeAudioFocus(Id());
--- a/dom/media/mediacontrol/MediaController.h
+++ b/dom/media/mediacontrol/MediaController.h
@@ -10,16 +10,24 @@
 #include "nsDataHashtable.h"
 #include "nsISupportsImpl.h"
 
 namespace mozilla {
 namespace dom {
 
 class BrowsingContext;
 
+enum class MediaControlActions : uint32_t {
+  ePlay,
+  ePause,
+  eStop,
+  /* do not use this, it's used to indicate the last value of enum */
+  eActionsNum,
+};
+
 /**
  * MediaController is a class which is used to control media in the content
  * process. It's a basic interface class and you should implement you own class
  * to inherit this class. Every controller would correspond to a browsing
  * context. For example, TabMediaController corresponds to the top level
  * browsing context. In the future, we might implement MediaSessionController
  * which could correspond to any browsing context, depending on which browsing
  * context has active media session.
--- a/dom/media/mediacontrol/moz.build
+++ b/dom/media/mediacontrol/moz.build
@@ -5,16 +5,20 @@
 
 EXPORTS.mozilla.dom += [
     'AudioFocusManager.h',
     'MediaController.h',
     'MediaControlService.h',
     'MediaControlUtils.h',
 ]
 
+EXPORTS.ipc += [
+    'MediaControlIPC.h',
+]
+
 UNIFIED_SOURCES += [
     'AudioFocusManager.cpp',
     'MediaController.cpp',
     'MediaControlService.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')