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 EmeRobustness
ConvertRobustness(const std::string
& robustness
) {
67 if (robustness
.empty())
68 return EmeRobustness::EMPTY
;
69 if (robustness
== "SW_SECURE_CRYPTO")
70 return EmeRobustness::SW_SECURE_CRYPTO
;
71 if (robustness
== "SW_SECURE_DECODE")
72 return EmeRobustness::SW_SECURE_DECODE
;
73 if (robustness
== "HW_SECURE_CRYPTO")
74 return EmeRobustness::HW_SECURE_CRYPTO
;
75 if (robustness
== "HW_SECURE_DECODE")
76 return EmeRobustness::HW_SECURE_DECODE
;
77 if (robustness
== "HW_SECURE_ALL")
78 return EmeRobustness::HW_SECURE_ALL
;
79 return EmeRobustness::INVALID
;
82 static void AddClearKey(std::vector
<KeySystemInfo
>* concrete_key_systems
) {
84 info
.key_system
= kClearKeyKeySystem
;
86 // On Android, Vorbis, VP8, AAC and AVC1 are supported in MediaCodec:
87 // http://developer.android.com/guide/appendix/media-formats.html
88 // VP9 support is device dependent.
90 info
.supported_init_data_types
=
91 kInitDataTypeMaskWebM
| kInitDataTypeMaskKeyIds
;
92 info
.supported_codecs
= EME_CODEC_WEBM_ALL
;
94 #if defined(OS_ANDROID)
95 // Temporarily disable VP9 support for Android.
96 // TODO(xhwang): Use mime_util.h to query VP9 support on Android.
97 info
.supported_codecs
&= ~EME_CODEC_WEBM_VP9
;
99 // Opus is not supported on Android yet. http://crbug.com/318436.
100 // TODO(sandersd): Check for platform support to set this bit.
101 info
.supported_codecs
&= ~EME_CODEC_WEBM_OPUS
;
102 #endif // defined(OS_ANDROID)
104 #if defined(USE_PROPRIETARY_CODECS)
105 info
.supported_init_data_types
|= kInitDataTypeMaskCenc
;
106 info
.supported_codecs
|= EME_CODEC_MP4_ALL
;
107 #endif // defined(USE_PROPRIETARY_CODECS)
109 info
.max_audio_robustness
= EmeRobustness::EMPTY
;
110 info
.max_video_robustness
= EmeRobustness::EMPTY
;
111 info
.persistent_license_support
= EmeSessionTypeSupport::NOT_SUPPORTED
;
112 info
.persistent_release_message_support
=
113 EmeSessionTypeSupport::NOT_SUPPORTED
;
114 info
.persistent_state_support
= EmeFeatureSupport::NOT_SUPPORTED
;
115 info
.distinctive_identifier_support
= EmeFeatureSupport::NOT_SUPPORTED
;
117 info
.use_aes_decryptor
= true;
119 concrete_key_systems
->push_back(info
);
122 // Returns whether the |key_system| is known to Chromium and is thus likely to
123 // be implemented in an interoperable way.
124 // True is always returned for a |key_system| that begins with "x-".
126 // As with other web platform features, advertising support for a key system
127 // implies that it adheres to a defined and interoperable specification.
129 // To ensure interoperability, implementations of a specific |key_system| string
130 // must conform to a specification for that identifier that defines
131 // key system-specific behaviors not fully defined by the EME specification.
132 // That specification should be provided by the owner of the domain that is the
133 // reverse of the |key_system| string.
134 // This involves more than calling a library, SDK, or platform API.
135 // KeySystemsImpl must be populated appropriately, and there will likely be glue
136 // code to adapt to the API of the library, SDK, or platform API.
138 // Chromium mainline contains this data and glue code for specific key systems,
139 // which should help ensure interoperability with other implementations using
140 // these key systems.
142 // If you need to add support for other key systems, ensure that you have
143 // obtained the specification for how to integrate it with EME, implemented the
144 // appropriate glue/adapter code, and added all the appropriate data to
145 // KeySystemsImpl. Only then should you change this function.
146 static bool IsPotentiallySupportedKeySystem(const std::string
& key_system
) {
147 // Known and supported key systems.
148 if (key_system
== kWidevineKeySystem
)
150 if (key_system
== kClearKey
)
153 // External Clear Key is known and supports suffixes for testing.
154 if (IsExternalClearKey(key_system
))
157 // Chromecast defines behaviors for Cast clients within its reverse domain.
158 const char kChromecastRoot
[] = "com.chromecast";
159 if (IsParentKeySystemOf(kChromecastRoot
, key_system
))
162 // Implementations that do not have a specification or appropriate glue code
163 // can use the "x-" prefix to avoid conflicting with and advertising support
164 // for real key system names. Use is discouraged.
165 const char kExcludedPrefix
[] = "x-";
166 if (key_system
.find(kExcludedPrefix
, 0, arraysize(kExcludedPrefix
) - 1) == 0)
172 class KeySystemsImpl
: public KeySystems
{
174 static KeySystemsImpl
* GetInstance();
176 void UpdateIfNeeded();
178 bool IsConcreteSupportedKeySystem(const std::string
& key_system
) const;
180 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
181 const std::string
& mime_type
,
182 const std::vector
<std::string
>& codecs
,
183 const std::string
& key_system
);
185 std::string
GetKeySystemNameForUMA(const std::string
& key_system
) const;
187 bool UseAesDecryptor(const std::string
& concrete_key_system
) const;
189 #if defined(ENABLE_PEPPER_CDMS)
190 std::string
GetPepperType(const std::string
& concrete_key_system
) const;
193 void AddContainerMask(const std::string
& container
, uint32 mask
);
195 EmeMediaType media_type
,
196 const std::string
& codec
,
199 // Implementation of KeySystems interface.
200 bool IsSupportedKeySystem(const std::string
& key_system
) const override
;
202 bool IsSupportedInitDataType(const std::string
& key_system
,
203 EmeInitDataType init_data_type
) const override
;
205 bool IsSupportedCodecCombination(
206 const std::string
& key_system
,
207 EmeMediaType media_type
,
208 const std::string
& container_mime_type
,
209 const std::vector
<std::string
>& codecs
) const override
;
211 EmeConfigRule
GetRobustnessConfigRule(
212 const std::string
& key_system
,
213 EmeMediaType media_type
,
214 const std::string
& requested_robustness
) const override
;
216 EmeSessionTypeSupport
GetPersistentLicenseSessionSupport(
217 const std::string
& key_system
) const override
;
219 EmeSessionTypeSupport
GetPersistentReleaseMessageSessionSupport(
220 const std::string
& key_system
) const override
;
222 EmeFeatureSupport
GetPersistentStateSupport(
223 const std::string
& key_system
) const override
;
225 EmeFeatureSupport
GetDistinctiveIdentifierSupport(
226 const std::string
& key_system
) const override
;
230 ~KeySystemsImpl() override
;
232 void InitializeUMAInfo();
234 void UpdateSupportedKeySystems();
236 void AddConcreteSupportedKeySystems(
237 const std::vector
<KeySystemInfo
>& concrete_key_systems
);
239 friend struct base::DefaultLazyInstanceTraits
<KeySystemsImpl
>;
241 typedef base::hash_map
<std::string
, KeySystemInfo
> KeySystemInfoMap
;
242 typedef base::hash_map
<std::string
, std::string
> ParentKeySystemMap
;
243 typedef base::hash_map
<std::string
, SupportedCodecs
> ContainerCodecsMap
;
244 typedef base::hash_map
<std::string
, EmeCodec
> CodecsMap
;
245 typedef base::hash_map
<std::string
, EmeInitDataType
> InitDataTypesMap
;
246 typedef base::hash_map
<std::string
, std::string
> KeySystemNameForUMAMap
;
248 // TODO(sandersd): Separate container enum from codec mask value.
249 // http://crbug.com/417440
250 SupportedCodecs
GetCodecMaskForContainer(
251 const std::string
& container
) const;
252 EmeCodec
GetCodecForString(const std::string
& codec
) const;
254 const std::string
& PrefixedGetConcreteKeySystemNameFor(
255 const std::string
& key_system
) const;
257 // Returns whether a |container| type is supported by checking
258 // |key_system_supported_codecs|.
259 // TODO(xhwang): Update this to actually check initDataType support.
260 bool IsSupportedContainer(const std::string
& container
,
261 SupportedCodecs key_system_supported_codecs
) const;
263 // Returns true if all |codecs| are supported in |container| by checking
264 // |key_system_supported_codecs|.
265 bool IsSupportedContainerAndCodecs(
266 const std::string
& container
,
267 const std::vector
<std::string
>& codecs
,
268 SupportedCodecs key_system_supported_codecs
) const;
270 // Map from key system string to capabilities.
271 KeySystemInfoMap concrete_key_system_map_
;
273 // Map from parent key system to the concrete key system that should be used
274 // to represent its capabilities.
275 ParentKeySystemMap parent_key_system_map_
;
277 KeySystemsSupportUMA key_systems_support_uma_
;
279 ContainerCodecsMap container_to_codec_mask_map_
;
280 CodecsMap codec_string_map_
;
281 KeySystemNameForUMAMap key_system_name_for_uma_map_
;
283 SupportedCodecs audio_codec_mask_
;
284 SupportedCodecs video_codec_mask_
;
286 // Makes sure all methods are called from the same thread.
287 base::ThreadChecker thread_checker_
;
289 DISALLOW_COPY_AND_ASSIGN(KeySystemsImpl
);
292 static base::LazyInstance
<KeySystemsImpl
> g_key_systems
=
293 LAZY_INSTANCE_INITIALIZER
;
295 KeySystemsImpl
* KeySystemsImpl::GetInstance() {
296 KeySystemsImpl
* key_systems
= g_key_systems
.Pointer();
297 key_systems
->UpdateIfNeeded();
301 // Because we use a LazyInstance, the key systems info must be populated when
302 // the instance is lazily initiated.
303 KeySystemsImpl::KeySystemsImpl() :
304 audio_codec_mask_(EME_CODEC_AUDIO_ALL
),
305 video_codec_mask_(EME_CODEC_VIDEO_ALL
) {
306 for (size_t i
= 0; i
< arraysize(kContainerToCodecMasks
); ++i
) {
307 const std::string
& name
= kContainerToCodecMasks
[i
].name
;
308 DCHECK(!container_to_codec_mask_map_
.count(name
));
309 container_to_codec_mask_map_
[name
] = kContainerToCodecMasks
[i
].type
;
311 for (size_t i
= 0; i
< arraysize(kCodecStrings
); ++i
) {
312 const std::string
& name
= kCodecStrings
[i
].name
;
313 DCHECK(!codec_string_map_
.count(name
));
314 codec_string_map_
[name
] = kCodecStrings
[i
].type
;
319 // Always update supported key systems during construction.
320 UpdateSupportedKeySystems();
323 KeySystemsImpl::~KeySystemsImpl() {
326 SupportedCodecs
KeySystemsImpl::GetCodecMaskForContainer(
327 const std::string
& container
) const {
328 ContainerCodecsMap::const_iterator iter
=
329 container_to_codec_mask_map_
.find(container
);
330 if (iter
!= container_to_codec_mask_map_
.end())
332 return EME_CODEC_NONE
;
335 EmeCodec
KeySystemsImpl::GetCodecForString(const std::string
& codec
) const {
336 CodecsMap::const_iterator iter
= codec_string_map_
.find(codec
);
337 if (iter
!= codec_string_map_
.end())
339 return EME_CODEC_NONE
;
342 const std::string
& KeySystemsImpl::PrefixedGetConcreteKeySystemNameFor(
343 const std::string
& key_system
) const {
344 ParentKeySystemMap::const_iterator iter
=
345 parent_key_system_map_
.find(key_system
);
346 if (iter
!= parent_key_system_map_
.end())
351 void KeySystemsImpl::InitializeUMAInfo() {
352 DCHECK(thread_checker_
.CalledOnValidThread());
353 DCHECK(key_system_name_for_uma_map_
.empty());
355 std::vector
<KeySystemInfoForUMA
> key_systems_info_for_uma
;
356 if (GetMediaClient())
357 GetMediaClient()->AddKeySystemsInfoForUMA(&key_systems_info_for_uma
);
359 for (const KeySystemInfoForUMA
& info
: key_systems_info_for_uma
) {
360 key_system_name_for_uma_map_
[info
.key_system
] =
361 info
.key_system_name_for_uma
;
362 if (info
.reports_key_system_support_to_uma
)
363 key_systems_support_uma_
.AddKeySystemToReport(info
.key_system
);
366 // Clear Key is always supported.
367 key_system_name_for_uma_map_
[kClearKeyKeySystem
] =
368 kClearKeyKeySystemNameForUMA
;
371 void KeySystemsImpl::UpdateIfNeeded() {
372 if (GetMediaClient() && GetMediaClient()->IsKeySystemsUpdateNeeded())
373 UpdateSupportedKeySystems();
376 void KeySystemsImpl::UpdateSupportedKeySystems() {
377 DCHECK(thread_checker_
.CalledOnValidThread());
378 concrete_key_system_map_
.clear();
379 parent_key_system_map_
.clear();
381 // Build KeySystemInfo.
382 std::vector
<KeySystemInfo
> key_systems_info
;
384 // Add key systems supported by the MediaClient implementation.
385 if (GetMediaClient())
386 GetMediaClient()->AddSupportedKeySystems(&key_systems_info
);
388 // Clear Key is always supported.
389 AddClearKey(&key_systems_info
);
391 AddConcreteSupportedKeySystems(key_systems_info
);
394 void KeySystemsImpl::AddConcreteSupportedKeySystems(
395 const std::vector
<KeySystemInfo
>& concrete_key_systems
) {
396 DCHECK(thread_checker_
.CalledOnValidThread());
397 DCHECK(concrete_key_system_map_
.empty());
398 DCHECK(parent_key_system_map_
.empty());
400 for (const KeySystemInfo
& info
: concrete_key_systems
) {
401 DCHECK(!info
.key_system
.empty());
402 DCHECK(info
.max_audio_robustness
!= EmeRobustness::INVALID
);
403 DCHECK(info
.max_video_robustness
!= EmeRobustness::INVALID
);
404 DCHECK(info
.persistent_license_support
!= EmeSessionTypeSupport::INVALID
);
405 DCHECK(info
.persistent_release_message_support
!=
406 EmeSessionTypeSupport::INVALID
);
407 DCHECK(info
.persistent_state_support
!= EmeFeatureSupport::INVALID
);
408 DCHECK(info
.distinctive_identifier_support
!= EmeFeatureSupport::INVALID
);
410 // Supporting persistent state is a prerequsite for supporting persistent
412 if (info
.persistent_state_support
== EmeFeatureSupport::NOT_SUPPORTED
) {
413 DCHECK(info
.persistent_license_support
==
414 EmeSessionTypeSupport::NOT_SUPPORTED
);
415 DCHECK(info
.persistent_release_message_support
==
416 EmeSessionTypeSupport::NOT_SUPPORTED
);
419 // persistent-release-message sessions are not currently supported.
420 // http://crbug.com/448888
421 DCHECK(info
.persistent_release_message_support
==
422 EmeSessionTypeSupport::NOT_SUPPORTED
);
424 // If distinctive identifiers are not supported, then no other features can
426 if (info
.distinctive_identifier_support
==
427 EmeFeatureSupport::NOT_SUPPORTED
) {
428 DCHECK(info
.persistent_license_support
!=
429 EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER
);
430 DCHECK(info
.persistent_release_message_support
!=
431 EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER
);
434 // Distinctive identifiers and persistent state can only be reliably blocked
435 // (and therefore be safely configurable) for Pepper-hosted key systems. For
436 // other platforms, (except for the AES decryptor) assume that the CDM can
437 // and will do anything.
438 bool can_block
= info
.use_aes_decryptor
;
439 #if defined(ENABLE_PEPPER_CDMS)
440 DCHECK_EQ(info
.use_aes_decryptor
, info
.pepper_type
.empty());
441 if (!info
.pepper_type
.empty())
445 DCHECK(info
.distinctive_identifier_support
==
446 EmeFeatureSupport::ALWAYS_ENABLED
);
447 DCHECK(info
.persistent_state_support
==
448 EmeFeatureSupport::ALWAYS_ENABLED
);
451 DCHECK(!IsSupportedKeySystem(info
.key_system
))
452 << "Key system '" << info
.key_system
<< "' already registered";
453 DCHECK(!parent_key_system_map_
.count(info
.key_system
))
454 << "'" << info
.key_system
<< "' is already registered as a parent";
455 concrete_key_system_map_
[info
.key_system
] = info
;
456 if (!info
.parent_key_system
.empty()) {
457 DCHECK(!IsConcreteSupportedKeySystem(info
.parent_key_system
))
458 << "Parent '" << info
.parent_key_system
<< "' "
459 << "already registered concrete";
460 DCHECK(!parent_key_system_map_
.count(info
.parent_key_system
))
461 << "Parent '" << info
.parent_key_system
<< "' already registered";
462 parent_key_system_map_
[info
.parent_key_system
] = info
.key_system
;
467 bool KeySystemsImpl::IsConcreteSupportedKeySystem(
468 const std::string
& key_system
) const {
469 DCHECK(thread_checker_
.CalledOnValidThread());
470 return concrete_key_system_map_
.count(key_system
) != 0;
473 bool KeySystemsImpl::IsSupportedContainer(
474 const std::string
& container
,
475 SupportedCodecs key_system_supported_codecs
) const {
476 DCHECK(thread_checker_
.CalledOnValidThread());
477 DCHECK(!container
.empty());
479 // When checking container support for EME, "audio/foo" should be treated the
480 // same as "video/foo". Convert the |container| to achieve this.
481 // TODO(xhwang): Replace this with real checks against supported initDataTypes
482 // combined with supported demuxers.
483 std::string canonical_container
= container
;
484 if (container
.find("audio/") == 0)
485 canonical_container
.replace(0, 6, "video/");
487 // A container is supported iif at least one codec in that container is
489 SupportedCodecs supported_codecs
=
490 GetCodecMaskForContainer(canonical_container
);
491 return (supported_codecs
& key_system_supported_codecs
) != 0;
494 bool KeySystemsImpl::IsSupportedContainerAndCodecs(
495 const std::string
& container
,
496 const std::vector
<std::string
>& codecs
,
497 SupportedCodecs key_system_supported_codecs
) const {
498 DCHECK(thread_checker_
.CalledOnValidThread());
499 DCHECK(!container
.empty());
500 DCHECK(!codecs
.empty());
501 DCHECK(IsSupportedContainer(container
, key_system_supported_codecs
));
503 SupportedCodecs container_supported_codecs
=
504 GetCodecMaskForContainer(container
);
506 for (size_t i
= 0; i
< codecs
.size(); ++i
) {
507 if (codecs
[i
].empty())
510 EmeCodec codec
= GetCodecForString(codecs
[i
]);
512 // Unsupported codec.
513 if (!(codec
& key_system_supported_codecs
))
516 // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
517 if (!(codec
& container_supported_codecs
))
524 bool KeySystemsImpl::IsSupportedInitDataType(
525 const std::string
& key_system
,
526 EmeInitDataType init_data_type
) const {
527 DCHECK(thread_checker_
.CalledOnValidThread());
529 // Locate |key_system|. Only concrete key systems are supported in unprefixed.
530 KeySystemInfoMap::const_iterator key_system_iter
=
531 concrete_key_system_map_
.find(key_system
);
532 if (key_system_iter
== concrete_key_system_map_
.end()) {
537 // Check |init_data_type|.
538 InitDataTypeMask available_init_data_types
=
539 key_system_iter
->second
.supported_init_data_types
;
540 switch (init_data_type
) {
541 case EmeInitDataType::UNKNOWN
:
543 case EmeInitDataType::WEBM
:
544 return (available_init_data_types
& kInitDataTypeMaskWebM
) != 0;
545 case EmeInitDataType::CENC
:
546 return (available_init_data_types
& kInitDataTypeMaskCenc
) != 0;
547 case EmeInitDataType::KEYIDS
:
548 return (available_init_data_types
& kInitDataTypeMaskKeyIds
) != 0;
554 bool KeySystemsImpl::PrefixedIsSupportedKeySystemWithMediaMimeType(
555 const std::string
& mime_type
,
556 const std::vector
<std::string
>& codecs
,
557 const std::string
& key_system
) {
558 DCHECK(thread_checker_
.CalledOnValidThread());
560 const std::string
& concrete_key_system
=
561 PrefixedGetConcreteKeySystemNameFor(key_system
);
563 bool has_type
= !mime_type
.empty();
565 key_systems_support_uma_
.ReportKeySystemQuery(key_system
, has_type
);
567 // Check key system support.
568 KeySystemInfoMap::const_iterator key_system_iter
=
569 concrete_key_system_map_
.find(concrete_key_system
);
570 if (key_system_iter
== concrete_key_system_map_
.end())
573 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, false);
576 DCHECK(codecs
.empty());
580 SupportedCodecs key_system_supported_codecs
=
581 key_system_iter
->second
.supported_codecs
;
583 if (!IsSupportedContainer(mime_type
, key_system_supported_codecs
))
586 if (!codecs
.empty() &&
587 !IsSupportedContainerAndCodecs(
588 mime_type
, codecs
, key_system_supported_codecs
)) {
592 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, true);
597 std::string
KeySystemsImpl::GetKeySystemNameForUMA(
598 const std::string
& key_system
) const {
599 DCHECK(thread_checker_
.CalledOnValidThread());
601 KeySystemNameForUMAMap::const_iterator iter
=
602 key_system_name_for_uma_map_
.find(key_system
);
603 if (iter
== key_system_name_for_uma_map_
.end())
604 return kUnknownKeySystemNameForUMA
;
609 bool KeySystemsImpl::UseAesDecryptor(
610 const std::string
& concrete_key_system
) const {
611 DCHECK(thread_checker_
.CalledOnValidThread());
613 KeySystemInfoMap::const_iterator key_system_iter
=
614 concrete_key_system_map_
.find(concrete_key_system
);
615 if (key_system_iter
== concrete_key_system_map_
.end()) {
616 DLOG(FATAL
) << concrete_key_system
<< " is not a known concrete system";
620 return key_system_iter
->second
.use_aes_decryptor
;
623 #if defined(ENABLE_PEPPER_CDMS)
624 std::string
KeySystemsImpl::GetPepperType(
625 const std::string
& concrete_key_system
) const {
626 DCHECK(thread_checker_
.CalledOnValidThread());
628 KeySystemInfoMap::const_iterator key_system_iter
=
629 concrete_key_system_map_
.find(concrete_key_system
);
630 if (key_system_iter
== concrete_key_system_map_
.end()) {
631 DLOG(FATAL
) << concrete_key_system
<< " is not a known concrete system";
632 return std::string();
635 const std::string
& type
= key_system_iter
->second
.pepper_type
;
636 DLOG_IF(FATAL
, type
.empty()) << concrete_key_system
<< " is not Pepper-based";
641 void KeySystemsImpl::AddContainerMask(
642 const std::string
& container
,
644 DCHECK(thread_checker_
.CalledOnValidThread());
645 DCHECK(!container_to_codec_mask_map_
.count(container
));
646 container_to_codec_mask_map_
[container
] = static_cast<EmeCodec
>(mask
);
649 void KeySystemsImpl::AddCodecMask(
650 EmeMediaType media_type
,
651 const std::string
& codec
,
653 DCHECK(thread_checker_
.CalledOnValidThread());
654 DCHECK(!codec_string_map_
.count(codec
));
655 codec_string_map_
[codec
] = static_cast<EmeCodec
>(mask
);
656 if (media_type
== EmeMediaType::AUDIO
) {
657 audio_codec_mask_
|= mask
;
659 video_codec_mask_
|= mask
;
663 bool KeySystemsImpl::IsSupportedKeySystem(const std::string
& key_system
) const {
664 DCHECK(thread_checker_
.CalledOnValidThread());
665 return concrete_key_system_map_
.count(key_system
) != 0;
668 bool KeySystemsImpl::IsSupportedCodecCombination(
669 const std::string
& key_system
,
670 EmeMediaType media_type
,
671 const std::string
& container_mime_type
,
672 const std::vector
<std::string
>& codecs
) const {
673 DCHECK(thread_checker_
.CalledOnValidThread());
675 // Make sure the container matches |media_type|.
676 SupportedCodecs media_type_codec_mask
= EME_CODEC_NONE
;
677 switch (media_type
) {
678 case EmeMediaType::AUDIO
:
679 if (!StartsWithASCII(container_mime_type
, "audio/", true))
681 media_type_codec_mask
= audio_codec_mask_
;
683 case EmeMediaType::VIDEO
:
684 if (!StartsWithASCII(container_mime_type
, "video/", true))
686 media_type_codec_mask
= video_codec_mask_
;
690 // Look up the key system's supported codecs.
691 KeySystemInfoMap::const_iterator key_system_iter
=
692 concrete_key_system_map_
.find(key_system
);
693 if (key_system_iter
== concrete_key_system_map_
.end()) {
697 SupportedCodecs key_system_codec_mask
=
698 key_system_iter
->second
.supported_codecs
;
700 // Check that the container is supported by the key system. (This check is
701 // necessary because |codecs| may be empty.)
702 SupportedCodecs container_codec_mask
=
703 GetCodecMaskForContainer(container_mime_type
) & media_type_codec_mask
;
704 if ((key_system_codec_mask
& container_codec_mask
) == 0)
707 // Check that the codecs are supported by the key system and container.
708 for (size_t i
= 0; i
< codecs
.size(); i
++) {
709 SupportedCodecs codec
= GetCodecForString(codecs
[i
]);
710 if ((codec
& key_system_codec_mask
& container_codec_mask
) == 0)
717 EmeConfigRule
KeySystemsImpl::GetRobustnessConfigRule(
718 const std::string
& key_system
,
719 EmeMediaType media_type
,
720 const std::string
& requested_robustness
) const {
721 DCHECK(thread_checker_
.CalledOnValidThread());
723 EmeRobustness robustness
= ConvertRobustness(requested_robustness
);
724 if (robustness
== EmeRobustness::INVALID
)
725 return EmeConfigRule::NOT_SUPPORTED
;
726 if (robustness
== EmeRobustness::EMPTY
)
727 return EmeConfigRule::SUPPORTED
;
729 KeySystemInfoMap::const_iterator key_system_iter
=
730 concrete_key_system_map_
.find(key_system
);
731 if (key_system_iter
== concrete_key_system_map_
.end()) {
733 return EmeConfigRule::NOT_SUPPORTED
;
736 EmeRobustness max_robustness
= EmeRobustness::INVALID
;
737 switch (media_type
) {
738 case EmeMediaType::AUDIO
:
739 max_robustness
= key_system_iter
->second
.max_audio_robustness
;
741 case EmeMediaType::VIDEO
:
742 max_robustness
= key_system_iter
->second
.max_video_robustness
;
746 // We can compare robustness levels whenever they are not HW_SECURE_CRYPTO
747 // and SW_SECURE_DECODE in some order. If they are exactly those two then the
748 // robustness requirement is not supported.
749 if ((max_robustness
== EmeRobustness::HW_SECURE_CRYPTO
&&
750 robustness
== EmeRobustness::SW_SECURE_DECODE
) ||
751 (max_robustness
== EmeRobustness::SW_SECURE_DECODE
&&
752 robustness
== EmeRobustness::HW_SECURE_CRYPTO
) ||
753 robustness
> max_robustness
) {
754 return EmeConfigRule::NOT_SUPPORTED
;
757 #if defined(OS_CHROMEOS)
758 if (key_system
== kWidevineKeySystem
) {
759 // Hardware security requires remote attestation.
760 if (robustness
>= EmeRobustness::HW_SECURE_CRYPTO
)
761 return EmeConfigRule::IDENTIFIER_REQUIRED
;
763 // For video, recommend remote attestation if HW_SECURE_ALL is available,
764 // because it enables hardware accelerated decoding.
765 // TODO(sandersd): Only do this when hardware accelerated decoding is
766 // available for the requested codecs.
767 if (media_type
== EmeMediaType::VIDEO
&&
768 max_robustness
== EmeRobustness::HW_SECURE_ALL
) {
769 return EmeConfigRule::IDENTIFIER_RECOMMENDED
;
772 #endif // defined(OS_CHROMEOS)
774 return EmeConfigRule::SUPPORTED
;
777 EmeSessionTypeSupport
KeySystemsImpl::GetPersistentLicenseSessionSupport(
778 const std::string
& key_system
) const {
779 DCHECK(thread_checker_
.CalledOnValidThread());
781 KeySystemInfoMap::const_iterator key_system_iter
=
782 concrete_key_system_map_
.find(key_system
);
783 if (key_system_iter
== concrete_key_system_map_
.end()) {
785 return EmeSessionTypeSupport::INVALID
;
787 return key_system_iter
->second
.persistent_license_support
;
790 EmeSessionTypeSupport
KeySystemsImpl::GetPersistentReleaseMessageSessionSupport(
791 const std::string
& key_system
) const {
792 DCHECK(thread_checker_
.CalledOnValidThread());
794 KeySystemInfoMap::const_iterator key_system_iter
=
795 concrete_key_system_map_
.find(key_system
);
796 if (key_system_iter
== concrete_key_system_map_
.end()) {
798 return EmeSessionTypeSupport::INVALID
;
800 return key_system_iter
->second
.persistent_release_message_support
;
803 EmeFeatureSupport
KeySystemsImpl::GetPersistentStateSupport(
804 const std::string
& key_system
) const {
805 DCHECK(thread_checker_
.CalledOnValidThread());
807 KeySystemInfoMap::const_iterator key_system_iter
=
808 concrete_key_system_map_
.find(key_system
);
809 if (key_system_iter
== concrete_key_system_map_
.end()) {
811 return EmeFeatureSupport::INVALID
;
813 return key_system_iter
->second
.persistent_state_support
;
816 EmeFeatureSupport
KeySystemsImpl::GetDistinctiveIdentifierSupport(
817 const std::string
& key_system
) 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 EmeFeatureSupport::INVALID
;
826 return key_system_iter
->second
.distinctive_identifier_support
;
829 KeySystems
* KeySystems::GetInstance() {
830 return KeySystemsImpl::GetInstance();
833 //------------------------------------------------------------------------------
835 std::string
GetUnprefixedKeySystemName(const std::string
& key_system
) {
836 if (key_system
== kClearKeyKeySystem
)
837 return kUnsupportedClearKeyKeySystem
;
839 if (key_system
== kPrefixedClearKeyKeySystem
)
840 return kClearKeyKeySystem
;
845 std::string
GetPrefixedKeySystemName(const std::string
& key_system
) {
846 DCHECK_NE(key_system
, kPrefixedClearKeyKeySystem
);
848 if (key_system
== kClearKeyKeySystem
)
849 return kPrefixedClearKeyKeySystem
;
854 bool PrefixedIsSupportedConcreteKeySystem(const std::string
& key_system
) {
855 return KeySystemsImpl::GetInstance()->IsConcreteSupportedKeySystem(
859 bool IsSupportedKeySystem(const std::string
& key_system
) {
860 if (!KeySystemsImpl::GetInstance()->IsSupportedKeySystem(key_system
))
863 // TODO(ddorwin): Move this to where we add key systems when prefixed EME is
864 // removed (crbug.com/249976).
865 if (!IsPotentiallySupportedKeySystem(key_system
)) {
866 // If you encounter this path, see the comments for the above function.
867 NOTREACHED() << "Unrecognized key system " << key_system
868 << ". See code comments.";
875 bool IsSupportedKeySystemWithInitDataType(const std::string
& key_system
,
876 EmeInitDataType init_data_type
) {
877 return KeySystemsImpl::GetInstance()->IsSupportedInitDataType(key_system
,
881 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
882 const std::string
& mime_type
,
883 const std::vector
<std::string
>& codecs
,
884 const std::string
& key_system
) {
885 return KeySystemsImpl::GetInstance()
886 ->PrefixedIsSupportedKeySystemWithMediaMimeType(mime_type
, codecs
,
890 std::string
GetKeySystemNameForUMA(const std::string
& key_system
) {
891 return KeySystemsImpl::GetInstance()->GetKeySystemNameForUMA(key_system
);
894 bool CanUseAesDecryptor(const std::string
& concrete_key_system
) {
895 return KeySystemsImpl::GetInstance()->UseAesDecryptor(concrete_key_system
);
898 #if defined(ENABLE_PEPPER_CDMS)
899 std::string
GetPepperType(const std::string
& concrete_key_system
) {
900 return KeySystemsImpl::GetInstance()->GetPepperType(concrete_key_system
);
904 // These two functions are for testing purpose only. The declaration in the
905 // header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
906 // by tests but not non-test code. However, this .cc file is compiled as part of
907 // "media" where "UNIT_TEST" is not defined. So we need to specify
908 // "MEDIA_EXPORT" here again so that they are visible to tests.
910 MEDIA_EXPORT
void AddContainerMask(const std::string
& container
, uint32 mask
) {
911 KeySystemsImpl::GetInstance()->AddContainerMask(container
, mask
);
914 MEDIA_EXPORT
void AddCodecMask(
915 EmeMediaType media_type
,
916 const std::string
& codec
,
918 KeySystemsImpl::GetInstance()->AddCodecMask(media_type
, codec
, mask
);