--- a/dom/media/eme/MediaKeySystemAccess.cpp
+++ b/dom/media/eme/MediaKeySystemAccess.cpp
@@ -32,17 +32,19 @@
#include "gmp-audio-decode.h"
#include "gmp-video-decode.h"
#include "DecoderDoctorDiagnostics.h"
#include "WebMDecoder.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsUnicharUtils.h"
#include "mozilla/dom/MediaSource.h"
-
+#ifdef MOZ_WIDGET_ANDROID
+#include "FennecJNIWrappers.h"
+#endif
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)
@@ -292,30 +294,40 @@ MediaKeySystemAccess::GetKeySystemStatus
aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Adobe EME");
return MediaKeySystemStatus::Cdm_not_supported;
}
#endif
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
}
}
- if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
- if (IsWidevineKeySystem(aKeySystem)) {
+ if (IsWidevineKeySystem(aKeySystem)) {
+ if (Preferences::GetBool("media.gmp-widevinecdm.visible", false)) {
#ifdef XP_WIN
// Win Vista and later only.
if (!IsVistaOrLater()) {
aOutMessage = NS_LITERAL_CSTRING("Minimum Windows version (Vista) not met for Widevine EME");
return MediaKeySystemStatus::Cdm_not_supported;
}
#endif
if (!Preferences::GetBool("media.gmp-widevinecdm.enabled", false)) {
aOutMessage = NS_LITERAL_CSTRING("Widevine EME disabled");
return MediaKeySystemStatus::Cdm_disabled;
}
return EnsureMinCDMVersion(mps, aKeySystem, aMinCdmVersion, aOutMessage, aOutCdmVersion);
+#ifdef MOZ_WIDGET_ANDROID
+ } else if (Preferences::GetBool("media.mediadrm-widevinecdm.visible", false)) {
+ nsCString keySystem = NS_ConvertUTF16toUTF8(aKeySystem);
+ bool supported = mozilla::java::MediaDrmProxy::IsSchemeSupported(keySystem);
+ if (!supported) {
+ aOutMessage = NS_LITERAL_CSTRING("Widevine CDM is not available");
+ return MediaKeySystemStatus::Cdm_not_installed;
+ }
+ return MediaKeySystemStatus::Available;
+#endif
}
}
return MediaKeySystemStatus::Cdm_not_supported;
}
typedef nsCString EMECodecString;
@@ -410,26 +422,43 @@ struct KeySystemConfig
KeySystemFeatureSupport mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
nsTArray<MediaKeySessionType> mSessionTypes;
nsTArray<nsString> mVideoRobustness;
nsTArray<nsString> mAudioRobustness;
KeySystemContainerSupport mMP4;
KeySystemContainerSupport mWebM;
};
-StaticAutoPtr<nsTArray<KeySystemConfig>> sKeySystemConfigs;
+bool
+HavePluginForKeySystem(const nsCString& aKeySystem)
+{
+ bool havePlugin = false;
+ nsCOMPtr<mozIGeckoMediaPluginService> mps =
+ do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+ if (mps) {
+ havePlugin = HaveGMPFor(mps,
+ aKeySystem,
+ NS_LITERAL_CSTRING(GMP_API_DECRYPTOR));
+ }
+#ifdef MOZ_WIDGET_ANDROID
+ // Check if we can use MediaDrm for this keysystem.
+ if (!havePlugin) {
+ havePlugin = mozilla::java::MediaDrmProxy::IsSchemeSupported(aKeySystem);
+ }
+#endif
+ return havePlugin;
+}
-static const nsTArray<KeySystemConfig>&
+static nsTArray<KeySystemConfig>
GetSupportedKeySystems()
{
- if (!sKeySystemConfigs) {
- sKeySystemConfigs = new nsTArray<KeySystemConfig>();
- ClearOnShutdown(&sKeySystemConfigs);
+ nsTArray<KeySystemConfig> keySystemConfigs;
- {
+ {
+ if (HavePluginForKeySystem(kEMEKeySystemClearkey)) {
KeySystemConfig clearkey;
clearkey.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemClearkey);
clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
clearkey.mPersistentState = KeySystemFeatureSupport::Requestable;
clearkey.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
@@ -449,114 +478,149 @@ GetSupportedKeySystems()
#else
clearkey.mMP4.SetCanDecrypt(EME_CODEC_AAC);
clearkey.mMP4.SetCanDecrypt(EME_CODEC_H264);
#endif
clearkey.mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
clearkey.mWebM.SetCanDecrypt(EME_CODEC_OPUS);
clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP8);
clearkey.mWebM.SetCanDecrypt(EME_CODEC_VP9);
- sKeySystemConfigs->AppendElement(Move(clearkey));
+ keySystemConfigs.AppendElement(Move(clearkey));
}
- {
+ }
+ {
+ if (HavePluginForKeySystem(kEMEKeySystemWidevine)) {
KeySystemConfig widevine;
widevine.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemWidevine);
widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids"));
widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm"));
widevine.mPersistentState = KeySystemFeatureSupport::Requestable;
widevine.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited;
widevine.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
+#ifdef MOZ_WIDGET_ANDROID
+ widevine.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license);
+#endif
widevine.mAudioRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO"));
widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_DECODE"));
#if defined(XP_WIN)
// Widevine CDM doesn't include an AAC decoder. So if WMF can't
// decode AAC, and a codec wasn't specified, be conservative
// and reject the MediaKeys request, since our policy is to prevent
// the Adobe GMP's unencrypted AAC decoding path being used to
// decode content decrypted by the Widevine CDM.
if (WMFDecoderModule::HasAAC()) {
widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC);
}
-#else
+#elif !defined(MOZ_WIDGET_ANDROID)
widevine.mMP4.SetCanDecrypt(EME_CODEC_AAC);
#endif
+
+#if defined(MOZ_WIDGET_ANDROID)
+ using namespace mozilla::java;
+ // MediaDrm.isCryptoSchemeSupported only allows passing
+ // "video/mp4" or "video/webm" for mimetype string.
+ // See https://developer.android.com/reference/android/media/MediaDrm.html#isCryptoSchemeSupported(java.util.UUID, java.lang.String)
+ // for more detail.
+ typedef struct {
+ const nsCString& mMimeType;
+ const nsCString& mEMECodecType;
+ const char16_t* mCodecType;
+ KeySystemContainerSupport* mSupportType;
+ } DataForValidation;
+
+ DataForValidation validationList[] = {
+ { nsCString("video/mp4"), EME_CODEC_H264, MediaDrmProxy::AVC, &widevine.mMP4 },
+ { nsCString("audio/mp4"), EME_CODEC_AAC, MediaDrmProxy::AAC, &widevine.mMP4 },
+ { nsCString("video/webm"), EME_CODEC_VP8, MediaDrmProxy::VP8, &widevine.mWebM },
+ { nsCString("video/webm"), EME_CODEC_VP9, MediaDrmProxy::VP9, &widevine.mWebM},
+ { nsCString("audio/webm"), EME_CODEC_VORBIS, MediaDrmProxy::VORBIS, &widevine.mWebM},
+ { nsCString("audio/webm"), EME_CODEC_OPUS, MediaDrmProxy::OPUS, &widevine.mWebM},
+ };
+
+ for (const auto& data: validationList) {
+ if (MediaDrmProxy::IsCryptoSchemeSupported(kEMEKeySystemWidevine,
+ data.mMimeType)) {
+ if (MediaDrmProxy::CanDecode(data.mCodecType)) {
+ data.mSupportType->SetCanDecryptAndDecode(data.mEMECodecType);
+ } else {
+ data.mSupportType->SetCanDecrypt(data.mEMECodecType);
+ }
+ }
+ }
+#else
widevine.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
widevine.mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
widevine.mWebM.SetCanDecrypt(EME_CODEC_OPUS);
widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP8);
widevine.mWebM.SetCanDecryptAndDecode(EME_CODEC_VP9);
- sKeySystemConfigs->AppendElement(Move(widevine));
+#endif
+ keySystemConfigs.AppendElement(Move(widevine));
}
- {
+ }
+ {
+ if (HavePluginForKeySystem(kEMEKeySystemPrimetime)) {
KeySystemConfig primetime;
primetime.mKeySystem = NS_ConvertUTF8toUTF16(kEMEKeySystemPrimetime);
primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc"));
primetime.mPersistentState = KeySystemFeatureSupport::Required;
primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required;
primetime.mSessionTypes.AppendElement(MediaKeySessionType::Temporary);
primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_AAC);
primetime.mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
- sKeySystemConfigs->AppendElement(Move(primetime));
+ keySystemConfigs.AppendElement(Move(primetime));
}
}
- return *sKeySystemConfigs;
+
+ return keySystemConfigs;
}
-static const KeySystemConfig*
-GetKeySystemConfig(const nsAString& aKeySystem)
+static bool
+GetKeySystemConfig(const nsAString& aKeySystem, KeySystemConfig& aOutKeySystemConfig)
{
- for (const KeySystemConfig& config : GetSupportedKeySystems()) {
+ for (auto&& config : GetSupportedKeySystems()) {
if (config.mKeySystem.Equals(aKeySystem)) {
- return &config;
+ aOutKeySystemConfig = mozilla::Move(config);
+ return true;
}
}
- return nullptr;
+ // No matching key system found.
+ return false;
}
/* static */
bool
MediaKeySystemAccess::KeySystemSupportsInitDataType(const nsAString& aKeySystem,
const nsAString& aInitDataType)
{
- const KeySystemConfig* implementation = GetKeySystemConfig(aKeySystem);
- return implementation &&
- implementation->mInitDataTypes.Contains(aInitDataType);
+ KeySystemConfig implementation;
+ return GetKeySystemConfig(aKeySystem, implementation) &&
+ implementation.mInitDataTypes.Contains(aInitDataType);
}
enum CodecType
{
Audio,
Video,
Invalid
};
static bool
-CanDecryptAndDecode(mozIGeckoMediaPluginService* aGMPService,
- const nsString& aKeySystem,
+CanDecryptAndDecode(const nsString& aKeySystem,
const nsString& aContentType,
CodecType aCodecType,
const KeySystemContainerSupport& aContainerSupport,
const nsTArray<EMECodecString>& aCodecs,
DecoderDoctorDiagnostics* aDiagnostics)
{
MOZ_ASSERT(aCodecType != Invalid);
- MOZ_ASSERT(HaveGMPFor(aGMPService,
- NS_ConvertUTF16toUTF8(aKeySystem),
- NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)));
for (const EMECodecString& codec : aCodecs) {
MOZ_ASSERT(!codec.IsEmpty());
- nsCString api = (aCodecType == Audio) ? NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER)
- : NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER);
- if (aContainerSupport.DecryptsAndDecodes(codec) &&
- HaveGMPFor(aGMPService,
- NS_ConvertUTF16toUTF8(aKeySystem),
- api,
- codec)) {
+ if (aContainerSupport.DecryptsAndDecodes(codec)) {
// GMP can decrypt-and-decode this codec.
continue;
}
if (aContainerSupport.Decrypts(codec) &&
NS_SUCCEEDED(MediaSource::IsTypeSupported(aContentType, aDiagnostics))) {
// GMP can decrypt and is allowed to return compressed samples to
// Gecko to decode, and Gecko has a decoder.
@@ -680,17 +744,16 @@ IsParameterUnrecognized(const nsAString&
}
}
return false;
}
// 3.1.2.3 Get Supported Capabilities for Audio/Video Type
static Sequence<MediaKeySystemMediaCapability>
GetSupportedCapabilities(const CodecType aCodecType,
- mozIGeckoMediaPluginService* aGMPService,
const nsTArray<MediaKeySystemMediaCapability>& aRequestedCapabilities,
const MediaKeySystemConfiguration& aPartialConfig,
const KeySystemConfig& aKeySystem,
DecoderDoctorDiagnostics* aDiagnostics)
{
// Let local accumulated configuration be a local copy of partial configuration.
// (Note: It's not necessary for us to maintain a local copy, as we don't need
// to test whether capabilites from previous calls to this algorithm work with
@@ -866,18 +929,17 @@ GetSupportedCapabilities(const CodecType
// Note: specified robustness requirements are satisfied.
}
// If the user agent and implementation definitely support playback of
// encrypted media data for the combination of container, media types,
// robustness and local accumulated configuration in combination with
// restrictions...
const auto& containerSupport = isMP4 ? aKeySystem.mMP4 : aKeySystem.mWebM;
- if (!CanDecryptAndDecode(aGMPService,
- aKeySystem.mKeySystem,
+ if (!CanDecryptAndDecode(aKeySystem.mKeySystem,
contentType,
majorType,
containerSupport,
codecs,
aDiagnostics)) {
EME_LOG("MediaKeySystemConfiguration (label='%s') "
"MediaKeySystemMediaCapability('%s','%s') unsupported; "
"codec unsupported by CDM requested.",
@@ -969,18 +1031,17 @@ UnboxSessionTypes(const Optional<Sequenc
// Note: fallible. Results in an empty array.
sessionTypes.AppendElement(NS_ConvertUTF8toUTF16(nsDependentCString(temporary)), mozilla::fallible);
}
return sessionTypes;
}
// 3.1.2.2 Get Supported Configuration and Consent
static bool
-GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService,
- const KeySystemConfig& aKeySystem,
+GetSupportedConfig(const KeySystemConfig& aKeySystem,
const MediaKeySystemConfiguration& aCandidate,
MediaKeySystemConfiguration& aOutConfig,
DecoderDoctorDiagnostics* aDiagnostics)
{
// Let accumulated configuration be a new MediaKeySystemConfiguration dictionary.
MediaKeySystemConfiguration config;
// Set the label member of accumulated configuration to equal the label member of
// candidate configuration.
@@ -1089,17 +1150,16 @@ GetSupportedConfig(mozIGeckoMediaPluginS
// If the videoCapabilities member in candidate configuration is non-empty:
if (!aCandidate.mVideoCapabilities.IsEmpty()) {
// Let video capabilities be the result of executing the Get Supported
// Capabilities for Audio/Video Type algorithm on Video, candidate
// configuration's videoCapabilities member, accumulated configuration,
// and restrictions.
Sequence<MediaKeySystemMediaCapability> caps =
GetSupportedCapabilities(Video,
- aGMPService,
aCandidate.mVideoCapabilities,
config,
aKeySystem,
aDiagnostics);
// If video capabilities is null, return NotSupported.
if (caps.IsEmpty()) {
EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
"no supported video capabilities.",
@@ -1115,17 +1175,16 @@ GetSupportedConfig(mozIGeckoMediaPluginS
// If the audioCapabilities member in candidate configuration is non-empty:
if (!aCandidate.mAudioCapabilities.IsEmpty()) {
// Let audio capabilities be the result of executing the Get Supported Capabilities
// for Audio/Video Type algorithm on Audio, candidate configuration's audioCapabilities
// member, accumulated configuration, and restrictions.
Sequence<MediaKeySystemMediaCapability> caps =
GetSupportedCapabilities(Audio,
- aGMPService,
aCandidate.mAudioCapabilities,
config,
aKeySystem,
aDiagnostics);
// If audio capabilities is null, return NotSupported.
if (caps.IsEmpty()) {
EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; "
"no supported audio capabilities.",
@@ -1198,31 +1257,22 @@ GetSupportedConfig(mozIGeckoMediaPluginS
/* static */
bool
MediaKeySystemAccess::GetSupportedConfig(const nsAString& aKeySystem,
const Sequence<MediaKeySystemConfiguration>& aConfigs,
MediaKeySystemConfiguration& aOutConfig,
DecoderDoctorDiagnostics* aDiagnostics)
{
- nsCOMPtr<mozIGeckoMediaPluginService> mps =
- do_GetService("@mozilla.org/gecko-media-plugin-service;1");
- if (NS_WARN_IF(!mps)) {
- return false;
- }
- const KeySystemConfig* implementation = nullptr;
- if (!HaveGMPFor(mps,
- NS_ConvertUTF16toUTF8(aKeySystem),
- NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)) ||
- !(implementation = GetKeySystemConfig(aKeySystem))) {
+ KeySystemConfig implementation;
+ if (!GetKeySystemConfig(aKeySystem, implementation)) {
return false;
}
for (const MediaKeySystemConfiguration& candidate : aConfigs) {
- if (mozilla::dom::GetSupportedConfig(mps,
- *implementation,
+ if (mozilla::dom::GetSupportedConfig(implementation,
candidate,
aOutConfig,
aDiagnostics)) {
return true;
}
}
return false;