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 "media/blink/webmediaplayer_util.h"
17 #include "net/base/mime_util.h"
18 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h"
19 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
21 #include "third_party/WebKit/public/platform/WebVector.h"
25 // These names are used by UMA.
26 const char kKeySystemSupportUMAPrefix
[] =
27 "Media.EME.RequestMediaKeySystemAccess.";
29 enum ConfigurationSupport
{
30 CONFIGURATION_NOT_SUPPORTED
,
31 CONFIGURATION_REQUIRES_PERMISSION
,
32 CONFIGURATION_SUPPORTED
,
35 // Accumulates configuration rules to determine if a feature (additional
36 // configuration rule) can be added to an accumulated configuration.
39 ConfigState(bool was_permission_requested
, bool is_permission_granted
)
40 : was_permission_requested_(was_permission_requested
),
41 is_permission_granted_(is_permission_granted
) {
44 bool IsPermissionGranted() const {
45 return is_permission_granted_
;
48 // Permission is possible if it has not been denied.
49 bool IsPermissionPossible() const {
50 return is_permission_granted_
|| !was_permission_requested_
;
53 bool IsIdentifierRequired() const {
54 return is_identifier_required_
;
57 bool IsIdentifierRecommended() const {
58 return is_identifier_recommended_
;
61 // Checks whether a rule is compatible with all previously added rules.
62 bool IsRuleSupported(EmeConfigRule rule
) const {
64 case EmeConfigRule::NOT_SUPPORTED
:
66 case EmeConfigRule::IDENTIFIER_NOT_ALLOWED
:
67 return !is_identifier_required_
;
68 case EmeConfigRule::IDENTIFIER_REQUIRED
:
69 // TODO(sandersd): Confirm if we should be refusing these rules when
70 // permission has been denied (as the spec currently says).
71 return !is_identifier_not_allowed_
&& IsPermissionPossible();
72 case EmeConfigRule::IDENTIFIER_RECOMMENDED
:
74 case EmeConfigRule::PERSISTENCE_NOT_ALLOWED
:
75 return !is_persistence_required_
;
76 case EmeConfigRule::PERSISTENCE_REQUIRED
:
77 return !is_persistence_not_allowed_
;
78 case EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED
:
79 return (!is_identifier_not_allowed_
&& IsPermissionPossible() &&
80 !is_persistence_not_allowed_
);
81 case EmeConfigRule::SUPPORTED
:
88 // Add a rule to the accumulated configuration state.
89 void AddRule(EmeConfigRule rule
) {
90 DCHECK(IsRuleSupported(rule
));
92 case EmeConfigRule::NOT_SUPPORTED
:
94 case EmeConfigRule::IDENTIFIER_NOT_ALLOWED
:
95 is_identifier_not_allowed_
= true;
97 case EmeConfigRule::IDENTIFIER_REQUIRED
:
98 is_identifier_required_
= true;
100 case EmeConfigRule::IDENTIFIER_RECOMMENDED
:
101 is_identifier_recommended_
= true;
103 case EmeConfigRule::PERSISTENCE_NOT_ALLOWED
:
104 is_persistence_not_allowed_
= true;
106 case EmeConfigRule::PERSISTENCE_REQUIRED
:
107 is_persistence_required_
= true;
109 case EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED
:
110 is_identifier_required_
= true;
111 is_persistence_required_
= true;
113 case EmeConfigRule::SUPPORTED
:
120 // Whether permission to use a distinctive identifier was requested. If set,
121 // |is_permission_granted_| represents the final decision.
122 const bool was_permission_requested_
;
124 // Whether permission to use a distinctive identifier has been granted.
125 const bool is_permission_granted_
;
127 // Whether a rule has been added that requires or blocks a distinctive
129 bool is_identifier_required_
= false;
130 bool is_identifier_not_allowed_
= false;
132 // Whether a rule has been added that recommends a distinctive identifier.
133 bool is_identifier_recommended_
= false;
135 // Whether a rule has been added that requires or blocks persistent state.
136 bool is_persistence_required_
= false;
137 bool is_persistence_not_allowed_
= false;
140 static bool IsSupportedContentType(
141 const KeySystems
& key_systems
,
142 const std::string
& key_system
,
143 EmeMediaType media_type
,
144 const std::string
& container_mime_type
,
145 const std::string
& codecs
) {
146 // TODO(sandersd): Move contentType parsing from Blink to here so that invalid
147 // parameters can be rejected. http://crbug.com/417561
148 std::string container_lower
= base::StringToLowerASCII(container_mime_type
);
150 // Check that |container_mime_type| and |codecs| are supported by the CDM.
151 // This check does not handle extended codecs, so extended codec information
153 std::vector
<std::string
> codec_vector
;
154 net::ParseCodecString(codecs
, &codec_vector
, true);
155 if (!key_systems
.IsSupportedCodecCombination(
156 key_system
, media_type
, container_lower
, codec_vector
)) {
160 // Check that |container_mime_type| is supported by Chrome. This can only
161 // happen if the CDM declares support for a container that Chrome does not.
162 if (!net::IsSupportedMediaMimeType(container_lower
)) {
167 // Check that |codecs| are supported by Chrome. This is done primarily to
168 // validate extended codecs, but it also ensures that the CDM cannot support
169 // codecs that Chrome does not (which could complicate the robustness
171 if (codec_vector
.empty())
173 codec_vector
.clear();
174 net::ParseCodecString(codecs
, &codec_vector
, false);
175 return (net::IsSupportedStrictMediaMimeType(container_lower
, codec_vector
) ==
179 static bool GetSupportedCapabilities(
180 const KeySystems
& key_systems
,
181 const std::string
& key_system
,
182 EmeMediaType media_type
,
183 const blink::WebVector
<blink::WebMediaKeySystemMediaCapability
>&
184 requested_media_capabilities
,
185 ConfigState
* config_state
,
186 std::vector
<blink::WebMediaKeySystemMediaCapability
>*
187 supported_media_capabilities
) {
189 // https://w3c.github.io/encrypted-media/#get-supported-capabilities-for-media-type
190 // 1. Let local accumulated capabilities be a local copy of partial
192 // (Skipped as we directly update |config_state|. This is safe because we
193 // only do so when at least one requested media capability is supported.)
194 // 2. Let supported media capabilities be empty.
195 DCHECK_EQ(supported_media_capabilities
->size(), 0ul);
196 // 3. For each value in requested media capabilities:
197 for (size_t i
= 0; i
< requested_media_capabilities
.size(); i
++) {
198 // 3.1. Let contentType be the value's contentType member.
199 // 3.2. Let robustness be the value's robustness member.
200 const blink::WebMediaKeySystemMediaCapability
& capability
=
201 requested_media_capabilities
[i
];
202 // 3.3. If contentType is the empty string, return null.
203 if (capability
.mimeType
.isEmpty()) {
204 DVLOG(2) << "Rejecting requested configuration because "
205 << "a capability contentType was empty.";
208 // 3.4-3.11. (Implemented by IsSupportedContentType().)
209 if (!base::IsStringASCII(capability
.mimeType
) ||
210 !base::IsStringASCII(capability
.codecs
) ||
211 !IsSupportedContentType(key_systems
, key_system
, media_type
,
212 base::UTF16ToASCII(capability
.mimeType
),
213 base::UTF16ToASCII(capability
.codecs
))) {
216 // 3.12. If robustness is not the empty string, run the following steps:
217 if (!capability
.robustness
.isEmpty()) {
218 // 3.12.1. If robustness is an unrecognized value or not supported by
219 // implementation, continue to the next iteration. String
220 // comparison is case-sensitive.
221 if (!base::IsStringASCII(capability
.robustness
))
223 EmeConfigRule robustness_rule
= key_systems
.GetRobustnessConfigRule(
224 key_system
, media_type
, base::UTF16ToASCII(capability
.robustness
));
225 if (!config_state
->IsRuleSupported(robustness_rule
))
227 config_state
->AddRule(robustness_rule
);
228 // 3.12.2. Add robustness to configuration.
229 // (It's already added, we use capability as configuration.)
231 // 3.13. If the user agent and implementation do not support playback of
232 // encrypted media data as specified by configuration, including all
233 // media types, in combination with local accumulated capabilities,
234 // continue to the next iteration.
235 // (This is handled when adding rules to |config_state|.)
236 // 3.14. Add configuration to supported media capabilities.
237 supported_media_capabilities
->push_back(capability
);
238 // 3.15. Add configuration to local accumulated capabilities.
239 // (Skipped as we directly update |config_state|.)
241 // 4. If supported media capabilities is empty, return null.
242 if (supported_media_capabilities
->empty()) {
243 DVLOG(2) << "Rejecting requested configuration because "
244 << "no capabilities were supported.";
247 // 5. Return media type capabilities.
251 static EmeFeatureRequirement
ConvertRequirement(
252 blink::WebMediaKeySystemConfiguration::Requirement requirement
) {
253 switch (requirement
) {
254 case blink::WebMediaKeySystemConfiguration::Requirement::Required
:
255 return EME_FEATURE_REQUIRED
;
256 case blink::WebMediaKeySystemConfiguration::Requirement::Optional
:
257 return EME_FEATURE_OPTIONAL
;
258 case blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
:
259 return EME_FEATURE_NOT_ALLOWED
;
263 return EME_FEATURE_NOT_ALLOWED
;
266 static ConfigurationSupport
GetSupportedConfiguration(
267 const KeySystems
& key_systems
,
268 const std::string
& key_system
,
269 const blink::WebMediaKeySystemConfiguration
& candidate
,
270 bool was_permission_requested
,
271 bool is_permission_granted
,
272 blink::WebMediaKeySystemConfiguration
* accumulated_configuration
) {
273 ConfigState
config_state(was_permission_requested
, is_permission_granted
);
275 // From https://w3c.github.io/encrypted-media/#get-supported-configuration
276 // 1. Let accumulated configuration be empty. (Done by caller.)
277 // 2. If the initDataTypes member is present in candidate configuration, run
278 // the following steps:
279 if (candidate
.hasInitDataTypes
) {
280 // 2.1. Let supported types be empty.
281 std::vector
<blink::WebEncryptedMediaInitDataType
> supported_types
;
283 // 2.2. For each value in candidate configuration's initDataTypes member:
284 for (size_t i
= 0; i
< candidate
.initDataTypes
.size(); i
++) {
285 // 2.2.1. Let initDataType be the value.
286 blink::WebEncryptedMediaInitDataType init_data_type
=
287 candidate
.initDataTypes
[i
];
288 // 2.2.2. If the implementation supports generating requests based on
289 // initDataType, add initDataType to supported types. String
290 // comparison is case-sensitive. The empty string is never
292 if (init_data_type
== blink::WebEncryptedMediaInitDataType::Unknown
)
294 if (key_systems
.IsSupportedInitDataType(
295 key_system
, ConvertToEmeInitDataType(init_data_type
))) {
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 member from the following list:
313 // - "required": If the implementation does not support a persistent
314 // Distinctive Identifier in combination with accumulated
315 // configuration, return null.
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 // member to accumulated configuration.
333 accumulated_configuration
->distinctiveIdentifier
=
334 candidate
.distinctiveIdentifier
;
336 // 5. Follow the steps for the value of candidate configuration's
337 // persistentState member 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 // member to accumulated configuration.
354 accumulated_configuration
->persistentState
= candidate
.persistentState
;
356 // 7. Follow the steps for the first matching condition from the following
358 // - If the sessionTypes member is present in candidate configuration,
359 // let session types be candidate configuration's sessionTypes member.
360 // - Otherwise, let session types be [ "temporary" ].
361 blink::WebVector
<blink::WebEncryptedMediaSessionType
> session_types
;
362 if (candidate
.hasSessionTypes
) {
363 session_types
= candidate
.sessionTypes
;
365 std::vector
<blink::WebEncryptedMediaSessionType
> temporary(1);
366 temporary
[0] = blink::WebEncryptedMediaSessionType::Temporary
;
367 session_types
= temporary
;
370 // 8. For each value in session types:
371 for (size_t i
= 0; i
< session_types
.size(); i
++) {
372 // 8.1. Let session type be the value.
373 blink::WebEncryptedMediaSessionType session_type
= session_types
[i
];
374 // 8.2. If the implementation does not support session type in combination
375 // with accumulated configuration, return null.
376 // 8.3. If session type is "persistent-license" or
377 // "persistent-release-message", follow the steps for accumulated
378 // configuration's persistentState value from the following list:
379 // - "required": Continue.
380 // - "optional": Change accumulated configuration's persistentState
381 // value to "required".
382 // - "not-allowed": Return null.
383 EmeConfigRule session_type_rule
= EmeConfigRule::NOT_SUPPORTED
;
384 switch (session_type
) {
385 case blink::WebEncryptedMediaSessionType::Unknown
:
386 DVLOG(2) << "Rejecting requested configuration because "
387 << "a required session type was not recognized.";
388 return CONFIGURATION_NOT_SUPPORTED
;
389 case blink::WebEncryptedMediaSessionType::Temporary
:
390 session_type_rule
= EmeConfigRule::SUPPORTED
;
392 case blink::WebEncryptedMediaSessionType::PersistentLicense
:
394 key_systems
.GetPersistentLicenseSessionConfigRule(key_system
);
396 case blink::WebEncryptedMediaSessionType::PersistentReleaseMessage
:
398 key_systems
.GetPersistentReleaseMessageSessionConfigRule(
402 if (!config_state
.IsRuleSupported(session_type_rule
)) {
403 DVLOG(2) << "Rejecting requested configuration because "
404 << "a required session type was not supported.";
405 return CONFIGURATION_NOT_SUPPORTED
;
407 config_state
.AddRule(session_type_rule
);
410 // 9. Add session types to accumulated configuration.
411 accumulated_configuration
->sessionTypes
= session_types
;
413 // 10. If the videoCapabilities member is present in candidate configuration:
414 if (candidate
.hasVideoCapabilities
) {
415 // 10.1. Let video capabilities be the result of executing the Get Supported
416 // Capabilities for Media Type algorithm on Video, candidate
417 // configuration's videoCapabilities member, and accumulated
419 // 10.2. If video capabilities is null, return null.
420 std::vector
<blink::WebMediaKeySystemMediaCapability
> video_capabilities
;
421 if (!GetSupportedCapabilities(key_systems
, key_system
, EmeMediaType::VIDEO
,
422 candidate
.videoCapabilities
,
423 &config_state
, &video_capabilities
)) {
424 return CONFIGURATION_NOT_SUPPORTED
;
427 // 10.3. Add video capabilities to accumulated configuration.
428 accumulated_configuration
->videoCapabilities
= video_capabilities
;
431 // 11. If the audioCapabilities member is present in candidate configuration:
432 if (candidate
.hasAudioCapabilities
) {
433 // 11.1. Let audio capabilities be the result of executing the Get Supported
434 // Capabilities for Media Type algorithm on Audio, candidate
435 // configuration's audioCapabilities member, and accumulated
437 // 11.2. If audio capabilities is null, return null.
438 std::vector
<blink::WebMediaKeySystemMediaCapability
> audio_capabilities
;
439 if (!GetSupportedCapabilities(key_systems
, key_system
, EmeMediaType::AUDIO
,
440 candidate
.audioCapabilities
,
441 &config_state
, &audio_capabilities
)) {
442 return CONFIGURATION_NOT_SUPPORTED
;
445 // 11.3. Add audio capabilities to accumulated configuration.
446 accumulated_configuration
->audioCapabilities
= audio_capabilities
;
449 // 12. If accumulated configuration's distinctiveIdentifier value is
450 // "optional", follow the steps for the first matching condition from the
452 // - If the implementation requires a Distinctive Identifier for any of
453 // the combinations in accumulated configuration, change accumulated
454 // configuration's distinctiveIdentifier value to "required".
455 // - Otherwise, change accumulated configuration's distinctiveIdentifier
456 // value to "not-allowed".
457 if (accumulated_configuration
->distinctiveIdentifier
==
458 blink::WebMediaKeySystemConfiguration::Requirement::Optional
) {
459 EmeConfigRule not_allowed_rule
=
460 key_systems
.GetDistinctiveIdentifierConfigRule(
461 key_system
, EME_FEATURE_NOT_ALLOWED
);
462 EmeConfigRule required_rule
=
463 key_systems
.GetDistinctiveIdentifierConfigRule(
464 key_system
, EME_FEATURE_REQUIRED
);
465 bool not_allowed_supported
= config_state
.IsRuleSupported(not_allowed_rule
);
466 bool required_supported
= config_state
.IsRuleSupported(required_rule
);
467 // If a distinctive identifier is recommend and that is a possible outcome,
469 if (required_supported
&&
470 config_state
.IsIdentifierRecommended() &&
471 config_state
.IsPermissionPossible()) {
472 not_allowed_supported
= false;
474 if (not_allowed_supported
) {
475 accumulated_configuration
->distinctiveIdentifier
=
476 blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
;
477 config_state
.AddRule(not_allowed_rule
);
478 } else if (required_supported
) {
479 accumulated_configuration
->distinctiveIdentifier
=
480 blink::WebMediaKeySystemConfiguration::Requirement::Required
;
481 config_state
.AddRule(required_rule
);
483 // We should not have passed step 3.
485 return CONFIGURATION_NOT_SUPPORTED
;
489 // 13. If accumulated configuration's persistentState value is "optional",
490 // follow the steps for the first matching condition from the following
492 // - If the implementation requires persisting state for any of the
493 // combinations in accumulated configuration, change accumulated
494 // configuration's persistentState value to "required".
495 // - Otherwise, change accumulated configuration's persistentState value
497 if (accumulated_configuration
->persistentState
==
498 blink::WebMediaKeySystemConfiguration::Requirement::Optional
) {
499 EmeConfigRule not_allowed_rule
=
500 key_systems
.GetPersistentStateConfigRule(
501 key_system
, EME_FEATURE_NOT_ALLOWED
);
502 EmeConfigRule required_rule
=
503 key_systems
.GetPersistentStateConfigRule(
504 key_system
, EME_FEATURE_REQUIRED
);
505 // |distinctiveIdentifier| should not be affected after it is decided.
506 DCHECK(not_allowed_rule
== EmeConfigRule::NOT_SUPPORTED
||
507 not_allowed_rule
== EmeConfigRule::PERSISTENCE_NOT_ALLOWED
);
508 DCHECK(required_rule
== EmeConfigRule::NOT_SUPPORTED
||
509 required_rule
== EmeConfigRule::PERSISTENCE_REQUIRED
);
510 bool not_allowed_supported
=
511 config_state
.IsRuleSupported(not_allowed_rule
);
512 bool required_supported
=
513 config_state
.IsRuleSupported(required_rule
);
514 if (not_allowed_supported
) {
515 accumulated_configuration
->persistentState
=
516 blink::WebMediaKeySystemConfiguration::Requirement::NotAllowed
;
517 config_state
.AddRule(not_allowed_rule
);
518 } else if (required_supported
) {
519 accumulated_configuration
->persistentState
=
520 blink::WebMediaKeySystemConfiguration::Requirement::Required
;
521 config_state
.AddRule(required_rule
);
523 // We should not have passed step 5.
525 return CONFIGURATION_NOT_SUPPORTED
;
529 // 14. If implementation in the configuration specified by the combination of
530 // the values in accumulated configuration is not supported or not allowed
531 // in the origin, return null.
532 // 15. If accumulated configuration's distinctiveIdentifier value is
533 // "required", [prompt the user for consent].
534 if (accumulated_configuration
->distinctiveIdentifier
==
535 blink::WebMediaKeySystemConfiguration::Requirement::Required
) {
536 // The caller is responsible for resolving what to do if permission is
537 // required but has been denied (it should treat it as NOT_SUPPORTED).
538 if (!config_state
.IsPermissionGranted())
539 return CONFIGURATION_REQUIRES_PERMISSION
;
542 // 16. If the label member is present in candidate configuration, add the
543 // value of the candidate configuration's label member to accumulated
545 accumulated_configuration
->label
= candidate
.label
;
547 // 17. Return accumulated configuration.
548 return CONFIGURATION_SUPPORTED
;
551 // Report usage of key system to UMA. There are 2 different counts logged:
552 // 1. The key system is requested.
553 // 2. The requested key system and options are supported.
554 // Each stat is only reported once per renderer frame per key system.
555 // Note that WebEncryptedMediaClientImpl is only created once by each
557 class WebEncryptedMediaClientImpl::Reporter
{
559 enum KeySystemSupportStatus
{
560 KEY_SYSTEM_REQUESTED
= 0,
561 KEY_SYSTEM_SUPPORTED
= 1,
562 KEY_SYSTEM_SUPPORT_STATUS_COUNT
565 explicit Reporter(const std::string
& key_system_for_uma
)
566 : uma_name_(kKeySystemSupportUMAPrefix
+ key_system_for_uma
),
567 is_request_reported_(false),
568 is_support_reported_(false) {}
571 void ReportRequested() {
572 if (is_request_reported_
)
574 Report(KEY_SYSTEM_REQUESTED
);
575 is_request_reported_
= true;
578 void ReportSupported() {
579 DCHECK(is_request_reported_
);
580 if (is_support_reported_
)
582 Report(KEY_SYSTEM_SUPPORTED
);
583 is_support_reported_
= true;
587 void Report(KeySystemSupportStatus status
) {
588 // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros
589 // require the names to be constant throughout the process' lifetime.
590 base::LinearHistogram::FactoryGet(
591 uma_name_
, 1, KEY_SYSTEM_SUPPORT_STATUS_COUNT
,
592 KEY_SYSTEM_SUPPORT_STATUS_COUNT
+ 1,
593 base::Histogram::kUmaTargetedHistogramFlag
)->Add(status
);
596 const std::string uma_name_
;
597 bool is_request_reported_
;
598 bool is_support_reported_
;
601 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(
602 CdmFactory
* cdm_factory
,
603 MediaPermission
* media_permission
)
604 : key_systems_(KeySystems::GetInstance()),
605 cdm_factory_(cdm_factory
),
606 media_permission_(media_permission
),
607 weak_factory_(this) {
608 DCHECK(media_permission
);
611 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() {
614 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
615 blink::WebEncryptedMediaRequest request
) {
616 // TODO(jrummell): This should be asynchronous, ideally not on the main
619 // Continued from requestMediaKeySystemAccess(), step 7, from
620 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
622 // 7.1. If keySystem is not one of the Key Systems supported by the user
623 // agent, reject promise with with a new DOMException whose name is
624 // NotSupportedError. String comparison is case-sensitive.
625 if (!base::IsStringASCII(request
.keySystem())) {
626 request
.requestNotSupported("Only ASCII keySystems are supported");
630 // Report this request to the UMA.
631 std::string key_system
= base::UTF16ToASCII(request
.keySystem());
632 GetReporter(key_system
)->ReportRequested();
634 if (!key_systems_
.IsSupportedKeySystem(key_system
)) {
635 request
.requestNotSupported("Unsupported keySystem");
639 // 7.2-7.4. Implemented by SelectSupportedConfiguration().
640 SelectSupportedConfiguration(request
, false, false);
643 void WebEncryptedMediaClientImpl::SelectSupportedConfiguration(
644 blink::WebEncryptedMediaRequest request
,
645 bool was_permission_requested
,
646 bool is_permission_granted
) {
647 // Continued from requestMediaKeySystemAccess(), step 7.1, from
648 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
650 // 7.2. Let implementation be the implementation of keySystem.
651 std::string key_system
= base::UTF16ToASCII(request
.keySystem());
653 // 7.3. For each value in supportedConfigurations:
654 const blink::WebVector
<blink::WebMediaKeySystemConfiguration
>&
655 configurations
= request
.supportedConfigurations();
656 for (size_t i
= 0; i
< configurations
.size(); i
++) {
657 // 7.3.1. Let candidate configuration be the value.
658 const blink::WebMediaKeySystemConfiguration
& candidate_configuration
=
660 // 7.3.2. Let supported configuration be the result of executing the Get
661 // Supported Configuration algorithm on implementation, candidate
662 // configuration, and origin.
663 // 7.3.3. If supported configuration is not null, [initialize and return a
664 // new MediaKeySystemAccess object.]
665 blink::WebMediaKeySystemConfiguration accumulated_configuration
;
666 ConfigurationSupport supported
= GetSupportedConfiguration(
667 key_systems_
, key_system
, candidate_configuration
,
668 was_permission_requested
, is_permission_granted
,
669 &accumulated_configuration
);
671 case CONFIGURATION_NOT_SUPPORTED
:
673 case CONFIGURATION_REQUIRES_PERMISSION
:
674 if (was_permission_requested
) {
675 DVLOG(2) << "Rejecting requested configuration because "
676 << "permission was denied.";
679 media_permission_
->RequestPermission(
680 MediaPermission::PROTECTED_MEDIA_IDENTIFIER
,
681 GURL(request
.securityOrigin().toString()),
682 // Try again with |was_permission_requested| true and
683 // |is_permission_granted| the value of the permission.
685 &WebEncryptedMediaClientImpl::SelectSupportedConfiguration
,
686 weak_factory_
.GetWeakPtr(), request
, true));
688 case CONFIGURATION_SUPPORTED
:
689 // Report that this request succeeded to the UMA.
690 GetReporter(key_system
)->ReportSupported();
691 request
.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
692 request
.keySystem(), accumulated_configuration
,
693 request
.securityOrigin(), weak_factory_
.GetWeakPtr()));
698 // 7.4. Reject promise with a new DOMException whose name is
699 // NotSupportedError.
700 request
.requestNotSupported(
701 "None of the requested configurations were supported.");
704 void WebEncryptedMediaClientImpl::CreateCdm(
705 const blink::WebString
& key_system
,
706 bool allow_distinctive_identifier
,
707 bool allow_persistent_state
,
708 const blink::WebSecurityOrigin
& security_origin
,
709 blink::WebContentDecryptionModuleResult result
) {
710 WebContentDecryptionModuleImpl::Create(
711 cdm_factory_
, key_system
, allow_distinctive_identifier
,
712 allow_persistent_state
, security_origin
, result
);
715 // Lazily create Reporters.
716 WebEncryptedMediaClientImpl::Reporter
* WebEncryptedMediaClientImpl::GetReporter(
717 const std::string
& key_system
) {
718 std::string uma_name
= GetKeySystemNameForUMA(key_system
);
719 Reporter
* reporter
= reporters_
.get(uma_name
);
720 if (reporter
!= nullptr)
723 // Reporter not found, so create one.
725 reporters_
.add(uma_name
, make_scoped_ptr(new Reporter(uma_name
)));
726 DCHECK(result
.second
);
727 return result
.first
->second
;