Bug 1315850 - Add PChromiumCDM.ipdl for Widevine CDM. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Thu, 23 Feb 2017 11:51:00 +1300
changeset 503966 b796bfb4c0d0d2872787043e3b9fc83a0e6b09ea
parent 503906 200182ef115692c4ed2909f1a8beae8a6f19d127
child 503967 3df4dd5bb8a89e75478b059a030193daaead1ed5
push id50727
push userbmo:cpearce@mozilla.com
push dateThu, 23 Mar 2017 22:10:26 +0000
reviewersgerald
bugs1315850
milestone55.0a1
Bug 1315850 - Add PChromiumCDM.ipdl for Widevine CDM. r=gerald The implementations of this protocol will be stubbed out in later patches. MozReview-Commit-ID: 622CB1BOoR9
dom/media/gmp/ChromiumCDMChild.cpp
dom/media/gmp/ChromiumCDMChild.h
dom/media/gmp/ChromiumCDMParent.cpp
dom/media/gmp/ChromiumCDMParent.h
dom/media/gmp/GMPContentChild.cpp
dom/media/gmp/GMPContentChild.h
dom/media/gmp/GMPContentParent.cpp
dom/media/gmp/GMPContentParent.h
dom/media/gmp/GMPTypes.ipdlh
dom/media/gmp/GMPVideoEncoderParent.cpp
dom/media/gmp/PChromiumCDM.ipdl
dom/media/gmp/PGMPContent.ipdl
dom/media/gmp/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -0,0 +1,102 @@
+/* -*- 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 "ChromiumCDMChild.h"
+#include "GMPContentChild.h"
+
+namespace mozilla {
+namespace gmp {
+
+ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
+  : mPlugin(aPlugin)
+{
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvInit(const bool& aAllowDistinctiveIdentifier,
+                           const bool& aAllowPersistentState)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvSetServerCertificate(const uint32_t& aPromiseId,
+                                           nsTArray<uint8_t>&& aServerCert)
+
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvCreateSessionAndGenerateRequest(
+  const uint32_t& aPromiseId,
+  const uint32_t& aSessionType,
+  const uint32_t& aInitDataType,
+  nsTArray<uint8_t>&& aInitData)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvUpdateSession(const uint32_t& aPromiseId,
+                                    const nsCString& aSessionId,
+                                    nsTArray<uint8_t>&& aResponse)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvCloseSession(const uint32_t& aPromiseId,
+                                   const nsCString& aSessionId)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvRemoveSession(const uint32_t& aPromiseId,
+                                    const nsCString& aSessionId)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvDecrypt(const CDMInputBuffer& aBuffer)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvInitializeVideoDecoder(
+  const CDMVideoDecoderConfig& aConfig)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvDeinitializeVideoDecoder()
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvResetVideoDecoder()
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvDecryptAndDecodeFrame(const CDMInputBuffer& aBuffer)
+{
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+ChromiumCDMChild::RecvDestroy()
+{
+  return IPC_OK();
+}
+
+} // namespace gmp
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -0,0 +1,58 @@
+/* -*- 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 ChromiumCDMChild_h_
+#define ChromiumCDMChild_h_
+
+#include "mozilla/gmp/PChromiumCDMChild.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPContentChild;
+
+class ChromiumCDMChild : public PChromiumCDMChild
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMChild);
+
+  explicit ChromiumCDMChild(GMPContentChild* aPlugin);
+
+protected:
+  ~ChromiumCDMChild() {}
+
+  ipc::IPCResult RecvInit(const bool& aAllowDistinctiveIdentifier,
+                          const bool& aAllowPersistentState) override;
+  ipc::IPCResult RecvSetServerCertificate(
+    const uint32_t& aPromiseId,
+    nsTArray<uint8_t>&& aServerCert) override;
+  ipc::IPCResult RecvCreateSessionAndGenerateRequest(
+    const uint32_t& aPromiseId,
+    const uint32_t& aSessionType,
+    const uint32_t& aInitDataType,
+    nsTArray<uint8_t>&& aInitData) override;
+  ipc::IPCResult RecvUpdateSession(const uint32_t& aPromiseId,
+                                   const nsCString& aSessionId,
+                                   nsTArray<uint8_t>&& aResponse) override;
+  ipc::IPCResult RecvCloseSession(const uint32_t& aPromiseId,
+                                  const nsCString& aSessionId) override;
+  ipc::IPCResult RecvRemoveSession(const uint32_t& aPromiseId,
+                                   const nsCString& aSessionId) override;
+  ipc::IPCResult RecvDecrypt(const CDMInputBuffer& aBuffer) override;
+  ipc::IPCResult RecvInitializeVideoDecoder(
+    const CDMVideoDecoderConfig& aConfig) override;
+  ipc::IPCResult RecvDeinitializeVideoDecoder() override;
+  ipc::IPCResult RecvResetVideoDecoder() override;
+  ipc::IPCResult RecvDecryptAndDecodeFrame(
+    const CDMInputBuffer& aBuffer) override;
+  ipc::IPCResult RecvDestroy() override;
+
+  GMPContentChild* mPlugin;
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // ChromiumCDMChild_h_
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/ChromiumCDMParent.cpp
@@ -0,0 +1,116 @@
+/* -*- 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"
+
+namespace mozilla {
+namespace gmp {
+
+ChromiumCDMParent::ChromiumCDMParent(GMPContentParent* aContentParent)
+  : mContentParent(aContentParent)
+{
+}
+
+ipc::IPCResult
+ChromiumCDMParent::Recv__delete__()
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnResolveNewSessionPromise(const uint32_t& aPromiseId,
+                                                  const nsCString& aSessionId)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnResolvePromise(const uint32_t& aPromiseId)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnRejectPromise(const uint32_t& aPromiseId,
+                                       const uint32_t& aError,
+                                       const uint32_t& aSystemCode,
+                                       const nsCString& aErrorMessage)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnSessionMessage(const nsCString& aSessionId,
+                                        const uint32_t& aMessageType,
+                                        nsTArray<uint8_t>&& aMessage)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnSessionKeysChange(
+  const nsCString& aSessionId,
+  nsTArray<CDMKeyInformation>&& aKeysInfo)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnExpirationChange(const nsCString& aSessionId,
+                                          const double& aSecondsSinceEpoch)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnSessionClosed(const nsCString& aSessionId)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvOnLegacySessionError(const nsCString& aSessionId,
+                                            const uint32_t& aError,
+                                            const uint32_t& aSystemCode,
+                                            const nsCString& aMessage)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvDecrypted(const uint32_t& aStatus,
+                                 nsTArray<uint8_t>&& aData)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvDecoded(const CDMVideoFrame& aFrame)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvDecodeFailed(const uint32_t& aStatus)
+{
+  return IPC_OK();
+}
+
+ipc::IPCResult
+ChromiumCDMParent::RecvShutdown()
+{
+  // TODO: SendDestroy(), call Terminated.
+  return IPC_OK();
+}
+
+void
+ChromiumCDMParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+}
+
+} // namespace gmp
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/ChromiumCDMParent.h
@@ -0,0 +1,71 @@
+/* -*- 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 ChromiumCDMParent_h_
+#define ChromiumCDMParent_h_
+
+#include "GMPCrashHelper.h"
+#include "GMPCrashHelperHolder.h"
+#include "GMPMessageUtils.h"
+#include "mozilla/gmp/PChromiumCDMParent.h"
+#include "mozilla/RefPtr.h"
+
+namespace mozilla {
+namespace gmp {
+
+class GMPContentParent;
+
+class ChromiumCDMParent final
+  : public PChromiumCDMParent
+  , public GMPCrashHelperHolder
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMParent)
+
+  explicit ChromiumCDMParent(GMPContentParent* aContentParent);
+
+  // TODO: Add functions for clients to send data to CDM, and
+  // a Close() function.
+
+protected:
+  ~ChromiumCDMParent() {}
+
+  ipc::IPCResult Recv__delete__() override;
+  ipc::IPCResult RecvOnResolveNewSessionPromise(
+    const uint32_t& aPromiseId,
+    const nsCString& aSessionId) override;
+  ipc::IPCResult RecvOnResolvePromise(const uint32_t& aPromiseId) override;
+  ipc::IPCResult RecvOnRejectPromise(const uint32_t& aPromiseId,
+                                     const uint32_t& aError,
+                                     const uint32_t& aSystemCode,
+                                     const nsCString& aErrorMessage) override;
+  ipc::IPCResult RecvOnSessionMessage(const nsCString& aSessionId,
+                                      const uint32_t& aMessageType,
+                                      nsTArray<uint8_t>&& aMessage) override;
+  ipc::IPCResult RecvOnSessionKeysChange(
+    const nsCString& aSessionId,
+    nsTArray<CDMKeyInformation>&& aKeysInfo) override;
+  ipc::IPCResult RecvOnExpirationChange(
+    const nsCString& aSessionId,
+    const double& aSecondsSinceEpoch) override;
+  ipc::IPCResult RecvOnSessionClosed(const nsCString& aSessionId) override;
+  ipc::IPCResult RecvOnLegacySessionError(const nsCString& aSessionId,
+                                          const uint32_t& aError,
+                                          const uint32_t& aSystemCode,
+                                          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;
+
+  GMPContentParent* mContentParent;
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // ChromiumCDMParent_h_
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -3,16 +3,17 @@
  * 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 "GMPContentChild.h"
 #include "GMPChild.h"
 #include "GMPDecryptorChild.h"
 #include "GMPVideoDecoderChild.h"
 #include "GMPVideoEncoderChild.h"
+#include "ChromiumCDMChild.h"
 #include "base/task.h"
 
 namespace mozilla {
 namespace gmp {
 
 GMPContentChild::GMPContentChild(GMPChild* aChild)
   : mGMPChild(aChild)
 {
@@ -88,16 +89,31 @@ GMPContentChild::AllocPGMPVideoEncoderCh
 
 bool
 GMPContentChild::DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor)
 {
   static_cast<GMPVideoEncoderChild*>(aActor)->Release();
   return true;
 }
 
+PChromiumCDMChild*
+GMPContentChild::AllocPChromiumCDMChild()
+{
+  ChromiumCDMChild* actor = new ChromiumCDMChild(this);
+  actor->AddRef();
+  return actor;
+}
+
+bool
+GMPContentChild::DeallocPChromiumCDMChild(PChromiumCDMChild* aActor)
+{
+  static_cast<ChromiumCDMChild*>(aActor)->Release();
+  return true;
+}
+
 mozilla::ipc::IPCResult
 GMPContentChild::RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor)
 {
   GMPDecryptorChild* child = static_cast<GMPDecryptorChild*>(aActor);
 
   void* ptr = nullptr;
   GMPErr err = mGMPChild->GetAPI(GMP_API_DECRYPTOR, nullptr, &ptr, child->DecryptorId());
   if (err != GMPNoErr || !ptr) {
@@ -139,16 +155,23 @@ GMPContentChild::RecvPGMPVideoEncoderCon
     return IPC_FAIL_NO_REASON(this);
   }
 
   vec->Init(static_cast<GMPVideoEncoder*>(ve));
 
   return IPC_OK();
 }
 
+mozilla::ipc::IPCResult
+GMPContentChild::RecvPChromiumCDMConstructor(PChromiumCDMChild* aActor)
+{
+  // TODO: Implement.
+  return IPC_OK();
+}
+
 void
 GMPContentChild::CloseActive()
 {
   // Invalidate and remove any remaining API objects.
   const ManagedContainer<PGMPDecryptorChild>& decryptors =
     ManagedPGMPDecryptorChild();
   for (auto iter = decryptors.ConstIter(); !iter.Done(); iter.Next()) {
     iter.Get()->GetKey()->SendShutdown();
@@ -160,20 +183,26 @@ GMPContentChild::CloseActive()
     iter.Get()->GetKey()->SendShutdown();
   }
 
   const ManagedContainer<PGMPVideoEncoderChild>& videoEncoders =
     ManagedPGMPVideoEncoderChild();
   for (auto iter = videoEncoders.ConstIter(); !iter.Done(); iter.Next()) {
     iter.Get()->GetKey()->SendShutdown();
   }
+
+  const ManagedContainer<PChromiumCDMChild>& cdms = ManagedPChromiumCDMChild();
+  for (auto iter = cdms.ConstIter(); !iter.Done(); iter.Next()) {
+    iter.Get()->GetKey()->SendShutdown();
+  }
 }
 
 bool
 GMPContentChild::IsUsed()
 {
   return !ManagedPGMPDecryptorChild().IsEmpty() ||
          !ManagedPGMPVideoDecoderChild().IsEmpty() ||
-         !ManagedPGMPVideoEncoderChild().IsEmpty();
+         !ManagedPGMPVideoEncoderChild().IsEmpty() ||
+         !ManagedPChromiumCDMChild().IsEmpty();
 }
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/GMPContentChild.h
+++ b/dom/media/gmp/GMPContentChild.h
@@ -21,26 +21,31 @@ public:
   explicit GMPContentChild(GMPChild* aChild);
   virtual ~GMPContentChild();
 
   MessageLoop* GMPMessageLoop();
 
   mozilla::ipc::IPCResult RecvPGMPDecryptorConstructor(PGMPDecryptorChild* aActor) override;
   mozilla::ipc::IPCResult RecvPGMPVideoDecoderConstructor(PGMPVideoDecoderChild* aActor, const uint32_t& aDecryptorId) override;
   mozilla::ipc::IPCResult RecvPGMPVideoEncoderConstructor(PGMPVideoEncoderChild* aActor) override;
+  mozilla::ipc::IPCResult RecvPChromiumCDMConstructor(
+    PChromiumCDMChild* aActor) override;
 
   PGMPDecryptorChild* AllocPGMPDecryptorChild() override;
   bool DeallocPGMPDecryptorChild(PGMPDecryptorChild* aActor) override;
 
   PGMPVideoDecoderChild* AllocPGMPVideoDecoderChild(const uint32_t& aDecryptorId) override;
   bool DeallocPGMPVideoDecoderChild(PGMPVideoDecoderChild* aActor) override;
 
   PGMPVideoEncoderChild* AllocPGMPVideoEncoderChild() override;
   bool DeallocPGMPVideoEncoderChild(PGMPVideoEncoderChild* aActor) override;
 
+  PChromiumCDMChild* AllocPChromiumCDMChild() override;
+  bool DeallocPChromiumCDMChild(PChromiumCDMChild* aActor) override;
+
   void ActorDestroy(ActorDestroyReason aWhy) override;
   void ProcessingError(Result aCode, const char* aReason) override;
 
   // GMPSharedMem
   void CheckThread() override;
 
   void CloseActive();
   bool IsUsed();
--- a/dom/media/gmp/GMPContentParent.cpp
+++ b/dom/media/gmp/GMPContentParent.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "GMPContentParent.h"
 #include "GMPDecryptorParent.h"
 #include "GMPParent.h"
 #include "GMPServiceChild.h"
 #include "GMPVideoDecoderParent.h"
 #include "GMPVideoEncoderParent.h"
+#include "ChromiumCDMParent.h"
 #include "mozIGeckoMediaPluginService.h"
 #include "mozilla/Logging.h"
 #include "mozilla/Unused.h"
 #include "base/task.h"
 
 namespace mozilla {
 
 #ifdef LOG
@@ -60,29 +61,37 @@ public:
 
 private:
   RefPtr<GMPContentParent> mToRelease;
 };
 
 void
 GMPContentParent::ActorDestroy(ActorDestroyReason aWhy)
 {
-  MOZ_ASSERT(mDecryptors.IsEmpty() &&
-             mVideoDecoders.IsEmpty() &&
-             mVideoEncoders.IsEmpty());
+  MOZ_ASSERT(mDecryptors.IsEmpty() && mVideoDecoders.IsEmpty() &&
+             mVideoEncoders.IsEmpty() && mChromiumCDMs.IsEmpty());
   NS_DispatchToCurrentThread(new ReleaseGMPContentParent(this));
 }
 
 void
 GMPContentParent::CheckThread()
 {
   MOZ_ASSERT(mGMPThread == NS_GetCurrentThread());
 }
 
 void
+GMPContentParent::ChromiumCDMDestroyed(ChromiumCDMParent* aDecoder)
+{
+  MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
+
+  MOZ_ALWAYS_TRUE(mChromiumCDMs.RemoveElement(aDecoder));
+  CloseIfUnused();
+}
+
+void
 GMPContentParent::VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder)
 {
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
 
   // If the constructor fails, we'll get called before it's added
   Unused << NS_WARN_IF(!mVideoDecoders.RemoveElement(aDecoder));
   CloseIfUnused();
 }
@@ -119,19 +128,18 @@ GMPContentParent::RemoveCloseBlocker()
   MOZ_ASSERT(GMPThread() == NS_GetCurrentThread());
   --mCloseBlockerCount;
   CloseIfUnused();
 }
 
 void
 GMPContentParent::CloseIfUnused()
 {
-  if (mDecryptors.IsEmpty() &&
-      mVideoDecoders.IsEmpty() &&
-      mVideoEncoders.IsEmpty() &&
+  if (mDecryptors.IsEmpty() && mVideoDecoders.IsEmpty() &&
+      mVideoEncoders.IsEmpty() && mChromiumCDMs.IsEmpty() &&
       mCloseBlockerCount == 0) {
     RefPtr<GMPContentParent> toClose;
     if (mParent) {
       toClose = mParent->ForgetGMPContentParent();
     } else {
       toClose = this;
       RefPtr<GeckoMediaPluginServiceChild> gmp(
         GeckoMediaPluginServiceChild::GetSingleton());
@@ -175,16 +183,31 @@ GMPContentParent::GMPThread()
     // to use swap() under a lock.
     mps->GetThread(getter_AddRefs(mGMPThread));
     MOZ_ASSERT(mGMPThread);
   }
 
   return mGMPThread;
 }
 
+already_AddRefed<ChromiumCDMParent>
+GMPContentParent::GetChromiumCDM()
+{
+  PChromiumCDMParent* actor = SendPChromiumCDMConstructor();
+  if (!actor) {
+    return nullptr;
+  }
+  RefPtr<ChromiumCDMParent> parent = static_cast<ChromiumCDMParent*>(actor);
+
+  // TODO: Remove parent from mChromiumCDMs in ChromiumCDMParent::Destroy().
+  mChromiumCDMs.AppendElement(parent);
+
+  return parent.forget();
+}
+
 nsresult
 GMPContentParent::GetGMPVideoDecoder(GMPVideoDecoderParent** aGMPVD,
                                      uint32_t aDecryptorId)
 {
   // returned with one anonymous AddRef that locks it until Destroy
   PGMPVideoDecoderParent* pvdp = SendPGMPVideoDecoderConstructor(aDecryptorId);
   if (!pvdp) {
     return NS_ERROR_FAILURE;
@@ -212,25 +235,41 @@ GMPContentParent::GetGMPVideoEncoder(GMP
   // It's dropped by calling Close() on the interface.
   NS_ADDREF(vep);
   *aGMPVE = vep;
   mVideoEncoders.AppendElement(vep);
 
   return NS_OK;
 }
 
+PChromiumCDMParent*
+GMPContentParent::AllocPChromiumCDMParent()
+{
+  ChromiumCDMParent* parent = new ChromiumCDMParent(this);
+  NS_ADDREF(parent);
+  return parent;
+}
+
 PGMPVideoDecoderParent*
 GMPContentParent::AllocPGMPVideoDecoderParent(const uint32_t& aDecryptorId)
 {
   GMPVideoDecoderParent* vdp = new GMPVideoDecoderParent(this);
   NS_ADDREF(vdp);
   return vdp;
 }
 
 bool
+GMPContentParent::DeallocPChromiumCDMParent(PChromiumCDMParent* aActor)
+{
+  ChromiumCDMParent* parent = static_cast<ChromiumCDMParent*>(aActor);
+  NS_RELEASE(parent);
+  return true;
+}
+
+bool
 GMPContentParent::DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor)
 {
   GMPVideoDecoderParent* vdp = static_cast<GMPVideoDecoderParent*>(aActor);
   NS_RELEASE(vdp);
   return true;
 }
 
 PGMPVideoEncoderParent*
--- a/dom/media/gmp/GMPContentParent.h
+++ b/dom/media/gmp/GMPContentParent.h
@@ -12,16 +12,17 @@
 
 namespace mozilla {
 namespace gmp {
 
 class GMPDecryptorParent;
 class GMPParent;
 class GMPVideoDecoderParent;
 class GMPVideoEncoderParent;
+class ChromiumCDMParent;
 
 class GMPContentParent final : public PGMPContentParent,
                                public GMPSharedMem
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPContentParent)
 
   explicit GMPContentParent(GMPParent* aParent = nullptr);
@@ -31,16 +32,19 @@ public:
   void VideoDecoderDestroyed(GMPVideoDecoderParent* aDecoder);
 
   nsresult GetGMPVideoEncoder(GMPVideoEncoderParent** aGMPVE);
   void VideoEncoderDestroyed(GMPVideoEncoderParent* aEncoder);
 
   nsresult GetGMPDecryptor(GMPDecryptorParent** aGMPKS);
   void DecryptorDestroyed(GMPDecryptorParent* aSession);
 
+  already_AddRefed<ChromiumCDMParent> GetChromiumCDM();
+  void ChromiumCDMDestroyed(ChromiumCDMParent* aCDM);
+
   nsIThread* GMPThread();
 
   // GMPSharedMem
   void CheckThread() override;
 
   void SetDisplayName(const nsCString& aDisplayName)
   {
     mDisplayName = aDisplayName;
@@ -87,27 +91,31 @@ private:
   bool DeallocPGMPVideoDecoderParent(PGMPVideoDecoderParent* aActor) override;
 
   PGMPVideoEncoderParent* AllocPGMPVideoEncoderParent() override;
   bool DeallocPGMPVideoEncoderParent(PGMPVideoEncoderParent* aActor) override;
 
   PGMPDecryptorParent* AllocPGMPDecryptorParent() override;
   bool DeallocPGMPDecryptorParent(PGMPDecryptorParent* aActor) override;
 
+  PChromiumCDMParent* AllocPChromiumCDMParent() override;
+  bool DeallocPChromiumCDMParent(PChromiumCDMParent* aActor) override;
+
   void CloseIfUnused();
   // Needed because NewRunnableMethod tried to use the class that the method
   // lives on to store the receiver, but PGMPContentParent isn't refcounted.
   void Close()
   {
     PGMPContentParent::Close();
   }
 
   nsTArray<RefPtr<GMPVideoDecoderParent>> mVideoDecoders;
   nsTArray<RefPtr<GMPVideoEncoderParent>> mVideoEncoders;
   nsTArray<RefPtr<GMPDecryptorParent>> mDecryptors;
+  nsTArray<RefPtr<ChromiumCDMParent>> mChromiumCDMs;
   nsCOMPtr<nsIThread> mGMPThread;
   RefPtr<GMPParent> mParent;
   nsCString mDisplayName;
   uint32_t mPluginId;
   uint32_t mCloseBlockerCount = 0;
 };
 
 } // namespace gmp
--- a/dom/media/gmp/GMPTypes.ipdlh
+++ b/dom/media/gmp/GMPTypes.ipdlh
@@ -49,10 +49,53 @@ struct GMPVideoi420FrameData
   uint64_t mDuration; // microseconds
 };
 
 struct GMPKeyInformation {
   uint8_t[] keyId;
   GMPMediaKeyStatus status;
 };
 
+struct CDMInputBuffer {
+  uint8_t[] mData;
+  uint8_t[] mKeyId;
+  uint8_t[] mIV;
+  int64_t mTimestamp;
+  int64_t mDuration;
+  uint16_t[] mClearBytes;
+  uint32_t[] mCipherBytes;
+  bool mIsEncrypted;
+};
+
+struct CDMVideoDecoderConfig {
+  uint32_t mCodec;
+  uint32_t mProfile;
+  uint32_t mFormat;
+  int32_t mImageWidth;
+  int32_t mImageHeight;
+  uint8_t[] mExtraData;
+};
+
+struct CDMKeyInformation {
+  uint8_t[] mKeyId;
+  uint32_t mStatus;
+  uint32_t mSystemCode;
+};
+
+struct CDMVideoPlane {
+  uint32_t mPlaneOffset;
+  uint32_t mStride;
+};
+
+struct CDMVideoFrame {
+  uint32_t mFormat;
+  int32_t mImageWidth;
+  int32_t mImageHeight;
+  uint8_t[] mData;
+  CDMVideoPlane mYPlane;
+  CDMVideoPlane mUPlane;
+  CDMVideoPlane mVPlane;
+  int64_t mTimestamp;
+  int64_t mDuration;
+};
+
 }
 }
--- a/dom/media/gmp/GMPVideoEncoderParent.cpp
+++ b/dom/media/gmp/GMPVideoEncoderParent.cpp
@@ -12,16 +12,17 @@
 #include "nsAutoRef.h"
 #include "GMPContentParent.h"
 #include "mozilla/gmp/GMPTypes.h"
 #include "nsThread.h"
 #include "nsThreadUtils.h"
 #include "runnable_utils.h"
 #include "GMPUtils.h"
 #include "mozilla/SystemGroup.h"
+#include "GMPCrashHelper.h"
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
 
 extern LogModule* GetGMPLog();
new file mode 100644
--- /dev/null
+++ b/dom/media/gmp/PChromiumCDM.ipdl
@@ -0,0 +1,92 @@
+/* -*- 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 protocol PGMPContent;
+include GMPTypes;
+
+namespace mozilla {
+namespace gmp {
+
+async protocol PChromiumCDM
+{
+  manager PGMPContent;
+child:
+
+  // cdm::ContentDecryptionModule8
+  async Init(bool aAllowDistinctiveIdentifier,
+             bool aAllowPersistentState);
+
+  async SetServerCertificate(uint32_t aPromiseId,
+                             uint8_t[] aServerCert);
+
+  async CreateSessionAndGenerateRequest(uint32_t aPromiseId,
+                                        uint32_t aSessionType,
+                                        uint32_t aInitDataType,
+                                        uint8_t[] aInitData);
+
+  async UpdateSession(uint32_t aPromiseId,
+                      nsCString aSessionId,
+                      uint8_t[] aResponse);
+
+  async CloseSession(uint32_t aPromiseId,
+                     nsCString aSessionId);
+
+  async RemoveSession(uint32_t aPromiseId,
+                      nsCString aSessionId);
+
+  async Decrypt(CDMInputBuffer aBuffer);
+
+  async InitializeVideoDecoder(CDMVideoDecoderConfig aConfig);
+
+  async DeinitializeVideoDecoder();
+
+  async ResetVideoDecoder();
+
+  async DecryptAndDecodeFrame(CDMInputBuffer aBuffer);
+
+  async Destroy();
+
+parent:
+  async __delete__();
+
+  // cdm::Host8
+  async OnResolveNewSessionPromise(uint32_t aPromiseId, nsCString aSessionId);
+
+  async OnResolvePromise(uint32_t aPromiseId);
+
+  async OnRejectPromise(uint32_t aPromiseId,
+                        uint32_t aError,
+                        uint32_t aSystemCode,
+                        nsCString aErrorMessage);
+
+  async OnSessionMessage(nsCString aSessionId,
+                         uint32_t aMessageType,
+                         uint8_t[] aMessage);
+
+  async OnSessionKeysChange(nsCString aSessionId,
+                            CDMKeyInformation[] aKeysInfo);
+
+  async OnExpirationChange(nsCString aSessionId,
+                           double aSecondsSinceEpoch);
+
+  async OnSessionClosed(nsCString aSessionId);
+
+  async OnLegacySessionError(nsCString aSessionId,
+                             uint32_t aError,
+                             uint32_t aSystemCode,
+                             nsCString aMessage);
+
+  // Return values of cdm::ContentDecryptionModule8::Decrypt
+  async Decrypted(uint32_t aStatus, uint8_t[] aData);
+
+  // Return values of cdm::ContentDecryptionModule8::DecryptAndDecodeFrame
+  async Decoded(CDMVideoFrame aFrame);
+  async DecodeFailed(uint32_t aStatus);
+
+  async Shutdown();
+};
+
+} // namespace gmp
+} // namespace mozilla
--- a/dom/media/gmp/PGMPContent.ipdl
+++ b/dom/media/gmp/PGMPContent.ipdl
@@ -1,26 +1,29 @@
 /* -*- 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 protocol PGMPVideoDecoder;
 include protocol PGMPVideoEncoder;
 include protocol PGMPDecryptor;
+include protocol PChromiumCDM;
 
 namespace mozilla {
 namespace gmp {
 
 intr protocol PGMPContent
 {
   manages PGMPDecryptor;
   manages PGMPVideoDecoder;
   manages PGMPVideoEncoder;
+  manages PChromiumCDM;
 
 child:
   async PGMPDecryptor();
   async PGMPVideoDecoder(uint32_t aDecryptorId);
   async PGMPVideoEncoder();
+  async PChromiumCDM();
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -63,16 +63,18 @@ EXPORTS += [
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
     'widevine-adapter/content_decryption_module.h',
 ]
 
 UNIFIED_SOURCES += [
+    'ChromiumCDMChild.cpp',
+    'ChromiumCDMParent.cpp',
     'DecryptJob.cpp',
     'GMPCDMCallbackProxy.cpp',
     'GMPCDMProxy.cpp',
     'GMPChild.cpp',
     'GMPContentChild.cpp',
     'GMPContentParent.cpp',
     'GMPCrashHelper.cpp',
     'GMPCrashHelperHolder.cpp',
@@ -106,16 +108,17 @@ UNIFIED_SOURCES += [
 ]
 
 DIRS += [
     'widevine-adapter',
 ]
 
 IPDL_SOURCES += [
   'GMPTypes.ipdlh',
+  'PChromiumCDM.ipdl',
   'PGMP.ipdl',
   'PGMPContent.ipdl',
   'PGMPDecryptor.ipdl',
   'PGMPService.ipdl',
   'PGMPStorage.ipdl',
   'PGMPTimer.ipdl',
   'PGMPVideoDecoder.ipdl',
   'PGMPVideoEncoder.ipdl',