1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "webencryptedmediaclient_impl.h"
8 #include "base/logging.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "media/base/key_systems.h"
13 #include "media/base/media_permission.h"
14 #include "media/blink/webcontentdecryptionmodule_impl.h"
15 #include "media/blink/webcontentdecryptionmoduleaccess_impl.h"
16 #include "net/base/mime_util.h"
17 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h"
18 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
19 #include "third_party/WebKit/public/platform/WebString.h"
20 #include "third_party/WebKit/public/platform/WebVector.h"
24 // These names are used by UMA.
25 const char kKeySystemSupportUMAPrefix
[] =
26 "Media.EME.RequestMediaKeySystemAccess.";
28 enum ConfigurationSupport
{
29 CONFIGURATION_NOT_SUPPORTED
,
30 CONFIGURATION_REQUIRES_PERMISSION
,
31 CONFIGURATION_SUPPORTED
,
34 // Accumulates configuration rules to determine if a feature (additional
35 // configuration rule) can be added to an accumulated configuration.
38 ConfigState(bool was_permission_requested
, bool is_permission_granted
)
39 : was_permission_requested_(was_permission_requested
),
40 is_permission_granted_(is_permission_granted
),
41 is_identifier_required_(false),
42 is_identifier_recommended_(false){
45 bool IsPermissionGranted() const {
46 return is_permission_granted_
;
49 // Permission is possible if it has not been denied.
50 bool IsPermissionPossible() const {
51 return is_permission_granted_
|| !was_permission_requested_
;
54 bool IsIdentifierRequired() const {
55 return is_identifier_required_
;
58 bool IsIdentifierRecommended() const {
59 return is_identifier_recommended_
;
62 // Checks whether a rule is compatible with all previously added rules.
63 bool IsRuleSupported(EmeConfigRule rule
) const {
65 case EmeConfigRule::NOT_SUPPORTED
:
67 case EmeConfigRule::IDENTIFIER_REQUIRED
:
68 return IsPermissionPossible();
69 case EmeConfigRule::IDENTIFIER_RECOMMENDED
:
71 case EmeConfigRule::SUPPORTED
:
78 // Checks whether a rule is compatible with all previously added rules, and
79 // can be accepted without needing to add it to the configuration state. This
80 // allows considering more rules after the configuration state is final (that
81 // is, after distinctiveIdentifier has been resolved).
82 bool IsRuleSupportedWithCurrentState(EmeConfigRule rule
) const {
84 case EmeConfigRule::NOT_SUPPORTED
:
86 case EmeConfigRule::IDENTIFIER_REQUIRED
:
87 return is_permission_granted_
;
88 case EmeConfigRule::IDENTIFIER_RECOMMENDED
:
90 case EmeConfigRule::SUPPORTED
:
97 // Add a rule to the accumulated configuration state.
98 void AddRule(EmeConfigRule rule
) {
100 case EmeConfigRule::NOT_SUPPORTED
:
102 case EmeConfigRule::IDENTIFIER_REQUIRED
:
103 is_identifier_required_
= true;
105 case EmeConfigRule::IDENTIFIER_RECOMMENDED
:
106 is_identifier_recommended_
= true;
108 case EmeConfigRule::SUPPORTED
:
115 // Whether permission to use a distinctive identifier was requested. If set,
116 // |is_permission_granted_| represents the final decision.
117 const bool was_permission_requested_
;
119 // Whether permission to use a distinctive identifier has been granted.
120 const bool is_permission_granted_
;
122 // Whether a rule has been added that requires a distinctive identifier.
123 bool is_identifier_required_
;
125 // Whether a rule has been added that recommends a distinctive identifier.
126 bool is_identifier_recommended_
;
129 static bool IsSupportedContentType(
130 const KeySystems
& key_systems
,
131 const std::string
& key_system
,
132 EmeMediaType media_type
,
133 const std::string
& container_mime_type
,
134 const std::string
& codecs
) {
135 // TODO(sandersd): Move contentType parsing from Blink to here so that invalid
136 // parameters can be rejected. http://crbug.com/417561
137 std::string container_lower
= base::StringToLowerASCII(container_mime_type
);
139 // Check that |container_mime_type| and |codecs| are supported by the CDM.
140 // This check does not handle extended codecs, so extended codec information
142 std::vector
<std::string
> codec_vector
;
143 net::ParseCodecString(codecs
, &codec_vector
, true);
144 if (!key_systems
.IsSupportedCodecCombination(
145 key_system
, media_type
, container_lower
, codec_vector
)) {
149 if (codec_vector
.empty())
152 // Check that |codecs| are supported by Chrome. This is done primarily to
153 // validate extended codecs, but it also ensures that the CDM cannot support
154 // codecs that Chrome does not (which could complicate the robustness
156 codec_vector
.clear();
157 net::ParseCodecString(codecs
, &codec_vector
, false);
158 return (net::IsSupportedStrictMediaMimeType(container_lower
, codec_vector
) ==
162 static bool GetSupportedCapabilities(
163 const KeySystems
& key_systems
,
164 const std::string
& key_system
,
165 EmeMediaType media_type
,
166 const blink::WebVector
<blink::WebMediaKeySystemMediaCapability
>&
167 requested_media_capabilities
,
168 ConfigState
* config_state
,
169 std::vector
<blink::WebMediaKeySystemMediaCapability
>*
170 supported_media_capabilities
) {
172 // https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-media-type
173 // 1. Let local accumulated capabilities be a local copy of partial
175 // (Skipped as we directly update |config_state|. This is safe because we
176 // only do so when at least one requested media capability is supported.)
177 // 2. Let supported media capabilities be empty.
178 DCHECK_EQ(supported_media_capabilities
->size(), 0ul);
179 // 3. For each value in requested media capabilities:
180 for (size_t i
= 0; i
< requested_media_capabilities
.size(); i
++) {
181 // 3.1. Let contentType be the value's contentType member.
182 // 3.2. Let robustness be the value's robustness member.
183 const blink::WebMediaKeySystemMediaCapability
& capability
=
184 requested_media_capabilities
[i
];
185 // 3.3. If contentType is the empty string, return null.
186 if (capability
.mimeType
.isEmpty()) {
187 DVLOG(2) << "Rejecting requested configuration because "
188 << "a capability contentType was empty.";
191 // 3.4-3.11. (Implemented by IsSupportedContentType().)
192 if (!base::IsStringASCII(capability
.mimeType
) ||
193 !base::IsStringASCII(capability
.codecs
) ||
194 !IsSupportedContentType(key_systems
, key_system
, media_type
,
195 base::UTF16ToASCII(capability
.mimeType
),
196 base::UTF16ToASCII(capability
.codecs
))) {
199 // 3.12. If robustness is not the empty string, run the following steps:
200 if (!capability
.robustness
.isEmpty()) {
201 // 3.12.1. If robustness is an unrecognized value or not supported by
202 // implementation, continue to the next iteration. String
203 // comparison is case-sensitive.
204 if (!base::IsStringASCII(capability
.robustness
))
206 EmeConfigRule robustness_rule
= key_systems
.GetRobustnessConfigRule(
207 key_system
, media_type
, base::UTF16ToASCII(capability
.robustness
));
208 if (!config_state
->IsRuleSupported(robustness_rule
))
210 config_state
->AddRule(robustness_rule
);
211 // 3.12.2. Add robustness to configuration.
212 // (It's already added, we use capability as configuration.)
214 // 3.13. If the user agent and implementation do not support playback of
215 // encrypted media data as specified by configuration, including all
216 // media types, in combination with local accumulated capabilities,
217 // continue to the next iteration.
218 // (This is handled when adding rules to |config_state|.)
219 // 3.14. Add configuration to supported media capabilities.
220 supported_media_capabilities
->push_back(capability
);
221 // 3.15. Add configuration to local accumulated capabilities.
222 // (Skipped as we directly update |config_state|.)
224 // 4. If supported media capabilities is empty, return null.
225 if (supported_media_capabilities
->empty()) {
226 DVLOG(2) << "Rejecting requested configuration because "
227 << "no capabilities were supported.";
230 // 5. Return media type capabilities.
234 static EmeFeatureRequirement
ConvertRequirement(
235 blink::WebMediaKeySystemConfiguration::Requirement requirement
) {
236 switch (requirement
) {
237 case blink::WebMediaKeySystemConfiguration::Requirement::Required
:
238 return EME_FEATURE_REQUIRED
;
239 case blink::WebMediaKeySystemConfiguration::Requirement::Optional
:
240 return EME_FEATURE_OPTIONAL
;
241 case blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
:
242 return EME_FEATURE_NOT_ALLOWED
;
246 return EME_FEATURE_NOT_ALLOWED
;
249 static ConfigurationSupport
GetSupportedConfiguration(
250 const KeySystems
& key_systems
,
251 const std::string
& key_system
,
252 const blink::WebMediaKeySystemConfiguration
& candidate
,
253 bool was_permission_requested
,
254 bool is_permission_granted
,
255 blink::WebMediaKeySystemConfiguration
* accumulated_configuration
) {
256 ConfigState
config_state(was_permission_requested
, is_permission_granted
);
258 // From https://w3c.github.io/encrypted-media/#get-supported-configuration
259 // 1. Let accumulated configuration be empty. (Done by caller.)
260 // 2. If candidate configuration's initDataTypes attribute is not empty, run
261 // the following steps:
262 if (!candidate
.initDataTypes
.isEmpty()) {
263 // 2.1. Let supported types be empty.
264 std::vector
<blink::WebEncryptedMediaInitDataType
> supported_types
;
266 // 2.2. For each value in candidate configuration's initDataTypes attribute:
267 for (size_t i
= 0; i
< candidate
.initDataTypes
.size(); i
++) {
268 // 2.2.1. Let initDataType be the value.
269 blink::WebEncryptedMediaInitDataType init_data_type
=
270 candidate
.initDataTypes
[i
];
271 // 2.2.2. If initDataType is the empty string, return null.
272 if (init_data_type
== blink::WebEncryptedMediaInitDataType::Unknown
)
274 // 2.2.3. If the implementation supports generating requests based on
275 // initDataType, add initDataType to supported types. String
276 // comparison is case-sensitive.
277 // TODO(jrummell): |init_data_type| should be an enum all the way through
278 // Chromium. http://crbug.com/417440
279 std::string init_data_type_as_ascii
= "unknown";
280 switch (init_data_type
) {
281 case blink::WebEncryptedMediaInitDataType::Cenc
:
282 init_data_type_as_ascii
= "cenc";
284 case blink::WebEncryptedMediaInitDataType::Keyids
:
285 init_data_type_as_ascii
= "keyids";
287 case blink::WebEncryptedMediaInitDataType::Webm
:
288 init_data_type_as_ascii
= "webm";
290 case blink::WebEncryptedMediaInitDataType::Unknown
:
294 if (IsSupportedKeySystemWithInitDataType(key_system
,
295 init_data_type_as_ascii
)) {
296 supported_types
.push_back(init_data_type
);
300 // 2.3. If supported types is empty, return null.
301 if (supported_types
.empty()) {
302 DVLOG(2) << "Rejecting requested configuration because "
303 << "no initDataType values were supported.";
304 return CONFIGURATION_NOT_SUPPORTED
;
307 // 2.4. Add supported types to accumulated configuration.
308 accumulated_configuration
->initDataTypes
= supported_types
;
311 // 3. Follow the steps for the value of candidate configuration's
312 // distinctiveIdentifier attribute from the following list:
313 // - "required": If the implementation does not support a persistent
314 // Distinctive Identifier in combination with accumulated configuration,
316 // - "optional": Continue.
317 // - "not-allowed": If the implementation requires a Distinctive
318 // Identifier in combination with accumulated configuration, return
320 // We also reject OPTIONAL when distinctive identifiers are ALWAYS_ENABLED and
321 // permission has already been denied. This would happen anyway at step 11.
322 EmeConfigRule di_rule
= key_systems
.GetDistinctiveIdentifierConfigRule(
323 key_system
, ConvertRequirement(candidate
.distinctiveIdentifier
));
324 if (!config_state
.IsRuleSupported(di_rule
)) {
325 DVLOG(2) << "Rejecting requested configuration because "
326 << "the distinctiveIdentifier requirement was not supported.";
327 return CONFIGURATION_NOT_SUPPORTED
;
329 config_state
.AddRule(di_rule
);
331 // 4. Add the value of the candidate configuration's distinctiveIdentifier
332 // attribute to accumulated configuration.
333 accumulated_configuration
->distinctiveIdentifier
=
334 candidate
.distinctiveIdentifier
;
336 // 5. Follow the steps for the value of candidate configuration's
337 // persistentState attribute from the following list:
338 // - "required": If the implementation does not support persisting state
339 // in combination with accumulated configuration, return null.
340 // - "optional": Continue.
341 // - "not-allowed": If the implementation requires persisting state in
342 // combination with accumulated configuration, return null.
343 EmeConfigRule ps_rule
= key_systems
.GetPersistentStateConfigRule(
344 key_system
, ConvertRequirement(candidate
.persistentState
));
345 if (!config_state
.IsRuleSupported(ps_rule
)) {
346 DVLOG(2) << "Rejecting requested configuration because "
347 << "the persistentState requirement was not supported.";
348 return CONFIGURATION_NOT_SUPPORTED
;
350 config_state
.AddRule(ps_rule
);
352 // 6. Add the value of the candidate configuration's persistentState
353 // attribute to accumulated configuration.
354 accumulated_configuration
->persistentState
= candidate
.persistentState
;
356 // 7. If candidate configuration's videoCapabilities attribute is not empty,
357 // run the following steps:
358 if (!candidate
.videoCapabilities
.isEmpty()) {
359 // 7.1. Let video capabilities be the result of executing the Get Supported
360 // Capabilities for Media Type algorithm on Video, candidate
361 // configuration's videoCapabilities attribute, and accumulated
363 // 7.2. If video capabilities is null, return null.
364 std::vector
<blink::WebMediaKeySystemMediaCapability
> video_capabilities
;
365 if (!GetSupportedCapabilities(key_systems
, key_system
, EmeMediaType::VIDEO
,
366 candidate
.videoCapabilities
,
367 &config_state
, &video_capabilities
)) {
368 return CONFIGURATION_NOT_SUPPORTED
;
371 // 7.3. Add video capabilities to accumulated configuration.
372 accumulated_configuration
->videoCapabilities
= video_capabilities
;
375 // 8. If candidate configuration's audioCapabilities attribute is not empty,
376 // run the following steps:
377 if (!candidate
.audioCapabilities
.isEmpty()) {
378 // 8.1. Let audio capabilities be the result of executing the Get Supported
379 // Capabilities for Media Type algorithm on Audio, candidate
380 // configuration's audioCapabilities attribute, and accumulated
382 // 8.2. If audio capabilities is null, return null.
383 std::vector
<blink::WebMediaKeySystemMediaCapability
> audio_capabilities
;
384 if (!GetSupportedCapabilities(key_systems
, key_system
, EmeMediaType::AUDIO
,
385 candidate
.audioCapabilities
,
386 &config_state
, &audio_capabilities
)) {
387 return CONFIGURATION_NOT_SUPPORTED
;
390 // 8.3. Add audio capabilities to accumulated configuration.
391 accumulated_configuration
->audioCapabilities
= audio_capabilities
;
394 // 9. If accumulated configuration's distinctiveIdentifier value is
395 // "optional", follow the steps for the first matching condition from the
397 // - If the implementation requires a Distinctive Identifier for any of
398 // the combinations in accumulated configuration, change accumulated
399 // configuration's distinctiveIdentifier value to "required".
400 // - Otherwise, change accumulated configuration's distinctiveIdentifier
401 // value to "not-allowed".
402 if (accumulated_configuration
->distinctiveIdentifier
==
403 blink::WebMediaKeySystemConfiguration::Requirement::Optional
) {
404 EmeConfigRule not_allowed_rule
=
405 key_systems
.GetDistinctiveIdentifierConfigRule(
406 key_system
, EME_FEATURE_NOT_ALLOWED
);
407 EmeConfigRule required_rule
=
408 key_systems
.GetDistinctiveIdentifierConfigRule(
409 key_system
, EME_FEATURE_REQUIRED
);
410 bool not_allowed_supported
= config_state
.IsRuleSupported(not_allowed_rule
);
411 bool required_supported
= config_state
.IsRuleSupported(required_rule
);
412 if (not_allowed_supported
) {
413 bool prefer_required
= config_state
.IsIdentifierRequired() ||
414 (config_state
.IsIdentifierRecommended() &&
415 config_state
.IsPermissionPossible());
416 if (required_supported
&& prefer_required
) {
417 accumulated_configuration
->distinctiveIdentifier
=
418 blink::WebMediaKeySystemConfiguration::Requirement::Required
;
419 config_state
.AddRule(required_rule
);
420 DCHECK(config_state
.IsIdentifierRequired());
422 accumulated_configuration
->distinctiveIdentifier
=
423 blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
;
424 config_state
.AddRule(not_allowed_rule
);
426 } else if (required_supported
) {
427 accumulated_configuration
->distinctiveIdentifier
=
428 blink::WebMediaKeySystemConfiguration::Requirement::Required
;
429 config_state
.AddRule(required_rule
);
431 // We should not have passed step 3.
433 return CONFIGURATION_NOT_SUPPORTED
;
437 // If permission is required but we couldn't enable it, reject the
439 if (config_state
.IsIdentifierRequired() &&
440 accumulated_configuration
->distinctiveIdentifier
!=
441 blink::WebMediaKeySystemConfiguration::Requirement::Required
) {
442 DVLOG(2) << "Rejecting requested configuration because "
443 << "distinctiveIdentifier was implicitly required but "
445 return CONFIGURATION_NOT_SUPPORTED
;
448 // 10. If accumulated configuration's persistentState value is "optional",
449 // follow the steps for the first matching condition from the following
451 // - If the implementation requires persisting state for any of the
452 // combinations in accumulated configuration, change accumulated
453 // configuration's persistentState value to "required".
454 // - Otherwise, change accumulated configuration's persistentState value
456 if (accumulated_configuration
->persistentState
==
457 blink::WebMediaKeySystemConfiguration::Requirement::Optional
) {
458 EmeConfigRule not_allowed_rule
=
459 key_systems
.GetPersistentStateConfigRule(
460 key_system
, EME_FEATURE_NOT_ALLOWED
);
461 EmeConfigRule required_rule
=
462 key_systems
.GetPersistentStateConfigRule(
463 key_system
, EME_FEATURE_REQUIRED
);
464 // Now that distinctiveIdentifier has been resolved, it is too late to allow
465 // persistentState to affect the configuration.
466 bool not_allowed_supported
=
467 config_state
.IsRuleSupportedWithCurrentState(not_allowed_rule
);
468 bool required_supported
=
469 config_state
.IsRuleSupportedWithCurrentState(required_rule
);
470 if (not_allowed_supported
) {
471 accumulated_configuration
->persistentState
=
472 blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
;
473 } else if (required_supported
) {
474 accumulated_configuration
->persistentState
=
475 blink::WebMediaKeySystemConfiguration::Requirement::Required
;
477 // We should not have passed step 5.
479 return CONFIGURATION_NOT_SUPPORTED
;
483 // 11. If implementation in the configuration specified by the combination of
484 // the values in accumulated configuration is not supported or not allowed
485 // in the origin, return null.
486 // 12. If accumulated configuration's distinctiveIdentifier value is
487 // "required", [prompt the user for consent].
488 if (accumulated_configuration
->distinctiveIdentifier
==
489 blink::WebMediaKeySystemConfiguration::Requirement::Required
) {
490 // The caller is responsible for resolving what to do if permission is
491 // required but has been denied (it should treat it as NOT_SUPPORTED).
492 if (!config_state
.IsPermissionGranted())
493 return CONFIGURATION_REQUIRES_PERMISSION
;
496 // 13. Return accumulated configuration.
498 // We also record the available session types so that createSession() can be
500 std::vector
<blink::WebEncryptedMediaSessionType
> session_types
;
501 session_types
.push_back(blink::WebEncryptedMediaSessionType::Temporary
);
502 if (accumulated_configuration
->persistentState
==
503 blink::WebMediaKeySystemConfiguration::Requirement::Required
) {
504 if (config_state
.IsRuleSupportedWithCurrentState(
505 key_systems
.GetPersistentLicenseSessionConfigRule(key_system
))) {
506 session_types
.push_back(
507 blink::WebEncryptedMediaSessionType::PersistentLicense
);
509 if (config_state
.IsRuleSupportedWithCurrentState(
510 key_systems
.GetPersistentReleaseMessageSessionConfigRule(
512 session_types
.push_back(
513 blink::WebEncryptedMediaSessionType::PersistentReleaseMessage
);
516 accumulated_configuration
->sessionTypes
= session_types
;
518 return CONFIGURATION_SUPPORTED
;
521 // Report usage of key system to UMA. There are 2 different counts logged:
522 // 1. The key system is requested.
523 // 2. The requested key system and options are supported.
524 // Each stat is only reported once per renderer frame per key system.
525 // Note that WebEncryptedMediaClientImpl is only created once by each
527 class WebEncryptedMediaClientImpl::Reporter
{
529 enum KeySystemSupportStatus
{
530 KEY_SYSTEM_REQUESTED
= 0,
531 KEY_SYSTEM_SUPPORTED
= 1,
532 KEY_SYSTEM_SUPPORT_STATUS_COUNT
535 explicit Reporter(const std::string
& key_system_for_uma
)
536 : uma_name_(kKeySystemSupportUMAPrefix
+ key_system_for_uma
),
537 is_request_reported_(false),
538 is_support_reported_(false) {}
541 void ReportRequested() {
542 if (is_request_reported_
)
544 Report(KEY_SYSTEM_REQUESTED
);
545 is_request_reported_
= true;
548 void ReportSupported() {
549 DCHECK(is_request_reported_
);
550 if (is_support_reported_
)
552 Report(KEY_SYSTEM_SUPPORTED
);
553 is_support_reported_
= true;
557 void Report(KeySystemSupportStatus status
) {
558 // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros
559 // require the names to be constant throughout the process' lifetime.
560 base::LinearHistogram::FactoryGet(
561 uma_name_
, 1, KEY_SYSTEM_SUPPORT_STATUS_COUNT
,
562 KEY_SYSTEM_SUPPORT_STATUS_COUNT
+ 1,
563 base::Histogram::kUmaTargetedHistogramFlag
)->Add(status
);
566 const std::string uma_name_
;
567 bool is_request_reported_
;
568 bool is_support_reported_
;
571 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(
572 scoped_ptr
<CdmFactory
> cdm_factory
,
573 MediaPermission
* media_permission
)
574 : key_systems_(KeySystems::GetInstance()),
575 cdm_factory_(cdm_factory
.Pass()),
576 media_permission_(media_permission
),
577 weak_factory_(this) {
578 DCHECK(media_permission
);
581 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() {
584 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
585 blink::WebEncryptedMediaRequest request
) {
586 // TODO(jrummell): This should be asynchronous, ideally not on the main
589 // Continued from requestMediaKeySystemAccess(), step 7, from
590 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
592 // 7.1. If keySystem is not one of the Key Systems supported by the user
593 // agent, reject promise with with a new DOMException whose name is
594 // NotSupportedError. String comparison is case-sensitive.
595 if (!base::IsStringASCII(request
.keySystem())) {
596 request
.requestNotSupported("Only ASCII keySystems are supported");
600 // Report this request to the UMA.
601 std::string key_system
= base::UTF16ToASCII(request
.keySystem());
602 GetReporter(key_system
)->ReportRequested();
604 if (!key_systems_
.IsSupportedKeySystem(key_system
)) {
605 request
.requestNotSupported("Unsupported keySystem");
609 // 7.2-7.4. Implemented by SelectSupportedConfiguration().
610 SelectSupportedConfiguration(request
, false, false);
613 void WebEncryptedMediaClientImpl::SelectSupportedConfiguration(
614 blink::WebEncryptedMediaRequest request
,
615 bool was_permission_requested
,
616 bool is_permission_granted
) {
617 // Continued from requestMediaKeySystemAccess(), step 7.1, from
618 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
620 // 7.2. Let implementation be the implementation of keySystem.
621 std::string key_system
= base::UTF16ToASCII(request
.keySystem());
623 // 7.3. For each value in supportedConfigurations:
624 const blink::WebVector
<blink::WebMediaKeySystemConfiguration
>&
625 configurations
= request
.supportedConfigurations();
626 for (size_t i
= 0; i
< configurations
.size(); i
++) {
627 // 7.3.1. Let candidate configuration be the value.
628 const blink::WebMediaKeySystemConfiguration
& candidate_configuration
=
630 // 7.3.2. Let supported configuration be the result of executing the Get
631 // Supported Configuration algorithm on implementation, candidate
632 // configuration, and origin.
633 // 7.3.3. If supported configuration is not null, [initialize and return a
634 // new MediaKeySystemAccess object.]
635 blink::WebMediaKeySystemConfiguration accumulated_configuration
;
636 ConfigurationSupport supported
= GetSupportedConfiguration(
637 key_systems_
, key_system
, candidate_configuration
,
638 was_permission_requested
, is_permission_granted
,
639 &accumulated_configuration
);
641 case CONFIGURATION_NOT_SUPPORTED
:
643 case CONFIGURATION_REQUIRES_PERMISSION
:
644 if (was_permission_requested
) {
645 DVLOG(2) << "Rejecting requested configuration because "
646 << "permission was denied.";
649 media_permission_
->RequestPermission(
650 MediaPermission::PROTECTED_MEDIA_IDENTIFIER
,
651 GURL(request
.securityOrigin().toString()),
652 // Try again with |was_permission_requested| true and
653 // |is_permission_granted| the value of the permission.
655 &WebEncryptedMediaClientImpl::SelectSupportedConfiguration
,
656 weak_factory_
.GetWeakPtr(), request
, true));
658 case CONFIGURATION_SUPPORTED
:
659 // Report that this request succeeded to the UMA.
660 GetReporter(key_system
)->ReportSupported();
661 request
.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
662 request
.keySystem(), accumulated_configuration
,
663 request
.securityOrigin(), weak_factory_
.GetWeakPtr()));
668 // 7.4. Reject promise with a new DOMException whose name is
669 // NotSupportedError.
670 request
.requestNotSupported(
671 "None of the requested configurations were supported.");
674 void WebEncryptedMediaClientImpl::CreateCdm(
675 const blink::WebString
& key_system
,
676 bool allow_distinctive_identifier
,
677 bool allow_persistent_state
,
678 const blink::WebSecurityOrigin
& security_origin
,
679 blink::WebContentDecryptionModuleResult result
) {
680 WebContentDecryptionModuleImpl::Create(cdm_factory_
.get(), key_system
,
681 allow_distinctive_identifier
,
682 allow_persistent_state
,
683 security_origin
, result
);
686 // Lazily create Reporters.
687 WebEncryptedMediaClientImpl::Reporter
* WebEncryptedMediaClientImpl::GetReporter(
688 const std::string
& key_system
) {
689 std::string uma_name
= GetKeySystemNameForUMA(key_system
);
690 Reporter
* reporter
= reporters_
.get(uma_name
);
691 if (reporter
!= nullptr)
694 // Reporter not found, so create one.
696 reporters_
.add(uma_name
, make_scoped_ptr(new Reporter(uma_name
)));
697 DCHECK(result
.second
);
698 return result
.first
->second
;