diff options
Diffstat (limited to 'dom/media')
97 files changed, 3 insertions, 12173 deletions
diff --git a/dom/media/AbstractMediaDecoder.h b/dom/media/AbstractMediaDecoder.h index c6aa997553..108f7a57f7 100644 --- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -32,9 +32,6 @@ class MediaResource; class ReentrantMonitor; class VideoFrameContainer; class MediaDecoderOwner; -#ifdef MOZ_EME -class CDMProxy; -#endif typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags; diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 87454a4686..921ec6bfbf 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -388,9 +388,6 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner) , mLogicalPosition(0.0) , mDuration(std::numeric_limits<double>::quiet_NaN()) , mResourceCallback(new ResourceCallback()) -#ifdef MOZ_EME - , mCDMProxyPromise(mCDMProxyPromiseHolder.Ensure(__func__)) -#endif , mIgnoreProgressData(false) , mInfiniteStream(false) , mOwner(aOwner) @@ -475,10 +472,6 @@ MediaDecoder::Shutdown() mResourceCallback->Disconnect(); -#ifdef MOZ_EME - mCDMProxyPromiseHolder.RejectIfExists(true, __func__); -#endif - DiscardOngoingSeekIfExists(); // This changes the decoder state to SHUTDOWN and does other things @@ -1551,23 +1544,6 @@ MediaDecoder::CanPlayThrough() return GetStatistics().CanPlayThrough(); } -#ifdef MOZ_EME -RefPtr<MediaDecoder::CDMProxyPromise> -MediaDecoder::RequestCDMProxy() const -{ - return mCDMProxyPromise; -} - -void -MediaDecoder::SetCDMProxy(CDMProxy* aProxy) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aProxy); - - mCDMProxyPromiseHolder.ResolveIfExists(aProxy, __func__); -} -#endif - bool MediaDecoder::IsOpusEnabled() { diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index 95f211e1c5..d54ba30de5 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -8,10 +8,6 @@ #include "mozilla/Atomics.h" -#ifdef MOZ_EME -#include "mozilla/CDMProxy.h" -#endif - #include "mozilla/MozPromise.h" #include "mozilla/ReentrantMonitor.h" #include "mozilla/StateMirroring.h" @@ -437,16 +433,6 @@ private: MediaDecoderOwner* GetOwner() const override; -#ifdef MOZ_EME - typedef MozPromise<RefPtr<CDMProxy>, bool /* aIgnored */, /* IsExclusive = */ true> CDMProxyPromise; - - // Resolved when a CDMProxy is available and the capabilities are known or - // rejected when this decoder is about to shut down. - RefPtr<CDMProxyPromise> RequestCDMProxy() const; - - void SetCDMProxy(CDMProxy* aProxy); -#endif - static bool IsOggEnabled(); static bool IsOpusEnabled(); static bool IsWaveEnabled(); @@ -596,11 +582,6 @@ private: RefPtr<ResourceCallback> mResourceCallback; -#ifdef MOZ_EME - MozPromiseHolder<CDMProxyPromise> mCDMProxyPromiseHolder; - RefPtr<CDMProxyPromise> mCDMProxyPromise; -#endif - protected: // The promise resolving/rejection is queued as a "micro-task" which will be // handled immediately after the current JS task and before any pending JS diff --git a/dom/media/MediaDecoderOwner.h b/dom/media/MediaDecoderOwner.h index 9be4be3d0b..50a29d0951 100644 --- a/dom/media/MediaDecoderOwner.h +++ b/dom/media/MediaDecoderOwner.h @@ -141,14 +141,6 @@ public: // The decoder owner should call Shutdown() on the decoder and drop the // reference to the decoder to prevent further calls into the decoder. virtual void NotifyXPCOMShutdown() = 0; - -#ifdef MOZ_EME - // Dispatches a "encrypted" event to the HTMLMediaElement, with the - // provided init data. Actual dispatch may be delayed until HAVE_METADATA. - // Main thread only. - virtual void DispatchEncrypted(const nsTArray<uint8_t>& aInitData, - const nsAString& aInitDataType) = 0; -#endif }; } // namespace mozilla diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index dd406ed90e..3a3e2ceb82 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -24,9 +24,6 @@ namespace mozilla { -#ifdef MOZ_EME -class CDMProxy; -#endif class MediaDecoderReader; struct WaitForDataRejectValue @@ -188,10 +185,6 @@ public: // when to call SetIdle(). virtual void SetIdle() {} -#ifdef MOZ_EME - virtual void SetCDMProxy(CDMProxy* aProxy) {} -#endif - // Tell the reader that the data decoded are not for direct playback, so it // can accept more files, in particular those which have more channels than // available in the audio output. diff --git a/dom/media/MediaDecoderReaderWrapper.h b/dom/media/MediaDecoderReaderWrapper.h index a0f845538e..c85c93d44f 100644 --- a/dom/media/MediaDecoderReaderWrapper.h +++ b/dom/media/MediaDecoderReaderWrapper.h @@ -112,10 +112,6 @@ public: return mReader->CanonicalBuffered(); } -#ifdef MOZ_EME - void SetCDMProxy(CDMProxy* aProxy) { mReader->SetCDMProxy(aProxy); } -#endif - void SetVideoBlankDecode(bool aIsBlankDecode); private: diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index b84a76d624..dc82e89e34 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -271,7 +271,6 @@ protected: * * Transition to other states when decoding metadata is done: * SHUTDOWN if failing to decode metadata. - * WAIT_FOR_CDM if the media is encrypted and CDM is not available. * DECODING_FIRSTFRAME otherwise. */ class MediaDecoderStateMachine::DecodeMetadataState @@ -342,60 +341,6 @@ private: }; /** - * Purpose: wait for the CDM to start decoding. - * - * Transition to other states when CDM is ready: - * DECODING_FIRSTFRAME otherwise. - */ -class MediaDecoderStateMachine::WaitForCDMState - : public MediaDecoderStateMachine::StateObject -{ -public: - explicit WaitForCDMState(Master* aPtr) : StateObject(aPtr) {} - - void Enter() - { - MOZ_ASSERT(!mMaster->mVideoDecodeSuspended); - } - - void Exit() override - { - // mPendingSeek is either moved in HandleCDMProxyReady() or should be - // rejected here before transition to SHUTDOWN. - mPendingSeek.RejectIfExists(__func__); - } - - State GetState() const override - { - return DECODER_STATE_WAIT_FOR_CDM; - } - - void HandleCDMProxyReady() override; - - RefPtr<MediaDecoder::SeekPromise> HandleSeek(SeekTarget aTarget) override - { - SLOG("Not Enough Data to seek at this stage, queuing seek"); - mPendingSeek.RejectIfExists(__func__); - mPendingSeek.mTarget = aTarget; - return mPendingSeek.mPromise.Ensure(__func__); - } - - void HandleVideoSuspendTimeout() override - { - // Do nothing since no decoders are created yet. - } - - void HandleResumeVideoDecoding() override - { - // We never suspend video decoding in this state. - MOZ_ASSERT(false, "Shouldn't have suspended video decoding."); - } - -private: - SeekJob mPendingSeek; -}; - -/** * Purpose: release decoder resources to save memory and hardware resources. * * Transition to: @@ -1231,33 +1176,14 @@ DecodeMetadataState::OnMetadataRead(MetadataHolder* aMetadata) mMaster->GetAmpleVideoFrames()); } - // In general, we wait until we know the duration before notifying the decoder. - // However, we notify unconditionally in this case without waiting for the start - // time, since the caller might be waiting on metadataloaded to be fired before - // feeding in the CDM, which we need to decode the first frame (and - // thus get the metadata). We could fix this if we could compute the start - // time by demuxing without necessaring decoding. - bool waitingForCDM = -#ifdef MOZ_EME - mMaster->Info().IsEncrypted() && !mMaster->mCDMProxy; -#else - false; -#endif - mMaster->mNotifyMetadataBeforeFirstFrame = - mMaster->mDuration.Ref().isSome() || waitingForCDM; + mMaster->mDuration.Ref().isSome(); if (mMaster->mNotifyMetadataBeforeFirstFrame) { mMaster->EnqueueLoadedMetadataEvent(); } - if (waitingForCDM) { - // Metadata parsing was successful but we're still waiting for CDM caps - // to become available so that we can build the correct decryptor/decoder. - SetState<WaitForCDMState>(); - } else { - SetState<DecodingFirstFrameState>(SeekJob{}); - } + SetState<DecodingFirstFrameState>(SeekJob{}); } void @@ -1266,9 +1192,6 @@ DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) { if (aPlayState == MediaDecoder::PLAY_STATE_PLAYING) { // Exit dormant when the user wants to play. -#ifdef MOZ_EME - MOZ_ASSERT(!Info().IsEncrypted() || mMaster->mCDMProxy); -#endif MOZ_ASSERT(mMaster->mSentFirstFrameLoadedEvent); SetState<SeekingState>(Move(mPendingSeek), EventVisibility::Suppressed); } @@ -1276,13 +1199,6 @@ DormantState::HandlePlayStateChanged(MediaDecoder::PlayState aPlayState) void MediaDecoderStateMachine:: -WaitForCDMState::HandleCDMProxyReady() -{ - SetState<DecodingFirstFrameState>(Move(mPendingSeek)); -} - -void -MediaDecoderStateMachine:: DecodingFirstFrameState::Enter(SeekJob aPendingSeek) { // Handle pending seek. @@ -1581,10 +1497,6 @@ ShutdownState::Enter() // dispose of the timer. master->mVideoDecodeSuspendTimer.Reset(); -#ifdef MOZ_EME - master->mCDMProxyPromise.DisconnectIfExists(); -#endif - if (master->IsPlaying()) { master->StopPlayback(); } @@ -2137,13 +2049,6 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder) mMediaSink = CreateMediaSink(mAudioCaptured); -#ifdef MOZ_EME - mCDMProxyPromise.Begin(aDecoder->RequestCDMProxy()->Then( - OwnerThread(), __func__, this, - &MediaDecoderStateMachine::OnCDMProxyReady, - &MediaDecoderStateMachine::OnCDMProxyNotReady)); -#endif - nsresult rv = mReader->Init(); NS_ENSURE_SUCCESS(rv, rv); @@ -2267,7 +2172,6 @@ MediaDecoderStateMachine::ToStateStr(State aState) { switch (aState) { case DECODER_STATE_DECODING_METADATA: return "DECODING_METADATA"; - case DECODER_STATE_WAIT_FOR_CDM: return "WAIT_FOR_CDM"; case DECODER_STATE_DORMANT: return "DORMANT"; case DECODER_STATE_DECODING_FIRSTFRAME: return "DECODING_FIRSTFRAME"; case DECODER_STATE_DECODING: return "DECODING"; @@ -3118,25 +3022,6 @@ void MediaDecoderStateMachine::OnMediaSinkAudioError(nsresult aResult) DecodeError(MediaResult(NS_ERROR_DOM_MEDIA_MEDIASINK_ERR, __func__)); } -#ifdef MOZ_EME -void -MediaDecoderStateMachine::OnCDMProxyReady(RefPtr<CDMProxy> aProxy) -{ - MOZ_ASSERT(OnTaskQueue()); - mCDMProxyPromise.Complete(); - mCDMProxy = aProxy; - mReader->SetCDMProxy(aProxy); - mStateObj->HandleCDMProxyReady(); -} - -void -MediaDecoderStateMachine::OnCDMProxyNotReady() -{ - MOZ_ASSERT(OnTaskQueue()); - mCDMProxyPromise.Complete(); -} -#endif - void MediaDecoderStateMachine::SetAudioCaptured(bool aCaptured) { diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index 29da56e57d..ba9034e4fa 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -155,7 +155,6 @@ public: // Enumeration for the valid decoding states enum State { DECODER_STATE_DECODING_METADATA, - DECODER_STATE_WAIT_FOR_CDM, DECODER_STATE_DORMANT, DECODER_STATE_DECODING_FIRSTFRAME, DECODER_STATE_DECODING, @@ -263,7 +262,6 @@ public: private: class StateObject; class DecodeMetadataState; - class WaitForCDMState; class DormantState; class DecodingFirstFrameState; class DecodingState; @@ -767,13 +765,6 @@ private: // Playback will not start when audio is offloading. bool mAudioOffloading; -#ifdef MOZ_EME - void OnCDMProxyReady(RefPtr<CDMProxy> aProxy); - void OnCDMProxyNotReady(); - RefPtr<CDMProxy> mCDMProxy; - MozPromiseRequestHolder<MediaDecoder::CDMProxyPromise> mCDMProxyPromise; -#endif - private: // The buffered range. Mirrored from the decoder thread. Mirror<media::TimeIntervals> mBuffered; diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index a658298e2d..17fa29c080 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -3,10 +3,6 @@ * 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/. */ -#ifdef MOZ_EME -#include "mozilla/CDMProxy.h" -#endif - #include "mozilla/ClearOnShutdown.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/Preferences.h" @@ -351,12 +347,7 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack) if (!mOwner->mPlatform) { mOwner->mPlatform = new PDMFactory(); if (mOwner->IsEncrypted()) { -#ifdef MOZ_EME - MOZ_ASSERT(mOwner->mCDMProxy); - mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy); -#else return MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, "EME not supported"); -#endif } } @@ -592,56 +583,6 @@ MediaFormatReader::InitInternal() return NS_OK; } -#ifdef MOZ_EME -class DispatchKeyNeededEvent : public Runnable { -public: - DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder, - nsTArray<uint8_t>& aInitData, - const nsString& aInitDataType) - : mDecoder(aDecoder) - , mInitData(aInitData) - , mInitDataType(aInitDataType) - { - } - NS_IMETHOD Run() override { - // Note: Null check the owner, as the decoder could have been shutdown - // since this event was dispatched. - MediaDecoderOwner* owner = mDecoder->GetOwner(); - if (owner) { - owner->DispatchEncrypted(mInitData, mInitDataType); - } - mDecoder = nullptr; - return NS_OK; - } -private: - RefPtr<AbstractMediaDecoder> mDecoder; - nsTArray<uint8_t> mInitData; - nsString mInitDataType; -}; - -void -MediaFormatReader::SetCDMProxy(CDMProxy* aProxy) -{ - RefPtr<CDMProxy> proxy = aProxy; - RefPtr<MediaFormatReader> self = this; - nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction([=] () { - MOZ_ASSERT(self->OnTaskQueue()); - self->mCDMProxy = proxy; - }); - OwnerThread()->Dispatch(r.forget()); -} -#endif // MOZ_EME - -bool -MediaFormatReader::IsWaitingOnCDMResource() { - MOZ_ASSERT(OnTaskQueue()); -#ifdef MOZ_EME - return IsEncrypted() && !mCDMProxy; -#else - return false; -#endif -} - RefPtr<MediaDecoderReader::MetadataPromise> MediaFormatReader::AsyncReadMetadata() { @@ -677,9 +618,7 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) UniquePtr<MetadataTags> tags(MakeUnique<MetadataTags>()); RefPtr<PDMFactory> platform; - if (!IsWaitingOnCDMResource()) { - platform = new PDMFactory(); - } + platform = new PDMFactory(); // To decode, we need valid video and a place to put it. bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && @@ -746,13 +685,6 @@ MediaFormatReader::OnDemuxerInitDone(nsresult) UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto(); if (mDecoder && crypto && crypto->IsEncrypted()) { -#ifdef MOZ_EME - // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING. - for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) { - NS_DispatchToMainThread( - new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData, crypto->mInitDatas[i].mType)); - } -#endif mInfo.mCrypto = *crypto; } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index ccd43f0e6a..60ee022264 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -19,10 +19,6 @@ namespace mozilla { -#ifdef MOZ_EME -class CDMProxy; -#endif - class MediaFormatReader final : public MediaDecoderReader { typedef TrackInfo::TrackType TrackType; @@ -92,10 +88,6 @@ public: return mTrackDemuxersMayBlock; } -#ifdef MOZ_EME - void SetCDMProxy(CDMProxy* aProxy) override; -#endif - // Returns a string describing the state of the decoder data. // Used for debugging purposes. void GetMozDebugReaderData(nsAString& aString); @@ -108,8 +100,6 @@ private: bool HasVideo() const { return mVideo.mTrackDemuxer; } bool HasAudio() const { return mAudio.mTrackDemuxer; } - bool IsWaitingOnCDMResource(); - bool InitDemuxer(); // Notify the demuxer that new data has been received. // The next queued task calling GetBuffered() is guaranteed to have up to date @@ -587,14 +577,6 @@ private: RefPtr<VideoFrameContainer> mVideoFrameContainer; layers::ImageContainer* GetImageContainer(); -#ifdef MOZ_EME - RefPtr<CDMProxy> mCDMProxy; -#endif - -#ifdef MOZ_GMP - RefPtr<GMPCrashHelper> mCrashHelper; -#endif - void SetBlankDecode(TrackType aTrack, bool aIsBlankDecode); class DecoderFactory; diff --git a/dom/media/MediaPrefs.h b/dom/media/MediaPrefs.h index 675518ba62..40d0971d80 100644 --- a/dom/media/MediaPrefs.h +++ b/dom/media/MediaPrefs.h @@ -102,9 +102,6 @@ private: DECL_MEDIA_PREF("media.gmp.insecure.allow", GMPAllowInsecure, bool, false); DECL_MEDIA_PREF("media.gmp.async-shutdown-timeout", GMPAsyncShutdownTimeout, uint32_t, GMP_DEFAULT_ASYNC_SHUTDOWN_TIMEOUT); #endif -#ifdef MOZ_EME - DECL_MEDIA_PREF("media.eme.enabled", EMEEnabled, bool, false); -#endif DECL_MEDIA_PREF("media.use-blank-decoder", PDMUseBlankDecoder, bool, false); DECL_MEDIA_PREF("media.gpu-process-decoder", PDMUseGPUDecoder, bool, false); #ifdef MOZ_FFMPEG diff --git a/dom/media/eme/CDMCaps.cpp b/dom/media/eme/CDMCaps.cpp deleted file mode 100644 index a30fb59ac8..0000000000 --- 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 cb4b5e2910..0000000000 --- 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 a9e783f506..0000000000 --- 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 c1fcb49a4f..0000000000 --- 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 1aa83bef5d..0000000000 --- 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 f7f10aa403..0000000000 --- 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 68ef52d83e..0000000000 --- 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 aef1574829..0000000000 --- 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 a9c83291e9..0000000000 --- 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 c2ac560612..0000000000 --- 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 95e544fe76..0000000000 --- a/dom/media/eme/MediaKeyError.cpp +++ /dev/null @@ -1,38 +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 "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 b1e7aad3ee..0000000000 --- a/dom/media/eme/MediaKeyError.h +++ /dev/null @@ -1,37 +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 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 ee13f8d26f..0000000000 --- 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 2ec50f4f07..0000000000 --- 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 b5f3fe498b..0000000000 --- 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 6b71370469..0000000000 --- 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 677fd0db2e..0000000000 --- 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 8bfbd4d07c..0000000000 --- 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 3c594f9191..0000000000 --- a/dom/media/eme/MediaKeySystemAccess.cpp +++ /dev/null @@ -1,1041 +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 "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 c260e92b5c..0000000000 --- a/dom/media/eme/MediaKeySystemAccess.h +++ /dev/null @@ -1,80 +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 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 ed31059e22..0000000000 --- a/dom/media/eme/MediaKeySystemAccessManager.cpp +++ /dev/null @@ -1,339 +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 -#ifdef XP_MACOSX -#include "nsCocoaFeatures.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 9c092248e2..0000000000 --- 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 8621007579..0000000000 --- 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 4919639342..0000000000 --- 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 31ab9ffd87..0000000000 --- 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', -] - -UNIFIED_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/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 3cfe5b1374..ed212992c0 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -9,9 +9,6 @@ #include "MP4Demuxer.h" #include "mozilla/Preferences.h" #include "nsCharSeparatedTokenizer.h" -#ifdef MOZ_EME -#include "mozilla/CDMProxy.h" -#endif #include "mozilla/Logging.h" #include "mozilla/SharedThreadPool.h" #include "nsMimeTypes.h" diff --git a/dom/media/gmp/GMPCDMCallbackProxy.cpp b/dom/media/gmp/GMPCDMCallbackProxy.cpp deleted file mode 100644 index a0b490849a..0000000000 --- a/dom/media/gmp/GMPCDMCallbackProxy.cpp +++ /dev/null @@ -1,250 +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 "GMPCDMCallbackProxy.h" -#include "mozilla/CDMProxy.h" -#include "nsString.h" -#include "mozilla/dom/MediaKeys.h" -#include "mozilla/dom/MediaKeySession.h" -#include "mozIGeckoMediaPluginService.h" -#include "nsContentCID.h" -#include "nsServiceManagerUtils.h" -#include "MainThreadUtils.h" -#include "mozilla/EMEUtils.h" - -namespace mozilla { - -GMPCDMCallbackProxy::GMPCDMCallbackProxy(CDMProxy* aProxy) - : mProxy(aProxy) -{} - -void -GMPCDMCallbackProxy::SetDecryptorId(uint32_t aId) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, aId] () - { - proxy->OnSetDecryptorId(aId); - }) - );} - -void -GMPCDMCallbackProxy::SetSessionId(uint32_t aToken, - const nsCString& aSessionId) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, - aToken, - sid] () - { - proxy->OnSetSessionId(aToken, sid); - }) - ); -} - -void -GMPCDMCallbackProxy::ResolveLoadSessionPromise(uint32_t aPromiseId, - bool aSuccess) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, aPromiseId, aSuccess] () - { - proxy->OnResolveLoadSessionPromise(aPromiseId, aSuccess); - }) - ); -} - -void -GMPCDMCallbackProxy::ResolvePromise(uint32_t aPromiseId) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - // Note: CDMProxy proxies this from non-main threads to main thread. - mProxy->ResolvePromise(aPromiseId); -} - -void -GMPCDMCallbackProxy::RejectPromise(uint32_t aPromiseId, - nsresult aException, - const nsCString& aMessage) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, - aPromiseId, - aException, - aMessage] () - { - proxy->OnRejectPromise(aPromiseId, aException, aMessage); - }) - ); -} - -void -GMPCDMCallbackProxy::SessionMessage(const nsCString& aSessionId, - dom::MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - nsTArray<uint8_t> msg(aMessage); - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, - sid, - aMessageType, - msg] () mutable - { - proxy->OnSessionMessage(sid, aMessageType, msg); - }) - ); -} - -void -GMPCDMCallbackProxy::ExpirationChange(const nsCString& aSessionId, - GMPTimestamp aExpiryTime) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, - sid, - aExpiryTime] () - { - proxy->OnExpirationChange(sid, aExpiryTime); - }) - ); -} - -void -GMPCDMCallbackProxy::SessionClosed(const nsCString& aSessionId) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - bool keyStatusesChange = false; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - { - CDMCaps::AutoLock caps(mProxy->Capabilites()); - keyStatusesChange = caps.RemoveKeysForSession(NS_ConvertUTF8toUTF16(aSessionId)); - } - if (keyStatusesChange) { - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, sid] () - { - proxy->OnKeyStatusesChange(sid); - }) - ); - } - - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, sid] () - { - proxy->OnSessionClosed(sid); - }) - ); -} - -void -GMPCDMCallbackProxy::SessionError(const nsCString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsCString& aMessage) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - auto msg = NS_ConvertUTF8toUTF16(aMessage); - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, - sid, - aException, - aSystemCode, - msg] () - { - proxy->OnSessionError(sid, - aException, - aSystemCode, - msg); - }) - ); -} - -void -GMPCDMCallbackProxy::BatchedKeyStatusChanged(const nsCString& aSessionId, - const nsTArray<CDMKeyInfo>& aKeyInfos) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - BatchedKeyStatusChangedInternal(aSessionId, aKeyInfos); -} - -void -GMPCDMCallbackProxy::BatchedKeyStatusChangedInternal(const nsCString& aSessionId, - const nsTArray<CDMKeyInfo>& aKeyInfos) -{ - bool keyStatusesChange = false; - { - CDMCaps::AutoLock caps(mProxy->Capabilites()); - for (size_t i = 0; i < aKeyInfos.Length(); i++) { - keyStatusesChange |= - caps.SetKeyStatus(aKeyInfos[i].mKeyId, - NS_ConvertUTF8toUTF16(aSessionId), - aKeyInfos[i].mStatus); - } - } - if (keyStatusesChange) { - RefPtr<CDMProxy> proxy = mProxy; - auto sid = NS_ConvertUTF8toUTF16(aSessionId); - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy, sid] () - { - proxy->OnKeyStatusesChange(sid); - }) - ); - } -} - -void -GMPCDMCallbackProxy::Decrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - mProxy->OnDecrypted(aId, aResult, aDecryptedData); -} - -void -GMPCDMCallbackProxy::Terminated() -{ - MOZ_ASSERT(mProxy->IsOnOwnerThread()); - - RefPtr<CDMProxy> proxy = mProxy; - NS_DispatchToMainThread( - NS_NewRunnableFunction([proxy] () - { - proxy->Terminated(); - }) - ); -} - -} // namespace mozilla diff --git a/dom/media/gmp/GMPCDMCallbackProxy.h b/dom/media/gmp/GMPCDMCallbackProxy.h deleted file mode 100644 index d2cc806825..0000000000 --- a/dom/media/gmp/GMPCDMCallbackProxy.h +++ /dev/null @@ -1,71 +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 GMPCDMCallbackProxy_h_ -#define GMPCDMCallbackProxy_h_ - -#include "mozilla/CDMProxy.h" -#include "gmp-decryption.h" -#include "GMPDecryptorProxy.h" - -namespace mozilla { - -// Proxies call backs from the CDM on the GMP thread back to the MediaKeys -// object on the main thread. -class GMPCDMCallbackProxy : public GMPDecryptorProxyCallback { -public: - - void SetDecryptorId(uint32_t aId) override; - - void SetSessionId(uint32_t aCreateSessionToken, - const nsCString& aSessionId) override; - - void ResolveLoadSessionPromise(uint32_t aPromiseId, - bool aSuccess) override; - - void ResolvePromise(uint32_t aPromiseId) override; - - void RejectPromise(uint32_t aPromiseId, - nsresult aException, - const nsCString& aSessionId) override; - - void SessionMessage(const nsCString& aSessionId, - dom::MediaKeyMessageType aMessageType, - const nsTArray<uint8_t>& aMessage) override; - - void ExpirationChange(const nsCString& aSessionId, - UnixTime aExpiryTime) override; - - void SessionClosed(const nsCString& aSessionId) override; - - void SessionError(const nsCString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsCString& aMessage) override; - - void Decrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) override; - - void BatchedKeyStatusChanged(const nsCString& aSessionId, - const nsTArray<CDMKeyInfo>& aKeyInfos) override; - - void Terminated() override; - - ~GMPCDMCallbackProxy() {} - -private: - friend class GMPCDMProxy; - explicit GMPCDMCallbackProxy(CDMProxy* aProxy); - - void BatchedKeyStatusChangedInternal(const nsCString& aSessionId, - const nsTArray<CDMKeyInfo>& aKeyInfos); - // Warning: Weak ref. - CDMProxy* mProxy; -}; - -} // namespace mozilla - -#endif // GMPCDMCallbackProxy_h_ diff --git a/dom/media/gmp/GMPCDMProxy.cpp b/dom/media/gmp/GMPCDMProxy.cpp deleted file mode 100644 index 0f19586321..0000000000 --- a/dom/media/gmp/GMPCDMProxy.cpp +++ /dev/null @@ -1,798 +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 "GMPCDMProxy.h" -#include "mozilla/EMEUtils.h" -#include "mozilla/PodOperations.h" - -#include "mozilla/dom/MediaKeys.h" -#include "mozilla/dom/MediaKeySession.h" - -#include "mozIGeckoMediaPluginService.h" -#include "nsContentCID.h" -#include "nsIConsoleService.h" -#include "nsPrintfCString.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "prenv.h" -#include "GMPCDMCallbackProxy.h" -#include "GMPService.h" -#include "MainThreadUtils.h" -#include "MediaData.h" - -namespace mozilla { - -GMPCDMProxy::GMPCDMProxy(dom::MediaKeys* aKeys, - const nsAString& aKeySystem, - GMPCrashHelper* aCrashHelper, - bool aDistinctiveIdentifierRequired, - bool aPersistentStateRequired) - : CDMProxy(aKeys, - aKeySystem, - aDistinctiveIdentifierRequired, - aPersistentStateRequired) - , mCrashHelper(aCrashHelper) - , mCDM(nullptr) - , mDecryptionJobCount(0) - , mShutdownCalled(false) - , mDecryptorId(0) - , mCreatePromiseId(0) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_COUNT_CTOR(GMPCDMProxy); -} - -GMPCDMProxy::~GMPCDMProxy() -{ - MOZ_COUNT_DTOR(GMPCDMProxy); -} - -void -GMPCDMProxy::Init(PromiseId aPromiseId, - const nsAString& aOrigin, - const nsAString& aTopLevelOrigin, - const nsAString& aGMPName, - bool aInPrivateBrowsing) -{ - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_TRUE_VOID(!mKeys.IsNull()); - - EME_LOG("GMPCDMProxy::Init (%s, %s) %s", - NS_ConvertUTF16toUTF8(aOrigin).get(), - NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(), - (aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing")); - - nsCString pluginVersion; - if (!mOwnerThread) { - nsCOMPtr<mozIGeckoMediaPluginService> mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - if (!mps) { - RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::Init")); - return; - } - mps->GetThread(getter_AddRefs(mOwnerThread)); - if (!mOwnerThread) { - RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get GMP thread GMPCDMProxy::Init")); - return; - } - } - - if (aGMPName.IsEmpty()) { - RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - nsPrintfCString("Unknown GMP for keysystem '%s'", NS_ConvertUTF16toUTF8(mKeySystem).get())); - return; - } - - nsAutoPtr<InitData> data(new InitData()); - data->mPromiseId = aPromiseId; - data->mOrigin = aOrigin; - data->mTopLevelOrigin = aTopLevelOrigin; - data->mGMPName = aGMPName; - data->mInPrivateBrowsing = aInPrivateBrowsing; - data->mCrashHelper = mCrashHelper; - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<InitData>>(this, - &GMPCDMProxy::gmp_Init, - Move(data))); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -#ifdef DEBUG -bool -GMPCDMProxy::IsOnOwnerThread() -{ - return NS_GetCurrentThread() == mOwnerThread; -} -#endif - -void -GMPCDMProxy::gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData) -{ - EME_LOG("GMPCDMProxy::gmp_InitDone"); - if (mShutdownCalled) { - if (aCDM) { - aCDM->Close(); - } - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("GMPCDMProxy was shut down before init could complete")); - return; - } - if (!aCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("GetGMPDecryptor failed to return a CDM")); - return; - } - - mCDM = aCDM; - mCallback = new GMPCDMCallbackProxy(this); - mCDM->Init(mCallback, - mDistinctiveIdentifierRequired, - mPersistentStateRequired); - - // Await the OnSetDecryptorId callback. - mCreatePromiseId = aData->mPromiseId; -} - -void GMPCDMProxy::OnSetDecryptorId(uint32_t aId) -{ - MOZ_ASSERT(mCreatePromiseId); - mDecryptorId = aId; - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<uint32_t>(this, - &GMPCDMProxy::OnCDMCreated, - mCreatePromiseId)); - NS_DispatchToMainThread(task); -} - -class gmp_InitDoneCallback : public GetGMPDecryptorCallback -{ -public: - gmp_InitDoneCallback(GMPCDMProxy* aGMPCDMProxy, - nsAutoPtr<GMPCDMProxy::InitData>&& aData) - : mGMPCDMProxy(aGMPCDMProxy), - mData(Move(aData)) - { - } - - void Done(GMPDecryptorProxy* aCDM) - { - mGMPCDMProxy->gmp_InitDone(aCDM, Move(mData)); - } - -private: - RefPtr<GMPCDMProxy> mGMPCDMProxy; - nsAutoPtr<GMPCDMProxy::InitData> mData; -}; - -class gmp_InitGetGMPDecryptorCallback : public GetNodeIdCallback -{ -public: - gmp_InitGetGMPDecryptorCallback(GMPCDMProxy* aGMPCDMProxy, - nsAutoPtr<GMPCDMProxy::InitData>&& aData) - : mGMPCDMProxy(aGMPCDMProxy), - mData(aData) - { - } - - void Done(nsresult aResult, const nsACString& aNodeId) - { - mGMPCDMProxy->gmp_InitGetGMPDecryptor(aResult, aNodeId, Move(mData)); - } - -private: - RefPtr<GMPCDMProxy> mGMPCDMProxy; - nsAutoPtr<GMPCDMProxy::InitData> mData; -}; - -void -GMPCDMProxy::gmp_Init(nsAutoPtr<InitData>&& aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - - nsCOMPtr<mozIGeckoMediaPluginService> mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - if (!mps) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::gmp_Init")); - return; - } - - // Make a copy before we transfer ownership of aData to the - // gmp_InitGetGMPDecryptorCallback. - InitData data(*aData); - UniquePtr<GetNodeIdCallback> callback( - new gmp_InitGetGMPDecryptorCallback(this, Move(aData))); - nsresult rv = mps->GetNodeId(data.mOrigin, - data.mTopLevelOrigin, - data.mGMPName, - data.mInPrivateBrowsing, - Move(callback)); - if (NS_FAILED(rv)) { - RejectPromise(data.mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Call to GetNodeId() failed early")); - } -} - -void -GMPCDMProxy::gmp_InitGetGMPDecryptor(nsresult aResult, - const nsACString& aNodeId, - nsAutoPtr<InitData>&& aData) -{ - uint32_t promiseID = aData->mPromiseId; - if (NS_FAILED(aResult)) { - RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("GetNodeId() called back, but with a failure result")); - return; - } - - mNodeId = aNodeId; - MOZ_ASSERT(!GetNodeId().IsEmpty()); - - nsCOMPtr<mozIGeckoMediaPluginService> mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - if (!mps) { - RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Couldn't get MediaPluginService in GMPCDMProxy::gmp_InitGetGMPDecryptor")); - return; - } - - EME_LOG("GMPCDMProxy::gmp_Init (%s, %s) %s NodeId=%s", - NS_ConvertUTF16toUTF8(aData->mOrigin).get(), - NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(), - (aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"), - GetNodeId().get()); - - nsTArray<nsCString> tags; - tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem)); - - // Note: must capture helper refptr here, before the Move() - // when we create the GetGMPDecryptorCallback below. - RefPtr<GMPCrashHelper> crashHelper = Move(aData->mCrashHelper); - UniquePtr<GetGMPDecryptorCallback> callback(new gmp_InitDoneCallback(this, - Move(aData))); - nsresult rv = mps->GetGMPDecryptor(crashHelper, - &tags, - GetNodeId(), - Move(callback)); - if (NS_FAILED(rv)) { - RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Call to GetGMPDecryptor() failed early")); - } -} - -void -GMPCDMProxy::OnCDMCreated(uint32_t aPromiseId) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - MOZ_ASSERT(!GetNodeId().IsEmpty()); - if (mCDM) { - mKeys->OnCDMCreated(aPromiseId, GetNodeId(), mCDM->GetPluginId()); - } else { - // No CDM? Just reject the promise. - mKeys->RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in OnCDMCreated()")); - } -} - -void -GMPCDMProxy::CreateSession(uint32_t aCreateSessionToken, - dom::MediaKeySessionType aSessionType, - PromiseId aPromiseId, - const nsAString& aInitDataType, - nsTArray<uint8_t>& aInitData) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mOwnerThread); - - nsAutoPtr<CreateSessionData> data(new CreateSessionData()); - data->mSessionType = aSessionType; - data->mCreateSessionToken = aCreateSessionToken; - data->mPromiseId = aPromiseId; - data->mInitDataType = NS_ConvertUTF16toUTF8(aInitDataType); - data->mInitData = Move(aInitData); - - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<CreateSessionData>>(this, &GMPCDMProxy::gmp_CreateSession, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -GMPSessionType -ToGMPSessionType(dom::MediaKeySessionType aSessionType) { - switch (aSessionType) { - case dom::MediaKeySessionType::Temporary: return kGMPTemporySession; - case dom::MediaKeySessionType::Persistent_license: return kGMPPersistentSession; - default: return kGMPTemporySession; - }; -}; - -void -GMPCDMProxy::gmp_CreateSession(nsAutoPtr<CreateSessionData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_CreateSession")); - return; - } - mCDM->CreateSession(aData->mCreateSessionToken, - aData->mPromiseId, - aData->mInitDataType, - aData->mInitData, - ToGMPSessionType(aData->mSessionType)); -} - -void -GMPCDMProxy::LoadSession(PromiseId aPromiseId, - const nsAString& aSessionId) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mOwnerThread); - - nsAutoPtr<SessionOpData> data(new SessionOpData()); - data->mPromiseId = aPromiseId; - data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId); - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<SessionOpData>>(this, &GMPCDMProxy::gmp_LoadSession, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -void -GMPCDMProxy::gmp_LoadSession(nsAutoPtr<SessionOpData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_LoadSession")); - return; - } - mCDM->LoadSession(aData->mPromiseId, aData->mSessionId); -} - -void -GMPCDMProxy::SetServerCertificate(PromiseId aPromiseId, - nsTArray<uint8_t>& aCert) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mOwnerThread); - - nsAutoPtr<SetServerCertificateData> data(new SetServerCertificateData()); - data->mPromiseId = aPromiseId; - data->mCert = Move(aCert); - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<SetServerCertificateData>>(this, &GMPCDMProxy::gmp_SetServerCertificate, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -void -GMPCDMProxy::gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_SetServerCertificate")); - return; - } - mCDM->SetServerCertificate(aData->mPromiseId, aData->mCert); -} - -void -GMPCDMProxy::UpdateSession(const nsAString& aSessionId, - PromiseId aPromiseId, - nsTArray<uint8_t>& aResponse) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mOwnerThread); - NS_ENSURE_TRUE_VOID(!mKeys.IsNull()); - - nsAutoPtr<UpdateSessionData> data(new UpdateSessionData()); - data->mPromiseId = aPromiseId; - data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId); - data->mResponse = Move(aResponse); - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<UpdateSessionData>>(this, &GMPCDMProxy::gmp_UpdateSession, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -void -GMPCDMProxy::gmp_UpdateSession(nsAutoPtr<UpdateSessionData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_UpdateSession")); - return; - } - mCDM->UpdateSession(aData->mPromiseId, - aData->mSessionId, - aData->mResponse); -} - -void -GMPCDMProxy::CloseSession(const nsAString& aSessionId, - PromiseId aPromiseId) -{ - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_TRUE_VOID(!mKeys.IsNull()); - - nsAutoPtr<SessionOpData> data(new SessionOpData()); - data->mPromiseId = aPromiseId; - data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId); - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<SessionOpData>>(this, &GMPCDMProxy::gmp_CloseSession, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -void -GMPCDMProxy::gmp_CloseSession(nsAutoPtr<SessionOpData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_CloseSession")); - return; - } - mCDM->CloseSession(aData->mPromiseId, aData->mSessionId); -} - -void -GMPCDMProxy::RemoveSession(const nsAString& aSessionId, - PromiseId aPromiseId) -{ - MOZ_ASSERT(NS_IsMainThread()); - NS_ENSURE_TRUE_VOID(!mKeys.IsNull()); - - nsAutoPtr<SessionOpData> data(new SessionOpData()); - data->mPromiseId = aPromiseId; - data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId); - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<nsAutoPtr<SessionOpData>>(this, &GMPCDMProxy::gmp_RemoveSession, data)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); -} - -void -GMPCDMProxy::gmp_RemoveSession(nsAutoPtr<SessionOpData> aData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - if (!mCDM) { - RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR, - NS_LITERAL_CSTRING("Null CDM in gmp_RemoveSession")); - return; - } - mCDM->RemoveSession(aData->mPromiseId, aData->mSessionId); -} - -void -GMPCDMProxy::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - mKeys.Clear(); - // Note: This may end up being the last owning reference to the GMPCDMProxy. - nsCOMPtr<nsIRunnable> task(NewRunnableMethod(this, &GMPCDMProxy::gmp_Shutdown)); - if (mOwnerThread) { - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); - } -} - -void -GMPCDMProxy::gmp_Shutdown() -{ - MOZ_ASSERT(IsOnOwnerThread()); - - mShutdownCalled = true; - - // Abort any pending decrypt jobs, to awaken any clients waiting on a job. - for (size_t i = 0; i < mDecryptionJobs.Length(); i++) { - DecryptJob* job = mDecryptionJobs[i]; - job->PostResult(AbortedErr); - } - mDecryptionJobs.Clear(); - - if (mCDM) { - mCDM->Close(); - mCDM = nullptr; - } -} - -void -GMPCDMProxy::RejectPromise(PromiseId aId, nsresult aCode, - const nsCString& aReason) -{ - if (NS_IsMainThread()) { - if (!mKeys.IsNull()) { - mKeys->RejectPromise(aId, aCode, aReason); - } - } else { - nsCOMPtr<nsIRunnable> task(new RejectPromiseTask(this, aId, aCode, - aReason)); - NS_DispatchToMainThread(task); - } -} - -void -GMPCDMProxy::ResolvePromise(PromiseId aId) -{ - if (NS_IsMainThread()) { - if (!mKeys.IsNull()) { - mKeys->ResolvePromise(aId); - } else { - NS_WARNING("GMPCDMProxy unable to resolve promise!"); - } - } else { - nsCOMPtr<nsIRunnable> task; - task = NewRunnableMethod<PromiseId>(this, - &GMPCDMProxy::ResolvePromise, - aId); - NS_DispatchToMainThread(task); - } -} - -const nsCString& -GMPCDMProxy::GetNodeId() const -{ - return mNodeId; -} - -void -GMPCDMProxy::OnSetSessionId(uint32_t aCreateSessionToken, - const nsAString& aSessionId) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - - RefPtr<dom::MediaKeySession> session(mKeys->GetPendingSession(aCreateSessionToken)); - if (session) { - session->SetSessionId(aSessionId); - } -} - -void -GMPCDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - mKeys->OnSessionLoaded(aPromiseId, aSuccess); -} - -void -GMPCDMProxy::OnSessionMessage(const nsAString& aSessionId, - dom::MediaKeyMessageType aMessageType, - nsTArray<uint8_t>& aMessage) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId)); - if (session) { - session->DispatchKeyMessage(aMessageType, aMessage); - } -} - -void -GMPCDMProxy::OnKeyStatusesChange(const nsAString& aSessionId) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId)); - if (session) { - session->DispatchKeyStatusesChange(); - } -} - -void -GMPCDMProxy::OnExpirationChange(const nsAString& aSessionId, - GMPTimestamp aExpiryTime) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId)); - if (session) { - session->SetExpiration(static_cast<double>(aExpiryTime)); - } -} - -void -GMPCDMProxy::OnSessionClosed(const nsAString& aSessionId) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId)); - if (session) { - session->OnClosed(); - } -} - -void -GMPCDMProxy::OnDecrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) -{ - MOZ_ASSERT(IsOnOwnerThread()); - gmp_Decrypted(aId, aResult, aDecryptedData); -} - -static void -LogToConsole(const nsAString& aMsg) -{ - nsCOMPtr<nsIConsoleService> console( - do_GetService("@mozilla.org/consoleservice;1")); - if (!console) { - NS_WARNING("Failed to log message to console."); - return; - } - nsAutoString msg(aMsg); - console->LogStringMessage(msg.get()); -} - -void -GMPCDMProxy::OnSessionError(const nsAString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsAString& aMsg) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (mKeys.IsNull()) { - return; - } - RefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId)); - if (session) { - session->DispatchKeyError(aSystemCode); - } - LogToConsole(aMsg); -} - -void -GMPCDMProxy::OnRejectPromise(uint32_t aPromiseId, - nsresult aDOMException, - const nsCString& aMsg) -{ - MOZ_ASSERT(NS_IsMainThread()); - RejectPromise(aPromiseId, aDOMException, aMsg); -} - -const nsString& -GMPCDMProxy::KeySystem() const -{ - return mKeySystem; -} - -CDMCaps& -GMPCDMProxy::Capabilites() { - return mCapabilites; -} - -RefPtr<GMPCDMProxy::DecryptPromise> -GMPCDMProxy::Decrypt(MediaRawData* aSample) -{ - RefPtr<DecryptJob> job(new DecryptJob(aSample)); - RefPtr<DecryptPromise> promise(job->Ensure()); - - nsCOMPtr<nsIRunnable> task( - NewRunnableMethod<RefPtr<DecryptJob>>(this, &GMPCDMProxy::gmp_Decrypt, job)); - mOwnerThread->Dispatch(task, NS_DISPATCH_NORMAL); - return promise; -} - -void -GMPCDMProxy::gmp_Decrypt(RefPtr<DecryptJob> aJob) -{ - MOZ_ASSERT(IsOnOwnerThread()); - - if (!mCDM) { - aJob->PostResult(AbortedErr); - return; - } - - aJob->mId = ++mDecryptionJobCount; - nsTArray<uint8_t> data; - data.AppendElements(aJob->mSample->Data(), aJob->mSample->Size()); - mCDM->Decrypt(aJob->mId, aJob->mSample->mCrypto, data); - mDecryptionJobs.AppendElement(aJob.forget()); -} - -void -GMPCDMProxy::gmp_Decrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) -{ - MOZ_ASSERT(IsOnOwnerThread()); -#ifdef DEBUG - bool jobIdFound = false; -#endif - for (size_t i = 0; i < mDecryptionJobs.Length(); i++) { - DecryptJob* job = mDecryptionJobs[i]; - if (job->mId == aId) { -#ifdef DEBUG - jobIdFound = true; -#endif - job->PostResult(aResult, aDecryptedData); - mDecryptionJobs.RemoveElementAt(i); - } - } -#ifdef DEBUG - if (!jobIdFound) { - NS_WARNING("GMPDecryptorChild returned incorrect job ID"); - } -#endif -} - -void -GMPCDMProxy::DecryptJob::PostResult(DecryptStatus aResult) -{ - nsTArray<uint8_t> empty; - PostResult(aResult, empty); -} - -void -GMPCDMProxy::DecryptJob::PostResult(DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) -{ - if (aDecryptedData.Length() != mSample->Size()) { - NS_WARNING("CDM returned incorrect number of decrypted bytes"); - } - if (aResult == Ok) { - nsAutoPtr<MediaRawDataWriter> writer(mSample->CreateWriter()); - PodCopy(writer->Data(), - aDecryptedData.Elements(), - std::min<size_t>(aDecryptedData.Length(), mSample->Size())); - } else if (aResult == NoKeyErr) { - NS_WARNING("CDM returned NoKeyErr"); - // We still have the encrypted sample, so we can re-enqueue it to be - // decrypted again once the key is usable again. - } else { - nsAutoCString str("CDM returned decode failure DecryptStatus="); - str.AppendInt(aResult); - NS_WARNING(str.get()); - } - mPromise.Resolve(DecryptResult(aResult, mSample), __func__); -} - -void -GMPCDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId, - nsTArray<nsCString>& aSessionIds) -{ - CDMCaps::AutoLock caps(Capabilites()); - caps.GetSessionIdsForKeyId(aKeyId, aSessionIds); -} - -void -GMPCDMProxy::Terminated() -{ - MOZ_ASSERT(NS_IsMainThread()); - NS_WARNING("CDM terminated"); - if (mCreatePromiseId) { - RejectPromise(mCreatePromiseId, - NS_ERROR_DOM_MEDIA_FATAL_ERR, - NS_LITERAL_CSTRING("Crashed waiting for CDM to initialize")); - mCreatePromiseId = 0; - } - if (!mKeys.IsNull()) { - mKeys->Terminated(); - } -} - -uint32_t -GMPCDMProxy::GetDecryptorId() -{ - return mDecryptorId; -} - -} // namespace mozilla diff --git a/dom/media/gmp/GMPCDMProxy.h b/dom/media/gmp/GMPCDMProxy.h deleted file mode 100644 index a7fae235b6..0000000000 --- a/dom/media/gmp/GMPCDMProxy.h +++ /dev/null @@ -1,265 +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 GMPCDMProxy_h_ -#define GMPCDMProxy_h_ - -#include "mozilla/CDMProxy.h" -#include "GMPCDMCallbackProxy.h" -#include "GMPDecryptorProxy.h" - -namespace mozilla { -class MediaRawData; - -// Implementation of CDMProxy which is based on GMP architecture. -class GMPCDMProxy : public CDMProxy { -public: - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPCDMProxy, override) - - typedef MozPromise<DecryptResult, DecryptResult, /* IsExclusive = */ true> DecryptPromise; - - GMPCDMProxy(dom::MediaKeys* aKeys, - const nsAString& aKeySystem, - GMPCrashHelper* aCrashHelper, - bool aDistinctiveIdentifierRequired, - bool aPersistentStateRequired); - - void Init(PromiseId aPromiseId, - const nsAString& aOrigin, - const nsAString& aTopLevelOrigin, - const nsAString& aGMPName, - bool aInPrivateBrowsing) override; - - void OnSetDecryptorId(uint32_t aId) override; - - void CreateSession(uint32_t aCreateSessionToken, - dom::MediaKeySessionType aSessionType, - PromiseId aPromiseId, - const nsAString& aInitDataType, - nsTArray<uint8_t>& aInitData) override; - - void LoadSession(PromiseId aPromiseId, - const nsAString& aSessionId) override; - - void SetServerCertificate(PromiseId aPromiseId, - nsTArray<uint8_t>& aCert) override; - - void UpdateSession(const nsAString& aSessionId, - PromiseId aPromiseId, - nsTArray<uint8_t>& aResponse) override; - - void CloseSession(const nsAString& aSessionId, - PromiseId aPromiseId) override; - - void RemoveSession(const nsAString& aSessionId, - PromiseId aPromiseId) override; - - void Shutdown() override; - - void Terminated() override; - - const nsCString& GetNodeId() const override; - - void OnSetSessionId(uint32_t aCreateSessionToken, - const nsAString& aSessionId) override; - - void OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess) override; - - void OnSessionMessage(const nsAString& aSessionId, - dom::MediaKeyMessageType aMessageType, - nsTArray<uint8_t>& aMessage) override; - - void OnExpirationChange(const nsAString& aSessionId, - GMPTimestamp aExpiryTime) override; - - void OnSessionClosed(const nsAString& aSessionId) override; - - void OnSessionError(const nsAString& aSessionId, - nsresult aException, - uint32_t aSystemCode, - const nsAString& aMsg) override; - - void OnRejectPromise(uint32_t aPromiseId, - nsresult aDOMException, - const nsCString& aMsg) override; - - RefPtr<DecryptPromise> Decrypt(MediaRawData* aSample) override; - - void OnDecrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData) override; - - void RejectPromise(PromiseId aId, nsresult aExceptionCode, - const nsCString& aReason) override; - - void ResolvePromise(PromiseId aId) override; - - const nsString& KeySystem() const override; - - CDMCaps& Capabilites() override; - - void OnKeyStatusesChange(const nsAString& aSessionId) override; - - void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId, - nsTArray<nsCString>& aSessionIds) override; - -#ifdef DEBUG - bool IsOnOwnerThread() override; -#endif - - uint32_t GetDecryptorId() override; - -private: - friend class gmp_InitDoneCallback; - friend class gmp_InitGetGMPDecryptorCallback; - - struct InitData { - uint32_t mPromiseId; - nsString mOrigin; - nsString mTopLevelOrigin; - nsString mGMPName; - RefPtr<GMPCrashHelper> mCrashHelper; - bool mInPrivateBrowsing; - }; - - // GMP thread only. - void gmp_Init(nsAutoPtr<InitData>&& aData); - void gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr<InitData>&& aData); - void gmp_InitGetGMPDecryptor(nsresult aResult, - const nsACString& aNodeId, - nsAutoPtr<InitData>&& aData); - - // GMP thread only. - void gmp_Shutdown(); - - // Main thread only. - void OnCDMCreated(uint32_t aPromiseId); - - struct CreateSessionData { - dom::MediaKeySessionType mSessionType; - uint32_t mCreateSessionToken; - PromiseId mPromiseId; - nsCString mInitDataType; - nsTArray<uint8_t> mInitData; - }; - // GMP thread only. - void gmp_CreateSession(nsAutoPtr<CreateSessionData> aData); - - struct SessionOpData { - PromiseId mPromiseId; - nsCString mSessionId; - }; - // GMP thread only. - void gmp_LoadSession(nsAutoPtr<SessionOpData> aData); - - struct SetServerCertificateData { - PromiseId mPromiseId; - nsTArray<uint8_t> mCert; - }; - // GMP thread only. - void gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData); - - struct UpdateSessionData { - PromiseId mPromiseId; - nsCString mSessionId; - nsTArray<uint8_t> mResponse; - }; - // GMP thread only. - void gmp_UpdateSession(nsAutoPtr<UpdateSessionData> aData); - - // GMP thread only. - void gmp_CloseSession(nsAutoPtr<SessionOpData> aData); - - // GMP thread only. - void gmp_RemoveSession(nsAutoPtr<SessionOpData> aData); - - class DecryptJob { - public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecryptJob) - - explicit DecryptJob(MediaRawData* aSample) - : mId(0) - , mSample(aSample) - { - } - - void PostResult(DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData); - void PostResult(DecryptStatus aResult); - - RefPtr<DecryptPromise> Ensure() { - return mPromise.Ensure(__func__); - } - - uint32_t mId; - RefPtr<MediaRawData> mSample; - private: - ~DecryptJob() {} - MozPromiseHolder<DecryptPromise> mPromise; - }; - // GMP thread only. - void gmp_Decrypt(RefPtr<DecryptJob> aJob); - - // GMP thread only. - void gmp_Decrypted(uint32_t aId, - DecryptStatus aResult, - const nsTArray<uint8_t>& aDecryptedData); - - class RejectPromiseTask : public Runnable { - public: - RejectPromiseTask(GMPCDMProxy* aProxy, - PromiseId aId, - nsresult aCode, - const nsCString& aReason) - : mProxy(aProxy) - , mId(aId) - , mCode(aCode) - , mReason(aReason) - { - } - NS_IMETHOD Run() override { - mProxy->RejectPromise(mId, mCode, mReason); - return NS_OK; - } - private: - RefPtr<GMPCDMProxy> mProxy; - PromiseId mId; - nsresult mCode; - nsCString mReason; - }; - - ~GMPCDMProxy(); - - GMPCrashHelper* mCrashHelper; - - GMPDecryptorProxy* mCDM; - - nsAutoPtr<GMPCDMCallbackProxy> mCallback; - - // Decryption jobs sent to CDM, awaiting result. - // GMP thread only. - nsTArray<RefPtr<DecryptJob>> mDecryptionJobs; - - // Number of buffers we've decrypted. Used to uniquely identify - // decryption jobs sent to CDM. Note we can't just use the length of - // mDecryptionJobs as that shrinks as jobs are completed and removed - // from it. - // GMP thread only. - uint32_t mDecryptionJobCount; - - // True if GMPCDMProxy::gmp_Shutdown was called. - // GMP thread only. - bool mShutdownCalled; - - uint32_t mDecryptorId; - - PromiseId mCreatePromiseId; -}; - - -} // namespace mozilla - -#endif // GMPCDMProxy_h_ diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp index fa6f2f4c83..0bf9d44036 100644 --- a/dom/media/gmp/GMPChild.cpp +++ b/dom/media/gmp/GMPChild.cpp @@ -22,9 +22,6 @@ #include "GMPUtils.h" #include "prio.h" #include "base/task.h" -#ifdef MOZ_EME -#include "widevine-adapter/WidevineAdapter.h" -#endif using namespace mozilla::ipc; @@ -256,13 +253,7 @@ GMPChild::AnswerStartPlugin(const nsString& aAdapter) return false; } -#ifdef MOZ_EME - bool isWidevine = aAdapter.EqualsLiteral("widevine"); - - GMPAdapter* adapter = (isWidevine) ? new WidevineAdapter() : nullptr; -#else GMPAdapter* adapter = nullptr; -#endif if (!mGMPLoader->Load(libPath.get(), libPath.Length(), mNodeId.BeginWriting(), diff --git a/dom/media/gmp/GMPDecryptorChild.cpp b/dom/media/gmp/GMPDecryptorChild.cpp index 6da3c6c43e..a1b561ab59 100644 --- a/dom/media/gmp/GMPDecryptorChild.cpp +++ b/dom/media/gmp/GMPDecryptorChild.cpp @@ -73,11 +73,6 @@ GMPDecryptorChild::Init(GMPDecryptor* aSession) { MOZ_ASSERT(aSession); mSession = aSession; - // The ID of this decryptor is the IPDL actor ID. Note it's unique inside - // the child process, but not necessarily across all gecko processes. However, - // since GMPDecryptors are segregated by node ID/origin, we shouldn't end up - // with clashes in the content process. - SendSetDecryptorId(Id()); } void diff --git a/dom/media/gmp/GMPDecryptorParent.cpp b/dom/media/gmp/GMPDecryptorParent.cpp index 56474e9736..c41d5d18f5 100644 --- a/dom/media/gmp/GMPDecryptorParent.cpp +++ b/dom/media/gmp/GMPDecryptorParent.cpp @@ -42,19 +42,6 @@ GMPDecryptorParent::~GMPDecryptorParent() { } -bool -GMPDecryptorParent::RecvSetDecryptorId(const uint32_t& aId) -{ -#ifdef MOZ_EME - if (!mIsOpen) { - NS_WARNING("Trying to use a dead GMP decrypter!"); - return false; - } - mCallback->SetDecryptorId(aId); -#endif - return true; -} - nsresult GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback, bool aDistinctiveIdentifierRequired, diff --git a/dom/media/gmp/GMPDecryptorParent.h b/dom/media/gmp/GMPDecryptorParent.h index 30ff246901..3acf7dbd96 100644 --- a/dom/media/gmp/GMPDecryptorParent.h +++ b/dom/media/gmp/GMPDecryptorParent.h @@ -72,8 +72,6 @@ private: // PGMPDecryptorParent - bool RecvSetDecryptorId(const uint32_t& aId) override; - bool RecvSetSessionId(const uint32_t& aCreateSessionToken, const nsCString& aSessionId) override; diff --git a/dom/media/gmp/GMPDecryptorProxy.h b/dom/media/gmp/GMPDecryptorProxy.h index ed16755f89..f9e34a45fd 100644 --- a/dom/media/gmp/GMPDecryptorProxy.h +++ b/dom/media/gmp/GMPDecryptorProxy.h @@ -6,9 +6,6 @@ #ifndef GMPDecryptorProxy_h_ #define GMPDecryptorProxy_h_ -#ifdef MOZ_EME -#include "mozilla/DecryptorProxyCallback.h" -#endif #include "GMPCallbackBase.h" #include "gmp-decryption.h" #include "nsString.h" @@ -17,12 +14,7 @@ namespace mozilla { class CryptoSample; } // namespace mozilla -#ifdef MOZ_EME -class GMPDecryptorProxyCallback : public DecryptorProxyCallback, - public GMPCallbackBase { -#else class GMPDecryptorProxyCallback : public GMPCallbackBase { -#endif public: virtual ~GMPDecryptorProxyCallback() {} diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index e6f7972649..c4a7a84a09 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -28,11 +28,6 @@ using mozilla::ipc::GeckoChildProcessHost; #include "WMFDecoderModule.h" #endif -#ifdef MOZ_EME -#include "mozilla/dom/WidevineCDMManifestBinding.h" -#include "widevine-adapter/WidevineAdapter.h" -#endif - namespace mozilla { #undef LOG @@ -654,18 +649,7 @@ GMPParent::ReadGMPMetaData() return ReadGMPInfoFile(infoFile); } -#ifdef MOZ_EME - // Maybe this is the Widevine adapted plugin? - nsCOMPtr<nsIFile> manifestFile; - rv = mDirectory->Clone(getter_AddRefs(manifestFile)); - if (NS_FAILED(rv)) { - return GenericPromise::CreateAndReject(rv, __func__); - } - manifestFile->AppendRelativePath(NS_LITERAL_STRING("manifest.json")); - return ReadChromiumManifestFile(manifestFile); -#else return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); -#endif } RefPtr<GenericPromise> @@ -758,48 +742,8 @@ GMPParent::ReadChromiumManifestFile(nsIFile* aFile) RefPtr<GenericPromise> GMPParent::ParseChromiumManifest(nsString aJSON) { -#ifdef MOZ_EME - LOGD("%s: for '%s'", __FUNCTION__, NS_LossyConvertUTF16toASCII(aJSON).get()); - - MOZ_ASSERT(NS_IsMainThread()); - mozilla::dom::WidevineCDMManifest m; - if (!m.Init(aJSON)) { - return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); - } - - nsresult ignored; // Note: ToInteger returns 0 on failure. - if (!WidevineAdapter::Supports(m.mX_cdm_module_versions.ToInteger(&ignored), - m.mX_cdm_interface_versions.ToInteger(&ignored), - m.mX_cdm_host_versions.ToInteger(&ignored))) { - return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); - } - - mDisplayName = NS_ConvertUTF16toUTF8(m.mName); - mDescription = NS_ConvertUTF16toUTF8(m.mDescription); - mVersion = NS_ConvertUTF16toUTF8(m.mVersion); - - GMPCapability video(NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER)); - video.mAPITags.AppendElement(NS_LITERAL_CSTRING("h264")); - video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp8")); - video.mAPITags.AppendElement(NS_LITERAL_CSTRING("vp9")); - video.mAPITags.AppendElement(kEMEKeySystemWidevine); - mCapabilities.AppendElement(Move(video)); - - GMPCapability decrypt(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)); - decrypt.mAPITags.AppendElement(kEMEKeySystemWidevine); - mCapabilities.AppendElement(Move(decrypt)); - - MOZ_ASSERT(mName.EqualsLiteral("widevinecdm")); - mAdapter = NS_LITERAL_STRING("widevine"); -#ifdef XP_WIN - mLibs = NS_LITERAL_CSTRING("dxva2.dll"); -#endif - - return GenericPromise::CreateAndResolve(true, __func__); -#else // !MOZ_EME MOZ_ASSERT_UNREACHABLE("don't call me if EME isn't enabled"); return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); -#endif // !MOZ_EME } bool diff --git a/dom/media/gmp/PGMPDecryptor.ipdl b/dom/media/gmp/PGMPDecryptor.ipdl index 06b9b9cb60..207933e8a6 100644 --- a/dom/media/gmp/PGMPDecryptor.ipdl +++ b/dom/media/gmp/PGMPDecryptor.ipdl @@ -53,8 +53,6 @@ child: parent: async __delete__(); - async SetDecryptorId(uint32_t aId); - async SetSessionId(uint32_t aCreateSessionToken, nsCString aSessionId); diff --git a/dom/media/gmp/moz.build b/dom/media/gmp/moz.build index c4da2573fb..82d091168d 100644 --- a/dom/media/gmp/moz.build +++ b/dom/media/gmp/moz.build @@ -70,12 +70,6 @@ EXPORTS += [ 'GMPVideoPlaneImpl.h', ] -if CONFIG['MOZ_EME']: - EXPORTS += [ - 'GMPCDMCallbackProxy.h', - 'GMPCDMProxy.h', - ] - UNIFIED_SOURCES += [ 'GMPAudioDecoderChild.cpp', 'GMPAudioDecoderParent.cpp', @@ -111,17 +105,8 @@ UNIFIED_SOURCES += [ 'GMPVideoPlaneImpl.cpp', ] -if CONFIG['MOZ_EME']: - UNIFIED_SOURCES += [ - 'GMPCDMCallbackProxy.cpp', - 'GMPCDMProxy.cpp', - ] - DIRS += ['rlz'] -if CONFIG['MOZ_EME']: - DIRS += ['widevine-adapter'] - IPDL_SOURCES += [ 'GMPTypes.ipdlh', 'PGMP.ipdl', diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp deleted file mode 100644 index 57d4ecec27..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ /dev/null @@ -1,168 +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 "WidevineAdapter.h" -#include "content_decryption_module.h" -#include "VideoUtils.h" -#include "WidevineDecryptor.h" -#include "WidevineUtils.h" -#include "WidevineVideoDecoder.h" -#include "gmp-api/gmp-entrypoints.h" -#include "gmp-api/gmp-decryption.h" -#include "gmp-api/gmp-video-codec.h" -#include "gmp-api/gmp-platform.h" - -static const GMPPlatformAPI* sPlatform = nullptr; - -namespace mozilla { - -GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime) { - return sPlatform->getcurrenttime(aOutTime); -} - -// Call on main thread only. -GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS) { - return sPlatform->settimer(aTask, aTimeoutMS); -} - -GMPErr GMPCreateRecord(const char* aRecordName, - uint32_t aRecordNameSize, - GMPRecord** aOutRecord, - GMPRecordClient* aClient) -{ - return sPlatform->createrecord(aRecordName, aRecordNameSize, aOutRecord, aClient); -} - -void -WidevineAdapter::SetAdaptee(PRLibrary* aLib) -{ - mLib = aLib; -} - -void* GetCdmHost(int aHostInterfaceVersion, void* aUserData) -{ - Log("GetCdmHostFunc(%d, %p)", aHostInterfaceVersion, aUserData); - WidevineDecryptor* decryptor = reinterpret_cast<WidevineDecryptor*>(aUserData); - MOZ_ASSERT(decryptor); - return static_cast<cdm::Host_9*>(decryptor); -} - -#define STRINGIFY(s) _STRINGIFY(s) -#define _STRINGIFY(s) #s - -GMPErr -WidevineAdapter::GMPInit(const GMPPlatformAPI* aPlatformAPI) -{ -#ifdef ENABLE_WIDEVINE_LOG - if (getenv("GMP_LOG_FILE")) { - // Clear log file. - FILE* f = fopen(getenv("GMP_LOG_FILE"), "w"); - if (f) { - fclose(f); - } - } -#endif - - sPlatform = aPlatformAPI; - if (!mLib) { - return GMPGenericErr; - } - - auto init = reinterpret_cast<decltype(::INITIALIZE_CDM_MODULE)*>( - PR_FindFunctionSymbol(mLib, STRINGIFY(INITIALIZE_CDM_MODULE))); - if (!init) { - return GMPGenericErr; - } - - Log(STRINGIFY(INITIALIZE_CDM_MODULE)"()"); - init(); - - return GMPNoErr; -} - -GMPErr -WidevineAdapter::GMPGetAPI(const char* aAPIName, - void* aHostAPI, - void** aPluginAPI, - uint32_t aDecryptorId) -{ - Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p", - aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId); - if (!strcmp(aAPIName, GMP_API_DECRYPTOR)) { - if (WidevineDecryptor::GetInstance(aDecryptorId)) { - // We only support one CDM instance per PGMPDecryptor. Fail! - Log("WidevineAdapter::GMPGetAPI() Tried to create more than once CDM per IPDL actor! FAIL!"); - return GMPQuotaExceededErr; - } - auto create = reinterpret_cast<decltype(::CreateCdmInstance)*>( - PR_FindFunctionSymbol(mLib, "CreateCdmInstance")); - if (!create) { - Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to find CreateCdmInstance", - aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId); - return GMPGenericErr; - } - - WidevineDecryptor* decryptor = new WidevineDecryptor(); - - auto cdm = reinterpret_cast<cdm::ContentDecryptionModule_9*>( - create(cdm::ContentDecryptionModule_9::kVersion, - kEMEKeySystemWidevine.get(), - kEMEKeySystemWidevine.Length(), - &GetCdmHost, - decryptor)); - if (!cdm) { - Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p FAILED to create cdm", - aAPIName, aHostAPI, aPluginAPI, this, aDecryptorId); - return GMPGenericErr; - } - Log("cdm: 0x%x", cdm); - RefPtr<CDMWrapper> wrapper(new CDMWrapper(cdm, decryptor)); - decryptor->SetCDM(wrapper, aDecryptorId); - *aPluginAPI = decryptor; - - } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) { - RefPtr<CDMWrapper> wrapper = WidevineDecryptor::GetInstance(aDecryptorId); - if (!wrapper) { - Log("WidevineAdapter::GMPGetAPI(%s, 0x%p, 0x%p, %u) this=0x%p No cdm for video decoder", - aAPIName, aHostAPI, aPluginAPI, thiss, aDecryptorId); - return GMPGenericErr; - } - *aPluginAPI = new WidevineVideoDecoder(static_cast<GMPVideoHost*>(aHostAPI), - wrapper); - } - return *aPluginAPI ? GMPNoErr : GMPNotImplementedErr; -} - -void -WidevineAdapter::GMPShutdown() -{ - Log("WidevineAdapter::GMPShutdown()"); - - decltype(::DeinitializeCdmModule)* deinit; - deinit = (decltype(deinit))(PR_FindFunctionSymbol(mLib, "DeinitializeCdmModule")); - if (deinit) { - Log("DeinitializeCdmModule()"); - deinit(); - } -} - -void -WidevineAdapter::GMPSetNodeId(const char* aNodeId, uint32_t aLength) -{ - -} - -/* static */ -bool -WidevineAdapter::Supports(int32_t aModuleVersion, - int32_t aInterfaceVersion, - int32_t aHostVersion) -{ - return aModuleVersion == CDM_MODULE_VERSION && - aInterfaceVersion == cdm::ContentDecryptionModule_9::kVersion && - aHostVersion == cdm::Host_9::kVersion; -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.h b/dom/media/gmp/widevine-adapter/WidevineAdapter.h deleted file mode 100644 index 714e041bef..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.h +++ /dev/null @@ -1,59 +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 WidevineAdapter_h_ -#define WidevineAdapter_h_ - -#include "GMPLoader.h" -#include "prlink.h" -#include "GMPUtils.h" - -struct GMPPlatformAPI; - -namespace mozilla { - -class WidevineAdapter : public gmp::GMPAdapter { -public: - - void SetAdaptee(PRLibrary* aLib) override; - - // These are called in place of the corresponding GMP API functions. - GMPErr GMPInit(const GMPPlatformAPI* aPlatformAPI) override; - GMPErr GMPGetAPI(const char* aAPIName, - void* aHostAPI, - void** aPluginAPI, - uint32_t aDecryptorId) override; - void GMPShutdown() override; - void GMPSetNodeId(const char* aNodeId, uint32_t aLength) override; - - static bool Supports(int32_t aModuleVersion, - int32_t aInterfaceVersion, - int32_t aHostVersion); - -private: - PRLibrary* mLib = nullptr; -}; - -GMPErr GMPCreateThread(GMPThread** aThread); -GMPErr GMPRunOnMainThread(GMPTask* aTask); -GMPErr GMPCreateMutex(GMPMutex** aMutex); - -// Call on main thread only. -GMPErr GMPCreateRecord(const char* aRecordName, - uint32_t aRecordNameSize, - GMPRecord** aOutRecord, - GMPRecordClient* aClient); - -// Call on main thread only. -GMPErr GMPSetTimerOnMainThread(GMPTask* aTask, int64_t aTimeoutMS); - -GMPErr GMPGetCurrentTime(GMPTimestamp* aOutTime); - -GMPErr GMPCreateRecordIterator(RecvGMPRecordIteratorPtr aRecvIteratorFunc, - void* aUserArg); - -} // namespace mozilla - -#endif // WidevineAdapter_h_ diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp deleted file mode 100644 index 4d3408804f..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ /dev/null @@ -1,554 +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 "WidevineDecryptor.h" - -#include "WidevineAdapter.h" -#include "WidevineUtils.h" -#include "WidevineFileIO.h" -#include <mozilla/SizePrintfMacros.h> -#include <stdarg.h> -#include "base/time.h" - -using namespace cdm; -using namespace std; - -namespace mozilla { - -static map<uint32_t, RefPtr<CDMWrapper>> sDecryptors; - -/* static */ -RefPtr<CDMWrapper> -WidevineDecryptor::GetInstance(uint32_t aInstanceId) -{ - auto itr = sDecryptors.find(aInstanceId); - if (itr != sDecryptors.end()) { - return itr->second; - } - return nullptr; -} - - -WidevineDecryptor::WidevineDecryptor() - : mCallback(nullptr) -{ - Log("WidevineDecryptor created this=%p", this); - AddRef(); // Released in DecryptingComplete(). -} - -WidevineDecryptor::~WidevineDecryptor() -{ - Log("WidevineDecryptor destroyed this=%p", this); -} - -void -WidevineDecryptor::SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aInstanceId) -{ - mCDM = aCDM; - mInstanceId = aInstanceId; - sDecryptors[mInstanceId] = aCDM; -} - -void -WidevineDecryptor::Init(GMPDecryptorCallback* aCallback, - bool aDistinctiveIdentifierRequired, - bool aPersistentStateRequired) -{ - Log("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d", - this, aDistinctiveIdentifierRequired, aPersistentStateRequired); - MOZ_ASSERT(aCallback); - mCallback = aCallback; - MOZ_ASSERT(mCDM); - mDistinctiveIdentifierRequired = aDistinctiveIdentifierRequired; - mPersistentStateRequired = aPersistentStateRequired; - if (CDM()) { - CDM()->Initialize(aDistinctiveIdentifierRequired, - aPersistentStateRequired); - } -} - -static SessionType -ToCDMSessionType(GMPSessionType aSessionType) -{ - switch (aSessionType) { - case kGMPTemporySession: return kTemporary; - case kGMPPersistentSession: return kPersistentLicense; - case kGMPSessionInvalid: return kTemporary; - // TODO: kPersistentKeyRelease - } - MOZ_ASSERT(false); // Not supposed to get here. - return kTemporary; -} - -void -WidevineDecryptor::CreateSession(uint32_t aCreateSessionToken, - uint32_t aPromiseId, - const char* aInitDataType, - uint32_t aInitDataTypeSize, - const uint8_t* aInitData, - uint32_t aInitDataSize, - GMPSessionType aSessionType) -{ - Log("Decryptor::CreateSession(token=%d, pid=%d)", aCreateSessionToken, aPromiseId); - InitDataType initDataType; - if (!strcmp(aInitDataType, "cenc")) { - initDataType = kCenc; - } else if (!strcmp(aInitDataType, "webm")) { - initDataType = kWebM; - } else if (!strcmp(aInitDataType, "keyids")) { - initDataType = kKeyIds; - } else { - // Invalid init data type - const char* errorMsg = "Invalid init data type when creating session."; - OnRejectPromise(aPromiseId, kExceptionNotSupportedError, 0, errorMsg, sizeof(errorMsg)); - return; - } - mPromiseIdToNewSessionTokens[aPromiseId] = aCreateSessionToken; - CDM()->CreateSessionAndGenerateRequest(aPromiseId, - ToCDMSessionType(aSessionType), - initDataType, - aInitData, aInitDataSize); -} - -void -WidevineDecryptor::LoadSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) -{ - Log("Decryptor::LoadSession(pid=%d, %s)", aPromiseId, aSessionId); - // TODO: session type?? - CDM()->LoadSession(aPromiseId, kPersistentLicense, aSessionId, aSessionIdLength); -} - -void -WidevineDecryptor::UpdateSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength, - const uint8_t* aResponse, - uint32_t aResponseSize) -{ - Log("Decryptor::UpdateSession(pid=%d, session=%s)", aPromiseId, aSessionId); - CDM()->UpdateSession(aPromiseId, aSessionId, aSessionIdLength, aResponse, aResponseSize); -} - -void -WidevineDecryptor::CloseSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) -{ - Log("Decryptor::CloseSession(pid=%d, session=%s)", aPromiseId, aSessionId); - CDM()->CloseSession(aPromiseId, aSessionId, aSessionIdLength); -} - -void -WidevineDecryptor::RemoveSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) -{ - Log("Decryptor::RemoveSession(%s)", aSessionId); - CDM()->RemoveSession(aPromiseId, aSessionId, aSessionIdLength); -} - -void -WidevineDecryptor::SetServerCertificate(uint32_t aPromiseId, - const uint8_t* aServerCert, - uint32_t aServerCertSize) -{ - Log("Decryptor::SetServerCertificate()"); - CDM()->SetServerCertificate(aPromiseId, aServerCert, aServerCertSize); -} - -class WidevineDecryptedBlock : public cdm::DecryptedBlock { -public: - - WidevineDecryptedBlock() - : mBuffer(nullptr) - , mTimestamp(0) - { - } - - ~WidevineDecryptedBlock() { - if (mBuffer) { - mBuffer->Destroy(); - mBuffer = nullptr; - } - } - - void SetDecryptedBuffer(cdm::Buffer* aBuffer) override { - mBuffer = aBuffer; - } - - cdm::Buffer* DecryptedBuffer() override { - return mBuffer; - } - - void SetTimestamp(int64_t aTimestamp) override { - mTimestamp = aTimestamp; - } - - int64_t Timestamp() const override { - return mTimestamp; - } - -private: - cdm::Buffer* mBuffer; - int64_t mTimestamp; -}; - -void -WidevineDecryptor::Decrypt(GMPBuffer* aBuffer, - GMPEncryptedBufferMetadata* aMetadata) -{ - if (!mCallback) { - Log("WidevineDecryptor::Decrypt() this=%p FAIL; !mCallback", this); - return; - } - const GMPEncryptedBufferMetadata* crypto = aMetadata; - InputBuffer sample; - nsTArray<SubsampleEntry> subsamples; - InitInputBuffer(crypto, aBuffer->Id(), aBuffer->Data(), aBuffer->Size(), sample, subsamples); - WidevineDecryptedBlock decrypted; - Status rv = CDM()->Decrypt(sample, &decrypted); - Log("Decryptor::Decrypt(timestamp=%lld) rv=%d sz=%d", - sample.timestamp, rv, decrypted.DecryptedBuffer()->Size()); - if (rv == kSuccess) { - aBuffer->Resize(decrypted.DecryptedBuffer()->Size()); - memcpy(aBuffer->Data(), - decrypted.DecryptedBuffer()->Data(), - decrypted.DecryptedBuffer()->Size()); - } - mCallback->Decrypted(aBuffer, ToGMPErr(rv)); -} - -void -WidevineDecryptor::DecryptingComplete() -{ - Log("WidevineDecryptor::DecryptingComplete() this=%p", this); - // Drop our references to the CDMWrapper. When any other references - // held elsewhere are dropped (for example references held by a - // WidevineVideoDecoder, or a runnable), the CDMWrapper destroys - // the CDM. - mCDM = nullptr; - sDecryptors.erase(mInstanceId); - mCallback = nullptr; - Release(); -} - -class WidevineBuffer : public cdm::Buffer { -public: - explicit WidevineBuffer(size_t aSize) { - Log("WidevineBuffer(size=" PRIuSIZE ") created", aSize); - mBuffer.SetLength(aSize); - } - ~WidevineBuffer() { - Log("WidevineBuffer(size=" PRIuSIZE ") destroyed", Size()); - } - void Destroy() override { delete this; } - uint32_t Capacity() const override { return mBuffer.Length(); }; - uint8_t* Data() override { return mBuffer.Elements(); } - void SetSize(uint32_t aSize) override { mBuffer.SetLength(aSize); } - uint32_t Size() const override { return mBuffer.Length(); } - -private: - WidevineBuffer(const WidevineBuffer&); - void operator=(const WidevineBuffer&); - - nsTArray<uint8_t> mBuffer; -}; - -Buffer* -WidevineDecryptor::Allocate(uint32_t aCapacity) -{ - Log("Decryptor::Allocate(capacity=%u)", aCapacity); - return new WidevineBuffer(aCapacity); -} - -class TimerTask : public GMPTask { -public: - TimerTask(WidevineDecryptor* aDecryptor, - RefPtr<CDMWrapper> aCDM, - void* aContext) - : mDecryptor(aDecryptor) - , mCDM(aCDM) - , mContext(aContext) - { - } - ~TimerTask() override {} - void Run() override { - mCDM->GetCDM()->TimerExpired(mContext); - } - void Destroy() override { delete this; } -private: - RefPtr<WidevineDecryptor> mDecryptor; - RefPtr<CDMWrapper> mCDM; - void* mContext; -}; - -void -WidevineDecryptor::SetTimer(int64_t aDelayMs, void* aContext) -{ - Log("Decryptor::SetTimer(delay_ms=%lld, context=0x%x)", aDelayMs, aContext); - if (mCDM) { - GMPSetTimerOnMainThread(new TimerTask(this, mCDM, aContext), aDelayMs); - } -} - -Time -WidevineDecryptor::GetCurrentWallTime() -{ - return base::Time::Now().ToDoubleT(); -} - -void -WidevineDecryptor::OnResolveKeyStatusPromise(uint32_t aPromiseId, - cdm::KeyStatus aKeyStatus) { - //TODO: The callback of GetStatusForPolicy. See Mozilla bug 1404230. -} - -void -WidevineDecryptor::OnResolveNewSessionPromise(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) -{ - if (!mCallback) { - Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId); - return; - } - Log("Decryptor::OnResolveNewSessionPromise(aPromiseId=0x%d)", aPromiseId); - auto iter = mPromiseIdToNewSessionTokens.find(aPromiseId); - if (iter == mPromiseIdToNewSessionTokens.end()) { - Log("FAIL: Decryptor::OnResolveNewSessionPromise(aPromiseId=%d) unknown aPromiseId", aPromiseId); - return; - } - mCallback->SetSessionId(iter->second, aSessionId, aSessionIdSize); - mCallback->ResolvePromise(aPromiseId); - mPromiseIdToNewSessionTokens.erase(iter); -} - -void -WidevineDecryptor::OnResolvePromise(uint32_t aPromiseId) -{ - if (!mCallback) { - Log("Decryptor::OnResolvePromise(aPromiseId=0x%d) FAIL; !mCallback", aPromiseId); - return; - } - Log("Decryptor::OnResolvePromise(aPromiseId=%d)", aPromiseId); - mCallback->ResolvePromise(aPromiseId); -} - -static GMPDOMException -ConvertCDMExceptionToGMPDOMException(cdm::Exception aException) -{ - switch (aException) { - case kExceptionNotSupportedError: return kGMPNotSupportedError; - case kExceptionInvalidStateError: return kGMPInvalidStateError; - case kExceptionTypeError: return kGMPTypeError; - case kExceptionQuotaExceededError: return kGMPQuotaExceededError; - case kUnknownError: return kGMPInvalidModificationError; // Note: Unique placeholder. - case kClientError: return kGMPAbortError; // Note: Unique placeholder. - case kOutputError: return kGMPSecurityError; // Note: Unique placeholder. - }; - return kGMPInvalidStateError; // Note: Unique placeholder. -} - -// Align with spec, the Exceptions used by CDM to reject promises . -// https://w3c.github.io/encrypted-media/#exceptions -cdm::Exception -ConvertCDMErrorToCDMException(cdm::Error error) { - switch (error) { - case cdm::kNotSupportedError: - return cdm::Exception::kExceptionNotSupportedError; - case cdm::kInvalidStateError: - return cdm::Exception::kExceptionInvalidStateError; - case cdm::kInvalidAccessError: - return cdm::Exception::kExceptionTypeError; - case cdm::kQuotaExceededError: - return cdm::Exception::kExceptionQuotaExceededError; - - case cdm::kUnknownError: - case cdm::kClientError: - case cdm::kOutputError: - break; - } - - return cdm::Exception::kExceptionInvalidStateError; -} - -void -WidevineDecryptor::OnRejectPromise(uint32_t aPromiseId, - cdm::Exception aException, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageSize) -{ - if (!mCallback) { - Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s) FAIL; !mCallback", - aPromiseId, (int)aException, aSystemCode, aErrorMessage); - return; - } - Log("Decryptor::OnRejectPromise(aPromiseId=%d, err=%d, sysCode=%u, msg=%s)", - aPromiseId, (int)aException, aSystemCode, aErrorMessage); - mCallback->RejectPromise(aPromiseId, - ConvertCDMExceptionToGMPDOMException(aException), - !aErrorMessageSize ? "" : aErrorMessage, - aErrorMessageSize); -} - -static GMPSessionMessageType -ToGMPMessageType(MessageType message_type) -{ - switch (message_type) { - case kLicenseRequest: return kGMPLicenseRequest; - case kLicenseRenewal: return kGMPLicenseRenewal; - case kLicenseRelease: return kGMPLicenseRelease; - } - return kGMPMessageInvalid; -} - -void -WidevineDecryptor::OnSessionMessage(const char* aSessionId, - uint32_t aSessionIdSize, - cdm::MessageType aMessageType, - const char* aMessage, - uint32_t aMessageSize) -{ - if (!mCallback) { - Log("Decryptor::OnSessionMessage() FAIL; !mCallback"); - return; - } - Log("Decryptor::OnSessionMessage()"); - mCallback->SessionMessage(aSessionId, - aSessionIdSize, - ToGMPMessageType(aMessageType), - reinterpret_cast<const uint8_t*>(aMessage), - aMessageSize); -} - -static GMPMediaKeyStatus -ToGMPKeyStatus(KeyStatus aStatus) -{ - switch (aStatus) { - case kUsable: return kGMPUsable; - case kInternalError: return kGMPInternalError; - case kExpired: return kGMPExpired; - case kOutputRestricted: return kGMPOutputRestricted; - case kOutputDownscaled: return kGMPOutputDownscaled; - case kStatusPending: return kGMPStatusPending; - case kReleased: return kGMPReleased; - } - return kGMPUnknown; -} - -void -WidevineDecryptor::OnSessionKeysChange(const char* aSessionId, - uint32_t aSessionIdSize, - bool aHasAdditionalUsableKey, - const KeyInformation* aKeysInfo, - uint32_t aKeysInfoCount) -{ - if (!mCallback) { - Log("Decryptor::OnSessionKeysChange() FAIL; !mCallback"); - return; - } - Log("Decryptor::OnSessionKeysChange()"); - - nsTArray<GMPMediaKeyInfo> key_infos; - for (uint32_t i = 0; i < aKeysInfoCount; i++) { - key_infos.AppendElement(GMPMediaKeyInfo(aKeysInfo[i].key_id, - aKeysInfo[i].key_id_size, - ToGMPKeyStatus(aKeysInfo[i].status))); - } - mCallback->BatchedKeyStatusChanged(aSessionId, aSessionIdSize, - key_infos.Elements(), key_infos.Length()); -} - -static GMPTimestamp -ToGMPTime(Time aCDMTime) -{ - return static_cast<GMPTimestamp>(aCDMTime * 1000); -} - -void -WidevineDecryptor::OnExpirationChange(const char* aSessionId, - uint32_t aSessionIdSize, - Time aNewExpiryTime) -{ - if (!mCallback) { - Log("Decryptor::OnExpirationChange(sid=%s) t=%lf FAIL; !mCallback", - aSessionId, aNewExpiryTime); - return; - } - Log("Decryptor::OnExpirationChange(sid=%s) t=%lf", aSessionId, aNewExpiryTime); - GMPTimestamp expiry = ToGMPTime(aNewExpiryTime); - if (aNewExpiryTime == 0) { - return; - } - mCallback->ExpirationChange(aSessionId, aSessionIdSize, expiry); -} - -void -WidevineDecryptor::OnSessionClosed(const char* aSessionId, - uint32_t aSessionIdSize) -{ - if (!mCallback) { - Log("Decryptor::OnSessionClosed(sid=%s) FAIL; !mCallback", aSessionId); - return; - } - Log("Decryptor::OnSessionClosed(sid=%s)", aSessionId); - mCallback->SessionClosed(aSessionId, aSessionIdSize); -} - -void -WidevineDecryptor::SendPlatformChallenge(const char* aServiceId, - uint32_t aServiceIdSize, - const char* aChallenge, - uint32_t aChallengeSize) -{ - Log("Decryptor::SendPlatformChallenge(service_id=%s)", aServiceId); -} - -void -WidevineDecryptor::EnableOutputProtection(uint32_t aDesiredProtectionMask) -{ - Log("Decryptor::EnableOutputProtection(mask=0x%x)", aDesiredProtectionMask); -} - -void -WidevineDecryptor::QueryOutputProtectionStatus() -{ - Log("Decryptor::QueryOutputProtectionStatus()"); -} - -void -WidevineDecryptor::OnDeferredInitializationDone(StreamType aStreamType, - Status aDecoderStatus) -{ - Log("Decryptor::OnDeferredInitializationDone()"); -} - -FileIO* -WidevineDecryptor::CreateFileIO(FileIOClient* aClient) -{ - Log("Decryptor::CreateFileIO()"); - if (!mPersistentStateRequired) { - return nullptr; - } - return new WidevineFileIO(aClient); -} - -void -WidevineDecryptor::RequestStorageId(uint32_t aVersion) -{ - Log("Decryptor::RequestStorageId() aVersion = %u", aVersion); - if (aVersion >= 0x80000000) { - mCDM->OnStorageId(aVersion, nullptr, 0); - return; - } - - //TODO: Need to provide a menaingful buffer instead of a dummy one. - mCDM->OnStorageId(aVersion, new uint8_t[1024*1024], 1024 * 1024); -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h deleted file mode 100644 index f291c321d3..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ /dev/null @@ -1,132 +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 WidevineDecryptor_h_ -#define WidevineDecryptor_h_ - -#include "stddef.h" -#include "content_decryption_module.h" -#include "gmp-api/gmp-decryption.h" -#include "mozilla/RefPtr.h" -#include "WidevineUtils.h" -#include <map> - -namespace mozilla { - -class WidevineDecryptor : public GMPDecryptor - , public cdm::Host_9 -{ -public: - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WidevineDecryptor) - - WidevineDecryptor(); - - void SetCDM(RefPtr<CDMWrapper> aCDM, uint32_t aDecryptorId); - - static RefPtr<CDMWrapper> GetInstance(uint32_t aDecryptorId); - - // GMPDecryptor - void Init(GMPDecryptorCallback* aCallback, - bool aDistinctiveIdentifierRequired, - bool aPersistentStateRequired) override; - - void CreateSession(uint32_t aCreateSessionToken, - uint32_t aPromiseId, - const char* aInitDataType, - uint32_t aInitDataTypeSize, - const uint8_t* aInitData, - uint32_t aInitDataSize, - GMPSessionType aSessionType) override; - - void LoadSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) override; - - void UpdateSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength, - const uint8_t* aResponse, - uint32_t aResponseSize) override; - - void CloseSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) override; - - void RemoveSession(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdLength) override; - - void SetServerCertificate(uint32_t aPromiseId, - const uint8_t* aServerCert, - uint32_t aServerCertSize) override; - - void Decrypt(GMPBuffer* aBuffer, - GMPEncryptedBufferMetadata* aMetadata) override; - - void DecryptingComplete() override; - - - // cdm::Host_9 implementation - cdm::Buffer* Allocate(uint32_t aCapacity) override; - void SetTimer(int64_t aDelayMs, void* aContext) override; - cdm::Time GetCurrentWallTime() override; - // cdm::Host_9 interface - void OnResolveKeyStatusPromise(uint32_t aPromiseId, - cdm::KeyStatus aKeyStatus) override; - void OnResolveNewSessionPromise(uint32_t aPromiseId, - const char* aSessionId, - uint32_t aSessionIdSize) override; - void OnResolvePromise(uint32_t aPromiseId) override; - void OnRejectPromise(uint32_t aPromiseId, - cdm::Exception aException, - uint32_t aSystemCode, - const char* aErrorMessage, - uint32_t aErrorMessageSize) override; - void OnSessionMessage(const char* aSessionId, - uint32_t aSessionIdSize, - cdm::MessageType aMessageType, - const char* aMessage, - uint32_t aMessageSize) override; - void OnSessionKeysChange(const char* aSessionId, - uint32_t aSessionIdSize, - bool aHasAdditionalUsableKey, - const cdm::KeyInformation* aKeysInfo, - uint32_t aKeysInfoCount) override; - void OnExpirationChange(const char* aSessionId, - uint32_t aSessionIdSize, - cdm::Time aNewExpiryTime) override; - void OnSessionClosed(const char* aSessionId, - uint32_t aSessionIdSize) override; - void SendPlatformChallenge(const char* aServiceId, - uint32_t aServiceIdSize, - const char* aChallenge, - uint32_t aChallengeSize) override; - void EnableOutputProtection(uint32_t aDesiredProtectionMask) override; - void QueryOutputProtectionStatus() override; - void OnDeferredInitializationDone(cdm::StreamType aStreamType, - cdm::Status aDecoderStatus) override; - // cdm::Host_9 interface - // NOTE: the interface has changed upstream. - void RequestStorageId(uint32_t aVersion) override; - cdm::FileIO* CreateFileIO(cdm::FileIOClient* aClient) override; - - GMPDecryptorCallback* Callback() const { return mCallback; } - RefPtr<CDMWrapper> GetCDMWrapper() const { return mCDM; } -private: - ~WidevineDecryptor(); - RefPtr<CDMWrapper> mCDM; - cdm::ContentDecryptionModule_9* CDM() { return mCDM->GetCDM(); } - - GMPDecryptorCallback* mCallback; - std::map<uint32_t, uint32_t> mPromiseIdToNewSessionTokens; - bool mDistinctiveIdentifierRequired = false; - bool mPersistentStateRequired = false; - uint32_t mInstanceId = 0; -}; - -} // namespace mozilla - -#endif // WidevineDecryptor_h_ diff --git a/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp b/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp deleted file mode 100644 index b5fb1d705c..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "WidevineFileIO.h" -#include "WidevineUtils.h" -#include "WidevineAdapter.h" - -using namespace cdm; - -namespace mozilla { - -void -WidevineFileIO::Open(const char* aFilename, uint32_t aFilenameLength) -{ - mName = std::string(aFilename, aFilename + aFilenameLength); - GMPRecord* record = nullptr; - GMPErr err = GMPCreateRecord(aFilename, aFilenameLength, &record, static_cast<GMPRecordClient*>(this)); - if (GMP_FAILED(err)) { - Log("WidevineFileIO::Open() '%s' GMPCreateRecord failed", mName.c_str()); - mClient->OnOpenComplete(FileIOClient::kError); - return; - } - if (GMP_FAILED(record->Open())) { - Log("WidevineFileIO::Open() '%s' record open failed", mName.c_str()); - mClient->OnOpenComplete(FileIOClient::kError); - return; - } - - Log("WidevineFileIO::Open() '%s'", mName.c_str()); - mRecord = record; -} - -void -WidevineFileIO::Read() -{ - if (!mRecord) { - Log("WidevineFileIO::Read() '%s' used uninitialized!", mName.c_str()); - mClient->OnReadComplete(FileIOClient::kError, nullptr, 0); - return; - } - Log("WidevineFileIO::Read() '%s'", mName.c_str()); - mRecord->Read(); -} - -void -WidevineFileIO::Write(const uint8_t* aData, uint32_t aDataSize) -{ - if (!mRecord) { - Log("WidevineFileIO::Write() '%s' used uninitialized!", mName.c_str()); - mClient->OnWriteComplete(FileIOClient::kError); - return; - } - mRecord->Write(aData, aDataSize); -} - -void -WidevineFileIO::Close() -{ - Log("WidevineFileIO::Close() '%s'", mName.c_str()); - if (mRecord) { - mRecord->Close(); - mRecord = nullptr; - } - delete this; -} - -static FileIOClient::Status -GMPToWidevineFileStatus(GMPErr aStatus) -{ - switch (aStatus) { - case GMPRecordInUse: return FileIOClient::kInUse; - case GMPNoErr: return FileIOClient::kSuccess; - default: return FileIOClient::kError; - } -} - -void -WidevineFileIO::OpenComplete(GMPErr aStatus) -{ - Log("WidevineFileIO::OpenComplete() '%s' status=%d", mName.c_str(), aStatus); - mClient->OnOpenComplete(GMPToWidevineFileStatus(aStatus)); -} - -void -WidevineFileIO::ReadComplete(GMPErr aStatus, - const uint8_t* aData, - uint32_t aDataSize) -{ - Log("WidevineFileIO::OnReadComplete() '%s' status=%d", mName.c_str(), aStatus); - mClient->OnReadComplete(GMPToWidevineFileStatus(aStatus), aData, aDataSize); -} - -void -WidevineFileIO::WriteComplete(GMPErr aStatus) -{ - Log("WidevineFileIO::WriteComplete() '%s' status=%d", mName.c_str(), aStatus); - mClient->OnWriteComplete(GMPToWidevineFileStatus(aStatus)); -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineFileIO.h b/dom/media/gmp/widevine-adapter/WidevineFileIO.h deleted file mode 100644 index 63003d9b60..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineFileIO.h +++ /dev/null @@ -1,46 +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 WidevineFileIO_h_ -#define WidevineFileIO_h_ - -#include <stddef.h> -#include "content_decryption_module.h" -#include "gmp-api/gmp-storage.h" -#include <string> - -namespace mozilla { - -class WidevineFileIO : public cdm::FileIO - , public GMPRecordClient -{ -public: - explicit WidevineFileIO(cdm::FileIOClient* aClient) - : mClient(aClient) - , mRecord(nullptr) - {} - - // cdm::FileIO - void Open(const char* aFilename, uint32_t aFilenameLength) override; - void Read() override; - void Write(const uint8_t* aData, uint32_t aDataSize) override; - void Close() override; - - // GMPRecordClient - void OpenComplete(GMPErr aStatus) override; - void ReadComplete(GMPErr aStatus, - const uint8_t* aData, - uint32_t aDataSize) override; - void WriteComplete(GMPErr aStatus) override; - -private: - cdm::FileIOClient* mClient; - GMPRecord* mRecord; - std::string mName; -}; - -} // namespace mozilla - -#endif // WidevineFileIO_h_
\ No newline at end of file diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp b/dom/media/gmp/widevine-adapter/WidevineUtils.cpp deleted file mode 100644 index 10c6c2e18c..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.cpp +++ /dev/null @@ -1,95 +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 "WidevineUtils.h" -#include "WidevineDecryptor.h" - -#include "gmp-api/gmp-errors.h" -#include <stdarg.h> -#include <stdio.h> - -namespace mozilla { - -#ifdef ENABLE_WIDEVINE_LOG -void -Log(const char* aFormat, ...) -{ - va_list ap; - va_start(ap, aFormat); - const size_t len = 1024; - char buf[len]; - vsnprintf(buf, len, aFormat, ap); - va_end(ap); - if (getenv("GMP_LOG_FILE")) { - FILE* f = fopen(getenv("GMP_LOG_FILE"), "a"); - if (f) { - fprintf(f, "%s\n", buf); - fflush(f); - fclose(f); - f = nullptr; - } - } else { - printf("LOG: %s\n", buf); - } -} -#endif // ENABLE_WIDEVINE_LOG - -GMPErr -ToGMPErr(cdm::Status aStatus) -{ - switch (aStatus) { - case cdm::kSuccess: return GMPNoErr; - case cdm::kNeedMoreData: return GMPGenericErr; - case cdm::kNoKey: return GMPNoKeyErr; - case cdm::kInitializationError: return GMPGenericErr; - case cdm::kDecryptError: return GMPCryptoErr; - case cdm::kDecodeError: return GMPDecodeErr; - case cdm::kDeferredInitialization: return GMPGenericErr; - default: return GMPGenericErr; - } -} - -void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto, - int64_t aTimestamp, - const uint8_t* aData, - size_t aDataSize, - cdm::InputBuffer &aInputBuffer, - nsTArray<cdm::SubsampleEntry> &aSubsamples) -{ - if (aCrypto) { - aInputBuffer.key_id = aCrypto->KeyId(); - aInputBuffer.key_id_size = aCrypto->KeyIdSize(); - aInputBuffer.iv = aCrypto->IV(); - aInputBuffer.iv_size = aCrypto->IVSize(); - aInputBuffer.num_subsamples = aCrypto->NumSubsamples(); - aSubsamples.SetCapacity(aInputBuffer.num_subsamples); - const uint16_t* clear = aCrypto->ClearBytes(); - const uint32_t* cipher = aCrypto->CipherBytes(); - for (size_t i = 0; i < aCrypto->NumSubsamples(); i++) { - aSubsamples.AppendElement(cdm::SubsampleEntry(clear[i], cipher[i])); - } - } - aInputBuffer.data = aData; - aInputBuffer.data_size = aDataSize; - aInputBuffer.subsamples = aSubsamples.Elements(); - aInputBuffer.timestamp = aTimestamp; -} - -CDMWrapper::CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, - WidevineDecryptor* aDecryptor) - : mCDM(aCDM) - , mDecryptor(aDecryptor) -{ - MOZ_ASSERT(mCDM); -} - -CDMWrapper::~CDMWrapper() -{ - Log("CDMWrapper destroying CDM=%p", mCDM); - mCDM->Destroy(); - mCDM = nullptr; -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineUtils.h b/dom/media/gmp/widevine-adapter/WidevineUtils.h deleted file mode 100644 index 2f6137fe3b..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineUtils.h +++ /dev/null @@ -1,73 +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 WidevineUtils_h_ -#define WidevineUtils_h_ - -#include "stddef.h" -#include "content_decryption_module.h" -#include "gmp-api/gmp-decryption.h" -#include "gmp-api/gmp-platform.h" -#include "nsISupportsImpl.h" -#include "nsTArray.h" - -namespace mozilla { - -// Uncomment for logging... -//#define ENABLE_WIDEVINE_LOG 1 -#ifdef ENABLE_WIDEVINE_LOG -void -Log(const char* aFormat, ...); -#else -#define Log(...) -#endif // ENABLE_WIDEVINE_LOG - - -#define ENSURE_TRUE(condition, rv) { \ - if (!(condition)) {\ - Log("ENSURE_TRUE FAILED %s:%d", __FILE__, __LINE__); \ - return rv; \ - } \ -} \ - -#define ENSURE_GMP_SUCCESS(err, rv) { \ - if (GMP_FAILED(err)) {\ - Log("ENSURE_GMP_SUCCESS FAILED %s:%d", __FILE__, __LINE__); \ - return rv; \ - } \ -} \ - -GMPErr -ToGMPErr(cdm::Status aStatus); - -class WidevineDecryptor; - -class CDMWrapper { -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMWrapper) - - explicit CDMWrapper(cdm::ContentDecryptionModule_9* aCDM, - WidevineDecryptor* aDecryptor); - cdm::ContentDecryptionModule_9* GetCDM() const { return mCDM; } - void OnStorageId(uint32_t aVersion, const uint8_t* aStorageId, - uint32_t aStorageIdSize) { - mCDM->OnStorageId(aVersion, aStorageId, aStorageIdSize); - } -private: - ~CDMWrapper(); - cdm::ContentDecryptionModule_9* mCDM; - RefPtr<WidevineDecryptor> mDecryptor; -}; - -void InitInputBuffer(const GMPEncryptedBufferMetadata* aCrypto, - int64_t aTimestamp, - const uint8_t* aData, - size_t aDataSize, - cdm::InputBuffer &aInputBuffer, - nsTArray<cdm::SubsampleEntry> &aSubsamples); - -} // namespace mozilla - -#endif // WidevineUtils_h_ diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp deleted file mode 100644 index 70d2fd8e08..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.cpp +++ /dev/null @@ -1,400 +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 "WidevineVideoDecoder.h" - -#include "mp4_demuxer/AnnexB.h" -#include "WidevineUtils.h" -#include "WidevineVideoFrame.h" -#include "mozilla/Move.h" - -using namespace cdm; - -namespace mozilla { - -WidevineVideoDecoder::WidevineVideoDecoder(GMPVideoHost* aVideoHost, - RefPtr<CDMWrapper> aCDMWrapper) - : mVideoHost(aVideoHost) - , mCDMWrapper(Move(aCDMWrapper)) - , mExtraData(new MediaByteBuffer()) - , mSentInput(false) - , mCodecType(kGMPVideoCodecInvalid) - , mReturnOutputCallDepth(0) - , mDrainPending(false) - , mResetInProgress(false) -{ - // Expect to start with a CDM wrapper, will release it in DecodingComplete(). - MOZ_ASSERT(mCDMWrapper); - Log("WidevineVideoDecoder created this=%p", this); - - // Corresponding Release is in DecodingComplete(). - AddRef(); -} - -WidevineVideoDecoder::~WidevineVideoDecoder() -{ - Log("WidevineVideoDecoder destroyed this=%p", this); -} - -static -VideoDecoderConfig::VideoCodecProfile -ToCDMH264Profile(uint8_t aProfile) -{ - switch (aProfile) { - case 66: return VideoDecoderConfig::kH264ProfileBaseline; - case 77: return VideoDecoderConfig::kH264ProfileMain; - case 88: return VideoDecoderConfig::kH264ProfileExtended; - case 100: return VideoDecoderConfig::kH264ProfileHigh; - case 110: return VideoDecoderConfig::kH264ProfileHigh10; - case 122: return VideoDecoderConfig::kH264ProfileHigh422; - case 144: return VideoDecoderConfig::kH264ProfileHigh444Predictive; - } - return VideoDecoderConfig::kUnknownVideoCodecProfile; -} - -void -WidevineVideoDecoder::InitDecode(const GMPVideoCodec& aCodecSettings, - const uint8_t* aCodecSpecific, - uint32_t aCodecSpecificLength, - GMPVideoDecoderCallback* aCallback, - int32_t aCoreCount) -{ - mCallback = aCallback; - VideoDecoderConfig config; - mCodecType = aCodecSettings.mCodecType; - if (mCodecType == kGMPVideoCodecH264) { - config.codec = VideoDecoderConfig::kCodecH264; - const GMPVideoCodecH264* h264 = (const GMPVideoCodecH264*)(aCodecSpecific); - config.profile = ToCDMH264Profile(h264->mAVCC.mProfile); - } else if (mCodecType == kGMPVideoCodecVP8) { - config.codec = VideoDecoderConfig::kCodecVp8; - config.profile = VideoDecoderConfig::kProfileNotNeeded; - } else if (mCodecType == kGMPVideoCodecVP9) { - config.codec = VideoDecoderConfig::kCodecVp9; - config.profile = VideoDecoderConfig::kProfileNotNeeded; - } else { - mCallback->Error(GMPInvalidArgErr); - return; - } - config.format = kYv12; - config.coded_size = Size(aCodecSettings.mWidth, aCodecSettings.mHeight); - mExtraData->AppendElements(aCodecSpecific + 1, aCodecSpecificLength); - config.extra_data = mExtraData->Elements(); - config.extra_data_size = mExtraData->Length(); - Status rv = CDM()->InitializeVideoDecoder(config); - if (rv != kSuccess) { - mCallback->Error(ToGMPErr(rv)); - return; - } - Log("WidevineVideoDecoder::InitDecode() rv=%d", rv); - mAnnexB = mp4_demuxer::AnnexB::ConvertExtraDataToAnnexB(mExtraData); -} - -void -WidevineVideoDecoder::Decode(GMPVideoEncodedFrame* aInputFrame, - bool aMissingFrames, - const uint8_t* aCodecSpecificInfo, - uint32_t aCodecSpecificInfoLength, - int64_t aRenderTimeMs) -{ - // We should not be given new input if a drain has been initiated - MOZ_ASSERT(!mDrainPending); - // We may not get the same out of the CDM decoder as we put in, and there - // may be some latency, i.e. we may need to input (say) 30 frames before - // we receive output. So we need to store the durations of the frames input, - // and retrieve them on output. - mFrameDurations[aInputFrame->TimeStamp()] = aInputFrame->Duration(); - - mSentInput = true; - InputBuffer sample; - - RefPtr<MediaRawData> raw( - new MediaRawData(aInputFrame->Buffer(), aInputFrame->Size())); - if (aInputFrame->Size() && !raw->Data()) { - // OOM. - mCallback->Error(GMPAllocErr); - return; - } - raw->mExtraData = mExtraData; - raw->mKeyframe = (aInputFrame->FrameType() == kGMPKeyFrame); - if (mCodecType == kGMPVideoCodecH264) { - // Convert input from AVCC, which GMPAPI passes in, to AnnexB, which - // Chromium uses internally. - mp4_demuxer::AnnexB::ConvertSampleToAnnexB(raw); - } - - const GMPEncryptedBufferMetadata* crypto = aInputFrame->GetDecryptionData(); - nsTArray<SubsampleEntry> subsamples; - InitInputBuffer(crypto, aInputFrame->TimeStamp(), raw->Data(), raw->Size(), sample, subsamples); - - // For keyframes, ConvertSampleToAnnexB will stick the AnnexB extra data - // at the start of the input. So we need to account for that as clear data - // in the subsamples. - if (raw->mKeyframe && !subsamples.IsEmpty() && mCodecType == kGMPVideoCodecH264) { - subsamples[0].clear_bytes += mAnnexB->Length(); - } - - WidevineVideoFrame frame; - Status rv = CDM()->DecryptAndDecodeFrame(sample, &frame); - Log("WidevineVideoDecoder::Decode(timestamp=%lld) rv=%d", sample.timestamp, rv); - - // Destroy frame, so that the shmem is now free to be used to return - // output to the Gecko process. - aInputFrame->Destroy(); - aInputFrame = nullptr; - - if (rv == kSuccess) { - if (!ReturnOutput(frame)) { - Log("WidevineVideoDecoder::Decode() Failed in ReturnOutput()"); - mCallback->Error(GMPDecodeErr); - return; - } - // A reset should only be started at most at level mReturnOutputCallDepth 1, - // and if it's started it should be finished by that call by the time - // the it returns, so it should always be false by this point. - MOZ_ASSERT(!mResetInProgress); - // Only request more data if we don't have pending samples. - if (mFrameAllocationQueue.empty()) { - MOZ_ASSERT(mCDMWrapper); - mCallback->InputDataExhausted(); - } - } else if (rv == kNeedMoreData) { - MOZ_ASSERT(mCDMWrapper); - mCallback->InputDataExhausted(); - } else { - mCallback->Error(ToGMPErr(rv)); - } - // Finish a drain if pending and we have no pending ReturnOutput calls on the stack. - if (mDrainPending && mReturnOutputCallDepth == 0) { - Drain(); - } -} - -// Util class to assist with counting mReturnOutputCallDepth. -class CounterHelper { -public: - // RAII, increment counter - explicit CounterHelper(int32_t& counter) - : mCounter(counter) - { - mCounter++; - } - - // RAII, decrement counter - ~CounterHelper() - { - mCounter--; - } - -private: - int32_t& mCounter; -}; - -// Util class to make sure GMP frames are freed. Holds a GMPVideoi420Frame* -// and will destroy it when the helper is destroyed unless the held frame -// if forgotten with ForgetFrame. -class FrameDestroyerHelper { -public: - explicit FrameDestroyerHelper(GMPVideoi420Frame*& frame) - : frame(frame) - { - } - - // RAII, destroy frame if held. - ~FrameDestroyerHelper() - { - if (frame) { - frame->Destroy(); - } - frame = nullptr; - } - - // Forget the frame without destroying it. - void ForgetFrame() - { - frame = nullptr; - } - -private: - GMPVideoi420Frame* frame; -}; - - -// Special handing is needed around ReturnOutput as it spins the IPC message -// queue when creating an empty frame and can end up with reentrant calls into -// the class methods. -bool -WidevineVideoDecoder::ReturnOutput(WidevineVideoFrame& aCDMFrame) -{ - MOZ_ASSERT(mReturnOutputCallDepth >= 0); - CounterHelper counterHelper(mReturnOutputCallDepth); - mFrameAllocationQueue.push_back(Move(aCDMFrame)); - if (mReturnOutputCallDepth > 1) { - // In a reentrant call. - return true; - } - while (!mFrameAllocationQueue.empty()) { - MOZ_ASSERT(mReturnOutputCallDepth == 1); - // If we're at call level 1 a reset should not have been started. A - // reset may be received during CreateEmptyFrame below, but we should not - // be in a reset at this stage -- this would indicate receiving decode - // messages before completing our reset, which we should not. - MOZ_ASSERT(!mResetInProgress); - WidevineVideoFrame currentCDMFrame = Move(mFrameAllocationQueue.front()); - mFrameAllocationQueue.pop_front(); - GMPVideoFrame* f = nullptr; - auto err = mVideoHost->CreateFrame(kGMPI420VideoFrame, &f); - if (GMP_FAILED(err) || !f) { - Log("Failed to create i420 frame!\n"); - return false; - } - auto gmpFrame = static_cast<GMPVideoi420Frame*>(f); - FrameDestroyerHelper frameDestroyerHelper(gmpFrame); - Size size = currentCDMFrame.Size(); - const int32_t yStride = currentCDMFrame.Stride(VideoFrame::kYPlane); - const int32_t uStride = currentCDMFrame.Stride(VideoFrame::kUPlane); - const int32_t vStride = currentCDMFrame.Stride(VideoFrame::kVPlane); - const int32_t halfHeight = size.height / 2; - // This call can cause a shmem alloc, during this alloc other calls - // may be made to this class and placed on the stack. ***WARNING***: - // other IPC calls can happen during this call, resulting in calls - // being made to the CDM. After this call state can have changed, - // and should be reevaluated. - err = gmpFrame->CreateEmptyFrame(size.width, - size.height, - yStride, - uStride, - vStride); - // Assert possible reentrant calls or resets haven't altered level unexpectedly. - MOZ_ASSERT(mReturnOutputCallDepth == 1); - ENSURE_GMP_SUCCESS(err, false); - - // If a reset started we need to dump the current frame and complete the reset. - if (mResetInProgress) { - MOZ_ASSERT(mCDMWrapper); - MOZ_ASSERT(mFrameAllocationQueue.empty()); - CompleteReset(); - return true; - } - - err = gmpFrame->SetWidth(size.width); - ENSURE_GMP_SUCCESS(err, false); - - err = gmpFrame->SetHeight(size.height); - ENSURE_GMP_SUCCESS(err, false); - - Buffer* buffer = currentCDMFrame.FrameBuffer(); - uint8_t* outBuffer = gmpFrame->Buffer(kGMPYPlane); - ENSURE_TRUE(outBuffer != nullptr, false); - MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPYPlane) >= yStride*size.height); - memcpy(outBuffer, - buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kYPlane), - yStride * size.height); - - outBuffer = gmpFrame->Buffer(kGMPUPlane); - ENSURE_TRUE(outBuffer != nullptr, false); - MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPUPlane) >= uStride * halfHeight); - memcpy(outBuffer, - buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kUPlane), - uStride * halfHeight); - - outBuffer = gmpFrame->Buffer(kGMPVPlane); - ENSURE_TRUE(outBuffer != nullptr, false); - MOZ_ASSERT(gmpFrame->AllocatedSize(kGMPVPlane) >= vStride * halfHeight); - memcpy(outBuffer, - buffer->Data() + currentCDMFrame.PlaneOffset(VideoFrame::kVPlane), - vStride * halfHeight); - - gmpFrame->SetTimestamp(currentCDMFrame.Timestamp()); - - auto d = mFrameDurations.find(currentCDMFrame.Timestamp()); - if (d != mFrameDurations.end()) { - gmpFrame->SetDuration(d->second); - mFrameDurations.erase(d); - } - - // Forget frame so it's not deleted, call back taking ownership. - frameDestroyerHelper.ForgetFrame(); - mCallback->Decoded(gmpFrame); - } - - return true; -} - -void -WidevineVideoDecoder::Reset() -{ - Log("WidevineVideoDecoder::Reset() mSentInput=%d", mSentInput); - // We shouldn't reset if a drain is pending. - MOZ_ASSERT(!mDrainPending); - mResetInProgress = true; - if (mSentInput) { - CDM()->ResetDecoder(kStreamTypeVideo); - } - // Remove queued frames, but do not reset mReturnOutputCallDepth, let the - // ReturnOutput calls unwind and decrement the counter as needed. - mFrameAllocationQueue.clear(); - mFrameDurations.clear(); - // Only if no ReturnOutput calls are in progress can we complete, otherwise - // ReturnOutput needs to finalize the reset. - if (mReturnOutputCallDepth == 0) { - CompleteReset(); - } -} - -void -WidevineVideoDecoder::CompleteReset() -{ - mCallback->ResetComplete(); - mSentInput = false; - mResetInProgress = false; -} - -void -WidevineVideoDecoder::Drain() -{ - Log("WidevineVideoDecoder::Drain()"); - if (mReturnOutputCallDepth > 0) { - Log("Drain call is reentrant, postponing drain"); - mDrainPending = true; - return; - } - - Status rv = kSuccess; - while (rv == kSuccess) { - WidevineVideoFrame frame; - InputBuffer sample; - Status rv = CDM()->DecryptAndDecodeFrame(sample, &frame); - Log("WidevineVideoDecoder::Drain(); DecryptAndDecodeFrame() rv=%d", rv); - if (frame.Format() == kUnknownVideoFormat) { - break; - } - if (rv == kSuccess) { - if (!ReturnOutput(frame)) { - Log("WidevineVideoDecoder::Decode() Failed in ReturnOutput()"); - } - } - } - // Shouldn't be reset while draining. - MOZ_ASSERT(!mResetInProgress); - - CDM()->ResetDecoder(kStreamTypeVideo); - mDrainPending = false; - mCallback->DrainComplete(); -} - -void -WidevineVideoDecoder::DecodingComplete() -{ - Log("WidevineVideoDecoder::DecodingComplete()"); - if (mCDMWrapper) { - CDM()->DeinitializeDecoder(kStreamTypeVideo); - mCDMWrapper = nullptr; - } - // Release that corresponds to AddRef() in constructor. - Release(); -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h b/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h deleted file mode 100644 index f5e63519be..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineVideoDecoder.h +++ /dev/null @@ -1,80 +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 WidevineVideoDecoder_h_ -#define WidevineVideoDecoder_h_ - -#include "stddef.h" -#include "content_decryption_module.h" -#include "gmp-api/gmp-video-decode.h" -#include "gmp-api/gmp-video-host.h" -#include "MediaData.h" -#include "nsISupportsImpl.h" -#include "nsTArray.h" -#include "WidevineDecryptor.h" -#include "WidevineVideoFrame.h" -#include <map> -#include <deque> - -namespace mozilla { - -class WidevineVideoDecoder : public GMPVideoDecoder { -public: - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WidevineVideoDecoder) - - WidevineVideoDecoder(GMPVideoHost* aVideoHost, - RefPtr<CDMWrapper> aCDMWrapper); - void InitDecode(const GMPVideoCodec& aCodecSettings, - const uint8_t* aCodecSpecific, - uint32_t aCodecSpecificLength, - GMPVideoDecoderCallback* aCallback, - int32_t aCoreCount) override; - void Decode(GMPVideoEncodedFrame* aInputFrame, - bool aMissingFrames, - const uint8_t* aCodecSpecificInfo, - uint32_t aCodecSpecificInfoLength, - int64_t aRenderTimeMs = -1) override; - void Reset() override; - void Drain() override; - void DecodingComplete() override; - -private: - - ~WidevineVideoDecoder(); - - cdm::ContentDecryptionModule_9* CDM() const { - // CDM should only be accessed before 'DecodingComplete'. - MOZ_ASSERT(mCDMWrapper); - // CDMWrapper ensure the CDM is non-null, no need to check again. - return mCDMWrapper->GetCDM(); - } - - bool ReturnOutput(WidevineVideoFrame& aFrame); - void CompleteReset(); - - GMPVideoHost* mVideoHost; - RefPtr<CDMWrapper> mCDMWrapper; - RefPtr<MediaByteBuffer> mExtraData; - RefPtr<MediaByteBuffer> mAnnexB; - GMPVideoDecoderCallback* mCallback; - std::map<uint64_t, uint64_t> mFrameDurations; - bool mSentInput; - GMPVideoCodecType mCodecType; - // Frames waiting on allocation - std::deque<WidevineVideoFrame> mFrameAllocationQueue; - // Number of calls of ReturnOutput currently in progress. - int32_t mReturnOutputCallDepth; - // If we're waiting to drain. Used to prevent drain completing while - // ReturnOutput calls are still on the stack. - bool mDrainPending; - // If a reset is being performed. Used to track if ReturnOutput should - // dump current frame. - bool mResetInProgress; -}; - -} // namespace mozilla - -#endif // WidevineVideoDecoder_h_ diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp b/dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp deleted file mode 100644 index 4221bf15b8..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.cpp +++ /dev/null @@ -1,126 +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 "WidevineVideoFrame.h" - -#include "WidevineUtils.h" - -using namespace cdm; - -namespace mozilla { - -WidevineVideoFrame::WidevineVideoFrame() - : mFormat(kUnknownVideoFormat) - , mSize(0,0) - , mBuffer(nullptr) - , mTimestamp(0) -{ - Log("WidevineVideoFrame::WidevineVideoFrame() this=%p", this); - memset(mPlaneOffsets, 0, sizeof(mPlaneOffsets)); - memset(mPlaneStrides, 0, sizeof(mPlaneStrides)); -} - -WidevineVideoFrame::WidevineVideoFrame(WidevineVideoFrame&& aOther) - : mFormat(aOther.mFormat) - , mSize(aOther.mSize) - , mBuffer(aOther.mBuffer) - , mTimestamp(aOther.mTimestamp) -{ - Log("WidevineVideoFrame::WidevineVideoFrame(WidevineVideoFrame&&) this=%p, other=%p", - this, &aOther); - memcpy(mPlaneOffsets, aOther.mPlaneOffsets, sizeof(mPlaneOffsets)); - memcpy(mPlaneStrides, aOther.mPlaneStrides, sizeof(mPlaneStrides)); - aOther.mBuffer = nullptr; -} - -WidevineVideoFrame::~WidevineVideoFrame() -{ - if (mBuffer) { - mBuffer->Destroy(); - mBuffer = nullptr; - } -} - -void -WidevineVideoFrame::SetFormat(cdm::VideoFormat aFormat) -{ - Log("WidevineVideoFrame::SetFormat(%d) this=%p", aFormat, this); - mFormat = aFormat; -} - -cdm::VideoFormat -WidevineVideoFrame::Format() const -{ - return mFormat; -} - -void -WidevineVideoFrame::SetSize(cdm::Size aSize) -{ - Log("WidevineVideoFrame::SetSize(%d,%d) this=%p", aSize.width, aSize.height, this); - mSize.width = aSize.width; - mSize.height = aSize.height; -} - -cdm::Size -WidevineVideoFrame::Size() const -{ - return mSize; -} - -void -WidevineVideoFrame::SetFrameBuffer(cdm::Buffer* aFrameBuffer) -{ - Log("WidevineVideoFrame::SetFrameBuffer(%p) this=%p", aFrameBuffer, this); - MOZ_ASSERT(!mBuffer); - mBuffer = aFrameBuffer; -} - -cdm::Buffer* -WidevineVideoFrame::FrameBuffer() -{ - return mBuffer; -} - -void -WidevineVideoFrame::SetPlaneOffset(cdm::VideoFrame::VideoPlane aPlane, uint32_t aOffset) -{ - Log("WidevineVideoFrame::SetPlaneOffset(%d, %d) this=%p", aPlane, aOffset, this); - mPlaneOffsets[aPlane] = aOffset; -} - -uint32_t -WidevineVideoFrame::PlaneOffset(cdm::VideoFrame::VideoPlane aPlane) -{ - return mPlaneOffsets[aPlane]; -} - -void -WidevineVideoFrame::SetStride(cdm::VideoFrame::VideoPlane aPlane, uint32_t aStride) -{ - Log("WidevineVideoFrame::SetStride(%d, %d) this=%p", aPlane, aStride, this); - mPlaneStrides[aPlane] = aStride; -} - -uint32_t -WidevineVideoFrame::Stride(cdm::VideoFrame::VideoPlane aPlane) -{ - return mPlaneStrides[aPlane]; -} - -void -WidevineVideoFrame::SetTimestamp(int64_t timestamp) -{ - Log("WidevineVideoFrame::SetTimestamp(%lld) this=%p", timestamp, this); - mTimestamp = timestamp; -} - -int64_t -WidevineVideoFrame::Timestamp() const -{ - return mTimestamp; -} - -} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.h b/dom/media/gmp/widevine-adapter/WidevineVideoFrame.h deleted file mode 100644 index 96d4f20f8e..0000000000 --- a/dom/media/gmp/widevine-adapter/WidevineVideoFrame.h +++ /dev/null @@ -1,50 +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 WidevineVideoFrame_h_ -#define WidevineVideoFrame_h_ - -#include "stddef.h" -#include "content_decryption_module.h" -#include <vector> - -namespace mozilla { - -class WidevineVideoFrame : public cdm::VideoFrame { -public: - WidevineVideoFrame(); - WidevineVideoFrame(WidevineVideoFrame&& other); - ~WidevineVideoFrame(); - - void SetFormat(cdm::VideoFormat aFormat) override; - cdm::VideoFormat Format() const override; - - void SetSize(cdm::Size aSize) override; - cdm::Size Size() const override; - - void SetFrameBuffer(cdm::Buffer* aFrameBuffer) override; - cdm::Buffer* FrameBuffer() override; - - void SetPlaneOffset(cdm::VideoFrame::VideoPlane aPlane, uint32_t aOffset) override; - uint32_t PlaneOffset(cdm::VideoFrame::VideoPlane aPlane) override; - - void SetStride(cdm::VideoFrame::VideoPlane aPlane, uint32_t aStride) override; - uint32_t Stride(cdm::VideoFrame::VideoPlane aPlane) override; - - void SetTimestamp(int64_t aTimestamp) override; - int64_t Timestamp() const override; - -protected: - cdm::VideoFormat mFormat; - cdm::Size mSize; - cdm::Buffer* mBuffer; - uint32_t mPlaneOffsets[kMaxPlanes]; - uint32_t mPlaneStrides[kMaxPlanes]; - int64_t mTimestamp; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module.h b/dom/media/gmp/widevine-adapter/content_decryption_module.h deleted file mode 100644 index 0539135fbe..0000000000 --- a/dom/media/gmp/widevine-adapter/content_decryption_module.h +++ /dev/null @@ -1,1278 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CDM_CONTENT_DECRYPTION_MODULE_H_ -#define CDM_CONTENT_DECRYPTION_MODULE_H_ - -#include "content_decryption_module_export.h" - -#if defined(_MSC_VER) -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef int int32_t; -typedef __int64 int64_t; -#else -#include <stdint.h> -#endif - -// Define CDM_CLASS_API to export class types. We have to add visibility -// attributes to make sure virtual tables in CDM consumer and CDM implementation -// are the same. Generally, it was always a good idea, as there're no guarantees -// about that for the internal symbols, but it has only become a practical issue -// after introduction of LTO devirtualization. See more details on -// https://crbug.com/609564#c35 -#if defined(_WIN32) -#if defined(__clang__) -#define CDM_CLASS_API [[clang::lto_visibility_public]] -#else -#define CDM_CLASS_API -#endif -#else // defined(_WIN32) -#define CDM_CLASS_API __attribute__((visibility("default"))) -#endif // defined(_WIN32) - -// The version number must be rolled when the exported functions are updated! -// If the CDM and the adapter use different versions of these functions, the -// adapter will fail to load or crash! -#define CDM_MODULE_VERSION 4 - -// Build the versioned entrypoint name. -// The extra macros are necessary to expand version to an actual value. -#define INITIALIZE_CDM_MODULE \ - BUILD_ENTRYPOINT(InitializeCdmModule, CDM_MODULE_VERSION) -#define BUILD_ENTRYPOINT(name, version) \ - BUILD_ENTRYPOINT_NO_EXPANSION(name, version) -#define BUILD_ENTRYPOINT_NO_EXPANSION(name, version) name##_##version - -extern "C" { -CDM_API void INITIALIZE_CDM_MODULE(); - -CDM_API void DeinitializeCdmModule(); - -// Returns a pointer to the requested CDM Host interface upon success. -// Returns NULL if the requested CDM Host interface is not supported. -// The caller should cast the returned pointer to the type matching -// |host_interface_version|. -typedef void* (*GetCdmHostFunc)(int host_interface_version, void* user_data); - -// Returns a pointer to the requested CDM upon success. -// Returns NULL if an error occurs or the requested |cdm_interface_version| or -// |key_system| is not supported or another error occurs. -// The caller should cast the returned pointer to the type matching -// |cdm_interface_version|. -// Caller retains ownership of arguments and must call Destroy() on the returned -// object. -CDM_API void* CreateCdmInstance( - int cdm_interface_version, - const char* key_system, uint32_t key_system_size, - GetCdmHostFunc get_cdm_host_func, void* user_data); - -CDM_API const char* GetCdmVersion(); -} - -namespace cdm { - -class CDM_CLASS_API AudioFrames; -class CDM_CLASS_API DecryptedBlock; -class CDM_CLASS_API VideoFrame; - -class CDM_CLASS_API Host_8; -class CDM_CLASS_API Host_9; - -enum Status { - kSuccess = 0, - kNeedMoreData, // Decoder needs more data to produce a decoded frame/sample. - kNoKey, // The required decryption key is not available. - kInitializationError, // Initialization error. - kDecryptError, // Decryption failed. - kDecodeError, // Error decoding audio or video. - kDeferredInitialization // Decoder is not ready for initialization. -}; - -// This must at least contain the exceptions defined in the spec: -// https://w3c.github.io/encrypted-media/#exceptions -// The following starts with the list of DOM4 exceptions from: -// http://www.w3.org/TR/dom/#domexception -// Some DOM4 exceptions are not included as they are not expected to be used. -// Should only be used on Host_8 and before. -enum Error { - kNotSupportedError = 9, - kInvalidStateError = 11, - kInvalidAccessError = 15, - kQuotaExceededError = 22, - - // Additional exceptions that do not have assigned codes. - // There are other non-EME-specific values, not included in this list. - kUnknownError = 30, - - // Additional values from previous EME versions. They currently have no - // matching DOMException. - kClientError = 100, - kOutputError = 101 -}; - -// Exceptions used by the CDM to reject promises. -// https://w3c.github.io/encrypted-media/#exceptions -enum Exception { - kExceptionTypeError, - kExceptionNotSupportedError, - kExceptionInvalidStateError, - kExceptionQuotaExceededError -}; - -// Time is defined as the number of seconds since the Epoch -// (00:00:00 UTC, January 1, 1970), not including any added leap second. -// Also see Time definition in spec: https://w3c.github.io/encrypted-media/#time -// Note that Time is defined in millisecond accuracy in the spec but in second -// accuracy here. -typedef double Time; - -// An input buffer can be split into several continuous subsamples. -// A SubsampleEntry specifies the number of clear and cipher bytes in each -// subsample. For example, the following buffer has three subsamples: -// -// |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->| -// | clear1 | cipher1 | clear2 | cipher2 | clear3 | cipher3 | -// -// For decryption, all of the cipher bytes in a buffer should be concatenated -// (in the subsample order) into a single logical stream. The clear bytes should -// not be considered as part of decryption. -// -// Stream to decrypt: | cipher1 | cipher2 | cipher3 | -// Decrypted stream: | decrypted1| decrypted2 | decrypted3 | -// -// After decryption, the decrypted bytes should be copied over the position -// of the corresponding cipher bytes in the original buffer to form the output -// buffer. Following the above example, the decrypted buffer should be: -// -// |<----- subsample1 ----->|<----- subsample2 ----->|<----- subsample3 ----->| -// | clear1 | decrypted1| clear2 | decrypted2 | clear3 | decrypted3 | -// -struct SubsampleEntry { - SubsampleEntry(uint32_t clear_bytes, uint32_t cipher_bytes) - : clear_bytes(clear_bytes), cipher_bytes(cipher_bytes) {} - - uint32_t clear_bytes; - uint32_t cipher_bytes; -}; - -// Represents an input buffer to be decrypted (and possibly decoded). It does -// not own any pointers in this struct. If |iv_size| = 0, the data is -// unencrypted. -struct InputBuffer { - InputBuffer() - : data(nullptr), - data_size(0), - key_id(nullptr), - key_id_size(0), - iv(nullptr), - iv_size(0), - subsamples(nullptr), - num_subsamples(0), - timestamp(0) {} - - const uint8_t* data; // Pointer to the beginning of the input data. - uint32_t data_size; // Size (in bytes) of |data|. - - const uint8_t* key_id; // Key ID to identify the decryption key. - uint32_t key_id_size; // Size (in bytes) of |key_id|. - - const uint8_t* iv; // Initialization vector. - uint32_t iv_size; // Size (in bytes) of |iv|. - - const struct SubsampleEntry* subsamples; - uint32_t num_subsamples; // Number of subsamples in |subsamples|. - - int64_t timestamp; // Presentation timestamp in microseconds. -}; - -struct AudioDecoderConfig { - enum AudioCodec { - kUnknownAudioCodec = 0, - kCodecVorbis, - kCodecAac - }; - - AudioDecoderConfig() - : codec(kUnknownAudioCodec), - channel_count(0), - bits_per_channel(0), - samples_per_second(0), - extra_data(nullptr), - extra_data_size(0) {} - - AudioCodec codec; - int32_t channel_count; - int32_t bits_per_channel; - int32_t samples_per_second; - - // Optional byte data required to initialize audio decoders, such as the - // vorbis setup header. - uint8_t* extra_data; - uint32_t extra_data_size; -}; - -// Supported sample formats for AudioFrames. -enum AudioFormat { - kUnknownAudioFormat = 0, // Unknown format value. Used for error reporting. - kAudioFormatU8, // Interleaved unsigned 8-bit w/ bias of 128. - kAudioFormatS16, // Interleaved signed 16-bit. - kAudioFormatS32, // Interleaved signed 32-bit. - kAudioFormatF32, // Interleaved float 32-bit. - kAudioFormatPlanarS16, // Signed 16-bit planar. - kAudioFormatPlanarF32, // Float 32-bit planar. -}; - -// Surface formats based on FOURCC labels, see: http://www.fourcc.org/yuv.php -// Values are chosen to be consistent with Chromium's VideoPixelFormat values. -enum VideoFormat { - kUnknownVideoFormat = 0, // Unknown format value. Used for error reporting. - kYv12 = 1, // 12bpp YVU planar 1x1 Y, 2x2 VU samples. - kI420 = 2, // 12bpp YUV planar 1x1 Y, 2x2 UV samples. - - // In the following formats, each sample uses 16-bit in storage, while the - // sample value is stored in the least significant N bits where N is - // specified by the number after "P". For example, for YUV420P9, each Y, U, - // and V sample is stored in the least significant 9 bits in a 2-byte block. - kYUV420P9 = 16, - kYUV420P10 = 17, - kYUV422P9 = 18, - kYUV422P10 = 19, - kYUV444P9 = 20, - kYUV444P10 = 21, - kYUV420P12 = 22, - kYUV422P12 = 23, - kYUV444P12 = 24, -}; - -struct Size { - Size() : width(0), height(0) {} - Size(int32_t width, int32_t height) : width(width), height(height) {} - - int32_t width; - int32_t height; -}; - -struct VideoDecoderConfig { - enum VideoCodec { - kUnknownVideoCodec = 0, - kCodecVp8, - kCodecH264, - kCodecVp9 - }; - - enum VideoCodecProfile { - kUnknownVideoCodecProfile = 0, - kProfileNotNeeded, - kH264ProfileBaseline, - kH264ProfileMain, - kH264ProfileExtended, - kH264ProfileHigh, - kH264ProfileHigh10, - kH264ProfileHigh422, - kH264ProfileHigh444Predictive, - // VP9 Profiles are only passed in starting from CDM_9. - kVP9Profile0, - kVP9Profile1, - kVP9Profile2, - kVP9Profile3 - }; - - VideoDecoderConfig() - : codec(kUnknownVideoCodec), - profile(kUnknownVideoCodecProfile), - format(kUnknownVideoFormat), - extra_data(nullptr), - extra_data_size(0) {} - - VideoCodec codec; - VideoCodecProfile profile; - VideoFormat format; - - // Width and height of video frame immediately post-decode. Not all pixels - // in this region are valid. - Size coded_size; - - // Optional byte data required to initialize video decoders, such as H.264 - // AAVC data. - uint8_t* extra_data; - uint32_t extra_data_size; -}; - -enum StreamType { - kStreamTypeAudio = 0, - kStreamTypeVideo = 1 -}; - -// Structure provided to ContentDecryptionModule::OnPlatformChallengeResponse() -// after a platform challenge was initiated via Host::SendPlatformChallenge(). -// All values will be NULL / zero in the event of a challenge failure. -struct PlatformChallengeResponse { - // |challenge| provided during Host::SendPlatformChallenge() combined with - // nonce data and signed with the platform's private key. - const uint8_t* signed_data; - uint32_t signed_data_length; - - // RSASSA-PKCS1-v1_5-SHA256 signature of the |signed_data| block. - const uint8_t* signed_data_signature; - uint32_t signed_data_signature_length; - - // X.509 device specific certificate for the |service_id| requested. - const uint8_t* platform_key_certificate; - uint32_t platform_key_certificate_length; -}; - -// Used when passing arrays of binary data. Does not own the referenced data. -struct BinaryData { - BinaryData() : data(nullptr), length(0) {} - const uint8_t* data; - uint32_t length; -}; - -// The current status of the associated key. The valid types are defined in the -// spec: https://w3c.github.io/encrypted-media/#idl-def-MediaKeyStatus -enum KeyStatus { - kUsable = 0, - kInternalError = 1, - kExpired = 2, - kOutputRestricted = 3, - kOutputDownscaled = 4, - kStatusPending = 5, - kReleased = 6 -}; - -// Used when passing arrays of key information. Does not own the referenced -// data. |system_code| is an additional error code for unusable keys and -// should be 0 when |status| == kUsable. -struct KeyInformation { - KeyInformation() - : key_id(nullptr), - key_id_size(0), - status(kInternalError), - system_code(0) {} - const uint8_t* key_id; - uint32_t key_id_size; - KeyStatus status; - uint32_t system_code; -}; - -// Supported output protection methods for use with EnableOutputProtection() and -// returned by OnQueryOutputProtectionStatus(). -enum OutputProtectionMethods { - kProtectionNone = 0, - kProtectionHDCP = 1 << 0 -}; - -// Connected output link types returned by OnQueryOutputProtectionStatus(). -enum OutputLinkTypes { - kLinkTypeNone = 0, - kLinkTypeUnknown = 1 << 0, - kLinkTypeInternal = 1 << 1, - kLinkTypeVGA = 1 << 2, - kLinkTypeHDMI = 1 << 3, - kLinkTypeDVI = 1 << 4, - kLinkTypeDisplayPort = 1 << 5, - kLinkTypeNetwork = 1 << 6 -}; - -// Result of the QueryOutputProtectionStatus() call. -enum QueryResult { - kQuerySucceeded = 0, - kQueryFailed -}; - -// The Initialization Data Type. The valid types are defined in the spec: -// http://w3c.github.io/encrypted-media/initdata-format-registry.html#registry -enum InitDataType { - kCenc = 0, - kKeyIds = 1, - kWebM = 2 -}; - -// The type of session to create. The valid types are defined in the spec: -// https://w3c.github.io/encrypted-media/#idl-def-SessionType -enum SessionType { - kTemporary = 0, - kPersistentLicense = 1, - kPersistentKeyRelease = 2 -}; - -// The type of the message event. The valid types are defined in the spec: -// https://w3c.github.io/encrypted-media/#idl-def-MediaKeyMessageType -enum MessageType { - kLicenseRequest = 0, - kLicenseRenewal = 1, - kLicenseRelease = 2 -}; - -enum HdcpVersion { - kHdcpVersionNone, - kHdcpVersion1_0, - kHdcpVersion1_1, - kHdcpVersion1_2, - kHdcpVersion1_3, - kHdcpVersion1_4, - kHdcpVersion2_0, - kHdcpVersion2_1, - kHdcpVersion2_2 -}; - -struct Policy { - Policy() : min_hdcp_version(kHdcpVersionNone) {} - - HdcpVersion min_hdcp_version; -}; - -// FileIO interface provides a way for the CDM to store data in a file in -// persistent storage. This interface aims only at providing basic read/write -// capabilities and should not be used as a full fledged file IO API. -// Each CDM and origin (e.g. HTTPS, "foo.example.com", 443) combination has -// its own persistent storage. All instances of a given CDM associated with a -// given origin share the same persistent storage. -// Note to implementors of this interface: -// Per-origin storage and the ability for users to clear it are important. -// See http://www.w3.org/TR/encrypted-media/#privacy-storedinfo. -class CDM_CLASS_API FileIO { - public: - // Opens the file with |file_name| for read and write. - // FileIOClient::OnOpenComplete() will be called after the opening - // operation finishes. - // - When the file is opened by a CDM instance, it will be classified as "in - // use". In this case other CDM instances in the same domain may receive - // kInUse status when trying to open it. - // - |file_name| must only contain letters (A-Za-z), digits(0-9), or "._-". - // It must not start with an underscore ('_'), and must be at least 1 - // character and no more than 256 characters long. - virtual void Open(const char* file_name, uint32_t file_name_size) = 0; - - // Reads the contents of the file. FileIOClient::OnReadComplete() will be - // called with the read status. Read() should not be called if a previous - // Read() or Write() call is still pending; otherwise OnReadComplete() will - // be called with kInUse. - virtual void Read() = 0; - - // Writes |data_size| bytes of |data| into the file. - // FileIOClient::OnWriteComplete() will be called with the write status. - // All existing contents in the file will be overwritten. Calling Write() with - // NULL |data| will clear all contents in the file. Write() should not be - // called if a previous Write() or Read() call is still pending; otherwise - // OnWriteComplete() will be called with kInUse. - virtual void Write(const uint8_t* data, uint32_t data_size) = 0; - - // Closes the file if opened, destroys this FileIO object and releases any - // resources allocated. The CDM must call this method when it finished using - // this object. A FileIO object must not be used after Close() is called. - virtual void Close() = 0; - - protected: - FileIO() {} - virtual ~FileIO() {} -}; - -// Responses to FileIO calls. All responses will be called asynchronously. -// When kError is returned, the FileIO object could be in an error state. All -// following calls (other than Close()) could return kError. The CDM should -// still call Close() to destroy the FileIO object. -class CDM_CLASS_API FileIOClient { - public: - enum Status { - kSuccess = 0, - kInUse, - kError - }; - - // Response to a FileIO::Open() call with the open |status|. - virtual void OnOpenComplete(Status status) = 0; - - // Response to a FileIO::Read() call to provide |data_size| bytes of |data| - // read from the file. - // - kSuccess indicates that all contents of the file has been successfully - // read. In this case, 0 |data_size| means that the file is empty. - // - kInUse indicates that there are other read/write operations pending. - // - kError indicates read failure, e.g. the storage is not open or cannot be - // fully read. - virtual void OnReadComplete(Status status, - const uint8_t* data, uint32_t data_size) = 0; - - // Response to a FileIO::Write() call. - // - kSuccess indicates that all the data has been written into the file - // successfully. - // - kInUse indicates that there are other read/write operations pending. - // - kError indicates write failure, e.g. the storage is not open or cannot be - // fully written. Upon write failure, the contents of the file should be - // regarded as corrupt and should not used. - virtual void OnWriteComplete(Status status) = 0; - - protected: - FileIOClient() {} - virtual ~FileIOClient() {} -}; - -// ContentDecryptionModule interface that all CDMs need to implement. -// The interface is versioned for backward compatibility. -// Note: ContentDecryptionModule implementations must use the allocator -// provided in CreateCdmInstance() to allocate any Buffer that needs to -// be passed back to the caller. Implementations must call Buffer::Destroy() -// when a Buffer is created that will never be returned to the caller. -class CDM_CLASS_API ContentDecryptionModule_8 { - public: - static const int kVersion = 8; - typedef Host_8 Host; - - // Initializes the CDM instance, providing information about permitted - // functionalities. - // If |allow_distinctive_identifier| is false, messages from the CDM, - // such as message events, must not contain a Distinctive Identifier, - // even in an encrypted form. - // If |allow_persistent_state| is false, the CDM must not attempt to - // persist state. Calls to CreateFileIO() will fail. - virtual void Initialize(bool allow_distinctive_identifier, - bool allow_persistent_state) = 0; - - // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), - // UpdateSession(), CloseSession(), and RemoveSession() all accept a - // |promise_id|, which must be passed to the completion Host method - // (e.g. Host::OnResolveNewSessionPromise()). - - // Provides a server certificate to be used to encrypt messages to the - // license server. The CDM must respond by calling either - // Host::OnResolvePromise() or Host::OnRejectPromise(). - virtual void SetServerCertificate(uint32_t promise_id, - const uint8_t* server_certificate_data, - uint32_t server_certificate_data_size) = 0; - - // Creates a session given |session_type|, |init_data_type|, and |init_data|. - // The CDM must respond by calling either Host::OnResolveNewSessionPromise() - // or Host::OnRejectPromise(). - virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, - SessionType session_type, - InitDataType init_data_type, - const uint8_t* init_data, - uint32_t init_data_size) = 0; - - // Loads the session of type |session_type| specified by |session_id|. - // The CDM must respond by calling either Host::OnResolveNewSessionPromise() - // or Host::OnRejectPromise(). If the session is not found, call - // Host::OnResolveNewSessionPromise() with session_id = NULL. - virtual void LoadSession(uint32_t promise_id, - SessionType session_type, - const char* session_id, - uint32_t session_id_size) = 0; - - // Updates the session with |response|. The CDM must respond by calling - // either Host::OnResolvePromise() or Host::OnRejectPromise(). - virtual void UpdateSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size, - const uint8_t* response, - uint32_t response_size) = 0; - - // Requests that the CDM close the session. The CDM must respond by calling - // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request - // has been processed. This may be before the session is closed. Once the - // session is closed, Host::OnSessionClosed() must also be called. - virtual void CloseSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Removes any stored session data associated with this session. Will only be - // called for persistent sessions. The CDM must respond by calling either - // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has - // been processed. - virtual void RemoveSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Performs scheduled operation with |context| when the timer fires. - virtual void TimerExpired(void* context) = 0; - - // Decrypts the |encrypted_buffer|. - // - // Returns kSuccess if decryption succeeded, in which case the callee - // should have filled the |decrypted_buffer| and passed the ownership of - // |data| in |decrypted_buffer| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kDecryptError if any other error happened. - // If the return value is not kSuccess, |decrypted_buffer| should be ignored - // by the caller. - virtual Status Decrypt(const InputBuffer& encrypted_buffer, - DecryptedBlock* decrypted_buffer) = 0; - - // Initializes the CDM audio decoder with |audio_decoder_config|. This - // function must be called before DecryptAndDecodeSamples() is called. - // - // Returns kSuccess if the |audio_decoder_config| is supported and the CDM - // audio decoder is successfully initialized. - // Returns kSessionError if |audio_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). - // Returns kDeferredInitialization if the CDM is not ready to initialize the - // decoder at this time. Must call Host::OnDeferredInitializationDone() once - // initialization is complete. - virtual Status InitializeAudioDecoder( - const AudioDecoderConfig& audio_decoder_config) = 0; - - // Initializes the CDM video decoder with |video_decoder_config|. This - // function must be called before DecryptAndDecodeFrame() is called. - // - // Returns kSuccess if the |video_decoder_config| is supported and the CDM - // video decoder is successfully initialized. - // Returns kSessionError if |video_decoder_config| is not supported. The CDM - // may still be able to do Decrypt(). - // Returns kDeferredInitialization if the CDM is not ready to initialize the - // decoder at this time. Must call Host::OnDeferredInitializationDone() once - // initialization is complete. - virtual Status InitializeVideoDecoder( - const VideoDecoderConfig& video_decoder_config) = 0; - - // De-initializes the CDM decoder and sets it to an uninitialized state. The - // caller can initialize the decoder again after this call to re-initialize - // it. This can be used to reconfigure the decoder if the configuration - // changes. - virtual void DeinitializeDecoder(StreamType decoder_type) = 0; - - // Resets the CDM decoder to an initialized clean state. All internal buffers - // MUST be flushed. - virtual void ResetDecoder(StreamType decoder_type) = 0; - - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a - // |video_frame|. Upon end-of-stream, the caller should call this function - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty - // |video_frame| (|format| == kEmptyVideoFrame) is produced. - // - // Returns kSuccess if decryption and decoding both succeeded, in which case - // the callee will have filled the |video_frame| and passed the ownership of - // |frame_buffer| in |video_frame| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kNeedMoreData if more data was needed by the decoder to generate - // a decoded frame (e.g. during initialization and end-of-stream). - // Returns kDecryptError if any decryption error happened. - // Returns kDecodeError if any decoding error happened. - // If the return value is not kSuccess, |video_frame| should be ignored by - // the caller. - virtual Status DecryptAndDecodeFrame(const InputBuffer& encrypted_buffer, - VideoFrame* video_frame) = 0; - - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into - // |audio_frames|. Upon end-of-stream, the caller should call this function - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty - // |audio_frames| is produced. - // - // Returns kSuccess if decryption and decoding both succeeded, in which case - // the callee will have filled |audio_frames| and passed the ownership of - // |data| in |audio_frames| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kNeedMoreData if more data was needed by the decoder to generate - // audio samples (e.g. during initialization and end-of-stream). - // Returns kDecryptError if any decryption error happened. - // Returns kDecodeError if any decoding error happened. - // If the return value is not kSuccess, |audio_frames| should be ignored by - // the caller. - virtual Status DecryptAndDecodeSamples(const InputBuffer& encrypted_buffer, - AudioFrames* audio_frames) = 0; - - // Called by the host after a platform challenge was initiated via - // Host::SendPlatformChallenge(). - virtual void OnPlatformChallengeResponse( - const PlatformChallengeResponse& response) = 0; - - // Called by the host after a call to Host::QueryOutputProtectionStatus(). The - // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask| - // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed, - // then |link_mask| and |output_protection_mask| are undefined and should - // be ignored. - virtual void OnQueryOutputProtectionStatus( - QueryResult result, - uint32_t link_mask, - uint32_t output_protection_mask) = 0; - - // Destroys the object in the same context as it was created. - virtual void Destroy() = 0; - - protected: - ContentDecryptionModule_8() {} - virtual ~ContentDecryptionModule_8() {} -}; - -// ContentDecryptionModule interface that all CDMs need to implement. -// The interface is versioned for backward compatibility. -// Note: ContentDecryptionModule implementations must use the allocator -// provided in CreateCdmInstance() to allocate any Buffer that needs to -// be passed back to the caller. Implementations must call Buffer::Destroy() -// when a Buffer is created that will never be returned to the caller. -class CDM_CLASS_API ContentDecryptionModule_9 { - public: - static const int kVersion = 9; - typedef Host_9 Host; - - // Initializes the CDM instance, providing information about permitted - // functionalities. - // If |allow_distinctive_identifier| is false, messages from the CDM, - // such as message events, must not contain a Distinctive Identifier, - // even in an encrypted form. - // If |allow_persistent_state| is false, the CDM must not attempt to - // persist state. Calls to CreateFileIO() will fail. - virtual void Initialize(bool allow_distinctive_identifier, - bool allow_persistent_state) = 0; - - // Gets the key status if the CDM has a hypothetical key with the |policy|. - // The CDM must respond by calling either Host::OnResolveKeyStatusPromise() - // with the result key status or Host::OnRejectPromise() if an unexpected - // error happened or this method is not supported. - virtual void GetStatusForPolicy(uint32_t promise_id, - const Policy& policy) = 0; - - // SetServerCertificate(), CreateSessionAndGenerateRequest(), LoadSession(), - // UpdateSession(), CloseSession(), and RemoveSession() all accept a - // |promise_id|, which must be passed to the completion Host method - // (e.g. Host::OnResolveNewSessionPromise()). - - // Provides a server certificate to be used to encrypt messages to the - // license server. The CDM must respond by calling either - // Host::OnResolvePromise() or Host::OnRejectPromise(). - virtual void SetServerCertificate(uint32_t promise_id, - const uint8_t* server_certificate_data, - uint32_t server_certificate_data_size) = 0; - - // Creates a session given |session_type|, |init_data_type|, and |init_data|. - // The CDM must respond by calling either Host::OnResolveNewSessionPromise() - // or Host::OnRejectPromise(). - virtual void CreateSessionAndGenerateRequest(uint32_t promise_id, - SessionType session_type, - InitDataType init_data_type, - const uint8_t* init_data, - uint32_t init_data_size) = 0; - - // Loads the session of type |session_type| specified by |session_id|. - // The CDM must respond by calling either Host::OnResolveNewSessionPromise() - // or Host::OnRejectPromise(). If the session is not found, call - // Host::OnResolveNewSessionPromise() with session_id = NULL. - virtual void LoadSession(uint32_t promise_id, - SessionType session_type, - const char* session_id, - uint32_t session_id_size) = 0; - - // Updates the session with |response|. The CDM must respond by calling - // either Host::OnResolvePromise() or Host::OnRejectPromise(). - virtual void UpdateSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size, - const uint8_t* response, - uint32_t response_size) = 0; - - // Requests that the CDM close the session. The CDM must respond by calling - // either Host::OnResolvePromise() or Host::OnRejectPromise() when the request - // has been processed. This may be before the session is closed. Once the - // session is closed, Host::OnSessionClosed() must also be called. - virtual void CloseSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Removes any stored session data associated with this session. Will only be - // called for persistent sessions. The CDM must respond by calling either - // Host::OnResolvePromise() or Host::OnRejectPromise() when the request has - // been processed. - virtual void RemoveSession(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Performs scheduled operation with |context| when the timer fires. - virtual void TimerExpired(void* context) = 0; - - // Decrypts the |encrypted_buffer|. - // - // Returns kSuccess if decryption succeeded, in which case the callee - // should have filled the |decrypted_buffer| and passed the ownership of - // |data| in |decrypted_buffer| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kDecryptError if any other error happened. - // If the return value is not kSuccess, |decrypted_buffer| should be ignored - // by the caller. - virtual Status Decrypt(const InputBuffer& encrypted_buffer, - DecryptedBlock* decrypted_buffer) = 0; - - // Initializes the CDM audio decoder with |audio_decoder_config|. This - // function must be called before DecryptAndDecodeSamples() is called. - // - // Returns kSuccess if the |audio_decoder_config| is supported and the CDM - // audio decoder is successfully initialized. - // Returns kInitializationError if |audio_decoder_config| is not supported. - // The CDM may still be able to do Decrypt(). - // Returns kDeferredInitialization if the CDM is not ready to initialize the - // decoder at this time. Must call Host::OnDeferredInitializationDone() once - // initialization is complete. - virtual Status InitializeAudioDecoder( - const AudioDecoderConfig& audio_decoder_config) = 0; - - // Initializes the CDM video decoder with |video_decoder_config|. This - // function must be called before DecryptAndDecodeFrame() is called. - // - // Returns kSuccess if the |video_decoder_config| is supported and the CDM - // video decoder is successfully initialized. - // Returns kInitializationError if |video_decoder_config| is not supported. - // The CDM may still be able to do Decrypt(). - // Returns kDeferredInitialization if the CDM is not ready to initialize the - // decoder at this time. Must call Host::OnDeferredInitializationDone() once - // initialization is complete. - virtual Status InitializeVideoDecoder( - const VideoDecoderConfig& video_decoder_config) = 0; - - // De-initializes the CDM decoder and sets it to an uninitialized state. The - // caller can initialize the decoder again after this call to re-initialize - // it. This can be used to reconfigure the decoder if the configuration - // changes. - virtual void DeinitializeDecoder(StreamType decoder_type) = 0; - - // Resets the CDM decoder to an initialized clean state. All internal buffers - // MUST be flushed. - virtual void ResetDecoder(StreamType decoder_type) = 0; - - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into a - // |video_frame|. Upon end-of-stream, the caller should call this function - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty - // |video_frame| (|format| == kEmptyVideoFrame) is produced. - // - // Returns kSuccess if decryption and decoding both succeeded, in which case - // the callee will have filled the |video_frame| and passed the ownership of - // |frame_buffer| in |video_frame| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kNeedMoreData if more data was needed by the decoder to generate - // a decoded frame (e.g. during initialization and end-of-stream). - // Returns kDecryptError if any decryption error happened. - // Returns kDecodeError if any decoding error happened. - // If the return value is not kSuccess, |video_frame| should be ignored by - // the caller. - virtual Status DecryptAndDecodeFrame(const InputBuffer& encrypted_buffer, - VideoFrame* video_frame) = 0; - - // Decrypts the |encrypted_buffer| and decodes the decrypted buffer into - // |audio_frames|. Upon end-of-stream, the caller should call this function - // repeatedly with empty |encrypted_buffer| (|data| == NULL) until only empty - // |audio_frames| is produced. - // - // Returns kSuccess if decryption and decoding both succeeded, in which case - // the callee will have filled |audio_frames| and passed the ownership of - // |data| in |audio_frames| to the caller. - // Returns kNoKey if the CDM did not have the necessary decryption key - // to decrypt. - // Returns kNeedMoreData if more data was needed by the decoder to generate - // audio samples (e.g. during initialization and end-of-stream). - // Returns kDecryptError if any decryption error happened. - // Returns kDecodeError if any decoding error happened. - // If the return value is not kSuccess, |audio_frames| should be ignored by - // the caller. - virtual Status DecryptAndDecodeSamples(const InputBuffer& encrypted_buffer, - AudioFrames* audio_frames) = 0; - - // Called by the host after a platform challenge was initiated via - // Host::SendPlatformChallenge(). - virtual void OnPlatformChallengeResponse( - const PlatformChallengeResponse& response) = 0; - - // Called by the host after a call to Host::QueryOutputProtectionStatus(). The - // |link_mask| is a bit mask of OutputLinkTypes and |output_protection_mask| - // is a bit mask of OutputProtectionMethods. If |result| is kQueryFailed, - // then |link_mask| and |output_protection_mask| are undefined and should - // be ignored. - virtual void OnQueryOutputProtectionStatus( - QueryResult result, - uint32_t link_mask, - uint32_t output_protection_mask) = 0; - - // Called by the host after a call to Host::RequestStorageId(). If the - // version of the storage ID requested is available, |storage_id| and - // |storage_id_size| are set appropriately. |version| will be the same as - // what was requested, unless 0 (latest) was requested, in which case - // |version| will be the actual version number for the |storage_id| returned. - // If the requested version is not available, null/zero will be provided as - // |storage_id| and |storage_id_size|, respectively, and |version| should be - // ignored. - virtual void OnStorageId(uint32_t version, - const uint8_t* storage_id, - uint32_t storage_id_size) = 0; - - // Destroys the object in the same context as it was created. - virtual void Destroy() = 0; - - protected: - ContentDecryptionModule_9() {} - virtual ~ContentDecryptionModule_9() {} -}; - -typedef ContentDecryptionModule_9 ContentDecryptionModule; - -// Represents a buffer created by Allocator implementations. -class CDM_CLASS_API Buffer { - public: - // Destroys the buffer in the same context as it was created. - virtual void Destroy() = 0; - - virtual uint32_t Capacity() const = 0; - virtual uint8_t* Data() = 0; - virtual void SetSize(uint32_t size) = 0; - virtual uint32_t Size() const = 0; - - protected: - Buffer() {} - virtual ~Buffer() {} - - private: - Buffer(const Buffer&); - void operator=(const Buffer&); -}; - -class CDM_CLASS_API Host_8 { - public: - static const int kVersion = 8; - - // Returns a Buffer* containing non-zero members upon success, or NULL on - // failure. The caller owns the Buffer* after this call. The buffer is not - // guaranteed to be zero initialized. The capacity of the allocated Buffer - // is guaranteed to be not less than |capacity|. - virtual Buffer* Allocate(uint32_t capacity) = 0; - - // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms| - // from now with |context|. - virtual void SetTimer(int64_t delay_ms, void* context) = 0; - - // Returns the current wall time. - virtual Time GetCurrentWallTime() = 0; - - // Called by the CDM when a session is created or loaded and the value for the - // MediaKeySession's sessionId attribute is available (|session_id|). - // This must be called before OnSessionMessage() or - // OnSessionKeysChange() is called for the same session. |session_id_size| - // should not include null termination. - // When called in response to LoadSession(), the |session_id| must be the - // same as the |session_id| passed in LoadSession(), or NULL if the - // session could not be loaded. - virtual void OnResolveNewSessionPromise(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Called by the CDM when a session is updated or released. - virtual void OnResolvePromise(uint32_t promise_id) = 0; - - // Called by the CDM when an error occurs as a result of one of the - // ContentDecryptionModule calls that accept a |promise_id|. - // |error| must be specified, |error_message| and |system_code| - // are optional. |error_message_size| should not include null termination. - virtual void OnRejectPromise(uint32_t promise_id, - Error error, - uint32_t system_code, - const char* error_message, - uint32_t error_message_size) = 0; - - // Called by the CDM when it has a message for session |session_id|. - // Size parameters should not include null termination. - // |legacy_destination_url| is only for supporting the prefixed EME API and - // is ignored by unprefixed EME. It should only be non-null if |message_type| - // is kLicenseRenewal. - virtual void OnSessionMessage(const char* session_id, - uint32_t session_id_size, - MessageType message_type, - const char* message, - uint32_t message_size, - const char* legacy_destination_url, - uint32_t legacy_destination_url_length) = 0; - - // Called by the CDM when there has been a change in keys or their status for - // session |session_id|. |has_additional_usable_key| should be set if a - // key is newly usable (e.g. new key available, previously expired key has - // been renewed, etc.) and the browser should attempt to resume playback. - // |key_ids| is the list of key ids for this session along with their - // current status. |key_ids_count| is the number of entries in |key_ids|. - // Size parameter for |session_id| should not include null termination. - virtual void OnSessionKeysChange(const char* session_id, - uint32_t session_id_size, - bool has_additional_usable_key, - const KeyInformation* keys_info, - uint32_t keys_info_count) = 0; - - // Called by the CDM when there has been a change in the expiration time for - // session |session_id|. This can happen as the result of an Update() call - // or some other event. If this happens as a result of a call to Update(), - // it must be called before resolving the Update() promise. |new_expiry_time| - // represents the time after which the key(s) in the session will no longer - // be usable for decryption. It can be 0 if no such time exists or if the - // license explicitly never expires. Size parameter should not include null - // termination. - virtual void OnExpirationChange(const char* session_id, - uint32_t session_id_size, - Time new_expiry_time) = 0; - - // Called by the CDM when session |session_id| is closed. Size - // parameter should not include null termination. - virtual void OnSessionClosed(const char* session_id, - uint32_t session_id_size) = 0; - - // Called by the CDM when an error occurs in session |session_id| - // unrelated to one of the ContentDecryptionModule calls that accept a - // |promise_id|. |error| must be specified, |error_message| and - // |system_code| are optional. Length parameters should not include null - // termination. - // Note: - // - This method is only for supporting prefixed EME API. - // - This method will be ignored by unprefixed EME. All errors reported - // in this method should probably also be reported by one of other methods. - virtual void OnLegacySessionError( - const char* session_id, uint32_t session_id_length, - Error error, - uint32_t system_code, - const char* error_message, uint32_t error_message_length) = 0; - - // The following are optional methods that may not be implemented on all - // platforms. - - // Sends a platform challenge for the given |service_id|. |challenge| is at - // most 256 bits of data to be signed. Once the challenge has been completed, - // the host will call ContentDecryptionModule::OnPlatformChallengeResponse() - // with the signed challenge response and platform certificate. Size - // parameters should not include null termination. - virtual void SendPlatformChallenge(const char* service_id, - uint32_t service_id_size, - const char* challenge, - uint32_t challenge_size) = 0; - - // Attempts to enable output protection (e.g. HDCP) on the display link. The - // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No - // status callback is issued, the CDM must call QueryOutputProtectionStatus() - // periodically to ensure the desired protections are applied. - virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0; - - // Requests the current output protection status. Once the host has the status - // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus(). - virtual void QueryOutputProtectionStatus() = 0; - - // Must be called by the CDM if it returned kDeferredInitialization during - // InitializeAudioDecoder() or InitializeVideoDecoder(). - virtual void OnDeferredInitializationDone(StreamType stream_type, - Status decoder_status) = 0; - - // Creates a FileIO object from the host to do file IO operation. Returns NULL - // if a FileIO object cannot be obtained. Once a valid FileIO object is - // returned, |client| must be valid until FileIO::Close() is called. The - // CDM can call this method multiple times to operate on different files. - virtual FileIO* CreateFileIO(FileIOClient* client) = 0; - - protected: - Host_8() {} - virtual ~Host_8() {} -}; - -class CDM_CLASS_API Host_9 { - public: - static const int kVersion = 9; - - // Returns a Buffer* containing non-zero members upon success, or NULL on - // failure. The caller owns the Buffer* after this call. The buffer is not - // guaranteed to be zero initialized. The capacity of the allocated Buffer - // is guaranteed to be not less than |capacity|. - virtual Buffer* Allocate(uint32_t capacity) = 0; - - // Requests the host to call ContentDecryptionModule::TimerFired() |delay_ms| - // from now with |context|. - virtual void SetTimer(int64_t delay_ms, void* context) = 0; - - // Returns the current wall time. - virtual Time GetCurrentWallTime() = 0; - - // Called by the CDM when a key status is available in response to - // GetStatusForPolicy(). - virtual void OnResolveKeyStatusPromise(uint32_t promise_id, - KeyStatus key_status) = 0; - - // Called by the CDM when a session is created or loaded and the value for the - // MediaKeySession's sessionId attribute is available (|session_id|). - // This must be called before OnSessionMessage() or - // OnSessionKeysChange() is called for the same session. |session_id_size| - // should not include null termination. - // When called in response to LoadSession(), the |session_id| must be the - // same as the |session_id| passed in LoadSession(), or NULL if the - // session could not be loaded. - virtual void OnResolveNewSessionPromise(uint32_t promise_id, - const char* session_id, - uint32_t session_id_size) = 0; - - // Called by the CDM when a session is updated or released. - virtual void OnResolvePromise(uint32_t promise_id) = 0; - - // Called by the CDM when an error occurs as a result of one of the - // ContentDecryptionModule calls that accept a |promise_id|. - // |exception| must be specified. |error_message| and |system_code| - // are optional. |error_message_size| should not include null termination. - virtual void OnRejectPromise(uint32_t promise_id, - Exception exception, - uint32_t system_code, - const char* error_message, - uint32_t error_message_size) = 0; - - // Called by the CDM when it has a message for session |session_id|. - // Size parameters should not include null termination. - virtual void OnSessionMessage(const char* session_id, - uint32_t session_id_size, - MessageType message_type, - const char* message, - uint32_t message_size) = 0; - - // Called by the CDM when there has been a change in keys or their status for - // session |session_id|. |has_additional_usable_key| should be set if a - // key is newly usable (e.g. new key available, previously expired key has - // been renewed, etc.) and the browser should attempt to resume playback. - // |key_ids| is the list of key ids for this session along with their - // current status. |key_ids_count| is the number of entries in |key_ids|. - // Size parameter for |session_id| should not include null termination. - virtual void OnSessionKeysChange(const char* session_id, - uint32_t session_id_size, - bool has_additional_usable_key, - const KeyInformation* keys_info, - uint32_t keys_info_count) = 0; - - // Called by the CDM when there has been a change in the expiration time for - // session |session_id|. This can happen as the result of an Update() call - // or some other event. If this happens as a result of a call to Update(), - // it must be called before resolving the Update() promise. |new_expiry_time| - // represents the time after which the key(s) in the session will no longer - // be usable for decryption. It can be 0 if no such time exists or if the - // license explicitly never expires. Size parameter should not include null - // termination. - virtual void OnExpirationChange(const char* session_id, - uint32_t session_id_size, - Time new_expiry_time) = 0; - - // Called by the CDM when session |session_id| is closed. Size - // parameter should not include null termination. - virtual void OnSessionClosed(const char* session_id, - uint32_t session_id_size) = 0; - - // The following are optional methods that may not be implemented on all - // platforms. - - // Sends a platform challenge for the given |service_id|. |challenge| is at - // most 256 bits of data to be signed. Once the challenge has been completed, - // the host will call ContentDecryptionModule::OnPlatformChallengeResponse() - // with the signed challenge response and platform certificate. Size - // parameters should not include null termination. - virtual void SendPlatformChallenge(const char* service_id, - uint32_t service_id_size, - const char* challenge, - uint32_t challenge_size) = 0; - - // Attempts to enable output protection (e.g. HDCP) on the display link. The - // |desired_protection_mask| is a bit mask of OutputProtectionMethods. No - // status callback is issued, the CDM must call QueryOutputProtectionStatus() - // periodically to ensure the desired protections are applied. - virtual void EnableOutputProtection(uint32_t desired_protection_mask) = 0; - - // Requests the current output protection status. Once the host has the status - // it will call ContentDecryptionModule::OnQueryOutputProtectionStatus(). - virtual void QueryOutputProtectionStatus() = 0; - - // Must be called by the CDM if it returned kDeferredInitialization during - // InitializeAudioDecoder() or InitializeVideoDecoder(). - virtual void OnDeferredInitializationDone(StreamType stream_type, - Status decoder_status) = 0; - - // Creates a FileIO object from the host to do file IO operation. Returns NULL - // if a FileIO object cannot be obtained. Once a valid FileIO object is - // returned, |client| must be valid until FileIO::Close() is called. The - // CDM can call this method multiple times to operate on different files. - virtual FileIO* CreateFileIO(FileIOClient* client) = 0; - - // Requests a specific version of the storage ID. A storage ID is a stable, - // device specific ID used by the CDM to securely store persistent data. The - // ID will be returned by the host via ContentDecryptionModule::OnStorageId(). - // If |version| is 0, the latest version will be returned. All |version|s - // that are greater than or equal to 0x80000000 are reserved for the CDM and - // should not be supported or returned by the host. The CDM must not expose - // the ID outside the client device, even in encrypted form. - virtual void RequestStorageId(uint32_t version) = 0; - - protected: - Host_9() {} - virtual ~Host_9() {} -}; - -// Represents a decrypted block that has not been decoded. -class CDM_CLASS_API DecryptedBlock { - public: - virtual void SetDecryptedBuffer(Buffer* buffer) = 0; - virtual Buffer* DecryptedBuffer() = 0; - - // TODO(tomfinegan): Figure out if timestamp is really needed. If it is not, - // we can just pass Buffer pointers around. - virtual void SetTimestamp(int64_t timestamp) = 0; - virtual int64_t Timestamp() const = 0; - - protected: - DecryptedBlock() {} - virtual ~DecryptedBlock() {} -}; - -class CDM_CLASS_API VideoFrame { - public: - enum VideoPlane { - kYPlane = 0, - kUPlane = 1, - kVPlane = 2, - kMaxPlanes = 3, - }; - - virtual void SetFormat(VideoFormat format) = 0; - virtual VideoFormat Format() const = 0; - - virtual void SetSize(cdm::Size size) = 0; - virtual cdm::Size Size() const = 0; - - virtual void SetFrameBuffer(Buffer* frame_buffer) = 0; - virtual Buffer* FrameBuffer() = 0; - - virtual void SetPlaneOffset(VideoPlane plane, uint32_t offset) = 0; - virtual uint32_t PlaneOffset(VideoPlane plane) = 0; - - virtual void SetStride(VideoPlane plane, uint32_t stride) = 0; - virtual uint32_t Stride(VideoPlane plane) = 0; - - virtual void SetTimestamp(int64_t timestamp) = 0; - virtual int64_t Timestamp() const = 0; - - protected: - VideoFrame() {} - virtual ~VideoFrame() {} -}; - -// Represents decrypted and decoded audio frames. AudioFrames can contain -// multiple audio output buffers, which are serialized into this format: -// -// |<------------------- serialized audio buffer ------------------->| -// | int64_t timestamp | int64_t length | length bytes of audio data | -// -// For example, with three audio output buffers, the AudioFrames will look -// like this: -// -// |<----------------- AudioFrames ------------------>| -// | audio buffer 0 | audio buffer 1 | audio buffer 2 | -class CDM_CLASS_API AudioFrames { - public: - virtual void SetFrameBuffer(Buffer* buffer) = 0; - virtual Buffer* FrameBuffer() = 0; - - // The CDM must call this method, providing a valid format, when providing - // frame buffers. Planar data should be stored end to end; e.g., - // |ch1 sample1||ch1 sample2|....|ch1 sample_last||ch2 sample1|... - virtual void SetFormat(AudioFormat format) = 0; - virtual AudioFormat Format() const = 0; - - protected: - AudioFrames() {} - virtual ~AudioFrames() {} -}; - -} // namespace cdm - -#endif // CDM_CONTENT_DECRYPTION_MODULE_H_ diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h b/dom/media/gmp/widevine-adapter/content_decryption_module_export.h deleted file mode 100644 index 51d485892b..0000000000 --- a/dom/media/gmp/widevine-adapter/content_decryption_module_export.h +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ -#define CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ - -// Define CDM_API so that functionality implemented by the CDM module -// can be exported to consumers. -#if defined(_WIN32) - -#if defined(CDM_IMPLEMENTATION) -#define CDM_API __declspec(dllexport) -#else -#define CDM_API __declspec(dllimport) -#endif // defined(CDM_IMPLEMENTATION) - -#else // defined(_WIN32) -#define CDM_API __attribute__((visibility("default"))) -#endif // defined(_WIN32) - -#endif // CDM_CONTENT_DECRYPTION_MODULE_EXPORT_H_ diff --git a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h b/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h deleted file mode 100644 index 5df8344e60..0000000000 --- a/dom/media/gmp/widevine-adapter/content_decryption_module_ext.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ -#define CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ - -#if defined(_WIN32) -#include <windows.h> -#endif - -#include "content_decryption_module_export.h" - -#if defined(_MSC_VER) -typedef unsigned int uint32_t; -#else -#include <stdint.h> -#endif - -namespace cdm { - -#if defined(_WIN32) -typedef wchar_t FilePathCharType; -typedef HANDLE PlatformFile; -const PlatformFile kInvalidPlatformFile = INVALID_HANDLE_VALUE; -#else -typedef char FilePathCharType; -typedef int PlatformFile; -const PlatformFile kInvalidPlatformFile = -1; -#endif // defined(_WIN32) - -struct HostFile { - HostFile(const FilePathCharType* file_path, - PlatformFile file, - PlatformFile sig_file) - : file_path(file_path), file(file), sig_file(sig_file) {} - - // File that is part of the host of the CDM. - const FilePathCharType* file_path = nullptr; - PlatformFile file = kInvalidPlatformFile; - - // Signature file for |file|. - PlatformFile sig_file = kInvalidPlatformFile; -}; - -} // namespace cdm - -extern "C" { - -// Functions in this file are dynamically retrieved by their versioned function -// names. Increment the version number for any backward incompatible API -// changes. - -// Verifies CDM host. All files in |host_files| are opened in read-only mode. -// -// Returns false and closes all files if there is an immediate failure. -// Otherwise returns true as soon as possible and processes the files -// asynchronously. All files MUST be closed by the CDM after this one-time -// processing is finished. -CDM_API bool VerifyCdmHost_0(const cdm::HostFile* host_files, - uint32_t num_files); -} - -#endif // CDM_CONTENT_DECRYPTION_MODULE_EXT_H_ diff --git a/dom/media/gmp/widevine-adapter/moz.build b/dom/media/gmp/widevine-adapter/moz.build deleted file mode 100644 index 4a3a079cec..0000000000 --- a/dom/media/gmp/widevine-adapter/moz.build +++ /dev/null @@ -1,24 +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/. - -SOURCES += [ - 'WidevineAdapter.cpp', - 'WidevineDecryptor.cpp', - 'WidevineFileIO.cpp', - 'WidevineUtils.cpp', - 'WidevineVideoDecoder.cpp', - 'WidevineVideoFrame.cpp', -] - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/media/gmp', -] - -if CONFIG['CLANG_CXX']: - CXXFLAGS += ['-Wno-error=shadow'] - -include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/media/gtest/MockMediaDecoderOwner.h b/dom/media/gtest/MockMediaDecoderOwner.h index 1009ca30a1..64d7290187 100644 --- a/dom/media/gtest/MockMediaDecoderOwner.h +++ b/dom/media/gtest/MockMediaDecoderOwner.h @@ -34,10 +34,6 @@ public: void DownloadProgressed() override {} void UpdateReadyState() override {} void FirstFrameLoaded() override {} -#ifdef MOZ_EME - void DispatchEncrypted(const nsTArray<uint8_t>& aInitData, - const nsAString& aInitDataType) override {} -#endif bool IsActive() const override { return true; } bool IsHidden() const override { return false; } void DownloadSuspended() override {} diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index 022bb5bd10..907ee40e8f 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -58,34 +58,6 @@ AppendStateToStr(SourceBufferAttributes::AppendState aState) static Atomic<uint32_t> sStreamSourceID(0u); -#ifdef MOZ_EME -class DispatchKeyNeededEvent : public Runnable { -public: - DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder, - nsTArray<uint8_t>& aInitData, - const nsString& aInitDataType) - : mDecoder(aDecoder) - , mInitData(aInitData) - , mInitDataType(aInitDataType) - { - } - NS_IMETHOD Run() override { - // Note: Null check the owner, as the decoder could have been shutdown - // since this event was dispatched. - MediaDecoderOwner* owner = mDecoder->GetOwner(); - if (owner) { - owner->DispatchEncrypted(mInitData, mInitDataType); - } - mDecoder = nullptr; - return NS_OK; - } -private: - RefPtr<AbstractMediaDecoder> mDecoder; - nsTArray<uint8_t> mInitData; - nsString mInitDataType; -}; -#endif // MOZ_EME - TrackBuffersManager::TrackBuffersManager(MediaSourceDecoder* aParentDecoder, const nsACString& aType) : mInputBuffer(new MediaByteBuffer) @@ -1101,14 +1073,6 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) UniquePtr<EncryptionInfo> crypto = mInputDemuxer->GetCrypto(); if (crypto && crypto->IsEncrypted()) { -#ifdef MOZ_EME - // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING. - for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) { - NS_DispatchToMainThread( - new DispatchKeyNeededEvent(mParentDecoder, crypto->mInitDatas[i].mInitData, - crypto->mInitDatas[i].mType)); - } -#endif info.mCrypto = *crypto; // We clear our crypto init data array, so the MediaFormatReader will // not emit an encrypted event for the same init data again. diff --git a/dom/media/moz.build b/dom/media/moz.build index ef018d4a75..ca3cdac1ca 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -44,9 +44,6 @@ if CONFIG['MOZ_FMP4']: if CONFIG['MOZ_WEBRTC']: DIRS += ['bridge'] -if CONFIG['MOZ_EME']: - DIRS += ['eme'] - if CONFIG['MOZ_GMP']: DIRS += [ 'gmp', diff --git a/dom/media/platforms/PDMFactory.cpp b/dom/media/platforms/PDMFactory.cpp index 029b88cecb..02cbd3d92b 100644 --- a/dom/media/platforms/PDMFactory.cpp +++ b/dom/media/platforms/PDMFactory.cpp @@ -35,11 +35,6 @@ #include "AgnosticDecoderModule.h" -#ifdef MOZ_EME -#include "mozilla/CDMProxy.h" -#include "EMEDecoderModule.h" -#endif - #include "DecoderDoctorDiagnostics.h" #include "MP4Decoder.h" @@ -206,11 +201,6 @@ PDMFactory::CreateDecoder(const CreateDecoderParams& aParams) } const TrackInfo& config = aParams.mConfig; - bool isEncrypted = mEMEPDM && config.mCrypto.mValid; - - if (isEncrypted) { - return CreateDecoderWithPDM(mEMEPDM, aParams); - } DecoderDoctorDiagnostics* diagnostics = aParams.mDiagnostics; if (diagnostics) { @@ -334,9 +324,6 @@ bool PDMFactory::Supports(const TrackInfo& aTrackInfo, DecoderDoctorDiagnostics* aDiagnostics) const { - if (mEMEPDM) { - return mEMEPDM->Supports(aTrackInfo, aDiagnostics); - } RefPtr<PlatformDecoderModule> current = GetDecoder(aTrackInfo, aDiagnostics); return !!current; } @@ -444,13 +431,4 @@ PDMFactory::GetDecoder(const TrackInfo& aTrackInfo, return pdm.forget(); } -#ifdef MOZ_EME -void -PDMFactory::SetCDMProxy(CDMProxy* aProxy) -{ - RefPtr<PDMFactory> m = new PDMFactory(); - mEMEPDM = new EMEDecoderModule(aProxy, m); -} -#endif - } // namespace mozilla diff --git a/dom/media/platforms/PDMFactory.h b/dom/media/platforms/PDMFactory.h index 186c05ca4e..313633ab57 100644 --- a/dom/media/platforms/PDMFactory.h +++ b/dom/media/platforms/PDMFactory.h @@ -10,10 +10,6 @@ #include "mozilla/Function.h" #include "mozilla/StaticMutex.h" -#ifdef MOZ_EME -class CDMProxy; -#endif - namespace mozilla { class DecoderDoctorDiagnostics; @@ -39,15 +35,6 @@ public: bool Supports(const TrackInfo& aTrackInfo, DecoderDoctorDiagnostics* aDiagnostics) const; -#ifdef MOZ_EME - // Creates a PlatformDecoderModule that uses a CDMProxy to decrypt or - // decrypt-and-decode EME encrypted content. If the CDM only decrypts and - // does not decode, we create a PDM and use that to create MediaDataDecoders - // that we use on on aTaskQueue to decode the decrypted stream. - // This is called on the decode task queue. - void SetCDMProxy(CDMProxy* aProxy); -#endif - static const int kYUV400 = 0; static const int kYUV420 = 1; static const int kYUV422 = 2; @@ -69,7 +56,6 @@ private: const CreateDecoderParams& aParams); nsTArray<RefPtr<PlatformDecoderModule>> mCurrentPDMs; - RefPtr<PlatformDecoderModule> mEMEPDM; RefPtr<PlatformDecoderModule> mBlankPDM; bool mWMFFailedToLoad = false; diff --git a/dom/media/platforms/PlatformDecoderModule.h b/dom/media/platforms/PlatformDecoderModule.h index f2abe4b7f7..63b4e00d5c 100644 --- a/dom/media/platforms/PlatformDecoderModule.h +++ b/dom/media/platforms/PlatformDecoderModule.h @@ -39,9 +39,6 @@ class RemoteDecoderModule; class MediaDataDecoder; class MediaDataDecoderCallback; class TaskQueue; -#ifdef MOZ_EME -class CDMProxy; -#endif static LazyLogModule sPDMLog("PlatformDecoderModule"); diff --git a/dom/media/platforms/agnostic/eme/EMEAudioDecoder.cpp b/dom/media/platforms/agnostic/eme/EMEAudioDecoder.cpp deleted file mode 100644 index fd0449d66f..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEAudioDecoder.cpp +++ /dev/null @@ -1,43 +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 "EMEAudioDecoder.h" -#include "mozilla/CDMProxy.h" - -namespace mozilla { - -void -EMEAudioCallbackAdapter::Error(GMPErr aErr) -{ - if (aErr == GMPNoKeyErr) { - // The GMP failed to decrypt a frame due to not having a key. This can - // happen if a key expires or a session is closed during playback. - NS_WARNING("GMP failed to decrypt due to lack of key"); - return; - } - AudioCallbackAdapter::Error(aErr); -} - -EMEAudioDecoder::EMEAudioDecoder(CDMProxy* aProxy, - const GMPAudioDecoderParams& aParams) - : GMPAudioDecoder(GMPAudioDecoderParams(aParams).WithAdapter( - new EMEAudioCallbackAdapter(aParams.mCallback))) - , mProxy(aProxy) -{} - -void -EMEAudioDecoder::InitTags(nsTArray<nsCString>& aTags) -{ - aTags.AppendElement(NS_LITERAL_CSTRING("aac")); - aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); -} - -nsCString -EMEAudioDecoder::GetNodeId() -{ - return mProxy->GetNodeId(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/agnostic/eme/EMEAudioDecoder.h b/dom/media/platforms/agnostic/eme/EMEAudioDecoder.h deleted file mode 100644 index fd41125d87..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEAudioDecoder.h +++ /dev/null @@ -1,36 +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 EMEAudioDecoder_h_ -#define EMEAudioDecoder_h_ - -#include "GMPAudioDecoder.h" -#include "PlatformDecoderModule.h" - -namespace mozilla { - -class EMEAudioCallbackAdapter : public AudioCallbackAdapter { -public: - explicit EMEAudioCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback) - : AudioCallbackAdapter(aCallback) - {} - - void Error(GMPErr aErr) override; -}; - -class EMEAudioDecoder : public GMPAudioDecoder { -public: - EMEAudioDecoder(CDMProxy* aProxy, const GMPAudioDecoderParams& aParams); - -private: - void InitTags(nsTArray<nsCString>& aTags) override; - nsCString GetNodeId() override; - - RefPtr<CDMProxy> mProxy; -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp b/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp deleted file mode 100644 index a293824608..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.cpp +++ /dev/null @@ -1,306 +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 "EMEDecoderModule.h" -#include "EMEAudioDecoder.h" -#include "EMEVideoDecoder.h" -#include "MediaDataDecoderProxy.h" -#include "mozIGeckoMediaPluginService.h" -#include "mozilla/CDMProxy.h" -#include "mozilla/Unused.h" -#include "nsAutoPtr.h" -#include "nsServiceManagerUtils.h" -#include "MediaInfo.h" -#include "nsClassHashtable.h" -#include "GMPDecoderModule.h" -#include "MP4Decoder.h" - -namespace mozilla { - -typedef MozPromiseRequestHolder<CDMProxy::DecryptPromise> DecryptPromiseRequestHolder; - -class EMEDecryptor : public MediaDataDecoder { - -public: - - EMEDecryptor(MediaDataDecoder* aDecoder, - MediaDataDecoderCallback* aCallback, - CDMProxy* aProxy, - TaskQueue* aDecodeTaskQueue) - : mDecoder(aDecoder) - , mCallback(aCallback) - , mTaskQueue(aDecodeTaskQueue) - , mProxy(aProxy) - , mSamplesWaitingForKey(new SamplesWaitingForKey(this, this->mCallback, - mTaskQueue, mProxy)) - , mIsShutdown(false) - { - } - - RefPtr<InitPromise> Init() override { - MOZ_ASSERT(!mIsShutdown); - return mDecoder->Init(); - } - - void Input(MediaRawData* aSample) override { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - if (mIsShutdown) { - NS_WARNING("EME encrypted sample arrived after shutdown"); - return; - } - if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) { - return; - } - - nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter()); - mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId, - writer->mCrypto.mSessionIds); - - mDecrypts.Put(aSample, new DecryptPromiseRequestHolder()); - mDecrypts.Get(aSample)->Begin(mProxy->Decrypt(aSample)->Then( - mTaskQueue, __func__, this, - &EMEDecryptor::Decrypted, - &EMEDecryptor::Decrypted)); - return; - } - - void Decrypted(const DecryptResult& aDecrypted) { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - MOZ_ASSERT(aDecrypted.mSample); - - nsAutoPtr<DecryptPromiseRequestHolder> holder; - mDecrypts.RemoveAndForget(aDecrypted.mSample, holder); - if (holder) { - holder->Complete(); - } else { - // Decryption is not in the list of decrypt operations waiting - // for a result. It must have been flushed or drained. Ignore result. - return; - } - - if (mIsShutdown) { - NS_WARNING("EME decrypted sample arrived after shutdown"); - return; - } - - if (aDecrypted.mStatus == NoKeyErr) { - // Key became unusable after we sent the sample to CDM to decrypt. - // Call Input() again, so that the sample is enqueued for decryption - // if the key becomes usable again. - Input(aDecrypted.mSample); - } else if (aDecrypted.mStatus != Ok) { - if (mCallback) { - mCallback->Error(MediaResult( - NS_ERROR_DOM_MEDIA_FATAL_ERR, - RESULT_DETAIL("decrypted.mStatus=%u", uint32_t(aDecrypted.mStatus)))); - } - } else { - MOZ_ASSERT(!mIsShutdown); - // The Adobe GMP AAC decoder gets confused if we pass it non-encrypted - // samples with valid crypto data. So clear the crypto data, since the - // sample should be decrypted now anyway. If we don't do this and we're - // using the Adobe GMP for unencrypted decoding of data that is decrypted - // by gmp-clearkey, decoding will fail. - UniquePtr<MediaRawDataWriter> writer(aDecrypted.mSample->CreateWriter()); - writer->mCrypto = CryptoSample(); - mDecoder->Input(aDecrypted.mSample); - } - } - - void Flush() override { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - MOZ_ASSERT(!mIsShutdown); - for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) { - nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data(); - holder->DisconnectIfExists(); - iter.Remove(); - } - mDecoder->Flush(); - mSamplesWaitingForKey->Flush(); - } - - void Drain() override { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - MOZ_ASSERT(!mIsShutdown); - for (auto iter = mDecrypts.Iter(); !iter.Done(); iter.Next()) { - nsAutoPtr<DecryptPromiseRequestHolder>& holder = iter.Data(); - holder->DisconnectIfExists(); - iter.Remove(); - } - mDecoder->Drain(); - } - - void Shutdown() override { - MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn()); - MOZ_ASSERT(!mIsShutdown); - mIsShutdown = true; - mDecoder->Shutdown(); - mSamplesWaitingForKey->BreakCycles(); - mSamplesWaitingForKey = nullptr; - mDecoder = nullptr; - mProxy = nullptr; - mCallback = nullptr; - } - - const char* GetDescriptionName() const override { - return mDecoder->GetDescriptionName(); - } - -private: - - RefPtr<MediaDataDecoder> mDecoder; - MediaDataDecoderCallback* mCallback; - RefPtr<TaskQueue> mTaskQueue; - RefPtr<CDMProxy> mProxy; - nsClassHashtable<nsRefPtrHashKey<MediaRawData>, DecryptPromiseRequestHolder> mDecrypts; - RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey; - bool mIsShutdown; -}; - -class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy { -public: - EMEMediaDataDecoderProxy(already_AddRefed<AbstractThread> aProxyThread, - MediaDataDecoderCallback* aCallback, - CDMProxy* aProxy, - TaskQueue* aTaskQueue) - : MediaDataDecoderProxy(Move(aProxyThread), aCallback) - , mSamplesWaitingForKey(new SamplesWaitingForKey(this, aCallback, - aTaskQueue, aProxy)) - , mProxy(aProxy) - { - } - - void Input(MediaRawData* aSample) override; - void Shutdown() override; - -private: - RefPtr<SamplesWaitingForKey> mSamplesWaitingForKey; - RefPtr<CDMProxy> mProxy; -}; - -void -EMEMediaDataDecoderProxy::Input(MediaRawData* aSample) -{ - if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) { - return; - } - - nsAutoPtr<MediaRawDataWriter> writer(aSample->CreateWriter()); - mProxy->GetSessionIdsForKeyId(aSample->mCrypto.mKeyId, - writer->mCrypto.mSessionIds); - - MediaDataDecoderProxy::Input(aSample); -} - -void -EMEMediaDataDecoderProxy::Shutdown() -{ - MediaDataDecoderProxy::Shutdown(); - - mSamplesWaitingForKey->BreakCycles(); - mSamplesWaitingForKey = nullptr; - mProxy = nullptr; -} - -EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM) - : mProxy(aProxy) - , mPDM(aPDM) -{ -} - -EMEDecoderModule::~EMEDecoderModule() -{ -} - -static already_AddRefed<MediaDataDecoderProxy> -CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, TaskQueue* aTaskQueue) -{ - RefPtr<gmp::GeckoMediaPluginService> s(gmp::GeckoMediaPluginService::GetGeckoMediaPluginService()); - if (!s) { - return nullptr; - } - RefPtr<AbstractThread> thread(s->GetAbstractGMPThread()); - if (!thread) { - return nullptr; - } - RefPtr<MediaDataDecoderProxy> decoder( - new EMEMediaDataDecoderProxy(thread.forget(), aCallback, aProxy, aTaskQueue)); - return decoder.forget(); -} - -already_AddRefed<MediaDataDecoder> -EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) -{ - MOZ_ASSERT(aParams.mConfig.mCrypto.mValid); - - if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) { - // GMP decodes. Assume that means it can decrypt too. - RefPtr<MediaDataDecoderProxy> wrapper = - CreateDecoderWrapper(aParams.mCallback, mProxy, aParams.mTaskQueue); - auto params = GMPVideoDecoderParams(aParams).WithCallback(wrapper); - wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, params)); - return wrapper.forget(); - } - - MOZ_ASSERT(mPDM); - RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams)); - if (!decoder) { - return nullptr; - } - - RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder, - aParams.mCallback, - mProxy, - AbstractThread::GetCurrent()->AsTaskQueue())); - return emeDecoder.forget(); -} - -already_AddRefed<MediaDataDecoder> -EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams) -{ - MOZ_ASSERT(aParams.mConfig.mCrypto.mValid); - - if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) { - // GMP decodes. Assume that means it can decrypt too. - RefPtr<MediaDataDecoderProxy> wrapper = - CreateDecoderWrapper(aParams.mCallback, mProxy, aParams.mTaskQueue); - auto gmpParams = GMPAudioDecoderParams(aParams).WithCallback(wrapper); - wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy, gmpParams)); - return wrapper.forget(); - } - - MOZ_ASSERT(mPDM); - RefPtr<MediaDataDecoder> decoder(mPDM->CreateDecoder(aParams)); - if (!decoder) { - return nullptr; - } - - RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder, - aParams.mCallback, - mProxy, - AbstractThread::GetCurrent()->AsTaskQueue())); - return emeDecoder.forget(); -} - -PlatformDecoderModule::ConversionRequired -EMEDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const -{ - if (aConfig.IsVideo() && MP4Decoder::IsH264(aConfig.mMimeType)) { - return ConversionRequired::kNeedAVCC; - } else { - return ConversionRequired::kNeedNone; - } -} - -bool -EMEDecoderModule::SupportsMimeType(const nsACString& aMimeType, - DecoderDoctorDiagnostics* aDiagnostics) const -{ - Maybe<nsCString> gmp; - gmp.emplace(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); - return GMPDecoderModule::SupportsMimeType(aMimeType, gmp); -} - -} // namespace mozilla diff --git a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h b/dom/media/platforms/agnostic/eme/EMEDecoderModule.h deleted file mode 100644 index 8480e54536..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEDecoderModule.h +++ /dev/null @@ -1,51 +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/. */ - -#if !defined(EMEDecoderModule_h_) -#define EMEDecoderModule_h_ - -#include "PlatformDecoderModule.h" -#include "PDMFactory.h" -#include "gmp-decryption.h" - -namespace mozilla { - -class CDMProxy; - -class EMEDecoderModule : public PlatformDecoderModule { -private: - -public: - EMEDecoderModule(CDMProxy* aProxy, PDMFactory* aPDM); - - virtual ~EMEDecoderModule(); - -protected: - // Decode thread. - already_AddRefed<MediaDataDecoder> - CreateVideoDecoder(const CreateDecoderParams& aParams) override; - - // Decode thread. - already_AddRefed<MediaDataDecoder> - CreateAudioDecoder(const CreateDecoderParams& aParams) override; - - ConversionRequired - DecoderNeedsConversion(const TrackInfo& aConfig) const override; - - bool - SupportsMimeType(const nsACString& aMimeType, - DecoderDoctorDiagnostics* aDiagnostics) const override; - -private: - RefPtr<CDMProxy> mProxy; - // Will be null if CDM has decoding capability. - RefPtr<PDMFactory> mPDM; - // We run the PDM on its own task queue. - RefPtr<TaskQueue> mTaskQueue; -}; - -} // namespace mozilla - -#endif // EMEDecoderModule_h_ diff --git a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp b/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp deleted file mode 100644 index d7b4b1c250..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.cpp +++ /dev/null @@ -1,67 +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 "EMEVideoDecoder.h" -#include "GMPVideoEncodedFrameImpl.h" -#include "mozilla/CDMProxy.h" -#include "MediaData.h" -#include "MP4Decoder.h" -#include "VPXDecoder.h" - -namespace mozilla { - -void -EMEVideoCallbackAdapter::Error(GMPErr aErr) -{ - if (aErr == GMPNoKeyErr) { - // The GMP failed to decrypt a frame due to not having a key. This can - // happen if a key expires or a session is closed during playback. - NS_WARNING("GMP failed to decrypt due to lack of key"); - return; - } - VideoCallbackAdapter::Error(aErr); -} - -EMEVideoDecoder::EMEVideoDecoder(CDMProxy* aProxy, - const GMPVideoDecoderParams& aParams) - : GMPVideoDecoder(GMPVideoDecoderParams(aParams).WithAdapter( - new EMEVideoCallbackAdapter(aParams.mCallback, - VideoInfo(aParams.mConfig.mDisplay), - aParams.mImageContainer))) - , mProxy(aProxy) - , mDecryptorId(aProxy->GetDecryptorId()) -{} - -void -EMEVideoDecoder::InitTags(nsTArray<nsCString>& aTags) -{ - VideoInfo config = GetConfig(); - if (MP4Decoder::IsH264(config.mMimeType)) { - aTags.AppendElement(NS_LITERAL_CSTRING("h264")); - } else if (VPXDecoder::IsVP8(config.mMimeType)) { - aTags.AppendElement(NS_LITERAL_CSTRING("vp8")); - } else if (VPXDecoder::IsVP9(config.mMimeType)) { - aTags.AppendElement(NS_LITERAL_CSTRING("vp9")); - } - aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem())); -} - -nsCString -EMEVideoDecoder::GetNodeId() -{ - return mProxy->GetNodeId(); -} - -GMPUniquePtr<GMPVideoEncodedFrame> -EMEVideoDecoder::CreateFrame(MediaRawData* aSample) -{ - GMPUniquePtr<GMPVideoEncodedFrame> frame = GMPVideoDecoder::CreateFrame(aSample); - if (frame && aSample->mCrypto.mValid) { - static_cast<gmp::GMPVideoEncodedFrameImpl*>(frame.get())->InitCrypto(aSample->mCrypto); - } - return frame; -} - -} // namespace mozilla diff --git a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.h b/dom/media/platforms/agnostic/eme/EMEVideoDecoder.h deleted file mode 100644 index e3b63b5066..0000000000 --- a/dom/media/platforms/agnostic/eme/EMEVideoDecoder.h +++ /dev/null @@ -1,44 +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 EMEVideoDecoder_h_ -#define EMEVideoDecoder_h_ - -#include "GMPVideoDecoder.h" -#include "PlatformDecoderModule.h" - -namespace mozilla { - -class CDMProxy; -class TaskQueue; - -class EMEVideoCallbackAdapter : public VideoCallbackAdapter { -public: - EMEVideoCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback, - VideoInfo aVideoInfo, - layers::ImageContainer* aImageContainer) - : VideoCallbackAdapter(aCallback, aVideoInfo, aImageContainer) - {} - - void Error(GMPErr aErr) override; -}; - -class EMEVideoDecoder : public GMPVideoDecoder { -public: - EMEVideoDecoder(CDMProxy* aProxy, const GMPVideoDecoderParams& aParams); - -private: - void InitTags(nsTArray<nsCString>& aTags) override; - nsCString GetNodeId() override; - uint32_t DecryptorId() const override { return mDecryptorId; } - GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(MediaRawData* aSample) override; - - RefPtr<CDMProxy> mProxy; - uint32_t mDecryptorId; -}; - -} // namespace mozilla - -#endif // EMEVideoDecoder_h_ diff --git a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp deleted file mode 100644 index 532fc63c01..0000000000 --- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.cpp +++ /dev/null @@ -1,85 +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 "SamplesWaitingForKey.h" -#include "mozilla/CDMProxy.h" -#include "mozilla/CDMCaps.h" -#include "MediaData.h" - -namespace mozilla { - -SamplesWaitingForKey::SamplesWaitingForKey(MediaDataDecoder* aDecoder, - MediaDataDecoderCallback* aCallback, - TaskQueue* aTaskQueue, - CDMProxy* aProxy) - : mMutex("SamplesWaitingForKey") - , mDecoder(aDecoder) - , mDecoderCallback(aCallback) - , mTaskQueue(aTaskQueue) - , mProxy(aProxy) -{ -} - -SamplesWaitingForKey::~SamplesWaitingForKey() -{ -} - -bool -SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample) -{ - if (!aSample || !aSample->mCrypto.mValid || !mProxy) { - return false; - } - CDMCaps::AutoLock caps(mProxy->Capabilites()); - const auto& keyid = aSample->mCrypto.mKeyId; - if (!caps.IsKeyUsable(keyid)) { - { - MutexAutoLock lock(mMutex); - mSamples.AppendElement(aSample); - } - mDecoderCallback->WaitingForKey(); - caps.NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this); - return true; - } - return false; -} - -void -SamplesWaitingForKey::NotifyUsable(const CencKeyId& aKeyId) -{ - MutexAutoLock lock(mMutex); - size_t i = 0; - while (i < mSamples.Length()) { - if (aKeyId == mSamples[i]->mCrypto.mKeyId) { - RefPtr<nsIRunnable> task; - task = NewRunnableMethod<RefPtr<MediaRawData>>(mDecoder, - &MediaDataDecoder::Input, - RefPtr<MediaRawData>(mSamples[i])); - mSamples.RemoveElementAt(i); - mTaskQueue->Dispatch(task.forget()); - } else { - i++; - } - } -} - -void -SamplesWaitingForKey::Flush() -{ - MutexAutoLock lock(mMutex); - mSamples.Clear(); -} - -void -SamplesWaitingForKey::BreakCycles() -{ - MutexAutoLock lock(mMutex); - mDecoder = nullptr; - mTaskQueue = nullptr; - mProxy = nullptr; - mSamples.Clear(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h b/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.h deleted file mode 100644 index 8672bccdd1..0000000000 --- a/dom/media/platforms/agnostic/eme/SamplesWaitingForKey.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 SamplesWaitingForKey_h_ -#define SamplesWaitingForKey_h_ - -#include "mozilla/TaskQueue.h" - -#include "PlatformDecoderModule.h" - -namespace mozilla { - -typedef nsTArray<uint8_t> CencKeyId; - -class CDMProxy; - -// Encapsulates the task of waiting for the CDMProxy to have the necessary -// keys to decrypt a given sample. -class SamplesWaitingForKey { -public: - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SamplesWaitingForKey) - - explicit SamplesWaitingForKey(MediaDataDecoder* aDecoder, - MediaDataDecoderCallback* aCallback, - TaskQueue* aTaskQueue, - CDMProxy* aProxy); - - // Returns true if we need to wait for a key to become usable. - // Will callback MediaDataDecoder::Input(aSample) on mDecoder once the - // sample is ready to be decrypted. The order of input samples is - // preserved. - bool WaitIfKeyNotUsable(MediaRawData* aSample); - - void NotifyUsable(const CencKeyId& aKeyId); - - void Flush(); - - void BreakCycles(); - -protected: - ~SamplesWaitingForKey(); - -private: - Mutex mMutex; - RefPtr<MediaDataDecoder> mDecoder; - MediaDataDecoderCallback* mDecoderCallback; - RefPtr<TaskQueue> mTaskQueue; - RefPtr<CDMProxy> mProxy; - nsTArray<RefPtr<MediaRawData>> mSamples; -}; - -} // namespace mozilla - -#endif // SamplesWaitingForKey_h_ diff --git a/dom/media/platforms/agnostic/eme/moz.build b/dom/media/platforms/agnostic/eme/moz.build deleted file mode 100644 index 74260b3ba2..0000000000 --- a/dom/media/platforms/agnostic/eme/moz.build +++ /dev/null @@ -1,22 +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 += [ - 'EMEAudioDecoder.h', - 'EMEDecoderModule.h', - 'EMEVideoDecoder.h', - 'SamplesWaitingForKey.h', -] - -UNIFIED_SOURCES += [ - 'EMEAudioDecoder.cpp', - 'EMEDecoderModule.cpp', - 'EMEVideoDecoder.cpp', - 'SamplesWaitingForKey.cpp', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 09d9afa4d2..d4dc579b19 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -32,9 +32,6 @@ DIRS += [ 'omx' ] -if CONFIG['MOZ_EME']: - DIRS += ['agnostic/eme'] - if CONFIG['MOZ_GMP']: DIRS += ['agnostic/gmp'] diff --git a/dom/media/test/mochitest.ini b/dom/media/test/mochitest.ini index 516c2beb03..2699c03ac2 100644 --- a/dom/media/test/mochitest.ini +++ b/dom/media/test/mochitest.ini @@ -425,9 +425,6 @@ support-files = dirac.ogg^headers^ dynamic_redirect.sjs dynamic_resource.sjs -#ifdef MOZ_EME - eme.js -#endif file_access_controls.html flac-s24.flac flac-s24.flac^headers^ @@ -684,38 +681,6 @@ tags=capturestream [test_decoder_disable.html] [test_defaultMuted.html] [test_delay_load.html] -#ifdef MOZ_EME -[test_eme_session_callable_value.html] -[test_eme_canvas_blocked.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_detach_media_keys.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_initDataTypes.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_missing_pssh.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_non_mse_fails.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_request_notifications.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_playback.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_requestKeySystemAccess.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_setMediaKeys_before_attach_MediaSource.html] -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_stream_capture_blocked_case1.html] -tags=msg capturestream -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_stream_capture_blocked_case2.html] -tags=msg capturestream -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_stream_capture_blocked_case3.html] -tags=msg capturestream -skip-if = toolkit == 'android' # bug 1149374 -[test_eme_waitingforkey.html] -skip-if = toolkit == 'android' # bug 1149374 -#endif [test_empty_resource.html] [test_error_in_video_document.html] [test_error_on_404.html] diff --git a/dom/media/test/test_eme_canvas_blocked.html b/dom/media/test/test_eme_canvas_blocked.html deleted file mode 100644 index e84b6db402..0000000000 --- a/dom/media/test/test_eme_canvas_blocked.html +++ /dev/null @@ -1,58 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function startTest(test, token) -{ - manager.started(token); - - var sessions = []; - - var v = SetupEME(test, token); - v.preload = "auto"; // Required due to "canplay" not firing for MSE unless we do this. - - v.addEventListener("loadeddata", function(ev) { - var video = ev.target; - var canvas = document.createElement("canvas"); - canvas.width = video.videoWidth; - canvas.height = video.videoHeight; - document.body.appendChild(canvas); - var ctx = canvas.getContext("2d"); - var threwError = false; - try { - ctx.drawImage(video, 0, 0); - } catch (ex) { - threwError = true; - } - ok(threwError, TimeStamp(token) + " - Should throw an error when trying to draw EME video to canvas."); - manager.finished(token); - }); - - LoadTestWithManagedLoadToken(test, v, manager, token, - { onlyLoadFirstFragments:2, noEndOfStream:false }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_detach_media_keys.html b/dom/media/test/test_eme_detach_media_keys.html deleted file mode 100644 index 6d3dc8467e..0000000000 --- a/dom/media/test/test_eme_detach_media_keys.html +++ /dev/null @@ -1,63 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<video id="v" controls></video> -<script class="testbody" type="text/javascript"> - -SimpleTest.waitForExplicitFinish(); - -function createAndSet() { - return new Promise(function(resolve, reject) { - var m; - navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig) - .then(function (access) { - return access.createMediaKeys(); - }) - .then(function (mediaKeys) { - m = mediaKeys; - return document.getElementById("v").setMediaKeys(mediaKeys); - }) - .then(function() { - resolve(m); - }); - } -)} - -var m1,m2; - -// Test that if we create and set two MediaKeys on one video element, -// that if the first MediaKeys we set on the media elemnt is still usable -// after the second MediaKeys has been set on the media element. -SetupEMEPref(() => { - createAndSet().then((m) => { - m1 = m; // Stash MediaKeys. - return createAndSet(); - }) - .then((m) => { - m2 = m; - is(document.getElementById("v").mediaKeys, m2, "Should have set MediaKeys on media element"); - ok(document.getElementById("v").mediaKeys != m1, "First MediaKeys should no longer be set on media element"); - var s = m1.createSession("temporary"); - return s.generateRequest("webm", StringToArrayBuffer(atob('YAYeAX5Hfod+V9ANHtANHg=='))); - }) - .then(() => { - ok(true, "Was able to generateRequest using second CDM"); - SimpleTest.finish(); - }, () => { - ok(false, "Was *NOT* able to generateRequest using second CDM"); - SimpleTest.finish(); - }); -}); - -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_initDataTypes.html b/dom/media/test/test_eme_initDataTypes.html deleted file mode 100644 index 4821c3cb82..0000000000 --- a/dom/media/test/test_eme_initDataTypes.html +++ /dev/null @@ -1,133 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -var tests = [ - { - name: "One keyId", - initDataType: 'keyids', - initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}', - expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"],"type":"temporary"}', - sessionType: 'temporary', - expectPass: true, - }, - { - name: "Two keyIds", - initDataType: 'keyids', - initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', - expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}', - sessionType: 'temporary', - expectPass: true, - }, - { - name: "Two keyIds, temporary session", - initDataType: 'keyids', - initData: '{"type":"temporary", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', - expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"temporary"}', - sessionType: 'temporary', - expectPass: true, - }, - { - name: "Two keyIds, persistent session, type before kids", - initDataType: 'keyids', - initData: '{"type":"persistent-license", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', - expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"persistent-license"}', - sessionType: 'persistent-license', - expectPass: false, - }, - { - name: "Invalid keyId", - initDataType: 'keyids', - initData: '{"kids":["0"]}', - sessionType: 'temporary', - expectPass: false, - }, - { - name: "Empty keyId", - initDataType: 'keyids', - initData: '{"kids":[""]}', - sessionType: 'temporary', - expectPass: false, - }, - { - name: "Invalid initData", - initDataType: 'keyids', - initData: 'invalid initData', - sessionType: 'temporary', - expectPass: false, - }, - { - name: "'webm' initDataType", - initDataType: 'webm', - initData: 'YAYeAX5Hfod+V9ANHtANHg==', - expectedRequest: '{"kids":["YAYeAX5Hfod-V9ANHtANHg"],"type":"temporary"}', - sessionType: 'temporary', - expectPass: true, - }, - { - name: "'webm' initDataType with non 16 byte keyid", - initDataType: 'webm', - initData: 'YAYeAX5Hfod', - expectedRequest: '{\"kids\":[\"YAYeAX5Hfoc\"],\"type\":\"temporary\"}', - sessionType: 'temporary', - expectPass: true, - }, -]; - -function PrepareInitData(initDataType, initData) -{ - if (initDataType == "keyids") { - return new TextEncoder().encode(initData); - } else if (initDataType == "webm") { - return StringToArrayBuffer(atob(initData)); - } -} - -function Test(test) { - return new Promise(function(resolve, reject) { - var configs = [{ - initDataTypes: [test.initDataType], - videoCapabilities: [{contentType: 'video/mp4' }], - }]; - navigator.requestMediaKeySystemAccess('org.w3.clearkey', configs) - .then((access) => access.createMediaKeys()) - .then((mediaKeys) => { - var session = mediaKeys.createSession(test.sessionType); - session.addEventListener("message", function(event) { - is(event.messageType, "license-request", "'" + test.name + "' MediaKeyMessage type should be license-request."); - var text = new TextDecoder().decode(event.message); - is(text, test.expectedRequest, "'" + test.name + "' got expected response."); - is(text == test.expectedRequest, test.expectPass, - "'" + test.name + "' expected to " + (test.expectPass ? "pass" : "fail")); - resolve(); - }); - var initData = PrepareInitData(test.initDataType, test.initData); - return session.generateRequest(test.initDataType, initData); - } - ).catch((x) => { - ok(!test.expectPass, "'" + test.name + "' expected to fail."); - resolve(); - }); - }); -} - -function beginTest() { - Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); }); -} - -SimpleTest.waitForExplicitFinish(); -SetupEMEPref(beginTest); - -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_missing_pssh.html b/dom/media/test/test_eme_missing_pssh.html deleted file mode 100644 index 196ced4022..0000000000 --- a/dom/media/test/test_eme_missing_pssh.html +++ /dev/null @@ -1,92 +0,0 @@ -<!DOCTYPE HTML> -<html> - <head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> - </head> - <body> - <audio controls id="audio"></audio> - <pre id="test"> - <script class="testbody" type="text/javascript"> - - // Tests that a fragmented MP4 file without a PSSH, but with valid encrypted - // tracks with valid TENC boxes, is able to load with EME. - // We setup MSE before starting up EME, so that we exercise the "waiting for - // cdm" step in the MediaDecoderStateMachine. - - SimpleTest.waitForExplicitFinish(); - - var pssh = [ - 0x00, 0x00, 0x00, 0x00, - 0x70, 0x73, 0x73, 0x68, // BMFF box header (76 bytes, 'pssh') - 0x01, 0x00, 0x00, 0x00, // Full box header (version = 1, flags = 0) - 0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2, 0x4d, 0x02, // SystemID - 0xac, 0xe3, 0x3c, 0x1e, 0x52, 0xe2, 0xfb, 0x4b, - 0x00, 0x00, 0x00, 0x01, // KID_count (1) - 0x2f, 0xef, 0x8a, 0xd8, 0x12, 0xdf, 0x42, 0x97, - 0x83, 0xe9, 0xbf, 0x6e, 0x5e, 0x49, 0x3e, 0x53, - 0x00, 0x00, 0x00, 0x00 // Size of Data (0) - ]; - - var audio = document.getElementById("audio"); - - function LoadEME() { - var options = [{ - initDataType: 'cenc', - audioType: 'audio/mp4; codecs="mp4a.40.2"', - }]; - navigator.requestMediaKeySystemAccess("org.w3.clearkey", options) - .then((keySystemAccess) => { - return keySystemAccess.createMediaKeys(); - }, bail("Failed to request key system access.")) - - .then((mediaKeys) => { - audio.setMediaKeys(mediaKeys); - var session = mediaKeys.createSession(); - once(session, "message", (message) => { - is(message.messageType, 'license-request', "Expected a license-request"); - var license = new TextEncoder().encode(JSON.stringify({ - 'keys': [{ - 'kty':'oct', - 'kid':'L--K2BLfQpeD6b9uXkk-Uw', - 'k':HexToBase64('7f412f0575f44f718259beef56ec7771') - }], - 'type': 'temporary' - })); - session.update(license); - }); - session.generateRequest('cenc', new Uint8Array(pssh)); - }); - } - - function DownloadMedia(url, type, mediaSource) { - return new Promise(function(resolve, reject) { - var sourceBuffer = mediaSource.addSourceBuffer(type); - fetchWithXHR(url, (response) => { - once(sourceBuffer, "updateend", resolve); - sourceBuffer.appendBuffer(new Uint8Array(response)); - }); - }); - } - - function LoadMSE() { - var ms = new MediaSource(); - audio.src = URL.createObjectURL(ms); - - once(ms, "sourceopen", ()=>{ - DownloadMedia('short-audio-fragmented-cenc-without-pssh.mp4', 'audio/mp4; codecs="mp4a.40.2"', ms) - .then(() => { ms.endOfStream(); LoadEME();}); - }); - - audio.addEventListener("loadeddata", SimpleTest.finish); - } - - SetupEMEPref(LoadMSE); - - </script> - </pre> - </body> -</html> diff --git a/dom/media/test/test_eme_non_mse_fails.html b/dom/media/test/test_eme_non_mse_fails.html deleted file mode 100644 index ede3edc5f2..0000000000 --- a/dom/media/test/test_eme_non_mse_fails.html +++ /dev/null @@ -1,103 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Bug 1131392 - Test that EME does not work for non-MSE media</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function DoSetMediaKeys(v, test) -{ - var options = [{ - initDataTypes: ["cenc"], - audioCapabilities: [{contentType: test.audioType}], - videoCapabilities: [{contentType: test.videoType}], - }]; - - return navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, options) - - .then(function(keySystemAccess) { - return keySystemAccess.createMediaKeys(); - }) - - .catch(function() { - ok(false, token + " was not expecting failure (yet)"); - }) - - .then(function(mediaKeys) { - return v.setMediaKeys(mediaKeys); - }); -} - -function TestSetMediaKeys(test, token) -{ - manager.started(token); - - var v = document.createElement("video"); - - v.addEventListener("encrypted", function() { - ok(false, token + " should not fire encrypted event"); - }); - - var loadedMetadata = false; - v.addEventListener("loadedmetadata", function() { - loadedMetadata = true; - }); - - v.addEventListener("error", function() { - ok(true, token + " expected error event"); - ok(loadedMetadata, token + " expected loadedmetadata to have fired"); - manager.finished(token); - }); - - v.src = test.name; -} - -function TestSetSrc(test, token) -{ - manager.started(token); - - var v = document.createElement("video"); - v.addEventListener("error", function(err) { - ok(true, token + " got error setting src on video element, as expected"); - manager.finished(token); - }); - - DoSetMediaKeys(v, test) - - .then(function() { - v.src = test.name; - }) - - .catch(function() { - ok(false, token + " got error setting media keys"); - }); -} - -function startTest(test, token) -{ - TestSetMediaKeys(test, token + "_setMediaKeys"); - TestSetSrc(test, token + "_setSrc"); -} - -function beginTest() { - manager.runTests(gEMENonMSEFailTests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> - diff --git a/dom/media/test/test_eme_playback.html b/dom/media/test/test_eme_playback.html deleted file mode 100644 index a568402cd6..0000000000 --- a/dom/media/test/test_eme_playback.html +++ /dev/null @@ -1,188 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function ArrayBuffersEqual(a, b) { - if (a.byteLength != b.byteLength) { - return false; - } - var ua = new Uint8Array(a); - var ub = new Uint8Array(b); - for (var i = 0; i < ua.length; i++) { - if (ua[i] != ub[i]) { - return false; - } - } - return true; -} - -function KeysChangeFunc(session, keys, token) { - session.keyIdsReceived = []; - for (var keyid in keys) { - Log(token, "Set " + keyid + " to false in session[" + session.sessionId + "].keyIdsReceived"); - session.keyIdsReceived[keyid] = false; - } - return function(ev) { - var session = ev.target; - session.gotKeysChanged = true; - - var keyList = []; - var valueList = []; - var map = session.keyStatuses; - - // Test that accessing keys not known to the CDM has expected behaviour. - var absentKey = new Uint8Array([0xeb, 0xdd, 0x62, 0xf1, 0x68, 0x14, 0xd2, 0x7b, - 0x68, 0xef, 0x12, 0x2a, 0xfc, 0xe4, 0xae, 0x3c]); - is(map.has(absentKey), false, "Shouldn't have a key that's not in the media"); - is(map.get(absentKey), undefined, "Unknown keys should undefined status"); - - // Verify known keys have expected status. - for (var [key, val] of map.entries()) { - is(key.constructor, ArrayBuffer, "keyId should be ArrayBuffer"); - ok(map.has(key), "MediaKeyStatusMap.has() should work."); - is(map.get(key), val, "MediaKeyStatusMap.get() should work."); - keyList.push(key); - valueList.push(val); - is(val, "usable", token + ": key status should be usable"); - var kid = Base64ToHex(window.btoa(ArrayBufferToString(key))); - ok(kid in session.keyIdsReceived, TimeStamp(token) + " session[" + session.sessionId + "].keyIdsReceived contained " + kid + " as expected."); - session.keyIdsReceived[kid] = true; - } - - var index = 0; - for (var keyId of map.keys()) { - ok(ArrayBuffersEqual(keyId, keyList[index]), "MediaKeyStatusMap.keys() should correspond to entries"); - index++; - } - index = 0; - for (var val of map.values()) { - is(val, valueList[index], "MediaKeyStatusMap.values() should correspond to entries"); - index++; - } - } -} - -function startTest(test, token) -{ - manager.started(token); - - var sessions = []; - - var v = SetupEME(test, token, - { - onsessioncreated: function(session) { - sessions.push(session); - session.addEventListener("keystatuseschange", KeysChangeFunc(session, test.keys, token), false); - - session.numKeystatuseschangeEvents = 0; - session.numOnkeystatuseschangeEvents = 0; - - session.addEventListener("keystatuseschange", function() { - session.numKeystatuseschangeEvents += 1; - }); - session.onkeystatuseschange = function() { - session.numOnkeystatuseschangeEvents += 1; - }; - - session.numMessageEvents = 0; - session.numOnMessageEvents = 0; - session.addEventListener("message", function() { - session.numMessageEvents += 1; - }); - session.onmessage = function() { - session.numOnMessageEvents += 1; - }; - } - } - ); - - document.body.appendChild(v); - - var gotEncrypted = 0; - - v.addEventListener("encrypted", function(ev) { - gotEncrypted += 1; - }); - - v.addEventListener("loadedmetadata", function() { - ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v), - TimeStamp(token) + " isEncrypted should be true"); - is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content"); - }); - - v.addEventListener("ended", function(ev) { - ok(true, TimeStamp(token) + " got ended event"); - - is(gotEncrypted, test.sessionCount, - TimeStamp(token) + " encrypted events expected: " + test.sessionCount - + ", actual: " + gotEncrypted); - - ok(Math.abs(test.duration - v.duration) < 0.1, - TimeStamp(token) + " Duration of video should be corrrect"); - ok(Math.abs(test.duration - v.currentTime) < 0.1, - TimeStamp(token) + " Current time should be same as duration"); - - // Verify all sessions had all keys went sent to the CDM usable, and thus - // that we received keystatuseschange event(s). - is(sessions.length, test.sessionCount, TimeStamp(token) + " should have " - + test.sessionCount - + " session" + (test.sessionCount === 1 ? "" : "s")); - var keyIdsReceived = []; - for (var keyid in test.keys) { keyIdsReceived[keyid] = false; } - for (var i = 0; i < sessions.length; i++) { - var session = sessions[i]; - ok(session.gotKeysChanged, - TimeStamp(token) + " session[" + session.sessionId - + "] should have received at least one keychange event"); - for (var kid in session.keyIdsReceived) { - Log(token, "session[" + session.sessionId + "] key " + kid + " = " + (session.keyIdsReceived[kid] ? "true" : "false")); - if (session.keyIdsReceived[kid]) { keyIdsReceived[kid] = true; } - } - ok(session.numKeystatuseschangeEvents > 0, TimeStamp(token) + " should get key status changes"); - is(session.numKeystatuseschangeEvents, session.numOnkeystatuseschangeEvents, - TimeStamp(token) + " should have as many keystatuseschange event listener calls as event handler calls."); - - ok(session.numMessageEvents > 0, TimeStamp(token) + " should get message events"); - is(session.numMessageEvents, session.numOnMessageEvents, - TimeStamp(token) + " should have as many message event listener calls as event handler calls."); - } - for (var kid in keyIdsReceived) { - ok(keyIdsReceived[kid], TimeStamp(token) + " key with id " + kid + " was usable as expected"); - } - - v.closeSessions().then(() => manager.finished(token)); - }); - - LoadTest(test, v, token) - .then(function() { - v.play(); - }).catch(function() { - ok(false, token + " failed to load"); - manager.finished(token); - }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_requestKeySystemAccess.html b/dom/media/test/test_eme_requestKeySystemAccess.html deleted file mode 100644 index 21ee91a68c..0000000000 --- a/dom/media/test/test_eme_requestKeySystemAccess.html +++ /dev/null @@ -1,484 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -const SUPPORTED_LABEL = "pass label"; - -function ValidateConfig(name, expected, observed) { - info("ValidateConfig " + name); - info("expected cfg=" + JSON.stringify(expected)); - info("observed cfg=" + JSON.stringify(observed)); - - is(observed.label, expected.label, name + " label should match"); - if (expected.initDataTypes) { - ok(expected.initDataTypes.every((element, index, array) => observed.initDataTypes.includes(element)), name + " initDataTypes should match."); - } - - if (expected.audioCapabilities) { - ok(expected.audioCapabilities.length == 1, "Test function can only handle one capability."); - ok(observed.audioCapabilities.length == 1, "Test function can only handle one capability."); - is(observed.audioCapabilities[0].contentType, expected.audioCapabilities[0].contentType, name + " audioCapabilities should match."); - } - if (typeof expected.videoCapabilities !== 'undefined') { - info("expected.videoCapabilities=" + expected.videoCapabilities); - dump("expected.videoCapabilities=" + expected.videoCapabilities + "\n"); - ok(expected.videoCapabilities.length == 1, "Test function can only handle one capability."); - ok(observed.videoCapabilities.length == 1, "Test function can only handle one capability."); - is(observed.videoCapabilities[0].contentType, expected.videoCapabilities[0].contentType, name + " videoCapabilities should match."); - } - if (expected.sessionTypes) { - is(expected.sessionTypes.length, observed.sessionTypes.length, "Should have expected number of sessionTypes"); - for (var i = 0; i < expected.sessionTypes.length; i++) { - is(expected[i], observed[i], "Session type " + i + " should match"); - } - } -} - -function Test(test) { - var name = "'" + test.name + "'"; - return new Promise(function(resolve, reject) { - var p; - if (test.options) { - var keySystem = (test.keySystem !== undefined) ? test.keySystem : CLEARKEY_KEYSYSTEM; - p = navigator.requestMediaKeySystemAccess(keySystem, test.options); - } else { - p = navigator.requestMediaKeySystemAccess(keySystem); - } - p.then( - function(keySystemAccess) { - ok(test.shouldPass, name + " passed and was expected to " + (test.shouldPass ? "pass" : "fail")); - is(keySystemAccess.keySystem, CLEARKEY_KEYSYSTEM, "CDM keySystem should be in MediaKeySystemAccess.keySystem"); - ValidateConfig(name, test.expectedConfig, keySystemAccess.getConfiguration()); - resolve(); - }, - function(ex) { - if (test.shouldPass) { - info(name + " failed: " + ex); - } - ok(!test.shouldPass, name + " failed and was expected to " + (test.shouldPass ? "pass" : "fail")); - resolve(); - }); - }); -} - -var tests = [ - { - name: 'Empty keySystem string', - keySystem: '', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - } - ], - shouldPass: false, - }, - { - name: 'Empty options specified', - options: [ ], - shouldPass: false, - }, - { - name: 'Undefined options', - shouldPass: false, - }, - { - name: 'Basic MP4 cenc', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - videoCapabilities: [{contentType: 'video/mp4'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - videoCapabilities: [{contentType: 'video/mp4'}], - }, - shouldPass: true, - }, - { - name: 'Invalid keysystem failure', - keySystem: 'bogusKeySystem', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - } - ], - shouldPass: false, - }, - { - name: 'Invalid initDataType', - options: [ - { - initDataTypes: ['bogus'], - audioCapabilities: [{contentType: 'audio/mp4'}], - } - ], - shouldPass: false, - }, - { - name: 'Valid initDataType after invalid', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['bogus', 'invalid', 'cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - }, - shouldPass: true, - }, - { - name: 'Invalid videoType', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/bogus'}], - } - ], - shouldPass: false, - }, - { - name: 'Invalid distinctiveIdentifier fails', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - distinctiveIdentifier: 'bogus', - persistentState: 'bogus', - } - ], - shouldPass: false, - }, - { - name: 'distinctiveIdentifier is prohibited for ClearKey', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - distinctiveIdentifier: 'required', - } - ], - shouldPass: false, - }, - { - name: 'Invalid persistentState fails', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - persistentState: 'bogus', - } - ], - shouldPass: false, - }, - { - name: 'Invalid robustness unsupported', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4', robustness: 'very much so'}], - } - ], - shouldPass: false, - }, - { - name: 'Unexpected config entry should be ignored', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - unexpectedEntry: 'this should be ignored', - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - }, - shouldPass: true, - }, - { - name: 'Invalid option followed by valid', - options: [ - { - label: "this config should not be supported", - initDataTypes: ['bogus'], - }, - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - }, - shouldPass: true, - }, - { - name: 'Persistent-license should not be supported by ClearKey', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - sessionTypes: ['persistent-license'], - persistentState: 'optional', - } - ], - shouldPass: false, - }, - { - name: 'Persistent-usage-record should not be supported by ClearKey', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4'}], - sessionTypes: ['persistent-usage-record'], - persistentState: 'optional', - } - ], - shouldPass: false, - }, - { - name: 'MP4 audio container', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4'}], - }, - shouldPass: true, - }, - { - name: 'MP4 audio container with AAC-LC', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}], - }, - shouldPass: true, - }, - { - name: 'MP4 audio container with invalid codecs', - options: [ - { - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4; codecs="bogus"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 audio container with mp3 is unsupported', - options: [ - { - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4; codecs="mp3"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 video container type with an mp3 codec is unsupported', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="mp3"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 audio container type with a video codec is unsupported', - options: [ - { - initDataTypes: ['cenc'], - audioCapabilities: [{contentType: 'audio/mp4; codecs="avc1.42E01E"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 video container with constrained baseline h.264', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}], - }, - shouldPass: true, - }, - { - name: 'MP4 video container with invalid codecs', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="bogus"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 video container with both audio and video codec type in videoType', - options: [ - { - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E,mp4a.40.2"'}], - } - ], - shouldPass: false, - }, - { - name: 'MP4 audio and video type both specified', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}], - audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['cenc'], - videoCapabilities: [{contentType: 'video/mp4; codecs="avc1.42E01E"'}], - audioCapabilities: [{contentType: 'audio/mp4; codecs="mp4a.40.2"'}], - }, - shouldPass: true, - }, - { - name: 'Basic WebM video', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm'}], - }, - shouldPass: true, - }, - { - name: 'Basic WebM audio', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - audioCapabilities: [{contentType: 'audio/webm'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - audioCapabilities: [{contentType: 'audio/webm'}], - }, - shouldPass: true, - }, - { - name: 'Webm with Vorbis audio and VP8 video.', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm;codecs="vp8"'}], - audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm;codecs="vp8"'}], - audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}], - }, - shouldPass: true, - }, - { - name: 'Webm with Vorbis audio and VP9 video.', - options: [ - { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm;codecs="vp9"'}], - audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}], - } - ], - expectedConfig: { - label: SUPPORTED_LABEL, - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm;codecs="vp9"'}], - audioCapabilities: [{contentType: 'audio/webm;codecs="vorbis"'}], - }, - shouldPass: true, - }, - { - name: 'Webm with bogus video.', - options: [ - { - initDataTypes: ['webm'], - videoCapabilities: [{contentType: 'video/webm;codecs="bogus"'}], - } - ], - shouldPass: false, - }, -]; - -function beginTest() { - Promise.all(tests.map(Test)).then(function() { SimpleTest.finish(); }); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} - -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_request_notifications.html b/dom/media/test/test_eme_request_notifications.html deleted file mode 100644 index c2fab5b152..0000000000 --- a/dom/media/test/test_eme_request_notifications.html +++ /dev/null @@ -1,88 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function SetPrefs(prefs) { - return new Promise(function(resolve, reject) { - SpecialPowers.pushPrefEnv({"set": prefs}, function() { resolve(); }); - }); -} - -function observe() { - return new Promise(function(resolve, reject) { - var observer = function(subject, topic, data) { - SpecialPowers.Services.obs.removeObserver(observer, "mediakeys-request"); - resolve(JSON.parse(data).status); - }; - SpecialPowers.Services.obs.addObserver(observer, "mediakeys-request", false); - }); -} - -function Test(test) { - var p = test.prefs ? SetPrefs(test.prefs) : Promise.resolve(); - observedStatus = "nothing"; - var name = "'" + test.keySystem + "'"; - - var res = observe().then((status) => { - is(status, test.expectedStatus, name + " expected status"); - }); - - p.then(() => navigator.requestMediaKeySystemAccess(test.keySystem, gCencMediaKeySystemConfig)) - .then((keySystemAccess) => keySystemAccess.createMediaKeys()); - - return res; -} - -const isWinXP = navigator.userAgent.indexOf("Windows NT 5.1") != -1; - -var tests = [ - { - keySystem: CLEARKEY_KEYSYSTEM, - expectedStatus: 'cdm-created', - prefs: [["media.eme.enabled", false]] - }, - { - keySystem: "com.widevine.alpha", - expectedStatus: 'api-disabled', - prefs: [["media.eme.enabled", false]] - }, - { - keySystem: "com.widevine.alpha", - expectedStatus: (isWinXP ? 'cdm-not-supported' : 'cdm-disabled'), - prefs: [["media.eme.enabled", true], ["media.gmp-widevinecdm.enabled", false]] - }, - { - keySystem: "com.widevine.alpha", - expectedStatus: (isWinXP ? 'cdm-not-supported' : 'cdm-not-installed'), - prefs: [["media.eme.enabled", true], , ["media.gmp-widevinecdm.enabled", true]] - }, - { - keySystem: CLEARKEY_KEYSYSTEM, - expectedStatus: 'cdm-created', - prefs: [["media.eme.enabled", true]] - } -]; - -SetupEMEPref(function() { - tests.reduce(function(p,c,i,array) { - return p.then(function() { return Test(c); }); - }, Promise.resolve()).then(SimpleTest.finish); -}); - - -SimpleTest.waitForExplicitFinish(); - -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_session_callable_value.html b/dom/media/test/test_eme_session_callable_value.html deleted file mode 100644 index 5c5f51e307..0000000000 --- a/dom/media/test/test_eme_session_callable_value.html +++ /dev/null @@ -1,35 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -function Test() { - navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig) - .then(access => access.createMediaKeys()) - .then(mediaKeys => { - var initData = (new TextEncoder()).encode( 'this is an invalid license, and that is ok'); - var s = mediaKeys.createSession("temporary"); - s.generateRequest("cenc", initData); // ignore result. - // "update()" call should fail, because MediaKeySession is "not callable" - // yet, since CDM won't have had a chance to set the sessionId on MediaKeySession. - return s.update(initData); - }) - .then(()=>{ok(false, "An exception should be thrown; MediaKeySession should be not callable."); SimpleTest.finish();}, - ()=>{ok(true, "We expect this to fail; MediaKeySession should be not callable."); SimpleTest.finish();}); -} - -SimpleTest.waitForExplicitFinish(); -SetupEMEPref(Test); - -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html b/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html deleted file mode 100644 index 72bc77124d..0000000000 --- a/dom/media/test/test_eme_setMediaKeys_before_attach_MediaSource.html +++ /dev/null @@ -1,41 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> - -function beginTest() { - var video = document.createElement("video"); - - navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig) - .then(function(keySystemAccess) { - return keySystemAccess.createMediaKeys(); - }) - .then(mediaKeys => { - return video.setMediaKeys(mediaKeys); - }) - .then(() => { - var ms = new MediaSource(); - ms.addEventListener("sourceopen", ()=>{ok(true, "MediaSource should open"); SimpleTest.finish();}); - video.addEventListener("error", ()=>{ok(false, "Shouldn't error."); SimpleTest.finish();}); - video.src = URL.createObjectURL(ms); - }); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_stream_capture_blocked_case1.html b/dom/media/test/test_eme_stream_capture_blocked_case1.html deleted file mode 100644 index 61e8d673f3..0000000000 --- a/dom/media/test/test_eme_stream_capture_blocked_case1.html +++ /dev/null @@ -1,52 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function startTest(test, token) -{ - // Three cases: - // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and - // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and - // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. - - // Case 1. setting MediaKeys on an element captured by MediaElementSource should fail. - var case1token = token + "_case1"; - var setKeysFailed = function() { - ok(true, TimeStamp(case1token) + " setMediaKeys failed as expected."); - manager.finished(case1token); - }; - var v1 = SetupEME(test, case1token, { onSetKeysFail: setKeysFailed }); - var context = new AudioContext(); - var node = context.createMediaElementSource(v1); - v1.addEventListener("loadeddata", function(ev) { - ok(false, TimeStamp(case1token) + " should never reach loadeddata, as setMediaKeys should fail"); - }); - manager.started(case1token); - LoadTestWithManagedLoadToken(test, v1, manager, case1token, - { onlyLoadFirstFragments:2, noEndOfStream:false }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_stream_capture_blocked_case2.html b/dom/media/test/test_eme_stream_capture_blocked_case2.html deleted file mode 100644 index 48c8bf3e4a..0000000000 --- a/dom/media/test/test_eme_stream_capture_blocked_case2.html +++ /dev/null @@ -1,55 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function startTest(test, token) -{ - // Three cases: - // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and - // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and - // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. - - // Case 2. creating a MediaElementSource on a media element with a MediaKeys should fail. - var case2token = token + "_case2"; - var v2 = SetupEME(test, case2token); - v2.addEventListener("loadeddata", function(ev) { - ok(true, case2token + " should reach loadeddata"); - var threw = false; - try { - var context = new AudioContext(); - var node = context.createMediaElementSource(v2); - } catch (e) { - threw = true; - } - ok(threw, "Should throw an error creating a MediaElementSource on an EME video."); - manager.finished(case2token); - }); - manager.started(case2token); - LoadTestWithManagedLoadToken(test, v2, manager, case2token, - { onlyLoadFirstFragments:2, noEndOfStream:false }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_stream_capture_blocked_case3.html b/dom/media/test/test_eme_stream_capture_blocked_case3.html deleted file mode 100644 index 1af4e0aadf..0000000000 --- a/dom/media/test/test_eme_stream_capture_blocked_case3.html +++ /dev/null @@ -1,54 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function startTest(test, token) -{ - // Three cases: - // 1. setting MediaKeys on an element captured by MediaElementSource should fail, and - // 2. creating a MediaElementSource on a media element with a MediaKeys should fail, and - // 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. - - // Case 3. capturing a media element with mozCaptureStream that has a MediaKeys should fail. - var case3token = token + "_case3"; - var v3 = SetupEME(test, case3token); - v3.addEventListener("loadeddata", function(ev) { - ok(true, TimeStamp(case3token) + " should reach loadeddata"); - var threw = false; - try { - var stream = v3.mozCaptureStreamUntilEnded(); - } catch (e) { - threw = true; - } - ok(threw, TimeStamp(case3token) + " Should throw an error calling mozCaptureStreamUntilEnded an EME video."); - manager.finished(case3token); - }); - manager.started(case3token); - LoadTestWithManagedLoadToken(test, v3, manager, case3token, - { onlyLoadFirstFragments:2, noEndOfStream:false }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/test/test_eme_waitingforkey.html b/dom/media/test/test_eme_waitingforkey.html deleted file mode 100644 index ce808342bb..0000000000 --- a/dom/media/test/test_eme_waitingforkey.html +++ /dev/null @@ -1,117 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test Encrypted Media Extensions</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> - <script type="text/javascript" src="manifest.js"></script> - <script type="text/javascript" src="http://test1.mochi.test:8888/tests/dom/media/test/eme.js"></script> -</head> -<body> -<pre id="test"> -<script class="testbody" type="text/javascript"> -var manager = new MediaTestManager; - -function startTest(test, token) -{ - // Test if the appropriate preconditions are met such that we can start - // prcoessing delayed sessions. - function TestIfDoneDelaying() - { - var got = "Got:"; - if (loaded) { got += " loaded,"; } - got += " " + gotEncrypted + "/" + test.sessionCount + " sessions,"; - got += " " + gotWaitingForKey + " waiting for key events" - if (loaded && gotEncrypted == test.sessionCount && gotWaitingForKey > 0) { - Log(token, got + " -> Update sessions with keys"); - params.ProcessSessions(); - } else { - Log(token, got + " -> Wait for more..."); - } - } - - manager.started(token); - - var updatedSessionsCount = 0; - var loaded = false; - - var params = { - // params will be populated with a ProcessSessions() callback, that can be - // called to process delayed sessions. - delaySessions: true, - // Function to be called once we start processing and updating sessions. - // This should only be called once the preconditions in TestIfDoneDealying - // are met. - onsessionupdated: function(session) { - updatedSessionsCount += 1; - if (updatedSessionsCount == test.sessionCount) { - info(TimeStamp(token) + " Updated all sessions, loading complete -> Play"); - v.play(); - } else { - info(TimeStamp(token) + " Updated " + updatedSessionsCount + "/" + test.sessionCount + " sessions so far"); - } - }, - }; - var v = SetupEME(test, token, params); - - document.body.appendChild(v); - - var gotEncrypted = 0; - var gotWaitingForKey = 0; - var gotOnwaitingforkey = 0; - - v.addEventListener("encrypted", function() { - gotEncrypted += 1; - TestIfDoneDelaying(); - }); - - v.addEventListener("waitingforkey", function() { - gotWaitingForKey += 1; - TestIfDoneDelaying() - }); - - v.onwaitingforkey = function() { - gotOnwaitingforkey += 1; - }; - - v.addEventListener("loadedmetadata", function() { - ok(SpecialPowers.do_lookupGetter(v, "isEncrypted").apply(v), - TimeStamp(token) + " isEncrypted should be true"); - is(v.isEncrypted, undefined, "isEncrypted should not be accessible from content"); - }); - - v.addEventListener("ended", function() { - ok(true, TimeStamp(token) + " got ended event"); - // We expect only one waitingForKey as we delay until all sessions are ready. - // I.e. one waitingForKey should be fired, after which, we process all sessions, - // so it should not be possible to be blocked by a key after that point. - ok(gotWaitingForKey == 1, "Expected number 1 wait, got: " + gotWaitingForKey); - ok(gotOnwaitingforkey == gotWaitingForKey, "Should have as many event listener calls as event handler calls, got: " + gotOnwaitingforkey); - - v.closeSessions().then(() => manager.finished(token)); - }); - - LoadTest(test, v, token) - .then(function() { - loaded = true; - TestIfDoneDelaying(); - }).catch(function() { - ok(false, token + " failed to load"); - manager.finished(token); - }); -} - -function beginTest() { - manager.runTests(gEMETests, startTest); -} - -if (!IsMacOSSnowLeopardOrEarlier()) { - SimpleTest.waitForExplicitFinish(); - SetupEMEPref(beginTest); -} else { - todo(false, "Test disabled on this platform."); -} -</script> -</pre> -</body> -</html> diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 44285735be..9539133a4f 100755 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -372,13 +372,6 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement, return nullptr; } -#ifdef MOZ_EME - if (aMediaElement.ContainsRestrictedContent()) { - aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return nullptr; - } -#endif - if (CheckClosed(aRv)) { return nullptr; } |