Bug 1293101 - Refactor CDMCaps.cpp to treat keys marked as output-restricted as usable in all cases. r?gerald draft
authorChris Pearce <cpearce@mozilla.com>
Mon, 08 Aug 2016 10:41:38 +1200
changeset 397689 1559c5f5e687784b5a57d921685db0e6ea820640
parent 397688 763fe887c37cee5fcfe0f00e94fdffc84a41ea1c
child 397702 4eb93f8799d381a9aa8dbba6db5862d0093df243
child 397704 596b66332f97932ebc7cd126f25cf88f60d509b6
push id25351
push usercpearce@mozilla.com
push dateSun, 07 Aug 2016 23:23:14 +0000
reviewersgerald
bugs1293101, 1289623
milestone51.0a1
Bug 1293101 - Refactor CDMCaps.cpp to treat keys marked as output-restricted as usable in all cases. r?gerald This is a follow up from bug 1289623, as I missed a few cases in that bug. MozReview-Commit-ID: DM7FtVSZUo3
dom/media/eme/CDMCaps.cpp
--- a/dom/media/eme/CDMCaps.cpp
+++ b/dom/media/eme/CDMCaps.cpp
@@ -38,66 +38,73 @@ CDMCaps::AutoLock::AutoLock(CDMCaps& aIn
   mData.Lock();
 }
 
 CDMCaps::AutoLock::~AutoLock()
 {
   mData.Unlock();
 }
 
+// Keys with kGMPUsable, kGMPOutputDownscaled, or kGMPOutputRestricted status
+// can be used by the CDM to decrypt or decrypt-and-decode samples.
+static bool
+IsUsableStatus(GMPMediaKeyStatus aStatus)
+{
+  return aStatus == kGMPUsable ||
+         aStatus == kGMPOutputRestricted ||
+         aStatus == kGMPOutputDownscaled;
+}
+
 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;
-    }
-    if (keys[i].mStatus == kGMPUsable ||
-        keys[i].mStatus == kGMPOutputRestricted ||
-        keys[i].mStatus == kGMPOutputDownscaled) {
-      return true;
+  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
+    if (keyStatus.mId == aKeyId) {
+      return IsUsableStatus(keyStatus.mStatus);
     }
   }
   return false;
 }
 
 bool
 CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
                                 const nsString& aSessionId,
                                 GMPMediaKeyStatus aStatus)
 {
   mData.mMonitor.AssertCurrentThreadOwns();
   KeyStatus key(aKeyId, aSessionId, aStatus);
-  auto index = mData.mKeyStatuses.IndexOf(key);
 
   if (aStatus == kGMPUnknown) {
     // Return true if the element is found to notify key changes.
     return mData.mKeyStatuses.RemoveElement(key);
   }
 
+  auto index = mData.mKeyStatuses.IndexOf(key);
   if (index != mData.mKeyStatuses.NoIndex) {
     if (mData.mKeyStatuses[index].mStatus == aStatus) {
+      // No change.
       return false;
     }
     auto oldStatus = mData.mKeyStatuses[index].mStatus;
     mData.mKeyStatuses[index].mStatus = aStatus;
-    if (oldStatus == kGMPUsable || oldStatus == kGMPOutputDownscaled) {
+    // 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);
   }
 
-  // Both kGMPUsable and kGMPOutputDownscaled are treated able to decrypt.
-  // We don't need to notify when transition happens between kGMPUsable and
-  // kGMPOutputDownscaled. Only call NotifyUsable() when we are going from
-  // ![kGMPUsable|kGMPOutputDownscaled] to [kGMPUsable|kGMPOutputDownscaled]
-  if (aStatus != kGMPUsable && aStatus != kGMPOutputDownscaled) {
+  // Only call NotifyUsable() for a key when we are going from non-usable
+  // to usable state.
+  if (!IsUsableStatus(aStatus)) {
     return true;
   }
 
   auto& waiters = mData.mWaitForKeys;
   size_t i = 0;
   while (i < waiters.Length()) {
     auto& w = waiters[i];
     if (w.mKeyId == aKeyId) {
@@ -119,40 +126,39 @@ CDMCaps::AutoLock::NotifyWhenKeyIdUsable
   MOZ_ASSERT(aListener);
   mData.mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener));
 }
 
 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);
+  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
+    if (keyStatus.mSessionId.Equals(aSessionId)) {
+      aOutKeyStatuses.AppendElement(keyStatus);
     }
   }
 }
 
 void
 CDMCaps::AutoLock::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
                                          nsTArray<nsCString>& aOutSessionIds)
 {
-  for (const auto& keyStatus : mData.mKeyStatuses) {
+  for (const KeyStatus& keyStatus : mData.mKeyStatuses) {
     if (keyStatus.mId == aKeyId) {
       aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
     }
   }
 }
 
 bool
 CDMCaps::AutoLock::RemoveKeysForSession(const nsString& aSessionId)
 {
   bool changed = false;
   nsTArray<KeyStatus> statuses;
   GetKeyStatusesForSession(aSessionId, statuses);
-  for (const KeyStatus& status : statuses) {
-    changed |= SetKeyStatus(status.mId, aSessionId, kGMPUnknown);
+  for (const KeyStatus& keyStatus : statuses) {
+    changed |= SetKeyStatus(keyStatus.mId, aSessionId, kGMPUnknown);
   }
   return changed;
 }
 
 } // namespace mozilla