summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt A. Tobin <email@mattatobin.com>2022-04-20 23:52:59 -0500
committerMatt A. Tobin <email@mattatobin.com>2022-04-20 23:52:59 -0500
commitdf1c87d8a7cb7ad0efaec527dc370e63b654b6db (patch)
treea91ebd62241986b7cc9e81636d75ebca05bda361
parent3ee1b0b8047610f07d4de262871d1f2ea8effed6 (diff)
downloadaura-central-df1c87d8a7cb7ad0efaec527dc370e63b654b6db.tar.gz
Issue #25 - Part 4: Remove EME Media code
-rw-r--r--dom/media/eme/CDMCaps.cpp169
-rw-r--r--dom/media/eme/CDMCaps.h112
-rw-r--r--dom/media/eme/CDMProxy.h278
-rw-r--r--dom/media/eme/DecryptorProxyCallback.h54
-rw-r--r--dom/media/eme/DetailedPromise.cpp57
-rw-r--r--dom/media/eme/DetailedPromise.h57
-rw-r--r--dom/media/eme/EMEUtils.cpp86
-rw-r--r--dom/media/eme/EMEUtils.h104
-rw-r--r--dom/media/eme/MediaEncryptedEvent.cpp128
-rw-r--r--dom/media/eme/MediaEncryptedEvent.h66
-rw-r--r--dom/media/eme/MediaKeyError.cpp39
-rw-r--r--dom/media/eme/MediaKeyError.h38
-rw-r--r--dom/media/eme/MediaKeyMessageEvent.cpp122
-rw-r--r--dom/media/eme/MediaKeyMessageEvent.h66
-rw-r--r--dom/media/eme/MediaKeySession.cpp670
-rw-r--r--dom/media/eme/MediaKeySession.h136
-rw-r--r--dom/media/eme/MediaKeyStatusMap.cpp120
-rw-r--r--dom/media/eme/MediaKeyStatusMap.h96
-rw-r--r--dom/media/eme/MediaKeySystemAccess.cpp1042
-rw-r--r--dom/media/eme/MediaKeySystemAccess.h81
-rw-r--r--dom/media/eme/MediaKeySystemAccessManager.cpp336
-rw-r--r--dom/media/eme/MediaKeySystemAccessManager.h83
-rw-r--r--dom/media/eme/MediaKeys.cpp579
-rw-r--r--dom/media/eme/MediaKeys.h167
-rw-r--r--dom/media/eme/moz.build41
-rw-r--r--dom/media/moz.build3
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',
]