Bug 1315850 - Implement ChromiumCDMProxy initialization. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Thu, 09 Mar 2017 11:29:45 +1300
changeset 504162 914db1f04e0770776ae25c7b8bdc59e729fe78d0
parent 504161 68ce766bede0f5c8e41de3a3f9e46b6ef88cab96
child 504163 0931d65116bf0c499933efc58cae97b275b0ba85
push id50748
push userbmo:cpearce@mozilla.com
push dateFri, 24 Mar 2017 01:10:17 +0000
reviewersgerald
bugs1315850
milestone55.0a1
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);