Bug 1315850 - Add PChromiumCDM.ipdl for Widevine CDM. r=gerald
authorChris Pearce <cpearce@mozilla.com>
Thu, 23 Feb 2017 11:51:00 +1300
changeset 349416 6e4c1af85be74c4ec0e018f84951469cc0dc4e2d
parent 349415 038761b0c9cded9af7ed44271074d534d2ffd85a
child 349417 778ae7585a4e306a9a88f3c2033d41ac0b193841
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 - 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',