From 8fd31a3e07ae0c81985001bf48b044b26ab43735 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 7 Sep 2018 22:43:39 -0700 Subject: [PATCH] build: [gn] widevine cdm support behind flag (3-0-x) (#14497) --- atom/app/atom_content_client.cc | 200 ++++++++------- atom/renderer/renderer_client_base.cc | 13 +- atom/renderer/renderer_client_base.h | 4 + chromium_src/chrome/common/chrome_paths.cc | 20 -- .../renderer/media/chrome_key_systems.cc | 236 ++++++++++-------- .../media/chrome_key_systems_provider.cc | 78 ++++++ .../media/chrome_key_systems_provider.h | 64 +++++ electron.gyp | 3 + filenames.gypi | 2 + 9 files changed, 405 insertions(+), 215 deletions(-) create mode 100644 chromium_src/chrome/renderer/media/chrome_key_systems_provider.cc create mode 100644 chromium_src/chrome/renderer/media/chrome_key_systems_provider.h diff --git a/atom/app/atom_content_client.cc b/atom/app/atom_content_client.cc index f17ae3137032..86151f0e5f8c 100644 --- a/atom/app/atom_content_client.cc +++ b/atom/app/atom_content_client.cc @@ -20,12 +20,17 @@ #include "content/public/common/user_agent.h" #include "media/media_features.h" #include "ppapi/shared_impl/ppapi_permissions.h" +#include "third_party/widevine/cdm/widevine_cdm_common.h" #include "ui/base/l10n/l10n_util.h" #include "url/url_constants.h" -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) +#if defined(WIDEVINE_CDM_AVAILABLE) +#include "base/native_library.h" +#include "base/strings/stringprintf.h" #include "chrome/common/widevine_cdm_constants.h" -#endif +#include "content/public/common/cdm_info.h" +#include "media/base/video_codecs.h" +#endif // defined(WIDEVINE_CDM_AVAILABLE) #if defined(ENABLE_PDF_VIEWER) #include "atom/common/atom_constants.h" @@ -36,6 +41,67 @@ namespace atom { namespace { +#if defined(WIDEVINE_CDM_AVAILABLE) +bool IsWidevineAvailable(base::FilePath* adapter_path, + base::FilePath* cdm_path, + std::vector* codecs_supported) { + static enum { + NOT_CHECKED, + FOUND, + NOT_FOUND, + } widevine_cdm_file_check = NOT_CHECKED; + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + *adapter_path = command_line->GetSwitchValuePath(switches::kWidevineCdmPath); + if (!adapter_path->empty()) { + *cdm_path = adapter_path->DirName().AppendASCII( + base::GetNativeLibraryName(kWidevineCdmLibraryName)); + if (widevine_cdm_file_check == NOT_CHECKED) { + widevine_cdm_file_check = + (base::PathExists(*adapter_path) && base::PathExists(*cdm_path)) + ? FOUND + : NOT_FOUND; + } + if (widevine_cdm_file_check == FOUND) { + // Add the supported codecs as if they came from the component manifest. + // This list must match the CDM that is being bundled with Chrome. + codecs_supported->push_back(media::VideoCodec::kCodecVP8); + codecs_supported->push_back(media::VideoCodec::kCodecVP9); +#if BUILDFLAG(USE_PROPRIETARY_CODECS) + codecs_supported->push_back(media::VideoCodec::kCodecH264); +#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) + return true; + } + } + return false; +} +void AddWidevineAdapterFromCommandLine( + base::CommandLine* command_line, + std::vector* plugins) { + base::FilePath adapter_path; + base::FilePath cdm_path; + std::vector video_codecs_supported; + if (IsWidevineAvailable(&adapter_path, &cdm_path, &video_codecs_supported)) { + auto cdm_version_string = + command_line->GetSwitchValueASCII(switches::kWidevineCdmVersion); + content::PepperPluginInfo info; + info.is_out_of_process = true; + info.path = adapter_path; + info.name = kWidevineCdmDisplayName; + info.description = + base::StringPrintf("%s (version: %s)", kWidevineCdmDescription, + cdm_version_string.c_str()); + info.version = cdm_version_string; + info.permissions = kWidevineCdmPluginPermissions; + content::WebPluginMimeType mime_type(kWidevineCdmPluginMimeType, + kWidevineCdmPluginExtension, + kWidevineCdmPluginMimeTypeDescription); + info.mime_types.push_back(mime_type); + plugins->push_back(info); + } +} +#endif // defined(WIDEVINE_CDM_AVAILABLE) + +#if defined(ENABLE_PEPPER_FLASH) content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, const std::string& version) { content::PepperPluginInfo plugin; @@ -75,29 +141,23 @@ content::PepperPluginInfo CreatePepperFlashInfo(const base::FilePath& path, return plugin; } -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) -content::PepperPluginInfo CreateWidevineCdmInfo(const base::FilePath& path, - const std::string& version) { - content::PepperPluginInfo widevine_cdm; - widevine_cdm.is_out_of_process = true; - widevine_cdm.path = path; - widevine_cdm.name = kWidevineCdmDisplayName; - widevine_cdm.description = - kWidevineCdmDescription + std::string(" (version: ") + version + ")"; - widevine_cdm.version = version; - content::WebPluginMimeType widevine_cdm_mime_type( - kWidevineCdmPluginMimeType, kWidevineCdmPluginExtension, - kWidevineCdmPluginMimeTypeDescription); +void AddPepperFlashFromCommandLine( + base::CommandLine* command_line, + std::vector* plugins) { + base::FilePath flash_path = + command_line->GetSwitchValuePath(switches::kPpapiFlashPath); + if (flash_path.empty()) + return; - widevine_cdm.mime_types.push_back(widevine_cdm_mime_type); - widevine_cdm.permissions = kWidevineCdmPluginPermissions; + auto flash_version = + command_line->GetSwitchValueASCII(switches::kPpapiFlashVersion); - return widevine_cdm; + plugins->push_back(CreatePepperFlashInfo(flash_path, flash_version)); } -#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) +#endif // defined(ENABLE_PEPPER_FLASH) -#if defined(ENABLE_PDF_VIEWER) void ComputeBuiltInPlugins(std::vector* plugins) { +#if defined(ENABLE_PDF_VIEWER) content::PepperPluginInfo pdf_info; pdf_info.is_internal = true; pdf_info.is_out_of_process = true; @@ -114,8 +174,8 @@ void ComputeBuiltInPlugins(std::vector* plugins) { chrome_pdf::PPP_ShutdownModule; pdf_info.permissions = ppapi::PERMISSION_PRIVATE | ppapi::PERMISSION_DEV; plugins->push_back(pdf_info); -} #endif // defined(ENABLE_PDF_VIEWER) +} void ConvertStringWithSeparatorToVector(std::vector* vec, const char* separator, @@ -129,42 +189,6 @@ void ConvertStringWithSeparatorToVector(std::vector* vec, } // namespace -void AddPepperFlashFromCommandLine( - std::vector* plugins) { - auto* command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath flash_path = - command_line->GetSwitchValuePath(switches::kPpapiFlashPath); - if (flash_path.empty()) - return; - - auto flash_version = - command_line->GetSwitchValueASCII(switches::kPpapiFlashVersion); - - plugins->push_back(CreatePepperFlashInfo(flash_path, flash_version)); -} - -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) -void AddWidevineCdmFromCommandLine( - std::vector* plugins) { - auto* command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath widevine_cdm_path = - command_line->GetSwitchValuePath(switches::kWidevineCdmPath); - if (widevine_cdm_path.empty()) - return; - - if (!base::PathExists(widevine_cdm_path)) - return; - - auto widevine_cdm_version = - command_line->GetSwitchValueASCII(switches::kWidevineCdmVersion); - if (widevine_cdm_version.empty()) - return; - - plugins->push_back( - CreateWidevineCdmInfo(widevine_cdm_path, widevine_cdm_version)); -} -#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) - AtomContentClient::AtomContentClient() {} AtomContentClient::~AtomContentClient() {} @@ -200,45 +224,43 @@ void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) { void AtomContentClient::AddPepperPlugins( std::vector* plugins) { - AddPepperFlashFromCommandLine(plugins); -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) - AddWidevineCdmFromCommandLine(plugins); -#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) -#if defined(ENABLE_PDF_VIEWER) + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); +#if defined(ENABLE_PEPPER_FLASH) + AddPepperFlashFromCommandLine(command_line, plugins); +#endif // defined(ENABLE_PEPPER_FLASH) +#if defined(WIDEVINE_CDM_AVAILABLE) + AddWidevineAdapterFromCommandLine(command_line, plugins); +#endif // defined(WIDEVINE_CDM_AVAILABLE) ComputeBuiltInPlugins(plugins); -#endif // defined(ENABLE_PDF_VIEWER) } void AtomContentClient::AddContentDecryptionModules( std::vector* cdms, std::vector* cdm_host_file_paths) { -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) - auto command_line = base::CommandLine::ForCurrentProcess(); - base::FilePath widevine_cdm_path = - command_line->GetSwitchValuePath(switches::kWidevineCdmPath); - if (widevine_cdm_path.empty()) - return; + if (cdms) { +#if defined(WIDEVINE_CDM_AVAILABLE) + base::FilePath adapter_path; + base::FilePath cdm_path; + std::vector video_codecs_supported; + bool supports_persistent_license = false; + if (IsWidevineAvailable(&adapter_path, &cdm_path, + &video_codecs_supported)) { + base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); + auto cdm_version_string = + command_line->GetSwitchValueASCII(switches::kWidevineCdmVersion); + // CdmInfo needs |path| to be the actual Widevine library, + // not the adapter, so adjust as necessary. It will be in the + // same directory as the installed adapter. + const base::Version version(cdm_version_string); + DCHECK(version.IsValid()); - if (!base::PathExists(widevine_cdm_path)) - return; - - auto widevine_cdm_version = - command_line->GetSwitchValueASCII(switches::kWidevineCdmVersion); - if (widevine_cdm_version.empty()) - return; - - std::vector supported_video_codecs; - supported_video_codecs.push_back(media::VideoCodec::kCodecVP8); - supported_video_codecs.push_back(media::VideoCodec::kCodecVP9); -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - supported_video_codecs.push_back(media::VideoCodec::kCodecH264); -#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) - content::CdmRegistry::GetInstance()->RegisterCdm( - content::CdmInfo(kWidevineCdmDisplayName, kWidevineCdmGuid, - base::Version(widevine_cdm_version), widevine_cdm_path, - kWidevineCdmFileSystemId, supported_video_codecs, false, - kWidevineKeySystem, false)); -#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) + cdms->push_back(content::CdmInfo( + kWidevineCdmDisplayName, kWidevineCdmGuid, version, cdm_path, + kWidevineCdmFileSystemId, video_codecs_supported, + supports_persistent_license, kWidevineKeySystem, false)); + } +#endif // defined(WIDEVINE_CDM_AVAILABLE) + } } } // namespace atom diff --git a/atom/renderer/renderer_client_base.cc b/atom/renderer/renderer_client_base.cc index 68ca0d2a3899..cd0c3025ddf5 100644 --- a/atom/renderer/renderer_client_base.cc +++ b/atom/renderer/renderer_client_base.cc @@ -19,7 +19,6 @@ #include "base/process/process.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" -#include "chrome/renderer/media/chrome_key_systems.h" #include "chrome/renderer/pepper/pepper_helper.h" #include "chrome/renderer/printing/print_web_view_helper.h" #include "chrome/renderer/tts_dispatcher.h" @@ -222,7 +221,17 @@ bool RendererClientBase::OverrideCreatePlugin( void RendererClientBase::AddSupportedKeySystems( std::vector>* key_systems) { - AddChromeKeySystems(key_systems); +#if defined(WIDEVINE_CDM_AVAILABLE) + key_systems_provider_.AddSupportedKeySystems(key_systems); +#endif +} + +bool RendererClientBase::IsKeySystemsUpdateNeeded() { +#if defined(WIDEVINE_CDM_AVAILABLE) + return key_systems_provider_.IsKeySystemsUpdateNeeded(); +#else + return false; +#endif } v8::Local RendererClientBase::GetContext( diff --git a/atom/renderer/renderer_client_base.h b/atom/renderer/renderer_client_base.h index f04be0a0fb55..9513bbb2b342 100644 --- a/atom/renderer/renderer_client_base.h +++ b/atom/renderer/renderer_client_base.h @@ -8,6 +8,7 @@ #include #include +#include "chrome/renderer/media/chrome_key_systems_provider.h" #include "content/public/renderer/content_renderer_client.h" #include "third_party/WebKit/public/web/WebLocalFrame.h" @@ -50,8 +51,11 @@ class RendererClientBase : public content::ContentRendererClient { std::vector>* key_systems) override; + bool IsKeySystemsUpdateNeeded() override; + private: std::unique_ptr preferences_manager_; + ChromeKeySystemsProvider key_systems_provider_; bool isolated_world_; // An increasing ID used for indentifying an V8 context in this process. diff --git a/chromium_src/chrome/common/chrome_paths.cc b/chromium_src/chrome/common/chrome_paths.cc index 30fe1fd7ba96..dbc0691aeb89 100644 --- a/chromium_src/chrome/common/chrome_paths.cc +++ b/chromium_src/chrome/common/chrome_paths.cc @@ -15,10 +15,7 @@ #include "base/version.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths_internal.h" -#include "chrome/common/widevine_cdm_constants.h" #include "media/media_features.h" -#include "third_party/widevine/cdm/stub/widevine_cdm_version.h" -#include "third_party/widevine/cdm/widevine_cdm_common.h" #if defined(OS_ANDROID) #include "base/android/path_utils.h" @@ -361,23 +358,6 @@ bool PathProvider(int key, base::FilePath* result) { #endif cur = cur.Append(FILE_PATH_LITERAL("pnacl")); break; -#if defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) -#if defined(WIDEVINE_CDM_IS_COMPONENT) - case chrome::DIR_COMPONENT_WIDEVINE_CDM: - if (!PathService::Get(chrome::DIR_USER_DATA, &cur)) - return false; - cur = cur.AppendASCII(kWidevineCdmBaseDirectory); - break; -#endif // defined(WIDEVINE_CDM_IS_COMPONENT) - // TODO(xhwang): FILE_WIDEVINE_CDM_ADAPTER has different meanings. - // In the component case, this is the source adapter. Otherwise, it is the - // actual Pepper module that gets loaded. - case chrome::FILE_WIDEVINE_CDM_ADAPTER: - if (!GetInternalPluginsDirectory(&cur)) - return false; - cur = cur.AppendASCII(kWidevineCdmAdapterFileName); - break; -#endif // defined(WIDEVINE_CDM_AVAILABLE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) case chrome::FILE_RESOURCES_PACK: #if defined(OS_MACOSX) && !defined(OS_IOS) if (base::mac::AmIBundled()) { diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems.cc b/chromium_src/chrome/renderer/media/chrome_key_systems.cc index c4ab859f06ba..fe38d0c0e646 100644 --- a/chromium_src/chrome/renderer/media/chrome_key_systems.cc +++ b/chromium_src/chrome/renderer/media/chrome_key_systems.cc @@ -13,116 +13,66 @@ #include "base/strings/string16.h" #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" +#include "build/build_config.h" +#if 0 +#include "chrome/renderer/chrome_render_thread_observer.h" +#endif +#include "components/cdm/renderer/external_clear_key_key_system_properties.h" #include "components/cdm/renderer/widevine_key_system_properties.h" #include "content/public/renderer/render_thread.h" #include "media/base/eme_constants.h" #include "media/base/key_system_properties.h" #include "media/media_features.h" +#include "third_party/widevine/cdm/widevine_cdm_common.h" #if BUILDFLAG(ENABLE_LIBRARY_CDMS) +#include "base/feature_list.h" #include "content/public/renderer/key_system_support.h" +#include "media/base/media_switches.h" #include "media/base/video_codecs.h" #endif -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. - -// The following must be after widevine_cdm_version.h. - #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) #include #include "base/version.h" #endif +using media::EmeFeatureSupport; +using media::EmeSessionTypeSupport; using media::KeySystemProperties; using media::SupportedCodecs; #if BUILDFLAG(ENABLE_LIBRARY_CDMS) -static const char kExternalClearKeyPepperType[] = - "application/x-ppapi-clearkey-cdm"; - -// KeySystemProperties implementation for external Clear Key systems. -class ExternalClearKeyProperties : public KeySystemProperties { - public: - explicit ExternalClearKeyProperties(const std::string& key_system_name) - : key_system_name_(key_system_name) {} - - std::string GetKeySystemName() const override { return key_system_name_; } - bool IsSupportedInitDataType( - media::EmeInitDataType init_data_type) const override { - switch (init_data_type) { - case media::EmeInitDataType::WEBM: - case media::EmeInitDataType::KEYIDS: - return true; - - case media::EmeInitDataType::CENC: -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - return true; -#else - return false; -#endif // BUILDFLAG(USE_PROPRIETARY_CODECS) - - case media::EmeInitDataType::UNKNOWN: - return false; - } - NOTREACHED(); - return false; - } - - SupportedCodecs GetSupportedCodecs() const override { -#if BUILDFLAG(USE_PROPRIETARY_CODECS) - return media::EME_CODEC_MP4_ALL | media::EME_CODEC_WEBM_ALL; -#else - return media::EME_CODEC_WEBM_ALL; -#endif - } - - media::EmeConfigRule GetRobustnessConfigRule( - media::EmeMediaType media_type, - const std::string& requested_robustness) const override { - return requested_robustness.empty() ? media::EmeConfigRule::SUPPORTED - : media::EmeConfigRule::NOT_SUPPORTED; - } - - // Persistent license sessions are faked. - media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport() - const override { - return media::EmeSessionTypeSupport::SUPPORTED; - } - - media::EmeSessionTypeSupport GetPersistentReleaseMessageSessionSupport() - const override { - return media::EmeSessionTypeSupport::NOT_SUPPORTED; - } - - media::EmeFeatureSupport GetPersistentStateSupport() const override { - return media::EmeFeatureSupport::REQUESTABLE; - } - - media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override { - return media::EmeFeatureSupport::NOT_SUPPORTED; - } - - std::string GetPepperType() const override { - return kExternalClearKeyPepperType; - } - - private: - const std::string key_system_name_; -}; // External Clear Key (used for testing). static void AddExternalClearKey( std::vector>* concrete_key_systems) { + // TODO(xhwang): Move these into an array so we can use a for loop to add + // supported key systems below. static const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey"; static const char kExternalClearKeyDecryptOnlyKeySystem[] = "org.chromium.externalclearkey.decryptonly"; + static const char kExternalClearKeyMessageTypeTestKeySystem[] = + "org.chromium.externalclearkey.messagetypetest"; static const char kExternalClearKeyFileIOTestKeySystem[] = "org.chromium.externalclearkey.fileiotest"; + static const char kExternalClearKeyOutputProtectionTestKeySystem[] = + "org.chromium.externalclearkey.outputprotectiontest"; + static const char kExternalClearKeyPlatformVerificationTestKeySystem[] = + "org.chromium.externalclearkey.platformverificationtest"; static const char kExternalClearKeyInitializeFailKeySystem[] = "org.chromium.externalclearkey.initializefail"; static const char kExternalClearKeyCrashKeySystem[] = "org.chromium.externalclearkey.crash"; + static const char kExternalClearKeyVerifyCdmHostTestKeySystem[] = + "org.chromium.externalclearkey.verifycdmhosttest"; + static const char kExternalClearKeyStorageIdTestKeySystem[] = + "org.chromium.externalclearkey.storageidtest"; + static const char kExternalClearKeyDifferentGuidTestKeySystem[] = + "org.chromium.externalclearkey.differentguid"; + static const char kExternalClearKeyCdmProxyTestKeySystem[] = + "org.chromium.externalclearkey.cdmproxytest"; std::vector supported_video_codecs; bool supports_persistent_license; @@ -133,32 +83,107 @@ static void AddExternalClearKey( } concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyKeySystem)); + new cdm::ExternalClearKeyProperties(kExternalClearKeyKeySystem)); // Add support of decrypt-only mode in ClearKeyCdm. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyDecryptOnlyKeySystem)); + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyDecryptOnlyKeySystem)); - // A key system that triggers FileIO test in ClearKeyCdm. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyFileIOTestKeySystem)); + // A key system that triggers various types of messages in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyMessageTypeTestKeySystem)); + + // A key system that triggers the FileIO test in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyFileIOTestKeySystem)); + + // A key system that triggers the output protection test in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyOutputProtectionTestKeySystem)); + + // A key system that triggers the platform verification test in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyPlatformVerificationTestKeySystem)); // A key system that Chrome thinks is supported by ClearKeyCdm, but actually // will be refused by ClearKeyCdm. This is to test the CDM initialization // failure case. - concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyInitializeFailKeySystem)); + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyInitializeFailKeySystem)); // A key system that triggers a crash in ClearKeyCdm. concrete_key_systems->emplace_back( - new ExternalClearKeyProperties(kExternalClearKeyCrashKeySystem)); + new cdm::ExternalClearKeyProperties(kExternalClearKeyCrashKeySystem)); + + // A key system that triggers the verify host files test in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyVerifyCdmHostTestKeySystem)); + + // A key system that fetches the Storage ID in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyStorageIdTestKeySystem)); + + // A key system that is registered with a different CDM GUID. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyDifferentGuidTestKeySystem)); + + // A key system that triggers CDM Proxy test in ClearKeyCdm. + concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties( + kExternalClearKeyCdmProxyTestKeySystem)); } #if defined(WIDEVINE_CDM_AVAILABLE) +// Returns persistent-license session support. +EmeSessionTypeSupport GetPersistentLicenseSupport(bool supported_by_the_cdm) { +#if 0 + // Do not support persistent-license if the process cannot persist data. + // TODO(crbug.com/457487): Have a better plan on this. See bug for details. + if (ChromeRenderThreadObserver::is_incognito_process()) { + DVLOG(2) << __func__ << ": Not supported in incognito process."; + return EmeSessionTypeSupport::NOT_SUPPORTED; + } +#endif + + if (!supported_by_the_cdm) { + DVLOG(2) << __func__ << ": Not supported by the CDM."; + return EmeSessionTypeSupport::NOT_SUPPORTED; + } + +// On ChromeOS, platform verification is similar to CDM host verification. +#if BUILDFLAG(ENABLE_CDM_HOST_VERIFICATION) || defined(OS_CHROMEOS) + bool cdm_host_verification_potentially_supported = true; +#else + bool cdm_host_verification_potentially_supported = false; +#endif + + // If we are sure CDM host verification is NOT supported, we should not + // support persistent-license. + if (!cdm_host_verification_potentially_supported) { + DVLOG(2) << __func__ << ": Not supported without CDM host verification."; + return EmeSessionTypeSupport::NOT_SUPPORTED; + } + +#if defined(OS_CHROMEOS) + // On ChromeOS, platform verification (similar to CDM host verification) + // requires identifier to be 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 EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER; +#elif BUILDFLAG(ENABLE_CDM_STORAGE_ID) + // On other platforms, we require storage ID to support persistent license. + return EmeSessionTypeSupport::SUPPORTED; +#else + // Storage ID not implemented, so no support for persistent license. + DVLOG(2) << __func__ << ": Not supported without CDM storage ID."; + return EmeSessionTypeSupport::NOT_SUPPORTED; +#endif // defined(OS_CHROMEOS) +} + static void AddPepperBasedWidevine( std::vector>* concrete_key_systems) { #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) - Version glibc_version(gnu_get_libc_version()); + base::Version glibc_version(gnu_get_libc_version()); DCHECK(glibc_version.IsValid()); if (glibc_version < base::Version(WIDEVINE_CDM_MIN_GLIBC_VERSION)) return; @@ -205,27 +230,28 @@ static void AddPepperBasedWidevine( } } + EmeSessionTypeSupport persistent_license_support = + GetPersistentLicenseSupport(supports_persistent_license); + using Robustness = cdm::WidevineKeySystemProperties::Robustness; + concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties( supported_codecs, #if defined(OS_CHROMEOS) - media::EmeRobustness::HW_SECURE_ALL, // Maximum audio robustness. - media::EmeRobustness::HW_SECURE_ALL, // Maximim video robustness. - media::EmeSessionTypeSupport:: - SUPPORTED_WITH_IDENTIFIER, // Persistent-license. - media::EmeSessionTypeSupport:: - NOT_SUPPORTED, // Persistent-release-message. - media::EmeFeatureSupport::REQUESTABLE, // Persistent state. - media::EmeFeatureSupport::REQUESTABLE)); // Distinctive identifier. -#else // (Desktop) - Robustness::SW_SECURE_CRYPTO, // Maximum audio robustness. - Robustness::SW_SECURE_DECODE, // Maximum video robustness. - media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent-license. - media::EmeSessionTypeSupport:: - NOT_SUPPORTED, // persistent-release-message. - media::EmeFeatureSupport::REQUESTABLE, // Persistent state. - media::EmeFeatureSupport::NOT_SUPPORTED)); // Distinctive identifier. -#endif // defined(OS_CHROMEOS) + Robustness::HW_SECURE_ALL, // Maximum audio robustness. + Robustness::HW_SECURE_ALL, // Maximum video robustness. + persistent_license_support, // Persistent-license. + EmeSessionTypeSupport::NOT_SUPPORTED, // Persistent-release-message. + EmeFeatureSupport::REQUESTABLE, // Persistent state. + EmeFeatureSupport::REQUESTABLE)); // Distinctive identifier. +#else // Desktop + Robustness::SW_SECURE_CRYPTO, // Maximum audio robustness. + Robustness::SW_SECURE_DECODE, // Maximum video robustness. + persistent_license_support, // persistent-license. + EmeSessionTypeSupport::NOT_SUPPORTED, // persistent-release-message. + EmeFeatureSupport::REQUESTABLE, // Persistent state. + EmeFeatureSupport::NOT_SUPPORTED)); // Distinctive identifier. +#endif // defined(OS_CHROMEOS) } #endif // defined(WIDEVINE_CDM_AVAILABLE) #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) @@ -233,10 +259,12 @@ static void AddPepperBasedWidevine( void AddChromeKeySystems( std::vector>* key_systems_properties) { #if BUILDFLAG(ENABLE_LIBRARY_CDMS) - AddExternalClearKey(key_systems_properties); + if (base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting)) + AddExternalClearKey(key_systems_properties); #if defined(WIDEVINE_CDM_AVAILABLE) AddPepperBasedWidevine(key_systems_properties); #endif // defined(WIDEVINE_CDM_AVAILABLE) + #endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) } diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems_provider.cc b/chromium_src/chrome/renderer/media/chrome_key_systems_provider.cc new file mode 100644 index 000000000000..a3699f8bc6c3 --- /dev/null +++ b/chromium_src/chrome/renderer/media/chrome_key_systems_provider.cc @@ -0,0 +1,78 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/renderer/media/chrome_key_systems_provider.h" + +#include "base/time/default_tick_clock.h" +#include "chrome/renderer/media/chrome_key_systems.h" +#include "third_party/widevine/cdm/widevine_cdm_common.h" + +ChromeKeySystemsProvider::ChromeKeySystemsProvider() + : has_updated_(false), + is_update_needed_(true), + tick_clock_(base::DefaultTickClock::GetInstance()) {} + +ChromeKeySystemsProvider::~ChromeKeySystemsProvider() {} + +void ChromeKeySystemsProvider::AddSupportedKeySystems( + std::vector>* key_systems) { + DCHECK(key_systems); + DCHECK(thread_checker_.CalledOnValidThread()); + + if (!test_provider_.is_null()) { + test_provider_.Run(key_systems); + } else { + AddChromeKeySystems(key_systems); + } + + has_updated_ = true; + last_update_time_ticks_ = tick_clock_->NowTicks(); + +// Check whether all potentially supported key systems are supported. If so, +// no need to update again. +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT) + for (const auto& properties : *key_systems) { + if (properties->GetKeySystemName() == kWidevineKeySystem) { + is_update_needed_ = false; + } + } +#else + is_update_needed_ = false; +#endif +} + +bool ChromeKeySystemsProvider::IsKeySystemsUpdateNeeded() { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Always needs update if we have never updated, regardless the + // |last_update_time_ticks_|'s initial value. + if (!has_updated_) { + DCHECK(is_update_needed_); + return true; + } + + if (!is_update_needed_) + return false; + + // The update could be expensive. For example, it could involve a sync IPC to + // the browser process. Use a minimum update interval to avoid unnecessarily + // frequent update. + static const int kMinUpdateIntervalInMilliseconds = 1000; + if ((tick_clock_->NowTicks() - last_update_time_ticks_).InMilliseconds() < + kMinUpdateIntervalInMilliseconds) { + return false; + } + + return true; +} + +void ChromeKeySystemsProvider::SetTickClockForTesting( + base::TickClock* tick_clock) { + tick_clock_ = tick_clock; +} + +void ChromeKeySystemsProvider::SetProviderDelegateForTesting( + const KeySystemsProviderDelegate& test_provider) { + test_provider_ = test_provider; +} diff --git a/chromium_src/chrome/renderer/media/chrome_key_systems_provider.h b/chromium_src/chrome/renderer/media/chrome_key_systems_provider.h new file mode 100644 index 000000000000..5e3eb0508f94 --- /dev/null +++ b/chromium_src/chrome/renderer/media/chrome_key_systems_provider.h @@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_PROVIDER_H_ +#define CHROME_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_PROVIDER_H_ + +#include +#include + +#include "base/callback.h" +#include "base/threading/thread_checker.h" +#include "base/time/tick_clock.h" +#include "base/time/time.h" +#include "media/base/key_system_properties.h" + +typedef std::vector> + KeySystemPropertiesVector; +typedef base::Callback + KeySystemsProviderDelegate; + +class ChromeKeySystemsProvider { + public: + ChromeKeySystemsProvider(); + ~ChromeKeySystemsProvider(); + + // Adds properties for supported key systems. + void AddSupportedKeySystems(KeySystemPropertiesVector* key_systems); + + // Returns whether client key systems properties should be updated. + // TODO(chcunningham): Refactor this to a proper change "observer" API that is + // less fragile (don't assume AddSupportedKeySystems has just one caller). + bool IsKeySystemsUpdateNeeded(); + + void SetTickClockForTesting(base::TickClock* tick_clock); + + void SetProviderDelegateForTesting( + const KeySystemsProviderDelegate& test_provider); + + private: + // Whether AddSupportedKeySystems() has ever been called. + bool has_updated_; + + // Whether a future update is needed. For example, when some potentially + // supported key systems are NOT supported yet. This could happen when the + // required component for a key system is not yet available. + bool is_update_needed_; + + // Throttle how often we signal an update is needed to avoid unnecessary high + // frequency of expensive IPC calls. + base::TimeTicks last_update_time_ticks_; + base::TickClock* tick_clock_; + + // Ensure all methods are called from the same (Main) thread. + base::ThreadChecker thread_checker_; + + // For unit tests to inject their own key systems. Will bypass adding default + // Chrome key systems when set. + KeySystemsProviderDelegate test_provider_; + + DISALLOW_COPY_AND_ASSIGN(ChromeKeySystemsProvider); +}; + +#endif // CHROME_RENDERER_MEDIA_CHROME_KEY_SYSTEMS_PROVIDER_H_ diff --git a/electron.gyp b/electron.gyp index 77d60d7faaf5..ff455185678f 100644 --- a/electron.gyp +++ b/electron.gyp @@ -288,6 +288,9 @@ # Enables SkBitmap size 64 operations 'SK_SUPPORT_LEGACY_SAFESIZE64', + + # Enables widevine cdm support + 'WIDEVINE_CDM_AVAILABLE', ], 'sources': [ '<@(lib_sources)', diff --git a/filenames.gypi b/filenames.gypi index b8f813a6d318..9aa6f5ea335b 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -648,6 +648,8 @@ 'chromium_src/chrome/common/widevine_cdm_constants.h', 'chromium_src/chrome/renderer/media/chrome_key_systems.cc', 'chromium_src/chrome/renderer/media/chrome_key_systems.h', + 'chromium_src/chrome/renderer/media/chrome_key_systems_provider.cc', + 'chromium_src/chrome/renderer/media/chrome_key_systems_provider.h', 'chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.cc', 'chromium_src/chrome/renderer/pepper/chrome_renderer_pepper_host_factory.h', 'chromium_src/chrome/renderer/pepper/pepper_flash_font_file_host.cc',