From 150a22a49c013b612d8cc81a6151abd2cfcd3ca9 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Wed, 5 Oct 2016 18:19:19 -0400 Subject: [PATCH] Add CefRegisterWidevineCdm function and remove component updater support (issue #2009) --- BUILD.gn | 9 +- cef.gyp | 8 +- cef_paths.gypi | 4 + cef_paths2.gypi | 3 + include/capi/cef_web_plugin_capi.h | 71 +++ include/cef_web_plugin.h | 66 +++ include/internal/cef_types.h | 25 ++ libcef/browser/chrome_browser_process_stub.cc | 2 +- .../cef_component_updater_configurator.cc | 167 ------- .../cef_component_updater_configurator.h | 31 -- libcef/browser/content_browser_client.cc | 20 +- libcef/browser/context.cc | 49 +-- libcef/browser/context.h | 9 - libcef/browser/web_plugin_impl.cc | 34 ++ libcef/common/cef_switches.cc | 6 - libcef/common/cef_switches.h | 2 - libcef/common/content_client.cc | 76 +--- libcef/common/main_delegate.cc | 23 - libcef/common/widevine_loader.cc | 406 ++++++++++++++++++ libcef/common/widevine_loader.h | 64 +++ .../cpptoc/register_cdm_callback_cpptoc.cc | 60 +++ .../cpptoc/register_cdm_callback_cpptoc.h | 37 ++ .../ctocpp/register_cdm_callback_ctocpp.cc | 54 +++ .../ctocpp/register_cdm_callback_ctocpp.h | 41 ++ libcef_dll/libcef_dll.cc | 18 + libcef_dll/wrapper/libcef_dll_wrapper.cc | 18 + libcef_dll/wrapper_types.h | 1 + tests/cefclient/browser/binding_test.cc | 2 - tests/cefclient/browser/drm_test.cc | 120 ++++++ tests/cefclient/browser/drm_test.h | 20 + tests/cefclient/browser/main_context_impl.cc | 11 + tests/cefclient/browser/resource.h | 37 +- tests/cefclient/browser/resource_util_win.cc | 1 + tests/cefclient/browser/test_runner.cc | 4 + tests/cefclient/common/client_switches.cc | 1 + tests/cefclient/common/client_switches.h | 1 + tests/cefclient/resources/drm.html | 126 ++++++ tests/cefclient/resources/other_tests.html | 1 + tests/cefclient/resources/win/cefclient.rc | 1 + tools/make_distrib.py | 2 + 40 files changed, 1241 insertions(+), 390 deletions(-) delete mode 100644 libcef/browser/component_updater/cef_component_updater_configurator.cc delete mode 100644 libcef/browser/component_updater/cef_component_updater_configurator.h create mode 100644 libcef/common/widevine_loader.cc create mode 100644 libcef/common/widevine_loader.h create mode 100644 libcef_dll/cpptoc/register_cdm_callback_cpptoc.cc create mode 100644 libcef_dll/cpptoc/register_cdm_callback_cpptoc.h create mode 100644 libcef_dll/ctocpp/register_cdm_callback_ctocpp.cc create mode 100644 libcef_dll/ctocpp/register_cdm_callback_ctocpp.h create mode 100644 tests/cefclient/browser/drm_test.cc create mode 100644 tests/cefclient/browser/drm_test.h create mode 100644 tests/cefclient/resources/drm.html diff --git a/BUILD.gn b/BUILD.gn index b99125b7f..10ec99a3b 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -230,8 +230,6 @@ static_library("libcef_static") { "libcef/browser/chrome_browser_process_stub.h", "libcef/browser/chrome_profile_stub.cc", "libcef/browser/chrome_profile_stub.h", - "libcef/browser/component_updater/cef_component_updater_configurator.cc", - "libcef/browser/component_updater/cef_component_updater_configurator.h", "libcef/browser/content_browser_client.cc", "libcef/browser/content_browser_client.h", "libcef/browser/context.cc", @@ -465,6 +463,8 @@ static_library("libcef_static") { "libcef/common/value_base.h", "libcef/common/values_impl.cc", "libcef/common/values_impl.h", + "libcef/common/widevine_loader.cc", + "libcef/common/widevine_loader.h", "libcef/renderer/browser_impl.cc", "libcef/renderer/browser_impl.h", "libcef/renderer/content_renderer_client.cc", @@ -636,10 +636,6 @@ static_library("libcef_static") { "//extensions/shell/browser/shell_display_info_provider.h", "//extensions/shell/browser/shell_web_contents_modal_dialog_manager.cc", - # Include sources for component-updater support. - "//chrome/browser/component_updater/widevine_cdm_component_installer.cc", - "//chrome/browser/component_updater/widevine_cdm_component_installer.h", - # Include sources for widevine support. "//chrome/common/widevine_cdm_constants.cc", "//chrome/common/widevine_cdm_constants.h", @@ -740,7 +736,6 @@ static_library("libcef_static") { "//base/third_party/dynamic_annotations", "//cc", "//components/cdm/renderer", - "//components/component_updater", "//components/content_settings/core/browser", "//components/content_settings/core/common", "//components/crash/content/app:app_breakpad_mac_win_to_be_deleted", diff --git a/cef.gyp b/cef.gyp index 791d2451f..2a133511b 100644 --- a/cef.gyp +++ b/cef.gyp @@ -978,7 +978,6 @@ # chrome/common/chrome_contants.cc '<(DEPTH)/chrome/common_constants.gyp:version_header', '<(DEPTH)/components/components.gyp:cdm_renderer', - '<(DEPTH)/components/components.gyp:component_updater', '<(DEPTH)/components/components.gyp:content_settings_core_browser', '<(DEPTH)/components/components.gyp:content_settings_core_common', '<(DEPTH)/components/components.gyp:crash_component_breakpad_to_be_deleted', @@ -1088,8 +1087,6 @@ 'libcef/browser/chrome_browser_process_stub.h', 'libcef/browser/chrome_profile_stub.cc', 'libcef/browser/chrome_profile_stub.h', - 'libcef/browser/component_updater/cef_component_updater_configurator.cc', - 'libcef/browser/component_updater/cef_component_updater_configurator.h', 'libcef/browser/content_browser_client.cc', 'libcef/browser/content_browser_client.h', 'libcef/browser/context.cc', @@ -1323,6 +1320,8 @@ 'libcef/common/value_base.h', 'libcef/common/values_impl.cc', 'libcef/common/values_impl.h', + 'libcef/common/widevine_loader.cc', + 'libcef/common/widevine_loader.h', 'libcef/renderer/browser_impl.cc', 'libcef/renderer/browser_impl.h', 'libcef/renderer/content_renderer_client.cc', @@ -1483,9 +1482,6 @@ '<(DEPTH)/extensions/shell/browser/shell_display_info_provider.h', '<(DEPTH)/extensions/shell/browser/shell_web_contents_modal_dialog_manager.cc', '<(grit_out_dir)/grit/component_extension_resources_map.cc', - # Include sources for component-updater support. - '<(DEPTH)/chrome/browser/component_updater/widevine_cdm_component_installer.cc', - '<(DEPTH)/chrome/browser/component_updater/widevine_cdm_component_installer.h', # Include sources for widevine support. '<(DEPTH)/chrome/common/widevine_cdm_constants.cc', '<(DEPTH)/chrome/common/widevine_cdm_constants.h', diff --git a/cef_paths.gypi b/cef_paths.gypi index 13338270d..a96c4725d 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -314,6 +314,8 @@ 'libcef_dll/cpptoc/process_message_cpptoc.h', 'libcef_dll/ctocpp/read_handler_ctocpp.cc', 'libcef_dll/ctocpp/read_handler_ctocpp.h', + 'libcef_dll/ctocpp/register_cdm_callback_ctocpp.cc', + 'libcef_dll/ctocpp/register_cdm_callback_ctocpp.h', 'libcef_dll/ctocpp/render_handler_ctocpp.cc', 'libcef_dll/ctocpp/render_handler_ctocpp.h', 'libcef_dll/ctocpp/render_process_handler_ctocpp.cc', @@ -562,6 +564,8 @@ 'libcef_dll/ctocpp/process_message_ctocpp.h', 'libcef_dll/cpptoc/read_handler_cpptoc.cc', 'libcef_dll/cpptoc/read_handler_cpptoc.h', + 'libcef_dll/cpptoc/register_cdm_callback_cpptoc.cc', + 'libcef_dll/cpptoc/register_cdm_callback_cpptoc.h', 'libcef_dll/cpptoc/render_handler_cpptoc.cc', 'libcef_dll/cpptoc/render_handler_cpptoc.h', 'libcef_dll/cpptoc/render_process_handler_cpptoc.cc', diff --git a/cef_paths2.gypi b/cef_paths2.gypi index 29aae9673..19b1a6f34 100644 --- a/cef_paths2.gypi +++ b/cef_paths2.gypi @@ -149,6 +149,8 @@ 'tests/cefclient/browser/client_types.h', 'tests/cefclient/browser/dialog_test.cc', 'tests/cefclient/browser/dialog_test.h', + 'tests/cefclient/browser/drm_test.cc', + 'tests/cefclient/browser/drm_test.h', 'tests/cefclient/browser/geometry_util.cc', 'tests/cefclient/browser/geometry_util.h', 'tests/cefclient/browser/main_context.cc', @@ -214,6 +216,7 @@ 'tests/cefclient/resources/binding.html', 'tests/cefclient/resources/dialogs.html', 'tests/cefclient/resources/draggable.html', + 'tests/cefclient/resources/drm.html', 'tests/cefclient/resources/localstorage.html', 'tests/cefclient/resources/logo.png', 'tests/cefclient/resources/menu_icon.1x.png', diff --git a/include/capi/cef_web_plugin_capi.h b/include/capi/cef_web_plugin_capi.h index d73050f86..a5cc828e0 100644 --- a/include/capi/cef_web_plugin_capi.h +++ b/include/capi/cef_web_plugin_capi.h @@ -127,6 +127,29 @@ typedef struct _cef_web_plugin_unstable_callback_t { } cef_web_plugin_unstable_callback_t; +/// +// Implement this structure to receive notification when CDM registration is +// complete. The functions of this structure will be called on the browser +// process UI thread. +/// +typedef struct _cef_register_cdm_callback_t { + /// + // Base structure. + /// + cef_base_t base; + + /// + // Method that will be called when CDM registration is complete. |result| will + // be CEF_CDM_REGISTRATION_ERROR_NONE if registration completed successfully. + // Otherwise, |result| and |error_message| will contain additional information + // about why registration failed. + /// + void (CEF_CALLBACK *on_cdm_registration_complete)( + struct _cef_register_cdm_callback_t* self, + cef_cdm_registration_error_t result, const cef_string_t* error_message); +} cef_register_cdm_callback_t; + + /// // Visit web plugin information. Can be called on any thread in the browser // process. @@ -161,6 +184,54 @@ CEF_EXPORT void cef_register_web_plugin_crash(const cef_string_t* path); CEF_EXPORT void cef_is_web_plugin_unstable(const cef_string_t* path, cef_web_plugin_unstable_callback_t* callback); +/// +// Register the Widevine CDM plugin. +// +// The client application is responsible for downloading an appropriate +// platform-specific CDM binary distribution from Google, extracting the +// contents, and building the required directory structure on the local machine. +// The cef_browser_host_t::StartDownload function and CefZipArchive structure +// can be used to implement this functionality in CEF. Contact Google via +// https://www.widevine.com/contact.html for details on CDM download. +// +// |path| is a directory that must contain the following files: +// 1. manifest.json file from the CDM binary distribution (see below). +// 2. widevinecdm file from the CDM binary distribution (e.g. +// widevinecdm.dll on on Windows, libwidevinecdm.dylib on OS X, +// libwidevinecdm.so on Linux). +// 3. widevidecdmadapter file from the CEF binary distribution (e.g. +// widevinecdmadapter.dll on Windows, widevinecdmadapter.plugin on OS X, +// libwidevinecdmadapter.so on Linux). +// +// If any of these files are missing or if the manifest file has incorrect +// contents the registration will fail and |callback| will receive a |result| +// value of CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS. +// +// The manifest.json file must contain the following keys: +// A. "os": Supported OS (e.g. "mac", "win" or "linux"). +// B. "arch": Supported architecture (e.g. "ia32" or "x64"). +// C. "x-cdm-module-versions": Module API version (e.g. "4"). +// D. "x-cdm-interface-versions": Interface API version (e.g. "8"). +// E. "x-cdm-host-versions": Host API version (e.g. "8"). +// F. "version": CDM version (e.g. "1.4.8.903"). +// G. "x-cdm-codecs": List of supported codecs (e.g. "vp8,vp9.0,avc1"). +// +// A through E are used to verify compatibility with the current Chromium +// version. If the CDM is not compatible the registration will fail and +// |callback| will receive a |result| value of +// CEF_CDM_REGISTRATION_ERROR_INCOMPATIBLE. +// +// |callback| will be executed asynchronously once registration is complete. +// +// On Linux this function must be called before cef_initialize() and the +// registration cannot be changed during runtime. If registration is not +// supported at the time that cef_register_widevine_cdm() is called then +// |callback| will receive a |result| value of +// CEF_CDM_REGISTRATION_ERROR_NOT_SUPPORTED. +/// +CEF_EXPORT void cef_register_widevine_cdm(const cef_string_t* path, + cef_register_cdm_callback_t* callback); + #ifdef __cplusplus } #endif diff --git a/include/cef_web_plugin.h b/include/cef_web_plugin.h index b7e199b97..731be7b94 100644 --- a/include/cef_web_plugin.h +++ b/include/cef_web_plugin.h @@ -144,5 +144,71 @@ class CefWebPluginUnstableCallback : public virtual CefBase { void CefIsWebPluginUnstable(const CefString& path, CefRefPtr callback); +/// +// Implement this interface to receive notification when CDM registration is +// complete. The methods of this class will be called on the browser process +// UI thread. +/// +/*--cef(source=client)--*/ +class CefRegisterCdmCallback : public virtual CefBase { + public: + /// + // Method that will be called when CDM registration is complete. |result| + // will be CEF_CDM_REGISTRATION_ERROR_NONE if registration completed + // successfully. Otherwise, |result| and |error_message| will contain + // additional information about why registration failed. + /// + /*--cef(optional_param=error_message)--*/ + virtual void OnCdmRegistrationComplete(cef_cdm_registration_error_t result, + const CefString& error_message) =0; +}; + +/// +// Register the Widevine CDM plugin. +// +// The client application is responsible for downloading an appropriate +// platform-specific CDM binary distribution from Google, extracting the +// contents, and building the required directory structure on the local machine. +// The CefBrowserHost::StartDownload method and CefZipArchive class can be used +// to implement this functionality in CEF. Contact Google via +// https://www.widevine.com/contact.html for details on CDM download. +// +// |path| is a directory that must contain the following files: +// 1. manifest.json file from the CDM binary distribution (see below). +// 2. widevinecdm file from the CDM binary distribution (e.g. +// widevinecdm.dll on on Windows, libwidevinecdm.dylib on OS X, +// libwidevinecdm.so on Linux). +// 3. widevidecdmadapter file from the CEF binary distribution (e.g. +// widevinecdmadapter.dll on Windows, widevinecdmadapter.plugin on OS X, +// libwidevinecdmadapter.so on Linux). +// +// If any of these files are missing or if the manifest file has incorrect +// contents the registration will fail and |callback| will receive a |result| +// value of CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS. +// +// The manifest.json file must contain the following keys: +// A. "os": Supported OS (e.g. "mac", "win" or "linux"). +// B. "arch": Supported architecture (e.g. "ia32" or "x64"). +// C. "x-cdm-module-versions": Module API version (e.g. "4"). +// D. "x-cdm-interface-versions": Interface API version (e.g. "8"). +// E. "x-cdm-host-versions": Host API version (e.g. "8"). +// F. "version": CDM version (e.g. "1.4.8.903"). +// G. "x-cdm-codecs": List of supported codecs (e.g. "vp8,vp9.0,avc1"). +// +// A through E are used to verify compatibility with the current Chromium +// version. If the CDM is not compatible the registration will fail and +// |callback| will receive a |result| value of +// CEF_CDM_REGISTRATION_ERROR_INCOMPATIBLE. +// +// |callback| will be executed asynchronously once registration is complete. +// +// On Linux this function must be called before CefInitialize() and the +// registration cannot be changed during runtime. If registration is not +// supported at the time that CefRegisterWidevineCdm() is called then |callback| +// will receive a |result| value of CEF_CDM_REGISTRATION_ERROR_NOT_SUPPORTED. +/// +/*--cef(optional_param=callback)--*/ +void CefRegisterWidevineCdm(const CefString& path, + CefRefPtr callback); #endif // CEF_INCLUDE_CEF_WEB_PLUGIN_H_ diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index fa01feca5..9d8d75b75 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -2635,6 +2635,31 @@ typedef enum { CEF_MENU_ANCHOR_BOTTOMCENTER, } cef_menu_anchor_position_t; +/// +// Error codes for CDM registration. See cef_web_plugin.h for details. +/// +typedef enum { + /// + // No error. Registration completed successfully. + /// + CEF_CDM_REGISTRATION_ERROR_NONE, + + /// + // Required files or manifest contents are missing. + /// + CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS, + + /// + // The CDM is incompatible with the current Chromium version. + /// + CEF_CDM_REGISTRATION_ERROR_INCOMPATIBLE, + + /// + // CDM registration is not supported at this time. + /// + CEF_CDM_REGISTRATION_ERROR_NOT_SUPPORTED, +} cef_cdm_registration_error_t; + #ifdef __cplusplus } #endif diff --git a/libcef/browser/chrome_browser_process_stub.cc b/libcef/browser/chrome_browser_process_stub.cc index 7051d33bf..bea23c283 100644 --- a/libcef/browser/chrome_browser_process_stub.cc +++ b/libcef/browser/chrome_browser_process_stub.cc @@ -226,7 +226,7 @@ net_log::ChromeNetLog* ChromeBrowserProcessStub::net_log() { component_updater::ComponentUpdateService* ChromeBrowserProcessStub::component_updater() { - return CefContext::Get()->component_updater(); + return NULL; } CRLSetFetcher* ChromeBrowserProcessStub::crl_set_fetcher() { diff --git a/libcef/browser/component_updater/cef_component_updater_configurator.cc b/libcef/browser/component_updater/cef_component_updater_configurator.cc deleted file mode 100644 index 1a4ef4f49..000000000 --- a/libcef/browser/component_updater/cef_component_updater_configurator.cc +++ /dev/null @@ -1,167 +0,0 @@ -// Copyright 2014 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 "libcef/browser/component_updater/cef_component_updater_configurator.h" -#include "include/cef_version.h" - -#include "base/version.h" -#include "components/component_updater/configurator_impl.h" -#include "components/update_client/component_patcher_operation.h" -#include "content/public/browser/browser_thread.h" - -namespace component_updater { - -namespace { - -class CefConfigurator : public update_client::Configurator { - public: - CefConfigurator(const base::CommandLine* cmdline, - net::URLRequestContextGetter* url_request_getter, - PrefService* pref_service); - - int InitialDelay() const override; - int NextCheckDelay() const override; - int StepDelay() const override; - int OnDemandDelay() const override; - int UpdateDelay() const override; - std::vector UpdateUrl() const override; - std::vector PingUrl() const override; - base::Version GetBrowserVersion() const override; - std::string GetChannel() const override; - std::string GetBrand() const override; - std::string GetLang() const override; - std::string GetOSLongName() const override; - std::string ExtraRequestParams() const override; - std::string GetDownloadPreference() const override; - net::URLRequestContextGetter* RequestContext() const override; - scoped_refptr - CreateOutOfProcessPatcher() const override; - bool DeltasEnabled() const override; - bool UseBackgroundDownloader() const override; - bool UseCupSigning() const override; - scoped_refptr GetSequencedTaskRunner() - const override; - PrefService* GetPrefService() const override; - - private: - friend class base::RefCountedThreadSafe; - - ~CefConfigurator() override {} - - ConfiguratorImpl configurator_impl_; - PrefService* pref_service_; -}; - -CefConfigurator::CefConfigurator( - const base::CommandLine* cmdline, - net::URLRequestContextGetter* url_request_getter, - PrefService* pref_service) - : configurator_impl_(cmdline, url_request_getter, false), - pref_service_(pref_service) { -} - -int CefConfigurator::InitialDelay() const { - return configurator_impl_.InitialDelay(); -} - -int CefConfigurator::NextCheckDelay() const { - return configurator_impl_.NextCheckDelay(); -} - -int CefConfigurator::StepDelay() const { - return configurator_impl_.StepDelay(); -} - -int CefConfigurator::OnDemandDelay() const { - return configurator_impl_.OnDemandDelay(); -} - -int CefConfigurator::UpdateDelay() const { - return configurator_impl_.UpdateDelay(); -} - -std::vector CefConfigurator::UpdateUrl() const { - return configurator_impl_.UpdateUrl(); -} - -std::vector CefConfigurator::PingUrl() const { - return configurator_impl_.PingUrl(); -} - -base::Version CefConfigurator::GetBrowserVersion() const { - return configurator_impl_.GetBrowserVersion(); -} - -std::string CefConfigurator::GetChannel() const { - return std::string(); -} - -std::string CefConfigurator::GetBrand() const { - return std::string(); -} - -std::string CefConfigurator::GetLang() const { - return std::string(); -} - -std::string CefConfigurator::GetOSLongName() const { - return configurator_impl_.GetOSLongName(); -} - -std::string CefConfigurator::ExtraRequestParams() const { - return configurator_impl_.ExtraRequestParams(); -} - -std::string CefConfigurator::GetDownloadPreference() const { - return std::string(); -} - -net::URLRequestContextGetter* CefConfigurator::RequestContext() const { - return configurator_impl_.RequestContext(); -} - -scoped_refptr -CefConfigurator::CreateOutOfProcessPatcher() const { - return nullptr; -} - -bool CefConfigurator::DeltasEnabled() const { - return configurator_impl_.DeltasEnabled(); -} - -bool CefConfigurator::UseBackgroundDownloader() const { - return configurator_impl_.UseBackgroundDownloader(); -} - -bool CefConfigurator::UseCupSigning() const { - return configurator_impl_.UseCupSigning(); -} - -// Returns a task runner to run blocking tasks. The task runner continues to run -// after the browser shuts down, until the OS terminates the process. This -// imposes certain requirements for the code using the task runner, such as -// not accessing any global browser state while the code is running. -scoped_refptr -CefConfigurator::GetSequencedTaskRunner() const { - return content::BrowserThread::GetBlockingPool() - ->GetSequencedTaskRunnerWithShutdownBehavior( - base::SequencedWorkerPool::GetSequenceToken(), - base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN); -} - -PrefService* CefConfigurator::GetPrefService() const { - return pref_service_; -} - -} // namespace - -scoped_refptr -MakeCefComponentUpdaterConfigurator( - const base::CommandLine* cmdline, - net::URLRequestContextGetter* context_getter, - PrefService* pref_service) { - return new CefConfigurator(cmdline, context_getter, pref_service); -} - -} // namespace component_updater diff --git a/libcef/browser/component_updater/cef_component_updater_configurator.h b/libcef/browser/component_updater/cef_component_updater_configurator.h deleted file mode 100644 index 353dc67d2..000000000 --- a/libcef/browser/component_updater/cef_component_updater_configurator.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 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 LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ -#define LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ - -#include "base/memory/ref_counted.h" -#include "components/update_client/configurator.h" - -namespace base { -class CommandLine; -} - -namespace net { -class URLRequestContextGetter; -} - -class PrefService; - -namespace component_updater { - -scoped_refptr -MakeCefComponentUpdaterConfigurator( - const base::CommandLine* cmdline, - net::URLRequestContextGetter* context_getter, - PrefService* pref_service); - -} // namespace component_updater - -#endif // LIBCEF_BROWSER_COMPONENT_UPDATER_CEF_COMPONENT_UPDATER_CONFIGURATOR_H_ diff --git a/libcef/browser/content_browser_client.cc b/libcef/browser/content_browser_client.cc index f7b0ef1ad..00220942f 100644 --- a/libcef/browser/content_browser_client.cc +++ b/libcef/browser/content_browser_client.cc @@ -76,6 +76,10 @@ #include "ui/base/ui_base_switches.h" #include "url/gurl.h" +#if defined(OS_LINUX) +#include "libcef/common/widevine_loader.h" +#endif + #if defined(OS_MACOSX) #include "chrome/browser/spellchecker/spellcheck_message_filter_platform.h" #endif @@ -559,8 +563,6 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches( switches::kPpapiFlashPath, switches::kPpapiFlashVersion, switches::kUncaughtExceptionStackSize, - switches::kWidevineCdmPath, - switches::kWidevineCdmVersion, }; command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, arraysize(kSwitchNames)); @@ -582,17 +584,25 @@ void CefContentBrowserClient::AppendExtraCommandLineSwitches( #if defined(OS_LINUX) if (process_type == switches::kZygoteProcess) { - // Propagate the following switches to the zygone command line (along with + // Propagate the following switches to the zygote command line (along with // any associated values) if present in the browser command line. static const char* const kSwitchNames[] = { switches::kPpapiFlashPath, switches::kPpapiFlashVersion, - switches::kWidevineCdmPath, - switches::kWidevineCdmVersion, }; command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames, arraysize(kSwitchNames)); +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + if (!browser_cmd->HasSwitch(switches::kNoSandbox)) { + // Pass the Widevine CDM path to the Zygote process. See comments in + // CefWidevineLoader::AddPepperPlugins. + const base::FilePath& cdm_path = CefWidevineLoader::GetInstance()->path(); + if (!cdm_path.empty()) + command_line->AppendSwitchPath(switches::kWidevineCdmPath, cdm_path); + } +#endif + if (browser_cmd->HasSwitch(switches::kBrowserSubprocessPath)) { // Force use of the sub-process executable path for the zygote process. const base::FilePath& subprocess_path = diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index add5bb20f..fead0c3c2 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -10,12 +10,12 @@ #include "libcef/browser/browser_main.h" #include "libcef/browser/browser_message_loop.h" #include "libcef/browser/chrome_browser_process_stub.h" -#include "libcef/browser/component_updater/cef_component_updater_configurator.h" #include "libcef/browser/content_browser_client.h" #include "libcef/browser/thread_util.h" #include "libcef/browser/trace_subscriber.h" #include "libcef/common/cef_switches.h" #include "libcef/common/main_delegate.h" +#include "libcef/common/widevine_loader.h" #include "libcef/renderer/content_renderer_client.h" #include "base/base_switches.h" @@ -24,12 +24,8 @@ #include "base/debug/debugger.h" #include "base/files/file_util.h" #include "base/synchronization/waitable_event.h" -#include "base/threading/thread_restrictions.h" -#include "chrome/browser/component_updater/widevine_cdm_component_installer.h" #include "chrome/browser/printing/print_job_manager.h" -#include "components/component_updater/component_updater_service.h" #include "components/network_session_configurator/switches.h" -#include "components/update_client/configurator.h" #include "content/public/app/content_main.h" #include "content/public/app/content_main_runner.h" #include "content/public/browser/notification_service.h" @@ -362,25 +358,6 @@ CefTraceSubscriber* CefContext::GetTraceSubscriber() { return trace_subscriber_.get(); } -component_updater::ComponentUpdateService* -CefContext::component_updater() { - if (!component_updater_.get()) { - CEF_REQUIRE_UIT_RETURN(NULL); - scoped_refptr browser_context = - CefContentBrowserClient::Get()->browser_context(); - scoped_refptr configurator = - component_updater::MakeCefComponentUpdaterConfigurator( - base::CommandLine::ForCurrentProcess(), - browser_context->request_context().get(), - browser_context->GetPrefs()); - // Creating the component updater does not do anything, components - // need to be registered and Start() needs to be called. - component_updater_.reset(component_updater::ComponentUpdateServiceFactory( - configurator).release()); - } - return component_updater_.get(); -} - void CefContext::PopulateRequestContextSettings( CefRequestContextSettings* settings) { CefRefPtr command_line = @@ -399,30 +376,15 @@ void CefContext::PopulateRequestContextSettings( CefString(&settings_.accept_language_list); } -void RegisterComponentsForUpdate() { - component_updater::ComponentUpdateService* cus = - CefContext::Get()->component_updater(); - - // Registration can be before or after cus->Start() so it is ok to post - // a task to the UI thread to do registration once you done the necessary - // file IO to know you existing component version. -#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableWidevineCdm)) { - RegisterWidevineCdmComponent(cus); - } -#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID) -} - void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); // Must be created after the NotificationService. print_job_manager_.reset(new printing::PrintJobManager()); - bool io_was_allowed = base::ThreadRestrictions::SetIOAllowed(true); - RegisterComponentsForUpdate(); - base::ThreadRestrictions::SetIOAllowed(io_was_allowed); +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + CefWidevineLoader::GetInstance()->OnContextInitialized(); +#endif // Notify the handler. CefRefPtr app = CefContentClient::Get()->application(); @@ -449,9 +411,6 @@ void CefContext::FinishShutdownOnUIThread( if (trace_subscriber_.get()) trace_subscriber_.reset(NULL); - if (component_updater_.get()) - component_updater_.reset(NULL); - if (uithread_shutdown_event) uithread_shutdown_event->Signal(); } diff --git a/libcef/browser/context.h b/libcef/browser/context.h index 440cde845..1d2ddebb9 100644 --- a/libcef/browser/context.h +++ b/libcef/browser/context.h @@ -18,10 +18,6 @@ namespace base { class WaitableEvent; } -namespace component_updater { -class ComponentUpdateService; -} - namespace content { class ContentMainRunner; } @@ -67,8 +63,6 @@ class CefContext { return print_job_manager_.get(); } - component_updater::ComponentUpdateService* component_updater(); - CefTraceSubscriber* GetTraceSubscriber(); // Populate the request context settings based on CefSettings and command- @@ -101,9 +95,6 @@ class CefContext { // Only accessed on the UI Thread. std::unique_ptr print_job_manager_; - - // Initially only for Widevine components. - std::unique_ptr component_updater_; }; // Helper macro that returns true if the global context is in a valid state. diff --git a/libcef/browser/web_plugin_impl.cc b/libcef/browser/web_plugin_impl.cc index 1722a6be0..1698aeb1a 100644 --- a/libcef/browser/web_plugin_impl.cc +++ b/libcef/browser/web_plugin_impl.cc @@ -3,8 +3,10 @@ // can be found in the LICENSE file. #include "libcef/browser/web_plugin_impl.h" + #include "libcef/browser/context.h" #include "libcef/browser/thread_util.h" +#include "libcef/common/widevine_loader.h" #include "base/bind.h" #include "base/files/file_path.h" @@ -28,6 +30,17 @@ void PluginsCallbackImpl( } } +void DeliverWidevineCdmError(const std::string& error_message, + CefRefPtr callback) { + LOG(ERROR) << error_message; + if (callback.get()) { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefRegisterCdmCallback::OnCdmRegistrationComplete, + callback.get(), CEF_CDM_REGISTRATION_ERROR_NOT_SUPPORTED, + error_message)); + } +} + } // namespace @@ -150,3 +163,24 @@ void CefIsWebPluginUnstable( CEF_POST_TASK(CEF_IOT, base::Bind(CefIsWebPluginUnstable, path, callback)); } } + +void CefRegisterWidevineCdm(const CefString& path, + CefRefPtr callback) { +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) +#if defined(OS_LINUX) + // Enforce the requirement that CefRegisterWidevineCdm() is called before + // CefInitialize() on Linux. See comments in + // CefWidevineLoader::AddPepperPlugins for details. + if (CONTEXT_STATE_VALID()) { + DeliverWidevineCdmError( + "Widevine registration is not supported after context initialization", + callback); + return; + } +#endif // defined(OS_LINUX) + + CefWidevineLoader::GetInstance()->LoadWidevineCdm(path, callback); +#else + DeliverWidevineCdmError("Widevine registration is not supported", callback); +#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) +} diff --git a/libcef/common/cef_switches.cc b/libcef/common/cef_switches.cc index 9e0624dba..d9ef2039d 100644 --- a/libcef/common/cef_switches.cc +++ b/libcef/common/cef_switches.cc @@ -106,15 +106,9 @@ const char kDisableScrollBounce[] = "disable-scroll-bounce"; // Disable the PDF extension. const char kDisablePdfExtension[] = "disable-pdf-extension"; -// Enable Widevine CDM. -const char kEnableWidevineCdm[] = "enable-widevine-cdm"; - // Path to Widevine CDM binaries. const char kWidevineCdmPath[] = "widevine-cdm-path"; -// Widevine CDM version. -const char kWidevineCdmVersion[] = "widevine-cdm-version"; - // Default plugin policy action. const char kPluginPolicy[] = "plugin-policy"; // Allow the content. This is the default value. diff --git a/libcef/common/cef_switches.h b/libcef/common/cef_switches.h index a3090d4c6..6ebc943f8 100644 --- a/libcef/common/cef_switches.h +++ b/libcef/common/cef_switches.h @@ -45,9 +45,7 @@ extern const char kOverrideSpellCheckLang[]; extern const char kEnableSystemFlash[]; extern const char kDisableScrollBounce[]; extern const char kDisablePdfExtension[]; -extern const char kEnableWidevineCdm[]; extern const char kWidevineCdmPath[]; -extern const char kWidevineCdmVersion[]; extern const char kPluginPolicy[]; extern const char kPluginPolicy_Allow[]; extern const char kPluginPolicy_Detect[]; diff --git a/libcef/common/content_client.cc b/libcef/common/content_client.cc index 0d2667d31..80e04aa05 100644 --- a/libcef/common/content_client.cc +++ b/libcef/common/content_client.cc @@ -37,12 +37,8 @@ #include "ppapi/shared_impl/ppapi_permissions.h" #include "ui/base/resource/resource_bundle.h" -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. - -// The following must be after widevine_cdm_version.h. -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \ - !defined(WIDEVINE_CDM_IS_COMPONENT) -#include "chrome/common/widevine_cdm_constants.h" +#if defined(OS_LINUX) +#include "libcef/common/widevine_loader.h" #endif namespace { @@ -182,67 +178,6 @@ bool GetSystemPepperFlash(content::PepperPluginInfo* plugin) { return true; } -void AddWidevineCdmFromCommandLine( - std::vector* plugins) { -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && \ - !defined(WIDEVINE_CDM_IS_COMPONENT) - static bool skip_widevine_cdm_file_check = false; - - base::FilePath widevine_cdm_path = - base::CommandLine::ForCurrentProcess()->GetSwitchValuePath( - switches::kWidevineCdmPath); - if (!widevine_cdm_path.empty()) { - widevine_cdm_path = - widevine_cdm_path.AppendASCII(kWidevineCdmAdapterFileName); - } - - // Also get the version from the command-line. Should be something like - // 1.4.8.824. - const std::string& widevine_cdm_version = - base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kWidevineCdmVersion); - - if (!widevine_cdm_path.empty() && !widevine_cdm_version.empty()) { - if (skip_widevine_cdm_file_check || base::PathExists(widevine_cdm_path)) { - content::PepperPluginInfo widevine_cdm; - widevine_cdm.is_out_of_process = true; - widevine_cdm.path = widevine_cdm_path; - widevine_cdm.name = kWidevineCdmDisplayName; - widevine_cdm.description = kWidevineCdmDescription + - std::string(" (version: ") + - widevine_cdm_version + ")"; - widevine_cdm.version = widevine_cdm_version; - content::WebPluginMimeType widevine_cdm_mime_type( - kWidevineCdmPluginMimeType, - kWidevineCdmPluginExtension, - kWidevineCdmPluginMimeTypeDescription); - - // Add the supported codecs as if they came from the component manifest. - // This list must match the CDM that is being shipped with Chrome. - std::vector codecs; - codecs.push_back(kCdmSupportedCodecVp8); - codecs.push_back(kCdmSupportedCodecVp9); -#if defined(USE_PROPRIETARY_CODECS) - codecs.push_back(kCdmSupportedCodecAvc1); -#endif // defined(USE_PROPRIETARY_CODECS) - std::string codec_string = base::JoinString( - codecs, std::string(1, kCdmSupportedCodecsValueDelimiter)); - widevine_cdm_mime_type.additional_param_names.push_back( - base::ASCIIToUTF16(kCdmSupportedCodecsParamName)); - widevine_cdm_mime_type.additional_param_values.push_back( - base::ASCIIToUTF16(codec_string)); - - widevine_cdm.mime_types.push_back(widevine_cdm_mime_type); - widevine_cdm.permissions = kWidevineCdmPluginPermissions; - plugins->push_back(widevine_cdm); - - skip_widevine_cdm_file_check = true; - } - } -#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) && - // !defined(WIDEVINE_CDM_IS_COMPONENT) -} - } // namespace const char CefContentClient::kPDFPluginPath[] = "internal-pdf-viewer"; @@ -269,7 +204,12 @@ void CefContentClient::AddPepperPlugins( std::vector* plugins) { ComputeBuiltInPlugins(plugins); AddPepperFlashFromCommandLine(plugins); - AddWidevineCdmFromCommandLine(plugins); + +#if defined(OS_LINUX) +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + CefWidevineLoader::AddPepperPlugins(plugins); +#endif +#endif content::PepperPluginInfo plugin; if (GetSystemPepperFlash(&plugin)) diff --git a/libcef/common/main_delegate.cc b/libcef/common/main_delegate.cc index f0bb4e096..c7f241161 100644 --- a/libcef/common/main_delegate.cc +++ b/libcef/common/main_delegate.cc @@ -27,7 +27,6 @@ #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" -#include "components/component_updater/component_updater_paths.h" #include "components/content_settings/core/common/content_settings_pattern.h" #include "content/public/browser/browser_main_runner.h" #include "content/public/browser/render_process_host.h" @@ -41,8 +40,6 @@ #include "ui/base/ui_base_paths.h" #include "ui/base/ui_base_switches.h" -#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. - #include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. #if defined(IPC_MESSAGE_LOG_ENABLED) @@ -559,26 +556,6 @@ void CefMainDelegate::PreSandboxStartup() { user_data_path.AppendASCII("Dictionaries"), false, // May not be an absolute path. true); // Create if necessary. - - const base::FilePath& resources_path = GetResourcesFilePath(); - -#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) - const base::FilePath& widevine_plugin_path = - resources_path.AppendASCII(kWidevineCdmAdapterFileName); - if (base::PathExists(widevine_plugin_path)) { - PathService::Override(chrome::FILE_WIDEVINE_CDM_ADAPTER, - widevine_plugin_path); - } -#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) - - // Paths to find pre-installed components. - PathService::Override(chrome::DIR_COMPONENTS, resources_path); - PathService::Override(chrome::DIR_INTERNAL_PLUGINS, resources_path); - - // Register paths to be used by the component updater. - component_updater::RegisterPathProvider(chrome::DIR_COMPONENTS, - chrome::DIR_INTERNAL_PLUGINS, - chrome::DIR_USER_DATA); } if (command_line->HasSwitch(switches::kDisablePackLoading)) diff --git a/libcef/common/widevine_loader.cc b/libcef/common/widevine_loader.cc new file mode 100644 index 000000000..a17657eb0 --- /dev/null +++ b/libcef/common/widevine_loader.cc @@ -0,0 +1,406 @@ +// Copyright 2016 The Chromium Embedded Framework Authors. Portions copyright +// 2013 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 "libcef/common/widevine_loader.h" + +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + +#include "libcef/browser/context.h" +#include "libcef/browser/thread_util.h" +#include "libcef/common/cef_switches.h" + +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/json/json_string_value_serializer.h" +#include "base/memory/ptr_util.h" +#include "base/native_library.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_split.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/common/widevine_cdm_constants.h" +#include "content/browser/plugin_service_impl.h" +#include "content/public/browser/cdm_service.h" +#include "content/public/common/cdm_info.h" +#include "content/public/common/content_switches.h" +#include "media/cdm/supported_cdm_versions.h" + +namespace { + +base::LazyInstance::Leaky g_widevine_loader = + LAZY_INSTANCE_INITIALIZER; + + +// Based on chrome/browser/component_updater/widevine_cdm_component_installer.cc + +// Name of the Widevine CDM OS in the component manifest. +const char kWidevineCdmOs[] = +#if defined(OS_MACOSX) + "mac"; +#elif defined(OS_WIN) + "win"; +#else // OS_LINUX, etc. TODO(viettrungluu): Separate out Chrome OS and Android? + "linux"; +#endif + +// Name of the Widevine CDM architecture in the component manifest. +const char kWidevineCdmArch[] = +#if defined(ARCH_CPU_X86) + "ia32"; // This differs from the component updater which uses "x86". +#elif defined(ARCH_CPU_X86_64) + "x64"; +#else // TODO(viettrungluu): Support an ARM check? + "???"; +#endif + +// The CDM OS and architecture. +const char kCdmOsName[] = "os"; +const char kCdmArchName[] = "arch"; + +// The CDM version (e.g. "1.4.8.903"). +const char kCdmVersionName[] = "version"; + +// The CDM manifest includes several custom values, all beginning with "x-cdm-". +// All values are strings. +// All values that are lists are delimited by commas. No trailing commas. +// For example, "1,2,4". +const char kCdmValueDelimiter = ','; +static_assert(kCdmValueDelimiter == kCdmSupportedCodecsValueDelimiter, + "cdm delimiters must match"); +// The following entries are required. +// Interface versions are lists of integers (e.g. "1" or "1,2,4"). +// These are checked in this file before registering the CDM. +// All match the interface versions from content_decryption_module.h that the +// CDM supports. +// Matches CDM_MODULE_VERSION. +const char kCdmModuleVersionsName[] = "x-cdm-module-versions"; +// Matches supported ContentDecryptionModule_* version(s). +const char kCdmInterfaceVersionsName[] = "x-cdm-interface-versions"; +// Matches supported Host_* version(s). +const char kCdmHostVersionsName[] = "x-cdm-host-versions"; +// The codecs list is a list of simple codec names (e.g. "vp8,vorbis"). +// The list is passed to other parts of Chrome. +const char kCdmCodecsListName[] = "x-cdm-codecs"; + +std::unique_ptr ParseManifestFile( + const base::FilePath& manifest_path) { + CEF_REQUIRE_FILET(); + + // Manifest file should be < 1kb. Read at most 2kb. + std::string manifest_contents; + if (!base::ReadFileToStringWithMaxSize(manifest_path, &manifest_contents, + 2048)) { + return nullptr; + } + + JSONStringValueDeserializer deserializer(manifest_contents); + std::unique_ptr manifest(deserializer.Deserialize(NULL, NULL)); + + if (!manifest.get() || !manifest->IsType(base::Value::TYPE_DICTIONARY)) + return nullptr; + + // Transfer ownership to the caller. + return base::WrapUnique( + static_cast(manifest.release())); +} + +std::string GetManifestValue(const base::DictionaryValue& manifest, + const std::string& key, + std::string* error_message) { + std::stringstream ss; + std::string value; + if (!manifest.GetString(key, &value)) { + ss << "Manifest missing " << key; + *error_message = ss.str(); + } else if (value.empty()) { + ss << "Manifest has empty " << key; + *error_message = ss.str(); + } + return value; +} + +typedef bool (*VersionCheckFunc)(int version); + +bool CheckForCompatibleVersion(const base::DictionaryValue& manifest, + const std::string version_name, + VersionCheckFunc version_check_func, + std::string* error_message) { + std::string versions_string = + GetManifestValue(manifest, version_name, error_message); + if (versions_string.empty()) + return false; + + for (const base::StringPiece& ver_str : base::SplitStringPiece( + versions_string, std::string(1, kCdmValueDelimiter), + base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { + int version = 0; + if (base::StringToInt(ver_str, &version)) + if (version_check_func(version)) + return true; + } + + std::stringstream ss; + ss << "Manifest has no supported " << version_name << " in '" << + versions_string << "'"; + *error_message = ss.str(); + return false; +} + +// Returns whether the CDM's OS/platform and module/interface/host API versions, +// as specified in the manifest, are compatible with this Chromium binary. +bool IsCompatibleWithChrome(const base::DictionaryValue& manifest, + std::string* error_message) { + return GetManifestValue(manifest, kCdmOsName, error_message) == + kWidevineCdmOs && + GetManifestValue(manifest, kCdmArchName, error_message) == + kWidevineCdmArch && + CheckForCompatibleVersion(manifest, + kCdmModuleVersionsName, + media::IsSupportedCdmModuleVersion, + error_message) && + CheckForCompatibleVersion(manifest, + kCdmInterfaceVersionsName, + media::IsSupportedCdmInterfaceVersion, + error_message) && + CheckForCompatibleVersion(manifest, + kCdmHostVersionsName, + media::IsSupportedCdmHostVersion, + error_message); +} + +// Populate the PepperPluginInfo structure. +void GetPluginInfo(const base::FilePath& cdm_adapter_path, + const base::FilePath& cdm_path, + const std::string& cdm_version, + const std::string& cdm_codecs, + content::PepperPluginInfo* widevine_cdm) { + widevine_cdm->is_out_of_process = true; + widevine_cdm->path = cdm_adapter_path; + widevine_cdm->name = kWidevineCdmDisplayName; + widevine_cdm->description = kWidevineCdmDescription + + std::string(" (version: ") + + cdm_version + ")"; + widevine_cdm->version = cdm_version; + content::WebPluginMimeType widevine_cdm_mime_type( + kWidevineCdmPluginMimeType, + kWidevineCdmPluginExtension, + kWidevineCdmPluginMimeTypeDescription); + + widevine_cdm_mime_type.additional_param_names.push_back( + base::ASCIIToUTF16(kCdmSupportedCodecsParamName)); + widevine_cdm_mime_type.additional_param_values.push_back( + base::ASCIIToUTF16(cdm_codecs)); + + widevine_cdm->mime_types.push_back(widevine_cdm_mime_type); + widevine_cdm->permissions = kWidevineCdmPluginPermissions; +} + +// Verify and load the contents of |base_path|. +cef_cdm_registration_error_t LoadWidevineCdmInfo( + const base::FilePath& base_path, + base::FilePath* cdm_adapter_path, + base::FilePath* cdm_path, + std::string* cdm_version, + std::string* cdm_codecs, + std::string* error_message) { + std::stringstream ss; + + *cdm_adapter_path = base_path.AppendASCII(kWidevineCdmAdapterFileName); + if (!base::PathExists(*cdm_adapter_path)) { + ss << "Missing adapter file " << cdm_adapter_path->value(); + *error_message = ss.str(); + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + } + + *cdm_path = base_path.AppendASCII( + base::GetNativeLibraryName(kWidevineCdmLibraryName)); + if (!base::PathExists(*cdm_path)) { + ss << "Missing file " << cdm_path->value(); + *error_message = ss.str(); + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + } + + base::FilePath manifest_path = base_path.AppendASCII("manifest.json"); + if (!base::PathExists(manifest_path)) { + ss << "Missing manifest file " << manifest_path.value(); + *error_message = ss.str(); + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + } + + std::unique_ptr manifest = + ParseManifestFile(manifest_path); + if (!manifest) { + ss << "Failed to parse manifest file " << manifest_path.value(); + *error_message = ss.str(); + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + } + + if (!IsCompatibleWithChrome(*manifest, error_message)) + return CEF_CDM_REGISTRATION_ERROR_INCOMPATIBLE; + + *cdm_version = GetManifestValue(*manifest, kCdmVersionName, error_message); + if (cdm_version->empty()) + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + + *cdm_codecs = GetManifestValue(*manifest, kCdmCodecsListName, error_message); + if (cdm_codecs->empty()) + return CEF_CDM_REGISTRATION_ERROR_INCORRECT_CONTENTS; + + return CEF_CDM_REGISTRATION_ERROR_NONE; +} + +void DeliverWidevineCdmCallback(cef_cdm_registration_error_t result, + const std::string& error_message, + CefRefPtr callback) { + CEF_REQUIRE_UIT(); + + if (result != CEF_CDM_REGISTRATION_ERROR_NONE) + LOG(ERROR) << "Widevine CDM registration failed; " << error_message; + + if (callback) + callback->OnCdmRegistrationComplete(result, error_message); +} + +void RegisterWidevineCdmOnUIThread( + const base::FilePath& cdm_adapter_path, + const base::FilePath& cdm_path, + const std::string& cdm_version, + const std::string& cdm_codecs, + CefRefPtr callback) { + CEF_REQUIRE_UIT(); + + content::PepperPluginInfo widevine_cdm; + GetPluginInfo(cdm_adapter_path, cdm_path, cdm_version, cdm_codecs, + &widevine_cdm); + + // true = Add to beginning of list to override any existing registrations. + content::PluginService::GetInstance()->RegisterInternalPlugin( + widevine_cdm.ToWebPluginInfo(), true); + // Tell the browser to refresh the plugin list. Then tell all renderers to + // update their plugin list caches. + content::PluginService::GetInstance()->RefreshPlugins(); + content::PluginService::GetInstance()->PurgePluginListCache(NULL, false); + + // Also register Widevine with the CdmService. + const std::vector codecs = base::SplitString( + cdm_codecs, std::string(1, kCdmSupportedCodecsValueDelimiter), + base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + content::CdmService::GetInstance()->RegisterCdm(content::CdmInfo( + kWidevineCdmType, base::Version(cdm_version), cdm_path, codecs)); + + DeliverWidevineCdmCallback(CEF_CDM_REGISTRATION_ERROR_NONE, std::string(), + callback); +} + +void LoadWidevineCdmInfoOnFileThread( + const base::FilePath& base_path, + CefRefPtr callback) { + CEF_REQUIRE_FILET(); + + base::FilePath cdm_adapter_path; + base::FilePath cdm_path; + std::string cdm_version; + std::string cdm_codecs; + std::string error_message; + cef_cdm_registration_error_t result = + LoadWidevineCdmInfo(base_path, &cdm_adapter_path, &cdm_path, &cdm_version, + &cdm_codecs, &error_message); + if (result != CEF_CDM_REGISTRATION_ERROR_NONE) { + CEF_POST_TASK(CEF_UIT, base::Bind(DeliverWidevineCdmCallback, result, + error_message, callback)); + return; + } + + // Continue execution on the UI thread. + CEF_POST_TASK(CEF_UIT, + base::Bind(RegisterWidevineCdmOnUIThread, cdm_adapter_path, cdm_path, + cdm_version, cdm_codecs, callback)); +} + +} // namespace + +// static +CefWidevineLoader* CefWidevineLoader::GetInstance() { + return &g_widevine_loader.Get(); +} + +void CefWidevineLoader::LoadWidevineCdm( + const base::FilePath& path, + CefRefPtr callback) { + if (!CONTEXT_STATE_VALID()) { + // Loading will proceed from OnContextInitialized(). + load_pending_ = true; + path_ = path; + callback_ = callback; + return; + } + + // Continue execution on the FILE thread. + CEF_POST_TASK(CEF_FILET, + base::Bind(LoadWidevineCdmInfoOnFileThread, path, callback)); +} + +void CefWidevineLoader::OnContextInitialized() { + CEF_REQUIRE_UIT(); + if (load_pending_) { + load_pending_ = false; + LoadWidevineCdm(path_, callback_); + callback_ = nullptr; + } +} + +#if defined(OS_LINUX) + +// static +void CefWidevineLoader::AddPepperPlugins( + std::vector* plugins) { + const base::CommandLine& command_line = + *base::CommandLine::ForCurrentProcess(); + + // Perform early plugin registration in the zygote process when the sandbox is + // enabled to avoid "cannot open shared object file: Operation not permitted" + // errors during plugin loading. This is because the Zygote process must pre- + // load all plugins before initializing the sandbox. + if (command_line.GetSwitchValueASCII(switches::kProcessType) != + switches::kZygoteProcess || + command_line.HasSwitch(switches::kNoSandbox)) { + return; + } + + // The Widevine CDM path is passed to the zygote process via + // CefContentBrowserClient::AppendExtraCommandLineSwitches. + const base::FilePath& base_path = command_line.GetSwitchValuePath( + switches::kWidevineCdmPath); + if (base_path.empty()) + return; + + // Load contents of the plugin directory synchronously. This only occurs once + // on zygote process startup so should not have a huge performance penalty. + base::FilePath cdm_adapter_path; + base::FilePath cdm_path; + std::string cdm_version; + std::string cdm_codecs; + std::string error_message; + cef_cdm_registration_error_t result = + LoadWidevineCdmInfo(base_path, &cdm_adapter_path, &cdm_path, &cdm_version, + &cdm_codecs, &error_message); + if (result != CEF_CDM_REGISTRATION_ERROR_NONE) { + LOG(ERROR) << "Widevine CDM registration failed; " << error_message; + return; + } + + content::PepperPluginInfo widevine_cdm; + GetPluginInfo(cdm_adapter_path, cdm_path, cdm_version, cdm_codecs, + &widevine_cdm); + plugins->push_back(widevine_cdm); +} + +#endif // defined(OS_LINUX) + +CefWidevineLoader::CefWidevineLoader() { +} + +CefWidevineLoader::~CefWidevineLoader() { +} + +#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) diff --git a/libcef/common/widevine_loader.h b/libcef/common/widevine_loader.h new file mode 100644 index 000000000..7c7784528 --- /dev/null +++ b/libcef/common/widevine_loader.h @@ -0,0 +1,64 @@ +// Copyright 2016 The Chromium Embedded Framework 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 CEF_LIBCEF_COMMON_WIDEVINE_LOADER_H_ +#define CEF_LIBCEF_COMMON_WIDEVINE_LOADER_H_ +#pragma once + +#include "build/build_config.h" + +#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. + +#if defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + +#include + +#include "include/cef_web_plugin.h" + +#include "base/lazy_instance.h" + +namespace content { +struct PepperPluginInfo; +} + +class CefWidevineLoader { + public: + // Returns the singleton instance of this object. + static CefWidevineLoader* GetInstance(); + + // Load the Widevine CDM. May be called before or after context creation. See + // comments in cef_web_plugin.h. + void LoadWidevineCdm(const base::FilePath& path, + CefRefPtr callback); + + // Plugin registration is triggered here if LoadWidevineCdm() was called + // before context creation. + void OnContextInitialized(); + +#if defined(OS_LINUX) + // The zygote process which is used when the sandbox is enabled on Linux + // requires early loading of pepper plugins. Other processes will receive + // load notification in the usual way. + // Called from CefContentClient::AddPepperPlugins. + static void AddPepperPlugins(std::vector* plugins); + + const base::FilePath& path() { return path_; } +#endif + + private: + friend struct base::DefaultLazyInstanceTraits; + + // Members are only accessed before context initialization or on the UI + // thread. + bool load_pending_ = false; + base::FilePath path_; + CefRefPtr callback_; + + CefWidevineLoader(); + ~CefWidevineLoader(); +}; + +#endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(ENABLE_PEPPER_CDMS) + +#endif // CEF_LIBCEF_COMMON_WIDEVINE_LOADER_H_ diff --git a/libcef_dll/cpptoc/register_cdm_callback_cpptoc.cc b/libcef_dll/cpptoc/register_cdm_callback_cpptoc.cc new file mode 100644 index 000000000..027e99ad2 --- /dev/null +++ b/libcef_dll/cpptoc/register_cdm_callback_cpptoc.cc @@ -0,0 +1,60 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/register_cdm_callback_cpptoc.h" + + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK register_cdm_callback_on_cdm_registration_complete( + struct _cef_register_cdm_callback_t* self, + cef_cdm_registration_error_t result, const cef_string_t* error_message) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Unverified params: error_message + + // Execute + CefRegisterCdmCallbackCppToC::Get(self)->OnCdmRegistrationComplete( + result, + CefString(error_message)); +} + +} // namespace + + +// CONSTRUCTOR - Do not edit by hand. + +CefRegisterCdmCallbackCppToC::CefRegisterCdmCallbackCppToC() { + GetStruct()->on_cdm_registration_complete = + register_cdm_callback_on_cdm_registration_complete; +} + +template<> CefRefPtr CefCppToC::UnwrapDerived( + CefWrapperType type, cef_register_cdm_callback_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCppToC::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCppToC::kWrapperType = + WT_REGISTER_CDM_CALLBACK; diff --git a/libcef_dll/cpptoc/register_cdm_callback_cpptoc.h b/libcef_dll/cpptoc/register_cdm_callback_cpptoc.h new file mode 100644 index 000000000..44706abd4 --- /dev/null +++ b/libcef_dll/cpptoc/register_cdm_callback_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_REGISTER_CDM_CALLBACK_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_REGISTER_CDM_CALLBACK_CPPTOC_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_web_plugin.h" +#include "include/capi/cef_web_plugin_capi.h" +#include "include/cef_browser.h" +#include "include/capi/cef_browser_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefRegisterCdmCallbackCppToC + : public CefCppToC { + public: + CefRegisterCdmCallbackCppToC(); +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_REGISTER_CDM_CALLBACK_CPPTOC_H_ diff --git a/libcef_dll/ctocpp/register_cdm_callback_ctocpp.cc b/libcef_dll/ctocpp/register_cdm_callback_ctocpp.cc new file mode 100644 index 000000000..d9a18352d --- /dev/null +++ b/libcef_dll/ctocpp/register_cdm_callback_ctocpp.cc @@ -0,0 +1,54 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/register_cdm_callback_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +void CefRegisterCdmCallbackCToCpp::OnCdmRegistrationComplete( + cef_cdm_registration_error_t result, const CefString& error_message) { + cef_register_cdm_callback_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_cdm_registration_complete)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Unverified params: error_message + + // Execute + _struct->on_cdm_registration_complete(_struct, + result, + error_message.GetStruct()); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefRegisterCdmCallbackCToCpp::CefRegisterCdmCallbackCToCpp() { +} + +template<> cef_register_cdm_callback_t* CefCToCpp::UnwrapDerived( + CefWrapperType type, CefRegisterCdmCallback* c) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#if DCHECK_IS_ON() +template<> base::AtomicRefCount CefCToCpp::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCToCpp::kWrapperType = + WT_REGISTER_CDM_CALLBACK; diff --git a/libcef_dll/ctocpp/register_cdm_callback_ctocpp.h b/libcef_dll/ctocpp/register_cdm_callback_ctocpp.h new file mode 100644 index 000000000..9f7a3b620 --- /dev/null +++ b/libcef_dll/ctocpp/register_cdm_callback_ctocpp.h @@ -0,0 +1,41 @@ +// Copyright (c) 2016 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_REGISTER_CDM_CALLBACK_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_REGISTER_CDM_CALLBACK_CTOCPP_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_web_plugin.h" +#include "include/capi/cef_web_plugin_capi.h" +#include "include/cef_browser.h" +#include "include/capi/cef_browser_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefRegisterCdmCallbackCToCpp + : public CefCToCpp { + public: + CefRegisterCdmCallbackCToCpp(); + + // CefRegisterCdmCallback methods. + void OnCdmRegistrationComplete(cef_cdm_registration_error_t result, + const CefString& error_message) override; +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_REGISTER_CDM_CALLBACK_CTOCPP_H_ diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index 6a49e8fdf..1360ec780 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -119,6 +119,7 @@ #include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h" #include "libcef_dll/ctocpp/print_handler_ctocpp.h" #include "libcef_dll/ctocpp/read_handler_ctocpp.h" +#include "libcef_dll/ctocpp/register_cdm_callback_ctocpp.h" #include "libcef_dll/ctocpp/render_handler_ctocpp.h" #include "libcef_dll/ctocpp/render_process_handler_ctocpp.h" #include "libcef_dll/ctocpp/request_handler_ctocpp.h" @@ -283,6 +284,7 @@ CEF_EXPORT void cef_shutdown() { DCHECK(base::AtomicRefCountIsZero(&CefPrintSettingsCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefProcessMessageCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefReadHandlerCToCpp::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefRegisterCdmCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefRenderHandlerCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero( &CefRenderProcessHandlerCToCpp::DebugObjCt)); @@ -964,3 +966,19 @@ CEF_EXPORT void cef_is_web_plugin_unstable(const cef_string_t* path, CefWebPluginUnstableCallbackCToCpp::Wrap(callback)); } +CEF_EXPORT void cef_register_widevine_cdm(const cef_string_t* path, + struct _cef_register_cdm_callback_t* callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: path; type: string_byref_const + DCHECK(path); + if (!path) + return; + // Unverified params: callback + + // Execute + CefRegisterWidevineCdm( + CefString(path), + CefRegisterCdmCallbackCToCpp::Wrap(callback)); +} + diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index ecb268ed8..cfbf0d627 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -63,6 +63,7 @@ #include "libcef_dll/cpptoc/pdf_print_callback_cpptoc.h" #include "libcef_dll/cpptoc/print_handler_cpptoc.h" #include "libcef_dll/cpptoc/read_handler_cpptoc.h" +#include "libcef_dll/cpptoc/register_cdm_callback_cpptoc.h" #include "libcef_dll/cpptoc/render_handler_cpptoc.h" #include "libcef_dll/cpptoc/render_process_handler_cpptoc.h" #include "libcef_dll/cpptoc/request_handler_cpptoc.h" @@ -275,6 +276,7 @@ CEF_GLOBAL void CefShutdown() { DCHECK(base::AtomicRefCountIsZero(&CefPrintSettingsCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefProcessMessageCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefReadHandlerCppToC::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefRegisterCdmCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefRenderHandlerCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero( &CefRenderProcessHandlerCppToC::DebugObjCt)); @@ -907,3 +909,19 @@ CEF_GLOBAL void CefIsWebPluginUnstable(const CefString& path, CefWebPluginUnstableCallbackCppToC::Wrap(callback)); } +CEF_GLOBAL void CefRegisterWidevineCdm(const CefString& path, + CefRefPtr callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: path; type: string_byref_const + DCHECK(!path.empty()); + if (path.empty()) + return; + // Unverified params: callback + + // Execute + cef_register_widevine_cdm( + path.GetStruct(), + CefRegisterCdmCallbackCppToC::Wrap(callback)); +} + diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index f8783de50..dba31eeb8 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -85,6 +85,7 @@ enum CefWrapperType { WT_PRINT_SETTINGS, WT_PROCESS_MESSAGE, WT_READ_HANDLER, + WT_REGISTER_CDM_CALLBACK, WT_RENDER_HANDLER, WT_RENDER_PROCESS_HANDLER, WT_REQUEST, diff --git a/tests/cefclient/browser/binding_test.cc b/tests/cefclient/browser/binding_test.cc index f02afc651..f16996cb3 100644 --- a/tests/cefclient/browser/binding_test.cc +++ b/tests/cefclient/browser/binding_test.cc @@ -7,8 +7,6 @@ #include #include -#include "include/wrapper/cef_stream_resource_handler.h" - namespace client { namespace binding_test { diff --git a/tests/cefclient/browser/drm_test.cc b/tests/cefclient/browser/drm_test.cc new file mode 100644 index 000000000..7177ff203 --- /dev/null +++ b/tests/cefclient/browser/drm_test.cc @@ -0,0 +1,120 @@ +// Copyright (c) 2016 The Chromium Embedded Framework 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 "cefclient/browser/drm_test.h" + +#include +#include + +#include "include/cef_parser.h" +#include "include/cef_web_plugin.h" + +namespace client { +namespace drm_test { + +namespace { + +// Application-specific error codes. +const int kMessageFormatError = 1; +const int kCdmLoadError = 2; + +const char kTestUrl[] = "http://tests/drm"; +const char kWidevineCdmPathKey[] = "widevine_cdm_path"; + +// Callback executed once CDM registration is complete. +class CdmCallback : public CefRegisterCdmCallback { + public: + CdmCallback(CefRefPtr callback) + : callback_(callback) { + } + + void OnCdmRegistrationComplete(cef_cdm_registration_error_t result, + const CefString& error_message) OVERRIDE { + if (result == CEF_CDM_REGISTRATION_ERROR_NONE) + callback_->Success(""); + else + callback_->Failure(kCdmLoadError, error_message); + callback_ = nullptr; + } + + private: + CefRefPtr callback_; + + IMPLEMENT_REFCOUNTING(CdmCallback); + DISALLOW_COPY_AND_ASSIGN(CdmCallback); +}; + +// Handle messages in the browser process. +class Handler : public CefMessageRouterBrowserSide::Handler { + public: + Handler() {} + + // Called due to cefQuery execution in binding.html. + virtual bool OnQuery(CefRefPtr browser, + CefRefPtr frame, + int64 query_id, + const CefString& request, + bool persistent, + CefRefPtr callback) OVERRIDE { + // Only handle messages from the test URL. + const std::string& url = frame->GetURL(); + if (url.find(kTestUrl) != 0) + return false; + + // Parse |request| as a JSON dictionary. + CefRefPtr request_dict = ParseJSON(request); + if (!request_dict) { + callback->Failure(kMessageFormatError, "Incorrect message format"); + return true; + } + + // Verify the "widevine_cdm_path" key. + if (!VerifyKey(request_dict, kWidevineCdmPathKey, VTYPE_STRING, callback)) + return true; + + const std::string& widevine_cdm_path = + request_dict->GetString(kWidevineCdmPathKey); + if (widevine_cdm_path.empty()) { + callback->Failure(kMessageFormatError, "Empty widevine CDM path"); + return true; + } + + // Register the Widvine CDM. + CefRegisterWidevineCdm(widevine_cdm_path, new CdmCallback(callback)); + return true; + } + + private: + // Convert a JSON string to a dictionary value. + static CefRefPtr ParseJSON(const CefString& string) { + CefRefPtr value = CefParseJSON(string, JSON_PARSER_RFC); + if (value.get() && value->GetType() == VTYPE_DICTIONARY) + return value->GetDictionary(); + return NULL; + } + + // Verify that |key| exists in |dictionary| and has type |value_type|. Fails + // |callback| and returns false on failure. + static bool VerifyKey(CefRefPtr dictionary, + const char* key, + cef_value_type_t value_type, + CefRefPtr callback) { + if (!dictionary->HasKey(key) || dictionary->GetType(key) != value_type) { + callback->Failure(kMessageFormatError, + "Missing or incorrectly formatted message key: " + + std::string(key)); + return false; + } + return true; + } +}; + +} // namespace + +void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers) { + handlers.insert(new Handler()); +} + +} // namespace drm_test +} // namespace client diff --git a/tests/cefclient/browser/drm_test.h b/tests/cefclient/browser/drm_test.h new file mode 100644 index 000000000..c243e78e7 --- /dev/null +++ b/tests/cefclient/browser/drm_test.h @@ -0,0 +1,20 @@ +// Copyright (c) 2016 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_BROWSER_DRM_TEST_H_ +#define CEF_TESTS_CEFCLIENT_BROWSER_DRM_TEST_H_ +#pragma once + +#include "cefclient/browser/test_runner.h" + +namespace client { +namespace drm_test { + +// Create message handlers. Called from test_runner.cc. +void CreateMessageHandlers(test_runner::MessageHandlerSet& handlers); + +} // namespace drm_test +} // namespace client + +#endif // CEF_TESTS_CEFCLIENT_BROWSER_DRM_TEST_H_ diff --git a/tests/cefclient/browser/main_context_impl.cc b/tests/cefclient/browser/main_context_impl.cc index 5dde106c8..af341750a 100644 --- a/tests/cefclient/browser/main_context_impl.cc +++ b/tests/cefclient/browser/main_context_impl.cc @@ -5,6 +5,7 @@ #include "cefclient/browser/main_context_impl.h" #include "include/cef_parser.h" +#include "include/cef_web_plugin.h" #include "cefclient/common/client_switches.h" namespace client { @@ -79,6 +80,16 @@ MainContextImpl::MainContextImpl(CefRefPtr command_line, main_url_ = "http://tests/draggable"; } #endif // defined(OS_WIN) || defined(OS_LINUX) + + const std::string& cdm_path = + command_line_->GetSwitchValue(switches::kWidevineCdmPath); + if (!cdm_path.empty()) { + // Register the Widevine CDM at the specified path. See comments in + // cef_web_plugin.h for details. It's safe to call this method before + // CefInitialize(), and calling it before CefInitialize() is required on + // Linux. + CefRegisterWidevineCdm(cdm_path, NULL); + } } MainContextImpl::~MainContextImpl() { diff --git a/tests/cefclient/browser/resource.h b/tests/cefclient/browser/resource.h index 49aeb17c7..4cf8f657e 100644 --- a/tests/cefclient/browser/resource.h +++ b/tests/cefclient/browser/resource.h @@ -46,24 +46,25 @@ #define IDS_BINDING_HTML 1000 #define IDS_DIALOGS_HTML 1001 #define IDS_DRAGGABLE_HTML 1002 -#define IDS_LOCALSTORAGE_HTML 1003 -#define IDS_LOGO_PNG 1004 -#define IDS_MENU_ICON_1X_PNG 1005 -#define IDS_MENU_ICON_2X_PNG 1006 -#define IDS_OSRTEST_HTML 1007 -#define IDS_OTHER_TESTS_HTML 1008 -#define IDS_PDF_HTML 1009 -#define IDS_PDF_PDF 1010 -#define IDS_PERFORMANCE_HTML 1011 -#define IDS_PERFORMANCE2_HTML 1012 -#define IDS_PREFERENCES_HTML 1013 -#define IDS_RESPONSE_FILTER_HTML 1014 -#define IDS_TRANSPARENCY_HTML 1015 -#define IDS_URLREQUEST_HTML 1016 -#define IDS_WINDOW_HTML 1017 -#define IDS_WINDOW_ICON_1X_PNG 1018 -#define IDS_WINDOW_ICON_2X_PNG 1019 -#define IDS_XMLHTTPREQUEST_HTML 1020 +#define IDS_DRM_HTML 1003 +#define IDS_LOCALSTORAGE_HTML 1004 +#define IDS_LOGO_PNG 1005 +#define IDS_MENU_ICON_1X_PNG 1006 +#define IDS_MENU_ICON_2X_PNG 1007 +#define IDS_OSRTEST_HTML 1008 +#define IDS_OTHER_TESTS_HTML 1009 +#define IDS_PDF_HTML 1010 +#define IDS_PDF_PDF 1011 +#define IDS_PERFORMANCE_HTML 1012 +#define IDS_PERFORMANCE2_HTML 1013 +#define IDS_PREFERENCES_HTML 1014 +#define IDS_RESPONSE_FILTER_HTML 1015 +#define IDS_TRANSPARENCY_HTML 1016 +#define IDS_URLREQUEST_HTML 1017 +#define IDS_WINDOW_HTML 1018 +#define IDS_WINDOW_ICON_1X_PNG 1019 +#define IDS_WINDOW_ICON_2X_PNG 1020 +#define IDS_XMLHTTPREQUEST_HTML 1021 // Next default values for new objects // diff --git a/tests/cefclient/browser/resource_util_win.cc b/tests/cefclient/browser/resource_util_win.cc index 588b16125..90d55f6e6 100644 --- a/tests/cefclient/browser/resource_util_win.cc +++ b/tests/cefclient/browser/resource_util_win.cc @@ -40,6 +40,7 @@ int GetResourceId(const char* resource_name) { {"binding.html", IDS_BINDING_HTML}, {"dialogs.html", IDS_DIALOGS_HTML}, {"draggable.html", IDS_DRAGGABLE_HTML}, + {"drm.html", IDS_DRM_HTML}, {"logo.png", IDS_LOGO_PNG}, {"localstorage.html", IDS_LOCALSTORAGE_HTML}, {"menu_icon.1x.png", IDS_MENU_ICON_1X_PNG}, diff --git a/tests/cefclient/browser/test_runner.cc b/tests/cefclient/browser/test_runner.cc index 4c3270a61..b2b4a0e35 100644 --- a/tests/cefclient/browser/test_runner.cc +++ b/tests/cefclient/browser/test_runner.cc @@ -15,6 +15,7 @@ #include "include/wrapper/cef_stream_resource_handler.h" #include "cefclient/browser/binding_test.h" #include "cefclient/browser/dialog_test.h" +#include "cefclient/browser/drm_test.h" #include "cefclient/browser/main_context.h" #include "cefclient/browser/preferences_test.h" #include "cefclient/browser/resource.h" @@ -715,6 +716,9 @@ void CreateMessageHandlers(MessageHandlerSet& handlers) { // Create the dialog test handlers. dialog_test::CreateMessageHandlers(handlers); + // Create the drm test handlers. + drm_test::CreateMessageHandlers(handlers); + // Create the preferences test handlers. preferences_test::CreateMessageHandlers(handlers); diff --git a/tests/cefclient/common/client_switches.cc b/tests/cefclient/common/client_switches.cc index 772129b55..310ded20e 100644 --- a/tests/cefclient/common/client_switches.cc +++ b/tests/cefclient/common/client_switches.cc @@ -34,6 +34,7 @@ const char kFilterURL[] = "filter-url"; const char kUseViews[] = "use-views"; const char kHideFrame[] = "hide-frame"; const char kHideControls[] = "hide-controls"; +const char kWidevineCdmPath[] = "widevine-cdm-path"; } // namespace switches } // namespace client diff --git a/tests/cefclient/common/client_switches.h b/tests/cefclient/common/client_switches.h index 80f9a63d7..1cdad730e 100644 --- a/tests/cefclient/common/client_switches.h +++ b/tests/cefclient/common/client_switches.h @@ -28,6 +28,7 @@ extern const char kFilterURL[]; extern const char kUseViews[]; extern const char kHideFrame[]; extern const char kHideControls[]; +extern const char kWidevineCdmPath[]; } // namespace switches } // namespace client diff --git a/tests/cefclient/resources/drm.html b/tests/cefclient/resources/drm.html new file mode 100644 index 000000000..05077d134 --- /dev/null +++ b/tests/cefclient/resources/drm.html @@ -0,0 +1,126 @@ + + +DRM Test + + + + +Important notes: +
    +
  • Clearkey support is built in and should always be enabled.
  • +
  • Widevine support requires CDM binaries that must be downloaded from Google. Contact Google here for details.
  • +
  • Widevine support is enabled by calling the CefRegisterWidevineCdm() function. See comments in cef_web_plugin.h for usage.
  • +
  • The CefRegisterWidevineCdm() function can be called during runtime on Windows and OS X to register Widevine binaries. Use the below form to test this capability.
  • +
  • Calling CefRegisterWidevineCdm() before CefInitialize() is required on Linux.
  • +
  • Cefclient will call CefRegisterWidevineCdm() before CefInitialize() if "--widevine-cdm-path=<path>" is specified on the command-line.
  • +
  • View extended media support information here.
  • +
  • Test DRM video playback here. Select an "asset" that includes Clearkey or Widevine in the name.
  • +
+ +
+Widevine CDM Path: + +
+

+
+
diff --git a/tests/cefclient/resources/other_tests.html b/tests/cefclient/resources/other_tests.html
index 1f931d6cc..493cf18cc 100644
--- a/tests/cefclient/resources/other_tests.html
+++ b/tests/cefclient/resources/other_tests.html
@@ -11,6 +11,7 @@
 
  • Dialogs
  • Drag & Drop
  • Draggable Regions
  • +
  • DRM (Clearkey, Widevine)
  • Flash Plugin
  • Geolocation
  • HTML5 Feature Test
  • diff --git a/tests/cefclient/resources/win/cefclient.rc b/tests/cefclient/resources/win/cefclient.rc index ecc95b114..0564092b9 100644 --- a/tests/cefclient/resources/win/cefclient.rc +++ b/tests/cefclient/resources/win/cefclient.rc @@ -32,6 +32,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US IDS_BINDING_HTML BINARY "..\\binding.html" IDS_DIALOGS_HTML BINARY "..\\dialogs.html" IDS_DRAGGABLE_HTML BINARY "..\\draggable.html" +IDS_DRM_HTML BINARY "..\\drm.html" IDS_LOCALSTORAGE_HTML BINARY "..\\localstorage.html" IDS_LOGO_PNG BINARY "..\\logo.png" IDS_MENU_ICON_1X_PNG BINARY "..\\menu_icon.1x.png" diff --git a/tools/make_distrib.py b/tools/make_distrib.py index 4b4364170..46413bff0 100644 --- a/tools/make_distrib.py +++ b/tools/make_distrib.py @@ -744,6 +744,7 @@ elif platform == 'linux': make_dir(dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'chrome_sandbox'), os.path.join(dst_dir, 'chrome-sandbox'), options.quiet) copy_file(libcef_path, dst_dir, options.quiet) + copy_file(os.path.join(build_dir, 'libwidevinecdmadapter.so'), dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'natives_blob.bin'), dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'snapshot_blob.bin'), dst_dir, options.quiet) else: @@ -771,6 +772,7 @@ elif platform == 'linux': else: copy_file(libcef_path, dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'chrome_sandbox'), os.path.join(dst_dir, 'chrome-sandbox'), options.quiet) + copy_file(os.path.join(build_dir, 'libwidevinecdmadapter.so'), dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'natives_blob.bin'), dst_dir, options.quiet) copy_file(os.path.join(build_dir, 'snapshot_blob.bin'), dst_dir, options.quiet) else: