Commit a8a9143d authored by sandersd's avatar sandersd Committed by Commit bot

Implement robustness strings in requestMediaKeySystemAccess().

BUG=442586,460616

Review URL: https://codereview.chromium.org/1005903003

Cr-Commit-Position: refs/heads/master@{#322219}
parent f1eb0a7e
......@@ -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,23 +193,20 @@ 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::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);
......
......@@ -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);
......
......@@ -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);
}
if (response.non_compositing_codecs != media::EME_CODEC_NONE) {
// 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) {
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 =
......
......@@ -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;
......
......@@ -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,
......
......@@ -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 =
......
......@@ -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;
......
......@@ -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_
......@@ -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),
......
......@@ -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;
......
......@@ -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);
EmeConfigRule GetPersistentReleaseMessageSessionConfigRule(
const std::string& key_system);
bool IsPersistentStateRequirementSupported(
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,
DCHECK(info.persistent_license_support == EME_SESSION_TYPE_NOT_SUPPORTED);
DCHECK(info.persistent_release_message_support ==
EME_SESSION_TYPE_NOT_SUPPORTED);
DCHECK_EQ(info.persistent_release_message_support,
}
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);
}
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";
// 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());
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_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
......
......@@ -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.
......
......@@ -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;
......
......@@ -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.";
// 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)) {
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::NotAllowed;
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 {
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.
// 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;
}
// 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()),
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment