Don't send a SHChangeNotify for creating an app icon when creating a shortcut.
[chromium-blink-merge.git] / media / blink / webencryptedmediaclient_impl.cc
blobccd44fb528f562d24de1e35b02f771f25eacef0b
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"
7 #include "base/bind.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"
22 namespace media {
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.
36 class ConfigState {
37 public:
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 {
64 switch (rule) {
65 case EmeConfigRule::NOT_SUPPORTED:
66 return false;
67 case EmeConfigRule::IDENTIFIER_REQUIRED:
68 return IsPermissionPossible();
69 case EmeConfigRule::IDENTIFIER_RECOMMENDED:
70 return true;
71 case EmeConfigRule::SUPPORTED:
72 return true;
74 NOTREACHED();
75 return false;
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 {
83 switch (rule) {
84 case EmeConfigRule::NOT_SUPPORTED:
85 return false;
86 case EmeConfigRule::IDENTIFIER_REQUIRED:
87 return is_permission_granted_;
88 case EmeConfigRule::IDENTIFIER_RECOMMENDED:
89 return true;
90 case EmeConfigRule::SUPPORTED:
91 return true;
93 NOTREACHED();
94 return false;
97 // Add a rule to the accumulated configuration state.
98 void AddRule(EmeConfigRule rule) {
99 switch (rule) {
100 case EmeConfigRule::NOT_SUPPORTED:
101 return;
102 case EmeConfigRule::IDENTIFIER_REQUIRED:
103 is_identifier_required_ = true;
104 return;
105 case EmeConfigRule::IDENTIFIER_RECOMMENDED:
106 is_identifier_recommended_ = true;
107 return;
108 case EmeConfigRule::SUPPORTED:
109 return;
111 NOTREACHED();
114 private:
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
141 // is stripped.
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)) {
146 return false;
149 if (codec_vector.empty())
150 return true;
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
155 // algorithm).
156 codec_vector.clear();
157 net::ParseCodecString(codecs, &codec_vector, false);
158 return (net::IsSupportedStrictMediaMimeType(container_lower, codec_vector) ==
159 net::IsSupported);
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) {
171 // From
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
174 // configuration.
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.";
189 return false;
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))) {
197 continue;
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))
205 continue;
206 EmeConfigRule robustness_rule = key_systems.GetRobustnessConfigRule(
207 key_system, media_type, base::UTF16ToASCII(capability.robustness));
208 if (!config_state->IsRuleSupported(robustness_rule))
209 continue;
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.";
228 return false;
230 // 5. Return media type capabilities.
231 return true;
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;
245 NOTREACHED();
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)
273 continue;
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";
283 break;
284 case blink::WebEncryptedMediaInitDataType::Keyids:
285 init_data_type_as_ascii = "keyids";
286 break;
287 case blink::WebEncryptedMediaInitDataType::Webm:
288 init_data_type_as_ascii = "webm";
289 break;
290 case blink::WebEncryptedMediaInitDataType::Unknown:
291 NOTREACHED();
292 break;
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,
315 // return null.
316 // - "optional": Continue.
317 // - "not-allowed": If the implementation requires a Distinctive
318 // Identifier in combination with accumulated configuration, return
319 // null.
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
362 // configuration.
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
381 // configuration.
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
396 // following list:
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());
421 } else {
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);
430 } else {
431 // We should not have passed step 3.
432 NOTREACHED();
433 return CONFIGURATION_NOT_SUPPORTED;
437 // If permission is required but we couldn't enable it, reject the
438 // configuration.
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 "
444 << "not allowed.";
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
450 // list:
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
455 // to "not-allowed".
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;
476 } else {
477 // We should not have passed step 5.
478 NOTREACHED();
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
499 // synchronous.
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(
511 key_system))) {
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
526 // renderer frame.
527 class WebEncryptedMediaClientImpl::Reporter {
528 public:
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) {}
539 ~Reporter() {}
541 void ReportRequested() {
542 if (is_request_reported_)
543 return;
544 Report(KEY_SYSTEM_REQUESTED);
545 is_request_reported_ = true;
548 void ReportSupported() {
549 DCHECK(is_request_reported_);
550 if (is_support_reported_)
551 return;
552 Report(KEY_SYSTEM_SUPPORTED);
553 is_support_reported_ = true;
556 private:
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
587 // thread.
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");
597 return;
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");
606 return;
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 =
629 configurations[i];
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);
640 switch (supported) {
641 case CONFIGURATION_NOT_SUPPORTED:
642 continue;
643 case CONFIGURATION_REQUIRES_PERMISSION:
644 if (was_permission_requested) {
645 DVLOG(2) << "Rejecting requested configuration because "
646 << "permission was denied.";
647 continue;
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.
654 base::Bind(
655 &WebEncryptedMediaClientImpl::SelectSupportedConfiguration,
656 weak_factory_.GetWeakPtr(), request, true));
657 return;
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()));
664 return;
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)
692 return reporter;
694 // Reporter not found, so create one.
695 auto result =
696 reporters_.add(uma_name, make_scoped_ptr(new Reporter(uma_name)));
697 DCHECK(result.second);
698 return result.first->second;
701 } // namespace media