summaryrefslogtreecommitdiffstats
path: root/dom/media/eme/KeySystemConfig.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/eme/KeySystemConfig.cpp')
-rw-r--r--dom/media/eme/KeySystemConfig.cpp363
1 files changed, 202 insertions, 161 deletions
diff --git a/dom/media/eme/KeySystemConfig.cpp b/dom/media/eme/KeySystemConfig.cpp
index 0cb5da1a56..8f3227ecf6 100644
--- a/dom/media/eme/KeySystemConfig.cpp
+++ b/dom/media/eme/KeySystemConfig.cpp
@@ -68,221 +68,262 @@ bool KeySystemConfig::Supports(const nsAString& aKeySystem) {
return false;
}
-/* static */
-bool KeySystemConfig::CreateKeySystemConfigs(
- const nsAString& aKeySystem, const DecryptionInfo aDecryption,
+/* static */ void KeySystemConfig::CreateClearKeyKeySystemConfigs(
+ const KeySystemConfigRequest& aRequest,
nsTArray<KeySystemConfig>& aOutConfigs) {
- if (!Supports(aKeySystem)) {
- return false;
+ KeySystemConfig* config = aOutConfigs.AppendElement();
+ config->mKeySystem = aRequest.mKeySystem;
+ config->mInitDataTypes.AppendElement(u"cenc"_ns);
+ config->mInitDataTypes.AppendElement(u"keyids"_ns);
+ config->mInitDataTypes.AppendElement(u"webm"_ns);
+ config->mPersistentState = Requirement::Optional;
+ config->mDistinctiveIdentifier = Requirement::NotAllowed;
+ config->mSessionTypes.AppendElement(SessionType::Temporary);
+ config->mEncryptionSchemes.AppendElement(u"cenc"_ns);
+ config->mEncryptionSchemes.AppendElement(u"cbcs"_ns);
+ config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns);
+ if (StaticPrefs::media_clearkey_persistent_license_enabled()) {
+ config->mSessionTypes.AppendElement(SessionType::PersistentLicense);
}
-
- if (IsClearkeyKeySystem(aKeySystem)) {
- KeySystemConfig* config = aOutConfigs.AppendElement();
- config->mKeySystem = aKeySystem;
- config->mInitDataTypes.AppendElement(u"cenc"_ns);
- config->mInitDataTypes.AppendElement(u"keyids"_ns);
- config->mInitDataTypes.AppendElement(u"webm"_ns);
- config->mPersistentState = Requirement::Optional;
- config->mDistinctiveIdentifier = Requirement::NotAllowed;
- config->mSessionTypes.AppendElement(SessionType::Temporary);
- config->mEncryptionSchemes.AppendElement(u"cenc"_ns);
- config->mEncryptionSchemes.AppendElement(u"cbcs"_ns);
- config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns);
- if (StaticPrefs::media_clearkey_persistent_license_enabled()) {
- config->mSessionTypes.AppendElement(SessionType::PersistentLicense);
- }
#if defined(XP_WIN)
- // Clearkey CDM uses WMF's H.264 decoder on Windows.
- if (WMFDecoderModule::CanCreateMFTDecoder(WMFStreamType::H264)) {
- config->mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
- } else {
- config->mMP4.SetCanDecrypt(EME_CODEC_H264);
- }
-#else
+ // Clearkey CDM uses WMF's H.264 decoder on Windows.
+ if (WMFDecoderModule::CanCreateMFTDecoder(WMFStreamType::H264)) {
+ config->mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
+ } else {
config->mMP4.SetCanDecrypt(EME_CODEC_H264);
+ }
+#else
+ config->mMP4.SetCanDecrypt(EME_CODEC_H264);
#endif
- config->mMP4.SetCanDecrypt(EME_CODEC_AAC);
- config->mMP4.SetCanDecrypt(EME_CODEC_FLAC);
- config->mMP4.SetCanDecrypt(EME_CODEC_OPUS);
- config->mMP4.SetCanDecrypt(EME_CODEC_VP9);
+ config->mMP4.SetCanDecrypt(EME_CODEC_AAC);
+ config->mMP4.SetCanDecrypt(EME_CODEC_FLAC);
+ config->mMP4.SetCanDecrypt(EME_CODEC_OPUS);
+ config->mMP4.SetCanDecrypt(EME_CODEC_VP9);
#ifdef MOZ_AV1
- config->mMP4.SetCanDecrypt(EME_CODEC_AV1);
+ config->mMP4.SetCanDecrypt(EME_CODEC_AV1);
#endif
- config->mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
- config->mWebM.SetCanDecrypt(EME_CODEC_OPUS);
- config->mWebM.SetCanDecrypt(EME_CODEC_VP8);
- config->mWebM.SetCanDecrypt(EME_CODEC_VP9);
+ config->mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
+ config->mWebM.SetCanDecrypt(EME_CODEC_OPUS);
+ config->mWebM.SetCanDecrypt(EME_CODEC_VP8);
+ config->mWebM.SetCanDecrypt(EME_CODEC_VP9);
#ifdef MOZ_AV1
- config->mWebM.SetCanDecrypt(EME_CODEC_AV1);
+ config->mWebM.SetCanDecrypt(EME_CODEC_AV1);
#endif
- if (StaticPrefs::media_clearkey_test_key_systems_enabled()) {
- // Add testing key systems. These offer the same capabilities as the
- // base clearkey system, so just clone clearkey and change the name.
- KeySystemConfig clearkeyWithProtectionQuery{*config};
- clearkeyWithProtectionQuery.mKeySystem.AssignLiteral(
- kClearKeyWithProtectionQueryKeySystemName);
- aOutConfigs.AppendElement(std::move(clearkeyWithProtectionQuery));
- }
- return true;
+ if (StaticPrefs::media_clearkey_test_key_systems_enabled()) {
+ // Add testing key systems. These offer the same capabilities as the
+ // base clearkey system, so just clone clearkey and change the name.
+ KeySystemConfig clearkeyWithProtectionQuery{*config};
+ clearkeyWithProtectionQuery.mKeySystem.AssignLiteral(
+ kClearKeyWithProtectionQueryKeySystemName);
+ aOutConfigs.AppendElement(std::move(clearkeyWithProtectionQuery));
}
+}
- if (IsWidevineKeySystem(aKeySystem)) {
- KeySystemConfig* config = aOutConfigs.AppendElement();
- config->mKeySystem = aKeySystem;
- config->mInitDataTypes.AppendElement(u"cenc"_ns);
- config->mInitDataTypes.AppendElement(u"keyids"_ns);
- config->mInitDataTypes.AppendElement(u"webm"_ns);
- config->mPersistentState = Requirement::Optional;
- config->mDistinctiveIdentifier = Requirement::NotAllowed;
- config->mSessionTypes.AppendElement(SessionType::Temporary);
+/* static */ void KeySystemConfig::CreateWivineL3KeySystemConfigs(
+ const KeySystemConfigRequest& aRequest,
+ nsTArray<KeySystemConfig>& aOutConfigs) {
+ KeySystemConfig* config = aOutConfigs.AppendElement();
+ config->mKeySystem = aRequest.mKeySystem;
+ config->mInitDataTypes.AppendElement(u"cenc"_ns);
+ config->mInitDataTypes.AppendElement(u"keyids"_ns);
+ config->mInitDataTypes.AppendElement(u"webm"_ns);
+ config->mPersistentState = Requirement::Optional;
+ config->mDistinctiveIdentifier = Requirement::NotAllowed;
+ config->mSessionTypes.AppendElement(SessionType::Temporary);
#ifdef MOZ_WIDGET_ANDROID
- config->mSessionTypes.AppendElement(SessionType::PersistentLicense);
+ config->mSessionTypes.AppendElement(SessionType::PersistentLicense);
#endif
- config->mAudioRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns);
- config->mVideoRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns);
- config->mVideoRobustness.AppendElement(u"SW_SECURE_DECODE"_ns);
- config->mEncryptionSchemes.AppendElement(u"cenc"_ns);
- config->mEncryptionSchemes.AppendElement(u"cbcs"_ns);
- config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns);
+ config->mAudioRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns);
+ config->mVideoRobustness.AppendElement(u"SW_SECURE_CRYPTO"_ns);
+ config->mVideoRobustness.AppendElement(u"SW_SECURE_DECODE"_ns);
+ config->mEncryptionSchemes.AppendElement(u"cenc"_ns);
+ config->mEncryptionSchemes.AppendElement(u"cbcs"_ns);
+ config->mEncryptionSchemes.AppendElement(u"cbcs-1-9"_ns);
#if defined(MOZ_WIDGET_ANDROID)
- // 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;
- KeySystemConfig::ContainerSupport* mSupportType;
- } DataForValidation;
+ // 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;
+ KeySystemConfig::ContainerSupport* mSupportType;
+ } DataForValidation;
- DataForValidation validationList[] = {
- {nsCString(VIDEO_MP4), EME_CODEC_H264, java::MediaDrmProxy::AVC,
- &config->mMP4},
- {nsCString(VIDEO_MP4), EME_CODEC_VP9, java::MediaDrmProxy::AVC,
- &config->mMP4},
+ DataForValidation validationList[] = {
+ {nsCString(VIDEO_MP4), EME_CODEC_H264, java::MediaDrmProxy::AVC,
+ &config->mMP4},
+ {nsCString(VIDEO_MP4), EME_CODEC_VP9, java::MediaDrmProxy::AVC,
+ &config->mMP4},
# ifdef MOZ_AV1
- {nsCString(VIDEO_MP4), EME_CODEC_AV1, java::MediaDrmProxy::AV1,
- &config->mMP4},
+ {nsCString(VIDEO_MP4), EME_CODEC_AV1, java::MediaDrmProxy::AV1,
+ &config->mMP4},
# endif
- {nsCString(AUDIO_MP4), EME_CODEC_AAC, java::MediaDrmProxy::AAC,
- &config->mMP4},
- {nsCString(AUDIO_MP4), EME_CODEC_FLAC, java::MediaDrmProxy::FLAC,
- &config->mMP4},
- {nsCString(AUDIO_MP4), EME_CODEC_OPUS, java::MediaDrmProxy::OPUS,
- &config->mMP4},
- {nsCString(VIDEO_WEBM), EME_CODEC_VP8, java::MediaDrmProxy::VP8,
- &config->mWebM},
- {nsCString(VIDEO_WEBM), EME_CODEC_VP9, java::MediaDrmProxy::VP9,
- &config->mWebM},
+ {nsCString(AUDIO_MP4), EME_CODEC_AAC, java::MediaDrmProxy::AAC,
+ &config->mMP4},
+ {nsCString(AUDIO_MP4), EME_CODEC_FLAC, java::MediaDrmProxy::FLAC,
+ &config->mMP4},
+ {nsCString(AUDIO_MP4), EME_CODEC_OPUS, java::MediaDrmProxy::OPUS,
+ &config->mMP4},
+ {nsCString(VIDEO_WEBM), EME_CODEC_VP8, java::MediaDrmProxy::VP8,
+ &config->mWebM},
+ {nsCString(VIDEO_WEBM), EME_CODEC_VP9, java::MediaDrmProxy::VP9,
+ &config->mWebM},
# ifdef MOZ_AV1
- {nsCString(VIDEO_WEBM), EME_CODEC_AV1, java::MediaDrmProxy::AV1,
- &config->mWebM},
+ {nsCString(VIDEO_WEBM), EME_CODEC_AV1, java::MediaDrmProxy::AV1,
+ &config->mWebM},
# endif
- {nsCString(AUDIO_WEBM), EME_CODEC_VORBIS, java::MediaDrmProxy::VORBIS,
- &config->mWebM},
- {nsCString(AUDIO_WEBM), EME_CODEC_OPUS, java::MediaDrmProxy::OPUS,
- &config->mWebM},
- };
+ {nsCString(AUDIO_WEBM), EME_CODEC_VORBIS, java::MediaDrmProxy::VORBIS,
+ &config->mWebM},
+ {nsCString(AUDIO_WEBM), EME_CODEC_OPUS, java::MediaDrmProxy::OPUS,
+ &config->mWebM},
+ };
- for (const auto& data : validationList) {
- if (java::MediaDrmProxy::IsCryptoSchemeSupported(kWidevineKeySystemName,
- data.mMimeType)) {
- if (!AndroidDecoderModule::SupportsMimeType(data.mMimeType).isEmpty()) {
- data.mSupportType->SetCanDecryptAndDecode(data.mEMECodecType);
- } else {
- data.mSupportType->SetCanDecrypt(data.mEMECodecType);
- }
+ for (const auto& data : validationList) {
+ if (java::MediaDrmProxy::IsCryptoSchemeSupported(kWidevineKeySystemName,
+ data.mMimeType)) {
+ if (!AndroidDecoderModule::SupportsMimeType(data.mMimeType).isEmpty()) {
+ data.mSupportType->SetCanDecryptAndDecode(data.mEMECodecType);
+ } else {
+ data.mSupportType->SetCanDecrypt(data.mEMECodecType);
}
}
+ }
#else
# 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 we assume Widevine
- // will be used with AAC.
- if (WMFDecoderModule::CanCreateMFTDecoder(WMFStreamType::AAC)) {
- config->mMP4.SetCanDecrypt(EME_CODEC_AAC);
- }
-# else
+ // 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 we assume Widevine
+ // will be used with AAC.
+ if (WMFDecoderModule::CanCreateMFTDecoder(WMFStreamType::AAC)) {
config->mMP4.SetCanDecrypt(EME_CODEC_AAC);
+ }
+# else
+ config->mMP4.SetCanDecrypt(EME_CODEC_AAC);
# endif
- config->mMP4.SetCanDecrypt(EME_CODEC_FLAC);
- config->mMP4.SetCanDecrypt(EME_CODEC_OPUS);
- config->mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
- config->mMP4.SetCanDecryptAndDecode(EME_CODEC_VP9);
+ config->mMP4.SetCanDecrypt(EME_CODEC_FLAC);
+ config->mMP4.SetCanDecrypt(EME_CODEC_OPUS);
+ config->mMP4.SetCanDecryptAndDecode(EME_CODEC_H264);
+ config->mMP4.SetCanDecryptAndDecode(EME_CODEC_VP9);
# ifdef MOZ_AV1
- config->mMP4.SetCanDecryptAndDecode(EME_CODEC_AV1);
+ config->mMP4.SetCanDecryptAndDecode(EME_CODEC_AV1);
# endif
- config->mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
- config->mWebM.SetCanDecrypt(EME_CODEC_OPUS);
- config->mWebM.SetCanDecryptAndDecode(EME_CODEC_VP8);
- config->mWebM.SetCanDecryptAndDecode(EME_CODEC_VP9);
+ config->mWebM.SetCanDecrypt(EME_CODEC_VORBIS);
+ config->mWebM.SetCanDecrypt(EME_CODEC_OPUS);
+ config->mWebM.SetCanDecryptAndDecode(EME_CODEC_VP8);
+ config->mWebM.SetCanDecryptAndDecode(EME_CODEC_VP9);
# ifdef MOZ_AV1
- config->mWebM.SetCanDecryptAndDecode(EME_CODEC_AV1);
+ config->mWebM.SetCanDecryptAndDecode(EME_CODEC_AV1);
# endif
#endif
- return true;
- }
+}
+
+/* static */
+RefPtr<KeySystemConfig::SupportedConfigsPromise>
+KeySystemConfig::CreateKeySystemConfigs(
+ const nsTArray<KeySystemConfigRequest>& aRequests) {
+ // Create available configs for all supported key systems in the request, but
+ // some of them might not be created immediately.
+
+ nsTArray<KeySystemConfig> outConfigs;
+ nsTArray<KeySystemConfigRequest> asyncRequests;
+
+ for (const auto& request : aRequests) {
+ const nsAString& keySystem = request.mKeySystem;
+ if (!Supports(keySystem)) {
+ continue;
+ }
+
+ if (IsClearkeyKeySystem(keySystem)) {
+ CreateClearKeyKeySystemConfigs(request, outConfigs);
+ } else if (IsWidevineKeySystem(keySystem)) {
+ CreateWivineL3KeySystemConfigs(request, outConfigs);
+ }
#ifdef MOZ_WMF_CDM
- if (IsPlayReadyKeySystemAndSupported(aKeySystem) ||
- IsWidevineExperimentKeySystemAndSupported(aKeySystem)) {
- RefPtr<WMFCDMImpl> cdm = MakeRefPtr<WMFCDMImpl>(aKeySystem);
- return cdm->GetCapabilities(aDecryption == DecryptionInfo::Hardware,
- aOutConfigs);
- }
+ else if (IsPlayReadyKeySystemAndSupported(keySystem) ||
+ IsWidevineExperimentKeySystemAndSupported(keySystem)) {
+ asyncRequests.AppendElement(request);
+ }
#endif
- return false;
-}
+ }
-bool KeySystemConfig::IsSameKeySystem(const nsAString& aKeySystem) const {
#ifdef MOZ_WMF_CDM
- // We want to map Widevine experiment key system to normal Widevine key system
- // as well.
- if (IsWidevineExperimentKeySystemAndSupported(mKeySystem)) {
- return mKeySystem.Equals(aKeySystem) ||
- aKeySystem.EqualsLiteral(kWidevineKeySystemName);
+ if (!asyncRequests.IsEmpty()) {
+ RefPtr<SupportedConfigsPromise::Private> promise =
+ new SupportedConfigsPromise::Private(__func__);
+ RefPtr<WMFCDMCapabilites> cdm = new WMFCDMCapabilites();
+ cdm->GetCapabilities(asyncRequests)
+ ->Then(GetMainThreadSerialEventTarget(), __func__,
+ [syncConfigs = std::move(outConfigs),
+ promise](SupportedConfigsPromise::ResolveOrRejectValue&&
+ aResult) mutable {
+ // Return the capabilities we already know
+ if (aResult.IsReject()) {
+ promise->Resolve(std::move(syncConfigs), __func__);
+ return;
+ }
+ // Merge sync results with async results
+ auto& asyncConfigs = aResult.ResolveValue();
+ asyncConfigs.AppendElements(std::move(syncConfigs));
+ promise->Resolve(std::move(asyncConfigs), __func__);
+ });
+ return promise;
}
#endif
- return mKeySystem.Equals(aKeySystem);
+ return SupportedConfigsPromise::CreateAndResolve(std::move(outConfigs),
+ __func__);
}
/* static */
void KeySystemConfig::GetGMPKeySystemConfigs(dom::Promise* aPromise) {
MOZ_ASSERT(aPromise);
- nsTArray<KeySystemConfig> keySystemConfigs;
+
+ // Generate config requests
const nsTArray<nsString> keySystemNames{
NS_ConvertUTF8toUTF16(kClearKeyKeySystemName),
NS_ConvertUTF8toUTF16(kWidevineKeySystemName),
};
- FallibleTArray<dom::CDMInformation> cdmInfo;
- for (const auto& name : keySystemNames) {
+ nsTArray<KeySystemConfigRequest> requests;
+ for (const auto& keySystem : keySystemNames) {
#ifdef MOZ_WMF_CDM
- if (IsWMFClearKeySystemAndSupported(name)) {
+ if (IsWMFClearKeySystemAndSupported(keySystem)) {
// Using wmf clearkey, not gmp clearkey.
continue;
}
#endif
- if (KeySystemConfig::CreateKeySystemConfigs(
- name, KeySystemConfig::DecryptionInfo::Software,
- keySystemConfigs)) {
- auto* info = cdmInfo.AppendElement(fallible);
- if (!info) {
- aPromise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
- return;
- }
- MOZ_ASSERT(keySystemConfigs.Length() == cdmInfo.Length());
- info->mKeySystemName = name;
- info->mCapabilities = keySystemConfigs.LastElement().GetDebugInfo();
- info->mClearlead = DoesKeySystemSupportClearLead(name);
- // TODO : ask real CDM
- info->mIsHDCP22Compatible = false;
- }
+ requests.AppendElement(
+ KeySystemConfigRequest{keySystem, DecryptionInfo::Software});
}
- aPromise->MaybeResolve(cdmInfo);
+
+ // Get supported configs
+ KeySystemConfig::CreateKeySystemConfigs(requests)->Then(
+ GetMainThreadSerialEventTarget(), __func__,
+ [promise = RefPtr<dom::Promise>{aPromise}](
+ const SupportedConfigsPromise::ResolveOrRejectValue& aResult) {
+ if (aResult.IsResolve()) {
+ // Generate CDMInformation from configs
+ FallibleTArray<dom::CDMInformation> cdmInfo;
+ for (const auto& config : aResult.ResolveValue()) {
+ auto* info = cdmInfo.AppendElement(fallible);
+ if (!info) {
+ promise->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
+ return;
+ }
+ info->mKeySystemName = config.mKeySystem;
+ info->mCapabilities = config.GetDebugInfo();
+ info->mClearlead = DoesKeySystemSupportClearLead(config.mKeySystem);
+ // TODO : ask real CDM
+ info->mIsHDCP22Compatible = false;
+ }
+ promise->MaybeResolve(cdmInfo);
+ } else {
+ promise->MaybeReject(NS_ERROR_DOM_MEDIA_CDM_ERR);
+ }
+ });
}
nsString KeySystemConfig::GetDebugInfo() const {