Bug 1315850 - Implement ChromiumCDMProxy initialization. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Thu, 09 Mar 2017 11:29:45 +1300
changeset 349429 63434c1f9900c9e6755b79df185da4a889bb3cda
parent 349428 ab102cdd2848a7c0069bd0981eb33c9d302d8b41
child 349430 b1281784ba5b9c90eacfde69fea2be5fdb7c9ba0
push id31551
push usercbook@mozilla.com
push dateFri, 24 Mar 2017 13:24:56 +0000
treeherdermozilla-central@4c987b7ed54a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald
bugs1315850
milestone55.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 1315850 - Implement ChromiumCDMProxy initialization. r=gerald This means the MediaKeys is able to create a CDM. MozReview-Commit-ID: 94Xc7sCLhH3
dom/media/gmp/ChromiumCDMParent.cpp
dom/media/gmp/ChromiumCDMParent.h
dom/media/gmp/ChromiumCDMProxy.cpp
dom/media/gmp/ChromiumCDMProxy.h
dom/media/gmp/GMPContentParent.cpp
--- a/dom/media/gmp/ChromiumCDMParent.cpp
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -1,25 +1,38 @@
 /* -*- 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/. */
 
 #include "ChromiumCDMParent.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "GMPContentChild.h"
+#include "mozilla/Unused.h"
+#include "ChromiumCDMProxy.h"
 
 namespace mozilla {
 namespace gmp {
 
-ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent)
-  : mContentParent(aContentParent)
+ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent,
+                                     uint32_t aPluginId)
+  : mPluginId(aPluginId)
+  , mContentParent(aContentParent)
 {
 }
 
+bool
+ChromiumCDMParent::Init(ChromiumCDMProxy* aProxy,
+                        bool aAllowDistinctiveIdentifier,
+                        bool aAllowPersistentState)
+{
+  mProxy = aProxy;
+  return SendInit(aAllowDistinctiveIdentifier, aAllowPersistentState);
+}
+
 ipc::IPCResult
 ChromiumCDMParent::Recv__delete__()
 {
   return IPC_OK();
 }
 
 ipc::IPCResult
 ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
--- a/dom/media/gmp/ChromiumCDMParent.h
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -8,28 +8,37 @@
 
 #include "GMPCrashHelper.h"
 #include "GMPCrashHelperHolder.h"
 #include "GMPMessageUtils.h"
 #include "mozilla/gmp/PChromiumCDMParent.h"
 #include "mozilla/RefPtr.h"
 
 namespace mozilla {
+
+class ChromiumCDMProxy;
+
 namespace gmp {
 
 class GMPContentParent;
 
 class ChromiumCDMParent final
   : public PChromiumCDMParent
   , public GMPCrashHelperHolder
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMParent)
 
-  explicit ChromiumCDMParent(GMPContentParent* aContentParent);
+  ChromiumCDMParent(GMPContentParent* aContentParent, uint32_t aPluginId);
+
+  uint32_t PluginId() const { return mPluginId; }
+
+  bool Init(ChromiumCDMProxy* aProxy,
+            bool aAllowDistinctiveIdentifier,
+            bool aAllowPersistentState);
 
   // TODO: Add functions for clients to send data to CDM, and
   // a Close() function.
 
 protected:
   ~ChromiumCDMParent() {}
 
   ipc::IPCResult Recv__delete__() override;
@@ -57,15 +66,20 @@ protected:
                                           const nsCString& aMessage) override;
   ipc::IPCResult RecvDecrypted(const uint32_t& aStatus,
                                nsTArray<uint8_t>&& aData) override;
   ipc::IPCResult RecvDecoded(const CDMVideoFrame& aFrame) override;
   ipc::IPCResult RecvDecodeFailed(const uint32_t& aStatus) override;
   ipc::IPCResult RecvShutdown() override;
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
+  const uint32_t mPluginId;
   GMPContentParent* mContentParent;
+  // Note: this pointer is a weak reference because otherwise it would cause
+  // a cycle, as ChromiumCDMProxy has a strong reference to the
+  // ChromiumCDMParent.
+  ChromiumCDMProxy* mProxy = nullptr;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // ChromiumCDMParent_h_
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -1,16 +1,18 @@
 /* -*- 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 "ChromiumCDMProxy.h"
 #include "GMPUtils.h"
+#include "nsPrintfCString.h"
+#include "GMPService.h"
 
 namespace mozilla {
 
 ChromiumCDMProxy::ChromiumCDMProxy(dom::MediaKeys* aKeys,
                                    const nsAString& aKeySystem,
                                    GMPCrashHelper* aCrashHelper,
                                    bool aDistinctiveIdentifierRequired,
                                    bool aPersistentStateRequired,
@@ -34,16 +36,105 @@ ChromiumCDMProxy::~ChromiumCDMProxy()
 }
 
 void
 ChromiumCDMProxy::Init(PromiseId aPromiseId,
                        const nsAString& aOrigin,
                        const nsAString& aTopLevelOrigin,
                        const nsAString& aGMPName)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
+
+  EME_LOG("ChromiumCDMProxy::Init(%s, %s)",
+          NS_ConvertUTF16toUTF8(aOrigin).get(),
+          NS_ConvertUTF16toUTF8(aTopLevelOrigin).get());
+
+  if (!mGMPThread) {
+    RejectPromise(
+      aPromiseId,
+      NS_ERROR_DOM_INVALID_STATE_ERR,
+      NS_LITERAL_CSTRING("Couldn't get GMP thread ChromiumCDMProxy::Init"));
+    return;
+  }
+
+  if (aGMPName.IsEmpty()) {
+    RejectPromise(aPromiseId,
+                  NS_ERROR_DOM_INVALID_STATE_ERR,
+                  nsPrintfCString("Unknown GMP for keysystem '%s'",
+                                  NS_ConvertUTF16toUTF8(mKeySystem).get()));
+    return;
+  }
+
+  gmp::NodeId nodeId(aOrigin, aTopLevelOrigin, aGMPName);
+  RefPtr<AbstractThread> thread = mGMPThread;
+  RefPtr<GMPCrashHelper> helper(mCrashHelper);
+  RefPtr<ChromiumCDMProxy> self(this);
+  nsCString keySystem = NS_ConvertUTF16toUTF8(mKeySystem);
+  RefPtr<Runnable> task(NS_NewRunnableFunction(
+    [self, nodeId, helper, aPromiseId, thread, keySystem]() -> void {
+      MOZ_ASSERT(self->IsOnOwnerThread());
+
+      RefPtr<gmp::GeckoMediaPluginService> service =
+        gmp::GeckoMediaPluginService::GetGeckoMediaPluginService();
+      if (!service) {
+        self->RejectPromise(
+          aPromiseId,
+          NS_ERROR_DOM_INVALID_STATE_ERR,
+          NS_LITERAL_CSTRING(
+            "Couldn't get GeckoMediaPluginService in ChromiumCDMProxy::Init"));
+        return;
+      }
+      RefPtr<gmp::GetCDMParentPromise> promise =
+        service->GetCDM(nodeId, { keySystem }, helper);
+      promise->Then(
+        thread,
+        __func__,
+        [self, aPromiseId](RefPtr<gmp::ChromiumCDMParent> cdm) {
+          if (!cdm->Init(self,
+                         self->mDistinctiveIdentifierRequired,
+                         self->mPersistentStateRequired)) {
+            self->RejectPromise(aPromiseId,
+                                NS_ERROR_FAILURE,
+                                NS_LITERAL_CSTRING("GetCDM failed."));
+            return;
+          }
+          self->mCDM = cdm;
+          self->OnCDMCreated(aPromiseId);
+        },
+        [self, aPromiseId](nsresult rv) {
+          self->RejectPromise(
+            aPromiseId, NS_ERROR_FAILURE, NS_LITERAL_CSTRING("GetCDM failed."));
+        });
+    }));
+
+  mGMPThread->Dispatch(task.forget());
+}
+
+void
+ChromiumCDMProxy::OnCDMCreated(uint32_t aPromiseId)
+{
+  EME_LOG("ChromiumCDMProxy::OnCDMCreated(pid=%u) isMainThread=%d this=%p",
+          aPromiseId,
+          NS_IsMainThread(),
+          this);
+
+  if (!NS_IsMainThread()) {
+    mMainThread->Dispatch(NewRunnableMethod<PromiseId>(
+                            this, &ChromiumCDMProxy::OnCDMCreated, aPromiseId),
+                          NS_DISPATCH_NORMAL);
+    return;
+  }
+  // This should only be called once the CDM has been created.
+  MOZ_ASSERT(mCDM);
+  MOZ_ASSERT(NS_IsMainThread());
+  if (mKeys.IsNull()) {
+    return;
+  }
+  mKeys->OnCDMCreated(aPromiseId, mCDM->PluginId());
 }
 
 #ifdef DEBUG
 bool
 ChromiumCDMProxy::IsOnOwnerThread()
 {
   return mGMPThread->IsCurrentThreadIn();
 }
@@ -93,21 +184,44 @@ ChromiumCDMProxy::Shutdown()
 {
 }
 
 void
 ChromiumCDMProxy::RejectPromise(PromiseId aId,
                                 nsresult aCode,
                                 const nsCString& aReason)
 {
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIRunnable> task;
+    task = NewRunnableMethod<PromiseId, nsresult, nsCString>(
+      this, &ChromiumCDMProxy::RejectPromise, aId, aCode, aReason);
+    NS_DispatchToMainThread(task);
+    return;
+  }
+  if (!mKeys.IsNull()) {
+    mKeys->RejectPromise(aId, aCode, aReason);
+  }
 }
 
 void
 ChromiumCDMProxy::ResolvePromise(PromiseId aId)
 {
+  if (!NS_IsMainThread()) {
+    nsCOMPtr<nsIRunnable> task;
+    task = NewRunnableMethod<PromiseId>(
+      this, &ChromiumCDMProxy::ResolvePromise, aId);
+    NS_DispatchToMainThread(task);
+    return;
+  }
+
+  if (!mKeys.IsNull()) {
+    mKeys->ResolvePromise(aId);
+  } else {
+    NS_WARNING("ChromiumCDMProxy unable to resolve promise!");
+  }
 }
 
 const nsCString&
 ChromiumCDMProxy::GetNodeId() const
 {
   return mNodeId;
 }
 
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -103,16 +103,18 @@ public:
   void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                              nsTArray<nsCString>& aSessionIds) override;
 
 #ifdef DEBUG
   bool IsOnOwnerThread() override;
 #endif
 
 private:
+  void OnCDMCreated(uint32_t aPromiseId);
+
   ~ChromiumCDMProxy();
 
   GMPCrashHelper* mCrashHelper;
 
   RefPtr<gmp::ChromiumCDMParent> mCDM;
   RefPtr<AbstractThread> mGMPThread;
 };
 
--- a/dom/media/gmp/GMPContentParent.cpp
+++ b/dom/media/gmp/GMPContentParent.cpp
@@ -238,17 +238,17 @@ GMPContentParent::GetGMPVideoEncoder(GMP
   mVideoEncoders.AppendElement(vep);
 
   return NS_OK;
 }
 
 PChromiumCDMParent*
 GMPContentParent::AllocPChromiumCDMParent()
 {
-  ChromiumCDMParent* parent = new ChromiumCDMParent(this);
+  ChromiumCDMParent* parent = new ChromiumCDMParent(this, GetPluginId());
   NS_ADDREF(parent);
   return parent;
 }
 
 PGMPVideoDecoderParent*
 GMPContentParent::AllocPGMPVideoDecoderParent(const uint32_t& aDecryptorId)
 {
   GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);