summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsandersd <sandersd@chromium.org>2015-03-25 12:53:06 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-25 19:54:38 +0000
commita8a9143d9373e1ae47f30d3da14c051d16188b3e (patch)
tree20796ef8d0a1e51b0988aa8ea5ace1a515ef61e6
parentf1eb0a7e1062b0ea684727df4d61c55a75fe4a87 (diff)
downloadchromium_src-a8a9143d9373e1ae47f30d3da14c051d16188b3e.zip
chromium_src-a8a9143d9373e1ae47f30d3da14c051d16188b3e.tar.gz
chromium_src-a8a9143d9373e1ae47f30d3da14c051d16188b3e.tar.bz2
Implement robustness strings in requestMediaKeySystemAccess().
BUG=442586,460616 Review URL: https://codereview.chromium.org/1005903003 Cr-Commit-Position: refs/heads/master@{#322219}
-rw-r--r--chrome/renderer/media/chrome_key_systems.cc43
-rw-r--r--chromecast/renderer/key_systems_cast.cc10
-rw-r--r--components/cdm/renderer/android_key_systems.cc45
-rw-r--r--components/cdm/renderer/widevine_key_systems.cc4
-rw-r--r--components/cdm/renderer/widevine_key_systems.h2
-rw-r--r--content/renderer/media/render_media_client_unittest.cc4
-rw-r--r--media/base/android/browser_cdm_factory_android.cc2
-rw-r--r--media/base/eme_constants.h53
-rw-r--r--media/base/key_system_info.cc2
-rw-r--r--media/base/key_system_info.h7
-rw-r--r--media/base/key_systems.cc390
-rw-r--r--media/base/key_systems.h35
-rw-r--r--media/base/key_systems_unittest.cc4
-rw-r--r--media/blink/webencryptedmediaclient_impl.cc323
-rw-r--r--media/test/data/eme_player_js/player_utils.js4
15 files changed, 640 insertions, 288 deletions
diff --git a/chrome/renderer/media/chrome_key_systems.cc b/chrome/renderer/media/chrome_key_systems.cc
index 5307481..33fea4a 100644
--- a/chrome/renderer/media/chrome_key_systems.cc
+++ b/chrome/renderer/media/chrome_key_systems.cc
@@ -75,22 +75,22 @@ static void AddExternalClearKey(
KeySystemInfo info;
info.key_system = kExternalClearKeyKeySystem;
- info.supported_codecs = media::EME_CODEC_WEBM_ALL;
info.supported_init_data_types =
media::EME_INIT_DATA_TYPE_WEBM | media::EME_INIT_DATA_TYPE_KEYIDS;
+ info.supported_codecs = media::EME_CODEC_WEBM_ALL;
#if defined(USE_PROPRIETARY_CODECS)
- info.supported_codecs |= media::EME_CODEC_MP4_ALL;
info.supported_init_data_types |= media::EME_INIT_DATA_TYPE_CENC;
+ info.supported_codecs |= media::EME_CODEC_MP4_ALL;
#endif // defined(USE_PROPRIETARY_CODECS)
+ info.max_audio_robustness = media::EmeRobustness::EMPTY;
+ info.max_video_robustness = media::EmeRobustness::EMPTY;
+
// Persistent sessions are faked.
info.persistent_license_support = media::EME_SESSION_TYPE_SUPPORTED;
info.persistent_release_message_support =
media::EME_SESSION_TYPE_NOT_SUPPORTED;
- // TODO(sandersd): Using ALWAYS_ENABLED prevents "not-allowed" from
- // succeeding. Change this to REQUESTABLE once the state can be blocked.
- // http://crbug.com/457482
- info.persistent_state_support = media::EME_FEATURE_ALWAYS_ENABLED;
+ info.persistent_state_support = media::EME_FEATURE_REQUESTABLE;
info.distinctive_identifier_support = media::EME_FEATURE_NOT_SUPPORTED;
info.pepper_type = kExternalClearKeyPepperType;
@@ -193,24 +193,21 @@ static void AddPepperBasedWidevine(
cdm::AddWidevineWithCodecs(
cdm::WIDEVINE, supported_codecs,
#if defined(OS_CHROMEOS)
- // Persistent licenses are supported if remote attestation succeeds.
- media::EME_SESSION_TYPE_SUPPORTED_WITH_PERMISSION,
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent release message.
- // TODO(sandersd): Using ALWAYS_ENABLED prevents "not-allowed" from
- // succeeding. Change this to REQUESTABLE once the state can be blocked.
- // http://crbug.com/457482
- media::EME_FEATURE_ALWAYS_ENABLED, // Persistent state.
- // A distinctive identifier will be available if remote attestation
- // succeeds.
- media::EME_FEATURE_REQUESTABLE_WITH_PERMISSION,
+ media::EmeRobustness::HW_SECURE_ALL, // Maximum audio robustness.
+ media::EmeRobustness::HW_SECURE_ALL, // Maximim video robustness.
+ // persistent-license.
+ media::EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER,
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-release-message.
+ media::EME_FEATURE_REQUESTABLE, // Persistent state.
+ // Distinctive identifier.
+ media::EME_FEATURE_REQUESTABLE_WITH_IDENTIFIER,
#else // (Desktop)
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent license.
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent release message.
- // TODO(sandersd): Using ALWAYS_ENABLED prevents "not-allowed" from
- // succeeding. Change this to REQUESTABLE once the state can be blocked.
- // http://crbug.com/457482
- media::EME_FEATURE_ALWAYS_ENABLED, // Persistent state.
- media::EME_FEATURE_NOT_SUPPORTED, // Distinctive identifier.
+ media::EmeRobustness::SW_SECURE_CRYPTO, // Maximum audio robustness.
+ media::EmeRobustness::SW_SECURE_DECODE, // Maximum video robustness.
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-license.
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-release-message.
+ media::EME_FEATURE_REQUESTABLE, // Persistent state.
+ media::EME_FEATURE_NOT_SUPPORTED, // Distinctive identifier.
#endif // defined(OS_CHROMEOS)
concrete_key_systems);
}
diff --git a/chromecast/renderer/key_systems_cast.cc b/chromecast/renderer/key_systems_cast.cc
index 246d6ad..995092d 100644
--- a/chromecast/renderer/key_systems_cast.cc
+++ b/chromecast/renderer/key_systems_cast.cc
@@ -22,9 +22,11 @@ void AddKeySystemWithCodecs(
std::vector<::media::KeySystemInfo>* key_systems_info) {
::media::KeySystemInfo info;
info.key_system = key_system_name;
+ info.supported_init_data_types = ::media::EME_INIT_DATA_TYPE_CENC;
info.supported_codecs =
::media::EME_CODEC_MP4_AAC | ::media::EME_CODEC_MP4_AVC1;
- info.supported_init_data_types = ::media::EME_INIT_DATA_TYPE_CENC;
+ info.max_audio_robustness = ::media::EmeRobustness::EMPTY;
+ info.max_video_robustness = ::media::EmeRobustness::EMPTY;
info.persistent_license_support = ::media::EME_SESSION_TYPE_NOT_SUPPORTED;
info.persistent_release_message_support =
::media::EME_SESSION_TYPE_NOT_SUPPORTED;
@@ -39,8 +41,10 @@ void AddChromecastKeySystems(
AddWidevineWithCodecs(
cdm::WIDEVINE,
::media::EME_CODEC_MP4_AAC | ::media::EME_CODEC_MP4_AVC1,
- ::media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent license.
- ::media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent release message.
+ ::media::EmeRobustness::HW_SECURE_ALL, // Max audio robustness.
+ ::media::EmeRobustness::HW_SECURE_ALL, // Max video robustness.
+ ::media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-license.
+ ::media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-release-message.
::media::EME_FEATURE_NOT_SUPPORTED, // Persistent state.
::media::EME_FEATURE_ALWAYS_ENABLED, // Distinctive identifier.
key_systems_info);
diff --git a/components/cdm/renderer/android_key_systems.cc b/components/cdm/renderer/android_key_systems.cc
index d1e0f2a..e773656 100644
--- a/components/cdm/renderer/android_key_systems.cc
+++ b/components/cdm/renderer/android_key_systems.cc
@@ -7,14 +7,17 @@
#include <string>
#include <vector>
+#include "base/command_line.h"
#include "base/logging.h"
#include "components/cdm/common/cdm_messages_android.h"
#include "components/cdm/renderer/widevine_key_systems.h"
#include "content/public/renderer/render_thread.h"
#include "media/base/eme_constants.h"
+#include "media/base/media_switches.h"
#include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
+using media::EmeRobustness;
using media::KeySystemInfo;
using media::SupportedCodecs;
@@ -39,24 +42,48 @@ static SupportedKeySystemResponse QueryKeySystemSupport(
void AddAndroidWidevine(std::vector<KeySystemInfo>* concrete_key_systems) {
SupportedKeySystemResponse response = QueryKeySystemSupport(
kWidevineKeySystem);
- if (response.compositing_codecs != media::EME_CODEC_NONE) {
+
+ // When creating the WIDEVINE key system, BrowserCdmFactoryAndroid configures
+ // the CDM's security level based on the --mediadrm-enable-non-compositing
+ // flag (L1 if the flag is enabled, L3 otherwise). Therefore the supported
+ // codec/robustenss combinations depend on that flag.
+ // TODO(sandersd): For unprefixed, set the security level based on the
+ // requested robustness instead of the flag. http://crbug.com/467779
+ SupportedCodecs codecs = response.compositing_codecs;
+ EmeRobustness max_audio_robustness = EmeRobustness::SW_SECURE_CRYPTO;
+ EmeRobustness max_video_robustness = EmeRobustness::SW_SECURE_CRYPTO;
+ if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kMediaDrmEnableNonCompositing)) {
+ codecs = response.non_compositing_codecs;
+ max_audio_robustness = EmeRobustness::HW_SECURE_CRYPTO;
+ max_video_robustness = EmeRobustness::HW_SECURE_ALL;
+ }
+ if (codecs != media::EME_CODEC_NONE) {
AddWidevineWithCodecs(
WIDEVINE,
- static_cast<SupportedCodecs>(response.compositing_codecs),
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent license.
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent release message.
+ codecs,
+ max_audio_robustness,
+ max_video_robustness,
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-license.
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-release-message.
media::EME_FEATURE_NOT_SUPPORTED, // Persistent state.
media::EME_FEATURE_ALWAYS_ENABLED, // Distinctive identifier.
concrete_key_systems);
}
+ // For compatibility with the prefixed API, register a separate L1 key system.
+ // When creating the WIDEVINE_HR_NON_COMPOSITING key system,
+ // BrowserCdmFactoryAndroid does not configure the CDM's security level (that
+ // is, leaves it as L1); therefore only secure codecs are supported.
+ // TODO(ddorwin): Remove with unprefixed. http://crbug.com/249976
if (response.non_compositing_codecs != media::EME_CODEC_NONE) {
- // TODO(ddorwin): Remove with unprefixed. http://crbug.com/249976
AddWidevineWithCodecs(
WIDEVINE_HR_NON_COMPOSITING,
- static_cast<SupportedCodecs>(response.non_compositing_codecs),
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent license.
- media::EME_SESSION_TYPE_NOT_SUPPORTED, // Persistent release message.
+ response.non_compositing_codecs,
+ EmeRobustness::HW_SECURE_CRYPTO, // Max audio robustness.
+ EmeRobustness::HW_SECURE_ALL, // Max video robustness.
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-license.
+ media::EME_SESSION_TYPE_NOT_SUPPORTED, // persistent-release-message.
media::EME_FEATURE_NOT_SUPPORTED, // Persistent state.
media::EME_FEATURE_ALWAYS_ENABLED, // Distinctive identifier.
concrete_key_systems);
@@ -85,6 +112,8 @@ void AddAndroidPlatformKeySystems(
if (response.compositing_codecs & media::EME_CODEC_MP4_ALL)
info.supported_init_data_types |= media::EME_INIT_DATA_TYPE_CENC;
#endif // defined(USE_PROPRIETARY_CODECS)
+ info.max_audio_robustness = EmeRobustness::EMPTY;
+ info.max_video_robustness = EmeRobustness::EMPTY;
// Assume the worst case (from a user point of view).
info.persistent_license_support = media::EME_SESSION_TYPE_NOT_SUPPORTED;
info.persistent_release_message_support =
diff --git a/components/cdm/renderer/widevine_key_systems.cc b/components/cdm/renderer/widevine_key_systems.cc
index 037df1b..ec38ab6 100644
--- a/components/cdm/renderer/widevine_key_systems.cc
+++ b/components/cdm/renderer/widevine_key_systems.cc
@@ -29,6 +29,8 @@ static std::string GetDirectParentName(std::string name) {
void AddWidevineWithCodecs(
WidevineCdmType widevine_cdm_type,
SupportedCodecs supported_codecs,
+ media::EmeRobustness max_audio_robustness,
+ media::EmeRobustness max_video_robustness,
media::EmeSessionTypeSupport persistent_license_support,
media::EmeSessionTypeSupport persistent_release_message_support,
media::EmeFeatureSupport persistent_state_support,
@@ -66,6 +68,8 @@ void AddWidevineWithCodecs(
info.supported_init_data_types |= media::EME_INIT_DATA_TYPE_CENC;
#endif // defined(USE_PROPRIETARY_CODECS)
+ info.max_audio_robustness = max_audio_robustness;
+ info.max_video_robustness = max_video_robustness;
info.persistent_license_support = persistent_license_support;
info.persistent_release_message_support = persistent_release_message_support;
info.persistent_state_support = persistent_state_support;
diff --git a/components/cdm/renderer/widevine_key_systems.h b/components/cdm/renderer/widevine_key_systems.h
index 15c55da..dc05bb8 100644
--- a/components/cdm/renderer/widevine_key_systems.h
+++ b/components/cdm/renderer/widevine_key_systems.h
@@ -22,6 +22,8 @@ enum WidevineCdmType {
void AddWidevineWithCodecs(
WidevineCdmType widevine_cdm_type,
media::SupportedCodecs supported_codecs,
+ media::EmeRobustness max_audio_robustness,
+ media::EmeRobustness max_video_robustness,
media::EmeSessionTypeSupport persistent_license_support,
media::EmeSessionTypeSupport persistent_release_message_support,
media::EmeFeatureSupport persistent_state_support,
diff --git a/content/renderer/media/render_media_client_unittest.cc b/content/renderer/media/render_media_client_unittest.cc
index 2366156..7ac253e 100644
--- a/content/renderer/media/render_media_client_unittest.cc
+++ b/content/renderer/media/render_media_client_unittest.cc
@@ -27,6 +27,8 @@ class TestContentRendererClient : public ContentRendererClient {
// TODO(sandersd): Was this supposed to be added to the list?
media::KeySystemInfo key_system_info;
key_system_info.key_system = "test.keysystem";
+ key_system_info.max_audio_robustness = media::EmeRobustness::EMPTY;
+ key_system_info.max_video_robustness = media::EmeRobustness::EMPTY;
key_system_info.persistent_license_support =
media::EME_SESSION_TYPE_NOT_SUPPORTED;
key_system_info.persistent_release_message_support =
@@ -40,6 +42,8 @@ class TestContentRendererClient : public ContentRendererClient {
if (is_extra_key_system_enabled_) {
media::KeySystemInfo wv_key_system_info;
wv_key_system_info.key_system = kWidevineKeySystem;
+ wv_key_system_info.max_audio_robustness = media::EmeRobustness::EMPTY;
+ wv_key_system_info.max_video_robustness = media::EmeRobustness::EMPTY;
wv_key_system_info.persistent_license_support =
media::EME_SESSION_TYPE_NOT_SUPPORTED;
wv_key_system_info.persistent_release_message_support =
diff --git a/media/base/android/browser_cdm_factory_android.cc b/media/base/android/browser_cdm_factory_android.cc
index e116863..614c8d1 100644
--- a/media/base/android/browser_cdm_factory_android.cc
+++ b/media/base/android/browser_cdm_factory_android.cc
@@ -34,7 +34,7 @@ scoped_ptr<BrowserCdm> BrowserCdmFactoryAndroid::CreateBrowserCdm(
}
// TODO(xhwang/ddorwin): Pass the security level from key system.
- // http://crbug.com/459400
+ // http://crbug.com/467779
if (key_system == kWidevineKeySystem) {
MediaDrmBridge::SecurityLevel security_level =
MediaDrmBridge::SECURITY_LEVEL_3;
diff --git a/media/base/eme_constants.h b/media/base/eme_constants.h
index 2f8f033..7882fae 100644
--- a/media/base/eme_constants.h
+++ b/media/base/eme_constants.h
@@ -55,32 +55,75 @@ enum EmeSessionTypeSupport {
EME_SESSION_TYPE_INVALID,
// The session type is not supported.
EME_SESSION_TYPE_NOT_SUPPORTED,
- // The session type is supported if the encrypted media permission is granted.
- EME_SESSION_TYPE_SUPPORTED_WITH_PERMISSION,
+ // The session type is supported if a distinctive identifier is available.
+ EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER,
// The session type is always supported.
EME_SESSION_TYPE_SUPPORTED,
};
+// Used to declare support for distinctive identifier and persistent state.
enum EmeFeatureSupport {
// Invalid default value.
EME_FEATURE_INVALID,
// Access to the feature is not supported at all.
EME_FEATURE_NOT_SUPPORTED,
- // Access to the feature may be requested if the encrypted media permission is
- // granted.
- EME_FEATURE_REQUESTABLE_WITH_PERMISSION,
+ // Access to the feature may be requested if a distinctive identifier is
+ // available. (This is the correct choice for declaring support for a
+ // requestable distinctive identifier.)
+ EME_FEATURE_REQUESTABLE_WITH_IDENTIFIER,
// Access to the feature may be requested.
EME_FEATURE_REQUESTABLE,
// Access to the feature cannot be blocked.
EME_FEATURE_ALWAYS_ENABLED,
};
+// Used to query support for distinctive identifier and persistent state.
enum EmeFeatureRequirement {
EME_FEATURE_NOT_ALLOWED,
EME_FEATURE_OPTIONAL,
EME_FEATURE_REQUIRED,
};
+enum class EmeMediaType {
+ AUDIO,
+ VIDEO,
+};
+
+// Robustness values understood by KeySystems.
+// Note: KeySystems expects this ordering (in GetRobustnessConfigRule()),
+// changes may be required there if this list changes.
+enum class EmeRobustness {
+ INVALID,
+ EMPTY,
+ SW_SECURE_CRYPTO,
+ SW_SECURE_DECODE,
+ HW_SECURE_CRYPTO,
+ HW_SECURE_DECODE,
+ HW_SECURE_ALL,
+};
+
+// Configuration rules indicate the configuration state required to support a
+// configuration option (note: a configuration option may be disallowing a
+// feature). Configuration rules are used to answer queries about distinctive
+// identifier, persistent state, and robustness requirements, as well as to
+// describe support for different session types.
+//
+// If in the future there are reasons to request user permission other than
+// access to a distinctive identifier, then additional rules should be added.
+// Rules are implemented in ConfigState and are otherwise opaque.
+enum class EmeConfigRule {
+ // The configuration option is not supported.
+ NOT_SUPPORTED,
+ // The configuration option is supported if a distinctive identifier is
+ // available.
+ IDENTIFIER_REQUIRED,
+ // The configuration option is supported, but the user experience may be
+ // improved if a distinctive identifier is available.
+ IDENTIFIER_RECOMMENDED,
+ // The configuration option is supported without conditions.
+ SUPPORTED,
+};
+
} // namespace media
#endif // MEDIA_BASE_EME_CONSTANTS_H_
diff --git a/media/base/key_system_info.cc b/media/base/key_system_info.cc
index b656f0f..55927790 100644
--- a/media/base/key_system_info.cc
+++ b/media/base/key_system_info.cc
@@ -9,6 +9,8 @@ namespace media {
KeySystemInfo::KeySystemInfo()
: supported_init_data_types(EME_INIT_DATA_TYPE_NONE),
supported_codecs(EME_CODEC_NONE),
+ max_audio_robustness(EmeRobustness::INVALID),
+ max_video_robustness(EmeRobustness::INVALID),
persistent_license_support(EME_SESSION_TYPE_INVALID),
persistent_release_message_support(EME_SESSION_TYPE_INVALID),
persistent_state_support(EME_FEATURE_INVALID),
diff --git a/media/base/key_system_info.h b/media/base/key_system_info.h
index e66d8be..218cebd 100644
--- a/media/base/key_system_info.h
+++ b/media/base/key_system_info.h
@@ -35,13 +35,10 @@ struct MEDIA_EXPORT KeySystemInfo {
std::string key_system;
- // Specifies registered initialization data types supported by |key_system|.
SupportedInitDataTypes supported_init_data_types;
-
- // Specifies codecs supported by |key_system|.
SupportedCodecs supported_codecs;
-
- // Specifies session types and features supported by |key_system|.
+ EmeRobustness max_audio_robustness;
+ EmeRobustness max_video_robustness;
EmeSessionTypeSupport persistent_license_support;
EmeSessionTypeSupport persistent_release_message_support;
EmeFeatureSupport persistent_state_support;
diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc
index 92bcc38e..bf33dcc 100644
--- a/media/base/key_systems.cc
+++ b/media/base/key_systems.cc
@@ -76,6 +76,39 @@ static NamedCodec kCodecStrings[] = {
#endif // defined(USE_PROPRIETARY_CODECS)
};
+static EmeConfigRule ConvertSessionTypeSupport(
+ EmeSessionTypeSupport support) {
+ switch (support) {
+ case EME_SESSION_TYPE_INVALID:
+ NOTREACHED();
+ return EmeConfigRule::NOT_SUPPORTED;
+ case EME_SESSION_TYPE_NOT_SUPPORTED:
+ return EmeConfigRule::NOT_SUPPORTED;
+ case EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER:
+ return EmeConfigRule::IDENTIFIER_REQUIRED;
+ case EME_SESSION_TYPE_SUPPORTED:
+ return EmeConfigRule::SUPPORTED;
+ }
+ NOTREACHED();
+ return EmeConfigRule::NOT_SUPPORTED;
+}
+
+static EmeRobustness ConvertRobustness(const std::string& robustness) {
+ if (robustness.empty())
+ return EmeRobustness::EMPTY;
+ if (robustness == "SW_SECURE_CRYPTO")
+ return EmeRobustness::SW_SECURE_CRYPTO;
+ if (robustness == "SW_SECURE_DECODE")
+ return EmeRobustness::SW_SECURE_DECODE;
+ if (robustness == "HW_SECURE_CRYPTO")
+ return EmeRobustness::HW_SECURE_CRYPTO;
+ if (robustness == "HW_SECURE_DECODE")
+ return EmeRobustness::HW_SECURE_DECODE;
+ if (robustness == "HW_SECURE_ALL")
+ return EmeRobustness::HW_SECURE_ALL;
+ return EmeRobustness::INVALID;
+}
+
static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
KeySystemInfo info;
info.key_system = kClearKeyKeySystem;
@@ -103,6 +136,8 @@ static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
info.supported_codecs |= EME_CODEC_MP4_ALL;
#endif // defined(USE_PROPRIETARY_CODECS)
+ info.max_audio_robustness = EmeRobustness::EMPTY;
+ info.max_video_robustness = EmeRobustness::EMPTY;
info.persistent_license_support = EME_SESSION_TYPE_NOT_SUPPORTED;
info.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
info.persistent_state_support = EME_FEATURE_NOT_SUPPORTED;
@@ -191,23 +226,24 @@ class KeySystems {
std::string GetPepperType(const std::string& concrete_key_system);
#endif
- bool IsPersistentLicenseSessionSupported(
+ EmeConfigRule GetRobustnessConfigRule(
const std::string& key_system,
- bool is_permission_granted);
+ EmeMediaType media_type,
+ const std::string& requested_robustness);
- bool IsPersistentReleaseMessageSessionSupported(
- const std::string& key_system,
- bool is_permission_granted);
+ EmeConfigRule GetPersistentLicenseSessionConfigRule(
+ const std::string& key_system);
- bool IsPersistentStateRequirementSupported(
+ EmeConfigRule GetPersistentReleaseMessageSessionConfigRule(
+ const std::string& key_system);
+
+ EmeConfigRule GetPersistentStateConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted);
+ EmeFeatureRequirement requirement);
- bool IsDistinctiveIdentifierRequirementSupported(
+ EmeConfigRule GetDistinctiveIdentifierConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted);
+ EmeFeatureRequirement requirement);
void AddContainerMask(const std::string& container, uint32 mask);
void AddCodecMask(const std::string& codec, uint32 mask);
@@ -394,45 +430,71 @@ void KeySystems::AddConcreteSupportedKeySystems(
for (const KeySystemInfo& info : concrete_key_systems) {
DCHECK(!info.key_system.empty());
- DCHECK_NE(info.persistent_license_support, EME_SESSION_TYPE_INVALID);
- DCHECK_NE(info.persistent_release_message_support,
- EME_SESSION_TYPE_INVALID);
- // TODO(sandersd): Add REQUESTABLE and REQUESTABLE_WITH_PERMISSION for
- // persistent_state_support once we can block access per-CDM-instance
- // (http://crbug.com/457482).
- DCHECK(info.persistent_state_support == EME_FEATURE_NOT_SUPPORTED ||
- info.persistent_state_support == EME_FEATURE_ALWAYS_ENABLED);
-// TODO(sandersd): Allow REQUESTABLE_WITH_PERMISSION for all key systems on
-// all platforms once we have proper enforcement (http://crbug.com/457482).
-// On Chrome OS, an ID will not be used without permission, but we cannot
-// currently prevent the CDM from requesting the permission again when no
-// there was no initial prompt. Thus, we block "not-allowed" below.
-#if defined(OS_CHROMEOS)
- DCHECK(info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED ||
- (info.distinctive_identifier_support ==
- EME_FEATURE_REQUESTABLE_WITH_PERMISSION &&
- info.key_system == kWidevineKeySystem) ||
- info.distinctive_identifier_support == EME_FEATURE_ALWAYS_ENABLED);
-#else
- DCHECK(info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED ||
- info.distinctive_identifier_support == EME_FEATURE_ALWAYS_ENABLED);
-#endif
+ DCHECK(info.max_audio_robustness != EmeRobustness::INVALID);
+ DCHECK(info.max_video_robustness != EmeRobustness::INVALID);
+ DCHECK(info.persistent_license_support != EME_SESSION_TYPE_INVALID);
+ DCHECK(info.persistent_release_message_support != EME_SESSION_TYPE_INVALID);
+ DCHECK(info.persistent_state_support != EME_FEATURE_INVALID);
+ DCHECK(info.distinctive_identifier_support != EME_FEATURE_INVALID);
+
+ // Supporting persistent state is a prerequsite for supporting persistent
+ // sessions.
if (info.persistent_state_support == EME_FEATURE_NOT_SUPPORTED) {
- DCHECK_EQ(info.persistent_license_support,
- EME_SESSION_TYPE_NOT_SUPPORTED);
- DCHECK_EQ(info.persistent_release_message_support,
- EME_SESSION_TYPE_NOT_SUPPORTED);
+ DCHECK(info.persistent_license_support == EME_SESSION_TYPE_NOT_SUPPORTED);
+ DCHECK(info.persistent_release_message_support ==
+ EME_SESSION_TYPE_NOT_SUPPORTED);
}
- DCHECK(!IsSupportedKeySystem(info.key_system))
- << "Key system '" << info.key_system << "' already registered";
- DCHECK(!parent_key_system_map_.count(info.key_system))
- << "'" << info.key_system << "' is already registered as a parent";
+ else if (info.persistent_state_support ==
+ EME_FEATURE_REQUESTABLE_WITH_IDENTIFIER) {
+ // Must be either NOT_SUPPORTED or SUPPORTED_WITH_IDENTIFIER.
+ DCHECK(info.persistent_license_support != EME_SESSION_TYPE_SUPPORTED);
+ DCHECK(info.persistent_release_message_support !=
+ EME_SESSION_TYPE_SUPPORTED);
+ }
+
+ // persistent-release-message sessions are not currently supported.
+ // http://crbug.com/448888
+ DCHECK(info.persistent_release_message_support ==
+ EME_SESSION_TYPE_NOT_SUPPORTED);
+
+ // Because an optional persistent state value is resolved after an optional
+ // distinctive identifier, persistent state requiring a distinctive
+ // identifier may not resolve correctly.
+ DCHECK(info.persistent_state_support !=
+ EME_FEATURE_REQUESTABLE_WITH_IDENTIFIER);
+
+ // If supported, distinctive identifiers always require permission.
+ DCHECK(info.distinctive_identifier_support != EME_FEATURE_REQUESTABLE);
+
+ // If distinctive identifiers are not supported, then no other features can
+ // require them.
+ if (info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED) {
+ DCHECK(info.persistent_license_support !=
+ EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER);
+ DCHECK(info.persistent_release_message_support !=
+ EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER);
+ }
+
+ // Distinctive identifiers and persistent state can only be reliably blocked
+ // (and therefore be safely configurable) for Pepper-hosted key systems. For
+ // other platforms, only non-configurable values are valid.
+ bool can_block = false;
#if defined(ENABLE_PEPPER_CDMS)
DCHECK_EQ(info.use_aes_decryptor, info.pepper_type.empty());
+ can_block = !info.pepper_type.empty();
#endif
+ if (!can_block) {
+ DCHECK(info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED ||
+ info.distinctive_identifier_support == EME_FEATURE_ALWAYS_ENABLED);
+ DCHECK(info.persistent_state_support == EME_FEATURE_NOT_SUPPORTED ||
+ info.persistent_state_support == EME_FEATURE_ALWAYS_ENABLED);
+ }
+ DCHECK(!IsSupportedKeySystem(info.key_system))
+ << "Key system '" << info.key_system << "' already registered";
+ DCHECK(!parent_key_system_map_.count(info.key_system))
+ << "'" << info.key_system << "' is already registered as a parent";
concrete_key_system_map_[info.key_system] = info;
-
if (!info.parent_key_system.empty()) {
DCHECK(!IsConcreteSupportedKeySystem(info.parent_key_system))
<< "Parent '" << info.parent_key_system << "' "
@@ -620,132 +682,172 @@ std::string KeySystems::GetPepperType(const std::string& concrete_key_system) {
}
#endif
-bool KeySystems::IsPersistentLicenseSessionSupported(
+EmeConfigRule KeySystems::GetRobustnessConfigRule(
const std::string& key_system,
- bool is_permission_granted) {
+ EmeMediaType media_type,
+ const std::string& requested_robustness) {
DCHECK(thread_checker_.CalledOnValidThread());
+ EmeRobustness robustness = ConvertRobustness(requested_robustness);
+ if (robustness == EmeRobustness::INVALID)
+ return EmeConfigRule::NOT_SUPPORTED;
+ if (robustness == EmeRobustness::EMPTY)
+ return EmeConfigRule::SUPPORTED;
+
KeySystemInfoMap::const_iterator key_system_iter =
concrete_key_system_map_.find(key_system);
if (key_system_iter == concrete_key_system_map_.end()) {
NOTREACHED();
- return false;
+ return EmeConfigRule::NOT_SUPPORTED;
}
- switch (key_system_iter->second.persistent_license_support) {
- case EME_SESSION_TYPE_INVALID:
- NOTREACHED();
- return false;
- case EME_SESSION_TYPE_NOT_SUPPORTED:
- return false;
- case EME_SESSION_TYPE_SUPPORTED_WITH_PERMISSION:
- return is_permission_granted;
- case EME_SESSION_TYPE_SUPPORTED:
- return true;
+ EmeRobustness max_robustness = EmeRobustness::INVALID;
+ switch (media_type) {
+ case EmeMediaType::AUDIO:
+ max_robustness = key_system_iter->second.max_audio_robustness;
+ break;
+ case EmeMediaType::VIDEO:
+ max_robustness = key_system_iter->second.max_video_robustness;
+ break;
}
- NOTREACHED();
- return false;
+ // We can compare robustness levels whenever they are not HW_SECURE_CRYPTO
+ // and SW_SECURE_DECODE in some order. If they are exactly those two then the
+ // robustness requirement is not supported.
+ if ((max_robustness == EmeRobustness::HW_SECURE_CRYPTO &&
+ robustness == EmeRobustness::SW_SECURE_DECODE) ||
+ (max_robustness == EmeRobustness::SW_SECURE_DECODE &&
+ robustness == EmeRobustness::HW_SECURE_CRYPTO) ||
+ robustness > max_robustness) {
+ return EmeConfigRule::NOT_SUPPORTED;
+ }
+
+#if defined(OS_CHROMEOS)
+ if (key_system == kWidevineKeySystem) {
+ // Hardware security requires remote attestation.
+ if (robustness >= EmeRobustness::HW_SECURE_CRYPTO)
+ return EmeConfigRule::IDENTIFIER_REQUIRED;
+
+ // For video, recommend remote attestation if HW_SECURE_ALL is available,
+ // because it enables hardware accelerated decoding.
+ // TODO(sandersd): Only do this when hardware accelerated decoding is
+ // available for the requested codecs.
+ if (media_type == EmeMediaType::VIDEO &&
+ max_robustness == EmeRobustness::HW_SECURE_ALL) {
+ return EmeConfigRule::IDENTIFIER_RECOMMENDED;
+ }
+ }
+#endif // defined(OS_CHROMEOS)
+
+ return EmeConfigRule::SUPPORTED;
}
-bool KeySystems::IsPersistentReleaseMessageSessionSupported(
- const std::string& key_system,
- bool is_permission_granted) {
+EmeConfigRule KeySystems::GetPersistentLicenseSessionConfigRule(
+ const std::string& key_system) {
DCHECK(thread_checker_.CalledOnValidThread());
KeySystemInfoMap::const_iterator key_system_iter =
concrete_key_system_map_.find(key_system);
if (key_system_iter == concrete_key_system_map_.end()) {
NOTREACHED();
- return false;
+ return EmeConfigRule::NOT_SUPPORTED;
}
+ return ConvertSessionTypeSupport(
+ key_system_iter->second.persistent_license_support);
+}
- switch (key_system_iter->second.persistent_release_message_support) {
- case EME_SESSION_TYPE_INVALID:
- NOTREACHED();
- return false;
- case EME_SESSION_TYPE_NOT_SUPPORTED:
- return false;
- case EME_SESSION_TYPE_SUPPORTED_WITH_PERMISSION:
- return is_permission_granted;
- case EME_SESSION_TYPE_SUPPORTED:
- return true;
- }
+EmeConfigRule KeySystems::GetPersistentReleaseMessageSessionConfigRule(
+ const std::string& key_system) {
+ DCHECK(thread_checker_.CalledOnValidThread());
- NOTREACHED();
- return false;
+ KeySystemInfoMap::const_iterator key_system_iter =
+ concrete_key_system_map_.find(key_system);
+ if (key_system_iter == concrete_key_system_map_.end()) {
+ NOTREACHED();
+ return EmeConfigRule::NOT_SUPPORTED;
+ }
+ return ConvertSessionTypeSupport(
+ key_system_iter->second.persistent_release_message_support);
}
-bool KeySystems::IsPersistentStateRequirementSupported(
+EmeConfigRule KeySystems::GetPersistentStateConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted) {
+ EmeFeatureRequirement requirement) {
DCHECK(thread_checker_.CalledOnValidThread());
KeySystemInfoMap::const_iterator key_system_iter =
concrete_key_system_map_.find(key_system);
if (key_system_iter == concrete_key_system_map_.end()) {
NOTREACHED();
- return false;
+ return EmeConfigRule::NOT_SUPPORTED;
}
- switch (key_system_iter->second.persistent_state_support) {
- case EME_FEATURE_INVALID:
- NOTREACHED();
- return false;
- case EME_FEATURE_NOT_SUPPORTED:
- return requirement != EME_FEATURE_REQUIRED;
- case EME_FEATURE_REQUESTABLE_WITH_PERMISSION:
- return (requirement != EME_FEATURE_REQUIRED) || is_permission_granted;
- case EME_FEATURE_REQUESTABLE:
- return true;
- case EME_FEATURE_ALWAYS_ENABLED:
- // Persistent state does not require user permission, but the session
- // types that use it might.
- return requirement != EME_FEATURE_NOT_ALLOWED;
+ // For NOT_ALLOWED and REQUIRED, the result is as expected. For OPTIONAL, we
+ // return the least restrictive of the two rules; this guarantees that if
+ // OPTIONAL is accepted, then it can always be resolved to some value. (In
+ // fact OPTIONAL is always accepted, because the least restrictive rule is
+ // always SUPPORTED.)
+ //
+ // Note that even if permission is not required for persistent state, it may
+ // be required for specific persistent session types.
+ //
+ // NOT_ALLOWED OPTIONAL REQUIRED
+ // NOT_SUPPORTED SUPPORTED SUPPORTED NOT_SUPPORTED
+ // REQUESTABLE_WITH_IDENTIFIER SUPPORTED SUPPORTED IDENTIFIER_REQ
+ // REQUESTABLE SUPPORTED SUPPORTED SUPPORTED
+ // ALWAYS_ENABLED NOT_SUPPORTED SUPPORTED SUPPORTED
+ EmeFeatureSupport support = key_system_iter->second.persistent_state_support;
+ if (support == EME_FEATURE_NOT_SUPPORTED &&
+ requirement == EME_FEATURE_REQUIRED) {
+ return EmeConfigRule::NOT_SUPPORTED;
}
-
- NOTREACHED();
- return false;
+ if (support == EME_FEATURE_ALWAYS_ENABLED &&
+ requirement == EME_FEATURE_NOT_ALLOWED) {
+ return EmeConfigRule::NOT_SUPPORTED;
+ }
+ if (support == EME_FEATURE_REQUESTABLE_WITH_IDENTIFIER &&
+ requirement == EME_FEATURE_REQUIRED) {
+ return EmeConfigRule::IDENTIFIER_REQUIRED;
+ }
+ return EmeConfigRule::SUPPORTED;
}
-bool KeySystems::IsDistinctiveIdentifierRequirementSupported(
+EmeConfigRule KeySystems::GetDistinctiveIdentifierConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted) {
+ EmeFeatureRequirement requirement) {
DCHECK(thread_checker_.CalledOnValidThread());
KeySystemInfoMap::const_iterator key_system_iter =
concrete_key_system_map_.find(key_system);
if (key_system_iter == concrete_key_system_map_.end()) {
NOTREACHED();
- return false;
+ return EmeConfigRule::NOT_SUPPORTED;
}
- switch (key_system_iter->second.distinctive_identifier_support) {
- case EME_FEATURE_INVALID:
- NOTREACHED();
- return false;
- case EME_FEATURE_NOT_SUPPORTED:
- return requirement != EME_FEATURE_REQUIRED;
- case EME_FEATURE_REQUESTABLE_WITH_PERMISSION:
- // TODO(sandersd): Remove this hack once crbug.com/457482 and
- // crbug.com/460616 are addressed.
- // We cannot currently enforce "not-allowed", so don't allow it.
- // Note: Removing this check will expose crbug.com/460616.
- if (requirement == EME_FEATURE_NOT_ALLOWED)
- return false;
- return (requirement != EME_FEATURE_REQUIRED) || is_permission_granted;
- case EME_FEATURE_REQUESTABLE:
- NOTREACHED();
- return true;
- case EME_FEATURE_ALWAYS_ENABLED:
- // Distinctive identifiers always require user permission.
- return (requirement != EME_FEATURE_NOT_ALLOWED) && is_permission_granted;
+ // Permission is required for REQUIRED, but not for NOT_ALLOWED. For OPTIONAL,
+ // we return the least restrictive of the two rules; this guarantees that if
+ // OPTIONAL is accepted, then it can always be resolved to some value.
+ //
+ // NOT_ALLOWED OPTIONAL REQUIRED
+ // NOT_SUPPORTED SUPPORTED SUPPORTED NOT_SUPPORTED
+ // REQUESTABLE_WITH_IDENTIFIER SUPPORTED SUPPORTED IDENTIFIER_REQ
+ // ALWAYS_ENABLED NOT_SUPPORTED IDENTIFIER_REQ IDENTIFIER_REQ
+ EmeFeatureSupport support =
+ key_system_iter->second.distinctive_identifier_support;
+ DCHECK(support != EME_FEATURE_REQUESTABLE);
+ if (support == EME_FEATURE_NOT_SUPPORTED &&
+ requirement == EME_FEATURE_REQUIRED) {
+ return EmeConfigRule::NOT_SUPPORTED;
}
-
- NOTREACHED();
- return false;
+ if (support == EME_FEATURE_ALWAYS_ENABLED &&
+ requirement == EME_FEATURE_NOT_ALLOWED) {
+ return EmeConfigRule::NOT_SUPPORTED;
+ }
+ if (support == EME_FEATURE_ALWAYS_ENABLED ||
+ requirement == EME_FEATURE_REQUIRED) {
+ return EmeConfigRule::IDENTIFIER_REQUIRED;
+ }
+ return EmeConfigRule::SUPPORTED;
}
void KeySystems::AddContainerMask(const std::string& container, uint32 mask) {
@@ -850,34 +952,38 @@ std::string GetPepperType(const std::string& concrete_key_system) {
}
#endif
-bool IsPersistentLicenseSessionSupported(
+EmeConfigRule GetRobustnessConfigRule(
const std::string& key_system,
- bool is_permission_granted) {
- return KeySystems::GetInstance().IsPersistentLicenseSessionSupported(
- key_system, is_permission_granted);
+ EmeMediaType media_type,
+ const std::string& robustness) {
+ return KeySystems::GetInstance().GetRobustnessConfigRule(
+ key_system, media_type, robustness);
}
-bool IsPersistentReleaseMessageSessionSupported(
- const std::string& key_system,
- bool is_permission_granted) {
- return KeySystems::GetInstance().IsPersistentReleaseMessageSessionSupported(
- key_system, is_permission_granted);
+EmeConfigRule GetPersistentLicenseSessionConfigRule(
+ const std::string& key_system) {
+ return KeySystems::GetInstance().GetPersistentLicenseSessionConfigRule(
+ key_system);
+}
+
+EmeConfigRule GetPersistentReleaseMessageSessionConfigRule(
+ const std::string& key_system) {
+ return KeySystems::GetInstance().GetPersistentReleaseMessageSessionConfigRule(
+ key_system);
}
-bool IsPersistentStateRequirementSupported(
+EmeConfigRule GetPersistentStateConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted) {
- return KeySystems::GetInstance().IsPersistentStateRequirementSupported(
- key_system, requirement, is_permission_granted);
+ EmeFeatureRequirement requirement) {
+ return KeySystems::GetInstance().GetPersistentStateConfigRule(
+ key_system, requirement);
}
-bool IsDistinctiveIdentifierRequirementSupported(
+EmeConfigRule GetDistinctiveIdentifierConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted) {
- return KeySystems::GetInstance().IsDistinctiveIdentifierRequirementSupported(
- key_system, requirement, is_permission_granted);
+ EmeFeatureRequirement requirement) {
+ return KeySystems::GetInstance().GetDistinctiveIdentifierConfigRule(
+ key_system, requirement);
}
// These two functions are for testing purpose only. The declaration in the
diff --git a/media/base/key_systems.h b/media/base/key_systems.h
index 93317a1..9cb727f 100644
--- a/media/base/key_systems.h
+++ b/media/base/key_systems.h
@@ -85,27 +85,32 @@ MEDIA_EXPORT std::string GetPepperType(
const std::string& concrete_key_system);
#endif
-// Returns whether |key_system| supports persistent-license sessions.
-MEDIA_EXPORT bool IsPersistentLicenseSessionSupported(
+// Returns the configuration rule for supporting a robustness requirement.
+// TODO(sandersd): Also take a list of codecs, as they may affect the result.
+MEDIA_EXPORT EmeConfigRule GetRobustnessConfigRule(
const std::string& key_system,
- bool is_permission_granted);
+ EmeMediaType media_type,
+ const std::string& requested_robustness);
-// Returns whether |key_system| supports persistent-release-message sessions.
-MEDIA_EXPORT bool IsPersistentReleaseMessageSessionSupported(
- const std::string& key_system,
- bool is_permission_granted);
+// Returns the configuration rule for supporting persistent-license sessions.
+MEDIA_EXPORT EmeConfigRule GetPersistentLicenseSessionConfigRule(
+ const std::string& key_system);
+
+// Returns the configuration rule for supporting persistent-release-message
+// sessions.
+MEDIA_EXPORT EmeConfigRule GetPersistentReleaseMessageSessionConfigRule(
+ const std::string& key_system);
-// Returns whether |key_system| supports persistent state as requested.
-MEDIA_EXPORT bool IsPersistentStateRequirementSupported(
+// Returns the configuration rule for supporting a persistent state requirement.
+MEDIA_EXPORT EmeConfigRule GetPersistentStateConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted);
+ EmeFeatureRequirement requirement);
-// Returns whether |key_system| supports distinctive identifiers as requested.
-MEDIA_EXPORT bool IsDistinctiveIdentifierRequirementSupported(
+// Returns the configuration rule for supporting a distinctive identifier
+// requirement.
+MEDIA_EXPORT EmeConfigRule GetDistinctiveIdentifierConfigRule(
const std::string& key_system,
- EmeFeatureRequirement requirement,
- bool is_permission_granted);
+ EmeFeatureRequirement requirement);
#if defined(UNIT_TEST)
// Helper functions to add container/codec types for testing purposes.
diff --git a/media/base/key_systems_unittest.cc b/media/base/key_systems_unittest.cc
index bb60e8b..9c5c46b 100644
--- a/media/base/key_systems_unittest.cc
+++ b/media/base/key_systems_unittest.cc
@@ -166,6 +166,8 @@ void TestMediaClient::AddUsesAesKeySystem(
system.supported_codecs = EME_CODEC_WEBM_ALL;
system.supported_codecs |= TEST_CODEC_FOO_ALL;
system.supported_init_data_types = EME_INIT_DATA_TYPE_WEBM;
+ system.max_audio_robustness = EmeRobustness::EMPTY;
+ system.max_video_robustness = EmeRobustness::EMPTY;
system.persistent_license_support = EME_SESSION_TYPE_NOT_SUPPORTED;
system.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
system.persistent_state_support = EME_FEATURE_NOT_SUPPORTED;
@@ -181,6 +183,8 @@ void TestMediaClient::AddExternalKeySystem(
ext.supported_codecs = EME_CODEC_WEBM_ALL;
ext.supported_codecs |= TEST_CODEC_FOO_ALL;
ext.supported_init_data_types = EME_INIT_DATA_TYPE_WEBM;
+ ext.max_audio_robustness = EmeRobustness::EMPTY;
+ ext.max_video_robustness = EmeRobustness::EMPTY;
ext.persistent_license_support = EME_SESSION_TYPE_SUPPORTED;
ext.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
ext.persistent_state_support = EME_FEATURE_ALWAYS_ENABLED;
diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc
index e770c4e..d9b6c96 100644
--- a/media/blink/webencryptedmediaclient_impl.cc
+++ b/media/blink/webencryptedmediaclient_impl.cc
@@ -31,6 +31,101 @@ enum ConfigurationSupport {
CONFIGURATION_SUPPORTED,
};
+// Accumulates configuration rules to determine if a feature (additional
+// configuration rule) can be added to an accumulated configuration.
+class ConfigState {
+ public:
+ ConfigState(bool was_permission_requested, bool is_permission_granted)
+ : was_permission_requested_(was_permission_requested),
+ is_permission_granted_(is_permission_granted),
+ is_identifier_required_(false),
+ is_identifier_recommended_(false){
+ }
+
+ bool IsPermissionGranted() const {
+ return is_permission_granted_;
+ }
+
+ // Permission is possible if it has not been denied.
+ bool IsPermissionPossible() const {
+ return is_permission_granted_ || !was_permission_requested_;
+ }
+
+ bool IsIdentifierRequired() const {
+ return is_identifier_required_;
+ }
+
+ bool IsIdentifierRecommended() const {
+ return is_identifier_recommended_;
+ }
+
+ // Checks whether a rule is compatible with all previously added rules.
+ bool IsRuleSupported(EmeConfigRule rule) const {
+ switch (rule) {
+ case EmeConfigRule::NOT_SUPPORTED:
+ return false;
+ case EmeConfigRule::IDENTIFIER_REQUIRED:
+ return IsPermissionPossible();
+ case EmeConfigRule::IDENTIFIER_RECOMMENDED:
+ return true;
+ case EmeConfigRule::SUPPORTED:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ // Checks whether a rule is compatible with all previously added rules, and
+ // can be accepted without needing to add it to the configuration state. This
+ // allows considering more rules after the configuration state is final (that
+ // is, after distinctiveIdentifier has been resolved).
+ bool IsRuleSupportedWithCurrentState(EmeConfigRule rule) const {
+ switch (rule) {
+ case EmeConfigRule::NOT_SUPPORTED:
+ return false;
+ case EmeConfigRule::IDENTIFIER_REQUIRED:
+ return is_permission_granted_;
+ case EmeConfigRule::IDENTIFIER_RECOMMENDED:
+ return true;
+ case EmeConfigRule::SUPPORTED:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ // Add a rule to the accumulated configuration state.
+ void AddRule(EmeConfigRule rule) {
+ switch (rule) {
+ case EmeConfigRule::NOT_SUPPORTED:
+ return;
+ case EmeConfigRule::IDENTIFIER_REQUIRED:
+ is_identifier_required_ = true;
+ return;
+ case EmeConfigRule::IDENTIFIER_RECOMMENDED:
+ is_identifier_recommended_ = true;
+ return;
+ case EmeConfigRule::SUPPORTED:
+ return;
+ }
+ NOTREACHED();
+ }
+
+ private:
+ // Whether permission to use a distinctive identifier was requested. If set,
+ // |is_permission_granted_| represents the final decision.
+ const bool was_permission_requested_;
+
+ // Whether permission to use a distinctive identifier has been granted.
+ const bool is_permission_granted_;
+
+ // Whether a rule has been added that requires a distinctive identifier.
+ bool is_identifier_required_;
+
+ // Whether a rule has been added that recommends a distinctive identifier.
+ bool is_identifier_recommended_;
+};
+
static bool IsSupportedContentType(const std::string& key_system,
const std::string& mime_type,
const std::string& codecs) {
@@ -65,23 +160,31 @@ static bool IsSupportedContentType(const std::string& key_system,
static bool GetSupportedCapabilities(
const std::string& key_system,
const blink::WebVector<blink::WebMediaKeySystemMediaCapability>&
- capabilities,
+ requested_media_capabilities,
+ EmeMediaType media_type,
std::vector<blink::WebMediaKeySystemMediaCapability>*
- media_type_capabilities) {
+ supported_media_capabilities,
+ ConfigState* config_state) {
// From
// https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-media-type
- // 1. Let accumulated capabilities be partial configuration.
- // (Skipped as there are no configuration-based codec restrictions.)
- // 2. Let media type capabilities be empty.
- DCHECK_EQ(media_type_capabilities->size(), 0ul);
- // 3. For each value in capabilities:
- for (size_t i = 0; i < capabilities.size(); i++) {
+ // 1. Let local accumulated capabilities be a local copy of partial
+ // configuration.
+ // (Skipped as we directly update |config_state|. This is safe because we
+ // only do so when at least one requested media capability is supported.)
+ // 2. Let supported media capabilities be empty.
+ DCHECK_EQ(supported_media_capabilities->size(), 0ul);
+ // 3. For each value in requested media capabilities:
+ for (size_t i = 0; i < requested_media_capabilities.size(); i++) {
// 3.1. Let contentType be the value's contentType member.
// 3.2. Let robustness be the value's robustness member.
- const blink::WebMediaKeySystemMediaCapability& capability = capabilities[i];
+ const blink::WebMediaKeySystemMediaCapability& capability =
+ requested_media_capabilities[i];
// 3.3. If contentType is the empty string, return null.
- if (capability.mimeType.isEmpty())
+ if (capability.mimeType.isEmpty()) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "a capability contentType was empty.";
return false;
+ }
// 3.4-3.11. (Implemented by IsSupportedContentType().)
if (!base::IsStringASCII(capability.mimeType) ||
!base::IsStringASCII(capability.codecs) ||
@@ -91,26 +194,38 @@ static bool GetSupportedCapabilities(
continue;
}
// 3.12. If robustness is not the empty string, run the following steps:
- // (Robustness is not supported.)
- // TODO(sandersd): Implement robustness. http://crbug.com/442586
if (!capability.robustness.isEmpty()) {
- LOG(WARNING) << "Configuration rejected because rubustness strings are "
- << "not yet supported.";
- continue;
+ // 3.12.1. If robustness is an unrecognized value or not supported by
+ // implementation, continue to the next iteration. String
+ // comparison is case-sensitive.
+ if (!base::IsStringASCII(capability.robustness))
+ continue;
+ EmeConfigRule robustness_rule = GetRobustnessConfigRule(
+ key_system, media_type, base::UTF16ToASCII(capability.robustness));
+ if (!config_state->IsRuleSupported(robustness_rule))
+ continue;
+ config_state->AddRule(robustness_rule);
+ // 3.12.2. Add robustness to configuration.
+ // (It's already added, we use capability as configuration.)
}
// 3.13. If the user agent and implementation do not support playback of
// encrypted media data as specified by configuration, including all
- // media types, in combination with accumulated capabilities,
+ // media types, in combination with local accumulated capabilities,
// continue to the next iteration.
- // (Skipped as there are no configuration-based codec restrictions.)
- // 3.14. Add configuration to media type capabilities.
- media_type_capabilities->push_back(capability);
- // 3.15. Add configuration to accumulated capabilities.
- // (Skipped as there are no configuration-based codec restrictions.)
+ // (This is handled when adding rules to |config_state|.)
+ // 3.14. Add configuration to supported media capabilities.
+ supported_media_capabilities->push_back(capability);
+ // 3.15. Add configuration to local accumulated capabilities.
+ // (Skipped as we directly update |config_state|.)
+ }
+ // 4. If supported media capabilities is empty, return null.
+ if (supported_media_capabilities->empty()) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "no capabilities were supported.";
+ return false;
}
- // 4. If media type capabilities is empty, return null.
// 5. Return media type capabilities.
- return !media_type_capabilities->empty();
+ return true;
}
static EmeFeatureRequirement ConvertRequirement(
@@ -131,15 +246,10 @@ static EmeFeatureRequirement ConvertRequirement(
static ConfigurationSupport GetSupportedConfiguration(
const std::string& key_system,
const blink::WebMediaKeySystemConfiguration& candidate,
- blink::WebMediaKeySystemConfiguration* accumulated_configuration,
bool was_permission_requested,
- bool is_permission_granted) {
- DCHECK(was_permission_requested || !is_permission_granted);
-
- // It is possible to obtain user permission unless permission was already
- // requested and denied.
- bool is_permission_possible =
- !was_permission_requested || is_permission_granted;
+ bool is_permission_granted,
+ blink::WebMediaKeySystemConfiguration* accumulated_configuration) {
+ ConfigState config_state(was_permission_requested, is_permission_granted);
// From https://w3c.github.io/encrypted-media/#get-supported-configuration
// 1. Let accumulated configuration be empty. (Done by caller.)
@@ -184,8 +294,11 @@ static ConfigurationSupport GetSupportedConfiguration(
}
// 2.3. If supported types is empty, return null.
- if (supported_types.empty())
+ if (supported_types.empty()) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "no initDataType values were supported.";
return CONFIGURATION_NOT_SUPPORTED;
+ }
// 2.4. Add supported types to accumulated configuration.
accumulated_configuration->initDataTypes = supported_types;
@@ -200,12 +313,16 @@ static ConfigurationSupport GetSupportedConfiguration(
// - "not-allowed": If the implementation requires a Distinctive
// Identifier in combination with accumulated configuration, return
// null.
- EmeFeatureRequirement di_requirement =
- ConvertRequirement(candidate.distinctiveIdentifier);
- if (!IsDistinctiveIdentifierRequirementSupported(key_system, di_requirement,
- is_permission_possible)) {
+ // We also reject OPTIONAL when distinctive identifiers are ALWAYS_ENABLED and
+ // permission has already been denied. This would happen anyway at step 11.
+ EmeConfigRule di_rule = GetDistinctiveIdentifierConfigRule(
+ key_system, ConvertRequirement(candidate.distinctiveIdentifier));
+ if (!config_state.IsRuleSupported(di_rule)) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "the distinctiveIdentifier requirement was not supported.";
return CONFIGURATION_NOT_SUPPORTED;
}
+ config_state.AddRule(di_rule);
// 4. Add the value of the candidate configuration's distinctiveIdentifier
// attribute to accumulated configuration.
@@ -219,12 +336,14 @@ static ConfigurationSupport GetSupportedConfiguration(
// - "optional": Continue.
// - "not-allowed": If the implementation requires persisting state in
// combination with accumulated configuration, return null.
- EmeFeatureRequirement ps_requirement =
- ConvertRequirement(candidate.persistentState);
- if (!IsPersistentStateRequirementSupported(key_system, ps_requirement,
- is_permission_possible)) {
+ EmeConfigRule ps_rule = GetPersistentStateConfigRule(
+ key_system, ConvertRequirement(candidate.persistentState));
+ if (!config_state.IsRuleSupported(ps_rule)) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "the persistentState requirement was not supported.";
return CONFIGURATION_NOT_SUPPORTED;
}
+ config_state.AddRule(ps_rule);
// 6. Add the value of the candidate configuration's persistentState
// attribute to accumulated configuration.
@@ -240,7 +359,8 @@ static ConfigurationSupport GetSupportedConfiguration(
// 7.2. If video capabilities is null, return null.
std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities;
if (!GetSupportedCapabilities(key_system, candidate.videoCapabilities,
- &video_capabilities)) {
+ EmeMediaType::VIDEO, &video_capabilities,
+ &config_state)) {
return CONFIGURATION_NOT_SUPPORTED;
}
@@ -258,7 +378,8 @@ static ConfigurationSupport GetSupportedConfiguration(
// 8.2. If audio capabilities is null, return null.
std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities;
if (!GetSupportedCapabilities(key_system, candidate.audioCapabilities,
- &audio_capabilities)) {
+ EmeMediaType::AUDIO, &audio_capabilities,
+ &config_state)) {
return CONFIGURATION_NOT_SUPPORTED;
}
@@ -274,20 +395,50 @@ static ConfigurationSupport GetSupportedConfiguration(
// configuration's distinctiveIdentifier value to "required".
// - Otherwise, change accumulated configuration's distinctiveIdentifier
// value to "not-allowed".
- // (Without robustness support, capabilities do not affect this.)
- // TODO(sandersd): Implement robustness. http://crbug.com/442586
if (accumulated_configuration->distinctiveIdentifier ==
blink::WebMediaKeySystemConfiguration::Requirement::Optional) {
- if (IsDistinctiveIdentifierRequirementSupported(
- key_system, EME_FEATURE_NOT_ALLOWED, is_permission_possible)) {
- accumulated_configuration->distinctiveIdentifier =
- blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed;
- } else {
+ EmeConfigRule not_allowed_rule =
+ GetDistinctiveIdentifierConfigRule(key_system, EME_FEATURE_NOT_ALLOWED);
+ EmeConfigRule required_rule =
+ GetDistinctiveIdentifierConfigRule(key_system, EME_FEATURE_REQUIRED);
+ bool not_allowed_supported = config_state.IsRuleSupported(not_allowed_rule);
+ bool required_supported = config_state.IsRuleSupported(required_rule);
+ if (not_allowed_supported) {
+ bool prefer_required = config_state.IsIdentifierRequired() ||
+ (config_state.IsIdentifierRecommended() &&
+ config_state.IsPermissionPossible());
+ if (required_supported && prefer_required) {
+ accumulated_configuration->distinctiveIdentifier =
+ blink::WebMediaKeySystemConfiguration::Requirement::Required;
+ config_state.AddRule(required_rule);
+ DCHECK(config_state.IsIdentifierRequired());
+ } else {
+ accumulated_configuration->distinctiveIdentifier =
+ blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed;
+ config_state.AddRule(not_allowed_rule);
+ }
+ } else if (required_supported) {
accumulated_configuration->distinctiveIdentifier =
blink::WebMediaKeySystemConfiguration::Requirement::Required;
+ config_state.AddRule(required_rule);
+ } else {
+ // We should not have passed step 3.
+ NOTREACHED();
+ return CONFIGURATION_NOT_SUPPORTED;
}
}
+ // If permission is required but we couldn't enable it, reject the
+ // configuration.
+ if (config_state.IsIdentifierRequired() &&
+ accumulated_configuration->distinctiveIdentifier !=
+ blink::WebMediaKeySystemConfiguration::Requirement::Required) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "distinctiveIdentifier was implicitly required but "
+ << "not allowed.";
+ return CONFIGURATION_NOT_SUPPORTED;
+ }
+
// 10. If accumulated configuration's persistentState value is "optional",
// follow the steps for the first matching condition from the following
// list:
@@ -298,59 +449,57 @@ static ConfigurationSupport GetSupportedConfiguration(
// to "not-allowed".
if (accumulated_configuration->persistentState ==
blink::WebMediaKeySystemConfiguration::Requirement::Optional) {
- if (IsPersistentStateRequirementSupported(
- key_system, EME_FEATURE_NOT_ALLOWED, is_permission_possible)) {
+ EmeConfigRule not_allowed_rule =
+ GetPersistentStateConfigRule(key_system, EME_FEATURE_NOT_ALLOWED);
+ EmeConfigRule required_rule =
+ GetPersistentStateConfigRule(key_system, EME_FEATURE_REQUIRED);
+ // Now that distinctiveIdentifier has been resolved, it is too late to allow
+ // persistentState to affect the configuration.
+ bool not_allowed_supported =
+ config_state.IsRuleSupportedWithCurrentState(not_allowed_rule);
+ bool required_supported =
+ config_state.IsRuleSupportedWithCurrentState(required_rule);
+ if (not_allowed_supported) {
accumulated_configuration->persistentState =
blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed;
- } else {
+ } else if (required_supported) {
accumulated_configuration->persistentState =
blink::WebMediaKeySystemConfiguration::Requirement::Required;
+ } else {
+ // We should not have passed step 5.
+ NOTREACHED();
+ return CONFIGURATION_NOT_SUPPORTED;
}
}
// 11. If implementation in the configuration specified by the combination of
// the values in accumulated configuration is not supported or not allowed
// in the origin, return null.
- di_requirement =
- ConvertRequirement(accumulated_configuration->distinctiveIdentifier);
- if (!IsDistinctiveIdentifierRequirementSupported(key_system, di_requirement,
- is_permission_granted)) {
- if (was_permission_requested) {
- // The optional permission was requested and denied.
- // TODO(sandersd): Avoid the need for this logic - crbug.com/460616.
- DCHECK(candidate.distinctiveIdentifier ==
- blink::WebMediaKeySystemConfiguration::Requirement::Optional);
- DCHECK(di_requirement == EME_FEATURE_REQUIRED);
- DCHECK(!is_permission_granted);
- accumulated_configuration->distinctiveIdentifier =
- blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed;
- } else {
+ // 12. If accumulated configuration's distinctiveIdentifier value is
+ // "required", [prompt the user for consent].
+ if (accumulated_configuration->distinctiveIdentifier ==
+ blink::WebMediaKeySystemConfiguration::Requirement::Required) {
+ // The caller is responsible for resolving what to do if permission is
+ // required but has been denied (it should treat it as NOT_SUPPORTED).
+ if (!config_state.IsPermissionGranted())
return CONFIGURATION_REQUIRES_PERMISSION;
- }
}
- ps_requirement =
- ConvertRequirement(accumulated_configuration->persistentState);
- if (!IsPersistentStateRequirementSupported(key_system, ps_requirement,
- is_permission_granted)) {
- DCHECK(!was_permission_requested); // Should have failed at step 5.
- return CONFIGURATION_REQUIRES_PERMISSION;
- }
-
- // 12. Return accumulated configuration.
- // (As an extra step, we record the available session types so that
- // createSession() can be synchronous.)
+ // 13. Return accumulated configuration.
+ //
+ // We also record the available session types so that createSession() can be
+ // synchronous.
std::vector<blink::WebEncryptedMediaSessionType> session_types;
session_types.push_back(blink::WebEncryptedMediaSessionType::Temporary);
if (accumulated_configuration->persistentState ==
blink::WebMediaKeySystemConfiguration::Requirement::Required) {
- if (IsPersistentLicenseSessionSupported(key_system,
- is_permission_granted)) {
+ if (config_state.IsRuleSupportedWithCurrentState(
+ GetPersistentLicenseSessionConfigRule(key_system))) {
session_types.push_back(
blink::WebEncryptedMediaSessionType::PersistentLicense);
}
- if (IsPersistentReleaseMessageSessionSupported(key_system,
- is_permission_granted)) {
+ if (config_state.IsRuleSupportedWithCurrentState(
+ GetPersistentReleaseMessageSessionConfigRule(key_system))) {
session_types.push_back(
blink::WebEncryptedMediaSessionType::PersistentReleaseMessage);
}
@@ -474,13 +623,17 @@ void WebEncryptedMediaClientImpl::SelectSupportedConfiguration(
// new MediaKeySystemAccess object.]
blink::WebMediaKeySystemConfiguration accumulated_configuration;
ConfigurationSupport supported = GetSupportedConfiguration(
- key_system, candidate_configuration, &accumulated_configuration,
- was_permission_requested, is_permission_granted);
+ key_system, candidate_configuration, was_permission_requested,
+ is_permission_granted, &accumulated_configuration);
switch (supported) {
case CONFIGURATION_NOT_SUPPORTED:
continue;
case CONFIGURATION_REQUIRES_PERMISSION:
- DCHECK(!was_permission_requested);
+ if (was_permission_requested) {
+ DVLOG(2) << "Rejecting requested configuration because "
+ << "permission was denied.";
+ continue;
+ }
media_permission_->RequestPermission(
MediaPermission::PROTECTED_MEDIA_IDENTIFIER,
GURL(request.securityOrigin().toString()),
diff --git a/media/test/data/eme_player_js/player_utils.js b/media/test/data/eme_player_js/player_utils.js
index d72bef7..86a3e0e 100644
--- a/media/test/data/eme_player_js/player_utils.js
+++ b/media/test/data/eme_player_js/player_utils.js
@@ -85,8 +85,10 @@ PlayerUtils.registerEMEEventListeners = function(player) {
this.registerDefaultEventListeners(player);
Utils.timeLog('Setting video media keys: ' + player.testConfig.keySystem);
+ var persistentState = player.testConfig.sessionToLoad ? "required"
+ : "optional";
return navigator.requestMediaKeySystemAccess(
- player.testConfig.keySystem, [{}])
+ player.testConfig.keySystem, [{persistentState: persistentState}])
.then(function(access) { return access.createMediaKeys(); })
.then(function(mediaKeys) {
return player.video.setMediaKeys(mediaKeys);