diff options
author | Matt A. Tobin <email@mattatobin.com> | 2022-04-20 23:52:59 -0500 |
---|---|---|
committer | Matt A. Tobin <email@mattatobin.com> | 2022-04-20 23:52:59 -0500 |
commit | df1c87d8a7cb7ad0efaec527dc370e63b654b6db (patch) | |
tree | a91ebd62241986b7cc9e81636d75ebca05bda361 /dom | |
parent | 3ee1b0b8047610f07d4de262871d1f2ea8effed6 (diff) | |
download | aura-central-df1c87d8a7cb7ad0efaec527dc370e63b654b6db.tar.gz |
Issue #25 - Part 4: Remove EME Media code
Diffstat (limited to 'dom')
26 files changed, 0 insertions, 4730 deletions
diff --git a/dom/media/eme/CDMCaps.cpp b/dom/media/eme/CDMCaps.cpp deleted file mode 100644 index a30fb59ac..000000000 --- a/dom/media/eme/CDMCaps.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#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) -{ - mData.mMonitor.AssertCurrentThreadOwns(); - 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, - 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)); - } - - KeyStatus key(aKeyId, aSessionId, aStatus.Value()); - auto index = mData.mKeyStatuses.IndexOf(key); - if (index != mData.mKeyStatuses.NoIndex) { - if (mData.mKeyStatuses[index].mStatus == aStatus.Value()) { - // No change. - return false; - } - auto oldStatus = mData.mKeyStatuses[index].mStatus; - mData.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); - } - - // 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; - 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) -{ - mData.mMonitor.AssertCurrentThreadOwns(); - MOZ_ASSERT(!IsKeyUsable(aKey)); - MOZ_ASSERT(aListener); - mData.mWaitForKeys.AppendElement(WaitForKeys(aKey, aListener)); -} - -void -CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId, - nsTArray<KeyStatus>& aOutKeyStatuses) -{ - 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 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, - dom::Optional<dom::MediaKeyStatus>()); - } - return changed; -} - -} // namespace mozilla diff --git a/dom/media/eme/CDMCaps.h b/dom/media/eme/CDMCaps.h deleted file mode 100644 index cb4b5e291..000000000 --- a/dom/media/eme/CDMCaps.h +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 CDMCaps_h_ -#define CDMCaps_h_ - -#include "gmp-decryption.h" -#include "nsIThread.h" -#include "nsTArray.h" -#include "nsString.h" -#include "SamplesWaitingForKey.h" - -#include "mozilla/Monitor.h" -#include "mozilla/Attributes.h" -#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus -#include "mozilla/dom/BindingDeclarations.h" // For Optional - -namespace mozilla { - -// 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, - dom::MediaKeyStatus aStatus) - : mId(aId) - , mSessionId(aSessionId) - , mStatus(aStatus) - {} - KeyStatus(const KeyStatus& aOther) - : mId(aOther.mId) - , mSessionId(aOther.mSessionId) - , mStatus(aOther.mStatus) - {} - bool operator==(const KeyStatus& aOther) const { - return mId == aOther.mId && - 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); - - // 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 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); - - // 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(); - - 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; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/eme/CDMProxy.h b/dom/media/eme/CDMProxy.h deleted file mode 100644 index a9e783f50..000000000 --- a/dom/media/eme/CDMProxy.h +++ /dev/null @@ -1,278 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/MozPromise.h" - -#include "mozilla/dom/MediaKeyMessageEvent.h" -#include "mozilla/dom/MediaKeys.h" - -#include "nsIThread.h" - -namespace mozilla { -class MediaRawData; - -enum DecryptStatus { - Ok = 0, - GenericErr = 1, - NoKeyErr = 2, - AbortedErr = 3, -}; - -struct DecryptResult { - DecryptResult(DecryptStatus aStatus, MediaRawData* aSample) - : mStatus(aStatus) - , mSample(aSample) - {} - DecryptStatus mStatus; - RefPtr<MediaRawData> mSample; -}; - -class CDMKeyInfo { -public: - explicit CDMKeyInfo(const nsTArray<uint8_t>& aKeyId) - : mKeyId(aKeyId) - , mStatus() - {} - - CDMKeyInfo(const nsTArray<uint8_t>& aKeyId, - const dom::Optional<dom::MediaKeyStatus>& aStatus) - : mKeyId(aKeyId) - , mStatus(aStatus.Value()) - {} - - // The copy-ctor and copy-assignment operator for Optional<T> are declared as - // delete, so override CDMKeyInfo copy-ctor for nsTArray operations. - CDMKeyInfo(const CDMKeyInfo& aKeyInfo) - { - mKeyId = aKeyInfo.mKeyId; - if (aKeyInfo.mStatus.WasPassed()) { - mStatus.Construct(aKeyInfo.mStatus.Value()); - } - } - - nsTArray<uint8_t> mKeyId; - dom::Optional<dom::MediaKeyStatus> mStatus; -}; - -typedef int64_t UnixTime; - -// Proxies calls CDM, and proxies calls back. -// Note: Promises are passed in via a PromiseId, so that the ID can be -// passed via IPC to the CDM, which can then signal when to reject or -// resolve the promise using its PromiseId. -class CDMProxy { -protected: - typedef dom::PromiseId PromiseId; - typedef dom::MediaKeySessionType MediaKeySessionType; -public: - - NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; - NS_IMETHOD_(MozExternalRefCountType) Release(void) = 0; - - typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true> DecryptPromise; - - // Main thread only. - CDMProxy(dom::MediaKeys* aKeys, - const nsAString& aKeySystem, - bool aDistinctiveIdentifierRequired, - bool aPersistentStateRequired) - : mKeys(aKeys) - , mKeySystem(aKeySystem) - , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired) - , mPersistentStateRequired(aPersistentStateRequired) - {} - - // Main thread only. - // Loads the CDM corresponding to mKeySystem. - // Calls MediaKeys::OnCDMCreated() when the CDM is created. - virtual void Init(PromiseId aPromiseId, - const nsAString& aOrigin, - const nsAString& aTopLevelOrigin, - const nsAString& aName, - bool aInPrivateBrowsing) = 0; - - virtual void OnSetDecryptorId(uint32_t aId) {} - - // Main thread only. - // Uses the CDM to create a key session. - // Calls MediaKeys::OnSessionActivated() when session is created. - // Assumes ownership of (Move()s) aInitData's contents. - virtual void CreateSession(uint32_t aCreateSessionToken, - MediaKeySessionType aSessionType, - PromiseId aPromiseId, - const nsAString& aInitDataType, - nsTArray<uint8_t>& aInitData) = 0; - - // Main thread only. - // Uses the CDM to load a presistent session stored on disk. - // Calls MediaKeys::OnSessionActivated() when session is loaded. - virtual void LoadSession(PromiseId aPromiseId, - const nsAString& aSessionId) = 0; - - // Main thread only. - // Sends a new certificate to the CDM. - // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has - // processed the request. - // Assumes ownership of (Move()s) aCert's contents. - virtual void SetServerCertificate(PromiseId aPromiseId, - nsTArray<uint8_t>& aCert) = 0; - - // Main thread only. - // Sends an update to the CDM. - // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has - // processed the request. - // Assumes ownership of (Move()s) aResponse's contents. - virtual void UpdateSession(const nsAString& aSessionId, - PromiseId aPromiseId, - nsTArray<uint8_t>& aResponse) = 0; - - // Main thread only. - // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has - // processed the request. - // If processing this operation results in the session actually closing, - // we also call MediaKeySession::OnClosed(), which in turn calls - // MediaKeys::OnSessionClosed(). - virtual void CloseSession(const nsAString& aSessionId, - PromiseId aPromiseId) = 0; - - // Main thread only. - // Removes all data for a persisent session. - // Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has - // processed the request. - virtual void RemoveSession(const nsAString& aSessionId, - PromiseId aPromiseId) = 0; - - // Main thread only. - virtual void Shutdown() = 0; - - // Main thread only. - virtual void Terminated() = 0; - - // Threadsafe. - virtual const nsCString& GetNodeId() const = 0; - - // Main thread only. - virtual void OnSetSessionId(uint32_t aCreateSessionToken, - const nsAString& aSessionId) = 0; - - // Main thread only. - virtual void OnResolveLoadSessionPromise(uint32_t aPromiseId, - bool aSuccess) = 0; - - // Main thread only. - virtual void OnSessionMessage(const nsAString& aSessionId, - dom::MediaKeyMessageType aMessageType, - nsTArray<uint8_t>& aMessage) = 0; - - // Main thread only. - virtual void OnExpirationChange(const nsAString& aSessionId, - UnixTime aExpiryTime) = 0; - - // Main thread only. - virtual void OnSessionClosed(const nsAString& aSessionId) = 0; - - // Main thread only. - virtual void OnSessionError(const nsAString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsAString& aMsg) = 0; - - // Main thread only. - virtual void OnRejectPromise(uint32_t aPromiseId, - nsresult aDOMException, - const nsCString& aMsg) = 0; - - virtual RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) = 0; - - // Owner thread only. - virtual void OnDecrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) = 0; - - // Reject promise with DOMException corresponding to aExceptionCode. - // Can be called from any thread. - virtual void RejectPromise(PromiseId aId, - nsresult aExceptionCode, - const nsCString& aReason) = 0; - - // 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; - - // Main thread only. - virtual void OnKeyStatusesChange(const nsAString& aSessionId) = 0; - - virtual void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId, - nsTArray<nsCString>& aSessionIds) = 0; - -#ifdef DEBUG - virtual bool IsOnOwnerThread() = 0; -#endif - - virtual uint32_t GetDecryptorId() { return 0; } - -protected: - virtual ~CDMProxy() {} - - // Helper to enforce that a raw pointer is only accessed on the main thread. - template<class Type> - class MainThreadOnlyRawPtr { - public: - explicit MainThreadOnlyRawPtr(Type* aPtr) - : mPtr(aPtr) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - bool IsNull() const { - MOZ_ASSERT(NS_IsMainThread()); - return !mPtr; - } - - void Clear() { - MOZ_ASSERT(NS_IsMainThread()); - mPtr = nullptr; - } - - Type* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN { - MOZ_ASSERT(NS_IsMainThread()); - return mPtr; - } - private: - Type* mPtr; - }; - - // Our reference back to the MediaKeys object. - // WARNING: This is a non-owning reference that is cleared by MediaKeys - // destructor. only use on main thread, and always nullcheck before using! - MainThreadOnlyRawPtr<dom::MediaKeys> mKeys; - - 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; - - const bool mDistinctiveIdentifierRequired; - const bool mPersistentStateRequired; -}; - - -} // namespace mozilla - -#endif // CDMProxy_h_ diff --git a/dom/media/eme/DecryptorProxyCallback.h b/dom/media/eme/DecryptorProxyCallback.h deleted file mode 100644 index c1fcb49a4..000000000 --- a/dom/media/eme/DecryptorProxyCallback.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 DecryptorProxyCallback_h_ -#define DecryptorProxyCallback_h_ - -#include "mozilla/dom/MediaKeyStatusMapBinding.h" // For MediaKeyStatus -#include "mozilla/dom/MediaKeyMessageEventBinding.h" // For MediaKeyMessageType -#include "mozilla/CDMProxy.h" - -class DecryptorProxyCallback { -public: - - virtual ~DecryptorProxyCallback() {} - - virtual void SetDecryptorId(uint32_t aId) = 0; - - virtual void SetSessionId(uint32_t aCreateSessionId, - const nsCString& aSessionId) = 0; - - virtual void ResolveLoadSessionPromise(uint32_t aPromiseId, - bool aSuccess) = 0; - - virtual void ResolvePromise(uint32_t aPromiseId) = 0; - - virtual void RejectPromise(uint32_t aPromiseId, - nsresult aException, - const nsCString& aSessionId) = 0; - - virtual void SessionMessage(const nsCString& aSessionId, - mozilla::dom::MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage) = 0; - - virtual void ExpirationChange(const nsCString& aSessionId, - mozilla::UnixTime aExpiryTime) = 0; - - virtual void SessionClosed(const nsCString& aSessionId) = 0; - - virtual void SessionError(const nsCString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsCString& aMessage) = 0; - - virtual void Decrypted(uint32_t aId, - mozilla::DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) = 0; - - virtual void BatchedKeyStatusChanged(const nsCString& aSessionId, - const nsTArray<mozilla::CDMKeyInfo>& aKeyInfos) = 0; -}; - -#endif diff --git a/dom/media/eme/DetailedPromise.cpp b/dom/media/eme/DetailedPromise.cpp deleted file mode 100644 index 1aa83bef5..000000000 --- a/dom/media/eme/DetailedPromise.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "DetailedPromise.h" -#include "mozilla/dom/DOMException.h" -#include "nsPrintfCString.h" - -namespace mozilla { -namespace dom { - -DetailedPromise::DetailedPromise(nsIGlobalObject* aGlobal, - const nsACString& aName) - : Promise(aGlobal) - , mName(aName) - , mResponded(false) - , mStartTime(TimeStamp::Now()) -{ -} - -DetailedPromise::~DetailedPromise() -{ -} - -void -DetailedPromise::MaybeReject(nsresult aArg, const nsACString& aReason) -{ - nsPrintfCString msg("%s promise rejected 0x%x '%s'", mName.get(), aArg, - PromiseFlatCString(aReason).get()); - EME_LOG(msg.get()); - - LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg)); - - ErrorResult rv; - rv.ThrowDOMException(aArg, aReason); - Promise::MaybeReject(rv); -} - -void -DetailedPromise::MaybeReject(ErrorResult&, const nsACString& aReason) -{ - NS_NOTREACHED("nsresult expected in MaybeReject()"); -} - -/* static */ already_AddRefed<DetailedPromise> -DetailedPromise::Create(nsIGlobalObject* aGlobal, - ErrorResult& aRv, - const nsACString& aName) -{ - RefPtr<DetailedPromise> promise = new DetailedPromise(aGlobal, aName); - promise->CreateWrapper(nullptr, aRv); - return aRv.Failed() ? nullptr : promise.forget(); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/DetailedPromise.h b/dom/media/eme/DetailedPromise.h deleted file mode 100644 index f7f10aa40..000000000 --- a/dom/media/eme/DetailedPromise.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 __DetailedPromise_h__ -#define __DetailedPromise_h__ - -#include "mozilla/dom/Promise.h" -#include "EMEUtils.h" - -namespace mozilla { -namespace dom { - -/* - * This is pretty horrible; bug 1160445. - * Extend Promise to add custom DOMException messages on rejection. - * Get rid of this once we've ironed out EME errors in the wild. - */ -class DetailedPromise : public Promise -{ -public: - static already_AddRefed<DetailedPromise> - Create(nsIGlobalObject* aGlobal, - ErrorResult& aRv, - const nsACString& aName); - - template <typename T> - void MaybeResolve(const T& aArg) - { - EME_LOG("%s promise resolved", mName.get()); - Promise::MaybeResolve<T>(aArg); - } - - void MaybeReject(nsresult aArg) = delete; - void MaybeReject(nsresult aArg, const nsACString& aReason); - - void MaybeReject(ErrorResult& aArg) = delete; - void MaybeReject(ErrorResult&, const nsACString& aReason); - -private: - explicit DetailedPromise(nsIGlobalObject* aGlobal, - const nsACString& aName); - - virtual ~DetailedPromise(); - - enum Status { Succeeded, Failed }; - - nsCString mName; - bool mResponded; - TimeStamp mStartTime; -}; - -} // namespace dom -} // namespace mozilla - -#endif // __DetailedPromise_h__ diff --git a/dom/media/eme/EMEUtils.cpp b/dom/media/eme/EMEUtils.cpp deleted file mode 100644 index 68ef52d83..000000000 --- a/dom/media/eme/EMEUtils.cpp +++ /dev/null @@ -1,86 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/EMEUtils.h" - -#include "jsfriendapi.h" // for AutoCheckCannotGC -#include "mozilla/dom/UnionTypes.h" - -namespace mozilla { - -LogModule* GetEMELog() { - static LazyLogModule log("EME"); - return log; -} - -LogModule* GetEMEVerboseLog() { - static LazyLogModule log("EMEV"); - return log; -} - -ArrayData -GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView) -{ - MOZ_ASSERT(aBufferOrView.IsArrayBuffer() || aBufferOrView.IsArrayBufferView()); - JS::AutoCheckCannotGC nogc; - if (aBufferOrView.IsArrayBuffer()) { - const dom::ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer(); - buffer.ComputeLengthAndData(); - return ArrayData(buffer.Data(), buffer.Length()); - } else if (aBufferOrView.IsArrayBufferView()) { - const dom::ArrayBufferView& bufferview = aBufferOrView.GetAsArrayBufferView(); - bufferview.ComputeLengthAndData(); - return ArrayData(bufferview.Data(), bufferview.Length()); - } - return ArrayData(nullptr, 0); -} - -void -CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView, - nsTArray<uint8_t>& aOutData) -{ - JS::AutoCheckCannotGC nogc; - ArrayData data = GetArrayBufferViewOrArrayBufferData(aBufferOrView); - aOutData.Clear(); - if (!data.IsValid()) { - return; - } - aOutData.AppendElements(data.mData, data.mLength); -} - -void CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBuffer& aBuffer, - nsTArray<uint8_t>& aOutData) { - JS::AutoCheckCannotGC nogc; - aBuffer.ComputeLengthAndData(); - aOutData.Clear(); - aOutData.AppendElements(aBuffer.Data(), aBuffer.Length()); -} - -bool -IsClearkeyKeySystem(const nsAString& aKeySystem) -{ - return !CompareUTF8toUTF16(kEMEKeySystemClearkey, aKeySystem); -} - -bool -IsWidevineKeySystem(const nsAString& aKeySystem) -{ - return !CompareUTF8toUTF16(kEMEKeySystemWidevine, aKeySystem); -} - -nsString -KeySystemToGMPName(const nsAString& aKeySystem) -{ - if (IsClearkeyKeySystem(aKeySystem)) { - return NS_LITERAL_STRING("gmp-clearkey"); - } - if (IsWidevineKeySystem(aKeySystem)) { - return NS_LITERAL_STRING("gmp-widevinecdm"); - } - MOZ_ASSERT(false, "We should only call this for known GMPs"); - return EmptyString(); -} - -} // namespace mozilla diff --git a/dom/media/eme/EMEUtils.h b/dom/media/eme/EMEUtils.h deleted file mode 100644 index aef157482..000000000 --- a/dom/media/eme/EMEUtils.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 EME_LOG_H_ -#define EME_LOG_H_ - -#include "VideoUtils.h" -#include "mozilla/Logging.h" -#include "nsString.h" -#include "nsTArray.h" -#include "mozilla/dom/TypedArray.h" - -namespace mozilla { - -namespace dom { -class ArrayBufferViewOrArrayBuffer; -} - -#ifndef EME_LOG - LogModule* GetEMELog(); - #define EME_LOG(...) MOZ_LOG(GetEMELog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) - #define EME_LOG_ENABLED() MOZ_LOG_TEST(GetEMELog(), mozilla::LogLevel::Debug) -#endif - -#ifndef EME_VERBOSE_LOG - LogModule* GetEMEVerboseLog(); - #define EME_VERBOSE_LOG(...) MOZ_LOG(GetEMEVerboseLog(), mozilla::LogLevel::Debug, (__VA_ARGS__)) -#else - #ifndef EME_LOG - #define EME_LOG(...) - #endif - - #ifndef EME_VERBOSE_LOG - #define EME_VERBOSE_LOG(...) - #endif -#endif - -// Helper function to extract a copy of data coming in from JS in an -// (ArrayBuffer or ArrayBufferView) IDL typed function argument. -// -// Only call this on a properly initialized ArrayBufferViewOrArrayBuffer. -void -CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView, - nsTArray<uint8_t>& aOutData); - -// Overload for ArrayBuffer -void CopyArrayBufferViewOrArrayBufferData(const dom::ArrayBuffer& aBufferOrView, - nsTArray<uint8_t>& aOutData); - -struct ArrayData { - explicit ArrayData(const uint8_t* aData, size_t aLength) - : mData(aData) - , mLength(aLength) - { - } - const uint8_t* mData; - const size_t mLength; - bool IsValid() const { - return mData != nullptr && mLength != 0; - } - bool operator== (const nsTArray<uint8_t>& aOther) const { - return mLength == aOther.Length() && - memcmp(mData, aOther.Elements(), mLength) == 0; - } -}; - -// Helper function to extract data coming in from JS in an -// (ArrayBuffer or ArrayBufferView) IDL typed function argument. -// -// Be *very* careful with this! -// -// Only use returned ArrayData inside the lifetime of the -// ArrayBufferViewOrArrayBuffer; the ArrayData struct does not contain -// a copy of the data! -// -// And do *not* call out to anything that could call into JavaScript, -// while the ArrayData is live, as then all bets about the data not changing -// are off! No calls into JS, no calls into JS-implemented WebIDL or XPIDL, -// nothing. Beware! -// -// Only call this on a properly initialized ArrayBufferViewOrArrayBuffer. -ArrayData -GetArrayBufferViewOrArrayBufferData(const dom::ArrayBufferViewOrArrayBuffer& aBufferOrView); - -nsString -KeySystemToGMPName(const nsAString& aKeySystem); - -bool -IsClearkeyKeySystem(const nsAString& aKeySystem); - -bool -IsWidevineKeySystem(const nsAString& aKeySystem); - -enum CDMType { - eClearKey = 0, - eWidevine = 2, - eUnknown = 3 -}; - -} // namespace mozilla - -#endif // EME_LOG_H_ diff --git a/dom/media/eme/MediaEncryptedEvent.cpp b/dom/media/eme/MediaEncryptedEvent.cpp deleted file mode 100644 index a9c83291e..000000000 --- a/dom/media/eme/MediaEncryptedEvent.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "MediaEncryptedEvent.h" -#include "mozilla/dom/MediaEncryptedEventBinding.h" -#include "nsContentUtils.h" -#include "jsfriendapi.h" -#include "nsINode.h" -#include "mozilla/dom/MediaKeys.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_CLASS(MediaEncryptedEvent) - -NS_IMPL_ADDREF_INHERITED(MediaEncryptedEvent, Event) -NS_IMPL_RELEASE_INHERITED(MediaEncryptedEvent, Event) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaEncryptedEvent, Event) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MediaEncryptedEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mInitData) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaEncryptedEvent, Event) - tmp->mInitData = nullptr; - mozilla::DropJSObjects(this); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaEncryptedEvent) -NS_INTERFACE_MAP_END_INHERITING(Event) - -MediaEncryptedEvent::MediaEncryptedEvent(EventTarget* aOwner) - : Event(aOwner, nullptr, nullptr) -{ - mozilla::HoldJSObjects(this); -} - -MediaEncryptedEvent::~MediaEncryptedEvent() -{ - mInitData = nullptr; - mozilla::DropJSObjects(this); -} - -JSObject* -MediaEncryptedEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaEncryptedEventBinding::Wrap(aCx, this, aGivenProto); -} - -already_AddRefed<MediaEncryptedEvent> -MediaEncryptedEvent::Constructor(EventTarget* aOwner) -{ - RefPtr<MediaEncryptedEvent> e = new MediaEncryptedEvent(aOwner); - e->InitEvent(NS_LITERAL_STRING("encrypted"), false, false); - e->SetTrusted(true); - return e.forget(); -} - -already_AddRefed<MediaEncryptedEvent> -MediaEncryptedEvent::Constructor(EventTarget* aOwner, - const nsAString& aInitDataType, - const nsTArray<uint8_t>& aInitData) -{ - RefPtr<MediaEncryptedEvent> e = new MediaEncryptedEvent(aOwner); - e->InitEvent(NS_LITERAL_STRING("encrypted"), false, false); - e->mInitDataType = aInitDataType; - e->mRawInitData = aInitData; - e->SetTrusted(true); - return e.forget(); -} - -already_AddRefed<MediaEncryptedEvent> -MediaEncryptedEvent::Constructor(const GlobalObject& aGlobal, - const nsAString& aType, - const MediaKeyNeededEventInit& aEventInitDict, - ErrorResult& aRv) -{ - nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports()); - RefPtr<MediaEncryptedEvent> e = new MediaEncryptedEvent(owner); - bool trusted = e->Init(owner); - e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); - e->mInitDataType = aEventInitDict.mInitDataType; - if (!aEventInitDict.mInitData.IsNull()) { - const auto& a = aEventInitDict.mInitData.Value(); - nsTArray<uint8_t> initData; - CopyArrayBufferViewOrArrayBufferData(a, initData); - e->mInitData = ArrayBuffer::Create(aGlobal.Context(), initData.Length(), - initData.Elements()); - if (!e->mInitData) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return nullptr; - } - } - e->SetTrusted(trusted); - return e.forget(); -} - -void -MediaEncryptedEvent::GetInitDataType(nsString& aRetVal) const -{ - aRetVal = mInitDataType; -} - -void -MediaEncryptedEvent::GetInitData(JSContext* cx, - JS::MutableHandle<JSObject*> aData, - ErrorResult& aRv) -{ - if (mRawInitData.Length()) { - mInitData = ArrayBuffer::Create(cx, - this, - mRawInitData.Length(), - mRawInitData.Elements()); - if (!mInitData) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - mRawInitData.Clear(); - } - aData.set(mInitData); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaEncryptedEvent.h b/dom/media/eme/MediaEncryptedEvent.h deleted file mode 100644 index c2ac56061..000000000 --- a/dom/media/eme/MediaEncryptedEvent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 mozilla_dom_MediaKeyNeededEvent_h__ -#define mozilla_dom_MediaKeyNeededEvent_h__ - -#include "mozilla/dom/MediaEncryptedEventBinding.h" -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" -#include "nsCOMPtr.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/TypedArray.h" -#include "mozilla/Attributes.h" -#include "mozilla/dom/BindingUtils.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class MediaEncryptedEvent final : public Event -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MediaEncryptedEvent, Event) -protected: - virtual ~MediaEncryptedEvent(); - explicit MediaEncryptedEvent(EventTarget* aOwner); - - nsString mInitDataType; - JS::Heap<JSObject*> mInitData; - -public: - - JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - static already_AddRefed<MediaEncryptedEvent> - Constructor(EventTarget* aOwner); - - static already_AddRefed<MediaEncryptedEvent> - Constructor(EventTarget* aOwner, - const nsAString& aInitDataType, - const nsTArray<uint8_t>& aInitData); - - static already_AddRefed<MediaEncryptedEvent> - Constructor(const GlobalObject& aGlobal, - const nsAString& aType, - const MediaKeyNeededEventInit& aEventInitDict, - ErrorResult& aRv); - - void GetInitDataType(nsString& aRetVal) const; - - void GetInitData(JSContext* cx, - JS::MutableHandle<JSObject*> aData, - ErrorResult& aRv); -private: - nsTArray<uint8_t> mRawInitData; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MediaKeyNeededEvent_h__ diff --git a/dom/media/eme/MediaKeyError.cpp b/dom/media/eme/MediaKeyError.cpp deleted file mode 100644 index 635c34364..000000000 --- a/dom/media/eme/MediaKeyError.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#include "MediaKeyError.h" -#include "mozilla/dom/MediaKeyErrorBinding.h" -#include "nsContentUtils.h" - -namespace mozilla { -namespace dom { - -MediaKeyError::MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode) - : Event(aOwner, nullptr, nullptr) - , mSystemCode(aSystemCode) -{ - InitEvent(NS_LITERAL_STRING("error"), false, false); -} - -MediaKeyError::~MediaKeyError() -{ -} - -uint32_t -MediaKeyError::SystemCode() const -{ - return mSystemCode; -} - -JSObject* -MediaKeyError::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeyErrorBinding::Wrap(aCx, this, aGivenProto); -} - - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeyError.h b/dom/media/eme/MediaKeyError.h deleted file mode 100644 index df79b2c95..000000000 --- a/dom/media/eme/MediaKeyError.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 mozilla_dom_MediaKeyError_h -#define mozilla_dom_MediaKeyError_h - -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "nsWrapperCache.h" -#include "mozilla/dom/Event.h" -#include "js/TypeDecls.h" - -namespace mozilla { -namespace dom { - -class MediaKeyError final : public Event -{ -public: - NS_FORWARD_TO_EVENT - - MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode); - ~MediaKeyError(); - - JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - uint32_t SystemCode() const; - -private: - uint32_t mSystemCode; -}; - -} // namespace dom -} // namespace mozilla - -#endif diff --git a/dom/media/eme/MediaKeyMessageEvent.cpp b/dom/media/eme/MediaKeyMessageEvent.cpp deleted file mode 100644 index ee13f8d26..000000000 --- a/dom/media/eme/MediaKeyMessageEvent.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/dom/MediaKeyMessageEvent.h" -#include "mozilla/dom/MediaKeyMessageEventBinding.h" -#include "js/GCAPI.h" -#include "jsfriendapi.h" -#include "mozilla/dom/Nullable.h" -#include "mozilla/dom/PrimitiveConversions.h" -#include "mozilla/HoldDropJSObjects.h" -#include "mozilla/dom/TypedArray.h" -#include "nsContentUtils.h" -#include "mozilla/dom/MediaKeys.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_CLASS(MediaKeyMessageEvent) - -NS_IMPL_ADDREF_INHERITED(MediaKeyMessageEvent, Event) -NS_IMPL_RELEASE_INHERITED(MediaKeyMessageEvent, Event) - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaKeyMessageEvent, Event) -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(MediaKeyMessageEvent, Event) - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMessage) -NS_IMPL_CYCLE_COLLECTION_TRACE_END - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaKeyMessageEvent, Event) - tmp->mMessage = nullptr; - mozilla::DropJSObjects(this); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaKeyMessageEvent) -NS_INTERFACE_MAP_END_INHERITING(Event) - -MediaKeyMessageEvent::MediaKeyMessageEvent(EventTarget* aOwner) - : Event(aOwner, nullptr, nullptr) -{ - mozilla::HoldJSObjects(this); -} - -MediaKeyMessageEvent::~MediaKeyMessageEvent() -{ - mMessage = nullptr; - mozilla::DropJSObjects(this); -} - -MediaKeyMessageEvent* -MediaKeyMessageEvent::AsMediaKeyMessageEvent() -{ - return this; -} - -JSObject* -MediaKeyMessageEvent::WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeyMessageEventBinding::Wrap(aCx, this, aGivenProto); -} - -already_AddRefed<MediaKeyMessageEvent> -MediaKeyMessageEvent::Constructor(EventTarget* aOwner, - MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage) -{ - RefPtr<MediaKeyMessageEvent> e = new MediaKeyMessageEvent(aOwner); - e->InitEvent(NS_LITERAL_STRING("message"), false, false); - e->mMessageType = aMessageType; - e->mRawMessage = aMessage; - e->SetTrusted(true); - return e.forget(); -} - -already_AddRefed<MediaKeyMessageEvent> -MediaKeyMessageEvent::Constructor(const GlobalObject& aGlobal, - const nsAString& aType, - const MediaKeyMessageEventInit& aEventInitDict, - ErrorResult& aRv) -{ - nsCOMPtr<EventTarget> owner = do_QueryInterface(aGlobal.GetAsSupports()); - RefPtr<MediaKeyMessageEvent> e = new MediaKeyMessageEvent(owner); - bool trusted = e->Init(owner); - e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable); - nsTArray<uint8_t> initData; - CopyArrayBufferViewOrArrayBufferData(aEventInitDict.mMessage, initData); - e->mMessage = ArrayBuffer::Create(aGlobal.Context(), - initData.Length(), - initData.Elements()); - if (!e->mMessage) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return nullptr; - } - e->mMessageType = aEventInitDict.mMessageType; - e->SetTrusted(trusted); - e->SetComposed(aEventInitDict.mComposed); - return e.forget(); -} - -void -MediaKeyMessageEvent::GetMessage(JSContext* cx, - JS::MutableHandle<JSObject*> aMessage, - ErrorResult& aRv) -{ - if (!mMessage) { - mMessage = ArrayBuffer::Create(cx, - this, - mRawMessage.Length(), - mRawMessage.Elements()); - if (!mMessage) { - aRv.Throw(NS_ERROR_OUT_OF_MEMORY); - return; - } - mRawMessage.Clear(); - } - aMessage.set(mMessage); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeyMessageEvent.h b/dom/media/eme/MediaKeyMessageEvent.h deleted file mode 100644 index 2ec50f4f0..000000000 --- a/dom/media/eme/MediaKeyMessageEvent.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 mozilla_dom_MediaKeyMessageEvent_h__ -#define mozilla_dom_MediaKeyMessageEvent_h__ - -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" -#include "nsCOMPtr.h" -#include "mozilla/dom/Event.h" -#include "mozilla/dom/TypedArray.h" -#include "js/TypeDecls.h" -#include "mozilla/dom/MediaKeyMessageEventBinding.h" - -namespace mozilla { -namespace dom { - -struct MediaKeyMessageEventInit; - -class MediaKeyMessageEvent final : public Event -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(MediaKeyMessageEvent, Event) -protected: - virtual ~MediaKeyMessageEvent(); - explicit MediaKeyMessageEvent(EventTarget* aOwner); - - MediaKeyMessageType mMessageType; - JS::Heap<JSObject*> mMessage; - -public: - virtual MediaKeyMessageEvent* AsMediaKeyMessageEvent(); - - JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - static already_AddRefed<MediaKeyMessageEvent> - Constructor(EventTarget* aOwner, - MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage); - - static already_AddRefed<MediaKeyMessageEvent> - Constructor(const GlobalObject& aGlobal, - const nsAString& aType, - const MediaKeyMessageEventInit& aEventInitDict, - ErrorResult& aRv); - - MediaKeyMessageType MessageType() const { return mMessageType; } - - void GetMessage(JSContext* cx, - JS::MutableHandle<JSObject*> aMessage, - ErrorResult& aRv); - -private: - nsTArray<uint8_t> mRawMessage; -}; - - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MediaKeyMessageEvent_h__ diff --git a/dom/media/eme/MediaKeySession.cpp b/dom/media/eme/MediaKeySession.cpp deleted file mode 100644 index b5f3fe498..000000000 --- a/dom/media/eme/MediaKeySession.cpp +++ /dev/null @@ -1,670 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/dom/MediaKeySession.h" -#include "mozilla/dom/MediaKeyError.h" -#include "mozilla/dom/MediaKeyMessageEvent.h" -#include "mozilla/dom/MediaEncryptedEvent.h" -#include "mozilla/dom/MediaKeyStatusMap.h" -#include "mozilla/dom/MediaKeySystemAccess.h" -#include "mozilla/dom/KeyIdsInitDataBinding.h" -#include "nsCycleCollectionParticipant.h" -#include "mozilla/CDMProxy.h" -#include "mozilla/AsyncEventDispatcher.h" -#include "mozilla/Move.h" -#include "nsContentUtils.h" -#include "mozilla/EMEUtils.h" -#include "GMPUtils.h" -#include "nsPrintfCString.h" -#include "psshparser/PsshParser.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaKeySession, - DOMEventTargetHelper, - mMediaKeyError, - mKeys, - mKeyStatusMap, - mClosed) - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaKeySession) -NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) - -NS_IMPL_ADDREF_INHERITED(MediaKeySession, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(MediaKeySession, DOMEventTargetHelper) - -// Count of number of instances. Used to give each instance a -// unique token. -static uint32_t sMediaKeySessionNum = 0; - -// Max length of keyId in EME "keyIds" or WebM init data format, as enforced -// by web platform tests. -static const uint32_t MAX_KEY_ID_LENGTH = 512; - -// Max length of CENC PSSH init data tolerated, as enforced by web -// platform tests. -static const uint32_t MAX_CENC_INIT_DATA_LENGTH = 64 * 1024; - - -MediaKeySession::MediaKeySession(JSContext* aCx, - nsPIDOMWindowInner* aParent, - MediaKeys* aKeys, - const nsAString& aKeySystem, - MediaKeySessionType aSessionType, - ErrorResult& aRv) - : DOMEventTargetHelper(aParent) - , mKeys(aKeys) - , mKeySystem(aKeySystem) - , mSessionType(aSessionType) - , mToken(sMediaKeySessionNum++) - , mIsClosed(false) - , mUninitialized(true) - , mKeyStatusMap(new MediaKeyStatusMap(aParent)) - , mExpiration(JS::GenericNaN()) -{ - EME_LOG("MediaKeySession[%p,''] ctor", this); - - MOZ_ASSERT(aParent); - if (aRv.Failed()) { - return; - } - mClosed = MakePromise(aRv, NS_LITERAL_CSTRING("MediaKeys.createSession")); -} - -void MediaKeySession::SetSessionId(const nsAString& aSessionId) -{ - EME_LOG("MediaKeySession[%p,'%s'] session Id set", - this, NS_ConvertUTF16toUTF8(aSessionId).get()); - - if (NS_WARN_IF(!mSessionId.IsEmpty())) { - return; - } - mSessionId = aSessionId; - mKeys->OnSessionIdReady(this); -} - -MediaKeySession::~MediaKeySession() -{ -} - -MediaKeyError* -MediaKeySession::GetError() const -{ - return mMediaKeyError; -} - -void -MediaKeySession::GetKeySystem(nsString& aOutKeySystem) const -{ - aOutKeySystem.Assign(mKeySystem); -} - -void -MediaKeySession::GetSessionId(nsString& aSessionId) const -{ - aSessionId = GetSessionId(); -} - -const nsString& -MediaKeySession::GetSessionId() const -{ - return mSessionId; -} - -JSObject* -MediaKeySession::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeySessionBinding::Wrap(aCx, this, aGivenProto); -} - -double -MediaKeySession::Expiration() const -{ - return mExpiration; -} - -Promise* -MediaKeySession::Closed() const -{ - return mClosed; -} - -void -MediaKeySession::UpdateKeyStatusMap() -{ - MOZ_ASSERT(!IsClosed()); - if (!mKeys->GetCDMProxy()) { - return; - } - - nsTArray<CDMCaps::KeyStatus> keyStatuses; - { - CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites()); - 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())); - using IntegerType = typename std::underlying_type<MediaKeyStatus>::type; - for (const CDMCaps::KeyStatus& status : keyStatuses) { - message.Append(nsPrintfCString(" (%s,%s)", ToBase64(status.mId).get(), - MediaKeyStatusValues::strings[static_cast<IntegerType>(status.mStatus)].value)); - } - message.Append(" }"); - EME_LOG(message.get()); - } -} - -MediaKeyStatusMap* -MediaKeySession::KeyStatuses() const -{ - return mKeyStatusMap; -} - -// The user agent MUST thoroughly validate the Initialization Data before -// passing it to the CDM. This includes verifying that the length and -// values of fields are reasonable, verifying that values are within -// reasonable limits, and stripping irrelevant, unsupported, or unknown -// data or fields. It is RECOMMENDED that user agents pre-parse, sanitize, -// and/or generate a fully sanitized version of the Initialization Data. -// If the Initialization Data format specified by initDataType supports -// multiple entries, the user agent SHOULD remove entries that are not -// needed by the CDM. The user agent MUST NOT re-order entries within -// the Initialization Data. -static bool -ValidateInitData(const nsTArray<uint8_t>& aInitData, const nsAString& aInitDataType) -{ - if (aInitDataType.LowerCaseEqualsLiteral("webm")) { - // WebM initData consists of a single keyId. Ensure it's of reasonable length. - return aInitData.Length() <= MAX_KEY_ID_LENGTH; - } else if (aInitDataType.LowerCaseEqualsLiteral("cenc")) { - // Limit initData to less than 64KB. - if (aInitData.Length() > MAX_CENC_INIT_DATA_LENGTH) { - return false; - } - std::vector<std::vector<uint8_t>> keyIds; - return ParseCENCInitData(aInitData.Elements(), aInitData.Length(), keyIds); - } else if (aInitDataType.LowerCaseEqualsLiteral("keyids")) { - if (aInitData.Length() > MAX_KEY_ID_LENGTH) { - return false; - } - // Ensure that init data matches the expected JSON format. - mozilla::dom::KeyIdsInitData keyIds; - nsString json; - nsDependentCSubstring raw(reinterpret_cast<const char*>(aInitData.Elements()), aInitData.Length()); - if (NS_FAILED(nsContentUtils::ConvertStringFromEncoding(NS_LITERAL_CSTRING("UTF-8"), raw, json))) { - return false; - } - if (!keyIds.Init(json)) { - return false; - } - if (keyIds.mKids.Length() == 0) { - return false; - } - for (const auto& kid : keyIds.mKids) { - if (kid.IsEmpty()) { - return false; - } - } - } - return true; -} - -// Generates a license request based on the initData. A message of type -// "license-request" or "individualization-request" will always be queued -// if the algorithm succeeds and the promise is resolved. -already_AddRefed<Promise> -MediaKeySession::GenerateRequest(const nsAString& aInitDataType, - const ArrayBufferViewOrArrayBuffer& aInitData, - ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeySession.generateRequest"))); - if (aRv.Failed()) { - return nullptr; - } - - // If this object is closed, return a promise rejected with an InvalidStateError. - if (IsClosed()) { - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, closed", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Session is closed in MediaKeySession.generateRequest()")); - return promise.forget(); - } - - // If this object's uninitialized value is false, return a promise rejected - // with an InvalidStateError. - if (!mUninitialized) { - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, uninitialized", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.generateRequest()")); - return promise.forget(); - } - - // Let this object's uninitialized value be false. - mUninitialized = false; - - // If initDataType is the empty string, return a promise rejected - // with a newly created TypeError. - if (aInitDataType.IsEmpty()) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Empty initDataType passed to MediaKeySession.generateRequest()")); - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initDataType", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - - // If initData is an empty array, return a promise rejected with - // a newly created TypeError. - nsTArray<uint8_t> data; - CopyArrayBufferViewOrArrayBufferData(aInitData, data); - if (data.IsEmpty()) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Empty initData passed to MediaKeySession.generateRequest()")); - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, empty initData", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - - // If the Key System implementation represented by this object's - // cdm implementation value does not support initDataType as an - // Initialization Data Type, return a promise rejected with a - // NotSupportedError. String comparison is case-sensitive. - if (!MediaKeySystemAccess::KeySystemSupportsInitDataType(mKeySystem, aInitDataType)) { - promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, - NS_LITERAL_CSTRING("Unsupported initDataType passed to MediaKeySession.generateRequest()")); - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() failed, unsupported initDataType", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - - // Let init data be a copy of the contents of the initData parameter. - // Note: Handled by the CopyArrayBufferViewOrArrayBufferData call above. - - // Let session type be this object's session type. - - // Let promise be a new promise. - - // Run the following steps in parallel: - - // If the init data is not valid for initDataType, reject promise with - // a newly created TypeError. - if (!ValidateInitData(data, aInitDataType)) { - // If the preceding step failed, reject promise with a newly created TypeError. - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("initData sanitization failed in MediaKeySession.generateRequest()")); - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() initData sanitization failed", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - - // Let sanitized init data be a validated and sanitized version of init data. - - // If sanitized init data is empty, reject promise with a NotSupportedError. - - // Note: Remaining steps of generateRequest method continue in CDM. - - // Convert initData to base64 for easier logging. - // Note: CreateSession() Move()s the data out of the array, so we have - // to copy it here. - nsAutoCString base64InitData(ToBase64(data)); - PromiseId pid = mKeys->StorePromise(promise); - mKeys->ConnectPendingPromiseIdWithToken(pid, Token()); - mKeys->GetCDMProxy()->CreateSession(Token(), - mSessionType, - pid, - aInitDataType, data); - - EME_LOG("MediaKeySession[%p,'%s'] GenerateRequest() sent, " - "promiseId=%d initData(base64)='%s' initDataType='%s'", - this, - NS_ConvertUTF16toUTF8(mSessionId).get(), - pid, - base64InitData.get(), - NS_ConvertUTF16toUTF8(aInitDataType).get()); - - return promise.forget(); -} - -already_AddRefed<Promise> -MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeySession.load"))); - if (aRv.Failed()) { - return nullptr; - } - - // 1. If this object is closed, return a promise rejected with an InvalidStateError. - if (IsClosed()) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Session is closed in MediaKeySession.load()")); - EME_LOG("MediaKeySession[%p,'%s'] Load() failed, closed", - this, NS_ConvertUTF16toUTF8(aSessionId).get()); - return promise.forget(); - } - - // 2.If this object's uninitialized value is false, return a promise rejected - // with an InvalidStateError. - if (!mUninitialized) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Session is already initialized in MediaKeySession.load()")); - EME_LOG("MediaKeySession[%p,'%s'] Load() failed, uninitialized", - this, NS_ConvertUTF16toUTF8(aSessionId).get()); - return promise.forget(); - } - - // 3.Let this object's uninitialized value be false. - mUninitialized = false; - - // 4. If sessionId is the empty string, return a promise rejected with a newly created TypeError. - if (aSessionId.IsEmpty()) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Trying to load a session with empty session ID")); - // "The sessionId parameter is empty." - EME_LOG("MediaKeySession[%p,''] Load() failed, no sessionId", this); - return promise.forget(); - } - - // 5. If the result of running the Is persistent session type? algorithm - // on this object's session type is false, return a promise rejected with - // a newly created TypeError. - if (mSessionType == MediaKeySessionType::Temporary) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Trying to load() into a non-persistent session")); - EME_LOG("MediaKeySession[%p,''] Load() failed, can't load in a non-persistent session", this); - return promise.forget(); - } - - // Note: We don't support persistent sessions in any keysystem, so all calls - // to Load() should reject with a TypeError in the preceding check. Omitting - // implementing the rest of the specified MediaKeySession::Load() algorithm. - - // We now know the sessionId being loaded into this session. Remove the - // session from its owning MediaKey's set of sessions awaiting a sessionId. - RefPtr<MediaKeySession> session(mKeys->GetPendingSession(Token())); - MOZ_ASSERT(session == this, "Session should be awaiting id on its own token"); - - // Associate with the known sessionId. - SetSessionId(aSessionId); - - PromiseId pid = mKeys->StorePromise(promise); - mKeys->GetCDMProxy()->LoadSession(pid, aSessionId); - - EME_LOG("MediaKeySession[%p,'%s'] Load() sent to CDM, promiseId=%d", - this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid); - - return promise.forget(); -} - -already_AddRefed<Promise> -MediaKeySession::Update(const ArrayBufferViewOrArrayBuffer& aResponse, ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeySession.update"))); - if (aRv.Failed()) { - return nullptr; - } - - if (!IsCallable()) { - // If this object's callable value is false, return a promise rejected - // with a new DOMException whose name is InvalidStateError. - EME_LOG("MediaKeySession[%p,''] Update() called before sessionId set by CDM", this); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("MediaKeySession.Update() called before sessionId set by CDM")); - return promise.forget(); - } - - nsTArray<uint8_t> data; - if (IsClosed() || !mKeys->GetCDMProxy()) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Session is closed or was not properly initialized")); - EME_LOG("MediaKeySession[%p,'%s'] Update() failed, session is closed or was not properly initialised.", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - CopyArrayBufferViewOrArrayBufferData(aResponse, data); - if (data.IsEmpty()) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Empty response buffer passed to MediaKeySession.update()")); - EME_LOG("MediaKeySession[%p,'%s'] Update() failed, empty response buffer", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - - - // Convert response to base64 for easier logging. - // Note: UpdateSession() Move()s the data out of the array, so we have - // to copy it here. - nsAutoCString base64Response(ToBase64(data)); - - PromiseId pid = mKeys->StorePromise(promise); - mKeys->GetCDMProxy()->UpdateSession(mSessionId, - pid, - data); - - EME_LOG("MediaKeySession[%p,'%s'] Update() sent to CDM, " - "promiseId=%d Response(base64)='%s'", - this, - NS_ConvertUTF16toUTF8(mSessionId).get(), - pid, - base64Response.get()); - - return promise.forget(); -} - -already_AddRefed<Promise> -MediaKeySession::Close(ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeySession.close"))); - if (aRv.Failed()) { - return nullptr; - } - // 1. Let session be the associated MediaKeySession object. - // 2. If session is closed, return a resolved promise. - if (IsClosed()) { - EME_LOG("MediaKeySession[%p,'%s'] Close() already closed", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - promise->MaybeResolveWithUndefined(); - return promise.forget(); - } - // 3. If session's callable value is false, return a promise rejected - // with an InvalidStateError. - if (!IsCallable()) { - EME_LOG("MediaKeySession[%p,''] Close() called before sessionId set by CDM", this); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("MediaKeySession.Close() called before sessionId set by CDM")); - return promise.forget(); - } - if (!mKeys->GetCDMProxy()) { - EME_LOG("MediaKeySession[%p,'%s'] Close() null CDMProxy", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("MediaKeySession.Close() lost reference to CDM")); - return promise.forget(); - } - // 4. Let promise be a new promise. - PromiseId pid = mKeys->StorePromise(promise); - // 5. Run the following steps in parallel: - // 5.1 Let cdm be the CDM instance represented by session's cdm instance value. - // 5.2 Use cdm to close the session associated with session. - mKeys->GetCDMProxy()->CloseSession(mSessionId, pid); - - EME_LOG("MediaKeySession[%p,'%s'] Close() sent to CDM, promiseId=%d", - this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid); - - // Session Closed algorithm is run when CDM causes us to run OnSessionClosed(). - - // 6. Return promise. - return promise.forget(); -} - -void -MediaKeySession::OnClosed() -{ - if (IsClosed()) { - return; - } - EME_LOG("MediaKeySession[%p,'%s'] session close operation complete.", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - mIsClosed = true; - mKeys->OnSessionClosed(this); - mKeys = nullptr; - mClosed->MaybeResolveWithUndefined(); -} - -bool -MediaKeySession::IsClosed() const -{ - return mIsClosed; -} - -already_AddRefed<Promise> -MediaKeySession::Remove(ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeySession.remove"))); - if (aRv.Failed()) { - return nullptr; - } - if (!IsCallable()) { - // If this object's callable value is false, return a promise rejected - // with a new DOMException whose name is InvalidStateError. - EME_LOG("MediaKeySession[%p,''] Remove() called before sessionId set by CDM", this); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("MediaKeySession.Remove() called before sessionId set by CDM")); - return promise.forget(); - } - if (mSessionType != MediaKeySessionType::Persistent_license) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("Calling MediaKeySession.remove() on non-persistent session")); - // "The operation is not supported on session type sessions." - EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, sesion not persisrtent.", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - if (IsClosed() || !mKeys->GetCDMProxy()) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("MediaKeySesison.remove() called but session is not active")); - // "The session is closed." - EME_LOG("MediaKeySession[%p,'%s'] Remove() failed, already session closed.", - this, NS_ConvertUTF16toUTF8(mSessionId).get()); - return promise.forget(); - } - PromiseId pid = mKeys->StorePromise(promise); - mKeys->GetCDMProxy()->RemoveSession(mSessionId, pid); - EME_LOG("MediaKeySession[%p,'%s'] Remove() sent to CDM, promiseId=%d.", - this, NS_ConvertUTF16toUTF8(mSessionId).get(), pid); - - return promise.forget(); -} - -void -MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage) -{ - if (EME_LOG_ENABLED()) { - EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyMessage() type=%s message(base64)='%s'", - this, NS_ConvertUTF16toUTF8(mSessionId).get(), - MediaKeyMessageTypeValues::strings[uint32_t(aMessageType)].value, - ToBase64(aMessage).get()); - } - - RefPtr<MediaKeyMessageEvent> event( - MediaKeyMessageEvent::Constructor(this, aMessageType, aMessage)); - RefPtr<AsyncEventDispatcher> asyncDispatcher = - new AsyncEventDispatcher(this, event); - asyncDispatcher->PostDOMEvent(); -} - -void -MediaKeySession::DispatchKeyError(uint32_t aSystemCode) -{ - EME_LOG("MediaKeySession[%p,'%s'] DispatchKeyError() systemCode=%u.", - this, NS_ConvertUTF16toUTF8(mSessionId).get(), aSystemCode); - - RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode)); - RefPtr<AsyncEventDispatcher> asyncDispatcher = - new AsyncEventDispatcher(this, event); - asyncDispatcher->PostDOMEvent(); -} - -void -MediaKeySession::DispatchKeyStatusesChange() -{ - if (IsClosed()) { - return; - } - - UpdateKeyStatusMap(); - - RefPtr<AsyncEventDispatcher> asyncDispatcher = - new AsyncEventDispatcher(this, NS_LITERAL_STRING("keystatuseschange"), false); - asyncDispatcher->PostDOMEvent(); -} - -uint32_t -MediaKeySession::Token() const -{ - return mToken; -} - -already_AddRefed<DetailedPromise> -MediaKeySession::MakePromise(ErrorResult& aRv, const nsACString& aName) -{ - nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); - if (!global) { - NS_WARNING("Passed non-global to MediaKeys ctor!"); - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - return DetailedPromise::Create(global, aRv, aName); -} - -void -MediaKeySession::SetExpiration(double aExpiration) -{ - EME_LOG("MediaKeySession[%p,'%s'] SetExpiry(%lf)", - this, - NS_ConvertUTF16toUTF8(mSessionId).get(), - aExpiration); - mExpiration = aExpiration; -} - -EventHandlerNonNull* -MediaKeySession::GetOnkeystatuseschange() -{ - return GetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString()); -} - -void -MediaKeySession::SetOnkeystatuseschange(EventHandlerNonNull* aCallback) -{ - SetEventHandler(nsGkAtoms::onkeystatuseschange, EmptyString(), aCallback); -} - -EventHandlerNonNull* -MediaKeySession::GetOnmessage() -{ - return GetEventHandler(nsGkAtoms::onmessage, EmptyString()); -} - -void -MediaKeySession::SetOnmessage(EventHandlerNonNull* aCallback) -{ - SetEventHandler(nsGkAtoms::onmessage, EmptyString(), aCallback); -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeySession.h b/dom/media/eme/MediaKeySession.h deleted file mode 100644 index 6b7137046..000000000 --- a/dom/media/eme/MediaKeySession.h +++ /dev/null @@ -1,136 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 mozilla_dom_MediaKeySession_h -#define mozilla_dom_MediaKeySession_h - -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "nsCycleCollectionParticipant.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "nsCOMPtr.h" -#include "mozilla/dom/TypedArray.h" -#include "mozilla/Mutex.h" -#include "mozilla/dom/Date.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/DetailedPromise.h" -#include "mozilla/dom/MediaKeySessionBinding.h" -#include "mozilla/dom/MediaKeysBinding.h" -#include "mozilla/dom/MediaKeyMessageEventBinding.h" - -struct JSContext; - -namespace mozilla { -namespace dom { - -class ArrayBufferViewOrArrayBuffer; -class MediaKeyError; -class MediaKeyStatusMap; - -class MediaKeySession final : public DOMEventTargetHelper -{ -public: - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaKeySession, - DOMEventTargetHelper) -public: - MediaKeySession(JSContext* aCx, - nsPIDOMWindowInner* aParent, - MediaKeys* aKeys, - const nsAString& aKeySystem, - MediaKeySessionType aSessionType, - ErrorResult& aRv); - - void SetSessionId(const nsAString& aSessionId); - - JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - // Mark this as resultNotAddRefed to return raw pointers - MediaKeyError* GetError() const; - - MediaKeyStatusMap* KeyStatuses() const; - - void GetKeySystem(nsString& aRetval) const; - - void GetSessionId(nsString& aRetval) const; - - const nsString& GetSessionId() const; - - // Number of ms since epoch at which expiration occurs, or NaN if unknown. - // TODO: The type of this attribute is still under contention. - // https://www.w3.org/Bugs/Public/show_bug.cgi?id=25902 - double Expiration() const; - - Promise* Closed() const; - - already_AddRefed<Promise> GenerateRequest(const nsAString& aInitDataType, - const ArrayBufferViewOrArrayBuffer& aInitData, - ErrorResult& aRv); - - already_AddRefed<Promise> Load(const nsAString& aSessionId, - ErrorResult& aRv); - - already_AddRefed<Promise> Update(const ArrayBufferViewOrArrayBuffer& response, - ErrorResult& aRv); - - already_AddRefed<Promise> Close(ErrorResult& aRv); - - already_AddRefed<Promise> Remove(ErrorResult& aRv); - - void DispatchKeyMessage(MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage); - - void DispatchKeyError(uint32_t system_code); - - void DispatchKeyStatusesChange(); - - void OnClosed(); - - bool IsClosed() const; - - void SetExpiration(double aExpiry); - - mozilla::dom::EventHandlerNonNull* GetOnkeystatuseschange(); - void SetOnkeystatuseschange(mozilla::dom::EventHandlerNonNull* aCallback); - - mozilla::dom::EventHandlerNonNull* GetOnmessage(); - void SetOnmessage(mozilla::dom::EventHandlerNonNull* aCallback); - - // Process-unique identifier. - uint32_t Token() const; - -private: - ~MediaKeySession(); - - void UpdateKeyStatusMap(); - - bool IsCallable() const { - // The EME spec sets the "callable value" to true whenever the CDM sets - // the sessionId. When the session is initialized, sessionId is empty and - // callable is thus false. - return !mSessionId.IsEmpty(); - } - - already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv, - const nsACString& aName); - - RefPtr<DetailedPromise> mClosed; - - RefPtr<MediaKeyError> mMediaKeyError; - RefPtr<MediaKeys> mKeys; - const nsString mKeySystem; - nsString mSessionId; - const MediaKeySessionType mSessionType; - const uint32_t mToken; - bool mIsClosed; - bool mUninitialized; - RefPtr<MediaKeyStatusMap> mKeyStatusMap; - double mExpiration; -}; - -} // namespace dom -} // namespace mozilla - -#endif diff --git a/dom/media/eme/MediaKeyStatusMap.cpp b/dom/media/eme/MediaKeyStatusMap.cpp deleted file mode 100644 index 677fd0db2..000000000 --- a/dom/media/eme/MediaKeyStatusMap.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/dom/MediaKeyStatusMap.h" -#include "nsPIDOMWindow.h" -#include "mozilla/dom/UnionTypes.h" -#include "mozilla/dom/ToJSValue.h" -#include "mozilla/EMEUtils.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeyStatusMap) -NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeyStatusMap) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeyStatusMap) - NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY - NS_INTERFACE_MAP_ENTRY(nsISupports) -NS_INTERFACE_MAP_END -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeyStatusMap, mParent) - -MediaKeyStatusMap::MediaKeyStatusMap(nsPIDOMWindowInner* aParent) - : mParent(aParent) -{ -} - -MediaKeyStatusMap::~MediaKeyStatusMap() -{ -} - -JSObject* -MediaKeyStatusMap::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeyStatusMapBinding::Wrap(aCx, this, aGivenProto); -} - -nsPIDOMWindowInner* -MediaKeyStatusMap::GetParentObject() const -{ - return mParent; -} - -void -MediaKeyStatusMap::Get(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - JS::MutableHandle<JS::Value> aOutValue, - ErrorResult& aOutRv) const -{ - ArrayData keyId = GetArrayBufferViewOrArrayBufferData(aKey); - if (!keyId.IsValid()) { - aOutValue.setUndefined(); - return; - } - for (const KeyStatus& status : mStatuses) { - if (keyId == status.mKeyId) { - bool ok = ToJSValue(aCx, status.mStatus, aOutValue);
- if (!ok) {
- aOutRv.NoteJSContextException(aCx);
- }
- return; - } - } - aOutValue.setUndefined(); -} - -bool -MediaKeyStatusMap::Has(const ArrayBufferViewOrArrayBuffer& aKey) const -{ - ArrayData keyId = GetArrayBufferViewOrArrayBufferData(aKey); - if (!keyId.IsValid()) { - return false; - } - - for (const KeyStatus& status : mStatuses) { - if (keyId == status.mKeyId) { - return true; - } - } - - return false; -} - -uint32_t -MediaKeyStatusMap::GetIterableLength() const -{ - return mStatuses.Length(); -} - -TypedArrayCreator<ArrayBuffer> -MediaKeyStatusMap::GetKeyAtIndex(uint32_t aIndex) const -{ - MOZ_ASSERT(aIndex < GetIterableLength()); - return TypedArrayCreator<ArrayBuffer>(mStatuses[aIndex].mKeyId); -} - -MediaKeyStatus -MediaKeyStatusMap::GetValueAtIndex(uint32_t aIndex) const -{ - MOZ_ASSERT(aIndex < GetIterableLength()); - return mStatuses[aIndex].mStatus; -} - -uint32_t -MediaKeyStatusMap::Size() const -{ - return mStatuses.Length(); -} - -void -MediaKeyStatusMap::Update(const nsTArray<CDMCaps::KeyStatus>& aKeys) -{ - mStatuses.Clear(); - for (const auto& key : aKeys) { - mStatuses.InsertElementSorted(KeyStatus(key.mId, key.mStatus)); - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeyStatusMap.h b/dom/media/eme/MediaKeyStatusMap.h deleted file mode 100644 index 8bfbd4d07..000000000 --- a/dom/media/eme/MediaKeyStatusMap.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 mozilla_dom_MediaKeyStatuses_h -#define mozilla_dom_MediaKeyStatuses_h - -#include "mozilla/ErrorResult.h" -#include "mozilla/Attributes.h" -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" - -#include "mozilla/dom/TypedArray.h" -#include "mozilla/dom/MediaKeyStatusMapBinding.h" -#include "mozilla/CDMCaps.h" - -class nsPIDOMWindowInner; - -namespace mozilla { -namespace dom { - -class ArrayBufferViewOrArrayBuffer; - -// The MediaKeyStatusMap WebIDL interface; maps a keyId to its status. -// Note that the underlying "map" is stored in an array, since we assume -// that a MediaKeySession won't have many key statuses to report. -class MediaKeyStatusMap final : public nsISupports, - public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeyStatusMap) - -public: - explicit MediaKeyStatusMap(nsPIDOMWindowInner* aParent); - -protected: - ~MediaKeyStatusMap(); - -public: - nsPIDOMWindowInner* GetParentObject() const; - - JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - void Get(JSContext* aCx, - const ArrayBufferViewOrArrayBuffer& aKey, - JS::MutableHandle<JS::Value> aOutValue, - ErrorResult& aOutRv) const; - bool Has(const ArrayBufferViewOrArrayBuffer& aKey) const; - uint32_t Size() const; - - uint32_t GetIterableLength() const; - TypedArrayCreator<ArrayBuffer> GetKeyAtIndex(uint32_t aIndex) const; - MediaKeyStatus GetValueAtIndex(uint32_t aIndex) const; - - void Update(const nsTArray<CDMCaps::KeyStatus>& keys); - -private: - - nsCOMPtr<nsPIDOMWindowInner> mParent; - - struct KeyStatus { - KeyStatus(const nsTArray<uint8_t>& aKeyId, - MediaKeyStatus aStatus) - : mKeyId(aKeyId) - , mStatus(aStatus) - { - } - bool operator== (const KeyStatus& aOther) const { - return aOther.mKeyId == mKeyId; - } - bool operator<(const KeyStatus& aOther) const { - // Copy chromium and compare keys' bytes. - // Update once https://github.com/w3c/encrypted-media/issues/69 - // is resolved. - const nsTArray<uint8_t>& other = aOther.mKeyId; - const nsTArray<uint8_t>& self = mKeyId; - size_t length = std::min<size_t>(other.Length(), self.Length()); - int cmp = memcmp(self.Elements(), other.Elements(), length); - if (cmp != 0) { - return cmp < 0; - } - return self.Length() <= other.Length(); - } - nsTArray<uint8_t> mKeyId; - MediaKeyStatus mStatus; - }; - - nsTArray<KeyStatus> mStatuses; -}; - -} // namespace dom -} // namespace mozilla - -#endif diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp deleted file mode 100644 index c65c57ed0..000000000 --- a/dom/media/eme/MediaKeySystemAccess.cpp +++ /dev/null @@ -1,1042 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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/. */ - -#include "mozilla/dom/MediaKeySystemAccess.h" -#include "mozilla/dom/MediaKeySystemAccessBinding.h" -#include "mozilla/Preferences.h" -#include "MediaPrefs.h" -#include "nsContentTypeParser.h" -#ifdef MOZ_FMP4 -#include "MP4Decoder.h" -#endif -#ifdef XP_WIN -#include "mozilla/WindowsVersion.h" -#include "WMFDecoderModule.h" -#endif -#include "nsContentCID.h" -#include "nsServiceManagerUtils.h" -#include "mozIGeckoMediaPluginService.h" -#include "VideoUtils.h" -#include "mozilla/Services.h" -#include "nsIObserverService.h" -#include "mozilla/EMEUtils.h" -#include "GMPUtils.h" -#include "nsAppDirectoryServiceDefs.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsXULAppAPI.h" -#include "gmp-audio-decode.h" -#include "gmp-video-decode.h" -#include "DecoderDoctorDiagnostics.h" -#include "WebMDecoder.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/ClearOnShutdown.h" -#include "nsUnicharUtils.h" -#include "mozilla/dom/MediaSource.h" -#include "DecoderTraits.h" - -namespace mozilla { -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeySystemAccess, - mParent) -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(nsPIDOMWindowInner* aParent, - const nsAString& aKeySystem, - const MediaKeySystemConfiguration& aConfig) - : mParent(aParent) - , mKeySystem(aKeySystem) - , mConfig(aConfig) -{ -} - -MediaKeySystemAccess::~MediaKeySystemAccess() -{ -} - -JSObject* -MediaKeySystemAccess::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeySystemAccessBinding::Wrap(aCx, this, aGivenProto); -} - -nsPIDOMWindowInner* -MediaKeySystemAccess::GetParentObject() const -{ - return mParent; -} - -void -MediaKeySystemAccess::GetKeySystem(nsString& aOutKeySystem) const -{ - aOutKeySystem.Assign(mKeySystem); -} - -void -MediaKeySystemAccess::GetConfiguration(MediaKeySystemConfiguration& aConfig) -{ - aConfig = mConfig; -} - -already_AddRefed<Promise> -MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv) -{ - RefPtr<MediaKeys> keys(new MediaKeys(mParent, - mKeySystem, - mConfig)); - return keys->Init(aRv); -} - -static bool -HavePluginForKeySystem(const nsCString& aKeySystem) -{ - bool havePlugin = HaveGMPFor(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR), - { aKeySystem }); - return havePlugin; -} - -static MediaKeySystemStatus -EnsureCDMInstalled(const nsAString& aKeySystem, - nsACString& aOutMessage) -{ - if (!HavePluginForKeySystem(NS_ConvertUTF16toUTF8(aKeySystem))) { - aOutMessage = NS_LITERAL_CSTRING("CDM is not installed"); - return MediaKeySystemStatus::Cdm_not_installed; - } - - return MediaKeySystemStatus::Available; -} - -/* static */ -MediaKeySystemStatus -MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem, - nsACString& aOutMessage) -{ - MOZ_ASSERT(MediaPrefs::EMEEnabled() || IsClearkeyKeySystem(aKeySystem)); - - if (IsClearkeyKeySystem(aKeySystem)) { - return EnsureCDMInstalled(aKeySystem, aOutMessage); - } - - if (IsWidevineKeySystem(aKeySystem)) { - if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) { - if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) { - aOutMessage = NS_LITERAL_CSTRING("Widevine EME disabled"); - return MediaKeySystemStatus::Cdm_disabled; - } - return EnsureCDMInstalled(aKeySystem, aOutMessage); - } - } - - return MediaKeySystemStatus::Cdm_not_supported; -} - -typedef nsCString EMECodecString; - -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_AAC, "aac"); -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_OPUS, "opus"); -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VORBIS, "vorbis"); -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_H264, "h264"); -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VP8, "vp8"); -static NS_NAMED_LITERAL_CSTRING(EME_CODEC_VP9, "vp9"); - -EMECodecString -ToEMEAPICodecString(const nsString& aCodec) -{ - if (IsAACCodecString(aCodec)) { - return EME_CODEC_AAC; - } - if (aCodec.EqualsLiteral("opus")) { - return EME_CODEC_OPUS; - } - if (aCodec.EqualsLiteral("vorbis")) { - return EME_CODEC_VORBIS; - } - if (IsH264CodecString(aCodec)) { - return EME_CODEC_H264; - } - if (IsVP8CodecString(aCodec)) { - return EME_CODEC_VP8; - } - if (IsVP9CodecString(aCodec)) { - return EME_CODEC_VP9; - } - return EmptyCString(); -} - -// A codec can be decrypted-and-decoded by the CDM, or only decrypted -// by the CDM and decoded by Gecko. Not both. -struct KeySystemContainerSupport -{ - bool IsSupported() const - { - return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty(); - } - - // CDM decrypts and decodes using a DRM robust decoder, and passes decoded - // samples back to Gecko for rendering. - bool DecryptsAndDecodes(EMECodecString aCodec) const - { - return mCodecsDecoded.Contains(aCodec); - } - - // CDM decrypts and passes the decrypted samples back to Gecko for decoding. - bool Decrypts(EMECodecString aCodec) const - { - return mCodecsDecrypted.Contains(aCodec); - } - - void SetCanDecryptAndDecode(EMECodecString aCodec) - { - // Can't both decrypt and decrypt-and-decode a codec. - MOZ_ASSERT(!Decrypts(aCodec)); - // Prevent duplicates. - MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); - mCodecsDecoded.AppendElement(aCodec); - } - - void SetCanDecrypt(EMECodecString aCodec) - { - // Prevent duplicates. - MOZ_ASSERT(!Decrypts(aCodec)); - // Can't both decrypt and decrypt-and-decode a codec. - MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); - mCodecsDecrypted.AppendElement(aCodec); - } - -private: - nsTArray<EMECodecString> mCodecsDecoded; - nsTArray<EMECodecString> mCodecsDecrypted; -}; - -enum class KeySystemFeatureSupport -{ - Prohibited = 1, - Requestable = 2, - Required = 3, -}; - -struct KeySystemConfig -{ - nsString mKeySystem; - nsTArray<nsString> mInitDataTypes; - KeySystemFeatureSupport mPersistentState = KeySystemFeatureSupport::Prohibited; - KeySystemFeatureSupport mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; - nsTArray<MediaKeySessionType> mSessionTypes; - nsTArray<nsString> mVideoRobustness; - nsTArray<nsString> mAudioRobustness; - KeySystemContainerSupport mMP4; - KeySystemContainerSupport mWebM; -}; - -static nsTArray<KeySystemConfig> -GetSupportedKeySystems() -{ - nsTArray<KeySystemConfig> keySystemConfigs; - - { - if (HavePluginForKeySystem(kEMEKeySystemClearkey)) { - KeySystemConfig clearkey; - clearkey.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemClearkey); - clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc")); - clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids")); - clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm")); - clearkey.mPersistentState = KeySystemFeatureSupport::Requestable; - clearkey.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; - clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Temporary); - if (MediaPrefs::ClearKeyPersistentLicenseEnabled()) { - clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license); - } -#if defined(XP_WIN) - // Clearkey CDM uses WMF decoders on Windows. - if (WMFDecoderModule::HasAAC()) { - clearkey.mMP4.SetCanDecryptAndDecode(EME_CODEC_AAC); - } else { - clearkey.mMP4.SetCanDecrypt(EME_CODEC_AAC); - } - if (WMFDecoderModule::HasH264()) { - clearkey.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264); - } else { - clearkey.mMP4.SetCanDecrypt(EME_CODEC_H264); - } -#else - clearkey.mMP4.SetCanDecrypt(EME_CODEC_AAC); - clearkey.mMP4.SetCanDecrypt(EME_CODEC_H264); -#endif - clearkey.mWebM.SetCanDecrypt(EME_CODEC_VORBIS); - clearkey.mWebM.SetCanDecrypt(EME_CODEC_OPUS); - clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP8); - clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP9); - keySystemConfigs.AppendElement(Move(clearkey)); - } - } - { - if (HavePluginForKeySystem(kEMEKeySystemWidevine)) { - KeySystemConfig widevine; - widevine.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemWidevine); - widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc")); - widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids")); - widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm")); - widevine.mPersistentState = KeySystemFeatureSupport::Requestable; - widevine.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; - widevine.mSessionTypes.AppendElement(MediaKeySessionType::Temporary); - widevine.mAudioRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO")); - widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_DECODE")); -#if defined(XP_WIN) - // Widevine CDM doesn't include an AAC decoder. So if WMF can't - // decode AAC, and a codec wasn't specified, be conservative - // and reject the MediaKeys request, since our policy is to prevent - // the Adobe GMP's unencrypted AAC decoding path being used to - // decode content decrypted by the Widevine CDM. - if (WMFDecoderModule::HasAAC()) { - widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC); - } -#endif - - widevine.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264); - widevine.mWebM.SetCanDecrypt(EME_CODEC_VORBIS); - widevine.mWebM.SetCanDecrypt(EME_CODEC_OPUS); - widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP8); - widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP9); - keySystemConfigs.AppendElement(Move(widevine)); - } - } - - return keySystemConfigs; -} - -static bool -GetKeySystemConfig(const nsAString& aKeySystem, KeySystemConfig& aOutKeySystemConfig) -{ - for (auto&& config : GetSupportedKeySystems()) { - if (config.mKeySystem.Equals(aKeySystem)) { - aOutKeySystemConfig = mozilla::Move(config); - return true; - } - } - // No matching key system found. - return false; -} - -/* static */ -bool -MediaKeySystemAccess::KeySystemSupportsInitDataType(const nsAString& aKeySystem, - const nsAString& aInitDataType) -{ - KeySystemConfig implementation; - return GetKeySystemConfig(aKeySystem, implementation) && - implementation.mInitDataTypes.Contains(aInitDataType); -} - -enum CodecType -{ - Audio, - Video, - Invalid -}; - -static bool -CanDecryptAndDecode(const nsString& aKeySystem, - const nsString& aContentType, - CodecType aCodecType, - const KeySystemContainerSupport& aContainerSupport, - const nsTArray<EMECodecString>& aCodecs, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(aCodecType != Invalid); - for (const EMECodecString& codec : aCodecs) { - MOZ_ASSERT(!codec.IsEmpty()); - - if (aContainerSupport.DecryptsAndDecodes(codec)) { - // GMP can decrypt-and-decode this codec. - continue; - } - - if (aContainerSupport.Decrypts(codec) && - NS_SUCCEEDED(MediaSource::IsTypeSupported(aContentType, aDiagnostics))) { - // GMP can decrypt and is allowed to return compressed samples to - // Gecko to decode, and Gecko has a decoder. - continue; - } - - // Neither the GMP nor Gecko can both decrypt and decode. We don't - // support this codec. - -#if defined(XP_WIN) - // Widevine CDM doesn't include an AAC decoder. So if WMF can't - // decode AAC, and a codec wasn't specified, be conservative - // and reject the MediaKeys request, since our policy is to prevent - // the Adobe GMP's unencrypted AAC decoding path being used to - // decode content decrypted by the Widevine CDM. - if (codec == EME_CODEC_AAC && - IsWidevineKeySystem(aKeySystem) && - !WMFDecoderModule::HasAAC()) { - if (aDiagnostics) { - aDiagnostics->SetKeySystemIssue( - DecoderDoctorDiagnostics::eWidevineWithNoWMF); - } - } -#endif - return false; - } - return true; -} - -static bool -ToSessionType(const nsAString& aSessionType, MediaKeySessionType& aOutType) -{ - using MediaKeySessionTypeValues::strings; - const char* temporary = - strings[static_cast<uint32_t>(MediaKeySessionType::Temporary)].value; - if (aSessionType.EqualsASCII(temporary)) { - aOutType = MediaKeySessionType::Temporary; - return true; - } - const char* persistentLicense = - strings[static_cast<uint32_t>(MediaKeySessionType::Persistent_license)].value; - if (aSessionType.EqualsASCII(persistentLicense)) { - aOutType = MediaKeySessionType::Persistent_license; - return true; - } - return false; -} - -// 5.2.1 Is persistent session type? -static bool -IsPersistentSessionType(MediaKeySessionType aSessionType) -{ - return aSessionType == MediaKeySessionType::Persistent_license; -} - -CodecType -GetMajorType(const nsAString& aContentType) -{ - if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("audio/"), aContentType)) { - return Audio; - } - if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("video/"), aContentType)) { - return Video; - } - return Invalid; -} - -static CodecType -GetCodecType(const EMECodecString& aCodec) -{ - if (aCodec.Equals(EME_CODEC_AAC) || - aCodec.Equals(EME_CODEC_OPUS) || - aCodec.Equals(EME_CODEC_VORBIS)) { - return Audio; - } - if (aCodec.Equals(EME_CODEC_H264) || - aCodec.Equals(EME_CODEC_VP8) || - aCodec.Equals(EME_CODEC_VP9)) { - return Video; - } - return Invalid; -} - -static bool -AllCodecsOfType(const nsTArray<EMECodecString>& aCodecs, const CodecType aCodecType) -{ - for (const EMECodecString& codec : aCodecs) { - if (GetCodecType(codec) != aCodecType) { - return false; - } - } - return true; -} - -static bool -IsParameterUnrecognized(const nsAString& aContentType) -{ - nsAutoString contentType(aContentType); - contentType.StripWhitespace(); - - nsTArray<nsString> params; - nsAString::const_iterator start, end, semicolon, equalSign; - contentType.BeginReading(start); - contentType.EndReading(end); - semicolon = start; - // Find any substring between ';' & '='. - while (semicolon != end) { - if (FindCharInReadable(';', semicolon, end)) { - equalSign = ++semicolon; - if (FindCharInReadable('=', equalSign, end)) { - params.AppendElement(Substring(semicolon, equalSign)); - semicolon = equalSign; - } - } - } - - for (auto param : params) { - if (!param.LowerCaseEqualsLiteral("codecs") && - !param.LowerCaseEqualsLiteral("profiles")) { - return true; - } - } - return false; -} - -// 3.1.2.3 Get Supported Capabilities for Audio/Video Type -static Sequence<MediaKeySystemMediaCapability> -GetSupportedCapabilities(const CodecType aCodecType, - const nsTArray<MediaKeySystemMediaCapability>& aRequestedCapabilities, - const MediaKeySystemConfiguration& aPartialConfig, - const KeySystemConfig& aKeySystem, - DecoderDoctorDiagnostics* aDiagnostics) -{ - // Let local accumulated configuration be a local copy of partial configuration. - // (Note: It's not necessary for us to maintain a local copy, as we don't need - // to test whether capabilites from previous calls to this algorithm work with - // the capabilities currently being considered in this call. ) - - // Let supported media capabilities be an empty sequence of - // MediaKeySystemMediaCapability dictionaries. - Sequence<MediaKeySystemMediaCapability> supportedCapabilities; - - // For each requested media capability in requested media capabilities: - for (const MediaKeySystemMediaCapability& capabilities : aRequestedCapabilities) { - // Let content type be requested media capability's contentType member. - const nsString& contentType = capabilities.mContentType; - // Let robustness be requested media capability's robustness member. - const nsString& robustness = capabilities.mRobustness; - // If content type is the empty string, return null. - if (contentType.IsEmpty()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') rejected; " - "audio or video capability has empty contentType.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - return Sequence<MediaKeySystemMediaCapability>(); - } - // If content type is an invalid or unrecognized MIME type, continue - // to the next iteration. - nsAutoString container; - nsTArray<nsString> codecStrings; - if (!ParseMIMETypeString(contentType, container, codecStrings)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "failed to parse contentType as MIME type.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - bool invalid = false; - nsTArray<EMECodecString> codecs; - for (const nsString& codecString : codecStrings) { - EMECodecString emeCodec = ToEMEAPICodecString(codecString); - if (emeCodec.IsEmpty()) { - invalid = true; - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "'%s' is an invalid codec string.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get(), - NS_ConvertUTF16toUTF8(codecString).get()); - break; - } - codecs.AppendElement(emeCodec); - } - if (invalid) { - continue; - } - - // If the user agent does not support container, continue to the next iteration. - // The case-sensitivity of string comparisons is determined by the appropriate RFC. - // (Note: Per RFC 6838 [RFC6838], "Both top-level type and subtype names are - // case-insensitive."'. We're using nsContentTypeParser and that is - // case-insensitive and converts all its parameter outputs to lower case.) - NS_ConvertUTF16toUTF8 container_utf8(container); - const bool isMP4 = DecoderTraits::IsMP4TypeAndEnabled(container_utf8, aDiagnostics); - if (isMP4 && !aKeySystem.mMP4.IsSupported()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "MP4 requested but unsupported.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - const bool isWebM = DecoderTraits::IsWebMTypeAndEnabled(container_utf8); - if (isWebM && !aKeySystem.mWebM.IsSupported()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "WebM requested but unsupported.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - if (!isMP4 && !isWebM) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "Unsupported or unrecognized container requested.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - - // Let parameters be the RFC 6381[RFC6381] parameters, if any, specified by - // content type. - // If the user agent does not recognize one or more parameters, continue to - // the next iteration. - if (IsParameterUnrecognized(contentType)) { - continue; - } - - // Let media types be the set of codecs and codec constraints specified by - // parameters. The case-sensitivity of string comparisons is determined by - // the appropriate RFC or other specification. - // (Note: codecs array is 'parameter'). - - // If media types is empty: - if (codecs.IsEmpty()) { - // If container normatively implies a specific set of codecs and codec constraints: - // Let parameters be that set. - if (isMP4) { - if (aCodecType == Audio) { - codecs.AppendElement(EME_CODEC_AAC); - } else if (aCodecType == Video) { - codecs.AppendElement(EME_CODEC_H264); - } - } else if (isWebM) { - if (aCodecType == Audio) { - codecs.AppendElement(EME_CODEC_VORBIS); - } else if (aCodecType == Video) { - codecs.AppendElement(EME_CODEC_VP8); - } - } - // Otherwise: Continue to the next iteration. - // (Note: all containers we support have implied codecs, so don't continue here.) - } - - // If content type is not strictly a audio/video type, continue to the next iteration. - const auto majorType = GetMajorType(container); - if (majorType == Invalid) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "MIME type is not an audio or video MIME type.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - if (majorType != aCodecType || !AllCodecsOfType(codecs, aCodecType)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "MIME type mixes audio codecs in video capabilities " - "or video codecs in audio capabilities.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - // If robustness is not the empty string and contains an unrecognized - // value or a value not supported by implementation, continue to the - // next iteration. String comparison is case-sensitive. - if (!robustness.IsEmpty()) { - if (majorType == Audio && !aKeySystem.mAudioRobustness.Contains(robustness)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "unsupported robustness string.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - if (majorType == Video && !aKeySystem.mVideoRobustness.Contains(robustness)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "unsupported robustness string.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - // Note: specified robustness requirements are satisfied. - } - - // If the user agent and implementation definitely support playback of - // encrypted media data for the combination of container, media types, - // robustness and local accumulated configuration in combination with - // restrictions... - const auto& containerSupport = isMP4 ? aKeySystem.mMP4 : aKeySystem.mWebM; - if (!CanDecryptAndDecode(aKeySystem.mKeySystem, - contentType, - majorType, - containerSupport, - codecs, - aDiagnostics)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') " - "MediaKeySystemMediaCapability('%s','%s') unsupported; " - "codec unsupported by CDM requested.", - NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), - NS_ConvertUTF16toUTF8(contentType).get(), - NS_ConvertUTF16toUTF8(robustness).get()); - continue; - } - - // ... add requested media capability to supported media capabilities. - if (!supportedCapabilities.AppendElement(capabilities, mozilla::fallible)) { - NS_WARNING("GetSupportedCapabilities: Malloc failure"); - return Sequence<MediaKeySystemMediaCapability>(); - } - - // Note: omitting steps 3.13.2, our robustness is not sophisticated enough - // to require considering all requirements together. - } - return Move(supportedCapabilities); -} - -// "Get Supported Configuration and Consent" algorithm, steps 4-7 for -// distinctive identifier, and steps 8-11 for persistent state. The steps -// are the same for both requirements/features, so we factor them out into -// a single function. -static bool -CheckRequirement(const MediaKeysRequirement aRequirement, - const KeySystemFeatureSupport aFeatureSupport, - MediaKeysRequirement& aOutRequirement) -{ - // Let requirement be the value of candidate configuration's member. - MediaKeysRequirement requirement = aRequirement; - // If requirement is "optional" and feature is not allowed according to - // restrictions, set requirement to "not-allowed". - if (aRequirement == MediaKeysRequirement::Optional && - aFeatureSupport == KeySystemFeatureSupport::Prohibited) { - requirement = MediaKeysRequirement::Not_allowed; - } - - // Follow the steps for requirement from the following list: - switch (requirement) { - case MediaKeysRequirement::Required: { - // If the implementation does not support use of requirement in combination - // with accumulated configuration and restrictions, return NotSupported. - if (aFeatureSupport == KeySystemFeatureSupport::Prohibited) { - return false; - } - break; - } - case MediaKeysRequirement::Optional: { - // Continue with the following steps. - break; - } - case MediaKeysRequirement::Not_allowed: { - // If the implementation requires use of feature in combination with - // accumulated configuration and restrictions, return NotSupported. - if (aFeatureSupport == KeySystemFeatureSupport::Required) { - return false; - } - break; - } - default: { - return false; - } - } - - // Set the requirement member of accumulated configuration to equal - // calculated requirement. - aOutRequirement = requirement; - - return true; -} - -// 3.1.2.2, step 12 -// Follow the steps for the first matching condition from the following list: -// If the sessionTypes member is present in candidate configuration. -// Let session types be candidate configuration's sessionTypes member. -// Otherwise let session types be ["temporary"]. -// Note: This returns an empty array on malloc failure. -static Sequence<nsString> -UnboxSessionTypes(const Optional<Sequence<nsString>>& aSessionTypes) -{ - Sequence<nsString> sessionTypes; - if (aSessionTypes.WasPassed()) { - sessionTypes = aSessionTypes.Value(); - } else { - using MediaKeySessionTypeValues::strings; - const char* temporary = strings[static_cast<uint32_t>(MediaKeySessionType::Temporary)].value; - // Note: fallible. Results in an empty array. - sessionTypes.AppendElement(NS_ConvertUTF8toUTF16(nsDependentCString(temporary)), mozilla::fallible); - } - return sessionTypes; -} - -// 3.1.2.2 Get Supported Configuration and Consent -static bool -GetSupportedConfig(const KeySystemConfig& aKeySystem, - const MediaKeySystemConfiguration& aCandidate, - MediaKeySystemConfiguration& aOutConfig, - DecoderDoctorDiagnostics* aDiagnostics) -{ - // Let accumulated configuration be a new MediaKeySystemConfiguration dictionary. - MediaKeySystemConfiguration config; - // Set the label member of accumulated configuration to equal the label member of - // candidate configuration. - config.mLabel = aCandidate.mLabel; - // If the initDataTypes member of candidate configuration is non-empty, run the - // following steps: - if (!aCandidate.mInitDataTypes.IsEmpty()) { - // Let supported types be an empty sequence of DOMStrings. - nsTArray<nsString> supportedTypes; - // For each value in candidate configuration's initDataTypes member: - for (const nsString& initDataType : aCandidate.mInitDataTypes) { - // Let initDataType be the value. - // If the implementation supports generating requests based on initDataType, - // add initDataType to supported types. String comparison is case-sensitive. - // The empty string is never supported. - if (aKeySystem.mInitDataTypes.Contains(initDataType)) { - supportedTypes.AppendElement(initDataType); - } - } - // If supported types is empty, return NotSupported. - if (supportedTypes.IsEmpty()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "no supported initDataTypes provided.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - // Set the initDataTypes member of accumulated configuration to supported types. - if (!config.mInitDataTypes.Assign(supportedTypes)) { - return false; - } - } - - if (!CheckRequirement(aCandidate.mDistinctiveIdentifier, - aKeySystem.mDistinctiveIdentifier, - config.mDistinctiveIdentifier)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "distinctiveIdentifier requirement not satisfied.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - - if (!CheckRequirement(aCandidate.mPersistentState, - aKeySystem.mPersistentState, - config.mPersistentState)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "persistentState requirement not satisfied.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - - Sequence<nsString> sessionTypes(UnboxSessionTypes(aCandidate.mSessionTypes)); - if (sessionTypes.IsEmpty()) { - // Malloc failure. - return false; - } - - // For each value in session types: - for (const auto& sessionTypeString : sessionTypes) { - // Let session type be the value. - MediaKeySessionType sessionType; - if (!ToSessionType(sessionTypeString, sessionType)) { - // (Assume invalid sessionType is unsupported as per steps below). - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "invalid session type specified.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - // If accumulated configuration's persistentState value is "not-allowed" - // and the Is persistent session type? algorithm returns true for session - // type return NotSupported. - if (config.mPersistentState == MediaKeysRequirement::Not_allowed && - IsPersistentSessionType(sessionType)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "persistent session requested but keysystem doesn't" - "support persistent state.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - // If the implementation does not support session type in combination - // with accumulated configuration and restrictions for other reasons, - // return NotSupported. - if (!aKeySystem.mSessionTypes.Contains(sessionType)) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "session type '%s' unsupported by keySystem.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get(), - NS_ConvertUTF16toUTF8(sessionTypeString).get()); - return false; - } - // If accumulated configuration's persistentState value is "optional" - // and the result of running the Is persistent session type? algorithm - // on session type is true, change accumulated configuration's - // persistentState value to "required". - if (config.mPersistentState == MediaKeysRequirement::Optional && - IsPersistentSessionType(sessionType)) { - config.mPersistentState = MediaKeysRequirement::Required; - } - } - // Set the sessionTypes member of accumulated configuration to session types. - config.mSessionTypes.Construct(Move(sessionTypes)); - - // If the videoCapabilities and audioCapabilities members in candidate - // configuration are both empty, return NotSupported. - // TODO: Most sites using EME still don't pass capabilities, so we - // can't reject on it yet without breaking them. So add this later. - - // If the videoCapabilities member in candidate configuration is non-empty: - if (!aCandidate.mVideoCapabilities.IsEmpty()) { - // Let video capabilities be the result of executing the Get Supported - // Capabilities for Audio/Video Type algorithm on Video, candidate - // configuration's videoCapabilities member, accumulated configuration, - // and restrictions. - Sequence<MediaKeySystemMediaCapability> caps = - GetSupportedCapabilities(Video, - aCandidate.mVideoCapabilities, - config, - aKeySystem, - aDiagnostics); - // If video capabilities is null, return NotSupported. - if (caps.IsEmpty()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "no supported video capabilities.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - // Set the videoCapabilities member of accumulated configuration to video capabilities. - config.mVideoCapabilities = Move(caps); - } else { - // Otherwise: - // Set the videoCapabilities member of accumulated configuration to an empty sequence. - } - - // If the audioCapabilities member in candidate configuration is non-empty: - if (!aCandidate.mAudioCapabilities.IsEmpty()) { - // Let audio capabilities be the result of executing the Get Supported Capabilities - // for Audio/Video Type algorithm on Audio, candidate configuration's audioCapabilities - // member, accumulated configuration, and restrictions. - Sequence<MediaKeySystemMediaCapability> caps = - GetSupportedCapabilities(Audio, - aCandidate.mAudioCapabilities, - config, - aKeySystem, - aDiagnostics); - // If audio capabilities is null, return NotSupported. - if (caps.IsEmpty()) { - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "no supported audio capabilities.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } - // Set the audioCapabilities member of accumulated configuration to audio capabilities. - config.mAudioCapabilities = Move(caps); - } else { - // Otherwise: - // Set the audioCapabilities member of accumulated configuration to an empty sequence. - } - - // If accumulated configuration's distinctiveIdentifier value is "optional", follow the - // steps for the first matching condition from the following list: - if (config.mDistinctiveIdentifier == MediaKeysRequirement::Optional) { - // If the implementation requires use Distinctive Identifier(s) or - // Distinctive Permanent Identifier(s) for any of the combinations - // in accumulated configuration - if (aKeySystem.mDistinctiveIdentifier == KeySystemFeatureSupport::Required) { - // Change accumulated configuration's distinctiveIdentifier value to "required". - config.mDistinctiveIdentifier = MediaKeysRequirement::Required; - } else { - // Otherwise, change accumulated configuration's distinctiveIdentifier - // value to "not-allowed". - config.mDistinctiveIdentifier = MediaKeysRequirement::Not_allowed; - } - } - - // If accumulated configuration's persistentState value is "optional", follow the - // steps for the first matching condition from the following list: - if (config.mPersistentState == MediaKeysRequirement::Optional) { - // If the implementation requires persisting state for any of the combinations - // in accumulated configuration - if (aKeySystem.mPersistentState == KeySystemFeatureSupport::Required) { - // Change accumulated configuration's persistentState value to "required". - config.mPersistentState = MediaKeysRequirement::Required; - } else { - // Otherwise, change accumulated configuration's persistentState - // value to "not-allowed". - config.mPersistentState = MediaKeysRequirement::Not_allowed; - } - } - - // Note: Omitting steps 20-22. We don't ask for consent. - -#if defined(XP_WIN) - // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC, - // and a codec wasn't specified, be conservative and reject the MediaKeys request. - if (IsWidevineKeySystem(aKeySystem.mKeySystem) && - (aCandidate.mAudioCapabilities.IsEmpty() || - aCandidate.mVideoCapabilities.IsEmpty()) && - !WMFDecoderModule::HasAAC()) { - if (aDiagnostics) { - aDiagnostics->SetKeySystemIssue( - DecoderDoctorDiagnostics::eWidevineWithNoWMF); - } - EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " - "WMF required for Widevine decoding, but it's not available.", - NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); - return false; - } -#endif - - // Return accumulated configuration. - aOutConfig = config; - - return true; -} - -/* static */ -bool -MediaKeySystemAccess::GetSupportedConfig(const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs, - MediaKeySystemConfiguration& aOutConfig, - DecoderDoctorDiagnostics* aDiagnostics) -{ - KeySystemConfig implementation; - if (!GetKeySystemConfig(aKeySystem, implementation)) { - return false; - } - for (const MediaKeySystemConfiguration& candidate : aConfigs) { - if (mozilla::dom::GetSupportedConfig(implementation, - candidate, - aOutConfig, - aDiagnostics)) { - return true; - } - } - - return false; -} - - -/* static */ -void -MediaKeySystemAccess::NotifyObservers(nsPIDOMWindowInner* aWindow, - const nsAString& aKeySystem, - MediaKeySystemStatus aStatus) -{ - RequestMediaKeySystemAccessNotification data; - data.mKeySystem = aKeySystem; - data.mStatus = aStatus; - nsAutoString json; - data.ToJSON(json); - EME_LOG("MediaKeySystemAccess::NotifyObservers() %s", NS_ConvertUTF16toUTF8(json).get()); - nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); - if (obs) { - obs->NotifyObservers(aWindow, "mediakeys-request", json.get()); - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeySystemAccess.h b/dom/media/eme/MediaKeySystemAccess.h deleted file mode 100644 index a166ac22e..000000000 --- a/dom/media/eme/MediaKeySystemAccess.h +++ /dev/null @@ -1,81 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* 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 mozilla_dom_MediaKeySystemAccess_h -#define mozilla_dom_MediaKeySystemAccess_h - -#include "mozilla/Attributes.h" -#include "mozilla/ErrorResult.h" -#include "nsCycleCollectionParticipant.h" -#include "nsWrapperCache.h" - -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/MediaKeySystemAccessBinding.h" -#include "mozilla/dom/MediaKeysRequestStatusBinding.h" - -#include "js/TypeDecls.h" - -namespace mozilla { - -class DecoderDoctorDiagnostics; - -namespace dom { - -class MediaKeySystemAccess final : public nsISupports, - public nsWrapperCache -{ -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeySystemAccess) - -public: - explicit MediaKeySystemAccess(nsPIDOMWindowInner* aParent, - const nsAString& aKeySystem, - const MediaKeySystemConfiguration& aConfig); - -protected: - ~MediaKeySystemAccess(); - -public: - nsPIDOMWindowInner* GetParentObject() const; - - JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - void GetKeySystem(nsString& aRetVal) const; - - void GetConfiguration(MediaKeySystemConfiguration& aConfig); - - already_AddRefed<Promise> CreateMediaKeys(ErrorResult& aRv); - - static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem, - nsACString& aOutExceptionMessage); - - static bool IsSupported(const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs, - DecoderDoctorDiagnostics* aDiagnostics); - - static void NotifyObservers(nsPIDOMWindowInner* aWindow, - const nsAString& aKeySystem, - MediaKeySystemStatus aStatus); - - static bool GetSupportedConfig(const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs, - MediaKeySystemConfiguration& aOutConfig, - DecoderDoctorDiagnostics* aDiagnostics); - - static bool KeySystemSupportsInitDataType(const nsAString& aKeySystem, - const nsAString& aInitDataType); - -private: - nsCOMPtr<nsPIDOMWindowInner> mParent; - const nsString mKeySystem; - const MediaKeySystemConfiguration mConfig; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_MediaKeySystemAccess_h diff --git a/dom/media/eme/MediaKeySystemAccessManager.cpp b/dom/media/eme/MediaKeySystemAccessManager.cpp deleted file mode 100644 index a1e1254ad..000000000 --- a/dom/media/eme/MediaKeySystemAccessManager.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* 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/. */ - -#include "MediaKeySystemAccessManager.h" -#include "DecoderDoctorDiagnostics.h" -#include "MediaPrefs.h" -#include "mozilla/EMEUtils.h" -#include "nsServiceManagerUtils.h" -#include "nsComponentManagerUtils.h" -#include "nsIObserverService.h" -#include "mozilla/Services.h" -#include "mozilla/DetailedPromise.h" -#ifdef XP_WIN -#include "mozilla/WindowsVersion.h" -#endif -#include "nsPrintfCString.h" - -namespace mozilla { -namespace dom { - -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeySystemAccessManager) - NS_INTERFACE_MAP_ENTRY(nsISupports) - NS_INTERFACE_MAP_ENTRY(nsIObserver) -NS_INTERFACE_MAP_END - -NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeySystemAccessManager) -NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeySystemAccessManager) - -NS_IMPL_CYCLE_COLLECTION_CLASS(MediaKeySystemAccessManager) - -NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaKeySystemAccessManager) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow) - for (size_t i = 0; i < tmp->mRequests.Length(); i++) { - tmp->mRequests[i].RejectPromise(NS_LITERAL_CSTRING("Promise still outstanding at MediaKeySystemAccessManager GC")); - tmp->mRequests[i].CancelTimer(); - NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequests[i].mPromise) - } - tmp->mRequests.Clear(); -NS_IMPL_CYCLE_COLLECTION_UNLINK_END - -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaKeySystemAccessManager) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow) - for (size_t i = 0; i < tmp->mRequests.Length(); i++) { - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequests[i].mPromise) - } -NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END - -MediaKeySystemAccessManager::MediaKeySystemAccessManager(nsPIDOMWindowInner* aWindow) - : mWindow(aWindow) - , mAddedObservers(false) -{ -} - -MediaKeySystemAccessManager::~MediaKeySystemAccessManager() -{ - Shutdown(); -} - -void -MediaKeySystemAccessManager::Request(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs) -{ - Request(aPromise, aKeySystem, aConfigs, RequestType::Initial); -} - -void -MediaKeySystemAccessManager::Request(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs, - RequestType aType) -{ - EME_LOG("MediaKeySystemAccessManager::Request %s", NS_ConvertUTF16toUTF8(aKeySystem).get()); - - if (aKeySystem.IsEmpty()) { - aPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Key system string is empty")); - // Don't notify DecoderDoctor, as there's nothing we or the user can - // do to fix this situation; the site is using the API wrong. - return; - } - if (aConfigs.IsEmpty()) { - aPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Candidate MediaKeySystemConfigs is empty")); - // Don't notify DecoderDoctor, as there's nothing we or the user can - // do to fix this situation; the site is using the API wrong. - return; - } - - DecoderDoctorDiagnostics diagnostics; - - // Ensure keysystem is supported. - if (!IsWidevineKeySystem(aKeySystem) && - !IsClearkeyKeySystem(aKeySystem)) { - // Not to inform user, because nothing to do if the keySystem is not - // supported. - aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, - NS_LITERAL_CSTRING("Key system is unsupported")); - diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(), - aKeySystem, false, __func__); - return; - } - - if (!MediaPrefs::EMEEnabled() && !IsClearkeyKeySystem(aKeySystem)) { - // EME disabled by user, send notification to chrome so UI can inform user. - // Clearkey is allowed even when EME is disabled because we want the pref - // "media.eme.enabled" only taking effect on proprietary DRMs. - MediaKeySystemAccess::NotifyObservers(mWindow, - aKeySystem, - MediaKeySystemStatus::Api_disabled); - aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, - NS_LITERAL_CSTRING("EME has been preffed off")); - diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(), - aKeySystem, false, __func__); - return; - } - - nsAutoCString message; - MediaKeySystemStatus status = - MediaKeySystemAccess::GetKeySystemStatus(aKeySystem, message); - - nsPrintfCString msg("MediaKeySystemAccess::GetKeySystemStatus(%s) " - "result=%s msg='%s'", - NS_ConvertUTF16toUTF8(aKeySystem).get(), - MediaKeySystemStatusValues::strings[(size_t)status].value, - message.get()); - LogToBrowserConsole(NS_ConvertUTF8toUTF16(msg)); - - if (status == MediaKeySystemStatus::Cdm_not_installed && - IsWidevineKeySystem(aKeySystem)) { - // 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 - // download or update the CDM. In AwaitInstall() we add listeners to wait - // for the update to complete, and we'll call this function again with - // aType==Subsequent once the download has completed and the GMPService - // has had a new plugin added. AwaitInstall() sets a timer to fail if the - // update/download takes too long or fails. - if (aType == RequestType::Initial && - AwaitInstall(aPromise, aKeySystem, aConfigs)) { - // Notify chrome that we're going to wait for the CDM to download/update. - // Note: If we're re-trying, we don't re-send the notification, - // as chrome is already displaying the "we can't play, updating" - // notification. - MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, status); - } else { - // We waited or can't wait for an update and we still can't service - // the request. Give up. Chrome will still be showing a "I can't play, - // updating" notification. - aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, - NS_LITERAL_CSTRING("Gave up while waiting for a CDM update")); - } - diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(), - aKeySystem, false, __func__); - return; - } - if (status != MediaKeySystemStatus::Available) { - // Failed due to user disabling something, send a notification to - // chrome, so we can show some UI to explain how the user can rectify - // the situation. - MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, status); - aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, message); - return; - } - - MediaKeySystemConfiguration config; - if (MediaKeySystemAccess::GetSupportedConfig(aKeySystem, aConfigs, config, &diagnostics)) { - RefPtr<MediaKeySystemAccess> access( - new MediaKeySystemAccess(mWindow, aKeySystem, config)); - aPromise->MaybeResolve(access); - diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(), - aKeySystem, true, __func__); - return; - } - // Not to inform user, because nothing to do if the corresponding keySystem - // configuration is not supported. - aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR, - NS_LITERAL_CSTRING("Key system configuration is not supported")); - diagnostics.StoreMediaKeySystemAccess(mWindow->GetExtantDoc(), - aKeySystem, false, __func__); -} - -MediaKeySystemAccessManager::PendingRequest::PendingRequest(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs, - nsITimer* aTimer) - : mPromise(aPromise) - , mKeySystem(aKeySystem) - , mConfigs(aConfigs) - , mTimer(aTimer) -{ - MOZ_COUNT_CTOR(MediaKeySystemAccessManager::PendingRequest); -} - -MediaKeySystemAccessManager::PendingRequest::PendingRequest(const PendingRequest& aOther) - : mPromise(aOther.mPromise) - , mKeySystem(aOther.mKeySystem) - , mConfigs(aOther.mConfigs) - , mTimer(aOther.mTimer) -{ - MOZ_COUNT_CTOR(MediaKeySystemAccessManager::PendingRequest); -} - -MediaKeySystemAccessManager::PendingRequest::~PendingRequest() -{ - MOZ_COUNT_DTOR(MediaKeySystemAccessManager::PendingRequest); -} - -void -MediaKeySystemAccessManager::PendingRequest::CancelTimer() -{ - if (mTimer) { - mTimer->Cancel(); - } -} - -void -MediaKeySystemAccessManager::PendingRequest::RejectPromise(const nsCString& aReason) -{ - if (mPromise) { - mPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, aReason); - } -} - -bool -MediaKeySystemAccessManager::AwaitInstall(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfigs) -{ - EME_LOG("MediaKeySystemAccessManager::AwaitInstall %s", NS_ConvertUTF16toUTF8(aKeySystem).get()); - - if (!EnsureObserversAdded()) { - NS_WARNING("Failed to add pref observer"); - return false; - } - - nsCOMPtr<nsITimer> timer(do_CreateInstance("@mozilla.org/timer;1")); - if (!timer || NS_FAILED(timer->Init(this, 60 * 1000, nsITimer::TYPE_ONE_SHOT))) { - NS_WARNING("Failed to create timer to await CDM install."); - return false; - } - - mRequests.AppendElement(PendingRequest(aPromise, aKeySystem, aConfigs, timer)); - return true; -} - -void -MediaKeySystemAccessManager::RetryRequest(PendingRequest& aRequest) -{ - aRequest.CancelTimer(); - Request(aRequest.mPromise, aRequest.mKeySystem, aRequest.mConfigs, RequestType::Subsequent); -} - -nsresult -MediaKeySystemAccessManager::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - EME_LOG("MediaKeySystemAccessManager::Observe %s", aTopic); - - if (!strcmp(aTopic, "gmp-changed")) { - // Filter out the requests where the CDM's install-status is no longer - // "unavailable". This will be the CDMs which have downloaded since the - // initial request. - // Note: We don't have a way to communicate from chrome that the CDM has - // failed to download, so we'll just let the timeout fail us in that case. - nsTArray<PendingRequest> requests; - for (size_t i = mRequests.Length(); i-- > 0; ) { - PendingRequest& request = mRequests[i]; - nsAutoCString message; - MediaKeySystemStatus status = - MediaKeySystemAccess::GetKeySystemStatus(request.mKeySystem, message); - if (status == MediaKeySystemStatus::Cdm_not_installed) { - // Not yet installed, don't retry. Keep waiting until timeout. - continue; - } - // Status has changed, retry request. - requests.AppendElement(Move(request)); - mRequests.RemoveElementAt(i); - } - // Retry all pending requests, but this time fail if the CDM is not installed. - for (PendingRequest& request : requests) { - RetryRequest(request); - } - } else if (!strcmp(aTopic, "timer-callback")) { - // Find the timer that expired and re-run the request for it. - nsCOMPtr<nsITimer> timer(do_QueryInterface(aSubject)); - for (size_t i = 0; i < mRequests.Length(); i++) { - if (mRequests[i].mTimer == timer) { - EME_LOG("MediaKeySystemAccessManager::AwaitInstall resuming request"); - PendingRequest request = mRequests[i]; - mRequests.RemoveElementAt(i); - RetryRequest(request); - break; - } - } - } - return NS_OK; -} - -bool -MediaKeySystemAccessManager::EnsureObserversAdded() -{ - if (mAddedObservers) { - return true; - } - - nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); - if (NS_WARN_IF(!obsService)) { - return false; - } - mAddedObservers = NS_SUCCEEDED(obsService->AddObserver(this, "gmp-changed", false)); - return mAddedObservers; -} - -void -MediaKeySystemAccessManager::Shutdown() -{ - EME_LOG("MediaKeySystemAccessManager::Shutdown"); - nsTArray<PendingRequest> requests(Move(mRequests)); - for (PendingRequest& request : requests) { - // Cancel all requests; we're shutting down. - request.CancelTimer(); - request.RejectPromise(NS_LITERAL_CSTRING("Promise still outstanding at MediaKeySystemAccessManager shutdown")); - } - if (mAddedObservers) { - nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService(); - if (obsService) { - obsService->RemoveObserver(this, "gmp-changed"); - mAddedObservers = false; - } - } -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeySystemAccessManager.h b/dom/media/eme/MediaKeySystemAccessManager.h deleted file mode 100644 index 9c092248e..000000000 --- a/dom/media/eme/MediaKeySystemAccessManager.h +++ /dev/null @@ -1,83 +0,0 @@ -/* 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 mozilla_dom_MediaKeySystemAccessManager_h -#define mozilla_dom_MediaKeySystemAccessManager_h - -#include "mozilla/dom/MediaKeySystemAccess.h" -#include "nsIObserver.h" -#include "nsCycleCollectionParticipant.h" -#include "nsISupportsImpl.h" -#include "nsITimer.h" - -namespace mozilla { -namespace dom { - -class DetailedPromise; -class TestGMPVideoDecoder; - -class MediaKeySystemAccessManager final : public nsIObserver -{ -public: - - explicit MediaKeySystemAccessManager(nsPIDOMWindowInner* aWindow); - - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(MediaKeySystemAccessManager, nsIObserver) - NS_DECL_NSIOBSERVER - - void Request(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfig); - - void Shutdown(); - - struct PendingRequest { - PendingRequest(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfig, - nsITimer* aTimer); - PendingRequest(const PendingRequest& aOther); - ~PendingRequest(); - void CancelTimer(); - void RejectPromise(const nsCString& aReason); - - RefPtr<DetailedPromise> mPromise; - const nsString mKeySystem; - const Sequence<MediaKeySystemConfiguration> mConfigs; - nsCOMPtr<nsITimer> mTimer; - }; - -private: - - enum RequestType { - Initial, - Subsequent - }; - - void Request(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfig, - RequestType aType); - - ~MediaKeySystemAccessManager(); - - bool EnsureObserversAdded(); - - bool AwaitInstall(DetailedPromise* aPromise, - const nsAString& aKeySystem, - const Sequence<MediaKeySystemConfiguration>& aConfig); - - void RetryRequest(PendingRequest& aRequest); - - nsTArray<PendingRequest> mRequests; - - nsCOMPtr<nsPIDOMWindowInner> mWindow; - bool mAddedObservers; -}; - -} // namespace dom -} // namespace mozilla - -#endif diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp deleted file mode 100644 index 862100757..000000000 --- a/dom/media/eme/MediaKeys.cpp +++ /dev/null @@ -1,579 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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/. */ - -#include "mozilla/dom/MediaKeys.h" -#include "GMPService.h" -#include "mozilla/dom/HTMLMediaElement.h" -#include "mozilla/dom/MediaKeysBinding.h" -#include "mozilla/dom/MediaKeyMessageEvent.h" -#include "mozilla/dom/MediaKeyError.h" -#include "mozilla/dom/MediaKeySession.h" -#include "mozilla/dom/DOMException.h" -#include "mozilla/dom/UnionTypes.h" -#include "GMPCDMProxy.h" -#include "mozilla/EMEUtils.h" -#include "nsContentUtils.h" -#include "nsIScriptObjectPrincipal.h" -#include "nsContentTypeParser.h" -#ifdef MOZ_FMP4 -#include "MP4Decoder.h" -#endif -#ifdef XP_WIN -#include "mozilla/WindowsVersion.h" -#endif -#include "nsContentCID.h" -#include "nsServiceManagerUtils.h" -#include "mozilla/dom/MediaKeySystemAccess.h" -#include "nsPrintfCString.h" - -namespace mozilla { - -namespace dom { - -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaKeys, - mElement, - mParent, - mKeySessions, - mPromises, - 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(nsPIDOMWindowInner* aParent, - const nsAString& aKeySystem, - const MediaKeySystemConfiguration& aConfig) - : mParent(aParent) - , mKeySystem(aKeySystem) - , mCreatePromiseId(0) - , mConfig(aConfig) -{ - EME_LOG("MediaKeys[%p] constructed keySystem=%s", - this, NS_ConvertUTF16toUTF8(mKeySystem).get()); -} - -MediaKeys::~MediaKeys() -{ - Shutdown(); - EME_LOG("MediaKeys[%p] destroyed", this); -} - -void -MediaKeys::Terminated() -{ - EME_LOG("MediaKeys[%p] CDM crashed unexpectedly", this); - - KeySessionHashMap keySessions; - // Remove entries during iteration will screw it. Make a copy first. - for (auto iter = mKeySessions.Iter(); !iter.Done(); iter.Next()) { - RefPtr<MediaKeySession>& session = iter.Data(); - keySessions.Put(session->GetSessionId(), session); - } - for (auto iter = keySessions.Iter(); !iter.Done(); iter.Next()) { - RefPtr<MediaKeySession>& session = iter.Data(); - session->OnClosed(); - } - keySessions.Clear(); - MOZ_ASSERT(mKeySessions.Count() == 0); - - // Notify the element about that CDM has terminated. - if (mElement) { - mElement->DecodeError(NS_ERROR_DOM_MEDIA_CDM_ERR); - } - - Shutdown(); -} - -void -MediaKeys::Shutdown() -{ - if (mProxy) { - mProxy->Shutdown(); - mProxy = nullptr; - } - - RefPtr<MediaKeys> kungFuDeathGrip = this; - - for (auto iter = mPromises.Iter(); !iter.Done(); iter.Next()) { - RefPtr<dom::DetailedPromise>& promise = iter.Data(); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Promise still outstanding at MediaKeys shutdown")); - Release(); - } - mPromises.Clear(); -} - -nsPIDOMWindowInner* -MediaKeys::GetParentObject() const -{ - return mParent; -} - -JSObject* -MediaKeys::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) -{ - return MediaKeysBinding::Wrap(aCx, this, aGivenProto); -} - -void -MediaKeys::GetKeySystem(nsString& aOutKeySystem) const -{ - aOutKeySystem.Assign(mKeySystem); -} - -already_AddRefed<DetailedPromise> -MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeys.setServerCertificate"))); - if (aRv.Failed()) { - return nullptr; - } - - if (!mProxy) { - NS_WARNING("Tried to use a MediaKeys without a CDM"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in MediaKeys.setServerCertificate()")); - return promise.forget(); - } - - nsTArray<uint8_t> data; - CopyArrayBufferViewOrArrayBufferData(aCert, data); - if (data.IsEmpty()) { - promise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, - NS_LITERAL_CSTRING("Empty certificate passed to MediaKeys.setServerCertificate()")); - return promise.forget(); - } - - mProxy->SetServerCertificate(StorePromise(promise), data); - return promise.forget(); -} - -already_AddRefed<DetailedPromise> -MediaKeys::MakePromise(ErrorResult& aRv, const nsACString& aName) -{ - nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject()); - if (!global) { - NS_WARNING("Passed non-global to MediaKeys ctor!"); - aRv.Throw(NS_ERROR_UNEXPECTED); - return nullptr; - } - return DetailedPromise::Create(global, aRv, aName); -} - -PromiseId -MediaKeys::StorePromise(DetailedPromise* aPromise) -{ - static uint32_t sEMEPromiseCount = 1; - MOZ_ASSERT(aPromise); - uint32_t id = sEMEPromiseCount++; - - EME_LOG("MediaKeys[%p]::StorePromise() id=%d", this, id); - - // Keep MediaKeys alive for the lifetime of its promises. Any still-pending - // promises are rejected in Shutdown(). - AddRef(); - -#ifdef DEBUG - // We should not have already stored this promise! - for (auto iter = mPromises.ConstIter(); !iter.Done(); iter.Next()) { - MOZ_ASSERT(iter.Data() != aPromise); - } -#endif - - mPromises.Put(id, aPromise); - return id; -} - -void -MediaKeys::ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken) -{ - // Should only be called from MediaKeySession::GenerateRequest. - mPromiseIdToken.Put(aId, aToken); - EME_LOG("MediaKeys[%p]::ConnectPendingPromiseIdWithToken() id=%u => token(%u)", - this, aId, aToken); -} - -already_AddRefed<DetailedPromise> -MediaKeys::RetrievePromise(PromiseId aId) -{ - if (!mPromises.Contains(aId)) { - NS_WARNING(nsPrintfCString("Tried to retrieve a non-existent promise id=%d", aId).get()); - return nullptr; - } - RefPtr<DetailedPromise> promise; - mPromises.Remove(aId, getter_AddRefs(promise)); - Release(); - return promise.forget(); -} - -void -MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode, - const nsCString& aReason) -{ - EME_LOG("MediaKeys[%p]::RejectPromise(%d, 0x%x)", this, aId, aExceptionCode); - - RefPtr<DetailedPromise> promise(RetrievePromise(aId)); - if (!promise) { - return; - } - - // This promise could be a createSession or loadSession promise, - // so we might have a pending session waiting to be resolved into - // the promise on success. We've been directed to reject to promise, - // so we can throw away the corresponding session object. - uint32_t token = 0; - if (mPromiseIdToken.Get(aId, &token)) { - MOZ_ASSERT(mPendingSessions.Contains(token)); - mPendingSessions.Remove(token); - mPromiseIdToken.Remove(aId); - } - - MOZ_ASSERT(NS_FAILED(aExceptionCode)); - promise->MaybeReject(aExceptionCode, aReason); - - if (mCreatePromiseId == aId) { - // Note: This will probably destroy the MediaKeys object! - Release(); - } -} - -void -MediaKeys::OnSessionIdReady(MediaKeySession* aSession) -{ - if (!aSession) { - NS_WARNING("Invalid MediaKeySession passed to OnSessionIdReady()"); - return; - } - if (mKeySessions.Contains(aSession->GetSessionId())) { - NS_WARNING("MediaKeySession's made ready multiple times!"); - return; - } - if (mPendingSessions.Contains(aSession->Token())) { - NS_WARNING("MediaKeySession made ready when it wasn't waiting to be ready!"); - return; - } - if (aSession->GetSessionId().IsEmpty()) { - NS_WARNING("MediaKeySession with invalid sessionId passed to OnSessionIdReady()"); - return; - } - mKeySessions.Put(aSession->GetSessionId(), aSession); -} - -void -MediaKeys::ResolvePromise(PromiseId aId) -{ - EME_LOG("MediaKeys[%p]::ResolvePromise(%d)", this, aId); - - RefPtr<DetailedPromise> promise(RetrievePromise(aId)); - MOZ_ASSERT(!mPromises.Contains(aId)); - if (!promise) { - return; - } - - uint32_t token = 0; - if (!mPromiseIdToken.Get(aId, &token)) { - promise->MaybeResolveWithUndefined(); - return; - } else if (!mPendingSessions.Contains(token)) { - // Pending session for CreateSession() should be removed when sessionId - // is ready. - promise->MaybeResolveWithUndefined(); - mPromiseIdToken.Remove(aId); - return; - } - mPromiseIdToken.Remove(aId); - - // We should only resolve LoadSession calls via this path, - // not CreateSession() promises. - RefPtr<MediaKeySession> session; - mPendingSessions.Remove(token, getter_AddRefs(session)); - if (!session || session->GetSessionId().IsEmpty()) { - NS_WARNING("Received activation for non-existent session!"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, - NS_LITERAL_CSTRING("CDM LoadSession() returned a different session ID than requested")); - return; - } - mKeySessions.Put(session->GetSessionId(), session); - promise->MaybeResolve(session); -} - -class MediaKeysGMPCrashHelper : public GMPCrashHelper -{ -public: - explicit MediaKeysGMPCrashHelper(MediaKeys* aMediaKeys) - : mMediaKeys(aMediaKeys) - { - MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe. - } - already_AddRefed<nsPIDOMWindowInner> - GetPluginCrashedEventTarget() override - { - MOZ_ASSERT(NS_IsMainThread()); // WeakPtr isn't thread safe. - EME_LOG("MediaKeysGMPCrashHelper::GetPluginCrashedEventTarget()"); - return (mMediaKeys && mMediaKeys->GetParentObject()) ? - do_AddRef(mMediaKeys->GetParentObject()) : nullptr; - } -private: - WeakPtr<MediaKeys> mMediaKeys; -}; - -already_AddRefed<CDMProxy> -MediaKeys::CreateCDMProxy() -{ - RefPtr<CDMProxy> proxy; - { - proxy = new GMPCDMProxy(this, - mKeySystem, - new MediaKeysGMPCrashHelper(this), - mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required, - mConfig.mPersistentState == MediaKeysRequirement::Required); - } - return proxy.forget(); -} - -already_AddRefed<DetailedPromise> -MediaKeys::Init(ErrorResult& aRv) -{ - RefPtr<DetailedPromise> promise(MakePromise(aRv, - NS_LITERAL_CSTRING("MediaKeys::Init()"))); - if (aRv.Failed()) { - return nullptr; - } - - mProxy = CreateCDMProxy(); - - // Determine principal (at creation time) of the MediaKeys object. - nsCOMPtr<nsIScriptObjectPrincipal> sop = do_QueryInterface(GetParentObject()); - if (!sop) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get script principal in MediaKeys::Init")); - return promise.forget(); - } - mPrincipal = sop->GetPrincipal(); - - // Determine principal of the "top-level" window; the principal of the - // page that will display in the URL bar. - nsCOMPtr<nsPIDOMWindowInner> window = GetParentObject(); - if (!window) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get top-level window in MediaKeys::Init")); - return promise.forget(); - } - nsCOMPtr<nsPIDOMWindowOuter> top = window->GetOuterWindow()->GetTop(); - if (!top || !top->GetExtantDoc()) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get document in MediaKeys::Init")); - return promise.forget(); - } - - mTopLevelPrincipal = top->GetExtantDoc()->NodePrincipal(); - - if (!mPrincipal || !mTopLevelPrincipal) { - NS_WARNING("Failed to get principals when creating MediaKeys"); - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get principal(s) in MediaKeys::Init")); - return promise.forget(); - } - - nsAutoCString origin; - nsresult rv = mPrincipal->GetOrigin(origin); - if (NS_FAILED(rv)) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get principal origin string in MediaKeys::Init")); - return promise.forget(); - } - nsAutoCString topLevelOrigin; - rv = mTopLevelPrincipal->GetOrigin(topLevelOrigin); - if (NS_FAILED(rv)) { - promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get top-level principal origin string in MediaKeys::Init")); - return promise.forget(); - } - - nsIDocument* doc = window->GetExtantDoc(); - const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc); - - EME_LOG("MediaKeys[%p]::Create() (%s, %s), %s", - this, - origin.get(), - topLevelOrigin.get(), - (inPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")); - - // The CDMProxy's initialization is asynchronous. The MediaKeys is - // refcounted, and its instance is returned to JS by promise once - // it's been initialized. No external refs exist to the MediaKeys while - // we're waiting for the promise to be resolved, so we must hold a - // reference to the new MediaKeys object until it's been created, - // or its creation has failed. Store the id of the promise returned - // here, and hold a self-reference until that promise is resolved or - // rejected. - MOZ_ASSERT(!mCreatePromiseId, "Should only be created once!"); - mCreatePromiseId = StorePromise(promise); - AddRef(); - mProxy->Init(mCreatePromiseId, - NS_ConvertUTF8toUTF16(origin), - NS_ConvertUTF8toUTF16(topLevelOrigin), - KeySystemToGMPName(mKeySystem), - inPrivateBrowsing); - - return promise.forget(); -} - -void -MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t aPluginId) -{ - RefPtr<DetailedPromise> promise(RetrievePromise(aId)); - if (!promise) { - return; - } - mNodeId = aNodeId; - RefPtr<MediaKeys> keys(this); - EME_LOG("MediaKeys[%p]::OnCDMCreated() resolve promise id=%d", this, aId); - promise->MaybeResolve(keys); - if (mCreatePromiseId == aId) { - Release(); - } - - MediaKeySystemAccess::NotifyObservers(mParent, - mKeySystem, - MediaKeySystemStatus::Cdm_created); - -} - -static bool -IsSessionTypeSupported(const MediaKeySessionType aSessionType, - const MediaKeySystemConfiguration& aConfig) -{ - if (aSessionType == MediaKeySessionType::Temporary) { - // Temporary is always supported. - return true; - } - if (!aConfig.mSessionTypes.WasPassed()) { - // No other session types supported. - return false; - } - using MediaKeySessionTypeValues::strings; - const char* sessionType = strings[static_cast<uint32_t>(aSessionType)].value; - for (const nsString& s : aConfig.mSessionTypes.Value()) { - if (s.EqualsASCII(sessionType)) { - return true; - } - } - return false; -} - -already_AddRefed<MediaKeySession> -MediaKeys::CreateSession(JSContext* aCx, - MediaKeySessionType aSessionType, - ErrorResult& aRv) -{ - if (!IsSessionTypeSupported(aSessionType, mConfig)) { - EME_LOG("MediaKeys[%p,'%s'] CreateSession() failed, unsupported session type", this); - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } - - if (!mProxy) { - NS_WARNING("Tried to use a MediaKeys which lost its CDM"); - aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); - return nullptr; - } - - EME_LOG("MediaKeys[%p] Creating session", this); - - RefPtr<MediaKeySession> session = new MediaKeySession(aCx, - GetParentObject(), - this, - mKeySystem, - aSessionType, - aRv); - - if (aRv.Failed()) { - return nullptr; - } - - // Add session to the set of sessions awaiting their sessionId being ready. - mPendingSessions.Put(session->Token(), session); - - return session.forget(); -} - -void -MediaKeys::OnSessionLoaded(PromiseId aId, bool aSuccess) -{ - RefPtr<DetailedPromise> promise(RetrievePromise(aId)); - if (!promise) { - return; - } - EME_LOG("MediaKeys[%p]::OnSessionLoaded() resolve promise id=%d", this, aId); - - promise->MaybeResolve(aSuccess); -} - -void -MediaKeys::OnSessionClosed(MediaKeySession* aSession) -{ - nsAutoString id; - aSession->GetSessionId(id); - mKeySessions.Remove(id); -} - -already_AddRefed<MediaKeySession> -MediaKeys::GetSession(const nsAString& aSessionId) -{ - RefPtr<MediaKeySession> session; - mKeySessions.Get(aSessionId, getter_AddRefs(session)); - return session.forget(); -} - -already_AddRefed<MediaKeySession> -MediaKeys::GetPendingSession(uint32_t aToken) -{ - RefPtr<MediaKeySession> session; - mPendingSessions.Get(aToken, getter_AddRefs(session)); - mPendingSessions.Remove(aToken); - return session.forget(); -} - -const nsCString& -MediaKeys::GetNodeId() const -{ - MOZ_ASSERT(NS_IsMainThread()); - return mNodeId; -} - -bool -MediaKeys::IsBoundToMediaElement() const -{ - MOZ_ASSERT(NS_IsMainThread()); - return mElement != nullptr; -} - -nsresult -MediaKeys::Bind(HTMLMediaElement* aElement) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (IsBoundToMediaElement()) { - return NS_ERROR_FAILURE; - } - - mElement = aElement; - - return NS_OK; -} - -void -MediaKeys::Unbind() -{ - MOZ_ASSERT(NS_IsMainThread()); - mElement = nullptr; -} - -} // namespace dom -} // namespace mozilla diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h deleted file mode 100644 index 491963934..000000000 --- a/dom/media/eme/MediaKeys.h +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* 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 mozilla_dom_mediakeys_h__ -#define mozilla_dom_mediakeys_h__ - -#include "nsWrapperCache.h" -#include "nsISupports.h" -#include "mozilla/Attributes.h" -#include "mozilla/RefPtr.h" -#include "nsCOMPtr.h" -#include "nsCycleCollectionParticipant.h" -#include "nsRefPtrHashtable.h" -#include "mozilla/dom/Promise.h" -#include "mozilla/dom/MediaKeysBinding.h" -#include "mozilla/dom/MediaKeySystemAccessBinding.h" -#include "mozIGeckoMediaPluginService.h" -#include "mozilla/DetailedPromise.h" -#include "mozilla/WeakPtr.h" - -namespace mozilla { - -class CDMProxy; - -namespace dom { - -class ArrayBufferViewOrArrayBuffer; -class MediaKeySession; -class HTMLMediaElement; - -typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap; -typedef nsRefPtrHashtable<nsUint32HashKey, dom::DetailedPromise> PromiseHashMap; -typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap; -typedef nsDataHashtable<nsUint32HashKey, uint32_t> PendingPromiseIdTokenHashMap; -typedef uint32_t PromiseId; - -// This class is used on the main thread only. -// Note: its addref/release is not (and can't be) thread safe! -class MediaKeys final : public nsISupports, - public nsWrapperCache, - public SupportsWeakPtr<MediaKeys> -{ - ~MediaKeys(); - -public: - NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys) - MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MediaKeys) - - MediaKeys(nsPIDOMWindowInner* aParentWindow, - const nsAString& aKeySystem, - const MediaKeySystemConfiguration& aConfig); - - already_AddRefed<DetailedPromise> Init(ErrorResult& aRv); - - nsPIDOMWindowInner* GetParentObject() const; - - JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - - nsresult Bind(HTMLMediaElement* aElement); - void Unbind(); - - // Javascript: readonly attribute DOMString keySystem; - void GetKeySystem(nsString& retval) const; - - // JavaScript: MediaKeys.createSession() - already_AddRefed<MediaKeySession> CreateSession(JSContext* aCx, - MediaKeySessionType aSessionType, - ErrorResult& aRv); - - // JavaScript: MediaKeys.SetServerCertificate() - already_AddRefed<DetailedPromise> - SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aServerCertificate, - ErrorResult& aRv); - - already_AddRefed<MediaKeySession> GetSession(const nsAString& aSessionId); - - // Removes and returns MediaKeySession from the set of sessions awaiting - // their sessionId to be assigned. - already_AddRefed<MediaKeySession> GetPendingSession(uint32_t aToken); - - // Called once a Init() operation succeeds. - void OnCDMCreated(PromiseId aId, - const nsACString& aNodeId, const uint32_t aPluginId); - - // Called once the CDM generates a sessionId while servicing a - // MediaKeySession.generateRequest() or MediaKeySession.load() call, - // once the sessionId of a MediaKeySession is known. - void OnSessionIdReady(MediaKeySession* aSession); - - // Called once a LoadSession succeeds. - void OnSessionLoaded(PromiseId aId, bool aSuccess); - - // Called once a session has closed. - void OnSessionClosed(MediaKeySession* aSession); - - CDMProxy* GetCDMProxy() { return mProxy; } - - // Makes a new promise, or nullptr on failure. - already_AddRefed<DetailedPromise> MakePromise(ErrorResult& aRv, - const nsACString& aName); - // Stores promise in mPromises, returning an ID that can be used to retrieve - // it later. The ID is passed to the CDM, so that it can signal specific - // promises to be resolved. - PromiseId StorePromise(DetailedPromise* aPromise); - - // Stores a map from promise id to pending session token. Using this - // mapping, when a promise is rejected via its ID, we can check if the - // promise corresponds to a pending session and retrieve that session - // via the mapped-to token, and remove the pending session from the - // list of sessions awaiting a session id. - void ConnectPendingPromiseIdWithToken(PromiseId aId, uint32_t aToken); - - // Reject promise with DOMException corresponding to aExceptionCode. - void RejectPromise(PromiseId aId, nsresult aExceptionCode, - const nsCString& aReason); - // Resolves promise with "undefined". - void ResolvePromise(PromiseId aId); - - const nsCString& GetNodeId() const; - - void Shutdown(); - - // Called by CDMProxy when CDM crashes or shuts down. It is different from - // Shutdown which is called from the script/dom side. - void Terminated(); - - // Returns true if this MediaKeys has been bound to a media element. - bool IsBoundToMediaElement() const; - -private: - - // Instantiate CDMProxy instance. - // It could be MediaDrmCDMProxy (Widevine on Fennec) or GMPCDMProxy (the rest). - already_AddRefed<CDMProxy> CreateCDMProxy(); - - // Removes promise from mPromises, and returns it. - already_AddRefed<DetailedPromise> RetrievePromise(PromiseId aId); - - // 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. - RefPtr<CDMProxy> mProxy; - - RefPtr<HTMLMediaElement> mElement; - - nsCOMPtr<nsPIDOMWindowInner> mParent; - const nsString mKeySystem; - nsCString mNodeId; - KeySessionHashMap mKeySessions; - PromiseHashMap mPromises; - PendingKeySessionsHashMap mPendingSessions; - PromiseId mCreatePromiseId; - - RefPtr<nsIPrincipal> mPrincipal; - RefPtr<nsIPrincipal> mTopLevelPrincipal; - - const MediaKeySystemConfiguration mConfig; - - PendingPromiseIdTokenHashMap mPromiseIdToken; -}; - -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_mediakeys_h__ diff --git a/dom/media/eme/moz.build b/dom/media/eme/moz.build deleted file mode 100644 index 7b1ad9d84..000000000 --- a/dom/media/eme/moz.build +++ /dev/null @@ -1,41 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# 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/. - -EXPORTS.mozilla.dom += [ - 'MediaEncryptedEvent.h', - 'MediaKeyError.h', - 'MediaKeyMessageEvent.h', - 'MediaKeys.h', - 'MediaKeySession.h', - 'MediaKeyStatusMap.h', - 'MediaKeySystemAccess.h', - 'MediaKeySystemAccessManager.h', -] - -EXPORTS.mozilla += [ - 'CDMCaps.h', - 'CDMProxy.h', - 'DecryptorProxyCallback.h', - 'DetailedPromise.h', - 'EMEUtils.h', -] - -SOURCES += [ - 'CDMCaps.cpp', - 'DetailedPromise.cpp', - 'EMEUtils.cpp', - 'MediaEncryptedEvent.cpp', - 'MediaKeyError.cpp', - 'MediaKeyMessageEvent.cpp', - 'MediaKeys.cpp', - 'MediaKeySession.cpp', - 'MediaKeyStatusMap.cpp', - 'MediaKeySystemAccess.cpp', - 'MediaKeySystemAccessManager.cpp', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' diff --git a/dom/media/moz.build b/dom/media/moz.build index fb162be81..ec36dfaf2 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -31,9 +31,6 @@ DIRS += [ if CONFIG['MOZ_FMP4']: DIRS += ['fmp4'] -if CONFIG['MOZ_EME']: - DIRS += ['eme'] - TEST_DIRS += [ 'gtest', ] |