Bug 805333, Patch 5 - mozAudioChannel for MediaElement - IPC. r=cjones a=blocking-basecamp
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 05 Dec 2012 19:01:58 -0800
changeset 120650 74987fe38fd23359ceb2953eee65930f02119c1a
parent 120649 137d80a07e64b82e2fbc95c9a0a7cc8690376bf4
child 120651 3c81e1c0d252325d6060d2252725ead8a2c6e705
push idunknown
push userunknown
push dateunknown
reviewerscjones, blocking-basecamp
bugs805333
milestone20.0a1
Bug 805333, Patch 5 - mozAudioChannel for MediaElement - IPC. r=cjones a=blocking-basecamp
dom/audiochannel/AudioChannelCommon.h
dom/audiochannel/AudioChannelService.cpp
dom/audiochannel/AudioChannelService.h
dom/audiochannel/AudioChannelServiceChild.cpp
dom/audiochannel/AudioChannelServiceChild.h
dom/audiochannel/Makefile.in
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/TabMessageUtils.h
--- a/dom/audiochannel/AudioChannelCommon.h
+++ b/dom/audiochannel/AudioChannelCommon.h
@@ -13,16 +13,17 @@ namespace dom {
 // The audio channel. Read the nsIHTMLMediaElement.idl for a description
 // about this attribute.
 enum AudioChannelType {
   AUDIO_CHANNEL_NORMAL = 0,
   AUDIO_CHANNEL_CONTENT,
   AUDIO_CHANNEL_NOTIFICATION,
   AUDIO_CHANNEL_ALARM,
   AUDIO_CHANNEL_TELEPHONY,
-  AUDIO_CHANNEL_PUBLICNOTIFICATION
+  AUDIO_CHANNEL_PUBLICNOTIFICATION,
+  AUDIO_CHANNEL_LAST
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
 
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=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 "AudioChannelService.h"
+#include "AudioChannelServiceChild.h"
 
 #include "base/basictypes.h"
 
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/Util.h"
 
@@ -25,32 +26,40 @@ using namespace mozilla::dom;
 StaticRefPtr<AudioChannelService> gAudioChannelService;
 
 // static
 AudioChannelService*
 AudioChannelService::GetAudioChannelService()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return AudioChannelServiceChild::GetAudioChannelService();
+  }
+
   // If we already exist, exit early
   if (gAudioChannelService) {
     return gAudioChannelService;
   }
 
   // Create new instance, register, return
   nsRefPtr<AudioChannelService> service = new AudioChannelService();
   NS_ENSURE_TRUE(service, nullptr);
 
   gAudioChannelService = service;
   return gAudioChannelService;
 }
 
 void
 AudioChannelService::Shutdown()
 {
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return AudioChannelServiceChild::Shutdown();
+  }
+
   if (gAudioChannelService) {
     delete gAudioChannelService;
     gAudioChannelService = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS0(AudioChannelService)
 
@@ -74,35 +83,46 @@ AudioChannelService::~AudioChannelServic
   delete [] mChannelCounters;
 }
 
 void
 AudioChannelService::RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
                                           AudioChannelType aType)
 {
   mMediaElements.Put(aMediaElement, aType);
+  RegisterType(aType);
+}
+
+void
+AudioChannelService::RegisterType(AudioChannelType aType)
+{
   mChannelCounters[aType]++;
 
   // In order to avoid race conditions, it's safer to notify any existing
   // media element any time a new one is registered.
   Notify();
 }
 
 void
 AudioChannelService::UnregisterMediaElement(nsHTMLMediaElement* aMediaElement)
 {
   AudioChannelType type;
   if (!mMediaElements.Get(aMediaElement, &type)) {
     return;
   }
 
   mMediaElements.Remove(aMediaElement);
+  UnregisterType(type);
+}
 
-  mChannelCounters[type]--;
-  MOZ_ASSERT(mChannelCounters[type] >= 0);
+void
+AudioChannelService::UnregisterType(AudioChannelType aType)
+{
+  mChannelCounters[aType]--;
+  MOZ_ASSERT(mChannelCounters[aType] >= 0);
 
   // In order to avoid race conditions, it's safer to notify any existing
   // media element any time a new one is registered.
   Notify();
 }
 
 bool
 AudioChannelService::GetMuted(AudioChannelType aType, bool aElementHidden)
@@ -188,16 +208,23 @@ NotifyEnumerator(nsHTMLMediaElement* aEl
 
 void
 AudioChannelService::Notify()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Notify any media element for the main process.
   mMediaElements.EnumerateRead(NotifyEnumerator, nullptr);
+
+  // Notify for the child processes.
+  nsTArray<ContentParent*> children;
+  ContentParent::GetAll(children);
+  for (uint32_t i = 0; i < children.Length(); i++) {
+    unused << children[i]->SendAudioChannelNotify();
+  }
 }
 
 bool
 AudioChannelService::ChannelsActiveWithHigherPriorityThan(AudioChannelType aType)
 {
   for (int i = AUDIO_CHANNEL_PUBLICNOTIFICATION;
        i != AUDIO_CHANNEL_CONTENT; --i) {
     if (i == aType) {
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -32,43 +32,52 @@ public:
    * Shutdown the singleton.
    */
   static void Shutdown();
 
   /**
    * Any MediaElement that starts playing should register itself to
    * this service, sharing the AudioChannelType.
    */
-  void RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
-                            AudioChannelType aType);
+  virtual void RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                    AudioChannelType aType);
 
   /**
    * Any MediaElement that stops playing should unregister itself to
    * this service.
    */
-  void UnregisterMediaElement(nsHTMLMediaElement* aMediaElement);
+  virtual void UnregisterMediaElement(nsHTMLMediaElement* aMediaElement);
 
   /**
    * Return true if this type should be muted.
    */
   virtual bool GetMuted(AudioChannelType aType, bool aElementHidden);
 
+protected:
   void Notify();
 
-protected:
+  /* Register/Unregister IPC types: */
+  void RegisterType(AudioChannelType aType);
+  void UnregisterType(AudioChannelType aType);
+
   AudioChannelService();
   virtual ~AudioChannelService();
 
   bool ChannelsActiveWithHigherPriorityThan(AudioChannelType aType);
 
   const char* ChannelName(AudioChannelType aType);
 
   nsDataHashtable< nsPtrHashKey<nsHTMLMediaElement>, AudioChannelType > mMediaElements;
 
   int32_t* mChannelCounters;
 
   AudioChannelType mCurrentHigherChannel;
+
+  // This is needed for IPC comunication between
+  // AudioChannelServiceChild and this class.
+  friend class ContentParent;
+  friend class ContentChild;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -0,0 +1,103 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "AudioChannelServiceChild.h"
+
+#include "base/basictypes.h"
+
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+
+#include "mozilla/dom/ContentChild.h"
+
+#include "base/basictypes.h"
+
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+StaticRefPtr<AudioChannelServiceChild> gAudioChannelServiceChild;
+
+// static
+AudioChannelService*
+AudioChannelServiceChild::GetAudioChannelService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we already exist, exit early
+  if (gAudioChannelServiceChild) {
+    return gAudioChannelServiceChild;
+  }
+
+  // Create new instance, register, return
+  nsRefPtr<AudioChannelServiceChild> service = new AudioChannelServiceChild();
+  NS_ENSURE_TRUE(service, nullptr);
+
+  gAudioChannelServiceChild = service;
+  return gAudioChannelServiceChild;
+}
+
+void
+AudioChannelServiceChild::Shutdown()
+{
+  if (gAudioChannelServiceChild) {
+    delete gAudioChannelServiceChild;
+    gAudioChannelServiceChild = nullptr;
+  }
+}
+
+AudioChannelServiceChild::AudioChannelServiceChild()
+{
+}
+
+AudioChannelServiceChild::~AudioChannelServiceChild()
+{
+}
+
+bool
+AudioChannelServiceChild::GetMuted(AudioChannelType aType, bool aMozHidden)
+{
+  ContentChild *cc = ContentChild::GetSingleton();
+  bool muted = false;
+
+  if (cc) {
+    cc->SendAudioChannelGetMuted(aType, aMozHidden, &muted);
+  }
+
+  return muted;
+}
+
+void
+AudioChannelServiceChild::RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                               AudioChannelType aType)
+{
+  AudioChannelService::RegisterMediaElement(aMediaElement, aType);
+
+  ContentChild *cc = ContentChild::GetSingleton();
+  if (cc) {
+    cc->SendAudioChannelRegisterType(aType);
+  }
+}
+
+void
+AudioChannelServiceChild::UnregisterMediaElement(nsHTMLMediaElement* aMediaElement)
+{
+  AudioChannelType type;
+  if (!mMediaElements.Get(aMediaElement, &type)) {
+    return;
+  }
+
+  AudioChannelService::UnregisterMediaElement(aMediaElement);
+
+  ContentChild *cc = ContentChild::GetSingleton();
+  if (cc) {
+    cc->SendAudioChannelUnregisterType(type);
+  }
+}
+
new file mode 100644
--- /dev/null
+++ b/dom/audiochannel/AudioChannelServiceChild.h
@@ -0,0 +1,51 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 mozilla_dom_audiochannelservicechild_h__
+#define mozilla_dom_audiochannelservicechild_h__
+
+#include "nsAutoPtr.h"
+#include "nsISupports.h"
+
+#include "AudioChannelService.h"
+#include "AudioChannelCommon.h"
+#include "nsHTMLMediaElement.h"
+
+namespace mozilla {
+namespace dom {
+
+class AudioChannelServiceChild : public AudioChannelService
+{
+public:
+
+  /**
+   * Returns the AudioChannelServce singleton. Only to be called from main thread.
+   * @return NS_OK on proper assignment, NS_ERROR_FAILURE otherwise.
+   */
+  static AudioChannelService*
+  GetAudioChannelService();
+
+  static void Shutdown();
+
+  virtual void RegisterMediaElement(nsHTMLMediaElement* aMediaElement,
+                                    AudioChannelType aType);
+  virtual void UnregisterMediaElement(nsHTMLMediaElement* aMediaElement);
+
+  /**
+   * Return true if this type + this mozHidden should be muted.
+   */
+  virtual bool GetMuted(AudioChannelType aType, bool aMozHidden);
+
+protected:
+  AudioChannelServiceChild();
+  virtual ~AudioChannelServiceChild();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
+
--- a/dom/audiochannel/Makefile.in
+++ b/dom/audiochannel/Makefile.in
@@ -27,18 +27,20 @@ FORCE_STATIC_LIB = 1
 EXPORT_LIBRARY = 1
 FAIL_ON_WARNINGS := 1
 
 EXPORTS_NAMESPACES = \
   mozilla/dom \
   $(NULL)
 
 EXPORTS = AudioChannelService.h \
+          AudioChannelServiceChild.h \
           AudioChannelCommon.h
 
 CPPSRCS += \
   AudioChannelService.cpp \
+  AudioChannelServiceChild.cpp \
   $(NULL)
 
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -93,16 +93,17 @@
 #include "nsIRemoteBlob.h"
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
 #include "URIUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsIPrincipal.h"
 #include "nsDeviceStorage.h"
+#include "AudioChannelService.h"
 
 using namespace base;
 using namespace mozilla::docshell;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::devicestorage;
 using namespace mozilla::dom::sms;
 using namespace mozilla::dom::indexedDB;
 using namespace mozilla::hal_sandbox;
@@ -427,16 +428,27 @@ ContentChild::RecvPMemoryReportRequestCo
       r->CollectReports(cb, wrappedReports);
     }
 
     child->Send__delete__(child, reports);
     return true;
 }
 
 bool
+ContentChild::RecvAudioChannelNotify()
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->Notify();
+    }
+    return true;
+}
+
+bool
 ContentChild::DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor)
 {
     delete actor;
     return true;
 }
 
 bool
 ContentChild::RecvDumpMemoryReportsToFile(const nsString& aIdentifier,
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -107,16 +107,19 @@ public:
 
     virtual bool
     DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor);
 
     virtual bool
     RecvPMemoryReportRequestConstructor(PMemoryReportRequestChild* child);
 
     virtual bool
+    RecvAudioChannelNotify();
+
+    virtual bool
     RecvDumpMemoryReportsToFile(const nsString& aIdentifier,
                                 const bool& aMinimizeMemoryUsage,
                                 const bool& aDumpChildProcesses);
     virtual bool
     RecvDumpGCAndCCLogsToFile(const nsString& aIdentifier,
                               const bool& aDumpChildProcesses);
 
     virtual PTestShellChild* AllocPTestShell();
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -11,16 +11,17 @@
 #if defined(ANDROID) || defined(LINUX)
 # include <sys/time.h>
 # include <sys/resource.h>
 #endif
 
 #include "chrome/common/process_watcher.h"
 
 #include "AppProcessPermissions.h"
+#include "AudioChannelService.h"
 #include "CrashReporterParent.h"
 #include "IHistory.h"
 #include "IDBFactory.h"
 #include "IndexedDBParent.h"
 #include "IndexedDatabaseManager.h"
 #include "mozIApplication.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/ExternalHelperAppParent.h"
@@ -1006,16 +1007,52 @@ ContentParent::RecvFirstIdle()
     // When the ContentChild goes idle, it sends us a FirstIdle message
     // which we use as a good time to prelaunch another process. If we
     // prelaunch any sooner than this, then we'll be competing with the
     // child process and slowing it down.
     ScheduleDelayedPreallocateAppProcess();
     return true;
 }
 
+bool
+ContentParent::RecvAudioChannelGetMuted(const AudioChannelType& aType,
+                                        const bool& aMozHidden,
+                                        bool* aValue)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    *aValue = false;
+    if (service) {
+        *aValue = service->GetMuted(aType, aMozHidden);
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvAudioChannelRegisterType(const AudioChannelType& aType)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->RegisterType(aType);
+    }
+    return true;
+}
+
+bool
+ContentParent::RecvAudioChannelUnregisterType(const AudioChannelType& aType)
+{
+    nsRefPtr<AudioChannelService> service =
+        AudioChannelService::GetAudioChannelService();
+    if (service) {
+        service->UnregisterType(aType);
+    }
+    return true;
+}
+
 NS_IMPL_THREADSAFE_ISUPPORTS3(ContentParent,
                               nsIObserver,
                               nsIThreadObserver,
                               nsIDOMGeoPositionCallback)
 
 NS_IMETHODIMP
 ContentParent::Observe(nsISupports* aSubject,
                        const char* aTopic,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -256,29 +256,29 @@ private:
     virtual bool RecvStartVisitedQuery(const URIParams& uri);
 
     virtual bool RecvVisitURI(const URIParams& uri,
                               const OptionalURIParams& referrer,
                               const uint32_t& flags);
 
     virtual bool RecvSetURITitle(const URIParams& uri,
                                  const nsString& title);
-    
+
     virtual bool RecvShowFilePicker(const int16_t& mode,
                                     const int16_t& selectedType,
                                     const bool& addToRecentDocs,
                                     const nsString& title,
                                     const nsString& defaultFile,
                                     const nsString& defaultExtension,
                                     const InfallibleTArray<nsString>& filters,
                                     const InfallibleTArray<nsString>& filterNames,
                                     InfallibleTArray<nsString>* files,
                                     int16_t* retValue,
                                     nsresult* result);
- 
+
     virtual bool RecvShowAlertNotification(const nsString& aImageUrl, const nsString& aTitle,
                                            const nsString& aText, const bool& aTextClickable,
                                            const nsString& aCookie, const nsString& aName);
 
     virtual bool RecvLoadURIExternal(const URIParams& uri);
 
     virtual bool RecvSyncMessage(const nsString& aMsg,
                                  const ClonedMessageData& aData,
@@ -297,16 +297,23 @@ private:
                                  const uint32_t& aColNumber,
                                  const uint32_t& aFlags,
                                  const nsCString& aCategory);
 
     virtual bool RecvPrivateDocShellsExist(const bool& aExist);
 
     virtual bool RecvFirstIdle();
 
+    virtual bool RecvAudioChannelGetMuted(const AudioChannelType& aType,
+                                          const bool& aMozHidden,
+                                          bool* aValue);
+
+    virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType);
+    virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType);
+
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     GeckoChildProcessHost* mSubprocess;
     ChildOSPrivileges mOSPrivileges;
 
     uint64_t mChildID;
     int32_t mGeolocationWatchID;
     int mRunToCompletionDepth;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -33,16 +33,17 @@ using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
 using IPC::Permission;
 using mozilla::null_t;
 using mozilla::void_t;
+using mozilla::dom::AudioChannelType;
 using mozilla::dom::NativeThreadId;
 using mozilla::layout::ScrollingBehavior;
 using gfxIntSize;
 
 namespace mozilla {
 namespace dom {
 
 // Data required to clone an existing DOMStorageImpl in the parent
@@ -260,16 +261,21 @@ both:
     async PBrowser(IPCTabContext context, uint32_t chromeFlags);
 
     async PBlob(BlobConstructorParams params);
 
 child:
     PMemoryReportRequest();
 
     /**
+     * Notify the AudioChannelService in the child processes.
+     */
+    async AudioChannelNotify();
+
+    /**
      * Dump the contents of about:memory to a file in our temp directory.
      *
      * For documentation on the args, see
      * MemoryInfoDumper::dumpMemoryReportsToFile.
      */
     async DumpMemoryReportsToFile(nsString identifier,
                                   bool minimizeMemoryUsage,
                                   bool dumpChildProcesses);
@@ -419,14 +425,21 @@ parent:
         returns (bool showPassword);
 
     // Notify the parent of the presence or absence of private docshells
     PrivateDocShellsExist(bool aExist);
 
     // Tell the parent that the child has gone idle for the first time
     async FirstIdle();
 
+    // Get Muted from the main AudioChannelService.
+    sync AudioChannelGetMuted(AudioChannelType aType, bool aMozHidden)
+        returns (bool value);
+
+    async AudioChannelRegisterType(AudioChannelType aType);
+    async AudioChannelUnregisterType(AudioChannelType aType);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData);
 };
 
 }
 }
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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 TABMESSAGE_UTILS_H
 #define TABMESSAGE_UTILS_H
 
+#include "AudioChannelCommon.h"
 #include "ipc/IPCMessageUtils.h"
 #include "nsIDOMEvent.h"
 #include "nsCOMPtr.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsExceptionHandler.h"
 #endif
 
@@ -51,12 +52,19 @@ struct ParamTraits<mozilla::dom::RemoteD
     return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
   }
 };
 
+template <>
+struct ParamTraits<mozilla::dom::AudioChannelType>
+  : public EnumSerializer<mozilla::dom::AudioChannelType,
+                          mozilla::dom::AUDIO_CHANNEL_NORMAL,
+                          mozilla::dom::AUDIO_CHANNEL_LAST>
+{ };
+
 }
 
 
 #endif