CDMCaps.cpp (3667B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/CDMCaps.h" 8 9 #include "SamplesWaitingForKey.h" 10 #include "mozilla/EMEUtils.h" 11 #include "nsThreadUtils.h" 12 13 namespace mozilla { 14 15 CDMCaps::CDMCaps() = default; 16 17 CDMCaps::~CDMCaps() = default; 18 19 // Keys with MediaKeyStatus::Usable, MediaKeyStatus::Output_downscaled, 20 // or MediaKeyStatus::Output_restricted status can be used by the CDM 21 // to decrypt or decrypt-and-decode samples. 22 static bool IsUsableStatus(dom::MediaKeyStatus aStatus) { 23 return aStatus == dom::MediaKeyStatus::Usable || 24 aStatus == dom::MediaKeyStatus::Output_restricted || 25 aStatus == dom::MediaKeyStatus::Output_downscaled; 26 } 27 28 bool CDMCaps::IsKeyUsable(const CencKeyId& aKeyId) { 29 for (const KeyStatus& keyStatus : mKeyStatuses) { 30 if (keyStatus.mId == aKeyId) { 31 return IsUsableStatus(keyStatus.mStatus); 32 } 33 } 34 return false; 35 } 36 37 bool CDMCaps::SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, 38 const dom::Optional<dom::MediaKeyStatus>& aStatus) { 39 if (!aStatus.WasPassed()) { 40 // Called from ForgetKeyStatus. 41 // Return true if the element is found to notify key changes. 42 return mKeyStatuses.RemoveElement( 43 KeyStatus(aKeyId, aSessionId, dom::MediaKeyStatus::Internal_error)); 44 } 45 46 KeyStatus key(aKeyId, aSessionId, aStatus.Value()); 47 auto index = mKeyStatuses.IndexOf(key); 48 if (index != mKeyStatuses.NoIndex) { 49 if (mKeyStatuses[index].mStatus == aStatus.Value()) { 50 // No change. 51 return false; 52 } 53 auto oldStatus = mKeyStatuses[index].mStatus; 54 mKeyStatuses[index].mStatus = aStatus.Value(); 55 // The old key status was one for which we can decrypt media. We don't 56 // need to do the "notify usable" step below, as it should be impossible 57 // for us to have anything waiting on this key to become usable, since it 58 // was already usable. 59 if (IsUsableStatus(oldStatus)) { 60 return true; 61 } 62 } else { 63 mKeyStatuses.AppendElement(key); 64 } 65 66 // Only call NotifyUsable() for a key when we are going from non-usable 67 // to usable state. 68 if (!IsUsableStatus(aStatus.Value())) { 69 return true; 70 } 71 72 auto& waiters = mWaitForKeys; 73 size_t i = 0; 74 while (i < waiters.Length()) { 75 auto& w = waiters[i]; 76 if (w.mKeyId == aKeyId) { 77 w.mListener->NotifyUsable(aKeyId); 78 waiters.RemoveElementAt(i); 79 } else { 80 i++; 81 } 82 } 83 return true; 84 } 85 86 void CDMCaps::NotifyWhenKeyIdUsable(const CencKeyId& aKey, 87 SamplesWaitingForKey* aListener) { 88 MOZ_ASSERT(!IsKeyUsable(aKey)); 89 MOZ_ASSERT(aListener); 90 mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener)); 91 } 92 93 void CDMCaps::GetKeyStatusesForSession(const nsAString& aSessionId, 94 nsTArray<KeyStatus>& aOutKeyStatuses) { 95 for (const KeyStatus& keyStatus : mKeyStatuses) { 96 if (keyStatus.mSessionId.Equals(aSessionId)) { 97 aOutKeyStatuses.AppendElement(keyStatus); 98 } 99 } 100 } 101 102 bool CDMCaps::RemoveKeysForSession(const nsString& aSessionId) { 103 bool changed = false; 104 nsTArray<KeyStatus> statuses; 105 GetKeyStatusesForSession(aSessionId, statuses); 106 for (const KeyStatus& status : statuses) { 107 changed |= SetKeyStatus(status.mId, aSessionId, 108 dom::Optional<dom::MediaKeyStatus>()); 109 } 110 return changed; 111 } 112 113 } // namespace mozilla