Bug 1271242 - Remove GMPDecryptorCallback::SetCapabilities(). r?jwwang draft
authorChris Pearce <cpearce@mozilla.com>
Tue, 10 May 2016 10:28:38 +1200
changeset 365062 68450d40febd29043470c6f4836482bd0b2f8fde
parent 364815 043082cb7bd8490c60815f67fbd1f33323ad7663
child 520441 56a7ff5714ec88211a97f87dbdbd910eae5e02de
push id17620
push usercpearce@mozilla.com
push dateMon, 09 May 2016 22:45:40 +0000
reviewersjwwang
bugs1271242
milestone49.0a1
Bug 1271242 - Remove GMPDecryptorCallback::SetCapabilities(). r?jwwang Now that GMPParent detects whether gmp-clearkey can decode using AAC/H.264 using WMF before reporting gmp-clearkey's GMPParent can decode AAC/H.264, we don't need the GMPDecryptorCallback::SetCapabilities() callback from the GMP to signal to the PDMFactory that the GMP can decode. We can now trust what the GMPService tells us. So we can remove the "waiting for CDM caps" step in the state machine's startup sequence. And all the plumbing. :) If we need more caps, like for an decode-and-render path, we can declare those as API strings in the info file. MozReview-Commit-ID: E0QhU4cYhjo
dom/media/MediaDecoder.cpp
dom/media/eme/CDMCallbackProxy.cpp
dom/media/eme/CDMCallbackProxy.h
dom/media/eme/CDMCaps.cpp
dom/media/eme/CDMCaps.h
dom/media/gmp/GMPDecryptorChild.cpp
dom/media/gmp/GMPDecryptorParent.cpp
dom/media/gmp/GMPDecryptorParent.h
dom/media/gmp/GMPDecryptorProxy.h
dom/media/gmp/PGMPDecryptor.ipdl
dom/media/gmp/gmp-api/gmp-decryption.h
dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
dom/media/gtest/TestGMPCrossOrigin.cpp
dom/media/platforms/PDMFactory.cpp
dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
dom/media/platforms/agnostic/eme/EMEDecoderModule.h
media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
media/gmp-clearkey/0.1/gmp-clearkey.cpp
--- a/dom/media/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -1652,29 +1652,17 @@ MediaDecoder::RequestCDMProxy() const
   return mCDMProxyPromise;
 }
 
 void
 MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  RefPtr<CDMProxy> proxy = aProxy;
-  {
-    CDMCaps::AutoLock caps(aProxy->Capabilites());
-    if (!caps.AreCapsKnown()) {
-      RefPtr<MediaDecoder> self = this;
-      nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () {
-        self->mCDMProxyPromiseHolder.ResolveIfExists(proxy, __func__);
-      });
-      caps.CallOnMainThreadWhenCapsAvailable(r);
-      return;
-    }
-  }
-  mCDMProxyPromiseHolder.ResolveIfExists(proxy, __func__);
+  mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__);
 }
 #endif
 
 #ifdef MOZ_RAW
 bool
 MediaDecoder::IsRawEnabled()
 {
   return Preferences::GetBool("media.raw.enabled");
--- a/dom/media/eme/CDMCallbackProxy.cpp
+++ b/dom/media/eme/CDMCallbackProxy.cpp
@@ -298,25 +298,16 @@ CDMCallbackProxy::KeyStatusChanged(const
     task = NewRunnableMethod<nsString>(mProxy,
                                        &CDMProxy::OnKeyStatusesChange,
                                        NS_ConvertUTF8toUTF16(aSessionId));
     NS_DispatchToMainThread(task);
   }
 }
 
 void
-CDMCallbackProxy::SetCaps(uint64_t aCaps)
-{
-  MOZ_ASSERT(mProxy->IsOnGMPThread());
-
-  CDMCaps::AutoLock caps(mProxy->Capabilites());
-  caps.SetCaps(aCaps);
-}
-
-void
 CDMCallbackProxy::Decrypted(uint32_t aId,
                             GMPErr aResult,
                             const nsTArray<uint8_t>& aDecryptedData)
 {
   MOZ_ASSERT(mProxy->IsOnGMPThread());
 
   mProxy->gmp_Decrypted(aId, aResult, aDecryptedData);
 }
--- a/dom/media/eme/CDMCallbackProxy.h
+++ b/dom/media/eme/CDMCallbackProxy.h
@@ -42,18 +42,16 @@ public:
                     nsresult aException,
                     uint32_t aSystemCode,
                     const nsCString& aMessage) override;
 
   void KeyStatusChanged(const nsCString& aSessionId,
                         const nsTArray<uint8_t>& aKeyId,
                         GMPMediaKeyStatus aStatus) override;
 
-  void SetCaps(uint64_t aCaps) override;
-
   void Decrypted(uint32_t aId,
                  GMPErr aResult,
                  const nsTArray<uint8_t>& aDecryptedData) override;
 
   void Terminated() override;
 
   ~CDMCallbackProxy() {}
 
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -8,17 +8,16 @@
 #include "mozilla/EMEUtils.h"
 #include "nsThreadUtils.h"
 #include "SamplesWaitingForKey.h"
 
 namespace mozilla {
 
 CDMCaps::CDMCaps()
   : mMonitor("CDMCaps")
-  , mCaps(0)
 {
 }
 
 CDMCaps::~CDMCaps()
 {
 }
 
 void
@@ -28,84 +27,27 @@ CDMCaps::Lock()
 }
 
 void
 CDMCaps::Unlock()
 {
   mMonitor.Unlock();
 }
 
-bool
-CDMCaps::HasCap(uint64_t aCap)
-{
-  mMonitor.AssertCurrentThreadOwns();
-  return (mCaps & aCap) == aCap;
-}
-
 CDMCaps::AutoLock::AutoLock(CDMCaps& aInstance)
   : mData(aInstance)
 {
   mData.Lock();
 }
 
 CDMCaps::AutoLock::~AutoLock()
 {
   mData.Unlock();
 }
 
-static void
-TestCap(uint64_t aFlag,
-        uint64_t aCaps,
-        const nsACString& aCapName,
-        nsACString& aCapStr)
-{
-  if (!(aFlag & aCaps)) {
-    return;
-  }
-  if (!aCapStr.IsEmpty()) {
-    aCapStr.AppendLiteral(",");
-  }
-  aCapStr.Append(aCapName);
-}
-
-nsCString
-CapsToString(uint64_t aCaps)
-{
-  nsCString capsStr;
-  TestCap(GMP_EME_CAP_DECRYPT_AUDIO, aCaps, NS_LITERAL_CSTRING("DecryptAudio"), capsStr);
-  TestCap(GMP_EME_CAP_DECRYPT_VIDEO, aCaps, NS_LITERAL_CSTRING("DecryptVideo"), capsStr);
-  TestCap(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO, aCaps, NS_LITERAL_CSTRING("DecryptAndDecodeAudio"), capsStr);
-  TestCap(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO, aCaps, NS_LITERAL_CSTRING("DecryptAndDecodeVideo"), capsStr);
-  return capsStr;
-}
-
-void
-CDMCaps::AutoLock::SetCaps(uint64_t aCaps)
-{
-  EME_LOG("SetCaps() %s", CapsToString(aCaps).get());
-  mData.mMonitor.AssertCurrentThreadOwns();
-  mData.mCaps = aCaps;
-  for (size_t i = 0; i < mData.mWaitForCaps.Length(); i++) {
-    NS_DispatchToMainThread(mData.mWaitForCaps[i], NS_DISPATCH_NORMAL);
-  }
-  mData.mWaitForCaps.Clear();
-}
-
-void
-CDMCaps::AutoLock::CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation)
-{
-  mData.mMonitor.AssertCurrentThreadOwns();
-  if (mData.mCaps) {
-    NS_DispatchToMainThread(aContinuation, NS_DISPATCH_NORMAL);
-    MOZ_ASSERT(mData.mWaitForCaps.IsEmpty());
-  } else {
-    mData.mWaitForCaps.AppendElement(aContinuation);
-  }
-}
-
 bool
 CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
   const auto& keys = mData.mKeyStatuses;
   for (size_t i = 0; i < keys.Length(); i++) {
     if (keys[i].mId != aKeyId) {
       continue;
@@ -172,59 +114,16 @@ CDMCaps::AutoLock::NotifyWhenKeyIdUsable
                                          SamplesWaitingForKey* aListener)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(!IsKeyUsable(aKey));
   MOZ_ASSERT(aListener);
   mData.mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener));
 }
 
-bool
-CDMCaps::AutoLock::AreCapsKnown()
-{
-  mData.mMonitor.AssertCurrentThreadOwns();
-  return mData.mCaps != 0;
-}
-
-bool
-CDMCaps::AutoLock::CanRenderAudio()
-{
-  return mData.HasCap(GMP_EME_CAP_RENDER_AUDIO);
-}
-
-bool
-CDMCaps::AutoLock::CanRenderVideo()
-{
-  return mData.HasCap(GMP_EME_CAP_RENDER_VIDEO);
-}
-
-bool
-CDMCaps::AutoLock::CanDecryptAndDecodeAudio()
-{
-  return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO);
-}
-
-bool
-CDMCaps::AutoLock::CanDecryptAndDecodeVideo()
-{
-  return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
-}
-
-bool
-CDMCaps::AutoLock::CanDecryptAudio()
-{
-  return mData.HasCap(GMP_EME_CAP_DECRYPT_AUDIO);
-}
-
-bool
-CDMCaps::AutoLock::CanDecryptVideo()
-{
-  return mData.HasCap(GMP_EME_CAP_DECRYPT_VIDEO);
-}
-
 void
 CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId,
                                             nsTArray<KeyStatus>& aOutKeyStatuses)
 {
   for (size_t i = 0; i < mData.mKeyStatuses.Length(); i++) {
     const auto& key = mData.mKeyStatuses[i];
     if (key.mSessionId.Equals(aSessionId)) {
       aOutKeyStatuses.AppendElement(key);
--- a/dom/media/eme/CDMCaps.h
+++ b/dom/media/eme/CDMCaps.h
@@ -13,18 +13,18 @@
 #include "nsIThread.h"
 #include "nsTArray.h"
 #include "mozilla/Attributes.h"
 #include "SamplesWaitingForKey.h"
 #include "gmp-decryption.h"
 
 namespace mozilla {
 
-// CDM capabilities; what keys a CDMProxy can use, and whether it can decrypt, or
-// decrypt-and-decode on a per stream basis. Must be locked to access state.
+// CDM capabilities; what keys a CDMProxy can use.
+// Must be locked to access state.
 class CDMCaps {
 public:
   CDMCaps();
   ~CDMCaps();
 
   struct KeyStatus {
     KeyStatus(const CencKeyId& aId,
               const nsString& aSessionId,
@@ -50,63 +50,43 @@ public:
 
   // Locks the CDMCaps. It must be locked to access its shared state.
   // Threadsafe when locked.
   class MOZ_STACK_CLASS AutoLock {
   public:
     explicit AutoLock(CDMCaps& aKeyCaps);
     ~AutoLock();
 
-    // Returns true if the capabilities of the CDM are known, i.e. they have
-    // been reported by the CDM to Gecko.
-    bool AreCapsKnown();
-
     bool IsKeyUsable(const CencKeyId& aKeyId);
 
     // Returns true if key status changed,
     // i.e. the key status changed from usable to expired.
     bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
 
     void GetKeyStatusesForSession(const nsAString& aSessionId,
                                   nsTArray<KeyStatus>& aOutKeyStatuses);
 
     void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
                                nsTArray<nsCString>& aOutSessionIds);
 
     // Ensures all keys for a session are marked as 'unknown', i.e. removed.
     // Returns true if a key status was changed.
     bool RemoveKeysForSession(const nsString& aSessionId);
 
-    // Sets the capabilities of the CDM. aCaps is the logical OR of the
-    // GMP_EME_CAP_* flags from gmp-decryption.h.
-    void SetCaps(uint64_t aCaps);
-
-    bool CanRenderAudio();
-    bool CanRenderVideo();
-
-    bool CanDecryptAndDecodeAudio();
-    bool CanDecryptAndDecodeVideo();
-
-    bool CanDecryptAudio();
-    bool CanDecryptVideo();
-
-    void CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation);
-
     // Notifies the SamplesWaitingForKey when key become usable.
     void NotifyWhenKeyIdUsable(const CencKeyId& aKey,
                                SamplesWaitingForKey* aSamplesWaiting);
   private:
     // Not taking a strong ref, since this should be allocated on the stack.
     CDMCaps& mData;
   };
 
 private:
   void Lock();
   void Unlock();
-  bool HasCap(uint64_t);
 
   struct WaitForKeys {
     WaitForKeys(const CencKeyId& aKeyId,
                 SamplesWaitingForKey* aListener)
       : mKeyId(aKeyId)
       , mListener(aListener)
     {}
     CencKeyId mKeyId;
@@ -114,19 +94,16 @@ private:
   };
 
   Monitor mMonitor;
 
   nsTArray<KeyStatus> mKeyStatuses;
 
   nsTArray<WaitForKeys> mWaitForKeys;
 
-  nsTArray<nsCOMPtr<nsIRunnable>> mWaitForCaps;
-  uint64_t mCaps;
-
   // It is not safe to copy this object.
   CDMCaps(const CDMCaps&) = delete;
   CDMCaps& operator=(const CDMCaps&) = delete;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/media/gmp/GMPDecryptorChild.cpp
+++ b/dom/media/gmp/GMPDecryptorChild.cpp
@@ -188,17 +188,17 @@ GMPDecryptorChild::Decrypted(GMPBuffer* 
     SendDecrypted(buffer->mId, aResult, buffer->mData);
   }
   delete buffer;
 }
 
 void
 GMPDecryptorChild::SetCapabilities(uint64_t aCaps)
 {
-  CALL_ON_GMP_THREAD(SendSetCaps, aCaps);
+  // Deprecated.
 }
 
 void
 GMPDecryptorChild::GetSandboxVoucher(const uint8_t** aVoucher,
                                      uint32_t* aVoucherLength)
 {
   if (!aVoucher || !aVoucherLength) {
     return;
--- a/dom/media/gmp/GMPDecryptorParent.cpp
+++ b/dom/media/gmp/GMPDecryptorParent.cpp
@@ -339,29 +339,16 @@ GMPDecryptorParent::RecvKeyStatusChanged
 
   if (mIsOpen) {
     mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
   }
   return true;
 }
 
 bool
-GMPDecryptorParent::RecvSetCaps(const uint64_t& aCaps)
-{
-  LOGD(("GMPDecryptorParent[%p]::RecvSetCaps(caps=0x%llx)", this, aCaps));
-
-  if (!mIsOpen) {
-    NS_WARNING("Trying to use a dead GMP decrypter!");
-    return false;
-  }
-  mCallback->SetCaps(aCaps);
-  return true;
-}
-
-bool
 GMPDecryptorParent::RecvDecrypted(const uint32_t& aId,
                                   const GMPErr& aErr,
                                   InfallibleTArray<uint8_t>&& aBuffer)
 {
   LOGV(("GMPDecryptorParent[%p]::RecvDecrypted(id=%d, err=%d)",
         this, aId, aErr));
 
   if (!mIsOpen) {
--- a/dom/media/gmp/GMPDecryptorParent.h
+++ b/dom/media/gmp/GMPDecryptorParent.h
@@ -97,18 +97,16 @@ private:
   bool RecvKeyStatusChanged(const nsCString& aSessionId,
                             InfallibleTArray<uint8_t>&& aKeyId,
                             const GMPMediaKeyStatus& aStatus) override;
 
   bool RecvDecrypted(const uint32_t& aId,
                      const GMPErr& aErr,
                      InfallibleTArray<uint8_t>&& aBuffer) override;
 
-  bool RecvSetCaps(const uint64_t& aCaps) override;
-
   bool RecvShutdown() override;
 
   void ActorDestroy(ActorDestroyReason aWhy) override;
   bool Recv__delete__() override;
 
   bool mIsOpen;
   bool mShuttingDown;
   bool mActorDestroyed;
--- a/dom/media/gmp/GMPDecryptorProxy.h
+++ b/dom/media/gmp/GMPDecryptorProxy.h
@@ -43,18 +43,16 @@ public:
                             nsresult aException,
                             uint32_t aSystemCode,
                             const nsCString& aMessage) = 0;
 
   virtual void KeyStatusChanged(const nsCString& aSessionId,
                                 const nsTArray<uint8_t>& aKeyId,
                                 GMPMediaKeyStatus aStatus) = 0;
 
-  virtual void SetCaps(uint64_t aCaps) = 0;
-
   virtual void Decrypted(uint32_t aId,
                          GMPErr aResult,
                          const nsTArray<uint8_t>& aDecryptedData) = 0;
 };
 
 class GMPDecryptorProxy {
 public:
   ~GMPDecryptorProxy() {}
--- a/dom/media/gmp/PGMPDecryptor.ipdl
+++ b/dom/media/gmp/PGMPDecryptor.ipdl
@@ -76,17 +76,15 @@ parent:
   async SessionError(nsCString aSessionId,
                      GMPDOMException aDOMExceptionCode,
                      uint32_t aSystemCode,
                      nsCString aMessage);
 
   async KeyStatusChanged(nsCString aSessionId, uint8_t[] aKey,
                          GMPMediaKeyStatus aStatus);
 
-  async SetCaps(uint64_t aCaps);
-
   async Decrypted(uint32_t aId, GMPErr aResult, uint8_t[] aBuffer);
 
   async Shutdown();
 };
 
 } // namespace gmp
 } // namespace mozilla
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -100,42 +100,16 @@ enum GMPMediaKeyStatus {
   kGMPReleased = 6,
   kGMPStatusPending = 7,
   kGMPMediaKeyStatusInvalid = 8 // Must always be last.
 };
 
 // Time in milliseconds, as offset from epoch, 1 Jan 1970.
 typedef int64_t GMPTimestamp;
 
-// Capability definitions. The capabilities of the EME GMP are reported
-// to Gecko by calling the GMPDecryptorCallback::SetCapabilities()
-// callback and specifying the logical OR of the GMP_EME_CAP_* flags below.
-//
-// Note the DECRYPT and the DECRYPT_AND_DECODE are mutually exclusive;
-// only one mode should be reported for each stream type, but different
-// modes can be reported for different stream types.
-//
-// Note: Gecko does not currently support the caps changing at runtime.
-// Set them once per plugin initialization, during the startup of
-// the GMPDecryptor.
-
-// Capability; CDM can decrypt encrypted buffers and return still
-// compressed buffers back to Gecko for decompression there.
-#define GMP_EME_CAP_DECRYPT_AUDIO (uint64_t(1) << 0)
-#define GMP_EME_CAP_DECRYPT_VIDEO (uint64_t(1) << 1)
-
-// Capability; CDM can decrypt and then decode encrypted buffers,
-// and return decompressed samples to Gecko for playback.
-#define GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO (uint64_t(1) << 2)
-#define GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO (uint64_t(1) << 3)
-
-// Capability; CDM can decrypt and then decode and render encrypted buffers
-#define GMP_EME_CAP_RENDER_AUDIO (uint64_t(1) << 4)
-#define GMP_EME_CAP_RENDER_VIDEO (uint64_t(1) << 5)
-
 // Callbacks to be called from the CDM. Threadsafe.
 class GMPDecryptorCallback {
 public:
 
   // The GMPDecryptor should call this in response to a call to
   // GMPDecryptor::CreateSession(). The GMP host calls CreateSession() when
   // MediaKeySession.generateRequest() is called by JavaScript.
   // After CreateSession() is called, the GMPDecryptor should call
@@ -207,22 +181,17 @@ public:
   // or decode content encrypted with a key unless the CDM has marked it
   // usable first. So a CDM *MUST* mark its usable keys as usable!
   virtual void KeyStatusChanged(const char* aSessionId,
                                 uint32_t aSessionIdLength,
                                 const uint8_t* aKeyId,
                                 uint32_t aKeyIdLength,
                                 GMPMediaKeyStatus aStatus) = 0;
 
-  // The CDM must report its capabilites of this CDM. aCaps should be a
-  // logical OR of the GMP_EME_CAP_* flags. The CDM *MUST* call this
-  // function and report whether it can decrypt and/or decode. Without
-  // this, Gecko does not know how to use the CDM and will not send
-  // samples to the CDM to decrypt or decrypt-and-decode mode. Note a
-  // CDM cannot change modes once playback has begun.
+  // DEPRECATED; this function has no affect.
   virtual void SetCapabilities(uint64_t aCaps) = 0;
 
   // Returns decrypted buffer to Gecko, or reports failure.
   virtual void Decrypted(GMPBuffer* aBuffer, GMPErr aResult) = 0;
 
   virtual ~GMPDecryptorCallback() {}
 };
 
@@ -253,23 +222,16 @@ enum GMPSessionType {
 //
 // API name macro: GMP_API_DECRYPTOR
 // Host API: GMPDecryptorHost
 class GMPDecryptor {
 public:
 
   // Sets the callback to use with the decryptor to return results
   // to Gecko.
-  //
-  // The CDM must also call GMPDecryptorCallback::SetCapabilities()
-  // exactly once during start up, to inform Gecko whether to use the CDM
-  // in decrypt or decrypt-and-decode mode.
-  //
-  // Note: GMPDecryptorCallback::SetCapabilities() must be called before
-  // Gecko will send any samples for decryption to the GMP.
   virtual void Init(GMPDecryptorCallback* aCallback) = 0;
 
   // Initiates the creation of a session given |aType| and |aInitData|, and
   // the generation of a license request message.
   //
   // This corresponds to a MediaKeySession.generateRequest() call in JS.
   //
   // The GMPDecryptor must do the following, in order, upon this method
--- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
+++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp
@@ -34,18 +34,16 @@ WidevineDecryptor::SetCDM(RefPtr<CDMWrap
   mCDM = aCDM;
 }
 
 void
 WidevineDecryptor::Init(GMPDecryptorCallback* aCallback)
 {
   MOZ_ASSERT(aCallback);
   mCallback = aCallback;
-  mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO |
-                             GMP_EME_CAP_DECRYPT_AUDIO);
 }
 
 static SessionType
 ToCDMSessionType(GMPSessionType aSessionType)
 {
   switch (aSessionType) {
     case kGMPTemporySession: return kTemporary;
     case kGMPPersistentSession: return kPersistentLicense;
--- a/dom/media/gtest/TestGMPCrossOrigin.cpp
+++ b/dom/media/gtest/TestGMPCrossOrigin.cpp
@@ -1344,17 +1344,16 @@ class GMPStorageTest : public GMPDecrypt
   void SessionClosed(const nsCString& aSessionId) override {}
   void SessionError(const nsCString& aSessionId,
                     nsresult aException,
                     uint32_t aSystemCode,
                     const nsCString& aMessage) override {}
   void KeyStatusChanged(const nsCString& aSessionId,
                         const nsTArray<uint8_t>& aKeyId,
                         GMPMediaKeyStatus aStatus) override { }
-  void SetCaps(uint64_t aCaps) override {}
   void Decrypted(uint32_t aId,
                  GMPErr aResult,
                  const nsTArray<uint8_t>& aDecryptedData) override { }
   void Terminated() override {
     if (mDecryptor) {
       mDecryptor->Close();
       mDecryptor = nullptr;
     }
--- a/dom/media/platforms/PDMFactory.cpp
+++ b/dom/media/platforms/PDMFactory.cpp
@@ -380,22 +380,14 @@ PDMFactory::GetDecoder(const nsACString&
   }
   return pdm.forget();
 }
 
 #ifdef MOZ_EME
 void
 PDMFactory::SetCDMProxy(CDMProxy* aProxy)
 {
-  bool cdmDecodesAudio;
-  bool cdmDecodesVideo;
-  {
-    CDMCaps::AutoLock caps(aProxy->Capabilites());
-    cdmDecodesAudio = caps.CanDecryptAndDecodeAudio();
-    cdmDecodesVideo = caps.CanDecryptAndDecodeVideo();
-  }
-
   RefPtr<PDMFactory> m = new PDMFactory();
-  mEMEPDM = new EMEDecoderModule(aProxy, m, cdmDecodesAudio, cdmDecodesVideo);
+  mEMEPDM = new EMEDecoderModule(aProxy, m);
 }
 #endif
 
 }  // namespace mozilla
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp
@@ -200,24 +200,19 @@ EMEMediaDataDecoderProxy::Shutdown()
 
   mSamplesWaitingForKey->BreakCycles();
   mSamplesWaitingForKey = nullptr;
   mProxy = nullptr;
 
   return rv;
 }
 
-EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy,
-                                   PDMFactory* aPDM,
-                                   bool aCDMDecodesAudio,
-                                   bool aCDMDecodesVideo)
+EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM)
   : mProxy(aProxy)
   , mPDM(aPDM)
-  , mCDMDecodesAudio(aCDMDecodesAudio)
-  , mCDMDecodesVideo(aCDMDecodesVideo)
 {
 }
 
 EMEDecoderModule::~EMEDecoderModule()
 {
 }
 
 static already_AddRefed<MediaDataDecoderProxy>
@@ -241,17 +236,18 @@ EMEDecoderModule::CreateVideoDecoder(con
                                      layers::LayersBackend aLayersBackend,
                                      layers::ImageContainer* aImageContainer,
                                      FlushableTaskQueue* aVideoTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   MOZ_ASSERT(aConfig.mCrypto.mValid);
 
-  if (mCDMDecodesVideo) {
+  if (SupportsMimeType(aConfig.mMimeType, nullptr)) {
+    // GMP decodes. Assume that means it can decrypt too.
     RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue);
     wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy,
                                                 aConfig,
                                                 aLayersBackend,
                                                 aImageContainer,
                                                 aVideoTaskQueue,
                                                 wrapper->Callback()));
     return wrapper.forget();
@@ -279,17 +275,18 @@ EMEDecoderModule::CreateVideoDecoder(con
 already_AddRefed<MediaDataDecoder>
 EMEDecoderModule::CreateAudioDecoder(const AudioInfo& aConfig,
                                      FlushableTaskQueue* aAudioTaskQueue,
                                      MediaDataDecoderCallback* aCallback,
                                      DecoderDoctorDiagnostics* aDiagnostics)
 {
   MOZ_ASSERT(aConfig.mCrypto.mValid);
 
-  if (mCDMDecodesAudio) {
+  if (SupportsMimeType(aConfig.mMimeType, nullptr)) {
+    // GMP decodes. Assume that means it can decrypt too.
     RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue);
     wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy,
                                                 aConfig,
                                                 aAudioTaskQueue,
                                                 wrapper->Callback()));
     return wrapper.forget();
   }
 
--- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
+++ b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h
@@ -14,20 +14,17 @@
 namespace mozilla {
 
 class CDMProxy;
 
 class EMEDecoderModule : public PlatformDecoderModule {
 private:
 
 public:
-  EMEDecoderModule(CDMProxy* aProxy,
-                   PDMFactory* aPDM,
-                   bool aCDMDecodesAudio,
-                   bool aCDMDecodesVideo);
+  EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM);
 
   virtual ~EMEDecoderModule();
 
 protected:
   // Decode thread.
   already_AddRefed<MediaDataDecoder>
   CreateVideoDecoder(const VideoInfo& aConfig,
                     layers::LayersBackend aLayersBackend,
@@ -51,15 +48,13 @@ protected:
                    DecoderDoctorDiagnostics* aDiagnostics) const override;
 
 private:
   RefPtr<CDMProxy> mProxy;
   // Will be null if CDM has decoding capability.
   RefPtr<PDMFactory> mPDM;
   // We run the PDM on its own task queue.
   RefPtr<TaskQueue> mTaskQueue;
-  bool mCDMDecodesAudio;
-  bool mCDMDecodesVideo;
 };
 
 } // namespace mozilla
 
 #endif // EMEDecoderModule_h_
--- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
+++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp
@@ -19,21 +19,16 @@
 #include <string.h>
 
 #include "ClearKeyDecryptionManager.h"
 #include "ClearKeySessionManager.h"
 #include "ClearKeyUtils.h"
 #include "ClearKeyStorage.h"
 #include "ClearKeyPersistence.h"
 #include "gmp-task-utils.h"
-#if defined(ENABLE_WMF)
-#include "WMFUtils.h"
-#include <versionhelpers.h>
-#endif
-
 #include <assert.h>
 
 using namespace std;
 
 ClearKeySessionManager::ClearKeySessionManager()
   : mDecryptionManager(ClearKeyDecryptionManager::Get())
 {
   CK_LOGD("ClearKeySessionManager ctor %p", this);
@@ -45,38 +40,21 @@ ClearKeySessionManager::ClearKeySessionM
   }
 }
 
 ClearKeySessionManager::~ClearKeySessionManager()
 {
   CK_LOGD("ClearKeySessionManager dtor %p", this);
 }
 
-static bool
-CanDecode()
-{
-  return
-#if defined(ENABLE_WMF)
-    wmf::EnsureLibs() ||
-#endif
-    false;
-}
-
 void
 ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback)
 {
   CK_LOGD("ClearKeySessionManager::Init");
   mCallback = aCallback;
-  if (!CanDecode()) {
-    mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AUDIO |
-                               GMP_EME_CAP_DECRYPT_VIDEO);
-  } else {
-    mCallback->SetCapabilities(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO |
-                               GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
-  }
   ClearKeyPersistence::EnsureInitialized();
 }
 
 void
 ClearKeySessionManager::CreateSession(uint32_t aCreateSessionToken,
                                       uint32_t aPromiseId,
                                       const char* aInitDataType,
                                       uint32_t aInitDataTypeSize,
--- a/media/gmp-clearkey/0.1/gmp-clearkey.cpp
+++ b/media/gmp-clearkey/0.1/gmp-clearkey.cpp
@@ -58,17 +58,17 @@ GMPGetAPI(const char* aApiName, void* aH
   CK_LOGD("ClearKey GMPGetAPI |%s|", aApiName);
   assert(!*aPluginAPI);
 
   if (!strcmp(aApiName, GMP_API_DECRYPTOR)) {
     *aPluginAPI = new ClearKeySessionManager();
   }
 #if defined(ENABLE_WMF)
   else if (!strcmp(aApiName, GMP_API_AUDIO_DECODER) &&
-      wmf::EnsureLibs()) {
+           wmf::EnsureLibs()) {
     *aPluginAPI = new AudioDecoder(static_cast<GMPAudioHost*>(aHostAPI));
   } else if (!strcmp(aApiName, GMP_API_VIDEO_DECODER) &&
              wmf::EnsureLibs()) {
     *aPluginAPI = new VideoDecoder(static_cast<GMPVideoHost*>(aHostAPI));
   }
 #endif
   else if (!strcmp(aApiName, GMP_API_ASYNC_SHUTDOWN)) {
     *aPluginAPI = new ClearKeyAsyncShutdown(static_cast<GMPAsyncShutdownHost*> (aHostAPI));