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"
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"
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";
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
) {
69 case EME_SESSION_TYPE_INVALID
:
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
;
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
) {
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
)
166 if (key_system
== kClearKey
)
169 // External Clear Key is known and supports suffixes for testing.
170 if (IsExternalClearKey(key_system
))
173 // Chromecast defines behaviors for Cast clients within its reverse domain.
174 const char kChromecastRoot
[] = "com.chromecast";
175 if (IsParentKeySystemOf(kChromecastRoot
, key_system
))
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)
188 class KeySystemsImpl
: public KeySystems
{
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;
209 void AddContainerMask(const std::string
& container
, uint32 mask
);
211 EmeMediaType media_type
,
212 const std::string
& codec
,
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
;
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
;
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
.Get();
315 key_systems
.UpdateIfNeeded();
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
;
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())
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())
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())
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
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
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();
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
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())
520 EmeCodec codec
= GetCodecForString(codecs
[i
]);
522 // Unsupported codec.
523 if (!(codec
& key_system_supported_codecs
))
526 // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
527 if (!(codec
& container_supported_codecs
))
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()) {
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
:
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;
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())
583 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, false);
586 DCHECK(codecs
.empty());
590 SupportedCodecs key_system_supported_codecs
=
591 key_system_iter
->second
.supported_codecs
;
593 if (!IsSupportedContainer(mime_type
, key_system_supported_codecs
))
596 if (!codecs
.empty() &&
597 !IsSupportedContainerAndCodecs(
598 mime_type
, codecs
, key_system_supported_codecs
)) {
602 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, 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
;
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";
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";
651 void KeySystemsImpl::AddContainerMask(
652 const std::string
& container
,
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
,
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
;
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))
691 media_type_codec_mask
= audio_codec_mask_
;
693 case EmeMediaType::VIDEO
:
694 if (!StartsWithASCII(container_mime_type
, "video/", true))
696 media_type_codec_mask
= video_codec_mask_
;
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()) {
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)
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)
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()) {
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
;
751 case EmeMediaType::VIDEO
:
752 max_robustness
= key_system_iter
->second
.max_video_robustness
;
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()) {
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()) {
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()) {
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()) {
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
;
925 std::string
GetPrefixedKeySystemName(const std::string
& key_system
) {
926 DCHECK_NE(key_system
, kPrefixedClearKeyKeySystem
);
928 if (key_system
== kClearKeyKeySystem
)
929 return kPrefixedClearKeyKeySystem
;
934 bool PrefixedIsSupportedConcreteKeySystem(const std::string
& key_system
) {
935 return KeySystemsImpl::GetInstance().IsConcreteSupportedKeySystem(key_system
);
938 bool IsSupportedKeySystem(const std::string
& key_system
) {
939 if (!KeySystemsImpl::GetInstance().IsSupportedKeySystem(key_system
))
942 // TODO(ddorwin): Move this to where we add key systems when prefixed EME is
943 // removed (crbug.com/249976).
944 if (!IsPotentiallySupportedKeySystem(key_system
)) {
945 // If you encounter this path, see the comments for the above function.
946 NOTREACHED() << "Unrecognized key system " << key_system
947 << ". See code comments.";
954 bool IsSupportedKeySystemWithInitDataType(const std::string
& key_system
,
955 EmeInitDataType init_data_type
) {
956 return KeySystemsImpl::GetInstance().IsSupportedInitDataType(key_system
,
960 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
961 const std::string
& mime_type
,
962 const std::vector
<std::string
>& codecs
,
963 const std::string
& key_system
) {
964 return KeySystemsImpl::GetInstance()
965 .PrefixedIsSupportedKeySystemWithMediaMimeType(mime_type
, codecs
,
969 std::string
GetKeySystemNameForUMA(const std::string
& key_system
) {
970 return KeySystemsImpl::GetInstance().GetKeySystemNameForUMA(key_system
);
973 bool CanUseAesDecryptor(const std::string
& concrete_key_system
) {
974 return KeySystemsImpl::GetInstance().UseAesDecryptor(concrete_key_system
);
977 #if defined(ENABLE_PEPPER_CDMS)
978 std::string
GetPepperType(const std::string
& concrete_key_system
) {
979 return KeySystemsImpl::GetInstance().GetPepperType(concrete_key_system
);
983 // These two functions are for testing purpose only. The declaration in the
984 // header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
985 // by tests but not non-test code. However, this .cc file is compiled as part of
986 // "media" where "UNIT_TEST" is not defined. So we need to specify
987 // "MEDIA_EXPORT" here again so that they are visible to tests.
989 MEDIA_EXPORT
void AddContainerMask(const std::string
& container
, uint32 mask
) {
990 KeySystemsImpl::GetInstance().AddContainerMask(container
, mask
);
993 MEDIA_EXPORT
void AddCodecMask(
994 EmeMediaType media_type
,
995 const std::string
& codec
,
997 KeySystemsImpl::GetInstance().AddCodecMask(media_type
, codec
, mask
);
1000 } // namespace media