Bug 1426291 - Use DataMutex<T> to synchronize CDMCaps. r=jwwang
authorChris Pearce <cpearce@mozilla.com>
Wed, 20 Dec 2017 16:16:50 +1300
changeset 448789 fb96226aef906b8faa4cde6749ccef3a6870e786
parent 448788 4ae5f2caa47120e4247d7d09f11fcc4f77357cd8
child 448790 98ca352b22c7332d6b6a609ae9783e85046bbced
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwwang
bugs1426291
milestone59.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 1426291 - Use DataMutex<T> to synchronize CDMCaps. r=jwwang MozReview-Commit-ID: NLnoItNZKP
dom/media/eme/CDMCaps.cpp
dom/media/eme/CDMCaps.h
dom/media/eme/CDMProxy.h
dom/media/eme/MediaKeySession.cpp
dom/media/eme/mediadrm/MediaDrmCDMCallbackProxy.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
dom/media/eme/mediadrm/MediaDrmCDMProxy.h
dom/media/gmp/ChromiumCDMCallbackProxy.cpp
dom/media/gmp/ChromiumCDMProxy.cpp
dom/media/gmp/ChromiumCDMProxy.h
dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -7,159 +7,130 @@
 #include "mozilla/CDMCaps.h"
 #include "mozilla/EMEUtils.h"
 #include "nsThreadUtils.h"
 #include "SamplesWaitingForKey.h"
 
 namespace mozilla {
 
 CDMCaps::CDMCaps()
-  : mMonitor("CDMCaps")
 {
 }
 
 CDMCaps::~CDMCaps()
 {
 }
 
-void
-CDMCaps::Lock()
-{
-  mMonitor.Lock();
-}
-
-void
-CDMCaps::Unlock()
-{
-  mMonitor.Unlock();
-}
-
-CDMCaps::AutoLock::AutoLock(CDMCaps& aInstance)
-  : mData(aInstance)
-{
-  mData.Lock();
-}
-
-CDMCaps::AutoLock::~AutoLock()
-{
-  mData.Unlock();
-}
-
 // Keys with MediaKeyStatus::Usable, MediaKeyStatus::Output_downscaled,
 // or MediaKeyStatus::Output_restricted status can be used by the CDM
 // to decrypt or decrypt-and-decode samples.
 static bool
 IsUsableStatus(dom::MediaKeyStatus aStatus)
 {
   return aStatus == dom::MediaKeyStatus::Usable ||
          aStatus == dom::MediaKeyStatus::Output_restricted ||
          aStatus == dom::MediaKeyStatus::Output_downscaled;
 }
 
 bool
-CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
+CDMCaps::IsKeyUsable(const CencKeyId& aKeyId)
 {
-  mData.mMonitor.AssertCurrentThreadOwns();
-  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
+  for (const KeyStatus& keyStatus : mKeyStatuses) {
     if (keyStatus.mId == aKeyId) {
       return IsUsableStatus(keyStatus.mStatus);
     }
   }
   return false;
 }
 
 bool
-CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
-                                const nsString& aSessionId,
-                                const dom::Optional<dom::MediaKeyStatus>& aStatus)
+CDMCaps::SetKeyStatus(const CencKeyId& aKeyId,
+                      const nsString& aSessionId,
+                      const dom::Optional<dom::MediaKeyStatus>& aStatus)
 {
-  mData.mMonitor.AssertCurrentThreadOwns();
-
   if (!aStatus.WasPassed()) {
     // Called from ForgetKeyStatus.
     // Return true if the element is found to notify key changes.
-    return mData.mKeyStatuses.RemoveElement(KeyStatus(aKeyId,
-                                                      aSessionId,
-                                                      dom::MediaKeyStatus::Internal_error));
+    return mKeyStatuses.RemoveElement(
+      KeyStatus(aKeyId, aSessionId, dom::MediaKeyStatus::Internal_error));
   }
 
   KeyStatus key(aKeyId, aSessionId, aStatus.Value());
-  auto index = mData.mKeyStatuses.IndexOf(key);
-  if (index != mData.mKeyStatuses.NoIndex) {
-    if (mData.mKeyStatuses[index].mStatus == aStatus.Value()) {
+  auto index = mKeyStatuses.IndexOf(key);
+  if (index != mKeyStatuses.NoIndex) {
+    if (mKeyStatuses[index].mStatus == aStatus.Value()) {
       // No change.
       return false;
     }
-    auto oldStatus = mData.mKeyStatuses[index].mStatus;
-    mData.mKeyStatuses[index].mStatus = aStatus.Value();
+    auto oldStatus = mKeyStatuses[index].mStatus;
+    mKeyStatuses[index].mStatus = aStatus.Value();
     // The old key status was one for which we can decrypt media. We don't
     // need to do the "notify usable" step below, as it should be impossible
     // for us to have anything waiting on this key to become usable, since it
     // was already usable.
     if (IsUsableStatus(oldStatus)) {
       return true;
     }
   } else {
-    mData.mKeyStatuses.AppendElement(key);
+    mKeyStatuses.AppendElement(key);
   }
 
   // Only call NotifyUsable() for a key when we are going from non-usable
   // to usable state.
   if (!IsUsableStatus(aStatus.Value())) {
     return true;
   }
 
-  auto& waiters = mData.mWaitForKeys;
+  auto& waiters = mWaitForKeys;
   size_t i = 0;
   while (i < waiters.Length()) {
     auto& w = waiters[i];
     if (w.mKeyId == aKeyId) {
       w.mListener->NotifyUsable(aKeyId);
       waiters.RemoveElementAt(i);
     } else {
       i++;
     }
   }
   return true;
 }
 
 void
-CDMCaps::AutoLock::NotifyWhenKeyIdUsable(const CencKeyId& aKey,
-                                         SamplesWaitingForKey* aListener)
+CDMCaps::NotifyWhenKeyIdUsable(const CencKeyId& aKey,
+                               SamplesWaitingForKey* aListener)
 {
-  mData.mMonitor.AssertCurrentThreadOwns();
   MOZ_ASSERT(!IsKeyUsable(aKey));
   MOZ_ASSERT(aListener);
-  mData.mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener));
+  mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener));
 }
 
 void
-CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId,
-                                            nsTArray<KeyStatus>& aOutKeyStatuses)
+CDMCaps::GetKeyStatusesForSession(const nsAString& aSessionId,
+                                  nsTArray<KeyStatus>& aOutKeyStatuses)
 {
-  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
+  for (const KeyStatus& keyStatus : mKeyStatuses) {
     if (keyStatus.mSessionId.Equals(aSessionId)) {
       aOutKeyStatuses.AppendElement(keyStatus);
     }
   }
 }
 
 void
-CDMCaps::AutoLock::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
-                                         nsTArray<nsCString>& aOutSessionIds)
+CDMCaps::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
+                               nsTArray<nsCString>& aOutSessionIds)
 {
-  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
+  for (const KeyStatus& keyStatus : mKeyStatuses) {
     if (keyStatus.mId == aKeyId) {
       aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
     }
   }
 }
 
 bool
-CDMCaps::AutoLock::RemoveKeysForSession(const nsString& aSessionId)
+CDMCaps::RemoveKeysForSession(const nsString& aSessionId)
 {
   bool changed = false;
   nsTArray<KeyStatus> statuses;
   GetKeyStatusesForSession(aSessionId, statuses);
   for (const KeyStatus& status : statuses) {
     changed |= SetKeyStatus(status.mId,
                             aSessionId,
                             dom::Optional<dom::MediaKeyStatus>());
--- a/dom/media/eme/CDMCaps.h
+++ b/dom/media/eme/CDMCaps.h
@@ -44,65 +44,50 @@ public:
              mSessionId == aOther.mSessionId;
     };
 
     CencKeyId mId;
     nsString mSessionId;
     dom::MediaKeyStatus mStatus;
   };
 
-  // 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();
+  bool IsKeyUsable(const CencKeyId& aKeyId);
 
-    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,
+                    const dom::Optional<dom::MediaKeyStatus>& aStatus);
 
-    // Returns true if key status changed,
-    // i.e. the key status changed from usable to expired.
-    bool SetKeyStatus(const CencKeyId& aKeyId,
-                      const nsString& aSessionId,
-                      const dom::Optional<dom::MediaKeyStatus>& aStatus);
+  void GetKeyStatusesForSession(const nsAString& aSessionId,
+                                nsTArray<KeyStatus>& aOutKeyStatuses);
 
-    void GetKeyStatusesForSession(const nsAString& aSessionId,
-                                  nsTArray<KeyStatus>& aOutKeyStatuses);
-
-    void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
-                               nsTArray<nsCString>& aOutSessionIds);
+  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);
+  // 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);
 
-    // 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;
-  };
+  // Notifies the SamplesWaitingForKey when key become usable.
+  void NotifyWhenKeyIdUsable(const CencKeyId& aKey,
+                             SamplesWaitingForKey* aSamplesWaiting);
 
 private:
-  void Lock();
-  void Unlock();
 
   struct WaitForKeys {
     WaitForKeys(const CencKeyId& aKeyId,
                 SamplesWaitingForKey* aListener)
       : mKeyId(aKeyId)
       , mListener(aListener)
     {}
     CencKeyId mKeyId;
     RefPtr<SamplesWaitingForKey> mListener;
   };
 
-  Monitor mMonitor;
-
   nsTArray<KeyStatus> mKeyStatuses;
 
   nsTArray<WaitForKeys> mWaitForKeys;
 
   // It is not safe to copy this object.
   CDMCaps(const CDMCaps&) = delete;
   CDMCaps& operator=(const CDMCaps&) = delete;
 };
--- a/dom/media/eme/CDMProxy.h
+++ b/dom/media/eme/CDMProxy.h
@@ -3,16 +3,17 @@
 /* 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 CDMProxy_h_
 #define CDMProxy_h_
 
 #include "mozilla/CDMCaps.h"
+#include "mozilla/DataMutex.h"
 #include "mozilla/MozPromise.h"
 
 #include "mozilla/dom/MediaKeyMessageEvent.h"
 #include "mozilla/dom/MediaKeys.h"
 
 #include "nsIThread.h"
 
 namespace mozilla {
@@ -87,16 +88,17 @@ public:
   // Main thread only.
   CDMProxy(dom::MediaKeys* aKeys,
            const nsAString& aKeySystem,
            bool aDistinctiveIdentifierRequired,
            bool aPersistentStateRequired,
            nsIEventTarget* aMainThread)
     : mKeys(aKeys)
     , mKeySystem(aKeySystem)
+    , mCapabilites("CDMProxy::mCDMCaps")
     , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired)
     , mPersistentStateRequired(aPersistentStateRequired)
     , mMainThread(aMainThread)
   {}
 
   // Main thread only.
   // Loads the CDM corresponding to mKeySystem.
   // Calls MediaKeys::OnCDMCreated() when the CDM is created.
@@ -212,17 +214,17 @@ public:
 
   // Resolves promise with "undefined".
   // Can be called from any thread.
   virtual void ResolvePromise(PromiseId aId) = 0;
 
   // Threadsafe.
   virtual const nsString& KeySystem() const = 0;
 
-  virtual  CDMCaps& Capabilites() = 0;
+  virtual DataMutex<CDMCaps>& Capabilites() = 0;
 
   // Main thread only.
   virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0;
 
   virtual void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                                      nsTArray<nsCString>& aSessionIds) = 0;
 
   // Main thread only.
@@ -278,17 +280,17 @@ protected:
   const nsString mKeySystem;
 
   // Onwer specified thread. e.g. Gecko Media Plugin thread.
   // All interactions with the out-of-process EME plugin must come from this thread.
   RefPtr<nsIThread> mOwnerThread;
 
   nsCString mNodeId;
 
-  CDMCaps mCapabilites;
+  DataMutex<CDMCaps> mCapabilites;
 
   const bool mDistinctiveIdentifierRequired;
   const bool mPersistentStateRequired;
 
   // The main thread associated with the root document.
   const nsCOMPtr<nsIEventTarget> mMainThread;
 };
 
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -134,18 +134,18 @@ MediaKeySession::UpdateKeyStatusMap()
 {
   MOZ_ASSERT(!IsClosed());
   if (!mKeys->GetCDMProxy()) {
     return;
   }
 
   nsTArray<CDMCaps::KeyStatus> keyStatuses;
   {
-    CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites());
-    caps.GetKeyStatusesForSession(mSessionId, keyStatuses);
+    auto caps = mKeys->GetCDMProxy()->Capabilites().Lock();
+    caps->GetKeyStatusesForSession(mSessionId, keyStatuses);
   }
 
   mKeyStatusMap->Update(keyStatuses);
 
   if (EME_LOG_ENABLED()) {
     nsAutoCString message(
       nsPrintfCString("MediaKeySession[%p,'%s'] key statuses change {",
                       this, NS_ConvertUTF16toUTF8(mSessionId).get()));
--- a/dom/media/eme/mediadrm/MediaDrmCDMCallbackProxy.cpp
+++ b/dom/media/eme/mediadrm/MediaDrmCDMCallbackProxy.cpp
@@ -75,18 +75,19 @@ MediaDrmCDMCallbackProxy::ExpirationChan
 }
 
 void
 MediaDrmCDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
 {
   MOZ_ASSERT(NS_IsMainThread());
   bool keyStatusesChange = false;
   {
-    CDMCaps::AutoLock caps(mProxy->Capabilites());
-    keyStatusesChange = caps.RemoveKeysForSession(NS_ConvertUTF8toUTF16(aSessionId));
+    auto caps = mProxy->Capabilites().Lock();
+    keyStatusesChange =
+      caps->RemoveKeysForSession(NS_ConvertUTF8toUTF16(aSessionId));
   }
   if (keyStatusesChange) {
     mProxy->OnKeyStatusesChange(NS_ConvertUTF8toUTF16(aSessionId));
   }
   mProxy->OnSessionClosed(NS_ConvertUTF8toUTF16(aSessionId));
 }
 
 void
@@ -111,22 +112,21 @@ MediaDrmCDMCallbackProxy::BatchedKeyStat
 }
 
 void
 MediaDrmCDMCallbackProxy::BatchedKeyStatusChangedInternal(const nsCString& aSessionId,
                                                           const nsTArray<CDMKeyInfo>& aKeyInfos)
 {
   bool keyStatusesChange = false;
   {
-    CDMCaps::AutoLock caps(mProxy->Capabilites());
+    auto caps = mProxy->Capabilites().Lock();
     for (size_t i = 0; i < aKeyInfos.Length(); i++) {
-      keyStatusesChange |=
-        caps.SetKeyStatus(aKeyInfos[i].mKeyId,
-                          NS_ConvertUTF8toUTF16(aSessionId),
-                          aKeyInfos[i].mStatus);
+      keyStatusesChange |= caps->SetKeyStatus(aKeyInfos[i].mKeyId,
+                                              NS_ConvertUTF8toUTF16(aSessionId),
+                                              aKeyInfos[i].mStatus);
     }
   }
   if (keyStatusesChange) {
     mProxy->OnKeyStatusesChange(NS_ConvertUTF8toUTF16(aSessionId));
   }
 }
 
 void
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.cpp
@@ -340,17 +340,17 @@ MediaDrmCDMProxy::ResolvePromise(Promise
 }
 
 const nsString&
 MediaDrmCDMProxy::KeySystem() const
 {
   return mKeySystem;
 }
 
-CDMCaps&
+DataMutex<CDMCaps>&
 MediaDrmCDMProxy::Capabilites()
 {
   return mCapabilites;
 }
 
 void
 MediaDrmCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
 {
@@ -363,18 +363,18 @@ MediaDrmCDMProxy::OnKeyStatusesChange(co
     session->DispatchKeyStatusesChange();
   }
 }
 
 void
 MediaDrmCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                                       nsTArray<nsCString>& aSessionIds)
 {
-  CDMCaps::AutoLock caps(Capabilites());
-  caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
+  auto caps = Capabilites().Lock();
+  caps->GetSessionIdsForKeyId(aKeyId, aSessionIds);
 }
 
 void
 MediaDrmCDMProxy::GetStatusForPolicy(PromiseId aPromiseId,
                                      const nsAString& aMinHdcpVersion)
 {
   // TODO: Implement GetStatusForPolicy.
   RejectPromise(aPromiseId, NS_ERROR_DOM_NOT_SUPPORTED_ERR,
--- a/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
+++ b/dom/media/eme/mediadrm/MediaDrmCDMProxy.h
@@ -103,17 +103,17 @@ public:
 
   // Resolves promise with "undefined".
   // Can be called from any thread.
   void ResolvePromise(PromiseId aId) override;
 
   // Threadsafe.
   const nsString& KeySystem() const override;
 
-  CDMCaps& Capabilites() override;
+  DataMutex<CDMCaps>& Capabilites() override;
 
   void OnKeyStatusesChange(const nsAString& aSessionId) override;
 
   void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                              nsTArray<nsCString>& aSessionIds) override;
 
   void GetStatusForPolicy(PromiseId aPromiseId,
                           const nsAString& aMinHdcpVersion) override;
--- a/dom/media/gmp/ChromiumCDMCallbackProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMCallbackProxy.cpp
@@ -127,23 +127,23 @@ ChromiumCDMCallbackProxy::ResolvePromise
 }
 
 void
 ChromiumCDMCallbackProxy::SessionKeysChange(const nsCString& aSessionId,
                                             nsTArray<mozilla::gmp::CDMKeyInformation> && aKeysInfo)
 {
   bool keyStatusesChange = false;
   {
-    CDMCaps::AutoLock caps(mProxy->Capabilites());
+    auto caps = mProxy->Capabilites().Lock();
     for (const auto& keyInfo : aKeysInfo) {
       keyStatusesChange |=
-        caps.SetKeyStatus(keyInfo.mKeyId(),
-                          NS_ConvertUTF8toUTF16(aSessionId),
-                          dom::Optional<dom::MediaKeyStatus>(
-                            ToDOMMediaKeyStatus(keyInfo.mStatus())));
+        caps->SetKeyStatus(keyInfo.mKeyId(),
+                           NS_ConvertUTF8toUTF16(aSessionId),
+                           dom::Optional<dom::MediaKeyStatus>(
+                             ToDOMMediaKeyStatus(keyInfo.mStatus())));
     }
   }
   if (keyStatusesChange) {
     DispatchToMainThread("ChromiumCDMProxy::OnKeyStatusesChange",
                          &ChromiumCDMProxy::OnKeyStatusesChange,
                          NS_ConvertUTF8toUTF16(aSessionId));
   }
 }
--- a/dom/media/gmp/ChromiumCDMProxy.cpp
+++ b/dom/media/gmp/ChromiumCDMProxy.cpp
@@ -523,18 +523,18 @@ ChromiumCDMProxy::OnExpirationChange(con
 
 void
 ChromiumCDMProxy::OnSessionClosed(const nsAString& aSessionId)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   bool keyStatusesChange = false;
   {
-    CDMCaps::AutoLock caps(Capabilites());
-    keyStatusesChange = caps.RemoveKeysForSession(nsString(aSessionId));
+    auto caps = Capabilites().Lock();
+    keyStatusesChange = caps->RemoveKeysForSession(nsString(aSessionId));
   }
   if (keyStatusesChange) {
     OnKeyStatusesChange(aSessionId);
   }
   if (mKeys.IsNull()) {
     return;
   }
   RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
@@ -577,17 +577,17 @@ ChromiumCDMProxy::OnRejectPromise(uint32
 }
 
 const nsString&
 ChromiumCDMProxy::KeySystem() const
 {
   return mKeySystem;
 }
 
-CDMCaps&
+DataMutex<CDMCaps>&
 ChromiumCDMProxy::Capabilites()
 {
   return mCapabilites;
 }
 
 RefPtr<DecryptPromise>
 ChromiumCDMProxy::Decrypt(MediaRawData* aSample)
 {
@@ -600,18 +600,18 @@ ChromiumCDMProxy::Decrypt(MediaRawData* 
   return InvokeAsync(
     mGMPThread, __func__, [cdm, sample]() { return cdm->Decrypt(sample); });
 }
 
 void
 ChromiumCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                                         nsTArray<nsCString>& aSessionIds)
 {
-  CDMCaps::AutoLock caps(Capabilites());
-  caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
+  auto caps = Capabilites().Lock();
+  caps->GetSessionIdsForKeyId(aKeyId, aSessionIds);
 }
 
 void
 ChromiumCDMProxy::GetStatusForPolicy(PromiseId aPromiseId,
                                      const nsAString& aMinHdcpVersion)
 {
   MOZ_ASSERT(NS_IsMainThread());
   EME_LOG("ChromiumCDMProxy::GetStatusForPolicy(pid=%u) minHdcpVersion=%s",
--- a/dom/media/gmp/ChromiumCDMProxy.h
+++ b/dom/media/gmp/ChromiumCDMProxy.h
@@ -93,17 +93,17 @@ public:
   void RejectPromise(PromiseId aId,
                      nsresult aExceptionCode,
                      const nsCString& aReason) override;
 
   void ResolvePromise(PromiseId aId) override;
 
   const nsString& KeySystem() const override;
 
-  CDMCaps& Capabilites() override;
+  DataMutex<CDMCaps>& Capabilites() override;
 
   void OnKeyStatusesChange(const nsAString& aSessionId) override;
 
   void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
                              nsTArray<nsCString>& aSessionIds) override;
 
   void GetStatusForPolicy(PromiseId aPromiseId,
                           const nsAString& aMinHdcpVersion) override;
--- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
+++ b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp
@@ -29,32 +29,32 @@ SamplesWaitingForKey::~SamplesWaitingFor
 }
 
 RefPtr<SamplesWaitingForKey::WaitForKeyPromise>
 SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample)
 {
   if (!aSample || !aSample->mCrypto.mValid || !mProxy) {
     return WaitForKeyPromise::CreateAndResolve(aSample, __func__);
   }
-  CDMCaps::AutoLock caps(mProxy->Capabilites());
+  auto caps = mProxy->Capabilites().Lock();
   const auto& keyid = aSample->mCrypto.mKeyId;
-  if (caps.IsKeyUsable(keyid)) {
+  if (caps->IsKeyUsable(keyid)) {
     return WaitForKeyPromise::CreateAndResolve(aSample, __func__);
   }
   SampleEntry entry;
   entry.mSample = aSample;
   RefPtr<WaitForKeyPromise> p = entry.mPromise.Ensure(__func__);
   {
     MutexAutoLock lock(mMutex);
     mSamples.AppendElement(Move(entry));
   }
   if (mOnWaitingForKeyEvent) {
     mOnWaitingForKeyEvent->Notify(mType);
   }
-  caps.NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this);
+  caps->NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this);
   return p;
 }
 
 void
 SamplesWaitingForKey::NotifyUsable(const CencKeyId& aKeyId)
 {
   MutexAutoLock lock(mMutex);
   size_t i = 0;