| Index: media/blink/webencryptedmediaclient_impl.cc
|
| diff --git a/media/blink/webencryptedmediaclient_impl.cc b/media/blink/webencryptedmediaclient_impl.cc
|
| index 53b658330e72ac3a15687c375ee701800e0670da..c963df8341e525ab06b861ea56adb5447f7fc988 100644
|
| --- a/media/blink/webencryptedmediaclient_impl.cc
|
| +++ b/media/blink/webencryptedmediaclient_impl.cc
|
| @@ -28,25 +28,97 @@ static bool IsSupportedContentType(
|
| const std::string& key_system,
|
| const std::string& mime_type,
|
| const std::string& codecs) {
|
| - // Per RFC 6838, "Both top-level type and subtype names are case-insensitive."
|
| - // TODO(sandersd): Check that |container| matches the capability:
|
| - // - audioCapabilitys: audio/mp4 or audio/webm.
|
| - // - videoCapabilitys: video/mp4 or video/webm.
|
| - // http://crbug.com/457384.
|
| + // TODO(sandersd): Move contentType parsing from Blink to here so that invalid
|
| + // parameters can be rejected. http://crbug.com/417561
|
| + // TODO(sandersd): Pass in the media type (audio or video) and check that the
|
| + // container type matches. http://crbug.com/457384
|
| std::string container = base::StringToLowerASCII(mime_type);
|
|
|
| - // Check that |codecs| are supported as specified (e.g. "mp4a.40.2").
|
| + // Check that |codecs| are supported by the CDM. This check does not handle
|
| + // extended codecs, so extended codec information is stripped.
|
| + // TODO(sandersd): Reject codecs that do not match the media type.
|
| + // http://crbug.com/457386
|
| std::vector<std::string> codec_vector;
|
| - net::ParseCodecString(codecs, &codec_vector, false);
|
| - if (!net::AreSupportedMediaCodecs(codec_vector))
|
| + net::ParseCodecString(codecs, &codec_vector, true);
|
| + if (!IsSupportedKeySystemWithMediaMimeType(container, codec_vector,
|
| + key_system)) {
|
| return false;
|
| + }
|
|
|
| - // IsSupportedKeySystemWithMediaMimeType() only works with base codecs
|
| - // (e.g. "mp4a"), so reparse |codecs| to get the base only.
|
| + // Check that |codecs| are supported by Chrome. This is done primarily to
|
| + // validate extended codecs, but it also ensures that the CDM cannot support
|
| + // codecs that Chrome does not (which would be bad because it would require
|
| + // considering the accumulated configuration, and could affect whether secure
|
| + // decode is required).
|
| + // TODO(sandersd): Reject ambiguous codecs. http://crbug.com/374751
|
| codec_vector.clear();
|
| - net::ParseCodecString(codecs, &codec_vector, true);
|
| - return IsSupportedKeySystemWithMediaMimeType(container, codec_vector,
|
| - key_system);
|
| + net::ParseCodecString(codecs, &codec_vector, false);
|
| + return net::AreSupportedMediaCodecs(codec_vector);
|
| +}
|
| +
|
| +static bool GetSupportedCapabilities(
|
| + const std::string& key_system,
|
| + const blink::WebVector<blink::WebMediaKeySystemMediaCapability>&
|
| + capabilities,
|
| + std::vector<blink::WebMediaKeySystemMediaCapability>*
|
| + media_type_capabilities) {
|
| + // 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++) {
|
| + // 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];
|
| + // 3.3. If contentType is the empty string, return null.
|
| + if (capability.mimeType.isEmpty())
|
| + return false;
|
| + // 3.4-3.11. (Implemented by IsSupportedContentType().)
|
| + if (!base::IsStringASCII(capability.mimeType) ||
|
| + !base::IsStringASCII(capability.codecs) ||
|
| + !IsSupportedContentType(key_system,
|
| + base::UTF16ToASCII(capability.mimeType),
|
| + base::UTF16ToASCII(capability.codecs))) {
|
| + 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.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,
|
| + // 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.)
|
| + }
|
| + // 4. If media type capabilities is empty, return null.
|
| + // 5. Return media type capabilities.
|
| + return !media_type_capabilities->empty();
|
| +}
|
| +
|
| +static EmeFeatureRequirement ConvertRequirement(
|
| + blink::WebMediaKeySystemConfiguration::Requirement requirement) {
|
| + switch (requirement) {
|
| + case blink::WebMediaKeySystemConfiguration::Requirement::Required:
|
| + return EME_FEATURE_REQUIRED;
|
| + case blink::WebMediaKeySystemConfiguration::Requirement::Optional:
|
| + return EME_FEATURE_OPTIONAL;
|
| + case blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed:
|
| + return EME_FEATURE_NOT_ALLOWED;
|
| + }
|
| +
|
| + NOTREACHED();
|
| + return EME_FEATURE_NOT_ALLOWED;
|
| }
|
|
|
| static bool GetSupportedConfiguration(
|
| @@ -54,92 +126,180 @@ static bool GetSupportedConfiguration(
|
| const blink::WebMediaKeySystemConfiguration& candidate,
|
| const blink::WebSecurityOrigin& security_origin,
|
| blink::WebMediaKeySystemConfiguration* accumulated_configuration) {
|
| + // When determining support, assume that permission could be granted.
|
| + // TODO(sandersd): Set to false if the permission is rejected.
|
| + bool is_permission_possible = true;
|
| +
|
| + // From https://w3c.github.io/encrypted-media/#get-supported-configuration
|
| + // 1. Let accumulated configuration be empty. (Done by caller.)
|
| + // 2. If candidate configuration's initDataTypes attribute is not empty, run
|
| + // the following steps:
|
| if (!candidate.initDataTypes.isEmpty()) {
|
| - std::vector<blink::WebString> init_data_types;
|
| + // 2.1. Let supported types be empty.
|
| + std::vector<blink::WebString> supported_types;
|
|
|
| + // 2.2. For each value in candidate configuration's initDataTypes attribute:
|
| for (size_t i = 0; i < candidate.initDataTypes.size(); i++) {
|
| + // 2.2.1. Let initDataType be the value.
|
| const blink::WebString& init_data_type = candidate.initDataTypes[i];
|
| + // 2.2.2. If initDataType is the empty string, return null.
|
| if (init_data_type.isEmpty())
|
| return false;
|
| + // 2.2.3. If the implementation supports generating requests based on
|
| + // initDataType, add initDataType to supported types. String
|
| + // comparison is case-sensitive.
|
| if (base::IsStringASCII(init_data_type) &&
|
| IsSupportedKeySystemWithInitDataType(
|
| key_system, base::UTF16ToASCII(init_data_type))) {
|
| - init_data_types.push_back(init_data_type);
|
| + supported_types.push_back(init_data_type);
|
| }
|
| }
|
|
|
| - if (init_data_types.empty())
|
| + // 2.3. If supported types is empty, return null.
|
| + if (supported_types.empty())
|
| return false;
|
|
|
| - accumulated_configuration->initDataTypes = init_data_types;
|
| + // 2.4. Add supported types to accumulated configuration.
|
| + accumulated_configuration->initDataTypes = supported_types;
|
| }
|
|
|
| - // TODO(sandersd): Implement distinctiveIdentifier and persistentState checks.
|
| - if (candidate.distinctiveIdentifier !=
|
| - blink::WebMediaKeySystemConfiguration::Requirement::Optional ||
|
| - candidate.persistentState !=
|
| - blink::WebMediaKeySystemConfiguration::Requirement::Optional) {
|
| + // 3. Follow the steps for the value of candidate configuration's
|
| + // distinctiveIdentifier attribute from the following list:
|
| + // - "required": If the implementation does not support a persistent
|
| + // Distinctive Identifier in combination with accumulated configuration,
|
| + // return null.
|
| + // - "optional": Continue.
|
| + // - "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)) {
|
| return false;
|
| }
|
|
|
| - if (!candidate.audioCapabilities.isEmpty()) {
|
| - std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities;
|
| + // 4. Add the value of the candidate configuration's distinctiveIdentifier
|
| + // attribute to accumulated configuration.
|
| + accumulated_configuration->distinctiveIdentifier =
|
| + candidate.distinctiveIdentifier;
|
| +
|
| + // 5. Follow the steps for the value of candidate configuration's
|
| + // persistentState attribute from the following list:
|
| + // - "required": If the implementation does not support persisting state
|
| + // in combination with accumulated configuration, return null.
|
| + // - "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)) {
|
| + return false;
|
| + }
|
|
|
| - for (size_t i = 0; i < candidate.audioCapabilities.size(); i++) {
|
| - const blink::WebMediaKeySystemMediaCapability& capabilities =
|
| - candidate.audioCapabilities[i];
|
| - if (capabilities.mimeType.isEmpty())
|
| - return false;
|
| - if (!base::IsStringASCII(capabilities.mimeType) ||
|
| - !base::IsStringASCII(capabilities.codecs) ||
|
| - !IsSupportedContentType(
|
| - key_system, base::UTF16ToASCII(capabilities.mimeType),
|
| - base::UTF16ToASCII(capabilities.codecs))) {
|
| - continue;
|
| - }
|
| - // TODO(sandersd): Support robustness.
|
| - if (!capabilities.robustness.isEmpty())
|
| - continue;
|
| - audio_capabilities.push_back(capabilities);
|
| + // 6. Add the value of the candidate configuration's persistentState
|
| + // attribute to accumulated configuration.
|
| + accumulated_configuration->persistentState = candidate.persistentState;
|
| +
|
| + // 7. If candidate configuration's videoCapabilities attribute is not empty,
|
| + // run the following steps:
|
| + if (!candidate.videoCapabilities.isEmpty()) {
|
| + // 7.1. Let video capabilities be the result of executing the Get Supported
|
| + // Capabilities for Media Type algorithm on Video, candidate
|
| + // configuration's videoCapabilities attribute, and accumulated
|
| + // configuration.
|
| + // 7.2. If video capabilities is null, return null.
|
| + std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities;
|
| + if (!GetSupportedCapabilities(key_system, candidate.videoCapabilities,
|
| + &video_capabilities)) {
|
| + return false;
|
| }
|
|
|
| - if (audio_capabilities.empty())
|
| + // 7.3. Add video capabilities to accumulated configuration.
|
| + accumulated_configuration->videoCapabilities = video_capabilities;
|
| + }
|
| +
|
| + // 8. If candidate configuration's audioCapabilities attribute is not empty,
|
| + // run the following steps:
|
| + if (!candidate.audioCapabilities.isEmpty()) {
|
| + // 8.1. Let audio capabilities be the result of executing the Get Supported
|
| + // Capabilities for Media Type algorithm on Audio, candidate
|
| + // configuration's audioCapabilities attribute, and accumulated
|
| + // configuration.
|
| + // 8.2. If audio capabilities is null, return null.
|
| + std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities;
|
| + if (!GetSupportedCapabilities(key_system, candidate.audioCapabilities,
|
| + &audio_capabilities)) {
|
| return false;
|
| + }
|
|
|
| + // 8.3. Add audio capabilities to accumulated configuration.
|
| accumulated_configuration->audioCapabilities = audio_capabilities;
|
| }
|
|
|
| - if (!candidate.videoCapabilities.isEmpty()) {
|
| - std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities;
|
| -
|
| - for (size_t i = 0; i < candidate.videoCapabilities.size(); i++) {
|
| - const blink::WebMediaKeySystemMediaCapability& capabilities =
|
| - candidate.videoCapabilities[i];
|
| - if (capabilities.mimeType.isEmpty())
|
| - return false;
|
| - if (!base::IsStringASCII(capabilities.mimeType) ||
|
| - !base::IsStringASCII(capabilities.codecs) ||
|
| - !IsSupportedContentType(
|
| - key_system, base::UTF16ToASCII(capabilities.mimeType),
|
| - base::UTF16ToASCII(capabilities.codecs))) {
|
| - continue;
|
| - }
|
| - // TODO(sandersd): Support robustness.
|
| - if (!capabilities.robustness.isEmpty())
|
| - continue;
|
| - video_capabilities.push_back(capabilities);
|
| + // 9. If accumulated configuration's distinctiveIdentifier value is
|
| + // "optional", follow the steps for the first matching condition from the
|
| + // following list:
|
| + // - If the implementation requires a Distinctive Identifier for any of
|
| + // the combinations in accumulated configuration, change accumulated
|
| + // 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 {
|
| + accumulated_configuration->distinctiveIdentifier =
|
| + blink::WebMediaKeySystemConfiguration::Requirement::Required;
|
| }
|
| + }
|
|
|
| - if (video_capabilities.empty())
|
| - return false;
|
| + // 10. If accumulated configuration's persistentState value is "optional",
|
| + // follow the steps for the first matching condition from the following
|
| + // list:
|
| + // - If the implementation requires persisting state for any of the
|
| + // combinations in accumulated configuration, change accumulated
|
| + // configuration's persistentState value to "required".
|
| + // - Otherwise, change accumulated configuration's persistentState value
|
| + // to "not-allowed".
|
| + if (accumulated_configuration->persistentState ==
|
| + blink::WebMediaKeySystemConfiguration::Requirement::Optional) {
|
| + if (IsPersistentStateRequirementSupported(key_system,
|
| + EME_FEATURE_NOT_ALLOWED,
|
| + is_permission_possible)) {
|
| + accumulated_configuration->persistentState =
|
| + blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed;
|
| + } else {
|
| + accumulated_configuration->persistentState =
|
| + blink::WebMediaKeySystemConfiguration::Requirement::Required;
|
| + }
|
| + }
|
|
|
| - accumulated_configuration->videoCapabilities = video_capabilities;
|
| + // 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.
|
| + // TODO(sandersd): Implement prompting. http://crbug.com/446263
|
| + // For now, assume that the permission was not granted.
|
| + di_requirement =
|
| + ConvertRequirement(accumulated_configuration->distinctiveIdentifier);
|
| + if (!IsDistinctiveIdentifierRequirementSupported(key_system, di_requirement,
|
| + false)) {
|
| + return false;
|
| }
|
|
|
| - // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state
|
| - // if required. Make sure that future checks are silent.
|
| - // http://crbug.com/446263.
|
| + ps_requirement =
|
| + ConvertRequirement(accumulated_configuration->persistentState);
|
| + if (!IsPersistentStateRequirementSupported(key_system, ps_requirement, false))
|
| + return false;
|
|
|
| + // 12. Return accumulated configuration.
|
| return true;
|
| }
|
|
|
| @@ -212,9 +372,9 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
|
| // Continued from requestMediaKeySystemAccess(), step 7, from
|
| // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
|
| //
|
| - // 7.1 If keySystem is not one of the Key Systems supported by the user
|
| - // agent, reject promise with with a new DOMException whose name is
|
| - // NotSupportedError. String comparison is case-sensitive.
|
| + // 7.1. If keySystem is not one of the Key Systems supported by the user
|
| + // agent, reject promise with with a new DOMException whose name is
|
| + // NotSupportedError. String comparison is case-sensitive.
|
| if (!base::IsStringASCII(request.keySystem())) {
|
| request.requestNotSupported("Only ASCII keySystems are supported");
|
| return;
|
| @@ -231,27 +391,21 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
|
| return;
|
| }
|
|
|
| - // 7.2 Let implementation be the implementation of keySystem.
|
| - // 7.3 For each value in supportedConfigurations, run the GetSupported
|
| - // Configuration algorithm and if successful, resolve promise with access
|
| - // and abort these steps.
|
| + // 7.2. Let implementation be the implementation of keySystem.
|
| + // 7.3. For each value in supportedConfigurations:
|
| const blink::WebVector<blink::WebMediaKeySystemConfiguration>&
|
| configurations = request.supportedConfigurations();
|
| -
|
| - // TODO(sandersd): Remove once Blink requires the configurations parameter for
|
| - // requestMediaKeySystemAccess().
|
| - if (configurations.isEmpty()) {
|
| - reporter->ReportSupported();
|
| - request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
|
| - request.keySystem(), blink::WebMediaKeySystemConfiguration(),
|
| - request.securityOrigin(), weak_factory_.GetWeakPtr()));
|
| - return;
|
| - }
|
| -
|
| for (size_t i = 0; i < configurations.size(); i++) {
|
| - const blink::WebMediaKeySystemConfiguration& candidate = configurations[i];
|
| + // 7.3.1. Let candidate configuration be the value.
|
| + const blink::WebMediaKeySystemConfiguration& candidate_configuration =
|
| + configurations[i];
|
| + // 7.3.2. Let supported configuration be the result of executing the Get
|
| + // Supported Configuration algorithm on implementation, candidate
|
| + // configuration, and origin.
|
| + // 7.3.3. If supported configuration is not null, [initialize and return a
|
| + // new MediaKeySystemAccess object.]
|
| blink::WebMediaKeySystemConfiguration accumulated_configuration;
|
| - if (GetSupportedConfiguration(key_system, candidate,
|
| + if (GetSupportedConfiguration(key_system, candidate_configuration,
|
| request.securityOrigin(),
|
| &accumulated_configuration)) {
|
| reporter->ReportSupported();
|
| @@ -262,7 +416,8 @@ void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
|
| }
|
| }
|
|
|
| - // 7.4 Reject promise with a new DOMException whose name is NotSupportedError.
|
| + // 7.4. Reject promise with a new DOMException whose name is
|
| + // NotSupportedError.
|
| request.requestNotSupported(
|
| "None of the requested configurations were supported.");
|
| }
|
|
|