Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / media / base / key_systems.cc
blobf8c5c53ac1511e926852651a9ec7b34d3004e0b4
1 // Copyright 2013 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 "media/base/key_systems.h"
7 #include <string>
9 #include "base/containers/hash_tables.h"
10 #include "base/lazy_instance.h"
11 #include "base/logging.h"
12 #include "base/strings/string_util.h"
13 #include "base/threading/thread_checker.h"
14 #include "base/time/time.h"
15 #include "media/base/eme_constants.h"
16 #include "media/base/key_system_info.h"
17 #include "media/base/key_systems_support_uma.h"
18 #include "media/base/media_client.h"
19 #include "media/cdm/key_system_names.h"
20 #include "third_party/widevine/cdm/widevine_cdm_common.h"
22 namespace media {
24 const char kClearKeyKeySystem[] = "org.w3.clearkey";
25 const char kPrefixedClearKeyKeySystem[] = "webkit-org.w3.clearkey";
26 const char kUnsupportedClearKeyKeySystem[] = "unsupported-org.w3.clearkey";
28 // These names are used by UMA. Do not change them!
29 const char kClearKeyKeySystemNameForUMA[] = "ClearKey";
30 const char kUnknownKeySystemNameForUMA[] = "Unknown";
32 struct NamedCodec {
33 const char* name;
34 EmeCodec type;
37 // Mapping between containers and their codecs.
38 // Only audio codec can belong to a "audio/*" container. Both audio and video
39 // codecs can belong to a "video/*" container.
40 // TODO(sandersd): This definition only makes sense for prefixed EME. Change it
41 // when prefixed EME is removed. http://crbug.com/249976
42 static NamedCodec kContainerToCodecMasks[] = {
43 {"audio/webm", EME_CODEC_WEBM_AUDIO_ALL},
44 {"video/webm", EME_CODEC_WEBM_ALL},
45 #if defined(USE_PROPRIETARY_CODECS)
46 {"audio/mp4", EME_CODEC_MP4_AUDIO_ALL},
47 {"video/mp4", EME_CODEC_MP4_ALL}
48 #endif // defined(USE_PROPRIETARY_CODECS)
51 // Mapping between codec names and enum values.
52 static NamedCodec kCodecStrings[] = {
53 {"opus", EME_CODEC_WEBM_OPUS},
54 {"vorbis", EME_CODEC_WEBM_VORBIS},
55 {"vp8", EME_CODEC_WEBM_VP8},
56 {"vp8.0", EME_CODEC_WEBM_VP8},
57 {"vp9", EME_CODEC_WEBM_VP9},
58 {"vp9.0", EME_CODEC_WEBM_VP9},
59 #if defined(USE_PROPRIETARY_CODECS)
60 {"mp4a", EME_CODEC_MP4_AAC},
61 {"avc1", EME_CODEC_MP4_AVC1},
62 {"avc3", EME_CODEC_MP4_AVC1}
63 #endif // defined(USE_PROPRIETARY_CODECS)
66 static EmeConfigRule ConvertSessionTypeSupport(
67 EmeSessionTypeSupport support) {
68 switch (support) {
69 case EME_SESSION_TYPE_INVALID:
70 NOTREACHED();
71 return EmeConfigRule::NOT_SUPPORTED;
72 case EME_SESSION_TYPE_NOT_SUPPORTED:
73 return EmeConfigRule::NOT_SUPPORTED;
74 case EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER:
75 return EmeConfigRule::IDENTIFIER_AND_PERSISTENCE_REQUIRED;
76 case EME_SESSION_TYPE_SUPPORTED:
77 return EmeConfigRule::PERSISTENCE_REQUIRED;
79 NOTREACHED();
80 return EmeConfigRule::NOT_SUPPORTED;
83 static EmeRobustness ConvertRobustness(const std::string& robustness) {
84 if (robustness.empty())
85 return EmeRobustness::EMPTY;
86 if (robustness == "SW_SECURE_CRYPTO")
87 return EmeRobustness::SW_SECURE_CRYPTO;
88 if (robustness == "SW_SECURE_DECODE")
89 return EmeRobustness::SW_SECURE_DECODE;
90 if (robustness == "HW_SECURE_CRYPTO")
91 return EmeRobustness::HW_SECURE_CRYPTO;
92 if (robustness == "HW_SECURE_DECODE")
93 return EmeRobustness::HW_SECURE_DECODE;
94 if (robustness == "HW_SECURE_ALL")
95 return EmeRobustness::HW_SECURE_ALL;
96 return EmeRobustness::INVALID;
99 static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
100 KeySystemInfo info;
101 info.key_system = kClearKeyKeySystem;
103 // On Android, Vorbis, VP8, AAC and AVC1 are supported in MediaCodec:
104 // http://developer.android.com/guide/appendix/media-formats.html
105 // VP9 support is device dependent.
107 info.supported_init_data_types =
108 kInitDataTypeMaskWebM | kInitDataTypeMaskKeyIds;
109 info.supported_codecs = EME_CODEC_WEBM_ALL;
111 #if defined(OS_ANDROID)
112 // Temporarily disable VP9 support for Android.
113 // TODO(xhwang): Use mime_util.h to query VP9 support on Android.
114 info.supported_codecs &= ~EME_CODEC_WEBM_VP9;
116 // Opus is not supported on Android yet. http://crbug.com/318436.
117 // TODO(sandersd): Check for platform support to set this bit.
118 info.supported_codecs &= ~EME_CODEC_WEBM_OPUS;
119 #endif // defined(OS_ANDROID)
121 #if defined(USE_PROPRIETARY_CODECS)
122 info.supported_init_data_types |= kInitDataTypeMaskCenc;
123 info.supported_codecs |= EME_CODEC_MP4_ALL;
124 #endif // defined(USE_PROPRIETARY_CODECS)
126 info.max_audio_robustness = EmeRobustness::EMPTY;
127 info.max_video_robustness = EmeRobustness::EMPTY;
128 info.persistent_license_support = EME_SESSION_TYPE_NOT_SUPPORTED;
129 info.persistent_release_message_support = EME_SESSION_TYPE_NOT_SUPPORTED;
130 info.persistent_state_support = EME_FEATURE_NOT_SUPPORTED;
131 info.distinctive_identifier_support = EME_FEATURE_NOT_SUPPORTED;
133 info.use_aes_decryptor = true;
135 concrete_key_systems->push_back(info);
138 // Returns whether the |key_system| is known to Chromium and is thus likely to
139 // be implemented in an interoperable way.
140 // True is always returned for a |key_system| that begins with "x-".
142 // As with other web platform features, advertising support for a key system
143 // implies that it adheres to a defined and interoperable specification.
145 // To ensure interoperability, implementations of a specific |key_system| string
146 // must conform to a specification for that identifier that defines
147 // key system-specific behaviors not fully defined by the EME specification.
148 // That specification should be provided by the owner of the domain that is the
149 // reverse of the |key_system| string.
150 // This involves more than calling a library, SDK, or platform API.
151 // KeySystemsImpl must be populated appropriately, and there will likely be glue
152 // code to adapt to the API of the library, SDK, or platform API.
154 // Chromium mainline contains this data and glue code for specific key systems,
155 // which should help ensure interoperability with other implementations using
156 // these key systems.
158 // If you need to add support for other key systems, ensure that you have
159 // obtained the specification for how to integrate it with EME, implemented the
160 // appropriate glue/adapter code, and added all the appropriate data to
161 // KeySystemsImpl. Only then should you change this function.
162 static bool IsPotentiallySupportedKeySystem(const std::string& key_system) {
163 // Known and supported key systems.
164 if (key_system == kWidevineKeySystem)
165 return true;
166 if (key_system == kClearKey)
167 return true;
169 // External Clear Key is known and supports suffixes for testing.
170 if (IsExternalClearKey(key_system))
171 return true;
173 // Chromecast defines behaviors for Cast clients within its reverse domain.
174 const char kChromecastRoot[] = "com.chromecast";
175 if (IsParentKeySystemOf(kChromecastRoot, key_system))
176 return true;
178 // Implementations that do not have a specification or appropriate glue code
179 // can use the "x-" prefix to avoid conflicting with and advertising support
180 // for real key system names. Use is discouraged.
181 const char kExcludedPrefix[] = "x-";
182 if (key_system.find(kExcludedPrefix, 0, arraysize(kExcludedPrefix) - 1) == 0)
183 return true;
185 return false;
188 class KeySystemsImpl : public KeySystems {
189 public:
190 static KeySystemsImpl* GetInstance();
192 void UpdateIfNeeded();
194 bool IsConcreteSupportedKeySystem(const std::string& key_system) const;
196 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
197 const std::string& mime_type,
198 const std::vector<std::string>& codecs,
199 const std::string& key_system);
201 std::string GetKeySystemNameForUMA(const std::string& key_system) const;
203 bool UseAesDecryptor(const std::string& concrete_key_system) const;
205 #if defined(ENABLE_PEPPER_CDMS)
206 std::string GetPepperType(const std::string& concrete_key_system) const;
207 #endif
209 void AddContainerMask(const std::string& container, uint32 mask);
210 void AddCodecMask(
211 EmeMediaType media_type,
212 const std::string& codec,
213 uint32 mask);
215 // Implementation of KeySystems interface.
216 bool IsSupportedKeySystem(const std::string& key_system) const override;
218 bool IsSupportedInitDataType(const std::string& key_system,
219 EmeInitDataType init_data_type) const override;
221 bool IsSupportedCodecCombination(
222 const std::string& key_system,
223 EmeMediaType media_type,
224 const std::string& container_mime_type,
225 const std::vector<std::string>& codecs) const override;
227 EmeConfigRule GetRobustnessConfigRule(
228 const std::string& key_system,
229 EmeMediaType media_type,
230 const std::string& requested_robustness) const override;
232 EmeConfigRule GetPersistentLicenseSessionConfigRule(
233 const std::string& key_system) const override;
235 EmeConfigRule GetPersistentReleaseMessageSessionConfigRule(
236 const std::string& key_system) const override;
238 EmeConfigRule GetPersistentStateConfigRule(
239 const std::string& key_system,
240 EmeFeatureRequirement requirement) const override;
242 EmeConfigRule GetDistinctiveIdentifierConfigRule(
243 const std::string& key_system,
244 EmeFeatureRequirement requirement) const override;
246 private:
247 void InitializeUMAInfo();
249 void UpdateSupportedKeySystems();
251 void AddConcreteSupportedKeySystems(
252 const std::vector<KeySystemInfo>& concrete_key_systems);
254 friend struct base::DefaultLazyInstanceTraits<KeySystemsImpl>;
256 typedef base::hash_map<std::string, KeySystemInfo> KeySystemInfoMap;
257 typedef base::hash_map<std::string, std::string> ParentKeySystemMap;
258 typedef base::hash_map<std::string, SupportedCodecs> ContainerCodecsMap;
259 typedef base::hash_map<std::string, EmeCodec> CodecsMap;
260 typedef base::hash_map<std::string, EmeInitDataType> InitDataTypesMap;
261 typedef base::hash_map<std::string, std::string> KeySystemNameForUMAMap;
263 KeySystemsImpl();
264 ~KeySystemsImpl() {}
266 // TODO(sandersd): Separate container enum from codec mask value.
267 // http://crbug.com/417440
268 SupportedCodecs GetCodecMaskForContainer(
269 const std::string& container) const;
270 EmeCodec GetCodecForString(const std::string& codec) const;
272 const std::string& PrefixedGetConcreteKeySystemNameFor(
273 const std::string& key_system) const;
275 // Returns whether a |container| type is supported by checking
276 // |key_system_supported_codecs|.
277 // TODO(xhwang): Update this to actually check initDataType support.
278 bool IsSupportedContainer(const std::string& container,
279 SupportedCodecs key_system_supported_codecs) const;
281 // Returns true if all |codecs| are supported in |container| by checking
282 // |key_system_supported_codecs|.
283 bool IsSupportedContainerAndCodecs(
284 const std::string& container,
285 const std::vector<std::string>& codecs,
286 SupportedCodecs key_system_supported_codecs) const;
288 // Map from key system string to capabilities.
289 KeySystemInfoMap concrete_key_system_map_;
291 // Map from parent key system to the concrete key system that should be used
292 // to represent its capabilities.
293 ParentKeySystemMap parent_key_system_map_;
295 KeySystemsSupportUMA key_systems_support_uma_;
297 ContainerCodecsMap container_to_codec_mask_map_;
298 CodecsMap codec_string_map_;
299 KeySystemNameForUMAMap key_system_name_for_uma_map_;
301 SupportedCodecs audio_codec_mask_;
302 SupportedCodecs video_codec_mask_;
304 // Makes sure all methods are called from the same thread.
305 base::ThreadChecker thread_checker_;
307 DISALLOW_COPY_AND_ASSIGN(KeySystemsImpl);
310 static base::LazyInstance<KeySystemsImpl> g_key_systems =
311 LAZY_INSTANCE_INITIALIZER;
313 KeySystemsImpl* KeySystemsImpl::GetInstance() {
314 KeySystemsImpl* key_systems = g_key_systems.Pointer();
315 key_systems->UpdateIfNeeded();
316 return key_systems;
319 // Because we use a LazyInstance, the key systems info must be populated when
320 // the instance is lazily initiated.
321 KeySystemsImpl::KeySystemsImpl() :
322 audio_codec_mask_(EME_CODEC_AUDIO_ALL),
323 video_codec_mask_(EME_CODEC_VIDEO_ALL) {
324 for (size_t i = 0; i < arraysize(kContainerToCodecMasks); ++i) {
325 const std::string& name = kContainerToCodecMasks[i].name;
326 DCHECK(!container_to_codec_mask_map_.count(name));
327 container_to_codec_mask_map_[name] = kContainerToCodecMasks[i].type;
329 for (size_t i = 0; i < arraysize(kCodecStrings); ++i) {
330 const std::string& name = kCodecStrings[i].name;
331 DCHECK(!codec_string_map_.count(name));
332 codec_string_map_[name] = kCodecStrings[i].type;
335 InitializeUMAInfo();
337 // Always update supported key systems during construction.
338 UpdateSupportedKeySystems();
341 SupportedCodecs KeySystemsImpl::GetCodecMaskForContainer(
342 const std::string& container) const {
343 ContainerCodecsMap::const_iterator iter =
344 container_to_codec_mask_map_.find(container);
345 if (iter != container_to_codec_mask_map_.end())
346 return iter->second;
347 return EME_CODEC_NONE;
350 EmeCodec KeySystemsImpl::GetCodecForString(const std::string& codec) const {
351 CodecsMap::const_iterator iter = codec_string_map_.find(codec);
352 if (iter != codec_string_map_.end())
353 return iter->second;
354 return EME_CODEC_NONE;
357 const std::string& KeySystemsImpl::PrefixedGetConcreteKeySystemNameFor(
358 const std::string& key_system) const {
359 ParentKeySystemMap::const_iterator iter =
360 parent_key_system_map_.find(key_system);
361 if (iter != parent_key_system_map_.end())
362 return iter->second;
363 return key_system;
366 void KeySystemsImpl::InitializeUMAInfo() {
367 DCHECK(thread_checker_.CalledOnValidThread());
368 DCHECK(key_system_name_for_uma_map_.empty());
370 std::vector<KeySystemInfoForUMA> key_systems_info_for_uma;
371 if (GetMediaClient())
372 GetMediaClient()->AddKeySystemsInfoForUMA(&key_systems_info_for_uma);
374 for (const KeySystemInfoForUMA& info : key_systems_info_for_uma) {
375 key_system_name_for_uma_map_[info.key_system] =
376 info.key_system_name_for_uma;
377 if (info.reports_key_system_support_to_uma)
378 key_systems_support_uma_.AddKeySystemToReport(info.key_system);
381 // Clear Key is always supported.
382 key_system_name_for_uma_map_[kClearKeyKeySystem] =
383 kClearKeyKeySystemNameForUMA;
386 void KeySystemsImpl::UpdateIfNeeded() {
387 if (GetMediaClient() && GetMediaClient()->IsKeySystemsUpdateNeeded())
388 UpdateSupportedKeySystems();
391 void KeySystemsImpl::UpdateSupportedKeySystems() {
392 DCHECK(thread_checker_.CalledOnValidThread());
393 concrete_key_system_map_.clear();
394 parent_key_system_map_.clear();
396 // Build KeySystemInfo.
397 std::vector<KeySystemInfo> key_systems_info;
399 // Add key systems supported by the MediaClient implementation.
400 if (GetMediaClient())
401 GetMediaClient()->AddSupportedKeySystems(&key_systems_info);
403 // Clear Key is always supported.
404 AddClearKey(&key_systems_info);
406 AddConcreteSupportedKeySystems(key_systems_info);
409 void KeySystemsImpl::AddConcreteSupportedKeySystems(
410 const std::vector<KeySystemInfo>& concrete_key_systems) {
411 DCHECK(thread_checker_.CalledOnValidThread());
412 DCHECK(concrete_key_system_map_.empty());
413 DCHECK(parent_key_system_map_.empty());
415 for (const KeySystemInfo& info : concrete_key_systems) {
416 DCHECK(!info.key_system.empty());
417 DCHECK(info.max_audio_robustness != EmeRobustness::INVALID);
418 DCHECK(info.max_video_robustness != EmeRobustness::INVALID);
419 DCHECK(info.persistent_license_support != EME_SESSION_TYPE_INVALID);
420 DCHECK(info.persistent_release_message_support != EME_SESSION_TYPE_INVALID);
421 DCHECK(info.persistent_state_support != EME_FEATURE_INVALID);
422 DCHECK(info.distinctive_identifier_support != EME_FEATURE_INVALID);
424 // Supporting persistent state is a prerequsite for supporting persistent
425 // sessions.
426 if (info.persistent_state_support == EME_FEATURE_NOT_SUPPORTED) {
427 DCHECK(info.persistent_license_support == EME_SESSION_TYPE_NOT_SUPPORTED);
428 DCHECK(info.persistent_release_message_support ==
429 EME_SESSION_TYPE_NOT_SUPPORTED);
432 // persistent-release-message sessions are not currently supported.
433 // http://crbug.com/448888
434 DCHECK(info.persistent_release_message_support ==
435 EME_SESSION_TYPE_NOT_SUPPORTED);
437 // If distinctive identifiers are not supported, then no other features can
438 // require them.
439 if (info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED) {
440 DCHECK(info.persistent_license_support !=
441 EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER);
442 DCHECK(info.persistent_release_message_support !=
443 EME_SESSION_TYPE_SUPPORTED_WITH_IDENTIFIER);
446 // Distinctive identifiers and persistent state can only be reliably blocked
447 // (and therefore be safely configurable) for Pepper-hosted key systems. For
448 // other platforms, only non-configurable values are valid.
449 bool can_block = false;
450 #if defined(ENABLE_PEPPER_CDMS)
451 DCHECK_EQ(info.use_aes_decryptor, info.pepper_type.empty());
452 can_block = !info.pepper_type.empty();
453 #endif
454 if (!can_block) {
455 DCHECK(info.distinctive_identifier_support == EME_FEATURE_NOT_SUPPORTED ||
456 info.distinctive_identifier_support == EME_FEATURE_ALWAYS_ENABLED);
457 DCHECK(info.persistent_state_support == EME_FEATURE_NOT_SUPPORTED ||
458 info.persistent_state_support == EME_FEATURE_ALWAYS_ENABLED);
461 DCHECK(!IsSupportedKeySystem(info.key_system))
462 << "Key system '" << info.key_system << "' already registered";
463 DCHECK(!parent_key_system_map_.count(info.key_system))
464 << "'" << info.key_system << "' is already registered as a parent";
465 concrete_key_system_map_[info.key_system] = info;
466 if (!info.parent_key_system.empty()) {
467 DCHECK(!IsConcreteSupportedKeySystem(info.parent_key_system))
468 << "Parent '" << info.parent_key_system << "' "
469 << "already registered concrete";
470 DCHECK(!parent_key_system_map_.count(info.parent_key_system))
471 << "Parent '" << info.parent_key_system << "' already registered";
472 parent_key_system_map_[info.parent_key_system] = info.key_system;
477 bool KeySystemsImpl::IsConcreteSupportedKeySystem(
478 const std::string& key_system) const {
479 DCHECK(thread_checker_.CalledOnValidThread());
480 return concrete_key_system_map_.count(key_system) != 0;
483 bool KeySystemsImpl::IsSupportedContainer(
484 const std::string& container,
485 SupportedCodecs key_system_supported_codecs) const {
486 DCHECK(thread_checker_.CalledOnValidThread());
487 DCHECK(!container.empty());
489 // When checking container support for EME, "audio/foo" should be treated the
490 // same as "video/foo". Convert the |container| to achieve this.
491 // TODO(xhwang): Replace this with real checks against supported initDataTypes
492 // combined with supported demuxers.
493 std::string canonical_container = container;
494 if (container.find("audio/") == 0)
495 canonical_container.replace(0, 6, "video/");
497 // A container is supported iif at least one codec in that container is
498 // supported.
499 SupportedCodecs supported_codecs =
500 GetCodecMaskForContainer(canonical_container);
501 return (supported_codecs & key_system_supported_codecs) != 0;
504 bool KeySystemsImpl::IsSupportedContainerAndCodecs(
505 const std::string& container,
506 const std::vector<std::string>& codecs,
507 SupportedCodecs key_system_supported_codecs) const {
508 DCHECK(thread_checker_.CalledOnValidThread());
509 DCHECK(!container.empty());
510 DCHECK(!codecs.empty());
511 DCHECK(IsSupportedContainer(container, key_system_supported_codecs));
513 SupportedCodecs container_supported_codecs =
514 GetCodecMaskForContainer(container);
516 for (size_t i = 0; i < codecs.size(); ++i) {
517 if (codecs[i].empty())
518 continue;
520 EmeCodec codec = GetCodecForString(codecs[i]);
522 // Unsupported codec.
523 if (!(codec & key_system_supported_codecs))
524 return false;
526 // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
527 if (!(codec & container_supported_codecs))
528 return false;
531 return true;
534 bool KeySystemsImpl::IsSupportedInitDataType(
535 const std::string& key_system,
536 EmeInitDataType init_data_type) const {
537 DCHECK(thread_checker_.CalledOnValidThread());
539 // Locate |key_system|. Only concrete key systems are supported in unprefixed.
540 KeySystemInfoMap::const_iterator key_system_iter =
541 concrete_key_system_map_.find(key_system);
542 if (key_system_iter == concrete_key_system_map_.end()) {
543 NOTREACHED();
544 return false;
547 // Check |init_data_type|.
548 InitDataTypeMask available_init_data_types =
549 key_system_iter->second.supported_init_data_types;
550 switch (init_data_type) {
551 case EmeInitDataType::UNKNOWN:
552 return false;
553 case EmeInitDataType::WEBM:
554 return (available_init_data_types & kInitDataTypeMaskWebM) != 0;
555 case EmeInitDataType::CENC:
556 return (available_init_data_types & kInitDataTypeMaskCenc) != 0;
557 case EmeInitDataType::KEYIDS:
558 return (available_init_data_types & kInitDataTypeMaskKeyIds) != 0;
560 NOTREACHED();
561 return false;
564 bool KeySystemsImpl::PrefixedIsSupportedKeySystemWithMediaMimeType(
565 const std::string& mime_type,
566 const std::vector<std::string>& codecs,
567 const std::string& key_system) {
568 DCHECK(thread_checker_.CalledOnValidThread());
570 const std::string& concrete_key_system =
571 PrefixedGetConcreteKeySystemNameFor(key_system);
573 bool has_type = !mime_type.empty();
575 key_systems_support_uma_.ReportKeySystemQuery(key_system, has_type);
577 // Check key system support.
578 KeySystemInfoMap::const_iterator key_system_iter =
579 concrete_key_system_map_.find(concrete_key_system);
580 if (key_system_iter == concrete_key_system_map_.end())
581 return false;
583 key_systems_support_uma_.ReportKeySystemSupport(key_system, false);
585 if (!has_type) {
586 DCHECK(codecs.empty());
587 return true;
590 SupportedCodecs key_system_supported_codecs =
591 key_system_iter->second.supported_codecs;
593 if (!IsSupportedContainer(mime_type, key_system_supported_codecs))
594 return false;
596 if (!codecs.empty() &&
597 !IsSupportedContainerAndCodecs(
598 mime_type, codecs, key_system_supported_codecs)) {
599 return false;
602 key_systems_support_uma_.ReportKeySystemSupport(key_system, true);
604 return true;
607 std::string KeySystemsImpl::GetKeySystemNameForUMA(
608 const std::string& key_system) const {
609 DCHECK(thread_checker_.CalledOnValidThread());
611 KeySystemNameForUMAMap::const_iterator iter =
612 key_system_name_for_uma_map_.find(key_system);
613 if (iter == key_system_name_for_uma_map_.end())
614 return kUnknownKeySystemNameForUMA;
616 return iter->second;
619 bool KeySystemsImpl::UseAesDecryptor(
620 const std::string& concrete_key_system) const {
621 DCHECK(thread_checker_.CalledOnValidThread());
623 KeySystemInfoMap::const_iterator key_system_iter =
624 concrete_key_system_map_.find(concrete_key_system);
625 if (key_system_iter == concrete_key_system_map_.end()) {
626 DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
627 return false;
630 return key_system_iter->second.use_aes_decryptor;
633 #if defined(ENABLE_PEPPER_CDMS)
634 std::string KeySystemsImpl::GetPepperType(
635 const std::string& concrete_key_system) const {
636 DCHECK(thread_checker_.CalledOnValidThread());
638 KeySystemInfoMap::const_iterator key_system_iter =
639 concrete_key_system_map_.find(concrete_key_system);
640 if (key_system_iter == concrete_key_system_map_.end()) {
641 DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
642 return std::string();
645 const std::string& type = key_system_iter->second.pepper_type;
646 DLOG_IF(FATAL, type.empty()) << concrete_key_system << " is not Pepper-based";
647 return type;
649 #endif
651 void KeySystemsImpl::AddContainerMask(
652 const std::string& container,
653 uint32 mask) {
654 DCHECK(thread_checker_.CalledOnValidThread());
655 DCHECK(!container_to_codec_mask_map_.count(container));
656 container_to_codec_mask_map_[container] = static_cast<EmeCodec>(mask);
659 void KeySystemsImpl::AddCodecMask(
660 EmeMediaType media_type,
661 const std::string& codec,
662 uint32 mask) {
663 DCHECK(thread_checker_.CalledOnValidThread());
664 DCHECK(!codec_string_map_.count(codec));
665 codec_string_map_[codec] = static_cast<EmeCodec>(mask);
666 if (media_type == EmeMediaType::AUDIO) {
667 audio_codec_mask_ |= mask;
668 } else {
669 video_codec_mask_ |= mask;
673 bool KeySystemsImpl::IsSupportedKeySystem(const std::string& key_system) const {
674 DCHECK(thread_checker_.CalledOnValidThread());
675 return concrete_key_system_map_.count(key_system) != 0;
678 bool KeySystemsImpl::IsSupportedCodecCombination(
679 const std::string& key_system,
680 EmeMediaType media_type,
681 const std::string& container_mime_type,
682 const std::vector<std::string>& codecs) const {
683 DCHECK(thread_checker_.CalledOnValidThread());
685 // Make sure the container matches |media_type|.
686 SupportedCodecs media_type_codec_mask = EME_CODEC_NONE;
687 switch (media_type) {
688 case EmeMediaType::AUDIO:
689 if (!StartsWithASCII(container_mime_type, "audio/", true))
690 return false;
691 media_type_codec_mask = audio_codec_mask_;
692 break;
693 case EmeMediaType::VIDEO:
694 if (!StartsWithASCII(container_mime_type, "video/", true))
695 return false;
696 media_type_codec_mask = video_codec_mask_;
697 break;
700 // Look up the key system's supported codecs.
701 KeySystemInfoMap::const_iterator key_system_iter =
702 concrete_key_system_map_.find(key_system);
703 if (key_system_iter == concrete_key_system_map_.end()) {
704 NOTREACHED();
705 return false;
707 SupportedCodecs key_system_codec_mask =
708 key_system_iter->second.supported_codecs;
710 // Check that the container is supported by the key system. (This check is
711 // necessary because |codecs| may be empty.)
712 SupportedCodecs container_codec_mask =
713 GetCodecMaskForContainer(container_mime_type) & media_type_codec_mask;
714 if ((key_system_codec_mask & container_codec_mask) == 0)
715 return false;
717 // Check that the codecs are supported by the key system and container.
718 for (size_t i = 0; i < codecs.size(); i++) {
719 SupportedCodecs codec = GetCodecForString(codecs[i]);
720 if ((codec & key_system_codec_mask & container_codec_mask) == 0)
721 return false;
724 return true;
727 EmeConfigRule KeySystemsImpl::GetRobustnessConfigRule(
728 const std::string& key_system,
729 EmeMediaType media_type,
730 const std::string& requested_robustness) const {
731 DCHECK(thread_checker_.CalledOnValidThread());
733 EmeRobustness robustness = ConvertRobustness(requested_robustness);
734 if (robustness == EmeRobustness::INVALID)
735 return EmeConfigRule::NOT_SUPPORTED;
736 if (robustness == EmeRobustness::EMPTY)
737 return EmeConfigRule::SUPPORTED;
739 KeySystemInfoMap::const_iterator key_system_iter =
740 concrete_key_system_map_.find(key_system);
741 if (key_system_iter == concrete_key_system_map_.end()) {
742 NOTREACHED();
743 return EmeConfigRule::NOT_SUPPORTED;
746 EmeRobustness max_robustness = EmeRobustness::INVALID;
747 switch (media_type) {
748 case EmeMediaType::AUDIO:
749 max_robustness = key_system_iter->second.max_audio_robustness;
750 break;
751 case EmeMediaType::VIDEO:
752 max_robustness = key_system_iter->second.max_video_robustness;
753 break;
756 // We can compare robustness levels whenever they are not HW_SECURE_CRYPTO
757 // and SW_SECURE_DECODE in some order. If they are exactly those two then the
758 // robustness requirement is not supported.
759 if ((max_robustness == EmeRobustness::HW_SECURE_CRYPTO &&
760 robustness == EmeRobustness::SW_SECURE_DECODE) ||
761 (max_robustness == EmeRobustness::SW_SECURE_DECODE &&
762 robustness == EmeRobustness::HW_SECURE_CRYPTO) ||
763 robustness > max_robustness) {
764 return EmeConfigRule::NOT_SUPPORTED;
767 #if defined(OS_CHROMEOS)
768 if (key_system == kWidevineKeySystem) {
769 // Hardware security requires remote attestation.
770 if (robustness >= EmeRobustness::HW_SECURE_CRYPTO)
771 return EmeConfigRule::IDENTIFIER_REQUIRED;
773 // For video, recommend remote attestation if HW_SECURE_ALL is available,
774 // because it enables hardware accelerated decoding.
775 // TODO(sandersd): Only do this when hardware accelerated decoding is
776 // available for the requested codecs.
777 if (media_type == EmeMediaType::VIDEO &&
778 max_robustness == EmeRobustness::HW_SECURE_ALL) {
779 return EmeConfigRule::IDENTIFIER_RECOMMENDED;
782 #endif // defined(OS_CHROMEOS)
784 return EmeConfigRule::SUPPORTED;
787 EmeConfigRule KeySystemsImpl::GetPersistentLicenseSessionConfigRule(
788 const std::string& key_system) const {
789 DCHECK(thread_checker_.CalledOnValidThread());
791 KeySystemInfoMap::const_iterator key_system_iter =
792 concrete_key_system_map_.find(key_system);
793 if (key_system_iter == concrete_key_system_map_.end()) {
794 NOTREACHED();
795 return EmeConfigRule::NOT_SUPPORTED;
797 return ConvertSessionTypeSupport(
798 key_system_iter->second.persistent_license_support);
801 EmeConfigRule KeySystemsImpl::GetPersistentReleaseMessageSessionConfigRule(
802 const std::string& key_system) const {
803 DCHECK(thread_checker_.CalledOnValidThread());
805 KeySystemInfoMap::const_iterator key_system_iter =
806 concrete_key_system_map_.find(key_system);
807 if (key_system_iter == concrete_key_system_map_.end()) {
808 NOTREACHED();
809 return EmeConfigRule::NOT_SUPPORTED;
811 return ConvertSessionTypeSupport(
812 key_system_iter->second.persistent_release_message_support);
815 EmeConfigRule KeySystemsImpl::GetPersistentStateConfigRule(
816 const std::string& key_system,
817 EmeFeatureRequirement requirement) const {
818 DCHECK(thread_checker_.CalledOnValidThread());
820 KeySystemInfoMap::const_iterator key_system_iter =
821 concrete_key_system_map_.find(key_system);
822 if (key_system_iter == concrete_key_system_map_.end()) {
823 NOTREACHED();
824 return EmeConfigRule::NOT_SUPPORTED;
827 // For NOT_ALLOWED and REQUIRED, the result is as expected. For OPTIONAL, we
828 // return the most restrictive rule that is not more restrictive than for
829 // NOT_ALLOWED or REQUIRED. Those values will be checked individually when
830 // the option is resolved.
832 // Note that even though a distinctive identifier can not be required for
833 // persistent state, it may still be required for persistent sessions.
835 // NOT_ALLOWED OPTIONAL REQUIRED
836 // NOT_SUPPORTED P_NOT_ALLOWED P_NOT_ALLOWED NOT_SUPPORTED
837 // REQUESTABLE P_NOT_ALLOWED SUPPORTED P_REQUIRED
838 // ALWAYS_ENABLED NOT_SUPPORTED P_REQUIRED P_REQUIRED
839 EmeFeatureSupport support = key_system_iter->second.persistent_state_support;
840 DCHECK(support == EME_FEATURE_NOT_SUPPORTED ||
841 support == EME_FEATURE_REQUESTABLE ||
842 support == EME_FEATURE_ALWAYS_ENABLED);
843 DCHECK(requirement == EME_FEATURE_NOT_ALLOWED ||
844 requirement == EME_FEATURE_OPTIONAL ||
845 requirement == EME_FEATURE_REQUIRED);
846 if ((support == EME_FEATURE_NOT_SUPPORTED &&
847 requirement == EME_FEATURE_REQUIRED) ||
848 (support == EME_FEATURE_ALWAYS_ENABLED &&
849 requirement == EME_FEATURE_NOT_ALLOWED)) {
850 return EmeConfigRule::NOT_SUPPORTED;
852 if (support == EME_FEATURE_REQUESTABLE &&
853 requirement == EME_FEATURE_OPTIONAL) {
854 return EmeConfigRule::SUPPORTED;
856 if (support == EME_FEATURE_NOT_SUPPORTED ||
857 requirement == EME_FEATURE_NOT_ALLOWED) {
858 return EmeConfigRule::PERSISTENCE_NOT_ALLOWED;
860 return EmeConfigRule::PERSISTENCE_REQUIRED;
863 EmeConfigRule KeySystemsImpl::GetDistinctiveIdentifierConfigRule(
864 const std::string& key_system,
865 EmeFeatureRequirement requirement) const {
866 DCHECK(thread_checker_.CalledOnValidThread());
868 KeySystemInfoMap::const_iterator key_system_iter =
869 concrete_key_system_map_.find(key_system);
870 if (key_system_iter == concrete_key_system_map_.end()) {
871 NOTREACHED();
872 return EmeConfigRule::NOT_SUPPORTED;
875 // For NOT_ALLOWED and REQUIRED, the result is as expected. For OPTIONAL, we
876 // return the most restrictive rule that is not more restrictive than for
877 // NOT_ALLOWED or REQUIRED. Those values will be checked individually when
878 // the option is resolved.
880 // NOT_ALLOWED OPTIONAL REQUIRED
881 // NOT_SUPPORTED I_NOT_ALLOWED I_NOT_ALLOWED NOT_SUPPORTED
882 // REQUESTABLE I_NOT_ALLOWED SUPPORTED I_REQUIRED
883 // ALWAYS_ENABLED NOT_SUPPORTED I_REQUIRED I_REQUIRED
884 EmeFeatureSupport support =
885 key_system_iter->second.distinctive_identifier_support;
886 DCHECK(support == EME_FEATURE_NOT_SUPPORTED ||
887 support == EME_FEATURE_REQUESTABLE ||
888 support == EME_FEATURE_ALWAYS_ENABLED);
889 DCHECK(requirement == EME_FEATURE_NOT_ALLOWED ||
890 requirement == EME_FEATURE_OPTIONAL ||
891 requirement == EME_FEATURE_REQUIRED);
892 if ((support == EME_FEATURE_NOT_SUPPORTED &&
893 requirement == EME_FEATURE_REQUIRED) ||
894 (support == EME_FEATURE_ALWAYS_ENABLED &&
895 requirement == EME_FEATURE_NOT_ALLOWED)) {
896 return EmeConfigRule::NOT_SUPPORTED;
898 if (support == EME_FEATURE_REQUESTABLE &&
899 requirement == EME_FEATURE_OPTIONAL) {
900 return EmeConfigRule::SUPPORTED;
902 if (support == EME_FEATURE_NOT_SUPPORTED ||
903 requirement == EME_FEATURE_NOT_ALLOWED) {
904 return EmeConfigRule::IDENTIFIER_NOT_ALLOWED;
906 return EmeConfigRule::IDENTIFIER_REQUIRED;
909 KeySystems* KeySystems::GetInstance() {
910 return KeySystemsImpl::GetInstance();
913 //------------------------------------------------------------------------------
915 std::string GetUnprefixedKeySystemName(const std::string& key_system) {
916 if (key_system == kClearKeyKeySystem)
917 return kUnsupportedClearKeyKeySystem;
919 if (key_system == kPrefixedClearKeyKeySystem)
920 return kClearKeyKeySystem;
922 return key_system;
925 std::string GetPrefixedKeySystemName(const std::string& key_system) {
926 DCHECK_NE(key_system, kPrefixedClearKeyKeySystem);
928 if (key_system == kClearKeyKeySystem)
929 return kPrefixedClearKeyKeySystem;
931 return key_system;
934 bool PrefixedIsSupportedConcreteKeySystem(const std::string& key_system) {
935 return KeySystemsImpl::GetInstance()->IsConcreteSupportedKeySystem(
936 key_system);
939 bool IsSupportedKeySystem(const std::string& key_system) {
940 if (!KeySystemsImpl::GetInstance()->IsSupportedKeySystem(key_system))
941 return false;
943 // TODO(ddorwin): Move this to where we add key systems when prefixed EME is
944 // removed (crbug.com/249976).
945 if (!IsPotentiallySupportedKeySystem(key_system)) {
946 // If you encounter this path, see the comments for the above function.
947 NOTREACHED() << "Unrecognized key system " << key_system
948 << ". See code comments.";
949 return false;
952 return true;
955 bool IsSupportedKeySystemWithInitDataType(const std::string& key_system,
956 EmeInitDataType init_data_type) {
957 return KeySystemsImpl::GetInstance()->IsSupportedInitDataType(key_system,
958 init_data_type);
961 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
962 const std::string& mime_type,
963 const std::vector<std::string>& codecs,
964 const std::string& key_system) {
965 return KeySystemsImpl::GetInstance()
966 ->PrefixedIsSupportedKeySystemWithMediaMimeType(mime_type, codecs,
967 key_system);
970 std::string GetKeySystemNameForUMA(const std::string& key_system) {
971 return KeySystemsImpl::GetInstance()->GetKeySystemNameForUMA(key_system);
974 bool CanUseAesDecryptor(const std::string& concrete_key_system) {
975 return KeySystemsImpl::GetInstance()->UseAesDecryptor(concrete_key_system);
978 #if defined(ENABLE_PEPPER_CDMS)
979 std::string GetPepperType(const std::string& concrete_key_system) {
980 return KeySystemsImpl::GetInstance()->GetPepperType(concrete_key_system);
982 #endif
984 // These two functions are for testing purpose only. The declaration in the
985 // header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
986 // by tests but not non-test code. However, this .cc file is compiled as part of
987 // "media" where "UNIT_TEST" is not defined. So we need to specify
988 // "MEDIA_EXPORT" here again so that they are visible to tests.
990 MEDIA_EXPORT void AddContainerMask(const std::string& container, uint32 mask) {
991 KeySystemsImpl::GetInstance()->AddContainerMask(container, mask);
994 MEDIA_EXPORT void AddCodecMask(
995 EmeMediaType media_type,
996 const std::string& codec,
997 uint32 mask) {
998 KeySystemsImpl::GetInstance()->AddCodecMask(media_type, codec, mask);
1001 } // namespace media