From a050ce3db572776db93174bee15d18aefefcf736 Mon Sep 17 00:00:00 2001 From: Blake Kaplan Date: Tue, 18 Nov 2014 13:38:39 -0800 Subject: [PATCH 01/84] Bug 1093607 - Enable this test. r=mmc/sworkman --- browser/base/content/test/general/browser.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/browser/base/content/test/general/browser.ini b/browser/base/content/test/general/browser.ini index d16d43838a60..08760a045a0e 100644 --- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -442,7 +442,6 @@ skip-if = e10s # Bug ?????? - test needs to be updated for e10s (captures a stac skip-if = e10s # Bug 1100664 - test relies on linkedBrowser.docShell [browser_tabs_owner.js] [browser_trackingUI.js] -skip-if = e10s # Bug 1093155 - tries to use context menu from browser-chrome and gets in a mess when in e10s mode support-files = trackingPage.html benignPage.html From bf9df9f607bb5132fc9fc2394154caa98dbe797f Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Tue, 18 Nov 2014 22:13:02 +1300 Subject: [PATCH 02/84] Bug 1095257 - Implement Navigator.requestMediaKeySystemAccess(). r=edwin r=bz r=peterv --- dom/base/Navigator.cpp | 38 +++ dom/base/Navigator.h | 10 + dom/media/DecoderTraits.cpp | 3 +- dom/media/eme/MediaKeySystemAccess.cpp | 212 +++++++++++++ dom/media/eme/MediaKeySystemAccess.h | 58 ++++ dom/media/eme/MediaKeys.cpp | 128 -------- dom/media/eme/MediaKeys.h | 20 +- dom/media/eme/moz.build | 2 + dom/media/fmp4/MP4Decoder.cpp | 41 ++- dom/media/fmp4/MP4Decoder.h | 8 +- dom/media/test/eme.js | 44 ++- dom/media/test/mochitest.ini | 2 + dom/media/test/test_eme_playback.html | 18 -- .../test/test_eme_requestKeySystemAccess.html | 293 ++++++++++++++++++ .../mochitest/general/test_interfaces.html | 2 + dom/webidl/MediaKeySystemAccess.webidl | 34 ++ dom/webidl/MediaKeys.webidl | 5 - dom/webidl/Navigator.webidl | 9 + dom/webidl/moz.build | 1 + 19 files changed, 732 insertions(+), 196 deletions(-) create mode 100644 dom/media/eme/MediaKeySystemAccess.cpp create mode 100644 dom/media/eme/MediaKeySystemAccess.h create mode 100644 dom/media/test/test_eme_requestKeySystemAccess.html create mode 100644 dom/webidl/MediaKeySystemAccess.webidl diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index 1ea41fb2179b..053c4190c67f 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -2533,5 +2533,43 @@ Navigator::GetUserAgent(nsPIDOMWindow* aWindow, nsIURI* aURI, return siteSpecificUA->GetUserAgentForURIAndWindow(aURI, aWindow, aUserAgent); } +#ifdef MOZ_EME +already_AddRefed +Navigator::RequestMediaKeySystemAccess(const nsAString& aKeySystem, + const Optional>& aOptions, + ErrorResult& aRv) +{ + nsCOMPtr go = do_QueryInterface(mWindow); + nsRefPtr p = Promise::Create(go, aRv); + if (aRv.Failed()) { + return nullptr; + } + + if (aKeySystem.IsEmpty() || + (aOptions.WasPassed() && aOptions.Value().IsEmpty())) { + p->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR); + return p.forget(); + } + + if (!MediaKeySystemAccess::IsKeySystemSupported(aKeySystem)) { + p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return p.forget(); + } + + // TODO: Wait (async) until the CDM is downloaded, if it's not already. + + if (!aOptions.WasPassed() || + MediaKeySystemAccess::IsSupported(aKeySystem, aOptions.Value())) { + nsRefPtr access(new MediaKeySystemAccess(mWindow, aKeySystem)); + p->MaybeResolve(access); + return p.forget(); + } + + p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + + return p.forget(); +} +#endif + } // namespace dom } // namespace mozilla diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index 900a65796039..180cbc71aa6b 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -18,6 +18,9 @@ #include "nsInterfaceHashtable.h" #include "nsString.h" #include "nsTArray.h" +#ifdef MOZ_EME +#include "mozilla/dom/MediaKeySystemAccess.h" +#endif class nsPluginArray; class nsMimeTypeArray; @@ -316,6 +319,13 @@ public: virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE; +#ifdef MOZ_EME + already_AddRefed + RequestMediaKeySystemAccess(const nsAString& aKeySystem, + const Optional>& aOptions, + ErrorResult& aRv); +#endif + private: virtual ~Navigator(); diff --git a/dom/media/DecoderTraits.cpp b/dom/media/DecoderTraits.cpp index 68efb4599bce..0c49c8b0abe9 100644 --- a/dom/media/DecoderTraits.cpp +++ b/dom/media/DecoderTraits.cpp @@ -335,8 +335,9 @@ IsMP4SupportedType(const nsACString& aType, #ifdef MOZ_OMX_DECODER return false; #else + bool haveAAC, haveMP3, haveH264; return Preferences::GetBool("media.fragmented-mp4.exposed", false) && - MP4Decoder::CanHandleMediaType(aType, aCodecs); + MP4Decoder::CanHandleMediaType(aType, aCodecs, haveAAC, haveH264, haveMP3); #endif } #endif diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp new file mode 100644 index 000000000000..6d596cfb6941 --- /dev/null +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -0,0 +1,212 @@ +/* -*- 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" +#endif +#include "nsContentCID.h" +#include "nsServiceManagerUtils.h" +#include "mozIGeckoMediaPluginService.h" +#include "VideoUtils.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 +MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv) +{ + nsRefPtr keys(new MediaKeys(mParent, mKeySystem)); + return keys->Init(aRv); +} + +static bool +HaveGMPFor(mozIGeckoMediaPluginService* aGMPService, + const nsCString& aKeySystem, + const nsCString& aAPI, + const nsCString& aTag = EmptyCString()) +{ + nsTArray tags; + tags.AppendElement(aKeySystem); + if (!aTag.IsEmpty()) { + tags.AppendElement(aTag); + } + // Note: EME plugins need a non-null nodeId here, as they must + // not be shared across origins. + bool hasPlugin = false; + if (NS_FAILED(aGMPService->HasPluginForAPI(aAPI, + &tags, + &hasPlugin))) { + return false; + } + return hasPlugin; +} + +/* static */ +bool +MediaKeySystemAccess::IsKeySystemSupported(const nsAString& aKeySystem) +{ + nsCOMPtr mps = + do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + if (NS_WARN_IF(!mps)) { + return false; + } + + if (aKeySystem.EqualsLiteral("org.w3.clearkey") && + HaveGMPFor(mps, + NS_LITERAL_CSTRING("org.w3.clearkey"), + NS_LITERAL_CSTRING("eme-decrypt"))) { + return true; + } + +#ifdef XP_WIN + if (aKeySystem.EqualsLiteral("com.adobe.access") && + Preferences::GetBool("media.eme.adobe-access.enabled", false) && + IsVistaOrLater() && // Win Vista and later only. + HaveGMPFor(mps, + NS_LITERAL_CSTRING("com.adobe.access"), + NS_LITERAL_CSTRING("eme-decrypt"))) { + return true; + } +#endif + + return false; +} + +static bool +IsPlayableWithGMP(mozIGeckoMediaPluginService* 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("eme-decrypt"), + NS_LITERAL_CSTRING("aac"))) && + (!hasH264 || !HaveGMPFor(aGMPS, + NS_ConvertUTF16toUTF8(aKeySystem), + NS_LITERAL_CSTRING("eme-decrypt"), + NS_LITERAL_CSTRING("h264"))); +#else + return false; +#endif +} + +/* static */ +bool +MediaKeySystemAccess::IsSupported(const nsAString& aKeySystem, + const Sequence& aOptions) +{ + nsCOMPtr mps = + do_GetService("@mozilla.org/gecko-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; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/eme/MediaKeySystemAccess.h b/dom/media/eme/MediaKeySystemAccess.h new file mode 100644 index 000000000000..9fbe23573359 --- /dev/null +++ b/dom/media/eme/MediaKeySystemAccess.h @@ -0,0 +1,58 @@ +/* -*- 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 "js/TypeDecls.h" + +namespace mozilla { +namespace dom { + +class MediaKeySystemAccess MOZ_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) MOZ_OVERRIDE; + + void GetKeySystem(nsString& aRetVal) const; + + already_AddRefed CreateMediaKeys(ErrorResult& aRv); + + static bool IsKeySystemSupported(const nsAString& aKeySystem); + + static bool IsSupported(const nsAString& aKeySystem, + const Sequence& aOptions); + +private: + nsCOMPtr mParent; + const nsString mKeySystem; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_MediaKeySystemAccess_h diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index 02453ff4cd18..8c2d1601ce77 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -114,111 +114,6 @@ MediaKeys::SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aCert, Error return promise.forget(); } -static bool -HaveGMPFor(const nsCString& aKeySystem, - const nsCString& aAPI, - const nsCString& aTag = EmptyCString()) -{ - nsCOMPtr mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - if (NS_WARN_IF(!mps)) { - return false; - } - - nsTArray tags; - tags.AppendElement(aKeySystem); - if (!aTag.IsEmpty()) { - tags.AppendElement(aTag); - } - // Note: EME plugins need a non-null nodeId here, as they must - // not be shared across origins. - bool hasPlugin = false; - if (NS_FAILED(mps->HasPluginForAPI(aAPI, - &tags, - &hasPlugin))) { - return false; - } - return hasPlugin; -} - -static bool -IsPlayableMP4Type(const nsAString& aContentType) -{ -#ifdef MOZ_FMP4 - nsContentTypeParser parser(aContentType); - nsAutoString mimeType; - nsresult rv = parser.GetType(mimeType); - if (NS_FAILED(rv)) { - return false; - } - nsAutoString codecs; - parser.GetParameter("codecs", codecs); - - NS_ConvertUTF16toUTF8 mimeTypeUTF8(mimeType); - return MP4Decoder::CanHandleMediaType(mimeTypeUTF8, codecs); -#else - return false; -#endif -} - -bool -MediaKeys::IsTypeSupported(const nsAString& aKeySystem, - const Optional& aInitDataType, - const Optional& aContentType) -{ - if (aKeySystem.EqualsLiteral("org.w3.clearkey") && - (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) && - (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) && - HaveGMPFor(NS_LITERAL_CSTRING("org.w3.clearkey"), - NS_LITERAL_CSTRING("eme-decrypt"))) { - return true; - } - -#ifdef XP_WIN - // Note: Adobe Access's GMP uses WMF to decode, so anything our MP4Reader - // thinks it can play on Windows, the Access GMP should be able to play. - if (aKeySystem.EqualsLiteral("com.adobe.access") && - Preferences::GetBool("media.eme.adobe-access.enabled", false) && - IsVistaOrLater() && // Win Vista and later only. - (!aInitDataType.WasPassed() || aInitDataType.Value().EqualsLiteral("cenc")) && - (!aContentType.WasPassed() || IsPlayableMP4Type(aContentType.Value())) && - HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"), - NS_LITERAL_CSTRING("eme-decrypt")) && - HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"), - NS_LITERAL_CSTRING("decode-video"), - NS_LITERAL_CSTRING("h264")) && - HaveGMPFor(NS_LITERAL_CSTRING("com.adobe.access"), - NS_LITERAL_CSTRING("decode-audio"), - NS_LITERAL_CSTRING("aac"))) { - return true; - } -#endif - - return false; -} - -/* static */ -IsTypeSupportedResult -MediaKeys::IsTypeSupported(const GlobalObject& aGlobal, - const nsAString& aKeySystem, - const Optional& aInitDataType, - const Optional& aContentType, - const Optional& aCapability) -{ - // TODO: Should really get spec changed to this is async, so we can wait - // for user to consent to running plugin. - bool supported = IsTypeSupported(aKeySystem, aInitDataType, aContentType); - - EME_LOG("MediaKeys::IsTypeSupported keySystem='%s' initDataType='%s' contentType='%s' supported=%d", - NS_ConvertUTF16toUTF8(aKeySystem).get(), - (aInitDataType.WasPassed() ? NS_ConvertUTF16toUTF8(aInitDataType.Value()).get() : ""), - (aContentType.WasPassed() ? NS_ConvertUTF16toUTF8(aContentType.Value()).get() : ""), - supported); - - return supported ? IsTypeSupportedResult::Probably - : IsTypeSupportedResult::_empty; -} - already_AddRefed MediaKeys::MakePromise(ErrorResult& aRv) { @@ -303,24 +198,6 @@ MediaKeys::ResolvePromise(PromiseId aId) } } -/* static */ -already_AddRefed -MediaKeys::Create(const GlobalObject& aGlobal, - const nsAString& aKeySystem, - ErrorResult& aRv) -{ - // CDMProxy keeps MediaKeys alive until it resolves the promise and thus - // returns the MediaKeys object to JS. - nsCOMPtr window = do_QueryInterface(aGlobal.GetAsSupports()); - if (!window || !window->GetExtantDoc()) { - aRv.Throw(NS_ERROR_FAILURE); - return nullptr; - } - - nsRefPtr keys = new MediaKeys(window, aKeySystem); - return keys->Init(aRv); -} - already_AddRefed MediaKeys::Init(ErrorResult& aRv) { @@ -329,11 +206,6 @@ MediaKeys::Init(ErrorResult& aRv) return nullptr; } - if (!IsTypeSupported(mKeySystem)) { - promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); - return promise.forget(); - } - mProxy = new CDMProxy(this, mKeySystem); // Determine principal (at creation time) of the MediaKeys object. diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h index e0cf26b67b91..5585feda232f 100644 --- a/dom/media/eme/MediaKeys.h +++ b/dom/media/eme/MediaKeys.h @@ -53,6 +53,8 @@ public: MediaKeys(nsPIDOMWindow* aParentWindow, const nsAString& aKeySystem); + already_AddRefed Init(ErrorResult& aRv); + nsPIDOMWindow* GetParentObject() const; virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; @@ -70,19 +72,6 @@ public: already_AddRefed SetServerCertificate(const ArrayBufferViewOrArrayBuffer& aServerCertificate, ErrorResult& aRv); - // JavaScript: MediaKeys.create() - static - already_AddRefed Create(const GlobalObject& aGlobal, - const nsAString& aKeySystem, - ErrorResult& aRv); - - // JavaScript: MediaKeys.IsTypeSupported() - static IsTypeSupportedResult IsTypeSupported(const GlobalObject& aGlobal, - const nsAString& aKeySystem, - const Optional& aInitDataType, - const Optional& aContentType, - const Optional& aCapability); - already_AddRefed GetSession(const nsAString& aSessionId); // Called once a Create() operation succeeds. @@ -128,12 +117,7 @@ public: private: - static bool IsTypeSupported(const nsAString& aKeySystem, - const Optional& aInitDataType = Optional(), - const Optional& aContentType = Optional()); - bool IsInPrivateBrowsing(); - already_AddRefed Init(ErrorResult& aRv); // Removes promise from mPromises, and returns it. already_AddRefed RetrievePromise(PromiseId aId); diff --git a/dom/media/eme/moz.build b/dom/media/eme/moz.build index 838156d0b99c..6e3d3532be02 100644 --- a/dom/media/eme/moz.build +++ b/dom/media/eme/moz.build @@ -10,6 +10,7 @@ EXPORTS.mozilla.dom += [ 'MediaKeyMessageEvent.h', 'MediaKeys.h', 'MediaKeySession.h', + 'MediaKeySystemAccess.h', ] EXPORTS.mozilla += [ @@ -29,6 +30,7 @@ UNIFIED_SOURCES += [ 'MediaKeyMessageEvent.cpp', 'MediaKeys.cpp', 'MediaKeySession.cpp', + 'MediaKeySystemAccess.cpp', ] FINAL_LIBRARY = 'xul' diff --git a/dom/media/fmp4/MP4Decoder.cpp b/dom/media/fmp4/MP4Decoder.cpp index 9e8c6887881d..c81f4fc9b5af 100644 --- a/dom/media/fmp4/MP4Decoder.cpp +++ b/dom/media/fmp4/MP4Decoder.cpp @@ -54,14 +54,25 @@ MP4Decoder::SetCDMProxy(CDMProxy* aProxy) #endif static bool -IsSupportedAudioCodec(const nsAString& aCodec) +IsSupportedAudioCodec(const nsAString& aCodec, + bool& aOutContainsAAC, + bool& aOutContainsMP3) { - // AAC-LC, HE-AAC or MP3 in M4A. - return aCodec.EqualsASCII("mp4a.40.2") || + // AAC-LC or HE-AAC in M4A. + aOutContainsAAC = aCodec.EqualsASCII("mp4a.40.2") || + aCodec.EqualsASCII("mp4a.40.5"); + if (aOutContainsAAC) { + return true; + } #ifndef MOZ_GONK_MEDIACODEC // B2G doesn't support MP3 in MP4 yet. - aCodec.EqualsASCII("mp3") || + aOutContainsMP3 = aCodec.EqualsASCII("mp3"); + if (aOutContainsMP3) { + return true; + } +#else + aOutContainsMP3 = false; #endif - aCodec.EqualsASCII("mp4a.40.5"); + return false; } static bool @@ -92,14 +103,20 @@ IsSupportedH264Codec(const nsAString& aCodec) /* static */ bool MP4Decoder::CanHandleMediaType(const nsACString& aType, - const nsAString& aCodecs) + const nsAString& aCodecs, + bool& aOutContainsAAC, + bool& aOutContainsH264, + bool& aOutContainsMP3) { if (!IsEnabled()) { return false; } if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) { - return aCodecs.IsEmpty() || IsSupportedAudioCodec(aCodecs); + return aCodecs.IsEmpty() || + IsSupportedAudioCodec(aCodecs, + aOutContainsAAC, + aOutContainsMP3); } if (!aType.EqualsASCII("video/mp4")) { @@ -113,7 +130,13 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType, while (tokenizer.hasMoreTokens()) { const nsSubstring& token = tokenizer.nextToken(); expectMoreTokens = tokenizer.separatorAfterCurrentToken(); - if (IsSupportedAudioCodec(token) || IsSupportedH264Codec(token)) { + if (IsSupportedAudioCodec(token, + aOutContainsAAC, + aOutContainsMP3)) { + continue; + } + if (IsSupportedH264Codec(token)) { + aOutContainsH264 = true; continue; } return false; @@ -122,8 +145,8 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType, // Last codec name was empty return false; } - return true; + return true; } static bool diff --git a/dom/media/fmp4/MP4Decoder.h b/dom/media/fmp4/MP4Decoder.h index 95f7131abb0a..0cffec1f60c3 100644 --- a/dom/media/fmp4/MP4Decoder.h +++ b/dom/media/fmp4/MP4Decoder.h @@ -30,9 +30,13 @@ public: // 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. + // with a comma-delimited list of codecs to check support for. Notes in + // out params wether the codecs string contains AAC or H.264. static bool CanHandleMediaType(const nsACString& aMIMEType, - const nsAString& aCodecs = EmptyString()); + const nsAString& aCodecs, + bool& aOutContainsAAC, + bool& aOutContainsH264, + bool& aOutContainsMP3); // Returns true if the MP4 backend is preffed on, and we're running on a // platform that is likely to have decoders for the contained formats. diff --git a/dom/media/test/eme.js b/dom/media/test/eme.js index 3d3a2c3af85f..398f4449281b 100644 --- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -192,23 +192,37 @@ function SetupEME(test, token, params) v.addEventListener("encrypted", function(ev) { Log(token, "got encrypted event"); - MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) { - Log(token, "created MediaKeys object ok"); - mediaKeys.sessions = []; - return v.setMediaKeys(mediaKeys); - }, bail("failed to create MediaKeys object")).then(function() { - Log(token, "set MediaKeys on