Bug 1176145 - Expose CDM version number in keySystem string. r=edwin,a=ritu
authorChris Pearce <cpearce@mozilla.com>
Mon, 31 Aug 2015 16:08:51 +1200
changeset 289144 28994d94c110726d42dac81e8ede6da16ad5365d
parent 289143 f9f0b25ca40d3c5d7f031808a49180ccc143b855
child 289145 441f51977790af03ac4555063c8d97e0600f8e08
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersedwin, ritu
bugs1176145
milestone42.0a2
Bug 1176145 - Expose CDM version number in keySystem string. r=edwin,a=ritu
dom/media/eme/EMEUtils.cpp
dom/media/eme/EMEUtils.h
dom/media/eme/MediaKeySession.cpp
dom/media/eme/MediaKeySession.h
dom/media/eme/MediaKeySystemAccess.cpp
dom/media/eme/MediaKeySystemAccess.h
dom/media/eme/MediaKeySystemAccessManager.cpp
dom/media/eme/MediaKeys.cpp
dom/media/eme/MediaKeys.h
dom/media/test/test_eme_requestKeySystemAccess.html
--- a/dom/media/eme/EMEUtils.cpp
+++ b/dom/media/eme/EMEUtils.cpp
@@ -119,9 +119,19 @@ LogToBrowserConsole(const nsAString& aMs
   if (!console) {
     NS_WARNING("Failed to log message to console.");
     return;
   }
   nsAutoString msg(aMsg);
   console->LogStringMessage(msg.get());
 }
 
+void
+ConstructKeySystem(const nsAString& aKeySystem,
+                   const nsAString& aCDMVersion,
+                   nsAString& aOutKeySystem)
+{
+  aOutKeySystem.Append(aKeySystem);
+  aOutKeySystem.AppendLiteral(".");
+  aOutKeySystem.Append(aCDMVersion);
+}
+
 } // namespace mozilla
--- a/dom/media/eme/EMEUtils.h
+++ b/dom/media/eme/EMEUtils.h
@@ -49,11 +49,16 @@ namespace mozilla {
 // if present. If it was not present, aOutMinCDMVersion is NO_CDM_VERSION.
 bool ParseKeySystem(const nsAString& aKeySystem,
                     nsAString& aOutKeySystem,
                     int32_t& aOutMinCDMVersion);
 
 void
 LogToBrowserConsole(const nsAString& aMsg);
 
+void
+ConstructKeySystem(const nsAString& aKeySystem,
+                   const nsAString& aCDMVersion,
+                   nsAString& aOutKeySystem);
+
 } // namespace mozilla
 
 #endif // EME_LOG_H_
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -38,21 +38,23 @@ NS_IMPL_RELEASE_INHERITED(MediaKeySessio
 // Count of number of instances. Used to give each instance a
 // unique token.
 static uint32_t sMediaKeySessionNum = 0;
 
 MediaKeySession::MediaKeySession(JSContext* aCx,
                                  nsPIDOMWindow* aParent,
                                  MediaKeys* aKeys,
                                  const nsAString& aKeySystem,
+                                 const nsAString& aCDMVersion,
                                  SessionType aSessionType,
                                  ErrorResult& aRv)
   : DOMEventTargetHelper(aParent)
   , mKeys(aKeys)
   , mKeySystem(aKeySystem)
+  , mCDMVersion(aCDMVersion)
   , mSessionType(aSessionType)
   , mToken(sMediaKeySessionNum++)
   , mIsClosed(false)
   , mUninitialized(true)
   , mKeyStatusMap(new MediaKeyStatusMap(aCx, aParent, aRv))
 {
   EME_LOG("MediaKeySession[%p,''] session Id set", this);
 
@@ -81,19 +83,19 @@ MediaKeySession::~MediaKeySession()
 
 MediaKeyError*
 MediaKeySession::GetError() const
 {
   return mMediaKeyError;
 }
 
 void
-MediaKeySession::GetKeySystem(nsString& aKeySystem) const
+MediaKeySession::GetKeySystem(nsString& aOutKeySystem) const
 {
-  aKeySystem = mKeySystem;
+  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
 }
 
 void
 MediaKeySession::GetSessionId(nsString& aSessionId) const
 {
   aSessionId = GetSessionId();
 }
 
--- a/dom/media/eme/MediaKeySession.h
+++ b/dom/media/eme/MediaKeySession.h
@@ -36,16 +36,17 @@ public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaKeySession,
                                            DOMEventTargetHelper)
 public:
   MediaKeySession(JSContext* aCx,
                   nsPIDOMWindow* aParent,
                   MediaKeys* aKeys,
                   const nsAString& aKeySystem,
+                  const nsAString& aCDMVersion,
                   SessionType aSessionType,
                   ErrorResult& aRv);
 
   void SetSessionId(const nsAString& aSessionId);
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   // Mark this as resultNotAddRefed to return raw pointers
@@ -101,16 +102,17 @@ private:
   already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv,
                                                 const nsACString& aName);
 
   nsRefPtr<DetailedPromise> mClosed;
 
   nsRefPtr<MediaKeyError> mMediaKeyError;
   nsRefPtr<MediaKeys> mKeys;
   const nsString mKeySystem;
+  const nsString mCDMVersion;
   nsString mSessionId;
   const SessionType mSessionType;
   const uint32_t mToken;
   bool mIsClosed;
   bool mUninitialized;
   nsRefPtr<MediaKeyStatusMap> mKeyStatusMap;
 };
 
--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -36,19 +36,21 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Me
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccess)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccess)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeySystemAccess)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
 MediaKeySystemAccess::MediaKeySystemAccess(nsPIDOMWindow* aParent,
-                                           const nsAString& aKeySystem)
+                                           const nsAString& aKeySystem,
+                                           const nsAString& aCDMVersion)
   : mParent(aParent)
   , mKeySystem(aKeySystem)
+  , mCDMVersion(aCDMVersion)
 {
 }
 
 MediaKeySystemAccess::~MediaKeySystemAccess()
 {
 }
 
 JSObject*
@@ -59,25 +61,25 @@ MediaKeySystemAccess::WrapObject(JSConte
 
 nsPIDOMWindow*
 MediaKeySystemAccess::GetParentObject() const
 {
   return mParent;
 }
 
 void
-MediaKeySystemAccess::GetKeySystem(nsString& aRetVal) const
+MediaKeySystemAccess::GetKeySystem(nsString& aOutKeySystem) const
 {
-  aRetVal = mKeySystem;
+  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
 }
 
 already_AddRefed<Promise>
 MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv)
 {
-  nsRefPtr<MediaKeys> keys(new MediaKeys(mParent, mKeySystem));
+  nsRefPtr<MediaKeys> keys(new MediaKeys(mParent, mKeySystem, mCDMVersion));
   return keys->Init(aRv);
 }
 
 static bool
 HaveGMPFor(mozIGeckoMediaPluginService* aGMPService,
            const nsCString& aKeySystem,
            const nsCString& aAPI,
            const nsCString& aTag = EmptyCString())
@@ -143,30 +145,33 @@ AdobePluginVoucherExists(const nsACStrin
   return AdobePluginFileExists(aVersionStr, NS_LITERAL_STRING("eme-adobe.voucher"));
 }
 #endif
 
 static MediaKeySystemStatus
 EnsureMinCDMVersion(mozIGeckoMediaPluginService* aGMPService,
                     const nsAString& aKeySystem,
                     int32_t aMinCdmVersion,
-                    nsACString& aOutMessage)
+                    nsACString& aOutMessage,
+                    nsACString& aOutCdmVersion)
 {
   nsTArray<nsCString> tags;
   tags.AppendElement(NS_ConvertUTF16toUTF8(aKeySystem));
   bool hasPlugin;
   nsAutoCString versionStr;
   if (NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
                                                     &tags,
                                                     &hasPlugin,
                                                     versionStr))) {
     aOutMessage = NS_LITERAL_CSTRING("GetPluginVersionForAPI failed");
     return MediaKeySystemStatus::Error;
   }
 
+  aOutCdmVersion = versionStr;
+
   if (!hasPlugin) {
     aOutMessage = NS_LITERAL_CSTRING("CDM is not installed");
     return MediaKeySystemStatus::Cdm_not_installed;
   }
 
 #ifdef XP_WIN
   if (aKeySystem.EqualsLiteral("com.adobe.access") ||
       aKeySystem.EqualsLiteral("com.adobe.primetime")) {
@@ -202,32 +207,33 @@ EnsureMinCDMVersion(mozIGeckoMediaPlugin
 
   return MediaKeySystemStatus::Available;
 }
 
 /* static */
 MediaKeySystemStatus
 MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
                                          int32_t aMinCdmVersion,
-                                         nsACString& aOutMessage)
+                                         nsACString& aOutMessage,
+                                         nsACString& aOutCdmVersion)
 {
   MOZ_ASSERT(Preferences::GetBool("media.eme.enabled", false));
   nsCOMPtr<mozIGeckoMediaPluginService> mps =
     do_GetService("@mozilla.org/gecko-media-plugin-service;1");
   if (NS_WARN_IF(!mps)) {
     aOutMessage = NS_LITERAL_CSTRING("Failed to get GMP service");
     return MediaKeySystemStatus::Error;
   }
 
   if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
     if (!Preferences::GetBool("media.eme.clearkey.enabled", true)) {
       aOutMessage = NS_LITERAL_CSTRING("ClearKey was disabled");
       return MediaKeySystemStatus::Cdm_disabled;
     }
-    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage);
+    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
   }
 
 #ifdef XP_WIN
   if ((aKeySystem.EqualsLiteral("com.adobe.access") ||
        aKeySystem.EqualsLiteral("com.adobe.primetime"))) {
     // Win Vista and later only.
     if (!IsVistaOrLater()) {
       aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version not met for Adobe EME");
@@ -239,17 +245,17 @@ MediaKeySystemAccess::GetKeySystemStatus
     }
     if (!EMEVoucherFileExists()) {
       // The system doesn't have the codecs that Adobe EME relies
       // on installed, or doesn't have a voucher for the plugin-container.
       // Adobe EME isn't going to work, so don't advertise that it will.
       aOutMessage = NS_LITERAL_CSTRING("Plugin-container voucher not present");
       return MediaKeySystemStatus::Cdm_not_supported;
     }
-    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage);
+    return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
   }
 #endif
 
   return MediaKeySystemStatus::Cdm_not_supported;
 }
 
 static bool
 IsPlayableWithGMP(mozIGeckoMediaPluginService* aGMPS,
--- a/dom/media/eme/MediaKeySystemAccess.h
+++ b/dom/media/eme/MediaKeySystemAccess.h
@@ -25,17 +25,18 @@ class MediaKeySystemAccess final : publi
                                    public nsWrapperCache
 {
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeySystemAccess)
 
 public:
   explicit MediaKeySystemAccess(nsPIDOMWindow* aParent,
-                                const nsAString& aKeySystem);
+                                const nsAString& aKeySystem,
+                                const nsAString& aCDMVersion);
 
 protected:
   ~MediaKeySystemAccess();
 
 public:
   nsPIDOMWindow* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
@@ -43,26 +44,28 @@ public:
   void GetKeySystem(nsString& aRetVal) const;
 
   already_AddRefed<Promise> CreateMediaKeys(ErrorResult& aRv);
 
 
 
   static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem,
                                                  int32_t aMinCdmVersion,
-                                                 nsACString& aOutExceptionMessage);
+                                                 nsACString& aOutExceptionMessage,
+                                                 nsACString& aOutCdmVersion);
 
   static bool IsSupported(const nsAString& aKeySystem,
                           const Sequence<MediaKeySystemOptions>& aOptions);
 
   static void NotifyObservers(nsIDOMWindow* aWindow,
                               const nsAString& aKeySystem,
                               MediaKeySystemStatus aStatus);
 
 private:
   nsCOMPtr<nsPIDOMWindow> mParent;
   const nsString mKeySystem;
+  const nsString mCDMVersion;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_MediaKeySystemAccess_h
--- a/dom/media/eme/MediaKeySystemAccessManager.cpp
+++ b/dom/media/eme/MediaKeySystemAccessManager.cpp
@@ -102,24 +102,26 @@ MediaKeySystemAccessManager::Request(Det
     // to chrome to show a failure notice.
     MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, MediaKeySystemStatus::Cdm_not_supported);
     aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR,
                           NS_LITERAL_CSTRING("Key system string is invalid, or key system is unsupported"));
     return;
   }
 
   nsAutoCString message;
+  nsAutoCString cdmVersion;
   MediaKeySystemStatus status =
-    MediaKeySystemAccess::GetKeySystemStatus(keySystem, minCdmVersion, message);
+    MediaKeySystemAccess::GetKeySystemStatus(keySystem, minCdmVersion, message, cdmVersion);
 
   nsPrintfCString msg("MediaKeySystemAccess::GetKeySystemStatus(%s, minVer=%d) "
-                      "result=%s msg='%s'",
+                      "result=%s version='%s' msg='%s'",
                       NS_ConvertUTF16toUTF8(keySystem).get(),
                       minCdmVersion,
                       MediaKeySystemStatusValues::strings[(size_t)status].value,
+                      cdmVersion.get(),
                       message.get());
   LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg));
 
   if ((status == MediaKeySystemStatus::Cdm_not_installed ||
        status == MediaKeySystemStatus::Cdm_insufficient_version) &&
       keySystem.EqualsLiteral("com.adobe.primetime")) {
     // These are cases which could be resolved by downloading a new(er) CDM.
     // When we send the status to chrome, chrome's GMPProvider will attempt to
@@ -155,17 +157,18 @@ MediaKeySystemAccessManager::Request(Det
     }
     aPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR,
                           NS_LITERAL_CSTRING("GetKeySystemAccess failed"));
     return;
   }
 
   if (aOptions.IsEmpty() ||
       MediaKeySystemAccess::IsSupported(keySystem, aOptions)) {
-    nsRefPtr<MediaKeySystemAccess> access(new MediaKeySystemAccess(mWindow, keySystem));
+    nsRefPtr<MediaKeySystemAccess> access(
+      new MediaKeySystemAccess(mWindow, keySystem, NS_ConvertUTF8toUTF16(cdmVersion)));
 #ifdef XP_WIN
     if (IsVistaOrLater()) {
       // On Windows, ensure we have tried creating a GMPVideoDecoder for this
       // keySystem, and that we can use it to decode. This ensures that we only
       // report that we support this keySystem when the CDM us usable (i.e.
       // all system libraries required are installed).
       mTrialCreator->MaybeAwaitTrialCreate(keySystem, access, aPromise, mWindow);
       return;
--- a/dom/media/eme/MediaKeys.cpp
+++ b/dom/media/eme/MediaKeys.cpp
@@ -42,19 +42,22 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Me
                                       mPendingSessions);
 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeys)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeys)
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeys)
   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   NS_INTERFACE_MAP_ENTRY(nsISupports)
 NS_INTERFACE_MAP_END
 
-MediaKeys::MediaKeys(nsPIDOMWindow* aParent, const nsAString& aKeySystem)
+MediaKeys::MediaKeys(nsPIDOMWindow* aParent,
+                     const nsAString& aKeySystem,
+                     const nsAString& aCDMVersion)
   : mParent(aParent)
   , mKeySystem(aKeySystem)
+  , mCDMVersion(aCDMVersion)
   , mCreatePromiseId(0)
 {
   EME_LOG("MediaKeys[%p] constructed keySystem=%s",
           this, NS_ConvertUTF16toUTF8(mKeySystem).get());
 }
 
 static PLDHashOperator
 RejectPromises(const uint32_t& aKey,
@@ -134,19 +137,19 @@ MediaKeys::GetParentObject() const
 
 JSObject*
 MediaKeys::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
 {
   return MediaKeysBinding::Wrap(aCx, this, aGivenProto);
 }
 
 void
-MediaKeys::GetKeySystem(nsString& retval) const
+MediaKeys::GetKeySystem(nsString& aOutKeySystem) const
 {
-  retval = mKeySystem;
+  ConstructKeySystem(mKeySystem, mCDMVersion, aOutKeySystem);
 }
 
 already_AddRefed<DetailedPromise>
 MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv)
 {
   nsRefPtr<DetailedPromise> promise(MakePromise(aRv,
     NS_LITERAL_CSTRING("MediaKeys.setServerCertificate")));
   if (aRv.Failed()) {
@@ -428,16 +431,17 @@ MediaKeys::CreateSession(JSContext* aCx,
   }
 
   EME_LOG("MediaKeys[%p] Creating session", this);
 
   nsRefPtr<MediaKeySession> session = new MediaKeySession(aCx,
                                                           GetParentObject(),
                                                           this,
                                                           mKeySystem,
+                                                          mCDMVersion,
                                                           aSessionType,
                                                           aRv);
 
   if (aRv.Failed()) {
     return nullptr;
   }
 
   // Add session to the set of sessions awaiting their sessionId being ready.
--- a/dom/media/eme/MediaKeys.h
+++ b/dom/media/eme/MediaKeys.h
@@ -47,17 +47,17 @@ class MediaKeys final : public nsISuppor
                         public nsWrapperCache
 {
   ~MediaKeys();
 
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys)
 
-  MediaKeys(nsPIDOMWindow* aParentWindow, const nsAString& aKeySystem);
+  MediaKeys(nsPIDOMWindow* aParentWindow, const nsAString& aKeySystem, const nsAString& aCDMVersion);
 
   already_AddRefed<DetailedPromise> Init(ErrorResult& aRv);
 
   nsPIDOMWindow* GetParentObject() const;
 
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   nsresult Bind(HTMLMediaElement* aElement);
@@ -132,17 +132,18 @@ private:
 
   // Owning ref to proxy. The proxy has a weak reference back to the MediaKeys,
   // and the MediaKeys destructor clears the proxy's reference to the MediaKeys.
   nsRefPtr<CDMProxy> mProxy;
 
   nsRefPtr<HTMLMediaElement> mElement;
 
   nsCOMPtr<nsPIDOMWindow> mParent;
-  nsString mKeySystem;
+  const nsString mKeySystem;
+  const nsString mCDMVersion;
   nsCString mNodeId;
   KeySessionHashMap mKeySessions;
   PromiseHashMap mPromises;
   PendingKeySessionsHashMap mPendingSessions;
   PromiseId mCreatePromiseId;
 
   nsRefPtr<nsIPrincipal> mPrincipal;
   nsRefPtr<nsIPrincipal> mTopLevelPrincipal;
--- a/dom/media/test/test_eme_requestKeySystemAccess.html
+++ b/dom/media/test/test_eme_requestKeySystemAccess.html
@@ -6,42 +6,44 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
   <script type="text/javascript" src="manifest.js"></script>
   <script type="text/javascript" src="eme.js"></script>
 </head>
 <body>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
+const CLEARKEY_ID = 'org.w3.clearkey';
+const CLEARKEY_VERSION = '1';
+
 function Test(test) {
   var name = "'" + test.name + "'";
   return new Promise(function(resolve, reject) {
     var p;
     if (test.options) {
       p = navigator.requestMediaKeySystemAccess(test.keySystem, test.options);
     } else {
       p = navigator.requestMediaKeySystemAccess(test.keySystem);
     }
     p.then(
       function(keySystemAccess) {
         ok(test.shouldPass, name + " passed and was expected to " + (test.shouldPass ? "pass" : "fail"));
+        is(keySystemAccess.keySystem, CLEARKEY_ID + "." + CLEARKEY_VERSION, "CDM version should be in MediaKeySystemAccess.keySystem");
         resolve();
       },
       function(ex) {
         if (test.shouldPass) {
           info(name + " failed: " + ex);
         }
         ok(!test.shouldPass, name + " failed and was expected to " + (test.shouldPass ? "pass" : "fail"));
         resolve();
       });
   });
 }
 
-const CLEARKEY_ID = 'org.w3.clearkey';
-
 var tests = [
   {
     name: 'Empty keySystem string',
     keySystem: '',
     options: [ ],
     shouldPass: false,
   },
   {