Bug 1315850 - Add ChromiumAdapter which we can use instead of WidevineAdapter. r=gerald draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 13 Mar 2017 16:59:34 +1300
changeset 504156 7c08edea3c11d41eb3ecfa9c7a8ef65cf3b8ddb0
parent 504155 c76f1f5f88f53abc4929d21abf6fabf1e47e6056
child 504157 dd262cc875ece0d82b4af002341ee0566125a401
push id50748
push userbmo:cpearce@mozilla.com
push dateFri, 24 Mar 2017 01:10:17 +0000
reviewersgerald
bugs1315850
milestone55.0a1
Bug 1315850 - Add ChromiumAdapter which we can use instead of WidevineAdapter. r=gerald We currently use an adapter object to adapt plugins that don't conform to the GMP interface to the GMP interface. We use the WidevineAdapter to talk to the CDM from the two GMP IPDL protocols. We will be using a single protocol to talk to the Chromium CDM, so we need a new adapter which handles that. MozReview-Commit-ID: F7hnZ9oo9mJ
dom/media/gmp/ChromiumCDMAdapter.cpp
dom/media/gmp/ChromiumCDMAdapter.h
dom/media/gmp/ChromiumCDMChild.cpp
dom/media/gmp/ChromiumCDMChild.h
dom/media/gmp/GMPChild.cpp
dom/media/gmp/GMPContentChild.cpp
dom/media/gmp/moz.build
dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
copy from dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
copy to dom/media/gmp/ChromiumCDMAdapter.cpp
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/ChromiumCDMAdapter.cpp
@@ -1,66 +1,51 @@
 /* -*- 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 "WidevineAdapter.h"
+#include "ChromiumCDMAdapter.h"
 #include "content_decryption_module.h"
 #include "VideoUtils.h"
-#include "WidevineDecryptor.h"
-#include "WidevineDummyDecoder.h"
-#include "WidevineUtils.h"
-#include "WidevineVideoDecoder.h"
 #include "gmp-api/gmp-entrypoints.h"
 #include "gmp-api/gmp-decryption.h"
 #include "gmp-api/gmp-video-codec.h"
 #include "gmp-api/gmp-platform.h"
+#include "WidevineUtils.h"
+#include "GMPLog.h"
 
-static const GMPPlatformAPI* sPlatform = nullptr;
+// Declared in WidevineAdapter.cpp.
+extern const GMPPlatformAPI* sPlatform;
 
 namespace mozilla {
 
-GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
-  return sPlatform->getcurrenttime(aOutTime);
-}
-
-// Call on main thread only.
-GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) {
-  return sPlatform->settimer(aTask, aTimeoutMS);
-}
-
-GMPErr GMPCreateRecord(const char* aRecordName,
-                       uint32_t aRecordNameSize,
-                       GMPRecord** aOutRecord,
-                       GMPRecordClient* aClient)
-{
-  return sPlatform->createrecord(aRecordName, aRecordNameSize, aOutRecord, aClient);
-}
-
 void
-WidevineAdapter::SetAdaptee(PRLibrary* aLib)
+ChromiumCDMAdapter::SetAdaptee(PRLibrary* aLib)
 {
   mLib = aLib;
 }
 
-void* GetCdmHost(int aHostInterfaceVersion, void* aUserData)
+void*
+ChromiumCdmHost(int aHostInterfaceVersion, void* aUserData)
 {
-  CDM_LOG("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
-  WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData);
-  MOZ_ASSERT(decryptor);
-  return static_cast<cdm::Host_8*>(decryptor);
+  CDM_LOG("ChromiumCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData);
+  if (aHostInterfaceVersion != cdm::Host_8::kVersion) {
+    return nullptr;
+  }
+  return static_cast<cdm::Host_8*>(aUserData);
 }
 
 #define STRINGIFY(s) _STRINGIFY(s)
 #define _STRINGIFY(s) #s
 
 GMPErr
-WidevineAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
+ChromiumCDMAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI)
 {
+  CDM_LOG("ChromiumCDMAdapter::GMPInit");
   sPlatform = aPlatformAPI;
   if (!mLib) {
     return GMPGenericErr;
   }
 
   auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>(
     PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE)));
   if (!init) {
@@ -69,91 +54,80 @@ WidevineAdapter::GMPInit(const GMPPlatfo
 
   CDM_LOG(STRINGIFY(INITIALIZE_CDM_MODULE)"()");
   init();
 
   return GMPNoErr;
 }
 
 GMPErr
-WidevineAdapter::GMPGetAPI(const char* aAPIName,
-                           void* aHostAPI,
-                           void** aPluginAPI,
-                           uint32_t aDecryptorId)
+ChromiumCDMAdapter::GMPGetAPI(const char* aAPIName,
+                              void* aHostAPI,
+                              void** aPluginAPI,
+                              uint32_t aDecryptorId)
 {
-  CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
-          aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
-  if (!strcmp(aAPIName, GMP_API_DECRYPTOR)) {
-    if (WidevineDecryptor::GetInstance(aDecryptorId)) {
-      // We only support one CDM instance per PGMPDecryptor. Fail!
-      CDM_LOG("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per IPDL actor! FAIL!");
-      return GMPQuotaExceededErr;
-    }
+  CDM_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p",
+          aAPIName,
+          aHostAPI,
+          aPluginAPI,
+          aDecryptorId,
+          this);
+  if (!strcmp(aAPIName, CHROMIUM_CDM_API)) {
     auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>(
       PR_FindFunctionSymbol(mLib, "CreateCdmInstance"));
     if (!create) {
-      CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to find CreateCdmInstance",
-              aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
+      CDM_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p "
+              "FAILED to find CreateCdmInstance",
+              aAPIName,
+              aHostAPI,
+              aPluginAPI,
+              aDecryptorId,
+              this);
       return GMPGenericErr;
     }
 
-    auto* decryptor = new WidevineDecryptor();
-
     auto cdm = reinterpret_cast<cdm::ContentDecryptionModule*>(
       create(cdm::ContentDecryptionModule::kVersion,
              kEMEKeySystemWidevine.get(),
              kEMEKeySystemWidevine.Length(),
-             &GetCdmHost,
-             decryptor));
+             &ChromiumCdmHost,
+             aHostAPI));
     if (!cdm) {
-      CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to create cdm",
-              aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
+      CDM_LOG("ChromiumCDMAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p "
+              "FAILED to create cdm",
+              aAPIName,
+              aHostAPI,
+              aPluginAPI,
+              aDecryptorId,
+              this);
       return GMPGenericErr;
     }
     CDM_LOG("cdm: 0x%p", cdm);
-    RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm, decryptor));
-    decryptor->SetCDM(wrapper, aDecryptorId);
-    *aPluginAPI = decryptor;
-
-  } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) {
-    RefPtr<CDMWrapper> wrapper = WidevineDecryptor::GetInstance(aDecryptorId);
-
-    // There is a possible race condition, where the decryptor will be destroyed
-    // before we are able to create the video decoder, so we create a dummy
-    // decoder to avoid crashing.
-    if (!wrapper) {
-      CDM_LOG("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p No cdm for video decoder. Using a DummyDecoder",
-              aAPIName, aHostAPI, aPluginAPI, aDecryptorId, this);
-
-      *aPluginAPI = new WidevineDummyDecoder();
-    } else {
-      *aPluginAPI = new WidevineVideoDecoder(static_cast<GMPVideoHost*>(aHostAPI),
-                                             wrapper);
-    }
+    *aPluginAPI = cdm;
   }
   return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr;
 }
 
 void
-WidevineAdapter::GMPShutdown()
+ChromiumCDMAdapter::GMPShutdown()
 {
-  CDM_LOG("WidevineAdapter::GMPShutdown()");
+  CDM_LOG("ChromiumCDMAdapter::GMPShutdown()");
 
   decltype(::DeinitializeCdmModule)* deinit;
   deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule"));
   if (deinit) {
     CDM_LOG("DeinitializeCdmModule()");
     deinit();
   }
 }
 
 /* static */
 bool
-WidevineAdapter::Supports(int32_t aModuleVersion,
-                          int32_t aInterfaceVersion,
-                          int32_t aHostVersion)
+ChromiumCDMAdapter::Supports(int32_t aModuleVersion,
+                             int32_t aInterfaceVersion,
+                             int32_t aHostVersion)
 {
   return aModuleVersion == CDM_MODULE_VERSION &&
          aInterfaceVersion == cdm::ContentDecryptionModule::kVersion &&
          aHostVersion == cdm::Host_8::kVersion;
 }
 
 } // namespace mozilla
copy from dom/media/gmp/widevine-adapter/WidevineAdapter.h
copy to dom/media/gmp/ChromiumCDMAdapter.h
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.h
+++ b/dom/media/gmp/ChromiumCDMAdapter.h
@@ -1,25 +1,26 @@
 /* -*- 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 WidevineAdapter_h_
-#define WidevineAdapter_h_
+#ifndef ChromiumAdapter_h_
+#define ChromiumAdapter_h_
 
 #include "GMPLoader.h"
 #include "prlink.h"
 #include "GMPUtils.h"
 
 struct GMPPlatformAPI;
 
 namespace mozilla {
 
-class WidevineAdapter : public gmp::GMPAdapter {
+class ChromiumCDMAdapter : public gmp::GMPAdapter
+{
 public:
 
   void SetAdaptee(PRLibrary* aLib) override;
 
   // These are called in place of the corresponding GMP API functions.
   GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override;
   GMPErr GMPGetAPI(const char* aAPIName,
                    void* aHostAPI,
@@ -30,26 +31,11 @@ public:
   static bool Supports(int32_t aModuleVersion,
                        int32_t aInterfaceVersion,
                        int32_t aHostVersion);
 
 private:
   PRLibrary* mLib = nullptr;
 };
 
-GMPErr GMPCreateThread(GMPThread** aThread);
-GMPErr GMPRunOnMainThread(GMPTask* aTask);
-GMPErr GMPCreateMutex(GMPMutex** aMutex);
-
-// Call on main thread only.
-GMPErr GMPCreateRecord(const char* aRecordName,
-                       uint32_t aRecordNameSize,
-                       GMPRecord** aOutRecord,
-                       GMPRecordClient* aClient);
-
-// Call on main thread only.
-GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS);
-
-GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime);
-
 } // namespace mozilla
 
-#endif // WidevineAdapter_h_
+#endif // ChromiumAdapter_h_
--- a/dom/media/gmp/ChromiumCDMChild.cpp
+++ b/dom/media/gmp/ChromiumCDMChild.cpp
@@ -9,16 +9,23 @@
 namespace mozilla {
 namespace gmp {
 
 ChromiumCDMChild::ChromiumCDMChild(GMPContentChild* aPlugin)
   : mPlugin(aPlugin)
 {
 }
 
+void
+ChromiumCDMChild::Init(cdm::ContentDecryptionModule_8* aCDM)
+{
+  mCDM = aCDM;
+  MOZ_ASSERT(mCDM);
+}
+
 mozilla::ipc::IPCResult
 ChromiumCDMChild::RecvInit(const bool& aAllowDistinctiveIdentifier,
                            const bool& aAllowPersistentState)
 {
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
--- a/dom/media/gmp/ChromiumCDMChild.h
+++ b/dom/media/gmp/ChromiumCDMChild.h
@@ -15,16 +15,17 @@ class GMPContentChild;
 
 class ChromiumCDMChild : public PChromiumCDMChild
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ChromiumCDMChild);
 
   explicit ChromiumCDMChild(GMPContentChild* aPlugin);
 
+  void Init(cdm::ContentDecryptionModule_8* aCDM);
 protected:
   ~ChromiumCDMChild() {}
 
   ipc::IPCResult RecvInit(const bool& aAllowDistinctiveIdentifier,
                           const bool& aAllowPersistentState) override;
   ipc::IPCResult RecvSetServerCertificate(
     const uint32_t& aPromiseId,
     nsTArray<uint8_t>&& aServerCert) override;
@@ -44,15 +45,16 @@ protected:
   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;
+  GMPContentChild* mPlugin = nullptr;
+  cdm::ContentDecryptionModule_8* mCDM = nullptr;
 };
 
 } // namespace gmp
 } // namespace mozilla
 
 #endif // ChromiumCDMChild_h_
--- a/dom/media/gmp/GMPChild.cpp
+++ b/dom/media/gmp/GMPChild.cpp
@@ -18,16 +18,17 @@
 #include "gmp-video-encode.h"
 #include "GMPPlatform.h"
 #include "mozilla/ipc/CrashReporterClient.h"
 #include "mozilla/ipc/ProcessChild.h"
 #include "GMPUtils.h"
 #include "prio.h"
 #include "base/task.h"
 #include "widevine-adapter/WidevineAdapter.h"
+#include "ChromiumCDMAdapter.h"
 
 using namespace mozilla::ipc;
 
 #ifdef XP_WIN
 #include <stdlib.h> // for _exit()
 #else
 #include <unistd.h> // for _exit()
 #endif
@@ -341,29 +342,36 @@ GMPChild::AnswerStartPlugin(const nsStri
   if (!mGMPLoader->CanSandbox()) {
     LOGD("%s Can't sandbox GMP, failing", __FUNCTION__);
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
 #endif
 
   bool isWidevine = aAdapter.EqualsLiteral("widevine");
+  bool isChromium = aAdapter.EqualsLiteral("chromium");
 #if defined(MOZ_GMP_SANDBOX) && defined(XP_MACOSX)
   MacSandboxPluginType pluginType = MacSandboxPluginType_GMPlugin_Default;
-  if (isWidevine) {
+  if (isWidevine || isChromium) {
     pluginType = MacSandboxPluginType_GMPlugin_EME_Widevine;
   }
   if (!SetMacSandboxInfo(pluginType)) {
     NS_WARNING("Failed to set Mac GMP sandbox info");
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
 #endif
 
-  GMPAdapter* adapter = (isWidevine) ? new WidevineAdapter() : nullptr;
+  GMPAdapter* adapter = nullptr;
+  if (isWidevine) {
+    adapter = new WidevineAdapter();
+  } else if (isChromium) {
+    adapter = new ChromiumCDMAdapter();
+  }
+
   if (!mGMPLoader->Load(libPath.get(),
                         libPath.Length(),
                         platformAPI,
                         adapter)) {
     NS_WARNING("Failed to load GMP");
     delete platformAPI;
     return IPC_FAIL_NO_REASON(this);
   }
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -158,17 +158,28 @@ GMPContentChild::RecvPGMPVideoEncoderCon
   vec->Init(static_cast<GMPVideoEncoder*>(ve));
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 GMPContentChild::RecvPChromiumCDMConstructor(PChromiumCDMChild* aActor)
 {
-  // TODO: Implement.
+  ChromiumCDMChild* child = static_cast<ChromiumCDMChild*>(aActor);
+  cdm::Host_8* host = child;
+
+  void* cdm = nullptr;
+  GMPErr err = mGMPChild->GetAPI(CHROMIUM_CDM_API, host, &cdm);
+  if (err != GMPNoErr || !cdm) {
+    NS_WARNING("GMPGetAPI call failed trying to get CDM.");
+    return IPC_FAIL_NO_REASON(this);
+  }
+
+  child->Init(static_cast<cdm::ContentDecryptionModule_8*>(cdm));
+
   return IPC_OK();
 }
 
 void
 GMPContentChild::CloseActive()
 {
   // Invalidate and remove any remaining API objects.
   const ManagedContainer<PGMPDecryptorChild>& decryptors =
--- a/dom/media/gmp/moz.build
+++ b/dom/media/gmp/moz.build
@@ -64,16 +64,17 @@ EXPORTS += [
     'GMPVideoEncoderProxy.h',
     'GMPVideoHost.h',
     'GMPVideoi420FrameImpl.h',
     'GMPVideoPlaneImpl.h',
     'widevine-adapter/content_decryption_module.h',
 ]
 
 UNIFIED_SOURCES += [
+    'ChromiumCDMAdapter.cpp',
     'ChromiumCDMChild.cpp',
     'ChromiumCDMParent.cpp',
     'DecryptJob.cpp',
     'GMPCDMCallbackProxy.cpp',
     'GMPCDMProxy.cpp',
     'GMPChild.cpp',
     'GMPContentChild.cpp',
     'GMPContentParent.cpp',
--- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp
@@ -10,17 +10,17 @@
 #include "WidevineDummyDecoder.h"
 #include "WidevineUtils.h"
 #include "WidevineVideoDecoder.h"
 #include "gmp-api/gmp-entrypoints.h"
 #include "gmp-api/gmp-decryption.h"
 #include "gmp-api/gmp-video-codec.h"
 #include "gmp-api/gmp-platform.h"
 
-static const GMPPlatformAPI* sPlatform = nullptr;
+const GMPPlatformAPI* sPlatform = nullptr;
 
 namespace mozilla {
 
 GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) {
   return sPlatform->getcurrenttime(aOutTime);
 }
 
 // Call on main thread only.