mirror of
https://github.com/roytam1/palemoon27.git
synced 2026-05-26 14:18:48 +00:00
Remove EME (Encrypted Media Extensions) DRM support.
This resolves #102.
This commit is contained in:
@@ -866,10 +866,3 @@ bin/libfreebl_32int64_3.so
|
||||
#if defined(MOZ_ASAN) && defined(CLANG_CL)
|
||||
@BINPATH@/clang_rt.asan_dynamic-i386.dll
|
||||
#endif
|
||||
|
||||
|
||||
; media
|
||||
#ifdef MOZ_EME
|
||||
@RESPATH@/gmp-clearkey/0.1/@DLL_PREFIX@clearkey@DLL_SUFFIX@
|
||||
@RESPATH@/gmp-clearkey/0.1/clearkey.info
|
||||
#endif
|
||||
|
||||
@@ -5290,23 +5290,6 @@ MOZ_ARG_DISABLE_BOOL(fmp4,
|
||||
|
||||
if test -n "$MOZ_FMP4"; then
|
||||
AC_DEFINE(MOZ_FMP4)
|
||||
MOZ_EME=1
|
||||
fi;
|
||||
|
||||
dnl ========================================================
|
||||
dnl = EME support
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_DISABLE_BOOL(eme,
|
||||
[ --disable-eme Disable support for Encrypted Media Extensions],
|
||||
MOZ_EME=,
|
||||
MOZ_EME=1)
|
||||
|
||||
if test -n "$MOZ_EME"; then
|
||||
if test -z "$MOZ_FMP4"; then
|
||||
AC_MSG_ERROR([Encrypted Media Extension support requires Fragmented MP4 support])
|
||||
fi
|
||||
AC_DEFINE(MOZ_EME)
|
||||
fi;
|
||||
|
||||
dnl ========================================================
|
||||
@@ -8737,7 +8720,6 @@ AC_SUBST(MOZ_WEBM)
|
||||
AC_SUBST(MOZ_WMF)
|
||||
AC_SUBST(MOZ_FFMPEG)
|
||||
AC_SUBST(MOZ_FMP4)
|
||||
AC_SUBST(MOZ_EME)
|
||||
AC_SUBST(MOZ_DIRECTSHOW)
|
||||
AC_SUBST(MOZ_ANDROID_OMX)
|
||||
AC_SUBST(MOZ_APPLEMEDIA)
|
||||
|
||||
@@ -112,10 +112,6 @@
|
||||
|
||||
#include "mozilla/dom/FeatureList.h"
|
||||
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
@@ -200,9 +196,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedResolveResults)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeySystemAccessManager)
|
||||
#endif
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
@@ -317,12 +310,6 @@ Navigator::Invalidate()
|
||||
|
||||
mServiceWorkerContainer = nullptr;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeySystemAccessManager) {
|
||||
mMediaKeySystemAccessManager->Shutdown();
|
||||
mMediaKeySystemAccessManager = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//*****************************************************************************
|
||||
@@ -2630,27 +2617,5 @@ Navigator::GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI,
|
||||
return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
already_AddRefed<Promise>
|
||||
Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(mWindow);
|
||||
nsRefPtr<Promise> promise = Promise::Create(go, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mMediaKeySystemAccessManager) {
|
||||
mMediaKeySystemAccessManager = new MediaKeySystemAccessManager(mWindow);
|
||||
}
|
||||
|
||||
mMediaKeySystemAccessManager->Request(promise, aKeySystem, aOptions);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -18,9 +18,6 @@
|
||||
#include "nsInterfaceHashtable.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeySystemAccessManager.h"
|
||||
#endif
|
||||
|
||||
class nsPluginArray;
|
||||
class nsMimeTypeArray;
|
||||
@@ -330,15 +327,6 @@ public:
|
||||
// any, else null.
|
||||
static already_AddRefed<nsPIDOMWindow> GetWindowFromGlobal(JSObject* aGlobal);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
already_AddRefed<Promise>
|
||||
RequestMediaKeySystemAccess(const nsAString& aKeySystem,
|
||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions,
|
||||
ErrorResult& aRv);
|
||||
private:
|
||||
nsRefPtr<MediaKeySystemAccessManager> mMediaKeySystemAccessManager;
|
||||
#endif
|
||||
|
||||
private:
|
||||
virtual ~Navigator();
|
||||
|
||||
|
||||
@@ -4554,32 +4554,6 @@ nsDocument::SetScopeObject(nsIGlobalObject* aGlobal)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
static void
|
||||
CheckIfContainsEMEContent(nsISupports* aSupports, void* aContainsEME)
|
||||
{
|
||||
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aSupports));
|
||||
if (domMediaElem) {
|
||||
nsCOMPtr<nsIContent> content(do_QueryInterface(domMediaElem));
|
||||
MOZ_ASSERT(content, "aSupports is not a content");
|
||||
HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(content.get());
|
||||
bool* contains = static_cast<bool*>(aContainsEME);
|
||||
if (mediaElem->GetMediaKeys()) {
|
||||
*contains = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::ContainsEMEContent()
|
||||
{
|
||||
bool containsEME = false;
|
||||
EnumerateActivityObservers(CheckIfContainsEMEContent,
|
||||
static_cast<void*>(&containsEME));
|
||||
return containsEME;
|
||||
}
|
||||
#endif // MOZ_EME
|
||||
|
||||
static void
|
||||
CheckIfContainsMSEContent(nsISupports* aSupports, void* aContainsMSE)
|
||||
{
|
||||
@@ -8855,14 +8829,6 @@ nsDocument::CanSavePresentation(nsIRequest *aNewRequest)
|
||||
}
|
||||
#endif // MOZ_WEBRTC
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Don't save presentations for documents containing EME content, so that
|
||||
// CDMs reliably shutdown upon user navigation.
|
||||
if (ContainsEMEContent()) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Don't save presentations for documents containing MSE content, to
|
||||
// reduce memory usage.
|
||||
if (ContainsMSEContent()) {
|
||||
|
||||
@@ -1473,10 +1473,6 @@ public:
|
||||
|
||||
js::ExpandoAndGeneration mExpandoAndGeneration;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
bool ContainsEMEContent();
|
||||
#endif
|
||||
|
||||
bool ContainsMSEContent();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaEncryptedEvent.h"
|
||||
#endif
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "nsIDOMHTMLMediaElement.h"
|
||||
@@ -451,9 +448,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTM
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTextTrackManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVideoTrackList)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaKeys)
|
||||
#endif
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
|
||||
@@ -476,9 +470,6 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLE
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mTextTrackManager)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioTrackList)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mVideoTrackList)
|
||||
#ifdef MOZ_EME
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMediaKeys)
|
||||
#endif
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(HTMLMediaElement)
|
||||
@@ -642,14 +633,6 @@ void HTMLMediaElement::ShutdownDecoder()
|
||||
|
||||
void HTMLMediaElement::AbortExistingLoads()
|
||||
{
|
||||
#ifdef MOZ_EME
|
||||
// If there is no existing decoder then we don't have anything to
|
||||
// report. This prevents reporting the initial load from an
|
||||
// empty video element as a failed EME load.
|
||||
if (mDecoder) {
|
||||
ReportEMETelemetry();
|
||||
}
|
||||
#endif
|
||||
// Abort any already-running instance of the resource selection algorithm.
|
||||
mLoadWaitStatus = NOT_WAITING;
|
||||
|
||||
@@ -1183,14 +1166,6 @@ nsresult HTMLMediaElement::LoadResource()
|
||||
// Set the media element's CORS mode only when loading a resource
|
||||
mCORSMode = AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys &&
|
||||
!IsMediaStreamURI(mLoadingSrc) &&
|
||||
Preferences::GetBool("media.eme.mse-only", true)) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
HTMLMediaElement* other = LookupMediaElementURITable(mLoadingSrc);
|
||||
if (other && other->mDecoder) {
|
||||
// Clone it.
|
||||
@@ -1881,11 +1856,6 @@ HTMLMediaElement::CaptureStreamInternal(bool aFinishWhenEnded)
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (ContainsRestrictedContent()) {
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
OutputMediaStream* out = mOutputStreams.AppendElement();
|
||||
out->mStream = DOMMediaStream::CreateTrackUnionStream(window);
|
||||
nsRefPtr<nsIPrincipal> principal = GetCurrentPrincipal();
|
||||
@@ -2587,20 +2557,6 @@ nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParen
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void
|
||||
HTMLMediaElement::ReportEMETelemetry()
|
||||
{
|
||||
// Report telemetry for EME videos when a page is unloaded.
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (mIsEncrypted && Preferences::GetBool("media.eme.enabled")) {
|
||||
Telemetry::Accumulate(Telemetry::VIDEO_EME_PLAY_SUCCESS, mLoadedDataFired);
|
||||
LOG(PR_LOG_DEBUG, ("%p VIDEO_EME_PLAY_SUCCESS = %s",
|
||||
this, mLoadedDataFired ? "true" : "false"));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
HTMLMediaElement::ReportMSETelemetry()
|
||||
{
|
||||
@@ -2845,12 +2801,6 @@ nsresult HTMLMediaElement::FinishDecoderSetup(MediaDecoder* aDecoder,
|
||||
return rv;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (mMediaKeys) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Decoder successfully created, the decoder now owns the MediaResource
|
||||
// which owns the channel.
|
||||
mChannel = nullptr;
|
||||
@@ -3909,25 +3859,8 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
|
||||
if (aPauseElement) {
|
||||
if (mMediaSource) {
|
||||
ReportMSETelemetry();
|
||||
#ifdef MOZ_EME
|
||||
ReportEMETelemetry();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// For EME content, force destruction of the CDM client (and CDM
|
||||
// instance if this is the last client for that CDM instance) and
|
||||
// the CDM's decoder. This ensures the CDM gets reliable and prompt
|
||||
// shutdown notifications, as it may have book-keeping it needs
|
||||
// to do on shutdown.
|
||||
if (mMediaKeys) {
|
||||
mMediaKeys->Shutdown();
|
||||
mMediaKeys = nullptr;
|
||||
if (mDecoder) {
|
||||
ShutdownDecoder();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (mDecoder) {
|
||||
mDecoder->Pause();
|
||||
mDecoder->Suspend();
|
||||
@@ -3936,9 +3869,6 @@ void HTMLMediaElement::SuspendOrResumeElement(bool aPauseElement, bool aSuspendE
|
||||
}
|
||||
mEventDeliveryPaused = aSuspendEvents;
|
||||
} else {
|
||||
#ifdef MOZ_EME
|
||||
MOZ_ASSERT(!mMediaKeys);
|
||||
#endif
|
||||
if (mDecoder) {
|
||||
mDecoder->Resume(false);
|
||||
if (!mPaused && !mDecoder->IsEndedOrShutdown()) {
|
||||
@@ -4496,137 +4426,6 @@ NS_IMETHODIMP HTMLMediaElement::CanPlayChanged(int32_t canPlay)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
MediaKeys*
|
||||
HTMLMediaElement::GetMediaKeys() const
|
||||
{
|
||||
return mMediaKeys;
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::ContainsRestrictedContent()
|
||||
{
|
||||
return GetMediaKeys() != nullptr;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
HTMLMediaElement::SetMediaKeys(mozilla::dom::MediaKeys* aMediaKeys,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (MozAudioCaptured()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global =
|
||||
do_QueryInterface(OwnerDoc()->GetInnerWindow());
|
||||
if (!global) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mMediaKeys == aMediaKeys) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
if (aMediaKeys && aMediaKeys->IsBoundToMediaElement()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
if (mMediaKeys) {
|
||||
// Existing MediaKeys object. Shut it down.
|
||||
mMediaKeys->Shutdown();
|
||||
mMediaKeys = nullptr;
|
||||
}
|
||||
if (mDecoder &&
|
||||
!mMediaSource &&
|
||||
Preferences::GetBool("media.eme.mse-only", true)) {
|
||||
ShutdownDecoder();
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
mMediaKeys = aMediaKeys;
|
||||
if (mMediaKeys) {
|
||||
if (NS_FAILED(mMediaKeys->Bind(this))) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
mMediaKeys = nullptr;
|
||||
return promise.forget();
|
||||
}
|
||||
if (mDecoder) {
|
||||
mDecoder->SetCDMProxy(mMediaKeys->GetCDMProxy());
|
||||
}
|
||||
}
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
EventHandlerNonNull*
|
||||
HTMLMediaElement::GetOnencrypted()
|
||||
{
|
||||
EventListenerManager *elm = GetExistingListenerManager();
|
||||
return elm ? elm->GetEventHandler(nsGkAtoms::onencrypted, EmptyString())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::SetOnencrypted(EventHandlerNonNull* handler)
|
||||
{
|
||||
EventListenerManager *elm = GetOrCreateListenerManager();
|
||||
if (elm) {
|
||||
elm->SetEventHandler(nsGkAtoms::onencrypted, EmptyString(), handler);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLMediaElement::DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType)
|
||||
{
|
||||
nsRefPtr<MediaEncryptedEvent> event;
|
||||
if (IsCORSSameOrigin()) {
|
||||
event = MediaEncryptedEvent::Constructor(this, aInitDataType, aInitData);
|
||||
} else {
|
||||
event = MediaEncryptedEvent::Constructor(this);
|
||||
}
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLMediaElement::IsEventAttributeName(nsIAtom* aName)
|
||||
{
|
||||
return aName == nsGkAtoms::onencrypted ||
|
||||
nsGenericHTMLElement::IsEventAttributeName(aName);
|
||||
}
|
||||
|
||||
already_AddRefed<nsIPrincipal>
|
||||
HTMLMediaElement::GetTopLevelPrincipal()
|
||||
{
|
||||
nsRefPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(OwnerDoc()->GetParentObject());
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
window->GetTop(getter_AddRefs(topWindow));
|
||||
nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
|
||||
if (!top) {
|
||||
return nullptr;
|
||||
}
|
||||
nsIDocument* doc = top->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
principal = doc->NodePrincipal();
|
||||
return principal.forget();
|
||||
}
|
||||
#endif // MOZ_EME
|
||||
|
||||
NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged()
|
||||
{
|
||||
SetVolumeInternal();
|
||||
|
||||
@@ -20,9 +20,6 @@
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/TextTrackManager.h"
|
||||
#include "MediaDecoder.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#endif
|
||||
#include "nsGkAtoms.h"
|
||||
|
||||
// X.h on Linux #defines CurrentTime as 0L, so we have to #undef it here.
|
||||
@@ -552,28 +549,6 @@ public:
|
||||
|
||||
// XPCOM MozPreservesPitch() is OK
|
||||
|
||||
#ifdef MOZ_EME
|
||||
MediaKeys* GetMediaKeys() const;
|
||||
|
||||
already_AddRefed<Promise> SetMediaKeys(MediaKeys* mediaKeys,
|
||||
ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::EventHandlerNonNull* GetOnencrypted();
|
||||
void SetOnencrypted(mozilla::dom::EventHandlerNonNull* listener);
|
||||
|
||||
void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) override;
|
||||
|
||||
|
||||
bool IsEventAttributeName(nsIAtom* aName) override;
|
||||
|
||||
// Returns the principal of the "top level" document; the origin displayed
|
||||
// in the URL bar of the browser window.
|
||||
already_AddRefed<nsIPrincipal> GetTopLevelPrincipal();
|
||||
|
||||
bool ContainsRestrictedContent();
|
||||
#endif // MOZ_EME
|
||||
|
||||
bool MozAutoplayEnabled() const
|
||||
{
|
||||
return mAutoplayEnabled;
|
||||
@@ -982,9 +957,6 @@ protected:
|
||||
return isPaused;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
void ReportEMETelemetry();
|
||||
#endif
|
||||
void ReportMSETelemetry();
|
||||
|
||||
// Check the permissions for audiochannel.
|
||||
@@ -1190,11 +1162,6 @@ protected:
|
||||
// Timer used for updating progress events
|
||||
nsCOMPtr<nsITimer> mProgressTimer;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Encrypted Media Extension media keys.
|
||||
nsRefPtr<MediaKeys> mMediaKeys;
|
||||
#endif
|
||||
|
||||
// Stores the time at the start of the current 'played' range.
|
||||
double mCurrentPlayRangeStart;
|
||||
|
||||
|
||||
@@ -25,9 +25,6 @@ class ReentrantMonitor;
|
||||
class VideoFrameContainer;
|
||||
class TimedMetadata;
|
||||
class MediaDecoderOwner;
|
||||
#ifdef MOZ_EME
|
||||
class CDMProxy;
|
||||
#endif
|
||||
|
||||
typedef nsDataHashtable<nsCStringHashKey, nsCString> MetadataTags;
|
||||
|
||||
@@ -159,10 +156,6 @@ public:
|
||||
AbstractMediaDecoder* mDecoder;
|
||||
};
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) { return NS_ERROR_NOT_IMPLEMENTED; }
|
||||
virtual CDMProxy* GetCDMProxy() { return nullptr; }
|
||||
#endif
|
||||
};
|
||||
|
||||
class MetadataContainer
|
||||
|
||||
@@ -1776,27 +1776,6 @@ bool MediaDecoder::CanPlayThrough()
|
||||
return stats.mDownloadPosition > stats.mPlaybackPosition + readAheadMargin;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mProxy = aProxy;
|
||||
// Awaken any readers waiting for the proxy.
|
||||
NotifyWaitingForResourcesStatusChanged();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CDMProxy*
|
||||
MediaDecoder::GetCDMProxy()
|
||||
{
|
||||
GetReentrantMonitor().AssertCurrentThreadIn();
|
||||
MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
|
||||
return mProxy;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_RAW
|
||||
bool
|
||||
MediaDecoder::IsRawEnabled()
|
||||
|
||||
@@ -196,9 +196,6 @@ destroying the MediaDecoder object.
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AbstractMediaDecoder.h"
|
||||
#include "necko-config.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
|
||||
class nsIStreamListener;
|
||||
class nsIPrincipal;
|
||||
@@ -853,14 +850,6 @@ public:
|
||||
// The decoder monitor must be held.
|
||||
bool IsLogicallyPlaying();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// This takes the decoder monitor.
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
|
||||
// Decoder monitor must be held.
|
||||
virtual CDMProxy* GetCDMProxy() override;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_RAW
|
||||
static bool IsRawEnabled();
|
||||
#endif
|
||||
@@ -1117,10 +1106,6 @@ private:
|
||||
// change. Explicitly private for force access via GetReentrantMonitor.
|
||||
ReentrantMonitor mReentrantMonitor;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// Data about MediaStreams that are being fed by this decoder.
|
||||
nsTArray<OutputStreamData> mOutputStreams;
|
||||
|
||||
@@ -133,14 +133,6 @@ public:
|
||||
// Called by the media decoder object, on the main thread,
|
||||
// when the connection between Rtsp server and client gets lost.
|
||||
virtual void ResetConnectionState() = 0;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Dispatches a "encrypted" event to the HTMLMediaElement, with the
|
||||
// provided init data.
|
||||
// Main thread only.
|
||||
virtual void DispatchEncrypted(const nsTArray<uint8_t>& aInitData,
|
||||
const nsAString& aInitDataType) = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,319 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/CDMCallbackProxy.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "mozilla/dom/MediaKeySession.h"
|
||||
#include "mozIGoannaMediaPluginService.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
CDMCallbackProxy::CDMCallbackProxy(CDMProxy* aProxy)
|
||||
: mProxy(aProxy)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
class SetSessionIdTask : public nsRunnable {
|
||||
public:
|
||||
SetSessionIdTask(CDMProxy* aProxy,
|
||||
uint32_t aToken,
|
||||
const nsCString& aSessionId)
|
||||
: mProxy(aProxy)
|
||||
, mToken(aToken)
|
||||
, mSid(NS_ConvertUTF8toUTF16(aSessionId))
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnSetSessionId(mToken, mSid);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
uint32_t mToken;
|
||||
nsString mSid;
|
||||
};
|
||||
|
||||
void
|
||||
CDMCallbackProxy::SetSessionId(uint32_t aToken,
|
||||
const nsCString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task(new SetSessionIdTask(mProxy,
|
||||
aToken,
|
||||
aSessionId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
class LoadSessionTask : public nsRunnable {
|
||||
public:
|
||||
LoadSessionTask(CDMProxy* aProxy,
|
||||
uint32_t aPromiseId,
|
||||
bool aSuccess)
|
||||
: mProxy(aProxy)
|
||||
, mPid(aPromiseId)
|
||||
, mSuccess(aSuccess)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnResolveLoadSessionPromise(mPid, mSuccess);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
dom::PromiseId mPid;
|
||||
bool mSuccess;
|
||||
};
|
||||
|
||||
void
|
||||
CDMCallbackProxy::ResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task(new LoadSessionTask(mProxy,
|
||||
aPromiseId,
|
||||
aSuccess));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::ResolvePromise(uint32_t aPromiseId)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
// Note: CDMProxy proxies this from non-main threads to main thread.
|
||||
mProxy->ResolvePromise(aPromiseId);
|
||||
}
|
||||
|
||||
class RejectPromiseTask : public nsRunnable {
|
||||
public:
|
||||
RejectPromiseTask(CDMProxy* aProxy,
|
||||
uint32_t aPromiseId,
|
||||
nsresult aException,
|
||||
const nsCString& aMessage)
|
||||
: mProxy(aProxy)
|
||||
, mPid(aPromiseId)
|
||||
, mException(aException)
|
||||
, mMsg(NS_ConvertUTF8toUTF16(aMessage))
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnRejectPromise(mPid, mException, mMsg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
dom::PromiseId mPid;
|
||||
nsresult mException;
|
||||
nsString mMsg;
|
||||
};
|
||||
|
||||
|
||||
void
|
||||
CDMCallbackProxy::RejectPromise(uint32_t aPromiseId,
|
||||
nsresult aException,
|
||||
const nsCString& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = new RejectPromiseTask(mProxy,
|
||||
aPromiseId,
|
||||
aException,
|
||||
aMessage);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
class SessionMessageTask : public nsRunnable {
|
||||
public:
|
||||
SessionMessageTask(CDMProxy* aProxy,
|
||||
const nsCString& aSessionId,
|
||||
GMPSessionMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
: mProxy(aProxy)
|
||||
, mSid(NS_ConvertUTF8toUTF16(aSessionId))
|
||||
, mMsgType(aMessageType)
|
||||
{
|
||||
mMsg.AppendElements(aMessage);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnSessionMessage(mSid, mMsgType, mMsg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
dom::PromiseId mPid;
|
||||
nsString mSid;
|
||||
GMPSessionMessageType mMsgType;
|
||||
nsTArray<uint8_t> mMsg;
|
||||
};
|
||||
|
||||
void
|
||||
CDMCallbackProxy::SessionMessage(const nsCString& aSessionId,
|
||||
GMPSessionMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = new SessionMessageTask(mProxy,
|
||||
aSessionId,
|
||||
aMessageType,
|
||||
aMessage);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
class ExpirationChangeTask : public nsRunnable {
|
||||
public:
|
||||
ExpirationChangeTask(CDMProxy* aProxy,
|
||||
const nsCString& aSessionId,
|
||||
GMPTimestamp aExpiryTime)
|
||||
: mProxy(aProxy)
|
||||
, mSid(NS_ConvertUTF8toUTF16(aSessionId))
|
||||
, mTimestamp(aExpiryTime)
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnExpirationChange(mSid, mTimestamp);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
nsString mSid;
|
||||
GMPTimestamp mTimestamp;
|
||||
};
|
||||
|
||||
void
|
||||
CDMCallbackProxy::ExpirationChange(const nsCString& aSessionId,
|
||||
GMPTimestamp aExpiryTime)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = new ExpirationChangeTask(mProxy,
|
||||
aSessionId,
|
||||
aExpiryTime);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::SessionClosed(const nsCString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
|
||||
&CDMProxy::OnSessionClosed,
|
||||
NS_ConvertUTF8toUTF16(aSessionId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
class SessionErrorTask : public nsRunnable {
|
||||
public:
|
||||
SessionErrorTask(CDMProxy* aProxy,
|
||||
const nsCString& aSessionId,
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage)
|
||||
: mProxy(aProxy)
|
||||
, mSid(NS_ConvertUTF8toUTF16(aSessionId))
|
||||
, mException(aException)
|
||||
, mSystemCode(aSystemCode)
|
||||
, mMsg(NS_ConvertUTF8toUTF16(aMessage))
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
mProxy->OnSessionError(mSid, mException, mSystemCode, mMsg);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
dom::PromiseId mPid;
|
||||
nsString mSid;
|
||||
nsresult mException;
|
||||
uint32_t mSystemCode;
|
||||
nsString mMsg;
|
||||
};
|
||||
|
||||
void
|
||||
CDMCallbackProxy::SessionError(const nsCString& aSessionId,
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = new SessionErrorTask(mProxy,
|
||||
aSessionId,
|
||||
aException,
|
||||
aSystemCode,
|
||||
aMessage);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
bool keyStatusesChange = false;
|
||||
{
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
keyStatusesChange = caps.SetKeyStatus(aKeyId,
|
||||
NS_ConvertUTF8toUTF16(aSessionId),
|
||||
aStatus);
|
||||
}
|
||||
if (keyStatusesChange) {
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
|
||||
&CDMProxy::OnKeyStatusesChange,
|
||||
NS_ConvertUTF8toUTF16(aSessionId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::SetCaps(uint64_t aCaps)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
caps.SetCaps(aCaps);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::Decrypted(uint32_t aId,
|
||||
GMPErr aResult,
|
||||
const nsTArray<uint8_t>& aDecryptedData)
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
|
||||
mProxy->gmp_Decrypted(aId, aResult, aDecryptedData);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCallbackProxy::Terminated()
|
||||
{
|
||||
MOZ_ASSERT(mProxy->IsOnGMPThread());
|
||||
nsRefPtr<nsIRunnable> task = NS_NewRunnableMethod(mProxy, &CDMProxy::Terminated);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,70 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 CDMCallbackProxy_h_
|
||||
#define CDMCallbackProxy_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 CDMCallbackProxy : public GMPDecryptorProxyCallback {
|
||||
public:
|
||||
virtual void SetSessionId(uint32_t aCreateSessionToken,
|
||||
const nsCString& aSessionId) override;
|
||||
|
||||
virtual void ResolveLoadSessionPromise(uint32_t aPromiseId,
|
||||
bool aSuccess) override;
|
||||
|
||||
virtual void ResolvePromise(uint32_t aPromiseId) override;
|
||||
|
||||
virtual void RejectPromise(uint32_t aPromiseId,
|
||||
nsresult aException,
|
||||
const nsCString& aSessionId) override;
|
||||
|
||||
virtual void SessionMessage(const nsCString& aSessionId,
|
||||
GMPSessionMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage) override;
|
||||
|
||||
virtual void ExpirationChange(const nsCString& aSessionId,
|
||||
GMPTimestamp aExpiryTime) override;
|
||||
|
||||
virtual void SessionClosed(const nsCString& aSessionId) override;
|
||||
|
||||
virtual void SessionError(const nsCString& aSessionId,
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsCString& aMessage) override;
|
||||
|
||||
virtual void KeyStatusChanged(const nsCString& aSessionId,
|
||||
const nsTArray<uint8_t>& aKeyId,
|
||||
GMPMediaKeyStatus aStatus) override;
|
||||
|
||||
virtual void SetCaps(uint64_t aCaps) override;
|
||||
|
||||
virtual void Decrypted(uint32_t aId,
|
||||
GMPErr aResult,
|
||||
const nsTArray<uint8_t>& aDecryptedData) override;
|
||||
|
||||
virtual void Terminated() override;
|
||||
|
||||
~CDMCallbackProxy() {}
|
||||
|
||||
private:
|
||||
friend class CDMProxy;
|
||||
explicit CDMCallbackProxy(CDMProxy* aProxy);
|
||||
|
||||
// Warning: Weak ref.
|
||||
CDMProxy* mProxy;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CDMCallbackProxy_h_
|
||||
@@ -1,236 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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")
|
||||
, mCaps(0)
|
||||
{
|
||||
}
|
||||
|
||||
CDMCaps::~CDMCaps()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::Lock()
|
||||
{
|
||||
mMonitor.Lock();
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::Unlock()
|
||||
{
|
||||
mMonitor.Unlock();
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::HasCap(uint64_t aCap)
|
||||
{
|
||||
mMonitor.AssertCurrentThreadOwns();
|
||||
return (mCaps & aCap) == aCap;
|
||||
}
|
||||
|
||||
CDMCaps::AutoLock::AutoLock(CDMCaps& aInstance)
|
||||
: mData(aInstance)
|
||||
{
|
||||
mData.Lock();
|
||||
}
|
||||
|
||||
CDMCaps::AutoLock::~AutoLock()
|
||||
{
|
||||
mData.Unlock();
|
||||
}
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
static void
|
||||
TestCap(uint64_t aFlag,
|
||||
uint64_t aCaps,
|
||||
const nsACString& aCapName,
|
||||
nsACString& aCapStr)
|
||||
{
|
||||
if (!(aFlag & aCaps)) {
|
||||
return;
|
||||
}
|
||||
if (!aCapStr.IsEmpty()) {
|
||||
aCapStr.AppendLiteral(",");
|
||||
}
|
||||
aCapStr.Append(aCapName);
|
||||
}
|
||||
|
||||
nsCString
|
||||
CapsToString(uint64_t aCaps)
|
||||
{
|
||||
nsCString capsStr;
|
||||
TestCap(GMP_EME_CAP_DECRYPT_AUDIO, aCaps, NS_LITERAL_CSTRING("DecryptAudio"), capsStr);
|
||||
TestCap(GMP_EME_CAP_DECRYPT_VIDEO, aCaps, NS_LITERAL_CSTRING("DecryptVideo"), capsStr);
|
||||
TestCap(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO, aCaps, NS_LITERAL_CSTRING("DecryptAndDecodeAudio"), capsStr);
|
||||
TestCap(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO, aCaps, NS_LITERAL_CSTRING("DecryptAndDecodeVideo"), capsStr);
|
||||
return capsStr;
|
||||
}
|
||||
#endif // PR_LOGGING
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::SetCaps(uint64_t aCaps)
|
||||
{
|
||||
EME_LOG("SetCaps() %s", CapsToString(aCaps).get());
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
mData.mCaps = aCaps;
|
||||
for (size_t i = 0; i < mData.mWaitForCaps.Length(); i++) {
|
||||
NS_DispatchToMainThread(mData.mWaitForCaps[i], NS_DISPATCH_NORMAL);
|
||||
}
|
||||
mData.mWaitForCaps.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
if (mData.mCaps) {
|
||||
NS_DispatchToMainThread(aContinuation, NS_DISPATCH_NORMAL);
|
||||
MOZ_ASSERT(mData.mWaitForCaps.IsEmpty());
|
||||
} else {
|
||||
mData.mWaitForCaps.AppendElement(aContinuation);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
const auto& keys = mData.mKeyStatuses;
|
||||
for (size_t i = 0; i < keys.Length(); i++) {
|
||||
if (keys[i].mId != aKeyId) {
|
||||
continue;
|
||||
}
|
||||
if (keys[i].mStatus == kGMPUsable ||
|
||||
keys[i].mStatus == kGMPOutputDownscaled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
|
||||
const nsString& aSessionId,
|
||||
GMPMediaKeyStatus aStatus)
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
KeyStatus key(aKeyId, aSessionId, aStatus);
|
||||
auto index = mData.mKeyStatuses.IndexOf(key);
|
||||
|
||||
if (aStatus == kGMPUnknown) {
|
||||
// Return true if the element is found to notify key changes.
|
||||
return mData.mKeyStatuses.RemoveElement(key);
|
||||
}
|
||||
|
||||
if (index != mData.mKeyStatuses.NoIndex) {
|
||||
if (mData.mKeyStatuses[index].mStatus == aStatus) {
|
||||
return false;
|
||||
}
|
||||
auto oldStatus = mData.mKeyStatuses[index].mStatus;
|
||||
mData.mKeyStatuses[index].mStatus = aStatus;
|
||||
if (oldStatus == kGMPUsable || oldStatus == kGMPOutputDownscaled) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
mData.mKeyStatuses.AppendElement(key);
|
||||
}
|
||||
|
||||
// Both kGMPUsable and kGMPOutputDownscaled are treated able to decrypt.
|
||||
// We don't need to notify when transition happens between kGMPUsable and
|
||||
// kGMPOutputDownscaled. Only call NotifyUsable() when we are going from
|
||||
// ![kGMPUsable|kGMPOutputDownscaled] to [kGMPUsable|kGMPOutputDownscaled]
|
||||
if (aStatus != kGMPUsable && aStatus != kGMPOutputDownscaled) {
|
||||
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));
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::AreCapsKnown()
|
||||
{
|
||||
mData.mMonitor.AssertCurrentThreadOwns();
|
||||
return mData.mCaps != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::CanDecryptAndDecodeAudio()
|
||||
{
|
||||
return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_AUDIO);
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::CanDecryptAndDecodeVideo()
|
||||
{
|
||||
return mData.HasCap(GMP_EME_CAP_DECRYPT_AND_DECODE_VIDEO);
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::CanDecryptAudio()
|
||||
{
|
||||
return mData.HasCap(GMP_EME_CAP_DECRYPT_AUDIO);
|
||||
}
|
||||
|
||||
bool
|
||||
CDMCaps::AutoLock::CanDecryptVideo()
|
||||
{
|
||||
return mData.HasCap(GMP_EME_CAP_DECRYPT_VIDEO);
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
nsTArray<KeyStatus>& aOutKeyStatuses)
|
||||
{
|
||||
for (size_t i = 0; i < mData.mKeyStatuses.Length(); i++) {
|
||||
const auto& key = mData.mKeyStatuses[i];
|
||||
if (key.mSessionId.Equals(aSessionId)) {
|
||||
aOutKeyStatuses.AppendElement(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMCaps::AutoLock::GetSessionIdsForKeyId(const CencKeyId& aKeyId,
|
||||
nsTArray<nsCString>& aOutSessionIds)
|
||||
{
|
||||
for (const auto& keyStatus : mData.mKeyStatuses) {
|
||||
if (keyStatus.mId == aKeyId) {
|
||||
aOutSessionIds.AppendElement(NS_ConvertUTF16toUTF8(keyStatus.mSessionId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,125 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "SamplesWaitingForKey.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// CDM capabilities; what keys a CDMProxy can use, and whether it can decrypt, or
|
||||
// decrypt-and-decode on a per stream basis. Must be locked to access state.
|
||||
class CDMCaps {
|
||||
public:
|
||||
CDMCaps();
|
||||
~CDMCaps();
|
||||
|
||||
struct KeyStatus {
|
||||
KeyStatus(const CencKeyId& aId,
|
||||
const nsString& aSessionId,
|
||||
GMPMediaKeyStatus 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;
|
||||
GMPMediaKeyStatus 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();
|
||||
|
||||
// Returns true if the capabilities of the CDM are known, i.e. they have
|
||||
// been reported by the CDM to Goanna.
|
||||
bool AreCapsKnown();
|
||||
|
||||
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, GMPMediaKeyStatus aStatus);
|
||||
|
||||
void GetKeyStatusesForSession(const nsAString& aSessionId,
|
||||
nsTArray<KeyStatus>& aOutKeyStatuses);
|
||||
|
||||
void GetSessionIdsForKeyId(const CencKeyId& aKeyId,
|
||||
nsTArray<nsCString>& aOutSessionIds);
|
||||
|
||||
// Sets the capabilities of the CDM. aCaps is the logical OR of the
|
||||
// GMP_EME_CAP_* flags from gmp-decryption.h.
|
||||
void SetCaps(uint64_t aCaps);
|
||||
|
||||
bool CanDecryptAndDecodeAudio();
|
||||
bool CanDecryptAndDecodeVideo();
|
||||
|
||||
bool CanDecryptAudio();
|
||||
bool CanDecryptVideo();
|
||||
|
||||
void CallOnMainThreadWhenCapsAvailable(nsIRunnable* aContinuation);
|
||||
|
||||
// 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();
|
||||
bool HasCap(uint64_t);
|
||||
|
||||
struct WaitForKeys {
|
||||
WaitForKeys(const CencKeyId& aKeyId,
|
||||
SamplesWaitingForKey* aListener)
|
||||
: mKeyId(aKeyId)
|
||||
, mListener(aListener)
|
||||
{}
|
||||
CencKeyId mKeyId;
|
||||
nsRefPtr<SamplesWaitingForKey> mListener;
|
||||
};
|
||||
|
||||
Monitor mMonitor;
|
||||
|
||||
nsTArray<KeyStatus> mKeyStatuses;
|
||||
|
||||
nsTArray<WaitForKeys> mWaitForKeys;
|
||||
|
||||
nsTArray<nsRefPtr<nsIRunnable>> mWaitForCaps;
|
||||
uint64_t mCaps;
|
||||
|
||||
// It is not safe to copy this object.
|
||||
CDMCaps(const CDMCaps&) = delete;
|
||||
CDMCaps& operator=(const CDMCaps&) = delete;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,615 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/CDMProxy.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "mozilla/dom/MediaKeySession.h"
|
||||
#include "mozIGoannaMediaPluginService.h"
|
||||
#include "nsContentCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "prenv.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/CDMCallbackProxy.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
CDMProxy::CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem)
|
||||
: mKeys(aKeys)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mCDM(nullptr)
|
||||
, mDecryptionJobCount(0)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(CDMProxy);
|
||||
}
|
||||
|
||||
CDMProxy::~CDMProxy()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CDMProxy);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::Init(PromiseId aPromiseId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPrivateBrowsing)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
|
||||
|
||||
EME_LOG("CDMProxy::Init (%s, %s) %s",
|
||||
NS_ConvertUTF16toUTF8(aOrigin).get(),
|
||||
NS_ConvertUTF16toUTF8(aTopLevelOrigin).get(),
|
||||
(aInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"));
|
||||
|
||||
if (!mGMPThread) {
|
||||
nsCOMPtr<mozIGoannaMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/goanna-media-plugin-service;1");
|
||||
if (!mps) {
|
||||
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mps->GetThread(getter_AddRefs(mGMPThread));
|
||||
if (!mGMPThread) {
|
||||
RejectPromise(aPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
nsAutoPtr<InitData> data(new InitData());
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mOrigin = aOrigin;
|
||||
data->mTopLevelOrigin = aTopLevelOrigin;
|
||||
data->mInPrivateBrowsing = aInPrivateBrowsing;
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<InitData>>(this,
|
||||
&CDMProxy::gmp_Init,
|
||||
data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
CDMProxy::IsOnGMPThread()
|
||||
{
|
||||
return NS_GetCurrentThread() == mGMPThread;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Init(nsAutoPtr<InitData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
nsCOMPtr<mozIGoannaMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/goanna-media-plugin-service;1");
|
||||
if (!mps) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsCString version;
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(mKeySystem));
|
||||
|
||||
nsresult rv = mps->GetNodeId(aData->mOrigin,
|
||||
aData->mTopLevelOrigin,
|
||||
aData->mInPrivateBrowsing,
|
||||
mNodeId);
|
||||
|
||||
MOZ_ASSERT(!GetNodeId().IsEmpty());
|
||||
if (NS_FAILED(rv)) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
EME_LOG("CDMProxy::gmp_Init (%s, %s) %s NodeId=%s",
|
||||
NS_ConvertUTF16toUTF8(aData->mOrigin).get(),
|
||||
NS_ConvertUTF16toUTF8(aData->mTopLevelOrigin).get(),
|
||||
(aData->mInPrivateBrowsing ? "PrivateBrowsing" : "NonPrivateBrowsing"),
|
||||
GetNodeId().get());
|
||||
|
||||
rv = mps->GetGMPDecryptor(&tags, GetNodeId(), &mCDM);
|
||||
if (NS_FAILED(rv) || !mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
} else {
|
||||
mCallback = new CDMCallbackProxy(this);
|
||||
mCDM->Init(mCallback);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<uint32_t>(this,
|
||||
&CDMProxy::OnCDMCreated,
|
||||
aData->mPromiseId));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::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);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::CreateSession(uint32_t aCreateSessionToken,
|
||||
dom::SessionType aSessionType,
|
||||
PromiseId aPromiseId,
|
||||
const nsAString& aInitDataType,
|
||||
nsTArray<uint8_t>& aInitData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
|
||||
nsAutoPtr<CreateSessionData> data(new CreateSessionData());
|
||||
data->mSessionType = aSessionType;
|
||||
data->mCreateSessionToken = aCreateSessionToken;
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mInitDataType = NS_ConvertUTF16toUTF8(aInitDataType);
|
||||
data->mInitData = Move(aInitData);
|
||||
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<CreateSessionData>>(this, &CDMProxy::gmp_CreateSession, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
GMPSessionType
|
||||
ToGMPSessionType(dom::SessionType aSessionType) {
|
||||
switch (aSessionType) {
|
||||
case dom::SessionType::Temporary: return kGMPTemporySession;
|
||||
case dom::SessionType::Persistent: return kGMPPersistentSession;
|
||||
default: return kGMPTemporySession;
|
||||
};
|
||||
};
|
||||
|
||||
void
|
||||
CDMProxy::gmp_CreateSession(nsAutoPtr<CreateSessionData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->CreateSession(aData->mCreateSessionToken,
|
||||
aData->mPromiseId,
|
||||
aData->mInitDataType,
|
||||
aData->mInitData,
|
||||
ToGMPSessionType(aData->mSessionType));
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::LoadSession(PromiseId aPromiseId,
|
||||
const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
|
||||
nsAutoPtr<SessionOpData> data(new SessionOpData());
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_LoadSession, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_LoadSession(nsAutoPtr<SessionOpData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->LoadSession(aData->mPromiseId, aData->mSessionId);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::SetServerCertificate(PromiseId aPromiseId,
|
||||
nsTArray<uint8_t>& aCert)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
|
||||
nsAutoPtr<SetServerCertificateData> data;
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mCert = Move(aCert);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<SetServerCertificateData>>(this, &CDMProxy::gmp_SetServerCertificate, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_SetServerCertificate(nsAutoPtr<SetServerCertificateData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->SetServerCertificate(aData->mPromiseId, aData->mCert);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::UpdateSession(const nsAString& aSessionId,
|
||||
PromiseId aPromiseId,
|
||||
nsTArray<uint8_t>& aResponse)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mGMPThread);
|
||||
NS_ENSURE_TRUE_VOID(!mKeys.IsNull());
|
||||
|
||||
nsAutoPtr<UpdateSessionData> data(new UpdateSessionData());
|
||||
data->mPromiseId = aPromiseId;
|
||||
data->mSessionId = NS_ConvertUTF16toUTF8(aSessionId);
|
||||
data->mResponse = Move(aResponse);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<UpdateSessionData>>(this, &CDMProxy::gmp_UpdateSession, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_UpdateSession(nsAutoPtr<UpdateSessionData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->UpdateSession(aData->mPromiseId,
|
||||
aData->mSessionId,
|
||||
aData->mResponse);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::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);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_CloseSession, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_CloseSession(nsAutoPtr<SessionOpData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->CloseSession(aData->mPromiseId, aData->mSessionId);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::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);
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<SessionOpData>>(this, &CDMProxy::gmp_RemoveSession, data));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_RemoveSession(nsAutoPtr<SessionOpData> aData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
if (!mCDM) {
|
||||
RejectPromise(aData->mPromiseId, NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
mCDM->RemoveSession(aData->mPromiseId, aData->mSessionId);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mKeys.Clear();
|
||||
// Note: This may end up being the last owning reference to the CDMProxy.
|
||||
nsRefPtr<nsIRunnable> task(NS_NewRunnableMethod(this, &CDMProxy::gmp_Shutdown));
|
||||
if (mGMPThread) {
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Shutdown()
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
|
||||
// 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->mClient->Decrypted(GMPAbortedErr, nullptr);
|
||||
}
|
||||
mDecryptionJobs.Clear();
|
||||
|
||||
if (mCDM) {
|
||||
mCDM->Close();
|
||||
mCDM = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::RejectPromise(PromiseId aId, nsresult aCode)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
if (!mKeys.IsNull()) {
|
||||
mKeys->RejectPromise(aId, aCode);
|
||||
}
|
||||
} else {
|
||||
nsRefPtr<nsIRunnable> task(new RejectPromiseTask(this, aId, aCode));
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::ResolvePromise(PromiseId aId)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
if (!mKeys.IsNull()) {
|
||||
mKeys->ResolvePromise(aId);
|
||||
} else {
|
||||
NS_WARNING("CDMProxy unable to resolve promise!");
|
||||
}
|
||||
} else {
|
||||
nsRefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<PromiseId>(this,
|
||||
&CDMProxy::ResolvePromise,
|
||||
aId);
|
||||
NS_DispatchToMainThread(task);
|
||||
}
|
||||
}
|
||||
|
||||
const nsCString&
|
||||
CDMProxy::GetNodeId() const
|
||||
{
|
||||
return mNodeId;
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnSetSessionId(uint32_t aCreateSessionToken,
|
||||
const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetPendingSession(aCreateSessionToken));
|
||||
if (session) {
|
||||
session->SetSessionId(aSessionId);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
mKeys->OnSessionLoaded(aPromiseId, aSuccess);
|
||||
}
|
||||
|
||||
static dom::MediaKeyMessageType
|
||||
ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
|
||||
switch (aMessageType) {
|
||||
case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
|
||||
case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
|
||||
case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
|
||||
case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
|
||||
default: return dom::MediaKeyMessageType::License_request;
|
||||
};
|
||||
};
|
||||
|
||||
void
|
||||
CDMProxy::OnSessionMessage(const nsAString& aSessionId,
|
||||
GMPSessionMessageType aMessageType,
|
||||
nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
|
||||
if (session) {
|
||||
session->DispatchKeyMessage(ToMediaKeyMessageType(aMessageType), aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnKeyStatusesChange(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
|
||||
if (session) {
|
||||
session->DispatchKeyStatusesChange();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnExpirationChange(const nsAString& aSessionId,
|
||||
GMPTimestamp aExpiryTime)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_WARNING("CDMProxy::OnExpirationChange() not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnSessionClosed(const nsAString& aSessionId)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
|
||||
if (session) {
|
||||
session->OnClosed();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
CDMProxy::OnSessionError(const nsAString& aSessionId,
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsAString& aMsg)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (mKeys.IsNull()) {
|
||||
return;
|
||||
}
|
||||
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
|
||||
if (session) {
|
||||
session->DispatchKeyError(aSystemCode);
|
||||
}
|
||||
LogToConsole(aMsg);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::OnRejectPromise(uint32_t aPromiseId,
|
||||
nsresult aDOMException,
|
||||
const nsAString& aMsg)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RejectPromise(aPromiseId, aDOMException);
|
||||
LogToConsole(aMsg);
|
||||
}
|
||||
|
||||
const nsString&
|
||||
CDMProxy::KeySystem() const
|
||||
{
|
||||
return mKeySystem;
|
||||
}
|
||||
|
||||
CDMCaps&
|
||||
CDMProxy::Capabilites() {
|
||||
return mCapabilites;
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::Decrypt(mp4_demuxer::MP4Sample* aSample,
|
||||
DecryptionClient* aClient)
|
||||
{
|
||||
nsAutoPtr<DecryptJob> job(new DecryptJob(aSample, aClient));
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethodWithArg<nsAutoPtr<DecryptJob>>(this, &CDMProxy::gmp_Decrypt, job));
|
||||
mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Decrypt(nsAutoPtr<DecryptJob> aJob)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
MOZ_ASSERT(aJob->mClient);
|
||||
MOZ_ASSERT(aJob->mSample);
|
||||
|
||||
if (!mCDM) {
|
||||
aJob->mClient->Decrypted(GMPAbortedErr, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
aJob->mId = ++mDecryptionJobCount;
|
||||
nsTArray<uint8_t> data;
|
||||
data.AppendElements(aJob->mSample->data, aJob->mSample->size);
|
||||
mCDM->Decrypt(aJob->mId, aJob->mSample->crypto, data);
|
||||
mDecryptionJobs.AppendElement(aJob.forget());
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::gmp_Decrypted(uint32_t aId,
|
||||
GMPErr aResult,
|
||||
const nsTArray<uint8_t>& aDecryptedData)
|
||||
{
|
||||
MOZ_ASSERT(IsOnGMPThread());
|
||||
for (size_t i = 0; i < mDecryptionJobs.Length(); i++) {
|
||||
DecryptJob* job = mDecryptionJobs[i];
|
||||
if (job->mId == aId) {
|
||||
if (aDecryptedData.Length() != job->mSample->size) {
|
||||
NS_WARNING("CDM returned incorrect number of decrypted bytes");
|
||||
}
|
||||
if (GMP_SUCCEEDED(aResult)) {
|
||||
PodCopy(job->mSample->data,
|
||||
aDecryptedData.Elements(),
|
||||
std::min<size_t>(aDecryptedData.Length(), job->mSample->size));
|
||||
job->mClient->Decrypted(GMPNoErr, job->mSample.forget());
|
||||
} else if (aResult == GMPNoKeyErr) {
|
||||
NS_WARNING("CDM returned GMPNoKeyErr");
|
||||
// We still have the encrypted sample, so we can re-enqueue it to be
|
||||
// decrypted again once the key is usable again.
|
||||
job->mClient->Decrypted(GMPNoKeyErr, job->mSample.forget());
|
||||
} else {
|
||||
nsAutoCString str("CDM returned decode failure GMPErr=");
|
||||
str.AppendInt(aResult);
|
||||
NS_WARNING(str.get());
|
||||
job->mClient->Decrypted(aResult, nullptr);
|
||||
}
|
||||
mDecryptionJobs.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NS_WARNING("GMPDecryptorChild returned incorrect job ID");
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
|
||||
nsTArray<nsCString>& aSessionIds)
|
||||
{
|
||||
CDMCaps::AutoLock caps(Capabilites());
|
||||
caps.GetSessionIdsForKeyId(aKeyId, aSessionIds);
|
||||
}
|
||||
|
||||
void
|
||||
CDMProxy::Terminated()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_WARNING("CDM terminated");
|
||||
if (!mKeys.IsNull()) {
|
||||
mKeys->Terminated();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,328 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsString.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "mozilla/dom/MediaKeys.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsIThread.h"
|
||||
#include "GMPDecryptorProxy.h"
|
||||
#include "mozilla/CDMCaps.h"
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMCallbackProxy;
|
||||
|
||||
namespace dom {
|
||||
class MediaKeySession;
|
||||
}
|
||||
|
||||
class DecryptionClient {
|
||||
public:
|
||||
virtual ~DecryptionClient() {}
|
||||
virtual void Decrypted(GMPErr aResult,
|
||||
mp4_demuxer::MP4Sample* aSample) = 0;
|
||||
};
|
||||
|
||||
// Proxies calls GMP/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 {
|
||||
typedef dom::PromiseId PromiseId;
|
||||
typedef dom::SessionType SessionType;
|
||||
public:
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CDMProxy)
|
||||
|
||||
// Main thread only.
|
||||
CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem);
|
||||
|
||||
// Main thread only.
|
||||
// Loads the CDM corresponding to mKeySystem.
|
||||
// Calls MediaKeys::OnCDMCreated() when the CDM is created.
|
||||
void Init(PromiseId aPromiseId,
|
||||
const nsAString& aOrigin,
|
||||
const nsAString& aTopLevelOrigin,
|
||||
bool aInPrivateBrowsing);
|
||||
|
||||
// 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.
|
||||
void CreateSession(uint32_t aCreateSessionToken,
|
||||
dom::SessionType aSessionType,
|
||||
PromiseId aPromiseId,
|
||||
const nsAString& aInitDataType,
|
||||
nsTArray<uint8_t>& aInitData);
|
||||
|
||||
// Main thread only.
|
||||
// Uses the CDM to load a presistent session stored on disk.
|
||||
// Calls MediaKeys::OnSessionActivated() when session is loaded.
|
||||
void LoadSession(PromiseId aPromiseId,
|
||||
const nsAString& aSessionId);
|
||||
|
||||
// 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.
|
||||
void SetServerCertificate(PromiseId aPromiseId,
|
||||
nsTArray<uint8_t>& aCert);
|
||||
|
||||
// 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.
|
||||
void UpdateSession(const nsAString& aSessionId,
|
||||
PromiseId aPromiseId,
|
||||
nsTArray<uint8_t>& aResponse);
|
||||
|
||||
// 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().
|
||||
void CloseSession(const nsAString& aSessionId,
|
||||
PromiseId aPromiseId);
|
||||
|
||||
// Main thread only.
|
||||
// Removes all data for a persisent session.
|
||||
// Calls MediaKeys->ResolvePromise(aPromiseId) after the CDM has
|
||||
// processed the request.
|
||||
void RemoveSession(const nsAString& aSessionId,
|
||||
PromiseId aPromiseId);
|
||||
|
||||
// Main thread only.
|
||||
void Shutdown();
|
||||
|
||||
// Main thread only.
|
||||
void Terminated();
|
||||
|
||||
// Threadsafe.
|
||||
const nsCString& GetNodeId() const;
|
||||
|
||||
// Main thread only.
|
||||
void OnSetSessionId(uint32_t aCreateSessionToken,
|
||||
const nsAString& aSessionId);
|
||||
|
||||
// Main thread only.
|
||||
void OnResolveLoadSessionPromise(uint32_t aPromiseId, bool aSuccess);
|
||||
|
||||
// Main thread only.
|
||||
void OnSessionMessage(const nsAString& aSessionId,
|
||||
GMPSessionMessageType aMessageType,
|
||||
nsTArray<uint8_t>& aMessage);
|
||||
|
||||
// Main thread only.
|
||||
void OnExpirationChange(const nsAString& aSessionId,
|
||||
GMPTimestamp aExpiryTime);
|
||||
|
||||
// Main thread only.
|
||||
void OnSessionClosed(const nsAString& aSessionId);
|
||||
|
||||
// Main thread only.
|
||||
void OnSessionError(const nsAString& aSessionId,
|
||||
nsresult aException,
|
||||
uint32_t aSystemCode,
|
||||
const nsAString& aMsg);
|
||||
|
||||
// Main thread only.
|
||||
void OnRejectPromise(uint32_t aPromiseId,
|
||||
nsresult aDOMException,
|
||||
const nsAString& aMsg);
|
||||
|
||||
// Threadsafe.
|
||||
void Decrypt(mp4_demuxer::MP4Sample* aSample,
|
||||
DecryptionClient* aSink);
|
||||
|
||||
// Reject promise with DOMException corresponding to aExceptionCode.
|
||||
// Can be called from any thread.
|
||||
void RejectPromise(PromiseId aId, nsresult aExceptionCode);
|
||||
|
||||
// Resolves promise with "undefined".
|
||||
// Can be called from any thread.
|
||||
void ResolvePromise(PromiseId aId);
|
||||
|
||||
// Threadsafe.
|
||||
const nsString& KeySystem() const;
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Decrypted(uint32_t aId,
|
||||
GMPErr aResult,
|
||||
const nsTArray<uint8_t>& aDecryptedData);
|
||||
|
||||
CDMCaps& Capabilites();
|
||||
|
||||
// Main thread only.
|
||||
void OnKeyStatusesChange(const nsAString& aSessionId);
|
||||
|
||||
void GetSessionIdsForKeyId(const nsTArray<uint8_t>& aKeyId,
|
||||
nsTArray<nsCString>& aSessionIds);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool IsOnGMPThread();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
struct InitData {
|
||||
uint32_t mPromiseId;
|
||||
nsAutoString mOrigin;
|
||||
nsAutoString mTopLevelOrigin;
|
||||
bool mInPrivateBrowsing;
|
||||
};
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Init(nsAutoPtr<InitData> aData);
|
||||
|
||||
// GMP thread only.
|
||||
void gmp_Shutdown();
|
||||
|
||||
// Main thread only.
|
||||
void OnCDMCreated(uint32_t aPromiseId);
|
||||
|
||||
struct CreateSessionData {
|
||||
dom::SessionType mSessionType;
|
||||
uint32_t mCreateSessionToken;
|
||||
PromiseId mPromiseId;
|
||||
nsAutoCString mInitDataType;
|
||||
nsTArray<uint8_t> mInitData;
|
||||
};
|
||||
// GMP thread only.
|
||||
void gmp_CreateSession(nsAutoPtr<CreateSessionData> aData);
|
||||
|
||||
struct SessionOpData {
|
||||
PromiseId mPromiseId;
|
||||
nsAutoCString 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;
|
||||
nsAutoCString 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);
|
||||
|
||||
struct DecryptJob {
|
||||
DecryptJob(mp4_demuxer::MP4Sample* aSample,
|
||||
DecryptionClient* aClient)
|
||||
: mId(0)
|
||||
, mSample(aSample)
|
||||
, mClient(aClient)
|
||||
{}
|
||||
uint32_t mId;
|
||||
nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
|
||||
nsAutoPtr<DecryptionClient> mClient;
|
||||
};
|
||||
// GMP thread only.
|
||||
void gmp_Decrypt(nsAutoPtr<DecryptJob> aJob);
|
||||
|
||||
class RejectPromiseTask : public nsRunnable {
|
||||
public:
|
||||
RejectPromiseTask(CDMProxy* aProxy,
|
||||
PromiseId aId,
|
||||
nsresult aCode)
|
||||
: mProxy(aProxy)
|
||||
, mId(aId)
|
||||
, mCode(aCode)
|
||||
{
|
||||
}
|
||||
NS_METHOD Run() {
|
||||
mProxy->RejectPromise(mId, mCode);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
PromiseId mId;
|
||||
nsresult mCode;
|
||||
};
|
||||
|
||||
~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 nsAutoString mKeySystem;
|
||||
|
||||
// Goanna Media Plugin thread. All interactions with the out-of-process
|
||||
// EME plugin must come from this thread.
|
||||
nsRefPtr<nsIThread> mGMPThread;
|
||||
|
||||
nsCString mNodeId;
|
||||
|
||||
GMPDecryptorProxy* mCDM;
|
||||
CDMCaps mCapabilites;
|
||||
nsAutoPtr<CDMCallbackProxy> mCallback;
|
||||
|
||||
// Decryption jobs sent to CDM, awaiting result.
|
||||
// GMP thread only.
|
||||
nsTArray<nsAutoPtr<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;
|
||||
};
|
||||
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CDMProxy_h_
|
||||
@@ -1,116 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
||||
PRLogModuleInfo* GetEMELog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("EME");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
PRLogModuleInfo* GetEMEVerboseLog() {
|
||||
static PRLogModuleInfo* log = nullptr;
|
||||
if (!log) {
|
||||
log = PR_NewLogModule("EMEV");
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool
|
||||
ContainsOnlyDigits(const nsAString& aString)
|
||||
{
|
||||
nsAString::const_iterator iter, end;
|
||||
aString.BeginReading(iter);
|
||||
aString.EndReading(end);
|
||||
while (iter != end) {
|
||||
char16_t ch = *iter;
|
||||
if (ch < '0' || ch > '9') {
|
||||
return false;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ParseKeySystem(const nsAString& aExpectedKeySystem,
|
||||
const nsAString& aInputKeySystem,
|
||||
int32_t& aOutCDMVersion)
|
||||
{
|
||||
if (!StringBeginsWith(aInputKeySystem, aExpectedKeySystem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aInputKeySystem.Length() > aExpectedKeySystem.Length() + 8) {
|
||||
// Allow up to 8 bytes for the ".version" field. 8 bytes should
|
||||
// be enough for any versioning scheme...
|
||||
NS_WARNING("Input KeySystem including was suspiciously long");
|
||||
return false;
|
||||
}
|
||||
|
||||
const char16_t* versionStart = aInputKeySystem.BeginReading() + aExpectedKeySystem.Length();
|
||||
const char16_t* end = aInputKeySystem.EndReading();
|
||||
if (versionStart == end) {
|
||||
// No version supplied with keysystem.
|
||||
aOutCDMVersion = NO_CDM_VERSION;
|
||||
return true;
|
||||
}
|
||||
if (*versionStart != '.') {
|
||||
// version not in correct format.
|
||||
NS_WARNING("EME keySystem version string not prefixed by '.'");
|
||||
return false;
|
||||
}
|
||||
versionStart++;
|
||||
const nsAutoString versionStr(Substring(versionStart, end));
|
||||
if (!ContainsOnlyDigits(versionStr)) {
|
||||
NS_WARNING("Non-digit character in EME keySystem string's version suffix");
|
||||
return false;
|
||||
}
|
||||
nsresult rv;
|
||||
int32_t version = versionStr.ToInteger(&rv);
|
||||
if (NS_FAILED(rv) || version < 0) {
|
||||
NS_WARNING("Invalid version in EME keySystem string");
|
||||
return false;
|
||||
}
|
||||
aOutCDMVersion = version;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static const char16_t* sKeySystems[] = {
|
||||
MOZ_UTF16("org.w3.clearkey"),
|
||||
MOZ_UTF16("com.adobe.access"),
|
||||
MOZ_UTF16("com.adobe.primetime"),
|
||||
};
|
||||
|
||||
bool
|
||||
ParseKeySystem(const nsAString& aInputKeySystem,
|
||||
nsAString& aOutKeySystem,
|
||||
int32_t& aOutCDMVersion)
|
||||
{
|
||||
for (const char16_t* keySystem : sKeySystems) {
|
||||
int32_t minCDMVersion = NO_CDM_VERSION;
|
||||
if (ParseKeySystem(nsDependentString(keySystem),
|
||||
aInputKeySystem,
|
||||
minCDMVersion)) {
|
||||
aOutKeySystem = keySystem;
|
||||
aOutCDMVersion = minCDMVersion;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,69 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "prlog.h"
|
||||
#include "nsString.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#ifdef PR_LOGGING
|
||||
|
||||
#ifndef EME_LOG
|
||||
PRLogModuleInfo* GetEMELog();
|
||||
#define EME_LOG(...) PR_LOG(GetEMELog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#ifndef EME_VERBOSE_LOG
|
||||
PRLogModuleInfo* GetEMEVerboseLog();
|
||||
#define EME_VERBOSE_LOG(...) PR_LOG(GetEMEVerboseLog(), PR_LOG_DEBUG, (__VA_ARGS__))
|
||||
#else
|
||||
#ifndef EME_LOG
|
||||
#define EME_LOG(...)
|
||||
#endif
|
||||
|
||||
#ifndef EME_VERBOSE_LOG
|
||||
#define EME_VERBOSE_LOG(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifndef EME_LOG
|
||||
#define EME_LOG(...)
|
||||
#endif
|
||||
|
||||
#ifndef EME_VERBOSE_LOG
|
||||
#define EME_VERBOSE_LOG(...)
|
||||
#endif
|
||||
|
||||
#endif // PR_LOGGING
|
||||
|
||||
#define NO_CDM_VERSION -1
|
||||
|
||||
// Checks a keySystem string against a whitelist, and determines whether
|
||||
// the keySystem is in the whitelist, and extracts the requested minimum
|
||||
// CDM version.
|
||||
//
|
||||
// Format of EME keysystems:
|
||||
// com.domain.keysystem[.minVersionAsInt]
|
||||
// i.e. org.w3.clearkey, com.adobe.primetime.7
|
||||
//
|
||||
// Returns true if aKeySystem contains a valid keySystem which we support,
|
||||
// false otherwise.
|
||||
//
|
||||
// On success, aOutKeySystem contains the keySystem string stripped of the
|
||||
// min version number, and aOutMinCDMVersion contains the min version number
|
||||
// if present. If it was not present, aOutMinCDMVersion is NO_CDM_VERSION.
|
||||
bool ParseKeySystem(const nsAString& aKeySystem,
|
||||
nsAString& aOutKeySystem,
|
||||
int32_t& aOutMinCDMVersion);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // EME_LOG_H_
|
||||
@@ -1,130 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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;
|
||||
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)
|
||||
{
|
||||
return MediaEncryptedEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
already_AddRefed<MediaEncryptedEvent>
|
||||
MediaEncryptedEvent::Constructor(EventTarget* aOwner)
|
||||
{
|
||||
nsRefPtr<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)
|
||||
{
|
||||
nsRefPtr<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());
|
||||
nsRefPtr<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();
|
||||
a.ComputeLengthAndData();
|
||||
e->mInitData = ArrayBuffer::Create(aGlobal.Context(),
|
||||
a.Length(),
|
||||
a.Data());
|
||||
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,
|
||||
mRawInitData.Length(),
|
||||
mRawInitData.Elements());
|
||||
if (!mInitData) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
mRawInitData.Clear();
|
||||
}
|
||||
if (mInitData) {
|
||||
JS::ExposeObjectToActiveJS(mInitData);
|
||||
}
|
||||
aData.set(mInitData);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,67 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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:
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) 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__
|
||||
@@ -1,39 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "MediaKeyError.h"
|
||||
#include "mozilla/dom/MediaKeyErrorBinding.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MediaKeyError::MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
, mSystemCode(aSystemCode)
|
||||
{
|
||||
InitEvent(NS_LITERAL_STRING("error"), false, false);
|
||||
}
|
||||
|
||||
MediaKeyError::~MediaKeyError()
|
||||
{
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MediaKeyError::SystemCode() const
|
||||
{
|
||||
return mSystemCode;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeyError::WrapObjectInternal(JSContext* aCx)
|
||||
{
|
||||
return MediaKeyErrorBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,38 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_MediaKeyError_h
|
||||
#define mozilla_dom_MediaKeyError_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MediaKeyError final : public Event
|
||||
{
|
||||
public:
|
||||
NS_FORWARD_TO_EVENT
|
||||
|
||||
MediaKeyError(EventTarget* aOwner, uint32_t aSystemCode);
|
||||
~MediaKeyError();
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) override;
|
||||
|
||||
uint32_t SystemCode() const;
|
||||
|
||||
private:
|
||||
uint32_t mSystemCode;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,125 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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;
|
||||
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)
|
||||
{
|
||||
return MediaKeyMessageEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
already_AddRefed<MediaKeyMessageEvent>
|
||||
MediaKeyMessageEvent::Constructor(EventTarget* aOwner,
|
||||
MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
nsRefPtr<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());
|
||||
nsRefPtr<MediaKeyMessageEvent> e = new MediaKeyMessageEvent(owner);
|
||||
bool trusted = e->Init(owner);
|
||||
e->InitEvent(aType, aEventInitDict.mBubbles, aEventInitDict.mCancelable);
|
||||
const uint8_t* data = nullptr;
|
||||
size_t length = 0;
|
||||
if (aEventInitDict.mMessage.WasPassed()) {
|
||||
const auto& a = aEventInitDict.mMessage.Value();
|
||||
a.ComputeLengthAndData();
|
||||
data = a.Data();
|
||||
length = a.Length();
|
||||
}
|
||||
e->mMessage = ArrayBuffer::Create(aGlobal.Context(), length, data);
|
||||
if (!e->mMessage) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
e->mMessageType = aEventInitDict.mMessageType;
|
||||
e->SetTrusted(trusted);
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyMessageEvent::GetMessage(JSContext* cx,
|
||||
JS::MutableHandle<JSObject*> aMessage,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!mMessage) {
|
||||
mMessage = ArrayBuffer::Create(cx,
|
||||
mRawMessage.Length(),
|
||||
mRawMessage.Elements());
|
||||
if (!mMessage) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
}
|
||||
mRawMessage.Clear();
|
||||
}
|
||||
JS::ExposeObjectToActiveJS(mMessage);
|
||||
aMessage.set(mMessage);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,67 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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();
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) 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__
|
||||
@@ -1,323 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/AsyncEventDispatcher.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "nsContentUtils.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;
|
||||
|
||||
MediaKeySession::MediaKeySession(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent,
|
||||
MediaKeys* aKeys,
|
||||
const nsAString& aKeySystem,
|
||||
SessionType aSessionType,
|
||||
ErrorResult& aRv)
|
||||
: DOMEventTargetHelper(aParent)
|
||||
, mKeys(aKeys)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mSessionType(aSessionType)
|
||||
, mToken(sMediaKeySessionNum++)
|
||||
, mIsClosed(false)
|
||||
, mUninitialized(true)
|
||||
, mKeyStatusMap(new MediaKeyStatusMap(aCx, aParent, aRv))
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
mClosed = mKeys->MakePromise(aRv);
|
||||
}
|
||||
|
||||
void MediaKeySession::SetSessionId(const nsAString& aSessionId)
|
||||
{
|
||||
if (NS_WARN_IF(!mSessionId.IsEmpty())) {
|
||||
return;
|
||||
}
|
||||
mSessionId = aSessionId;
|
||||
mKeys->OnSessionIdReady(this);
|
||||
}
|
||||
|
||||
MediaKeySession::~MediaKeySession()
|
||||
{
|
||||
}
|
||||
|
||||
MediaKeyError*
|
||||
MediaKeySession::GetError() const
|
||||
{
|
||||
return mMediaKeyError;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::GetKeySystem(nsString& aKeySystem) const
|
||||
{
|
||||
aKeySystem = mKeySystem;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::GetSessionId(nsString& aSessionId) const
|
||||
{
|
||||
aSessionId = GetSessionId();
|
||||
}
|
||||
|
||||
const nsString&
|
||||
MediaKeySession::GetSessionId() const
|
||||
{
|
||||
return mSessionId;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeySession::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return MediaKeySessionBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
double
|
||||
MediaKeySession::Expiration() const
|
||||
{
|
||||
return JS::GenericNaN();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
MediaKeyStatusMap*
|
||||
MediaKeySession::KeyStatuses() const
|
||||
{
|
||||
return mKeyStatusMap;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
|
||||
const ArrayBufferViewOrArrayBuffer& aInitData,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
mUninitialized = false;
|
||||
|
||||
nsTArray<uint8_t> data;
|
||||
if (aInitDataType.IsEmpty() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aInitData, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
PromiseId pid = mKeys->StorePromise(promise);
|
||||
mKeys->GetCDMProxy()->CreateSession(Token(),
|
||||
mSessionType,
|
||||
pid,
|
||||
aInitDataType, data);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::Load(const nsAString& aSessionId, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aSessionId.IsEmpty()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The sessionId parameter is empty."
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!mUninitialized) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
mUninitialized = false;
|
||||
|
||||
// We now know the sessionId being loaded into this session. Remove the
|
||||
// session from its owning MediaKey's set of sessions awaiting a sessionId.
|
||||
nsRefPtr<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);
|
||||
|
||||
mKeys->GetCDMProxy()->LoadSession(mKeys->StorePromise(promise), aSessionId);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::Update(const ArrayBufferViewOrArrayBuffer& aResponse, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
nsTArray<uint8_t> data;
|
||||
if (IsClosed() ||
|
||||
!mKeys->GetCDMProxy() ||
|
||||
!CopyArrayBufferViewOrArrayBufferData(aResponse, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
mKeys->GetCDMProxy()->UpdateSession(mSessionId,
|
||||
mKeys->StorePromise(promise),
|
||||
data);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::Close(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
return promise.forget();
|
||||
}
|
||||
mKeys->GetCDMProxy()->CloseSession(mSessionId, mKeys->StorePromise(promise));
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::OnClosed()
|
||||
{
|
||||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
mIsClosed = true;
|
||||
mKeys->OnSessionClosed(this);
|
||||
mKeys = nullptr;
|
||||
mClosed->MaybeResolve(JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaKeySession::IsClosed() const
|
||||
{
|
||||
return mIsClosed;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySession::Remove(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
if (mSessionType != SessionType::Persistent) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
// "The operation is not supported on session type sessions."
|
||||
return promise.forget();
|
||||
}
|
||||
if (IsClosed() || !mKeys->GetCDMProxy()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
// "The session is closed."
|
||||
return promise.forget();
|
||||
}
|
||||
mKeys->GetCDMProxy()->RemoveSession(mSessionId, mKeys->StorePromise(promise));
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
|
||||
const nsTArray<uint8_t>& aMessage)
|
||||
{
|
||||
nsRefPtr<MediaKeyMessageEvent> event(
|
||||
MediaKeyMessageEvent::Constructor(this, aMessageType, aMessage));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
|
||||
{
|
||||
RefPtr<MediaKeyError> event(new MediaKeyError(this, aSystemCode));
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, event);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySession::DispatchKeyStatusesChange()
|
||||
{
|
||||
if (IsClosed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateKeyStatusMap();
|
||||
|
||||
nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("keystatuseschange"), false);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MediaKeySession::Token() const
|
||||
{
|
||||
return mToken;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,120 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/dom/MediaKeySessionBinding.h"
|
||||
#include "mozilla/dom/MediaKeysBinding.h"
|
||||
#include "mozilla/dom/MediaKeyMessageEventBinding.h"
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
|
||||
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,
|
||||
nsPIDOMWindow* aParent,
|
||||
MediaKeys* aKeys,
|
||||
const nsAString& aKeySystem,
|
||||
SessionType aSessionType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void SetSessionId(const nsAString& aSessionId);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) 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;
|
||||
|
||||
// Process-unique identifier.
|
||||
uint32_t Token() const;
|
||||
|
||||
private:
|
||||
~MediaKeySession();
|
||||
|
||||
void UpdateKeyStatusMap();
|
||||
|
||||
nsRefPtr<Promise> mClosed;
|
||||
|
||||
nsRefPtr<MediaKeyError> mMediaKeyError;
|
||||
nsRefPtr<MediaKeys> mKeys;
|
||||
const nsString mKeySystem;
|
||||
nsString mSessionId;
|
||||
const SessionType mSessionType;
|
||||
const uint32_t mToken;
|
||||
bool mIsClosed;
|
||||
bool mUninitialized;
|
||||
nsRefPtr<MediaKeyStatusMap> mKeyStatusMap;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,246 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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"
|
||||
|
||||
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_CLASS(MediaKeyStatusMap)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
tmp->mMap = nullptr;
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MediaKeyStatusMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMap)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
MediaKeyStatusMap::MediaKeyStatusMap(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent,
|
||||
ErrorResult& aRv)
|
||||
: mParent(aParent)
|
||||
, mUpdateError(NS_OK)
|
||||
{
|
||||
mMap = JS::NewMapObject(aCx);
|
||||
if (NS_WARN_IF(!mMap)) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
mozilla::HoldJSObjects(this);
|
||||
}
|
||||
|
||||
MediaKeyStatusMap::~MediaKeyStatusMap()
|
||||
{
|
||||
mozilla::DropJSObjects(this);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeyStatusMap::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return MediaKeyStatusMapBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
MediaKeyStatusMap::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
MediaKeyStatus
|
||||
MediaKeyStatusMap::Get(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
JS::Rooted<JS::Value> key(aCx);
|
||||
JS::Rooted<JS::Value> val(aCx);
|
||||
|
||||
if (!aKey.ToJSVal(aCx, map, &key) ||
|
||||
!JS::MapGet(aCx, map, key, &val)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int index = FindEnumStringIndex<true>(
|
||||
aCx, val, MediaKeyStatusValues::strings,
|
||||
"MediaKeyStatus", "Invalid MediaKeyStatus value", &ok);
|
||||
|
||||
return ok ? static_cast<MediaKeyStatus>(index) :
|
||||
MediaKeyStatus::Internal_error;
|
||||
}
|
||||
|
||||
bool
|
||||
MediaKeyStatusMap::Has(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
JS::Rooted<JS::Value> key(aCx);
|
||||
bool result = false;
|
||||
|
||||
if (!aKey.ToJSVal(aCx, map, &key) ||
|
||||
!JS::MapHas(aCx, map, key, &result)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<decltype(JS::MapKeys) Method>
|
||||
static void CallMapMethod(JSContext* aCx,
|
||||
const JS::Heap<JSObject*>& aMap,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv,
|
||||
nsresult aUpdateError)
|
||||
{
|
||||
if (NS_FAILED(aUpdateError)) {
|
||||
aRv.Throw(aUpdateError);
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> map(aCx, aMap);
|
||||
JS::Rooted<JS::Value> result(aCx);
|
||||
if (!Method(aCx, map, &result)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
aResult.set(&result.toObject());
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Keys(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapKeys>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Values(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapValues>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
void
|
||||
MediaKeyStatusMap::Entries(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
CallMapMethod<JS::MapEntries>(aCx, mMap, aResult, aRv, mUpdateError);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MediaKeyStatusMap::GetSize(JSContext* aCx, ErrorResult& aRv) const
|
||||
{
|
||||
if (NS_FAILED(mUpdateError)) {
|
||||
aRv.Throw(mUpdateError);
|
||||
return 0;
|
||||
}
|
||||
JS::Rooted<JSObject*> map(aCx, mMap);
|
||||
return JS::MapSize(aCx, map);
|
||||
}
|
||||
|
||||
static MediaKeyStatus
|
||||
ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
|
||||
switch (aStatus) {
|
||||
case kGMPUsable: return MediaKeyStatus::Usable;
|
||||
case kGMPExpired: return MediaKeyStatus::Expired;
|
||||
case kGMPOutputDownscaled: return MediaKeyStatus::Output_downscaled;
|
||||
case kGMPOutputNotAllowed: return MediaKeyStatus::Output_not_allowed;
|
||||
case kGMPInternalError: return MediaKeyStatus::Internal_error;
|
||||
default: return MediaKeyStatus::Internal_error;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
ToJSString(JSContext* aCx, GMPMediaKeyStatus aStatus,
|
||||
JS::MutableHandle<JS::Value> aResult)
|
||||
{
|
||||
auto val = uint32_t(ToMediaKeyStatus(aStatus));
|
||||
MOZ_ASSERT(val < ArrayLength(MediaKeyStatusValues::strings));
|
||||
JSString* str = JS_NewStringCopyN(aCx,
|
||||
MediaKeyStatusValues::strings[val].value,
|
||||
MediaKeyStatusValues::strings[val].length);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
aResult.setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaKeyStatusMap::UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys)
|
||||
{
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(mParent))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
jsapi.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = jsapi.cx();
|
||||
JS::Rooted<JSObject*> map(cx, mMap);
|
||||
if (!JS::MapClear(cx, map)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < keys.Length(); i++) {
|
||||
const auto& ks = keys[i];
|
||||
JS::Rooted<JS::Value> key(cx);
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
if (!ToJSValue(cx, TypedArrayCreator<ArrayBuffer>(ks.mId), &key) ||
|
||||
!ToJSString(cx, ks.mStatus, &val) ||
|
||||
!JS::MapSet(cx, map, key, val)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeyStatusMap::Update(const nsTArray<CDMCaps::KeyStatus>& keys)
|
||||
{
|
||||
// Since we can't leave the map in a partial update state, we need
|
||||
// to remember the error and throw it next time the interface methods
|
||||
// are called.
|
||||
mUpdateError = UpdateInternal(keys);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,81 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
|
||||
class MediaKeyStatusMap final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeyStatusMap)
|
||||
|
||||
public:
|
||||
explicit MediaKeyStatusMap(JSContext* aCx,
|
||||
nsPIDOMWindow* aParent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
~MediaKeyStatusMap();
|
||||
|
||||
public:
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) override;
|
||||
|
||||
MediaKeyStatus Get(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
bool Has(JSContext* aCx,
|
||||
const ArrayBufferViewOrArrayBuffer& aKey,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Keys(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Values(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void Entries(JSContext* aCx,
|
||||
JS::MutableHandle<JSObject*> aResult,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
uint32_t GetSize(JSContext* aCx, ErrorResult& aRv) const;
|
||||
|
||||
void Update(const nsTArray<CDMCaps::KeyStatus>& keys);
|
||||
|
||||
private:
|
||||
nsresult UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
JS::Heap<JSObject*> mMap;
|
||||
nsresult mUpdateError;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,301 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/MediaKeySystemAccess.h"
|
||||
#include "mozilla/dom/MediaKeySystemAccessBinding.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "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 "mozIGoannaMediaPluginService.h"
|
||||
#include "VideoUtils.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "GMPUtils.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(nsPIDOMWindow* aParent,
|
||||
const nsAString& aKeySystem)
|
||||
: mParent(aParent)
|
||||
, mKeySystem(aKeySystem)
|
||||
{
|
||||
}
|
||||
|
||||
MediaKeySystemAccess::~MediaKeySystemAccess()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeySystemAccess::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return MediaKeySystemAccessBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
MediaKeySystemAccess::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySystemAccess::GetKeySystem(nsString& aRetVal) const
|
||||
{
|
||||
aRetVal = mKeySystem;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<MediaKeys> keys(new MediaKeys(mParent, mKeySystem));
|
||||
return keys->Init(aRv);
|
||||
}
|
||||
|
||||
static bool
|
||||
HaveGMPFor(mozIGoannaMediaPluginService* aGMPService,
|
||||
const nsCString& aKeySystem,
|
||||
const nsCString& aAPI,
|
||||
const nsCString& aTag = EmptyCString())
|
||||
{
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(aKeySystem);
|
||||
if (!aTag.IsEmpty()) {
|
||||
tags.AppendElement(aTag);
|
||||
}
|
||||
bool hasPlugin = false;
|
||||
if (NS_FAILED(aGMPService->HasPluginForAPI(aAPI,
|
||||
&tags,
|
||||
&hasPlugin))) {
|
||||
return false;
|
||||
}
|
||||
return hasPlugin;
|
||||
}
|
||||
|
||||
static MediaKeySystemStatus
|
||||
EnsureMinCDMVersion(mozIGoannaMediaPluginService* aGMPService,
|
||||
const nsAString& aKeySystem,
|
||||
int32_t aMinCdmVersion)
|
||||
{
|
||||
if (aMinCdmVersion == NO_CDM_VERSION) {
|
||||
return MediaKeySystemStatus::Available;
|
||||
}
|
||||
|
||||
nsTArray<nsCString> tags;
|
||||
tags.AppendElement(NS_ConvertUTF16toUTF8(aKeySystem));
|
||||
nsAutoCString versionStr;
|
||||
if (NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
&tags,
|
||||
versionStr)) &&
|
||||
// XXX to be removed later in bug 1147692
|
||||
NS_FAILED(aGMPService->GetPluginVersionForAPI(NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
&tags,
|
||||
versionStr))) {
|
||||
return MediaKeySystemStatus::Error;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
int32_t version = versionStr.ToInteger(&rv);
|
||||
if (NS_FAILED(rv) || version < 0 || aMinCdmVersion > version) {
|
||||
return MediaKeySystemStatus::Cdm_insufficient_version;
|
||||
}
|
||||
|
||||
return MediaKeySystemStatus::Available;
|
||||
}
|
||||
|
||||
/* static */
|
||||
MediaKeySystemStatus
|
||||
MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem,
|
||||
int32_t aMinCdmVersion)
|
||||
{
|
||||
MOZ_ASSERT(Preferences::GetBool("media.eme.enabled", false));
|
||||
nsCOMPtr<mozIGoannaMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/goanna-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return MediaKeySystemStatus::Error;
|
||||
}
|
||||
|
||||
if (aKeySystem.EqualsLiteral("org.w3.clearkey")) {
|
||||
if (!Preferences::GetBool("media.eme.clearkey.enabled", true)) {
|
||||
return MediaKeySystemStatus::Cdm_disabled;
|
||||
}
|
||||
if (!HaveGMPFor(mps,
|
||||
NS_LITERAL_CSTRING("org.w3.clearkey"),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) {
|
||||
return MediaKeySystemStatus::Cdm_not_installed;
|
||||
}
|
||||
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion);
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
if ((aKeySystem.EqualsLiteral("com.adobe.access") ||
|
||||
aKeySystem.EqualsLiteral("com.adobe.primetime"))) {
|
||||
// Win Vista and later only.
|
||||
if (!IsVistaOrLater()) {
|
||||
return MediaKeySystemStatus::Cdm_not_supported;
|
||||
}
|
||||
if (!Preferences::GetBool("media.gmp-eme-adobe.enabled", false)) {
|
||||
return MediaKeySystemStatus::Cdm_disabled;
|
||||
}
|
||||
if ((!WMFDecoderModule::HasH264() || !WMFDecoderModule::HasAAC()) ||
|
||||
!EMEVoucherFileExists()) {
|
||||
// The system doesn't have the codecs that Adobe EME relies
|
||||
// on installed, or doesn't have a voucher for the plugin-container.
|
||||
// Adobe EME isn't going to work, so don't advertise that it will.
|
||||
return MediaKeySystemStatus::Cdm_not_supported;
|
||||
}
|
||||
if (!HaveGMPFor(mps,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)) &&
|
||||
// XXX to be removed later in bug 1147692
|
||||
!HaveGMPFor(mps,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT))) {
|
||||
return MediaKeySystemStatus::Cdm_not_installed;
|
||||
}
|
||||
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion);
|
||||
}
|
||||
#endif
|
||||
|
||||
return MediaKeySystemStatus::Cdm_not_supported;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsPlayableWithGMP(mozIGoannaMediaPluginService* aGMPS,
|
||||
const nsAString& aKeySystem,
|
||||
const nsAString& aContentType)
|
||||
{
|
||||
#ifdef MOZ_FMP4
|
||||
nsContentTypeParser parser(aContentType);
|
||||
nsAutoString mimeType;
|
||||
nsresult rv = parser.GetType(mimeType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mimeType.EqualsLiteral("audio/mp4") &&
|
||||
!mimeType.EqualsLiteral("audio/x-m4a") &&
|
||||
!mimeType.EqualsLiteral("video/mp4")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsAutoString codecs;
|
||||
parser.GetParameter("codecs", codecs);
|
||||
|
||||
NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType);
|
||||
bool hasAAC = false;
|
||||
bool hasH264 = false;
|
||||
bool hasMP3 = false;
|
||||
if (!MP4Decoder::CanHandleMediaType(mimeTypeUTF8,
|
||||
codecs,
|
||||
hasAAC,
|
||||
hasH264,
|
||||
hasMP3) ||
|
||||
hasMP3) {
|
||||
return false;
|
||||
}
|
||||
return (!hasAAC ||
|
||||
!(HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
NS_LITERAL_CSTRING("aac")) ||
|
||||
// XXX remove later in bug 1147692
|
||||
HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
NS_LITERAL_CSTRING("aac")))) &&
|
||||
(!hasH264 ||
|
||||
!(HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR),
|
||||
NS_LITERAL_CSTRING("h264")) ||
|
||||
// XXX remove later in bug 1147692
|
||||
HaveGMPFor(aGMPS,
|
||||
NS_ConvertUTF16toUTF8(aKeySystem),
|
||||
NS_LITERAL_CSTRING(GMP_API_DECRYPTOR_COMPAT),
|
||||
NS_LITERAL_CSTRING("h264"))));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
MediaKeySystemAccess::IsSupported(const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions)
|
||||
{
|
||||
nsCOMPtr<mozIGoannaMediaPluginService> mps =
|
||||
do_GetService("@mozilla.org/goanna-media-plugin-service;1");
|
||||
if (NS_WARN_IF(!mps)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < aOptions.Length(); i++) {
|
||||
const MediaKeySystemOptions& options = aOptions[i];
|
||||
if (!options.mInitDataType.EqualsLiteral("cenc")) {
|
||||
continue;
|
||||
}
|
||||
if (!options.mAudioCapability.IsEmpty() ||
|
||||
!options.mVideoCapability.IsEmpty()) {
|
||||
// Don't support any capabilites until we know we have a CDM with
|
||||
// capabilities...
|
||||
continue;
|
||||
}
|
||||
if (!options.mAudioType.IsEmpty() &&
|
||||
!IsPlayableWithGMP(mps, aKeySystem, options.mAudioType)) {
|
||||
continue;
|
||||
}
|
||||
if (!options.mVideoType.IsEmpty() &&
|
||||
!IsPlayableWithGMP(mps, aKeySystem, options.mVideoType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Our sandbox provides an origin specific unique identifier, and the
|
||||
// ability to persist data. We don't yet have a way to turn those off
|
||||
// and on for specific GMPs/CDMs, so we don't check the uniqueidentifier
|
||||
// and stateful attributes here.
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
MediaKeySystemAccess::NotifyObservers(nsIDOMWindow* aWindow,
|
||||
const nsAString& aKeySystem,
|
||||
MediaKeySystemStatus aStatus)
|
||||
{
|
||||
RequestMediaKeySystemAccessNotification data;
|
||||
data.mKeySystem = aKeySystem;
|
||||
data.mStatus = aStatus;
|
||||
nsAutoString json;
|
||||
data.ToJSON(json);
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->NotifyObservers(aWindow, "mediakeys-request", json.get());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,65 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_MediaKeySystemAccess_h
|
||||
#define mozilla_dom_MediaKeySystemAccess_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/MediaKeySystemAccessBinding.h"
|
||||
#include "mozilla/dom/MediaKeysRequestStatusBinding.h"
|
||||
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
namespace mozilla {
|
||||
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(nsPIDOMWindow* aParent,
|
||||
const nsAString& aKeySystem);
|
||||
|
||||
protected:
|
||||
~MediaKeySystemAccess();
|
||||
|
||||
public:
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) override;
|
||||
|
||||
void GetKeySystem(nsString& aRetVal) const;
|
||||
|
||||
already_AddRefed<Promise> CreateMediaKeys(ErrorResult& aRv);
|
||||
|
||||
static MediaKeySystemStatus GetKeySystemStatus(const nsAString& aKeySystem,
|
||||
int32_t aMinCdmVersion);
|
||||
|
||||
static bool IsSupported(const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions);
|
||||
|
||||
static void NotifyObservers(nsIDOMWindow* aWindow,
|
||||
const nsAString& aKeySystem,
|
||||
MediaKeySystemStatus aStatus);
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
const nsString mKeySystem;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_MediaKeySystemAccess_h
|
||||
@@ -1,280 +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 "mozilla/Preferences.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.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();
|
||||
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(nsPIDOMWindow* aWindow)
|
||||
: mWindow(aWindow)
|
||||
, mAddedObservers(false)
|
||||
{
|
||||
}
|
||||
|
||||
MediaKeySystemAccessManager::~MediaKeySystemAccessManager()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySystemAccessManager::Request(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions)
|
||||
{
|
||||
if (aKeySystem.IsEmpty() || (aOptions.WasPassed() && aOptions.Value().IsEmpty())) {
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
Sequence<MediaKeySystemOptions> optionsNotPassed;
|
||||
const auto& options = aOptions.WasPassed() ? aOptions.Value() : optionsNotPassed;
|
||||
Request(aPromise, aKeySystem, options, RequestType::Initial);
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySystemAccessManager::Request(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions,
|
||||
RequestType aType)
|
||||
{
|
||||
EME_LOG("MediaKeySystemAccessManager::Request %s", NS_ConvertUTF16toUTF8(aKeySystem).get());
|
||||
if (!Preferences::GetBool("media.eme.enabled", false)) {
|
||||
// EME disabled by user, send notification to chrome so UI can
|
||||
// inform user.
|
||||
MediaKeySystemAccess::NotifyObservers(mWindow,
|
||||
aKeySystem,
|
||||
MediaKeySystemStatus::Api_disabled);
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse keysystem, split it out into keySystem prefix, and version suffix.
|
||||
nsAutoString keySystem;
|
||||
int32_t minCdmVersion = NO_CDM_VERSION;
|
||||
if (!ParseKeySystem(aKeySystem,
|
||||
keySystem,
|
||||
minCdmVersion)) {
|
||||
// Invalid keySystem string, or unsupported keySystem. Send notification
|
||||
// to chrome to show a failure notice.
|
||||
MediaKeySystemAccess::NotifyObservers(mWindow, aKeySystem, MediaKeySystemStatus::Cdm_not_supported);
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MediaKeySystemStatus status = MediaKeySystemAccess::GetKeySystemStatus(keySystem, minCdmVersion);
|
||||
if ((status == MediaKeySystemStatus::Cdm_not_installed ||
|
||||
status == MediaKeySystemStatus::Cdm_insufficient_version) &&
|
||||
keySystem.EqualsLiteral("com.adobe.primetime")) {
|
||||
// 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, aOptions)) {
|
||||
// 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 notificaiton,
|
||||
// as chrome is already displaying the "we can't play, updating"
|
||||
// notification.
|
||||
MediaKeySystemAccess::NotifyObservers(mWindow, keySystem, 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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (status != MediaKeySystemStatus::Available) {
|
||||
if (status != MediaKeySystemStatus::Error) {
|
||||
// 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, keySystem, status);
|
||||
}
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (aOptions.IsEmpty() ||
|
||||
MediaKeySystemAccess::IsSupported(keySystem, aOptions)) {
|
||||
nsRefPtr<MediaKeySystemAccess> access(new MediaKeySystemAccess(mWindow, keySystem));
|
||||
aPromise->MaybeResolve(access);
|
||||
return;
|
||||
}
|
||||
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
MediaKeySystemAccessManager::PendingRequest::PendingRequest(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions,
|
||||
nsITimer* aTimer)
|
||||
: mPromise(aPromise)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mOptions(aOptions)
|
||||
, mTimer(aTimer)
|
||||
{
|
||||
MOZ_COUNT_CTOR(MediaKeySystemAccessManager::PendingRequest);
|
||||
}
|
||||
|
||||
MediaKeySystemAccessManager::PendingRequest::PendingRequest(const PendingRequest& aOther)
|
||||
: mPromise(aOther.mPromise)
|
||||
, mKeySystem(aOther.mKeySystem)
|
||||
, mOptions(aOther.mOptions)
|
||||
, 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()
|
||||
{
|
||||
if (mPromise) {
|
||||
mPromise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MediaKeySystemAccessManager::AwaitInstall(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions)
|
||||
{
|
||||
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, aOptions, timer));
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeySystemAccessManager::RetryRequest(PendingRequest& aRequest)
|
||||
{
|
||||
aRequest.CancelTimer();
|
||||
Request(aRequest.mPromise, aRequest.mKeySystem, aRequest.mOptions, RequestType::Subsequent);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaKeySystemAccessManager::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
EME_LOG("MediaKeySystemAccessManager::Observe %s", aTopic);
|
||||
|
||||
if (!strcmp(aTopic, "gmp-path-added")) {
|
||||
nsTArray<PendingRequest> requests(Move(mRequests));
|
||||
// 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-path-added", 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();
|
||||
}
|
||||
if (mAddedObservers) {
|
||||
nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
|
||||
if (obsService) {
|
||||
obsService->RemoveObserver(this, "gmp-path-added");
|
||||
mAddedObservers = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,80 +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 MediaKeySystemAccessManager final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
|
||||
explicit MediaKeySystemAccessManager(nsPIDOMWindow* aWindow);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(MediaKeySystemAccessManager, nsIObserver)
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
void Request(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Optional<Sequence<MediaKeySystemOptions>>& aOptions);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
struct PendingRequest {
|
||||
PendingRequest(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions,
|
||||
nsITimer* aTimer);
|
||||
PendingRequest(const PendingRequest& aOther);
|
||||
~PendingRequest();
|
||||
void CancelTimer();
|
||||
void RejectPromise();
|
||||
|
||||
nsRefPtr<Promise> mPromise;
|
||||
const nsString mKeySystem;
|
||||
const Sequence<MediaKeySystemOptions> mOptions;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
enum RequestType {
|
||||
Initial,
|
||||
Subsequent
|
||||
};
|
||||
|
||||
void Request(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions,
|
||||
RequestType aType);
|
||||
|
||||
~MediaKeySystemAccessManager();
|
||||
|
||||
bool EnsureObserversAdded();
|
||||
|
||||
bool AwaitInstall(Promise* aPromise,
|
||||
const nsAString& aKeySystem,
|
||||
const Sequence<MediaKeySystemOptions>& aOptions);
|
||||
|
||||
void RetryRequest(PendingRequest& aRequest);
|
||||
|
||||
nsTArray<PendingRequest> mRequests;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
bool mAddedObservers;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,597 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/EventDispatcher.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/PluginCrashedEvent.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "mozilla/Preferences.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(nsPIDOMWindow* aParent, const nsAString& aKeySystem)
|
||||
: mParent(aParent)
|
||||
, mKeySystem(aKeySystem)
|
||||
, mCreatePromiseId(0)
|
||||
{
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
RejectPromises(const uint32_t& aKey,
|
||||
nsRefPtr<dom::Promise>& aPromise,
|
||||
void* aClosure)
|
||||
{
|
||||
aPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
((MediaKeys*)aClosure)->Release();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
MediaKeys::~MediaKeys()
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CopySessions(const nsAString& aKey,
|
||||
nsRefPtr<MediaKeySession>& aSession,
|
||||
void* aClosure)
|
||||
{
|
||||
KeySessionHashMap* p = static_cast<KeySessionHashMap*>(aClosure);
|
||||
p->Put(aSession->GetSessionId(), aSession);
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CloseSessions(const nsAString& aKey,
|
||||
nsRefPtr<MediaKeySession>& aSession,
|
||||
void* aClosure)
|
||||
{
|
||||
aSession->OnClosed();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeys::Terminated()
|
||||
{
|
||||
KeySessionHashMap keySessions;
|
||||
// Remove entries during iteration will screw it. Make a copy first.
|
||||
mKeySessions.Enumerate(&CopySessions, &keySessions);
|
||||
keySessions.Enumerate(&CloseSessions, nullptr);
|
||||
keySessions.Clear();
|
||||
MOZ_ASSERT(mKeySessions.Count() == 0);
|
||||
|
||||
// Notify the element about that CDM has terminated.
|
||||
if (mElement) {
|
||||
mElement->DecodeError();
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeys::Shutdown()
|
||||
{
|
||||
if (mProxy) {
|
||||
mProxy->Shutdown();
|
||||
mProxy = nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaKeys> kungFuDeathGrip = this;
|
||||
|
||||
mPromises.Enumerate(&RejectPromises, this);
|
||||
mPromises.Clear();
|
||||
}
|
||||
|
||||
nsPIDOMWindow*
|
||||
MediaKeys::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaKeys::WrapObject(JSContext* aCx)
|
||||
{
|
||||
return MediaKeysBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeys::GetKeySystem(nsString& retval) const
|
||||
{
|
||||
retval = mKeySystem;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(MakePromise(aRv));
|
||||
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);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsTArray<uint8_t> data;
|
||||
if (!CopyArrayBufferViewOrArrayBufferData(aCert, data)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
mProxy->SetServerCertificate(StorePromise(promise), data);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeys::MakePromise(ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
if (!global) {
|
||||
NS_WARNING("Passed non-global to MediaKeys ctor!");
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
return Promise::Create(global, aRv);
|
||||
}
|
||||
|
||||
PromiseId
|
||||
MediaKeys::StorePromise(Promise* 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();
|
||||
|
||||
mPromises.Put(id, aPromise);
|
||||
return id;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeys::RetrievePromise(PromiseId aId)
|
||||
{
|
||||
if (!mPromises.Contains(aId)) {
|
||||
NS_WARNING(nsPrintfCString("Tried to retrieve a non-existent promise id=%d", aId).get());
|
||||
return nullptr;
|
||||
}
|
||||
nsRefPtr<Promise> promise;
|
||||
mPromises.Remove(aId, getter_AddRefs(promise));
|
||||
Release();
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
void
|
||||
MediaKeys::RejectPromise(PromiseId aId, nsresult aExceptionCode)
|
||||
{
|
||||
EME_LOG("MediaKeys[%p]::RejectPromise(%d, 0x%x)", this, aId, aExceptionCode);
|
||||
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
if (mPendingSessions.Contains(aId)) {
|
||||
// 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.
|
||||
mPendingSessions.Remove(aId);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_FAILED(aExceptionCode));
|
||||
promise->MaybeReject(aExceptionCode);
|
||||
|
||||
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);
|
||||
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
if (mPendingSessions.Contains(aId)) {
|
||||
// We should only resolve LoadSession calls via this path,
|
||||
// not CreateSession() promises.
|
||||
nsRefPtr<MediaKeySession> session;
|
||||
if (!mPendingSessions.Get(aId, getter_AddRefs(session)) ||
|
||||
!session ||
|
||||
session->GetSessionId().IsEmpty()) {
|
||||
NS_WARNING("Received activation for non-existent session!");
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
mPendingSessions.Remove(aId);
|
||||
return;
|
||||
}
|
||||
mPendingSessions.Remove(aId);
|
||||
mKeySessions.Put(session->GetSessionId(), session);
|
||||
promise->MaybeResolve(session);
|
||||
} else {
|
||||
promise->MaybeResolve(JS::UndefinedHandleValue);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
MediaKeys::Init(ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<Promise> promise(MakePromise(aRv));
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
mProxy = new CDMProxy(this, mKeySystem);
|
||||
|
||||
// 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);
|
||||
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<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
|
||||
if (!window) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsCOMPtr<nsIDOMWindow> topWindow;
|
||||
window->GetTop(getter_AddRefs(topWindow));
|
||||
nsCOMPtr<nsPIDOMWindow> top = do_QueryInterface(topWindow);
|
||||
if (!top || !top->GetExtantDoc()) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
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);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
nsAutoString origin;
|
||||
nsresult rv = nsContentUtils::GetUTFOrigin(mPrincipal, origin);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsAutoString topLevelOrigin;
|
||||
rv = nsContentUtils::GetUTFOrigin(mTopLevelPrincipal, topLevelOrigin);
|
||||
if (NS_FAILED(rv)) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return promise.forget();
|
||||
}
|
||||
nsIDocument* doc = window->GetExtantDoc();
|
||||
const bool inPrivateBrowsing = nsContentUtils::IsInPrivateBrowsing(doc);
|
||||
|
||||
EME_LOG("MediaKeys[%p]::Create() (%s, %s), %s",
|
||||
this,
|
||||
NS_ConvertUTF16toUTF8(origin).get(),
|
||||
NS_ConvertUTF16toUTF8(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,
|
||||
origin,
|
||||
topLevelOrigin,
|
||||
inPrivateBrowsing);
|
||||
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
class CrashHandler : public gmp::GoannaMediaPluginService::PluginCrashCallback
|
||||
{
|
||||
public:
|
||||
CrashHandler(const nsACString& aPluginId,
|
||||
nsPIDOMWindow* aParentWindow,
|
||||
nsIDocument* aDocument)
|
||||
: gmp::GoannaMediaPluginService::PluginCrashCallback(aPluginId)
|
||||
, mParentWindowWeakPtr(do_GetWeakReference(aParentWindow))
|
||||
, mDocumentWeakPtr(do_GetWeakReference(aDocument))
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Run(const nsACString& aPluginName, const nsAString& aPluginDumpId) override
|
||||
{
|
||||
PluginCrashedEventInit init;
|
||||
init.mBubbles = true;
|
||||
init.mCancelable = true;
|
||||
init.mGmpPlugin = true;
|
||||
init.mPluginDumpID = aPluginDumpId;
|
||||
CopyUTF8toUTF16(aPluginName, init.mPluginName);
|
||||
init.mSubmittedCrashReport = false;
|
||||
|
||||
// The following PluginCrashedEvent fields stay empty:
|
||||
// init.mBrowserDumpID
|
||||
// init.mPluginFilename
|
||||
// TODO: Can/should we fill them?
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> parentWindow;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
if (!GetParentWindowAndDocumentIfValid(parentWindow, document)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<PluginCrashedEvent> event =
|
||||
PluginCrashedEvent::Constructor(document, NS_LITERAL_STRING("PluginCrashed"), init);
|
||||
event->SetTrusted(true);
|
||||
event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true;
|
||||
|
||||
EventDispatcher::DispatchDOMEvent(parentWindow, nullptr, event, nullptr, nullptr);
|
||||
}
|
||||
|
||||
virtual bool IsStillValid() override
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> parentWindow;
|
||||
nsCOMPtr<nsIDocument> document;
|
||||
return GetParentWindowAndDocumentIfValid(parentWindow, document);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~CrashHandler()
|
||||
{ }
|
||||
|
||||
bool
|
||||
GetParentWindowAndDocumentIfValid(nsCOMPtr<nsPIDOMWindow>& parentWindow,
|
||||
nsCOMPtr<nsIDocument>& document)
|
||||
{
|
||||
parentWindow = do_QueryReferent(mParentWindowWeakPtr);
|
||||
if (!parentWindow) {
|
||||
return false;
|
||||
}
|
||||
document = do_QueryReferent(mDocumentWeakPtr);
|
||||
if (!document) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> parentWindowDocument = parentWindow->GetExtantDoc();
|
||||
if (!parentWindowDocument || document.get() != parentWindowDocument.get()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
nsWeakPtr mParentWindowWeakPtr;
|
||||
nsWeakPtr mDocumentWeakPtr;
|
||||
};
|
||||
|
||||
void
|
||||
MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const nsACString& aPluginId)
|
||||
{
|
||||
nsRefPtr<Promise> promise(RetrievePromise(aId));
|
||||
if (!promise) {
|
||||
return;
|
||||
}
|
||||
mNodeId = aNodeId;
|
||||
nsRefPtr<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);
|
||||
|
||||
if (!aPluginId.IsEmpty()) {
|
||||
// Prepare plugin crash reporter.
|
||||
nsRefPtr<gmp::GoannaMediaPluginService> service =
|
||||
gmp::GoannaMediaPluginService::GetGoannaMediaPluginService();
|
||||
if (NS_WARN_IF(!service)) {
|
||||
return;
|
||||
}
|
||||
if (NS_WARN_IF(!mParent)) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc = mParent->GetExtantDoc();
|
||||
if (NS_WARN_IF(!doc)) {
|
||||
return;
|
||||
}
|
||||
service->AddPluginCrashCallback(new CrashHandler(aPluginId, mParent, doc));
|
||||
EME_LOG("MediaKeys[%p]::OnCDMCreated() registered crash handler for pluginId '%s'",
|
||||
this, aPluginId.Data());
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<MediaKeySession>
|
||||
MediaKeys::CreateSession(JSContext* aCx,
|
||||
SessionType aSessionType,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!mProxy) {
|
||||
NS_WARNING("Tried to use a MediaKeys which lost its CDM");
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<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)
|
||||
{
|
||||
nsRefPtr<Promise> 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)
|
||||
{
|
||||
nsRefPtr<MediaKeySession> session;
|
||||
mKeySessions.Get(aSessionId, getter_AddRefs(session));
|
||||
return session.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaKeySession>
|
||||
MediaKeys::GetPendingSession(uint32_t aToken)
|
||||
{
|
||||
nsRefPtr<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;
|
||||
}
|
||||
|
||||
bool
|
||||
CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBufferOrView,
|
||||
nsTArray<uint8_t>& aOutData)
|
||||
{
|
||||
if (aBufferOrView.IsArrayBuffer()) {
|
||||
const ArrayBuffer& buffer = aBufferOrView.GetAsArrayBuffer();
|
||||
buffer.ComputeLengthAndData();
|
||||
aOutData.AppendElements(buffer.Data(), buffer.Length());
|
||||
} else if (aBufferOrView.IsArrayBufferView()) {
|
||||
const ArrayBufferView& bufferview = aBufferOrView.GetAsArrayBufferView();
|
||||
bufferview.ComputeLengthAndData();
|
||||
aOutData.AppendElements(bufferview.Data(), bufferview.Length());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
@@ -1,151 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsIDOMMediaError.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 "mozIGoannaMediaPluginService.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class ArrayBufferViewOrArrayBuffer;
|
||||
class MediaKeySession;
|
||||
class HTMLMediaElement;
|
||||
|
||||
typedef nsRefPtrHashtable<nsStringHashKey, MediaKeySession> KeySessionHashMap;
|
||||
typedef nsRefPtrHashtable<nsUint32HashKey, dom::Promise> PromiseHashMap;
|
||||
typedef nsRefPtrHashtable<nsUint32HashKey, MediaKeySession> PendingKeySessionsHashMap;
|
||||
typedef uint32_t PromiseId;
|
||||
|
||||
// Helper function to extract data coming in from JS in an
|
||||
// (ArrayBuffer or ArrayBufferView) IDL typed function argument.
|
||||
bool
|
||||
CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBufferOrView,
|
||||
nsTArray<uint8_t>& aOutData);
|
||||
|
||||
// This class is used on the main thread only.
|
||||
// Note: it's addref/release is not (and can't be) thread safe!
|
||||
class MediaKeys final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
~MediaKeys();
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeys)
|
||||
|
||||
MediaKeys(nsPIDOMWindow* aParentWindow, const nsAString& aKeySystem);
|
||||
|
||||
already_AddRefed<Promise> Init(ErrorResult& aRv);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx) override;
|
||||
|
||||
nsresult Bind(HTMLMediaElement* aElement);
|
||||
|
||||
// Javascript: readonly attribute DOMString keySystem;
|
||||
void GetKeySystem(nsString& retval) const;
|
||||
|
||||
// JavaScript: MediaKeys.createSession()
|
||||
already_AddRefed<MediaKeySession> CreateSession(JSContext* aCx,
|
||||
SessionType aSessionType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// JavaScript: MediaKeys.SetServerCertificate()
|
||||
already_AddRefed<Promise> 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 nsACString& 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<Promise> MakePromise(ErrorResult& aRv);
|
||||
// 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(Promise* aPromise);
|
||||
|
||||
// Reject promise with DOMException corresponding to aExceptionCode.
|
||||
void RejectPromise(PromiseId aId, nsresult aExceptionCode);
|
||||
// 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:
|
||||
|
||||
bool IsInPrivateBrowsing();
|
||||
|
||||
// Removes promise from mPromises, and returns it.
|
||||
already_AddRefed<Promise> 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.
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
|
||||
nsRefPtr<HTMLMediaElement> mElement;
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mParent;
|
||||
nsString mKeySystem;
|
||||
nsCString mNodeId;
|
||||
KeySessionHashMap mKeySessions;
|
||||
PromiseHashMap mPromises;
|
||||
PendingKeySessionsHashMap mPendingSessions;
|
||||
PromiseId mCreatePromiseId;
|
||||
|
||||
nsRefPtr<nsIPrincipal> mPrincipal;
|
||||
nsRefPtr<nsIPrincipal> mTopLevelPrincipal;
|
||||
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_mediakeys_h__
|
||||
@@ -1,42 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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 += [
|
||||
'CDMCallbackProxy.h',
|
||||
'CDMCaps.h',
|
||||
'CDMProxy.h',
|
||||
'EMEUtils.h'
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'CDMCallbackProxy.cpp',
|
||||
'CDMCaps.cpp',
|
||||
'CDMProxy.cpp',
|
||||
'EMEUtils.cpp',
|
||||
'MediaEncryptedEvent.cpp',
|
||||
'MediaKeyError.cpp',
|
||||
'MediaKeyMessageEvent.cpp',
|
||||
'MediaKeys.cpp',
|
||||
'MediaKeySession.cpp',
|
||||
'MediaKeyStatusMap.cpp',
|
||||
'MediaKeySystemAccess.cpp',
|
||||
'MediaKeySystemAccessManager.cpp',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
@@ -9,9 +9,6 @@
|
||||
#include "MediaDecoderStateMachine.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
#include "prlog.h"
|
||||
|
||||
#ifdef XP_WIN
|
||||
@@ -36,25 +33,6 @@ MediaDecoderStateMachine* MP4Decoder::CreateStateMachine()
|
||||
return new MediaDecoderStateMachine(this, new MP4Reader(this));
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MP4Decoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aProxy) {
|
||||
// The MP4Reader can't decrypt EME content until it has a CDMProxy,
|
||||
// and the CDMProxy knows the capabilities of the CDM. The MP4Reader
|
||||
// remains in "waiting for resources" state until then.
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
nsRefPtr<nsIRunnable> task(
|
||||
NS_NewRunnableMethod(this, &MediaDecoder::NotifyWaitingForResourcesStatusChanged));
|
||||
caps.CallOnMainThreadWhenCapsAvailable(task);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool
|
||||
IsSupportedAudioCodec(const nsAString& aCodec,
|
||||
bool& aOutContainsAAC,
|
||||
|
||||
@@ -24,10 +24,6 @@ public:
|
||||
|
||||
virtual MediaDecoderStateMachine* CreateStateMachine() override;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
#endif
|
||||
|
||||
// Returns true if aMIMEType is a type that we think we can render with the
|
||||
// a MP4 platform decoder backend. If aCodecs is non emtpy, it is filled
|
||||
// with a comma-delimited list of codecs to check support for. Notes in
|
||||
|
||||
@@ -22,10 +22,6 @@
|
||||
#include "SharedDecoderManager.h"
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
|
||||
using mozilla::layers::Image;
|
||||
using mozilla::layers::LayerManager;
|
||||
using mozilla::layers::LayersBackend;
|
||||
@@ -263,34 +259,6 @@ MP4Reader::Init(MediaDecoderReader* aCloneDonor)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
class DispatchKeyNeededEvent : public nsRunnable {
|
||||
public:
|
||||
DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
|
||||
nsTArray<uint8_t>& aInitData,
|
||||
const nsString& aInitDataType)
|
||||
: mDecoder(aDecoder)
|
||||
, mInitData(aInitData)
|
||||
, mInitDataType(aInitDataType)
|
||||
{
|
||||
}
|
||||
NS_IMETHOD Run() {
|
||||
// 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:
|
||||
nsRefPtr<AbstractMediaDecoder> mDecoder;
|
||||
nsTArray<uint8_t> mInitData;
|
||||
nsString mInitDataType;
|
||||
};
|
||||
#endif
|
||||
|
||||
void MP4Reader::RequestCodecResource() {
|
||||
if (mVideo.mDecoder) {
|
||||
mVideo.mDecoder->AllocateMediaResources();
|
||||
@@ -302,29 +270,8 @@ bool MP4Reader::IsWaitingOnCodecResource() {
|
||||
}
|
||||
|
||||
bool MP4Reader::IsWaitingOnCDMResource() {
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
if (!mIsEncrypted) {
|
||||
// Not encrypted, no need to wait for CDMProxy.
|
||||
return false;
|
||||
}
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
if (!proxy) {
|
||||
// We're encrypted, we need a CDMProxy to decrypt file.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// We'll keep waiting if the CDM hasn't informed Goanna of its capabilities.
|
||||
{
|
||||
CDMCaps::AutoLock caps(proxy->Capabilites());
|
||||
LOG("capsKnown=%d", caps.AreCapsKnown());
|
||||
return !caps.AreCapsKnown();
|
||||
}
|
||||
#else
|
||||
// EME Stub
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MP4Reader::IsWaitingMediaResources()
|
||||
@@ -411,42 +358,8 @@ MP4Reader::ReadMetadata(MediaInfo* aInfo,
|
||||
}
|
||||
|
||||
if (mDemuxer->Crypto().valid) {
|
||||
#ifdef MOZ_EME
|
||||
// We have encrypted audio or video. We'll need a CDM to decrypt and
|
||||
// possibly decode this. Wait until we've received a CDM from the
|
||||
// JavaScript player app. Note: we still go through the motions here
|
||||
// even if EME is disabled, so that if script tries and fails to create
|
||||
// a CDM, we can detect that and notify chrome and show some UI explaining
|
||||
// that we failed due to EME being disabled.
|
||||
nsRefPtr<CDMProxy> proxy;
|
||||
nsTArray<uint8_t> initData;
|
||||
ExtractCryptoInitData(initData);
|
||||
if (initData.Length() == 0) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (!mInitDataEncountered.Contains(initData)) {
|
||||
mInitDataEncountered.AppendElement(initData);
|
||||
NS_DispatchToMainThread(new DispatchKeyNeededEvent(mDecoder, initData, NS_LITERAL_STRING("cenc")));
|
||||
}
|
||||
if (IsWaitingMediaResources()) {
|
||||
return NS_OK;
|
||||
}
|
||||
MOZ_ASSERT(!IsWaitingMediaResources());
|
||||
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
proxy = mDecoder->GetCDMProxy();
|
||||
}
|
||||
MOZ_ASSERT(proxy);
|
||||
|
||||
mPlatform = PlatformDecoderModule::CreateCDMWrapper(proxy,
|
||||
HasAudio(),
|
||||
HasVideo());
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
#else
|
||||
// EME not supported.
|
||||
return NS_ERROR_FAILURE;
|
||||
#endif
|
||||
} else {
|
||||
mPlatform = PlatformDecoderModule::Create();
|
||||
NS_ENSURE_TRUE(mPlatform, NS_ERROR_FAILURE);
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
#include "GMPDecoderModule.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "EMEDecoderModule.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
#include "SharedThreadPool.h"
|
||||
#include "MediaTaskQueue.h"
|
||||
|
||||
@@ -81,40 +77,6 @@ PlatformDecoderModule::Init()
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
/* static */
|
||||
already_AddRefed<PlatformDecoderModule>
|
||||
PlatformDecoderModule::CreateCDMWrapper(CDMProxy* aProxy,
|
||||
bool aHasAudio,
|
||||
bool aHasVideo)
|
||||
{
|
||||
bool cdmDecodesAudio;
|
||||
bool cdmDecodesVideo;
|
||||
{
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
cdmDecodesAudio = caps.CanDecryptAndDecodeAudio();
|
||||
cdmDecodesVideo = caps.CanDecryptAndDecodeVideo();
|
||||
}
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> pdm;
|
||||
if ((!cdmDecodesAudio && aHasAudio) || (!cdmDecodesVideo && aHasVideo)) {
|
||||
// The CDM itself can't decode. We need to wrap a PDM to decode the
|
||||
// decrypted output of the CDM.
|
||||
pdm = Create();
|
||||
if (!pdm) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<PlatformDecoderModule> emepdm(
|
||||
new AVCCDecoderModule(new EMEDecoderModule(aProxy,
|
||||
pdm,
|
||||
cdmDecodesAudio,
|
||||
cdmDecodesVideo)));
|
||||
return emepdm.forget();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */
|
||||
already_AddRefed<PlatformDecoderModule>
|
||||
PlatformDecoderModule::Create()
|
||||
|
||||
@@ -74,18 +74,6 @@ public:
|
||||
// This is called on the decode task queue.
|
||||
virtual nsresult Startup() { return NS_OK; };
|
||||
|
||||
#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.
|
||||
static already_AddRefed<PlatformDecoderModule>
|
||||
CreateCDMWrapper(CDMProxy* aProxy,
|
||||
bool aHasAudio,
|
||||
bool aHasVideo);
|
||||
#endif
|
||||
|
||||
// Creates an H.264 decoder. The layers backend is passed in so that
|
||||
// decoders can determine whether hardware accelerated decoding can be used.
|
||||
// Asynchronous decoding of video should be done in runnables dispatched
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "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);
|
||||
}
|
||||
|
||||
void
|
||||
EMEAudioDecoder::InitTags(nsTArray<nsCString>& aTags)
|
||||
{
|
||||
GMPAudioDecoder::InitTags(aTags);
|
||||
aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
|
||||
}
|
||||
|
||||
nsCString
|
||||
EMEAudioDecoder::GetNodeId()
|
||||
{
|
||||
return mProxy->GetNodeId();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,44 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef EMEAudioDecoder_h_
|
||||
#define EMEAudioDecoder_h_
|
||||
|
||||
#include "GMPAudioDecoder.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EMEAudioCallbackAdapter : public AudioCallbackAdapter {
|
||||
public:
|
||||
explicit EMEAudioCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback)
|
||||
: AudioCallbackAdapter(aCallback)
|
||||
{}
|
||||
|
||||
virtual void Error(GMPErr aErr) override;
|
||||
};
|
||||
|
||||
class EMEAudioDecoder : public GMPAudioDecoder {
|
||||
public:
|
||||
EMEAudioDecoder(CDMProxy* aProxy,
|
||||
const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
MediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallbackProxy* aCallback)
|
||||
: GMPAudioDecoder(aConfig, aTaskQueue, aCallback, new EMEAudioCallbackAdapter(aCallback))
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void InitTags(nsTArray<nsCString>& aTags) override;
|
||||
virtual nsCString GetNodeId() override;
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
@@ -1,312 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EMEDecoderModule.h"
|
||||
#include "EMEAudioDecoder.h"
|
||||
#include "EMEVideoDecoder.h"
|
||||
#include "MediaDataDecoderProxy.h"
|
||||
#include "mozIGoannaMediaPluginService.h"
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class EMEDecryptor : public MediaDataDecoder {
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
|
||||
public:
|
||||
|
||||
EMEDecryptor(MediaDataDecoder* aDecoder,
|
||||
MediaDataDecoderCallback* aCallback,
|
||||
CDMProxy* aProxy)
|
||||
: mDecoder(aDecoder)
|
||||
, mCallback(aCallback)
|
||||
, mTaskQueue(CreateFlushableMediaDecodeTaskQueue())
|
||||
, mProxy(aProxy)
|
||||
, mSamplesWaitingForKey(new SamplesWaitingForKey(this, mTaskQueue, mProxy))
|
||||
#ifdef DEBUG
|
||||
, mIsShutdown(false)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Init() override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
nsresult rv = mTaskQueue->SyncDispatch(
|
||||
NS_NewRunnableMethod(mDecoder, &MediaDataDecoder::Init));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
class DeliverDecrypted : public DecryptionClient {
|
||||
public:
|
||||
DeliverDecrypted(EMEDecryptor* aDecryptor, FlushableMediaTaskQueue* aTaskQueue)
|
||||
: mDecryptor(aDecryptor)
|
||||
, mTaskQueue(aTaskQueue)
|
||||
{}
|
||||
virtual void Decrypted(GMPErr aResult,
|
||||
mp4_demuxer::MP4Sample* aSample) override {
|
||||
if (aResult == GMPNoKeyErr) {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
|
||||
&EMEDecryptor::Input,
|
||||
aSample);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
} else if (GMP_FAILED(aResult)) {
|
||||
if (mDecryptor->mCallback) {
|
||||
mDecryptor->mCallback->Error();
|
||||
}
|
||||
MOZ_ASSERT(!aSample);
|
||||
} else {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecryptor,
|
||||
&EMEDecryptor::Decrypted,
|
||||
aSample);
|
||||
mTaskQueue->Dispatch(task.forget());
|
||||
}
|
||||
mTaskQueue = nullptr;
|
||||
mDecryptor = nullptr;
|
||||
}
|
||||
private:
|
||||
nsRefPtr<EMEDecryptor> mDecryptor;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
};
|
||||
|
||||
virtual nsresult Input(MP4Sample* aSample) override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
// We run the PDM on its own task queue. We can't run it on the decode
|
||||
// task queue, because that calls into Input() in a loop and waits until
|
||||
// output is delivered. We need to defer some Input() calls while we wait
|
||||
// for keys to become usable, and once they do we need to dispatch an event
|
||||
// to run the PDM on the same task queue, but since the decode task queue
|
||||
// is waiting in MP4Reader::Decode() for output our task would never run.
|
||||
// So we dispatch tasks to make all calls into the wrapped decoder.
|
||||
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mProxy->GetSessionIdsForKeyId(aSample->crypto.key,
|
||||
aSample->crypto.session_ids);
|
||||
|
||||
mProxy->Decrypt(aSample, new DeliverDecrypted(this, mTaskQueue));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Decrypted(mp4_demuxer::MP4Sample* aSample) {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
nsresult rv = mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethodWithArg<mp4_demuxer::MP4Sample*>(
|
||||
mDecoder,
|
||||
&MediaDataDecoder::Input,
|
||||
aSample));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
virtual nsresult Flush() override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
nsresult rv = mTaskQueue->SyncDispatch(
|
||||
NS_NewRunnableMethod(
|
||||
mDecoder,
|
||||
&MediaDataDecoder::Flush));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
mSamplesWaitingForKey->Flush();
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual nsresult Drain() override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
nsresult rv = mTaskQueue->Dispatch(
|
||||
NS_NewRunnableMethod(
|
||||
mDecoder,
|
||||
&MediaDataDecoder::Drain));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
return rv;
|
||||
}
|
||||
|
||||
virtual nsresult Shutdown() override {
|
||||
MOZ_ASSERT(!mIsShutdown);
|
||||
#ifdef DEBUG
|
||||
mIsShutdown = true;
|
||||
#endif
|
||||
nsresult rv = mTaskQueue->SyncDispatch(
|
||||
NS_NewRunnableMethod(
|
||||
mDecoder,
|
||||
&MediaDataDecoder::Shutdown));
|
||||
unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
mSamplesWaitingForKey->BreakCycles();
|
||||
mSamplesWaitingForKey = nullptr;
|
||||
mDecoder = nullptr;
|
||||
mTaskQueue->BeginShutdown();
|
||||
mTaskQueue->AwaitShutdownAndIdle();
|
||||
mTaskQueue = nullptr;
|
||||
mProxy = nullptr;
|
||||
mCallback = nullptr;
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
|
||||
#ifdef DEBUG
|
||||
bool mIsShutdown;
|
||||
#endif
|
||||
};
|
||||
|
||||
class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy {
|
||||
public:
|
||||
EMEMediaDataDecoderProxy(nsIThread* aProxyThread, MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
|
||||
: MediaDataDecoderProxy(aProxyThread, aCallback)
|
||||
, mSamplesWaitingForKey(new SamplesWaitingForKey(this, aTaskQueue, aProxy))
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
}
|
||||
|
||||
virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) override;
|
||||
virtual nsresult Shutdown() override;
|
||||
|
||||
private:
|
||||
nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
};
|
||||
|
||||
nsresult
|
||||
EMEMediaDataDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mProxy->GetSessionIdsForKeyId(aSample->crypto.key,
|
||||
aSample->crypto.session_ids);
|
||||
|
||||
return MediaDataDecoderProxy::Input(aSample);
|
||||
}
|
||||
|
||||
nsresult
|
||||
EMEMediaDataDecoderProxy::Shutdown()
|
||||
{
|
||||
nsresult rv = MediaDataDecoderProxy::Shutdown();
|
||||
|
||||
mSamplesWaitingForKey->BreakCycles();
|
||||
mSamplesWaitingForKey = nullptr;
|
||||
mProxy = nullptr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy,
|
||||
PlatformDecoderModule* aPDM,
|
||||
bool aCDMDecodesAudio,
|
||||
bool aCDMDecodesVideo)
|
||||
: mProxy(aProxy)
|
||||
, mPDM(aPDM)
|
||||
, mCDMDecodesAudio(aCDMDecodesAudio)
|
||||
, mCDMDecodesVideo(aCDMDecodesVideo)
|
||||
{
|
||||
}
|
||||
|
||||
EMEDecoderModule::~EMEDecoderModule()
|
||||
{
|
||||
}
|
||||
|
||||
static already_AddRefed<MediaDataDecoderProxy>
|
||||
CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
|
||||
{
|
||||
nsCOMPtr<mozIGoannaMediaPluginService> gmpService = do_GetService("@mozilla.org/goanna-media-plugin-service;1");
|
||||
if (!gmpService) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = gmpService->GetThread(getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoderProxy> decoder(new EMEMediaDataDecoderProxy(thread, aCallback, aProxy, aTaskQueue));
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (mCDMDecodesVideo && aConfig.crypto.valid) {
|
||||
nsRefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue);
|
||||
wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy,
|
||||
aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
wrapper->Callback()));
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateVideoDecoder(aConfig,
|
||||
aLayersBackend,
|
||||
aImageContainer,
|
||||
aVideoTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aConfig.crypto.valid) {
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mProxy));
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<MediaDataDecoder>
|
||||
EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (mCDMDecodesAudio && aConfig.crypto.valid) {
|
||||
nsRefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue);
|
||||
wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy,
|
||||
aConfig,
|
||||
aAudioTaskQueue,
|
||||
wrapper->Callback()));
|
||||
return wrapper.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAudioDecoder(aConfig,
|
||||
aAudioTaskQueue,
|
||||
aCallback));
|
||||
if (!decoder) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!aConfig.crypto.valid) {
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(decoder,
|
||||
aCallback,
|
||||
mProxy));
|
||||
return emeDecoder.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
EMEDecoderModule::DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig)
|
||||
{
|
||||
return mCDMDecodesVideo && aConfig.crypto.valid;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,61 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#if !defined(EMEDecoderModule_h_)
|
||||
#define EMEDecoderModule_h_
|
||||
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include "gmp-decryption.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
class FlushableMediaTaskQueue;
|
||||
|
||||
class EMEDecoderModule : public PlatformDecoderModule {
|
||||
private:
|
||||
typedef mp4_demuxer::AudioDecoderConfig AudioDecoderConfig;
|
||||
typedef mp4_demuxer::VideoDecoderConfig VideoDecoderConfig;
|
||||
|
||||
public:
|
||||
EMEDecoderModule(CDMProxy* aProxy,
|
||||
PlatformDecoderModule* aPDM,
|
||||
bool aCDMDecodesAudio,
|
||||
bool aCDMDecodesVideo);
|
||||
|
||||
virtual ~EMEDecoderModule();
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateVideoDecoder(const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
FlushableMediaTaskQueue* aVideoTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
// Decode thread.
|
||||
virtual already_AddRefed<MediaDataDecoder>
|
||||
CreateAudioDecoder(const mp4_demuxer::AudioDecoderConfig& aConfig,
|
||||
FlushableMediaTaskQueue* aAudioTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
virtual bool
|
||||
DecoderNeedsAVCC(const mp4_demuxer::VideoDecoderConfig& aConfig) override;
|
||||
|
||||
private:
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
// Will be null if CDM has decoding capability.
|
||||
nsRefPtr<PlatformDecoderModule> mPDM;
|
||||
// We run the PDM on its own task queue.
|
||||
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
|
||||
bool mCDMDecodesAudio;
|
||||
bool mCDMDecodesVideo;
|
||||
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // EMEDecoderModule_h_
|
||||
@@ -1,48 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EMEVideoDecoder.h"
|
||||
#include "GMPVideoEncodedFrameImpl.h"
|
||||
#include "mozilla/CDMProxy.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);
|
||||
}
|
||||
|
||||
void
|
||||
EMEVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
|
||||
{
|
||||
GMPVideoDecoder::InitTags(aTags);
|
||||
aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
|
||||
}
|
||||
|
||||
nsCString
|
||||
EMEVideoDecoder::GetNodeId()
|
||||
{
|
||||
return mProxy->GetNodeId();
|
||||
}
|
||||
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr
|
||||
EMEVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
|
||||
{
|
||||
GMPUnique<GMPVideoEncodedFrame>::Ptr frame = GMPVideoDecoder::CreateFrame(aSample);
|
||||
if (frame && aSample->crypto.valid) {
|
||||
static_cast<gmp::GMPVideoEncodedFrameImpl*>(frame.get())->InitCrypto(aSample->crypto);
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
@@ -1,54 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef EMEVideoDecoder_h_
|
||||
#define EMEVideoDecoder_h_
|
||||
|
||||
#include "GMPVideoDecoder.h"
|
||||
#include "PlatformDecoderModule.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CDMProxy;
|
||||
class MediaTaskQueue;
|
||||
|
||||
class EMEVideoCallbackAdapter : public VideoCallbackAdapter {
|
||||
public:
|
||||
EMEVideoCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback,
|
||||
VideoInfo aVideoInfo,
|
||||
layers::ImageContainer* aImageContainer)
|
||||
: VideoCallbackAdapter(aCallback, aVideoInfo, aImageContainer)
|
||||
{}
|
||||
|
||||
virtual void Error(GMPErr aErr) override;
|
||||
};
|
||||
|
||||
class EMEVideoDecoder : public GMPVideoDecoder {
|
||||
public:
|
||||
EMEVideoDecoder(CDMProxy* aProxy,
|
||||
const mp4_demuxer::VideoDecoderConfig& aConfig,
|
||||
layers::LayersBackend aLayersBackend,
|
||||
layers::ImageContainer* aImageContainer,
|
||||
MediaTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallbackProxy* aCallback)
|
||||
: GMPVideoDecoder(aConfig, aLayersBackend, aImageContainer, aTaskQueue, aCallback,
|
||||
new EMEVideoCallbackAdapter(aCallback, VideoInfo(aConfig.display_width,
|
||||
aConfig.display_height), aImageContainer))
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void InitTags(nsTArray<nsCString>& aTags) override;
|
||||
virtual nsCString GetNodeId() override;
|
||||
virtual GMPUnique<GMPVideoEncodedFrame>::Ptr CreateFrame(mp4_demuxer::MP4Sample* aSample) override;
|
||||
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // EMEVideoDecoder_h_
|
||||
@@ -1,82 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
SamplesWaitingForKey::SamplesWaitingForKey(MediaDataDecoder* aDecoder,
|
||||
MediaTaskQueue* aTaskQueue,
|
||||
CDMProxy* aProxy)
|
||||
: mMutex("SamplesWaitingForKey")
|
||||
, mDecoder(aDecoder)
|
||||
, mTaskQueue(aTaskQueue)
|
||||
, mProxy(aProxy)
|
||||
{
|
||||
}
|
||||
|
||||
SamplesWaitingForKey::~SamplesWaitingForKey()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
SamplesWaitingForKey::WaitIfKeyNotUsable(MP4Sample* aSample)
|
||||
{
|
||||
if (!aSample || !aSample->crypto.valid || !mProxy) {
|
||||
return false;
|
||||
}
|
||||
CDMCaps::AutoLock caps(mProxy->Capabilites());
|
||||
const auto& keyid = aSample->crypto.key;
|
||||
if (!caps.IsKeyUsable(keyid)) {
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mSamples.AppendElement(aSample);
|
||||
}
|
||||
caps.NotifyWhenKeyIdUsable(aSample->crypto.key, 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]->crypto.key) {
|
||||
RefPtr<nsIRunnable> task;
|
||||
task = NS_NewRunnableMethodWithArg<MP4Sample*>(mDecoder,
|
||||
&MediaDataDecoder::Input,
|
||||
mSamples[i].forget());
|
||||
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
|
||||
@@ -1,57 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SamplesWaitingForKey_h_
|
||||
#define SamplesWaitingForKey_h_
|
||||
|
||||
#include "mp4_demuxer/DecoderData.h"
|
||||
#include "MediaTaskQueue.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 decypt a given sample.
|
||||
class SamplesWaitingForKey {
|
||||
typedef mp4_demuxer::MP4Sample MP4Sample;
|
||||
public:
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SamplesWaitingForKey)
|
||||
|
||||
explicit SamplesWaitingForKey(MediaDataDecoder* aDecoder,
|
||||
MediaTaskQueue* 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(MP4Sample* aSample);
|
||||
|
||||
void NotifyUsable(const CencKeyId& aKeyId);
|
||||
|
||||
void Flush();
|
||||
|
||||
void BreakCycles();
|
||||
|
||||
protected:
|
||||
~SamplesWaitingForKey();
|
||||
|
||||
private:
|
||||
Mutex mMutex;
|
||||
nsRefPtr<MediaDataDecoder> mDecoder;
|
||||
nsRefPtr<MediaTaskQueue> mTaskQueue;
|
||||
nsRefPtr<CDMProxy> mProxy;
|
||||
nsTArray<nsAutoPtr<MP4Sample>> mSamples;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // SamplesWaitingForKey_h_
|
||||
@@ -1,28 +0,0 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
DEFINES['NOMINMAX'] = True
|
||||
@@ -31,9 +31,6 @@ DIRS += ['gmp']
|
||||
if CONFIG['MOZ_WMF']:
|
||||
DIRS += [ 'wmf' ];
|
||||
|
||||
if CONFIG['MOZ_EME']:
|
||||
DIRS += ['eme']
|
||||
|
||||
if CONFIG['MOZ_FFMPEG']:
|
||||
EXPORTS += [
|
||||
'ffmpeg/FFmpegRuntimeLinker.h',
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIGfxInfo.h"
|
||||
#include "GfxDriverInfo.h"
|
||||
#include "nsServiceManagerUtils.h" // for do_GetService
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "gtest/gtest.h"
|
||||
#include "mozilla/EMEUtils.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace mozilla;
|
||||
|
||||
struct ParseKeySystemTestCase {
|
||||
const char16_t* mInputKeySystemString;
|
||||
int32_t mOutCDMVersion;
|
||||
bool mShouldPass;
|
||||
};
|
||||
|
||||
const ParseKeySystemTestCase ParseKeySystemTests[] = {
|
||||
{
|
||||
MOZ_UTF16("org.w3.clearkey"),
|
||||
NO_CDM_VERSION,
|
||||
true,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.123"),
|
||||
123,
|
||||
true,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.-1"),
|
||||
NO_CDM_VERSION,
|
||||
false,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.NaN"),
|
||||
NO_CDM_VERSION,
|
||||
false,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.0"),
|
||||
0,
|
||||
true,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.123567890123567890123567890123567890123567890"),
|
||||
NO_CDM_VERSION,
|
||||
false,
|
||||
}, {
|
||||
MOZ_UTF16("org.w3.clearkey.0.1"),
|
||||
NO_CDM_VERSION,
|
||||
false,
|
||||
}
|
||||
};
|
||||
|
||||
TEST(EME, EMEParseKeySystem) {
|
||||
const nsAutoString clearkey(MOZ_UTF16("org.w3.clearkey"));
|
||||
for (const ParseKeySystemTestCase& test : ParseKeySystemTests) {
|
||||
nsAutoString keySystem;
|
||||
int32_t version;
|
||||
bool rv = ParseKeySystem(nsDependentString(test.mInputKeySystemString),
|
||||
keySystem,
|
||||
version);
|
||||
EXPECT_EQ(rv, test.mShouldPass) << "parse should succeed if expected to";
|
||||
if (!test.mShouldPass) {
|
||||
continue;
|
||||
}
|
||||
EXPECT_TRUE(keySystem.Equals(clearkey)) << NS_ConvertUTF16toUTF8(keySystem).get(); //"should extract expected keysystem" << ;
|
||||
EXPECT_EQ(test.mOutCDMVersion, version) << "should extract expected version";
|
||||
}
|
||||
}
|
||||
@@ -15,11 +15,6 @@ SOURCES += [
|
||||
'TestWebMBuffered.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_EME']:
|
||||
SOURCES += [
|
||||
'TestEME.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBM_ENCODER']:
|
||||
SOURCES += [
|
||||
'TestVideoTrackEncoder.cpp',
|
||||
|
||||
@@ -296,19 +296,6 @@ MediaSourceDecoder::GetMozDebugReaderData(nsAString& aString)
|
||||
mReader->GetMozDebugReaderData(aString);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceDecoder::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
nsresult rv = MediaDecoder::SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mReader->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
MediaSourceDecoder::IsActiveReader(MediaDecoderReader* aReader)
|
||||
{
|
||||
|
||||
@@ -72,10 +72,6 @@ public:
|
||||
// registered TrackBuffers essential for initialization.
|
||||
void PrepareReaderInitialization();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override;
|
||||
#endif
|
||||
|
||||
MediaSourceReader* GetReader() { return mReader; }
|
||||
|
||||
// Returns true if aReader is a currently active audio or video
|
||||
|
||||
@@ -702,9 +702,6 @@ MediaSourceReader::CreateSubDecoder(const nsACString& aType, int64_t aTimestampO
|
||||
MSE_DEBUG("subdecoder %p subreader %p",
|
||||
decoder.get(), reader.get());
|
||||
decoder->SetReader(reader);
|
||||
#ifdef MOZ_EME
|
||||
decoder->SetCDMProxy(mCDMProxy);
|
||||
#endif
|
||||
return decoder.forget();
|
||||
}
|
||||
|
||||
@@ -1233,22 +1230,6 @@ MediaSourceReader::GetMozDebugReaderData(nsAString& aString)
|
||||
aString += NS_ConvertUTF8toUTF16(result);
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
MediaSourceReader::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
|
||||
|
||||
mCDMProxy = aProxy;
|
||||
for (size_t i = 0; i < mTrackBuffers.Length(); i++) {
|
||||
nsresult rv = mTrackBuffers[i]->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
MediaSourceReader::IsActiveReader(MediaDecoderReader* aReader)
|
||||
{
|
||||
|
||||
@@ -143,10 +143,6 @@ public:
|
||||
// Set the duration of the attached mediasource element.
|
||||
void SetMediaSourceDuration(double aDuration /* seconds */);
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
virtual bool IsAsync() const override {
|
||||
return (!GetAudioReader() || GetAudioReader()->IsAsync()) &&
|
||||
(!GetVideoReader() || GetVideoReader()->IsAsync());
|
||||
@@ -246,10 +242,6 @@ private:
|
||||
return aType == MediaData::AUDIO_DATA ? mAudioWaitPromise : mVideoWaitPromise;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
#endif
|
||||
|
||||
// These are read and written on the decode task queue threads.
|
||||
int64_t mLastAudioTime;
|
||||
int64_t mLastVideoTime;
|
||||
|
||||
@@ -11,9 +11,6 @@
|
||||
#include "MediaDecoderReader.h"
|
||||
#include "SourceBufferResource.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#ifdef MOZ_EME
|
||||
#include "mozilla/CDMProxy.h"
|
||||
#endif
|
||||
#include "mozilla/ReentrantMonitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
@@ -99,28 +96,8 @@ public:
|
||||
mReader = nullptr;
|
||||
}
|
||||
mTaskQueue = nullptr;
|
||||
#ifdef MOZ_EME
|
||||
mCDMProxy = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
virtual nsresult SetCDMProxy(CDMProxy* aProxy) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
mCDMProxy = aProxy;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual CDMProxy* GetCDMProxy() override
|
||||
{
|
||||
MOZ_ASSERT(OnDecodeThread() || NS_IsMainThread());
|
||||
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
|
||||
return mCDMProxy;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Given a time convert it into an approximate byte offset from the
|
||||
// cached data. Returns -1 if no such value is computable.
|
||||
int64_t ConvertToByteOffset(double aTime);
|
||||
@@ -163,10 +140,6 @@ private:
|
||||
int64_t mRealMediaDuration;
|
||||
// in seconds
|
||||
double mTrimmedOffset;
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsRefPtr<CDMProxy> mCDMProxy;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
@@ -869,31 +869,6 @@ TrackBuffer::Decoders()
|
||||
return mInitializedDecoders;
|
||||
}
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult
|
||||
TrackBuffer::SetCDMProxy(CDMProxy* aProxy)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mParentDecoder->GetReentrantMonitor());
|
||||
|
||||
for (uint32_t i = 0; i < mDecoders.Length(); ++i) {
|
||||
nsresult rv = mDecoders[i]->SetCDMProxy(aProxy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mWaitingDecoders.Length(); ++i) {
|
||||
CDMCaps::AutoLock caps(aProxy->Capabilites());
|
||||
caps.CallOnMainThreadWhenCapsAvailable(
|
||||
NS_NewRunnableMethodWithArg<SourceBufferDecoder*>(this,
|
||||
&TrackBuffer::QueueInitializeDecoder,
|
||||
mWaitingDecoders[i]));
|
||||
}
|
||||
|
||||
mWaitingDecoders.Clear();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
void
|
||||
TrackBuffer::Dump(const char* aPath)
|
||||
|
||||
@@ -110,10 +110,6 @@ public:
|
||||
// currently not playable.
|
||||
bool HasOnlyIncompleteMedia();
|
||||
|
||||
#ifdef MOZ_EME
|
||||
nsresult SetCDMProxy(CDMProxy* aProxy);
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG)
|
||||
void Dump(const char* aPath);
|
||||
#endif
|
||||
|
||||
@@ -53,9 +53,6 @@ if CONFIG['MOZ_OMX_DECODER']:
|
||||
DIRS += ['omx']
|
||||
DIRS += ['omx/mediaresourcemanager']
|
||||
|
||||
if CONFIG['MOZ_EME']:
|
||||
DIRS += ['eme']
|
||||
|
||||
TEST_DIRS += [
|
||||
'compiledtest',
|
||||
'gtest',
|
||||
|
||||
@@ -294,12 +294,6 @@ AudioContext::CreateMediaElementSource(HTMLMediaElement& aMediaElement,
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
#ifdef MOZ_EME
|
||||
if (aMediaElement.ContainsRestrictedContent()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
return nullptr;
|
||||
}
|
||||
#endif
|
||||
nsRefPtr<DOMMediaStream> stream = aMediaElement.MozCaptureStream(aRv);
|
||||
if (aRv.Failed()) {
|
||||
return nullptr;
|
||||
|
||||
@@ -141,18 +141,3 @@ partial interface HTMLMediaElement {
|
||||
// because of the audiochannel manager.
|
||||
// * onmozinterruptend - called when the interruption is concluded
|
||||
};
|
||||
|
||||
#ifdef MOZ_EME
|
||||
// Encrypted Media Extensions
|
||||
partial interface HTMLMediaElement {
|
||||
[Pref="media.eme.apiVisible"]
|
||||
readonly attribute MediaKeys? mediaKeys;
|
||||
|
||||
// void, not any: https://www.w3.org/Bugs/Public/show_bug.cgi?id=26457
|
||||
[Pref="media.eme.apiVisible", NewObject]
|
||||
Promise<void> setMediaKeys(MediaKeys? mediaKeys);
|
||||
|
||||
[Pref="media.eme.apiVisible"]
|
||||
attribute EventHandler onencrypted;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="media.eme.apiVisible", Constructor(DOMString type, optional MediaKeyNeededEventInit eventInitDict)]
|
||||
interface MediaEncryptedEvent : Event {
|
||||
readonly attribute DOMString initDataType;
|
||||
[Throws]
|
||||
readonly attribute ArrayBuffer? initData;
|
||||
};
|
||||
|
||||
dictionary MediaKeyNeededEventInit : EventInit {
|
||||
DOMString initDataType = "";
|
||||
ArrayBuffer? initData = null;
|
||||
};
|
||||
@@ -1,19 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
// According to the spec, "The future of error events and MediaKeyError
|
||||
// is uncertain."
|
||||
// https://www.w3.org/Bugs/Public/show_bug.cgi?id=21798
|
||||
[Pref="media.eme.apiVisible"]
|
||||
interface MediaKeyError : Event {
|
||||
readonly attribute unsigned long systemCode;
|
||||
};
|
||||
@@ -1,30 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum MediaKeyMessageType {
|
||||
"license-request",
|
||||
"license-renewal",
|
||||
"license-release",
|
||||
"individualization-request"
|
||||
};
|
||||
|
||||
[Pref="media.eme.apiVisible", Constructor(DOMString type, optional MediaKeyMessageEventInit eventInitDict)]
|
||||
interface MediaKeyMessageEvent : Event {
|
||||
readonly attribute MediaKeyMessageType messageType;
|
||||
[Throws]
|
||||
readonly attribute ArrayBuffer message;
|
||||
};
|
||||
|
||||
dictionary MediaKeyMessageEventInit : EventInit {
|
||||
MediaKeyMessageType messageType = "license-request";
|
||||
ArrayBuffer message;
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="media.eme.apiVisible"]
|
||||
interface MediaKeySession : EventTarget {
|
||||
// error state
|
||||
readonly attribute MediaKeyError? error;
|
||||
|
||||
// session properties
|
||||
readonly attribute DOMString keySystem;
|
||||
readonly attribute DOMString sessionId;
|
||||
|
||||
readonly attribute unrestricted double expiration;
|
||||
|
||||
readonly attribute Promise<void> closed;
|
||||
|
||||
readonly attribute MediaKeyStatusMap keyStatuses;
|
||||
|
||||
[NewObject]
|
||||
Promise<void> generateRequest(DOMString initDataType, BufferSource initData);
|
||||
|
||||
[NewObject]
|
||||
Promise<boolean> load(DOMString sessionId);
|
||||
|
||||
// session operations
|
||||
[NewObject]
|
||||
Promise<void> update(BufferSource response);
|
||||
|
||||
[NewObject]
|
||||
Promise<void> close();
|
||||
|
||||
[NewObject]
|
||||
Promise<void> remove();
|
||||
};
|
||||
@@ -1,36 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum MediaKeyStatus {
|
||||
"usable",
|
||||
"expired",
|
||||
"output-downscaled",
|
||||
"output-not-allowed",
|
||||
"internal-error"
|
||||
};
|
||||
|
||||
[Pref="media.eme.apiVisible"]
|
||||
interface MediaKeyStatusMap {
|
||||
[Throws]
|
||||
readonly attribute unsigned long size;
|
||||
|
||||
[Throws]
|
||||
object keys();
|
||||
|
||||
[Throws]
|
||||
object values();
|
||||
|
||||
[Throws]
|
||||
object entries();
|
||||
|
||||
// XXX: forEach, @@iterator
|
||||
};
|
||||
@@ -1,34 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum MediaKeysRequirement {
|
||||
"required",
|
||||
"optional",
|
||||
"disallowed"
|
||||
};
|
||||
|
||||
dictionary MediaKeySystemOptions {
|
||||
DOMString initDataType = "";
|
||||
DOMString audioType = "";
|
||||
DOMString audioCapability = "";
|
||||
DOMString videoType = "";
|
||||
DOMString videoCapability = "";
|
||||
MediaKeysRequirement uniqueidentifier = "optional";
|
||||
MediaKeysRequirement stateful = "optional";
|
||||
};
|
||||
|
||||
[Pref="media.eme.apiVisible"]
|
||||
interface MediaKeySystemAccess {
|
||||
readonly attribute DOMString keySystem;
|
||||
[NewObject]
|
||||
Promise<MediaKeys> createMediaKeys();
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
|
||||
*
|
||||
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
|
||||
* W3C liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum IsTypeSupportedResult { "" /* empty string */, "maybe", "probably" };
|
||||
enum SessionType { "temporary", "persistent" };
|
||||
|
||||
[Pref="media.eme.apiVisible"]
|
||||
interface MediaKeys {
|
||||
readonly attribute DOMString keySystem;
|
||||
|
||||
[NewObject, Throws]
|
||||
MediaKeySession createSession(optional SessionType sessionType = "temporary");
|
||||
|
||||
[NewObject]
|
||||
Promise<void> setServerCertificate((ArrayBufferView or ArrayBuffer) serverCertificate);
|
||||
};
|
||||
@@ -1,21 +0,0 @@
|
||||
/* -*- Mode: IDL; 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/.
|
||||
*/
|
||||
|
||||
enum MediaKeySystemStatus {
|
||||
"available",
|
||||
"api-disabled",
|
||||
"cdm-disabled",
|
||||
"cdm-not-supported",
|
||||
"cdm-not-installed",
|
||||
"cdm-insufficient-version",
|
||||
"cdm-created",
|
||||
"error"
|
||||
};
|
||||
|
||||
dictionary RequestMediaKeySystemAccessNotification {
|
||||
required DOMString keySystem;
|
||||
required MediaKeySystemStatus status;
|
||||
};
|
||||
@@ -412,15 +412,6 @@ partial interface Navigator {
|
||||
readonly attribute TVManager? tv;
|
||||
};
|
||||
|
||||
#ifdef MOZ_EME
|
||||
partial interface Navigator {
|
||||
[Pref="media.eme.apiVisible", NewObject]
|
||||
Promise<MediaKeySystemAccess>
|
||||
requestMediaKeySystemAccess(DOMString keySystem,
|
||||
optional sequence<MediaKeySystemOptions> supportedConfigurations);
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
partial interface Navigator {
|
||||
[Func="Navigator::IsE10sEnabled"]
|
||||
|
||||
@@ -808,18 +808,6 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser', 'mobile/android', 'xulrunner']:
|
||||
'External.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_EME']:
|
||||
WEBIDL_FILES += [
|
||||
'MediaEncryptedEvent.webidl',
|
||||
'MediaKeyError.webidl',
|
||||
'MediaKeyMessageEvent.webidl',
|
||||
'MediaKeys.webidl',
|
||||
'MediaKeySession.webidl',
|
||||
'MediaKeysRequestStatus.webidl',
|
||||
'MediaKeyStatusMap.webidl',
|
||||
'MediaKeySystemAccess.webidl',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_PAY']:
|
||||
WEBIDL_FILES += [
|
||||
'MozPaymentProvider.webidl'
|
||||
|
||||
@@ -6669,12 +6669,6 @@ nsLayoutUtils::SurfaceFromElement(HTMLVideoElement* aElement,
|
||||
|
||||
NS_WARN_IF_FALSE((aSurfaceFlags & SFE_PREFER_NO_PREMULTIPLY_ALPHA) == 0, "We can't support non-premultiplied alpha for video!");
|
||||
|
||||
#ifdef MOZ_EME
|
||||
if (aElement->ContainsRestrictedContent()) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint16_t readyState;
|
||||
if (NS_SUCCEEDED(aElement->GetReadyState(&readyState)) &&
|
||||
(readyState == nsIDOMHTMLMediaElement::HAVE_NOTHING ||
|
||||
|
||||
Reference in New Issue
Block a user