| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "components/cdm/renderer/key_system_support_update.h" |
| |
| #include <stddef.h> |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/containers/contains.h" |
| #include "base/containers/flat_set.h" |
| #include "base/feature_list.h" |
| #include "base/logging.h" |
| #include "build/build_config.h" |
| #include "components/cdm/common/buildflags.h" |
| #include "components/cdm/renderer/external_clear_key_key_system_info.h" |
| #include "content/public/renderer/key_system_support.h" |
| #include "content/public/renderer/render_frame.h" |
| #include "media/base/audio_codecs.h" |
| #include "media/base/cdm_capability.h" |
| #include "media/base/content_decryption_module.h" |
| #include "media/base/eme_constants.h" |
| #include "media/base/key_system_capability.h" |
| #include "media/base/key_system_info.h" |
| #include "media/base/media_switches.h" |
| #include "media/base/video_codecs.h" |
| #include "media/cdm/clear_key_cdm_common.h" |
| #include "media/media_buildflags.h" |
| #include "third_party/widevine/cdm/buildflags.h" |
| |
| #if BUILDFLAG(ENABLE_WIDEVINE) |
| #include "components/cdm/renderer/widevine_key_system_info.h" |
| #include "third_party/widevine/cdm/widevine_cdm_common.h" // nogncheck |
| #endif // BUILDFLAG(ENABLE_WIDEVINE) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| #include "components/cdm/renderer/android_key_system_info.h" |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| #if BUILDFLAG(ENABLE_PLAYREADY) |
| #include "components/cdm/common/playready_cdm_common.h" |
| #include "components/cdm/renderer/playready_key_system_info.h" |
| #include "media/base/supported_types.h" |
| #include "media/base/win/mf_feature_checks.h" |
| #endif // BUILDFLAG(ENABLE_PLAYREADY) |
| |
| using media::CdmSessionType; |
| using media::EmeFeatureSupport; |
| using media::KeySystemInfo; |
| using media::KeySystemInfos; |
| using media::SupportedCodecs; |
| |
| namespace cdm { |
| |
| namespace { |
| |
| #if BUILDFLAG(ENABLE_WIDEVINE) || BUILDFLAG(IS_ANDROID) || \ |
| BUILDFLAG(ENABLE_PLAYREADY) |
| SupportedCodecs GetVP9Codecs( |
| const base::flat_set<media::VideoCodecProfile>& profiles) { |
| if (profiles.empty()) { |
| // If no profiles are specified, then all are supported. |
| return media::EME_CODEC_VP9_PROFILE0 | media::EME_CODEC_VP9_PROFILE2; |
| } |
| |
| SupportedCodecs supported_vp9_codecs = media::EME_CODEC_NONE; |
| for (const auto& profile : profiles) { |
| switch (profile) { |
| case media::VP9PROFILE_PROFILE0: |
| supported_vp9_codecs |= media::EME_CODEC_VP9_PROFILE0; |
| break; |
| case media::VP9PROFILE_PROFILE2: |
| supported_vp9_codecs |= media::EME_CODEC_VP9_PROFILE2; |
| break; |
| default: |
| DVLOG(1) << "Unexpected " << GetCodecName(media::VideoCodec::kVP9) |
| << " profile: " << GetProfileName(profile); |
| break; |
| } |
| } |
| |
| return supported_vp9_codecs; |
| } |
| |
| #if BUILDFLAG(ENABLE_PLATFORM_HEVC) |
| SupportedCodecs GetHevcCodecs( |
| const base::flat_set<media::VideoCodecProfile>& profiles) { |
| #if BUILDFLAG(IS_CHROMEOS) |
| if (!base::FeatureList::IsEnabled(media::kPlatformHEVCDecoderSupport)) { |
| return media::EME_CODEC_NONE; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| // If no profiles are specified, then all are supported. |
| if (profiles.empty()) { |
| return media::EME_CODEC_HEVC_PROFILE_MAIN | |
| media::EME_CODEC_HEVC_PROFILE_MAIN10; |
| } |
| |
| SupportedCodecs supported_hevc_codecs = media::EME_CODEC_NONE; |
| for (const auto& profile : profiles) { |
| switch (profile) { |
| case media::HEVCPROFILE_MAIN: |
| supported_hevc_codecs |= media::EME_CODEC_HEVC_PROFILE_MAIN; |
| break; |
| case media::HEVCPROFILE_MAIN10: |
| supported_hevc_codecs |= media::EME_CODEC_HEVC_PROFILE_MAIN10; |
| break; |
| default: |
| DVLOG(1) << "Unexpected " << GetCodecName(media::VideoCodec::kHEVC) |
| << " profile: " << GetProfileName(profile); |
| break; |
| } |
| } |
| |
| return supported_hevc_codecs; |
| } |
| #endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) |
| |
| #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) |
| // Dolby Vision HEVC-based profiles are only be supported when HEVC is enabled. |
| // However, this is enforced elsewhere, as DV profiles for both AVC and HEVC |
| // are returned here. |
| SupportedCodecs GetDolbyVisionCodecs( |
| const base::flat_set<media::VideoCodecProfile>& profiles) { |
| // If no profiles are specified, then all are supported. |
| if (profiles.empty()) { |
| return media::EME_CODEC_DOLBY_VISION_AVC | |
| media::EME_CODEC_DOLBY_VISION_HEVC; |
| } |
| |
| SupportedCodecs supported_dv_codecs = media::EME_CODEC_NONE; |
| for (const auto& profile : profiles) { |
| switch (profile) { |
| case media::DOLBYVISION_PROFILE0: |
| supported_dv_codecs |= media::EME_CODEC_DOLBY_VISION_PROFILE0; |
| break; |
| case media::DOLBYVISION_PROFILE5: |
| supported_dv_codecs |= media::EME_CODEC_DOLBY_VISION_PROFILE5; |
| break; |
| case media::DOLBYVISION_PROFILE7: |
| supported_dv_codecs |= media::EME_CODEC_DOLBY_VISION_PROFILE7; |
| break; |
| case media::DOLBYVISION_PROFILE8: |
| supported_dv_codecs |= media::EME_CODEC_DOLBY_VISION_PROFILE8; |
| break; |
| case media::DOLBYVISION_PROFILE9: |
| supported_dv_codecs |= media::EME_CODEC_DOLBY_VISION_PROFILE9; |
| break; |
| default: |
| DVLOG(1) << "Unexpected " |
| << GetCodecName(media::VideoCodec::kDolbyVision) |
| << " profile: " << GetProfileName(profile); |
| break; |
| } |
| } |
| |
| return supported_dv_codecs; |
| } |
| #endif // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) |
| |
| SupportedCodecs GetSupportedCodecs(const media::CdmCapability& capability, |
| bool requires_clear_lead_support = true) { |
| SupportedCodecs supported_codecs = media::EME_CODEC_NONE; |
| |
| for (const auto& codec : capability.audio_codecs) { |
| switch (codec) { |
| case media::AudioCodec::kOpus: |
| supported_codecs |= media::EME_CODEC_OPUS; |
| break; |
| case media::AudioCodec::kVorbis: |
| supported_codecs |= media::EME_CODEC_VORBIS; |
| break; |
| case media::AudioCodec::kFLAC: |
| supported_codecs |= media::EME_CODEC_FLAC; |
| break; |
| #if BUILDFLAG(USE_PROPRIETARY_CODECS) |
| case media::AudioCodec::kAAC: |
| supported_codecs |= media::EME_CODEC_AAC; |
| break; |
| #if BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) |
| case media::AudioCodec::kDTS: |
| supported_codecs |= media::EME_CODEC_DTS; |
| supported_codecs |= media::EME_CODEC_DTSE; |
| supported_codecs |= media::EME_CODEC_DTSXP2; |
| break; |
| #endif // BUILDFLAG(ENABLE_PLATFORM_DTS_AUDIO) |
| #if BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO) |
| case media::AudioCodec::kAC3: |
| supported_codecs |= media::EME_CODEC_AC3; |
| break; |
| case media::AudioCodec::kEAC3: |
| supported_codecs |= media::EME_CODEC_EAC3; |
| break; |
| #endif // BUILDFLAG(ENABLE_PLATFORM_AC3_EAC3_AUDIO) |
| #if BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) |
| case media::AudioCodec::kAC4: |
| supported_codecs |= media::EME_CODEC_AC4; |
| break; |
| #endif // BUILDFLAG(ENABLE_PLATFORM_AC4_AUDIO) |
| #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) |
| default: |
| DVLOG(1) << "Unexpected supported codec: " << GetCodecName(codec); |
| break; |
| } |
| } |
| |
| // For compatibility with older CDMs different profiles are only used |
| // with some video codecs. |
| for (const auto& [codec, video_codec_info] : capability.video_codecs) { |
| if (requires_clear_lead_support && !video_codec_info.supports_clear_lead) { |
| continue; |
| } |
| switch (codec) { |
| case media::VideoCodec::kVP8: |
| supported_codecs |= media::EME_CODEC_VP8; |
| break; |
| case media::VideoCodec::kVP9: |
| supported_codecs |= GetVP9Codecs(video_codec_info.supported_profiles); |
| break; |
| case media::VideoCodec::kAV1: |
| supported_codecs |= media::EME_CODEC_AV1; |
| break; |
| #if BUILDFLAG(USE_PROPRIETARY_CODECS) |
| case media::VideoCodec::kH264: |
| supported_codecs |= media::EME_CODEC_AVC1; |
| break; |
| #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) |
| #if BUILDFLAG(ENABLE_PLATFORM_HEVC) |
| case media::VideoCodec::kHEVC: |
| supported_codecs |= GetHevcCodecs(video_codec_info.supported_profiles); |
| break; |
| #endif // BUILDFLAG(ENABLE_PLATFORM_HEVC) |
| #if BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) |
| case media::VideoCodec::kDolbyVision: |
| supported_codecs |= |
| GetDolbyVisionCodecs(video_codec_info.supported_profiles); |
| break; |
| #endif // BUILDFLAG(ENABLE_PLATFORM_DOLBY_VISION) |
| default: |
| DVLOG(1) << "Unexpected supported codec: " << GetCodecName(codec); |
| break; |
| } |
| } |
| |
| return supported_codecs; |
| } |
| #endif // BUILDFLAG(ENABLE_WIDEVINE) || BUILDFLAG(IS_ANDROID) || |
| // BUILDFLAG(ENABLE_PLAYREADY) |
| |
| #if BUILDFLAG(ENABLE_WIDEVINE) |
| |
| // Returns whether persistent-license session can be supported. |
| bool CanSupportPersistentLicense() { |
| // Do not support persistent-license if the process cannot persist data. |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // On ChromeOS, platform verification is similar to CDM host verification |
| // and is always checked, so persistent licenses are allowed. |
| // TODO(jrummell): Currently the ChromeOS CDM does not require storage ID |
| // to support persistent license. Update this logic when the new CDM requires |
| // storage ID. |
| return true; |
| |
| #elif BUILDFLAG(IS_ANDROID) |
| // Since we do not control the implementation of the MediaDrm API on Android, |
| // we assume that it can and will make use of persistence no matter whether |
| // persistence-based features are supported or not. |
| return true; |
| |
| #elif BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) && \ |
| BUILDFLAG(ENABLE_CDM_STORAGE_ID) |
| // On other platforms, persistent licenses are only supported if CDM host |
| // verification and CDM storage ID are available. |
| return true; |
| |
| #else |
| DVLOG_IF(2, !BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION)) |
| << __func__ << ": Not supported without CDM host verification."; |
| DVLOG_IF(2, !BUILDFLAG(ENABLE_CDM_STORAGE_ID)) |
| << __func__ << ": Not supported without CDM storage ID."; |
| return false; |
| |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| } |
| |
| // Remove `kPersistentLicense` support if it's not supported by the platform. |
| base::flat_set<CdmSessionType> UpdatePersistentLicenseSupport( |
| bool can_persist_data, |
| base::flat_set<CdmSessionType> session_types) { |
| if (!can_persist_data || !CanSupportPersistentLicense()) { |
| session_types.erase(CdmSessionType::kPersistentLicense); |
| } |
| return session_types; |
| } |
| |
| void AddWidevine(const media::KeySystemCapability& capability, |
| bool can_persist_data, |
| KeySystemInfos* key_systems) { |
| #if BUILDFLAG(IS_ANDROID) |
| // When using MediaDrm, we assume it'll always try to persist some data. |
| // If we are in incognito mode and MediaDrm were to persist data, we are |
| // somewhat violating the incognito assumption, so don't allow this. |
| if (!can_persist_data) { |
| DVLOG(2) << __func__ << ": Persistent data not supported."; |
| return; |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| // Codecs and encryption schemes. |
| SupportedCodecs codecs = media::EME_CODEC_NONE; |
| SupportedCodecs hw_secure_codecs = media::EME_CODEC_NONE; |
| #if BUILDFLAG(IS_WIN) |
| // The experimental key system has a different set of hardware codecs, where |
| // these hardware codecs do not require clear lead support. |
| SupportedCodecs hw_secure_codecs_experimental = media::EME_CODEC_NONE; |
| #endif |
| base::flat_set<::media::EncryptionScheme> encryption_schemes; |
| base::flat_set<::media::EncryptionScheme> hw_secure_encryption_schemes; |
| base::flat_set<CdmSessionType> session_types; |
| base::flat_set<CdmSessionType> hw_secure_session_types; |
| |
| if (capability.sw_cdm_capability_or_status.has_value()) { |
| const auto& sw_secure_capability = |
| capability.sw_cdm_capability_or_status.value(); |
| codecs = GetSupportedCodecs(sw_secure_capability); |
| encryption_schemes = sw_secure_capability.encryption_schemes; |
| session_types = UpdatePersistentLicenseSupport( |
| can_persist_data, sw_secure_capability.session_types); |
| if (!base::Contains(session_types, CdmSessionType::kTemporary)) { |
| DVLOG(1) << "Temporary sessions must be supported."; |
| return; |
| } |
| DVLOG(2) << "Software secure Widevine supported"; |
| } else { |
| DVLOG(2) << "Software secure Widevine NOT supported"; |
| } |
| |
| if (capability.hw_cdm_capability_or_status.has_value()) { |
| const auto& hw_secure_capability = |
| capability.hw_cdm_capability_or_status.value(); |
| hw_secure_codecs = GetSupportedCodecs(hw_secure_capability); |
| |
| #if BUILDFLAG(IS_WIN) |
| // For the experimental Widevine key system, we do not have to filter the |
| // hardware secure codecs by whether they support clear lead or not. |
| hw_secure_codecs_experimental = |
| GetSupportedCodecs(hw_secure_capability, |
| /*requires_clear_lead_support=*/false); |
| #endif // BUILDFLAG(IS_WIN) |
| |
| hw_secure_encryption_schemes = hw_secure_capability.encryption_schemes; |
| hw_secure_session_types = UpdatePersistentLicenseSupport( |
| can_persist_data, hw_secure_capability.session_types); |
| if (!base::Contains(hw_secure_session_types, CdmSessionType::kTemporary)) { |
| DVLOG(1) << "Temporary sessions must be supported."; |
| return; |
| } |
| DVLOG(2) << "Hardware secure Widevine supported"; |
| } else { |
| DVLOG(2) << "Hardware secure Widevine NOT supported"; |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // It doesn't make sense to support hw secure codecs but not regular codecs. |
| if (codecs == media::EME_CODEC_NONE) { |
| DCHECK(hw_secure_codecs == media::EME_CODEC_NONE); |
| DVLOG(3) << __func__ << " Widevine NOT supported."; |
| return; |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| // Robustness. |
| using Robustness = WidevineKeySystemInfo::Robustness; |
| auto max_audio_robustness = Robustness::SW_SECURE_CRYPTO; |
| auto max_video_robustness = Robustness::SW_SECURE_DECODE; |
| #if BUILDFLAG(IS_WIN) |
| auto max_experimental_audio_robustness = Robustness::SW_SECURE_CRYPTO; |
| auto max_experimental_video_robustness = Robustness::SW_SECURE_DECODE; |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // On ChromeOS, we support HW_SECURE_ALL even without hardware secure codecs. |
| // See WidevineKeySystemInfo::GetRobustnessConfigRule(). |
| max_audio_robustness = Robustness::HW_SECURE_ALL; |
| max_video_robustness = Robustness::HW_SECURE_ALL; |
| #elif BUILDFLAG(IS_ANDROID) |
| // On Android we support hardware secure if possible. |
| max_audio_robustness = Robustness::HW_SECURE_CRYPTO; |
| max_video_robustness = Robustness::HW_SECURE_ALL; |
| #elif BUILDFLAG(IS_WIN) |
| if (base::FeatureList::IsEnabled( |
| media::kHardwareSecureDecryptionExperiment)) { |
| max_experimental_audio_robustness = Robustness::HW_SECURE_CRYPTO; |
| max_experimental_video_robustness = Robustness::HW_SECURE_ALL; |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| |
| // Others. |
| auto persistent_state_support = EmeFeatureSupport::REQUESTABLE; |
| auto distinctive_identifier_support = EmeFeatureSupport::NOT_SUPPORTED; |
| #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) |
| distinctive_identifier_support = EmeFeatureSupport::REQUESTABLE; |
| #elif BUILDFLAG(IS_ANDROID) |
| // Since we do not control the implementation of the MediaDrm API on Android, |
| // we assume that it can and will make use of persistence no matter whether |
| // persistence-based features are supported or not. |
| persistent_state_support = EmeFeatureSupport::ALWAYS_ENABLED; |
| distinctive_identifier_support = EmeFeatureSupport::ALWAYS_ENABLED; |
| #endif |
| |
| key_systems->emplace_back(std::make_unique<WidevineKeySystemInfo>( |
| codecs, encryption_schemes, session_types, hw_secure_codecs, |
| hw_secure_encryption_schemes, hw_secure_session_types, |
| max_audio_robustness, max_video_robustness, persistent_state_support, |
| distinctive_identifier_support)); |
| |
| #if BUILDFLAG(IS_WIN) |
| if (base::FeatureList::IsEnabled( |
| media::kHardwareSecureDecryptionExperiment)) { |
| // Register another WidevineKeySystemInfo on Windows only for |
| // `kWidevineExperimentKeySystem`. The default WidevineKeySystemInfo |
| // above requires clear lead to be supported. This is not required for |
| // the experimental key system because content providers using the |
| // experimental key system would not serve clear lead content. |
| auto experimental_key_system_info = std::make_unique<WidevineKeySystemInfo>( |
| codecs, encryption_schemes, session_types, |
| hw_secure_codecs_experimental, hw_secure_encryption_schemes, |
| hw_secure_session_types, max_experimental_audio_robustness, |
| max_experimental_video_robustness, persistent_state_support, |
| distinctive_identifier_support); |
| experimental_key_system_info->set_experimental(); |
| |
| key_systems->emplace_back(std::move(experimental_key_system_info)); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| } |
| #endif // BUILDFLAG(ENABLE_WIDEVINE) |
| |
| void AddExternalClearKey(const media::KeySystemCapability& /*capability*/, |
| KeySystemInfos* key_systems) { |
| DVLOG(1) << __func__; |
| |
| if (!base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting)) { |
| DLOG(ERROR) << "ExternalClearKey supported despite not enabled."; |
| return; |
| } |
| |
| // TODO(xhwang): Actually use `capability` to determine capabilities. |
| key_systems->push_back(std::make_unique<ExternalClearKeyKeySystemInfo>()); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| #if BUILDFLAG(ENABLE_PLAYREADY) |
| void AddPlayReady(const media::KeySystemCapability& capability, |
| bool can_persist_data, |
| KeySystemInfos* key_systems) { |
| DVLOG(1) << __func__; |
| |
| // When using MediaFoundation, it is assumed that it will try to persist some |
| // data. If incognito mode is enabled and MediaFoundation were to persist data |
| // this would violate the incognito assumption. |
| if (!can_persist_data) { |
| DVLOG(2) << __func__ << ": Persistent data not supported."; |
| return; |
| } |
| |
| if (!media::SupportMediaFoundationEncryptedPlayback()) { |
| DLOG(ERROR) << __func__ |
| << ": Media Foundation encrypted playback not supported."; |
| return; |
| } |
| |
| if (capability.sw_cdm_capability_or_status.has_value()) { |
| DVLOG(2) << "Software secure PlayReady supported but not expected"; |
| } |
| |
| // Codecs and encryption schemes. |
| SupportedCodecs hw_secure_codecs = media::EME_CODEC_NONE; |
| base::flat_set<::media::EncryptionScheme> hw_secure_encryption_schemes; |
| if (!capability.hw_cdm_capability_or_status.has_value()) { |
| DVLOG(2) << __func__ << ": Hardware secure PlayReady NOT supported"; |
| return; |
| } |
| |
| const auto& hw_secure_capability = |
| capability.hw_cdm_capability_or_status.value(); |
| // For the default PlayReady key system, we support a codec only when it |
| // supports clear lead, unless `force_support_clear_lead` is set to true. |
| hw_secure_codecs = GetSupportedCodecs( |
| hw_secure_capability, |
| !media::kHardwareSecureDecryptionForceSupportClearLead.Get()); |
| hw_secure_encryption_schemes = |
| capability.hw_cdm_capability_or_status->encryption_schemes; |
| if (!base::Contains(capability.hw_cdm_capability_or_status->session_types, |
| CdmSessionType::kTemporary)) { |
| DVLOG(1) << "Temporary sessions must be supported for hardware secure " |
| "PlayReady"; |
| return; |
| } |
| DVLOG(2) << __func__ << ": Hardware secure PlayReady supported"; |
| |
| key_systems->emplace_back(new PlayReadyKeySystemInfo( |
| hw_secure_codecs, hw_secure_encryption_schemes)); |
| } |
| #endif // BUILDFLAG(ENABLE_PLAYREADY) |
| |
| void AddMediaFoundationClearKey( |
| const media::KeySystemCapability& /*capability*/, |
| KeySystemInfos* key_systems) { |
| DVLOG(1) << __func__; |
| |
| if (!base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting)) { |
| DLOG(ERROR) << "ExternalClearKey supported despite not enabled."; |
| return; |
| } |
| |
| #if BUILDFLAG(USE_PROPRIETARY_CODECS) |
| // TODO(crbug.com/40890911): Remove this hard-codeded supported codecs so that |
| // real hardware capabilities can be checked. |
| key_systems->push_back(std::make_unique<ExternalClearKeyKeySystemInfo>( |
| media::kMediaFoundationClearKeyKeySystem, std::vector<std::string>(), |
| // MediaFoundation Clear Key Key System uses Windows Media Foundation's |
| // decoders. H264 ("avc1.64001E") for video and MP4 AAC ("mp4a.40.2") for |
| // audio are always supported. VideoCodec::kH264 is an EME_CODEC_AVC1. |
| // AudioCodec::kAAC is an EME_CODEC_AAC. DolbyVision Profile 5 |
| // ("dvh1.05.06") and 8.1/8.4 ("dvhe.08.07") are also always supported. |
| media::EME_CODEC_AVC1 | media::EME_CODEC_AAC | |
| media::EME_CODEC_DOLBY_VISION_HEVC, |
| // On Windows, MediaFoundation Clear Key CDM requires identifier, |
| // persistent state and HW secure codecs. We pretent to require these for |
| // testing purposes. |
| media::EmeConfig{ |
| .identifier = media::EmeConfigRuleState::kRequired, |
| .persistence = media::EmeConfigRuleState::kRequired, |
| .hw_secure_codecs = media::EmeConfigRuleState::kRequired}, |
| EmeFeatureSupport::ALWAYS_ENABLED, EmeFeatureSupport::ALWAYS_ENABLED)); |
| #endif // BUILDFLAG(USE_PROPRIETARY_CODECS) |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| void AddAndroidPlatformKeySystem(const std::string& key_system, |
| const media::KeySystemCapability& capability, |
| bool can_persist_data, |
| KeySystemInfos* key_systems) { |
| DCHECK_NE(key_system, kWidevineKeySystem); |
| |
| // When using MediaDrm, we assume it'll always try to persist some data. |
| // If we don't allow data to be persisted, then skip this key system. |
| if (!can_persist_data) { |
| DVLOG(2) << __func__ << ": Key system " << key_system |
| << " not supported in incognito process."; |
| return; |
| } |
| |
| // Codecs and encryption schemes. |
| SupportedCodecs sw_secure_codecs = media::EME_CODEC_NONE; |
| SupportedCodecs hw_secure_codecs = media::EME_CODEC_NONE; |
| base::flat_set<::media::EncryptionScheme> sw_secure_encryption_schemes; |
| base::flat_set<::media::EncryptionScheme> hw_secure_encryption_schemes; |
| |
| if (capability.sw_cdm_capability_or_status.has_value()) { |
| const auto sw_secure_capability = |
| capability.sw_cdm_capability_or_status.value(); |
| sw_secure_codecs = GetSupportedCodecs(sw_secure_capability); |
| sw_secure_encryption_schemes = sw_secure_capability.encryption_schemes; |
| DVLOG(2) << "Software secure " << key_system << " supported"; |
| } |
| |
| if (capability.hw_cdm_capability_or_status.has_value()) { |
| const auto hw_secure_capability = |
| capability.hw_cdm_capability_or_status.value(); |
| hw_secure_codecs = GetSupportedCodecs(hw_secure_capability); |
| hw_secure_encryption_schemes = hw_secure_capability.encryption_schemes; |
| DVLOG(2) << "Hardware secure " << key_system << " supported"; |
| } |
| |
| key_systems->push_back(std::make_unique<AndroidKeySystemInfo>( |
| key_system, sw_secure_codecs, sw_secure_encryption_schemes, |
| hw_secure_codecs, hw_secure_encryption_schemes)); |
| } |
| #endif // BUILDFLAG(IS_ANDROID) |
| |
| void OnKeySystemSupportUpdated( |
| bool can_persist_data, |
| media::GetSupportedKeySystemsCB cb, |
| content::KeySystemCapabilities key_system_capabilities) { |
| KeySystemInfos key_systems; |
| for (const auto& [key_system, capability] : key_system_capabilities) { |
| #if BUILDFLAG(ENABLE_WIDEVINE) |
| if (key_system == kWidevineKeySystem) { |
| AddWidevine(capability, can_persist_data, &key_systems); |
| continue; |
| } |
| #endif // BUILDFLAG(ENABLE_WIDEVINE) |
| |
| if (key_system == media::kExternalClearKeyKeySystem) { |
| AddExternalClearKey(capability, &key_systems); |
| continue; |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| #if BUILDFLAG(ENABLE_PLAYREADY) |
| if (key_system == kPlayReadyKeySystemRecommendationDefault) { |
| AddPlayReady(capability, can_persist_data, &key_systems); |
| continue; |
| } |
| #endif // BUILDFLAG(ENABLE_PLAYREADY) |
| |
| if (key_system == media::kMediaFoundationClearKeyKeySystem) { |
| AddMediaFoundationClearKey(capability, &key_systems); |
| continue; |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| #if BUILDFLAG(IS_ANDROID) |
| AddAndroidPlatformKeySystem(key_system, capability, can_persist_data, |
| &key_systems); |
| #else |
| DLOG(ERROR) << "Unrecognized key system: " << key_system; |
| #endif // BUILDFLAG(IS_ANDROID) |
| } |
| |
| cb.Run(std::move(key_systems)); |
| } |
| |
| } // namespace |
| |
| std::unique_ptr<media::KeySystemSupportRegistration> |
| GetSupportedKeySystemsUpdates(content::RenderFrame* render_frame, |
| bool can_persist_data, |
| media::GetSupportedKeySystemsCB cb) { |
| return content::ObserveKeySystemSupportUpdate( |
| render_frame, base::BindRepeating(&OnKeySystemSupportUpdated, |
| can_persist_data, std::move(cb))); |
| } |
| |
| } // namespace cdm |