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"
8 #include "base/containers/hash_tables.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "base/threading/thread_checker.h"
13 #include "base/time/time.h"
14 #include "media/base/key_system_info.h"
15 #include "media/base/key_systems_support_uma.h"
16 #include "media/base/media_client.h"
17 #include "media/cdm/key_system_names.h"
18 #include "third_party/widevine/cdm/widevine_cdm_common.h"
22 const char kClearKeyKeySystem
[] = "org.w3.clearkey";
23 const char kPrefixedClearKeyKeySystem
[] = "webkit-org.w3.clearkey";
24 const char kUnsupportedClearKeyKeySystem
[] = "unsupported-org.w3.clearkey";
26 // These names are used by UMA. Do not change them!
27 const char kClearKeyKeySystemNameForUMA
[] = "ClearKey";
28 const char kUnknownKeySystemNameForUMA
[] = "Unknown";
35 // Mapping between containers and their codecs.
36 // Only audio codec can belong to a "audio/*" container. Both audio and video
37 // codecs can belong to a "video/*" container.
38 // TODO(sandersd): This definition only makes sense for prefixed EME. Change it
39 // when prefixed EME is removed. http://crbug.com/249976
40 static NamedCodec kContainerToCodecMasks
[] = {
41 {"audio/webm", EME_CODEC_WEBM_AUDIO_ALL
},
42 {"video/webm", EME_CODEC_WEBM_ALL
},
43 #if defined(USE_PROPRIETARY_CODECS)
44 {"audio/mp4", EME_CODEC_MP4_AUDIO_ALL
},
45 {"video/mp4", EME_CODEC_MP4_ALL
}
46 #endif // defined(USE_PROPRIETARY_CODECS)
49 // Mapping between codec names and enum values.
50 static NamedCodec kCodecStrings
[] = {
51 {"opus", EME_CODEC_WEBM_OPUS
},
52 {"vorbis", EME_CODEC_WEBM_VORBIS
},
53 {"vp8", EME_CODEC_WEBM_VP8
},
54 {"vp8.0", EME_CODEC_WEBM_VP8
},
55 {"vp9", EME_CODEC_WEBM_VP9
},
56 {"vp9.0", EME_CODEC_WEBM_VP9
},
57 #if defined(USE_PROPRIETARY_CODECS)
58 {"mp4a", EME_CODEC_MP4_AAC
},
59 {"avc1", EME_CODEC_MP4_AVC1
},
60 {"avc3", EME_CODEC_MP4_AVC1
}
61 #endif // defined(USE_PROPRIETARY_CODECS)
64 static EmeRobustness
ConvertRobustness(const std::string
& robustness
) {
65 if (robustness
.empty())
66 return EmeRobustness::EMPTY
;
67 if (robustness
== "SW_SECURE_CRYPTO")
68 return EmeRobustness::SW_SECURE_CRYPTO
;
69 if (robustness
== "SW_SECURE_DECODE")
70 return EmeRobustness::SW_SECURE_DECODE
;
71 if (robustness
== "HW_SECURE_CRYPTO")
72 return EmeRobustness::HW_SECURE_CRYPTO
;
73 if (robustness
== "HW_SECURE_DECODE")
74 return EmeRobustness::HW_SECURE_DECODE
;
75 if (robustness
== "HW_SECURE_ALL")
76 return EmeRobustness::HW_SECURE_ALL
;
77 return EmeRobustness::INVALID
;
80 static void AddClearKey(std::vector
<KeySystemInfo
>* concrete_key_systems
) {
82 info
.key_system
= kClearKeyKeySystem
;
84 // On Android, Vorbis, VP8, AAC and AVC1 are supported in MediaCodec:
85 // http://developer.android.com/guide/appendix/media-formats.html
86 // VP9 support is device dependent.
88 info
.supported_init_data_types
=
89 kInitDataTypeMaskWebM
| kInitDataTypeMaskKeyIds
;
90 info
.supported_codecs
= EME_CODEC_WEBM_ALL
;
92 #if defined(OS_ANDROID)
93 // Temporarily disable VP9 support for Android.
94 // TODO(xhwang): Use mime_util.h to query VP9 support on Android.
95 info
.supported_codecs
&= ~EME_CODEC_WEBM_VP9
;
97 // Opus is not supported on Android yet. http://crbug.com/318436.
98 // TODO(sandersd): Check for platform support to set this bit.
99 info
.supported_codecs
&= ~EME_CODEC_WEBM_OPUS
;
100 #endif // defined(OS_ANDROID)
102 #if defined(USE_PROPRIETARY_CODECS)
103 info
.supported_init_data_types
|= kInitDataTypeMaskCenc
;
104 info
.supported_codecs
|= EME_CODEC_MP4_ALL
;
105 #endif // defined(USE_PROPRIETARY_CODECS)
107 info
.max_audio_robustness
= EmeRobustness::EMPTY
;
108 info
.max_video_robustness
= EmeRobustness::EMPTY
;
109 info
.persistent_license_support
= EmeSessionTypeSupport::NOT_SUPPORTED
;
110 info
.persistent_release_message_support
=
111 EmeSessionTypeSupport::NOT_SUPPORTED
;
112 info
.persistent_state_support
= EmeFeatureSupport::NOT_SUPPORTED
;
113 info
.distinctive_identifier_support
= EmeFeatureSupport::NOT_SUPPORTED
;
115 info
.use_aes_decryptor
= true;
117 concrete_key_systems
->push_back(info
);
120 // Returns whether the |key_system| is known to Chromium and is thus likely to
121 // be implemented in an interoperable way.
122 // True is always returned for a |key_system| that begins with "x-".
124 // As with other web platform features, advertising support for a key system
125 // implies that it adheres to a defined and interoperable specification.
127 // To ensure interoperability, implementations of a specific |key_system| string
128 // must conform to a specification for that identifier that defines
129 // key system-specific behaviors not fully defined by the EME specification.
130 // That specification should be provided by the owner of the domain that is the
131 // reverse of the |key_system| string.
132 // This involves more than calling a library, SDK, or platform API.
133 // KeySystemsImpl must be populated appropriately, and there will likely be glue
134 // code to adapt to the API of the library, SDK, or platform API.
136 // Chromium mainline contains this data and glue code for specific key systems,
137 // which should help ensure interoperability with other implementations using
138 // these key systems.
140 // If you need to add support for other key systems, ensure that you have
141 // obtained the specification for how to integrate it with EME, implemented the
142 // appropriate glue/adapter code, and added all the appropriate data to
143 // KeySystemsImpl. Only then should you change this function.
144 static bool IsPotentiallySupportedKeySystem(const std::string
& key_system
) {
145 // Known and supported key systems.
146 if (key_system
== kWidevineKeySystem
)
148 if (key_system
== kClearKey
)
151 // External Clear Key is known and supports suffixes for testing.
152 if (IsExternalClearKey(key_system
))
155 // Chromecast defines behaviors for Cast clients within its reverse domain.
156 const char kChromecastRoot
[] = "com.chromecast";
157 if (IsParentKeySystemOf(kChromecastRoot
, key_system
))
160 // Implementations that do not have a specification or appropriate glue code
161 // can use the "x-" prefix to avoid conflicting with and advertising support
162 // for real key system names. Use is discouraged.
163 const char kExcludedPrefix
[] = "x-";
164 if (key_system
.find(kExcludedPrefix
, 0, arraysize(kExcludedPrefix
) - 1) == 0)
170 class KeySystemsImpl
: public KeySystems
{
172 static KeySystemsImpl
* GetInstance();
174 void UpdateIfNeeded();
176 bool IsConcreteSupportedKeySystem(const std::string
& key_system
) const;
178 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
179 const std::string
& mime_type
,
180 const std::vector
<std::string
>& codecs
,
181 const std::string
& key_system
);
183 std::string
GetKeySystemNameForUMA(const std::string
& key_system
) const;
185 bool UseAesDecryptor(const std::string
& concrete_key_system
) const;
187 #if defined(ENABLE_PEPPER_CDMS)
188 std::string
GetPepperType(const std::string
& concrete_key_system
) const;
191 void AddContainerMask(const std::string
& container
, uint32 mask
);
193 EmeMediaType media_type
,
194 const std::string
& codec
,
197 // Implementation of KeySystems interface.
198 bool IsSupportedKeySystem(const std::string
& key_system
) const override
;
200 bool IsSupportedInitDataType(const std::string
& key_system
,
201 EmeInitDataType init_data_type
) const override
;
203 EmeConfigRule
GetContentTypeConfigRule(
204 const std::string
& key_system
,
205 EmeMediaType media_type
,
206 const std::string
& container_mime_type
,
207 const std::vector
<std::string
>& codecs
) const override
;
209 EmeConfigRule
GetRobustnessConfigRule(
210 const std::string
& key_system
,
211 EmeMediaType media_type
,
212 const std::string
& requested_robustness
) const override
;
214 EmeSessionTypeSupport
GetPersistentLicenseSessionSupport(
215 const std::string
& key_system
) const override
;
217 EmeSessionTypeSupport
GetPersistentReleaseMessageSessionSupport(
218 const std::string
& key_system
) const override
;
220 EmeFeatureSupport
GetPersistentStateSupport(
221 const std::string
& key_system
) const override
;
223 EmeFeatureSupport
GetDistinctiveIdentifierSupport(
224 const std::string
& key_system
) const override
;
228 ~KeySystemsImpl() override
;
230 void InitializeUMAInfo();
232 void UpdateSupportedKeySystems();
234 void AddConcreteSupportedKeySystems(
235 const std::vector
<KeySystemInfo
>& concrete_key_systems
);
237 friend struct base::DefaultLazyInstanceTraits
<KeySystemsImpl
>;
239 typedef base::hash_map
<std::string
, KeySystemInfo
> KeySystemInfoMap
;
240 typedef base::hash_map
<std::string
, std::string
> ParentKeySystemMap
;
241 typedef base::hash_map
<std::string
, SupportedCodecs
> ContainerCodecsMap
;
242 typedef base::hash_map
<std::string
, EmeCodec
> CodecsMap
;
243 typedef base::hash_map
<std::string
, EmeInitDataType
> InitDataTypesMap
;
244 typedef base::hash_map
<std::string
, std::string
> KeySystemNameForUMAMap
;
246 // TODO(sandersd): Separate container enum from codec mask value.
247 // http://crbug.com/417440
248 SupportedCodecs
GetCodecMaskForContainer(
249 const std::string
& container
) const;
250 EmeCodec
GetCodecForString(const std::string
& codec
) const;
252 const std::string
& PrefixedGetConcreteKeySystemNameFor(
253 const std::string
& key_system
) const;
255 // Returns whether a |container| type is supported by checking
256 // |key_system_supported_codecs|.
257 // TODO(xhwang): Update this to actually check initDataType support.
258 bool IsSupportedContainer(const std::string
& container
,
259 SupportedCodecs key_system_supported_codecs
) const;
261 // Returns true if all |codecs| are supported in |container| by checking
262 // |key_system_supported_codecs|.
263 bool IsSupportedContainerAndCodecs(
264 const std::string
& container
,
265 const std::vector
<std::string
>& codecs
,
266 SupportedCodecs key_system_supported_codecs
) const;
268 // Map from key system string to capabilities.
269 KeySystemInfoMap concrete_key_system_map_
;
271 // Map from parent key system to the concrete key system that should be used
272 // to represent its capabilities.
273 ParentKeySystemMap parent_key_system_map_
;
275 KeySystemsSupportUMA key_systems_support_uma_
;
277 ContainerCodecsMap container_to_codec_mask_map_
;
278 CodecsMap codec_string_map_
;
279 KeySystemNameForUMAMap key_system_name_for_uma_map_
;
281 SupportedCodecs audio_codec_mask_
;
282 SupportedCodecs video_codec_mask_
;
284 // Makes sure all methods are called from the same thread.
285 base::ThreadChecker thread_checker_
;
287 DISALLOW_COPY_AND_ASSIGN(KeySystemsImpl
);
290 static base::LazyInstance
<KeySystemsImpl
>::Leaky g_key_systems
=
291 LAZY_INSTANCE_INITIALIZER
;
293 KeySystemsImpl
* KeySystemsImpl::GetInstance() {
294 KeySystemsImpl
* key_systems
= g_key_systems
.Pointer();
295 key_systems
->UpdateIfNeeded();
299 // Because we use a LazyInstance, the key systems info must be populated when
300 // the instance is lazily initiated.
301 KeySystemsImpl::KeySystemsImpl() :
302 audio_codec_mask_(EME_CODEC_AUDIO_ALL
),
303 video_codec_mask_(EME_CODEC_VIDEO_ALL
) {
304 for (size_t i
= 0; i
< arraysize(kContainerToCodecMasks
); ++i
) {
305 const std::string
& name
= kContainerToCodecMasks
[i
].name
;
306 DCHECK(!container_to_codec_mask_map_
.count(name
));
307 container_to_codec_mask_map_
[name
] = kContainerToCodecMasks
[i
].type
;
309 for (size_t i
= 0; i
< arraysize(kCodecStrings
); ++i
) {
310 const std::string
& name
= kCodecStrings
[i
].name
;
311 DCHECK(!codec_string_map_
.count(name
));
312 codec_string_map_
[name
] = kCodecStrings
[i
].type
;
317 // Always update supported key systems during construction.
318 UpdateSupportedKeySystems();
321 KeySystemsImpl::~KeySystemsImpl() {
324 SupportedCodecs
KeySystemsImpl::GetCodecMaskForContainer(
325 const std::string
& container
) const {
326 ContainerCodecsMap::const_iterator iter
=
327 container_to_codec_mask_map_
.find(container
);
328 if (iter
!= container_to_codec_mask_map_
.end())
330 return EME_CODEC_NONE
;
333 EmeCodec
KeySystemsImpl::GetCodecForString(const std::string
& codec
) const {
334 CodecsMap::const_iterator iter
= codec_string_map_
.find(codec
);
335 if (iter
!= codec_string_map_
.end())
337 return EME_CODEC_NONE
;
340 const std::string
& KeySystemsImpl::PrefixedGetConcreteKeySystemNameFor(
341 const std::string
& key_system
) const {
342 ParentKeySystemMap::const_iterator iter
=
343 parent_key_system_map_
.find(key_system
);
344 if (iter
!= parent_key_system_map_
.end())
349 void KeySystemsImpl::InitializeUMAInfo() {
350 DCHECK(thread_checker_
.CalledOnValidThread());
351 DCHECK(key_system_name_for_uma_map_
.empty());
353 std::vector
<KeySystemInfoForUMA
> key_systems_info_for_uma
;
354 if (GetMediaClient())
355 GetMediaClient()->AddKeySystemsInfoForUMA(&key_systems_info_for_uma
);
357 for (const KeySystemInfoForUMA
& info
: key_systems_info_for_uma
) {
358 key_system_name_for_uma_map_
[info
.key_system
] =
359 info
.key_system_name_for_uma
;
360 if (info
.reports_key_system_support_to_uma
)
361 key_systems_support_uma_
.AddKeySystemToReport(info
.key_system
);
364 // Clear Key is always supported.
365 key_system_name_for_uma_map_
[kClearKeyKeySystem
] =
366 kClearKeyKeySystemNameForUMA
;
369 void KeySystemsImpl::UpdateIfNeeded() {
370 if (GetMediaClient() && GetMediaClient()->IsKeySystemsUpdateNeeded())
371 UpdateSupportedKeySystems();
374 void KeySystemsImpl::UpdateSupportedKeySystems() {
375 DCHECK(thread_checker_
.CalledOnValidThread());
376 concrete_key_system_map_
.clear();
377 parent_key_system_map_
.clear();
379 // Build KeySystemInfo.
380 std::vector
<KeySystemInfo
> key_systems_info
;
382 // Add key systems supported by the MediaClient implementation.
383 if (GetMediaClient())
384 GetMediaClient()->AddSupportedKeySystems(&key_systems_info
);
386 // Clear Key is always supported.
387 AddClearKey(&key_systems_info
);
389 AddConcreteSupportedKeySystems(key_systems_info
);
392 void KeySystemsImpl::AddConcreteSupportedKeySystems(
393 const std::vector
<KeySystemInfo
>& concrete_key_systems
) {
394 DCHECK(thread_checker_
.CalledOnValidThread());
395 DCHECK(concrete_key_system_map_
.empty());
396 DCHECK(parent_key_system_map_
.empty());
398 for (const KeySystemInfo
& info
: concrete_key_systems
) {
399 DCHECK(!info
.key_system
.empty());
400 DCHECK(info
.max_audio_robustness
!= EmeRobustness::INVALID
);
401 DCHECK(info
.max_video_robustness
!= EmeRobustness::INVALID
);
402 DCHECK(info
.persistent_license_support
!= EmeSessionTypeSupport::INVALID
);
403 DCHECK(info
.persistent_release_message_support
!=
404 EmeSessionTypeSupport::INVALID
);
405 DCHECK(info
.persistent_state_support
!= EmeFeatureSupport::INVALID
);
406 DCHECK(info
.distinctive_identifier_support
!= EmeFeatureSupport::INVALID
);
408 // Supporting persistent state is a prerequsite for supporting persistent
410 if (info
.persistent_state_support
== EmeFeatureSupport::NOT_SUPPORTED
) {
411 DCHECK(info
.persistent_license_support
==
412 EmeSessionTypeSupport::NOT_SUPPORTED
);
413 DCHECK(info
.persistent_release_message_support
==
414 EmeSessionTypeSupport::NOT_SUPPORTED
);
417 // persistent-release-message sessions are not currently supported.
418 // http://crbug.com/448888
419 DCHECK(info
.persistent_release_message_support
==
420 EmeSessionTypeSupport::NOT_SUPPORTED
);
422 // If distinctive identifiers are not supported, then no other features can
424 if (info
.distinctive_identifier_support
==
425 EmeFeatureSupport::NOT_SUPPORTED
) {
426 DCHECK(info
.persistent_license_support
!=
427 EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER
);
428 DCHECK(info
.persistent_release_message_support
!=
429 EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER
);
432 // Distinctive identifiers and persistent state can only be reliably blocked
433 // (and therefore be safely configurable) for Pepper-hosted key systems. For
434 // other platforms, (except for the AES decryptor) assume that the CDM can
435 // and will do anything.
436 bool can_block
= info
.use_aes_decryptor
;
437 #if defined(ENABLE_PEPPER_CDMS)
438 DCHECK_EQ(info
.use_aes_decryptor
, info
.pepper_type
.empty());
439 if (!info
.pepper_type
.empty())
443 DCHECK(info
.distinctive_identifier_support
==
444 EmeFeatureSupport::ALWAYS_ENABLED
);
445 DCHECK(info
.persistent_state_support
==
446 EmeFeatureSupport::ALWAYS_ENABLED
);
449 DCHECK(!IsSupportedKeySystem(info
.key_system
))
450 << "Key system '" << info
.key_system
<< "' already registered";
451 DCHECK(!parent_key_system_map_
.count(info
.key_system
))
452 << "'" << info
.key_system
<< "' is already registered as a parent";
453 concrete_key_system_map_
[info
.key_system
] = info
;
454 if (!info
.parent_key_system
.empty()) {
455 DCHECK(!IsConcreteSupportedKeySystem(info
.parent_key_system
))
456 << "Parent '" << info
.parent_key_system
<< "' "
457 << "already registered concrete";
458 DCHECK(!parent_key_system_map_
.count(info
.parent_key_system
))
459 << "Parent '" << info
.parent_key_system
<< "' already registered";
460 parent_key_system_map_
[info
.parent_key_system
] = info
.key_system
;
465 bool KeySystemsImpl::IsConcreteSupportedKeySystem(
466 const std::string
& key_system
) const {
467 DCHECK(thread_checker_
.CalledOnValidThread());
468 return concrete_key_system_map_
.count(key_system
) != 0;
471 bool KeySystemsImpl::IsSupportedContainer(
472 const std::string
& container
,
473 SupportedCodecs key_system_supported_codecs
) const {
474 DCHECK(thread_checker_
.CalledOnValidThread());
475 DCHECK(!container
.empty());
477 // When checking container support for EME, "audio/foo" should be treated the
478 // same as "video/foo". Convert the |container| to achieve this.
479 // TODO(xhwang): Replace this with real checks against supported initDataTypes
480 // combined with supported demuxers.
481 std::string canonical_container
= container
;
482 if (container
.find("audio/") == 0)
483 canonical_container
.replace(0, 6, "video/");
485 // A container is supported iif at least one codec in that container is
487 SupportedCodecs supported_codecs
=
488 GetCodecMaskForContainer(canonical_container
);
489 return (supported_codecs
& key_system_supported_codecs
) != 0;
492 bool KeySystemsImpl::IsSupportedContainerAndCodecs(
493 const std::string
& container
,
494 const std::vector
<std::string
>& codecs
,
495 SupportedCodecs key_system_supported_codecs
) const {
496 DCHECK(thread_checker_
.CalledOnValidThread());
497 DCHECK(!container
.empty());
498 DCHECK(!codecs
.empty());
499 DCHECK(IsSupportedContainer(container
, key_system_supported_codecs
));
501 SupportedCodecs container_supported_codecs
=
502 GetCodecMaskForContainer(container
);
504 for (size_t i
= 0; i
< codecs
.size(); ++i
) {
505 if (codecs
[i
].empty())
508 EmeCodec codec
= GetCodecForString(codecs
[i
]);
510 // Unsupported codec.
511 if (!(codec
& key_system_supported_codecs
))
514 // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
515 if (!(codec
& container_supported_codecs
))
522 bool KeySystemsImpl::IsSupportedInitDataType(
523 const std::string
& key_system
,
524 EmeInitDataType init_data_type
) const {
525 DCHECK(thread_checker_
.CalledOnValidThread());
527 // Locate |key_system|. Only concrete key systems are supported in unprefixed.
528 KeySystemInfoMap::const_iterator key_system_iter
=
529 concrete_key_system_map_
.find(key_system
);
530 if (key_system_iter
== concrete_key_system_map_
.end()) {
535 // Check |init_data_type|.
536 InitDataTypeMask available_init_data_types
=
537 key_system_iter
->second
.supported_init_data_types
;
538 switch (init_data_type
) {
539 case EmeInitDataType::UNKNOWN
:
541 case EmeInitDataType::WEBM
:
542 return (available_init_data_types
& kInitDataTypeMaskWebM
) != 0;
543 case EmeInitDataType::CENC
:
544 return (available_init_data_types
& kInitDataTypeMaskCenc
) != 0;
545 case EmeInitDataType::KEYIDS
:
546 return (available_init_data_types
& kInitDataTypeMaskKeyIds
) != 0;
552 bool KeySystemsImpl::PrefixedIsSupportedKeySystemWithMediaMimeType(
553 const std::string
& mime_type
,
554 const std::vector
<std::string
>& codecs
,
555 const std::string
& key_system
) {
556 DCHECK(thread_checker_
.CalledOnValidThread());
558 const std::string
& concrete_key_system
=
559 PrefixedGetConcreteKeySystemNameFor(key_system
);
561 bool has_type
= !mime_type
.empty();
563 key_systems_support_uma_
.ReportKeySystemQuery(key_system
, has_type
);
565 // Check key system support.
566 KeySystemInfoMap::const_iterator key_system_iter
=
567 concrete_key_system_map_
.find(concrete_key_system
);
568 if (key_system_iter
== concrete_key_system_map_
.end())
571 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, false);
574 DCHECK(codecs
.empty());
578 SupportedCodecs key_system_supported_codecs
=
579 key_system_iter
->second
.supported_codecs
;
581 if (!IsSupportedContainer(mime_type
, key_system_supported_codecs
))
584 if (!codecs
.empty() &&
585 !IsSupportedContainerAndCodecs(
586 mime_type
, codecs
, key_system_supported_codecs
)) {
590 key_systems_support_uma_
.ReportKeySystemSupport(key_system
, true);
595 std::string
KeySystemsImpl::GetKeySystemNameForUMA(
596 const std::string
& key_system
) const {
597 DCHECK(thread_checker_
.CalledOnValidThread());
599 KeySystemNameForUMAMap::const_iterator iter
=
600 key_system_name_for_uma_map_
.find(key_system
);
601 if (iter
== key_system_name_for_uma_map_
.end())
602 return kUnknownKeySystemNameForUMA
;
607 bool KeySystemsImpl::UseAesDecryptor(
608 const std::string
& concrete_key_system
) const {
609 DCHECK(thread_checker_
.CalledOnValidThread());
611 KeySystemInfoMap::const_iterator key_system_iter
=
612 concrete_key_system_map_
.find(concrete_key_system
);
613 if (key_system_iter
== concrete_key_system_map_
.end()) {
614 DLOG(ERROR
) << concrete_key_system
<< " is not a known concrete system";
618 return key_system_iter
->second
.use_aes_decryptor
;
621 #if defined(ENABLE_PEPPER_CDMS)
622 std::string
KeySystemsImpl::GetPepperType(
623 const std::string
& concrete_key_system
) const {
624 DCHECK(thread_checker_
.CalledOnValidThread());
626 KeySystemInfoMap::const_iterator key_system_iter
=
627 concrete_key_system_map_
.find(concrete_key_system
);
628 if (key_system_iter
== concrete_key_system_map_
.end()) {
629 DLOG(FATAL
) << concrete_key_system
<< " is not a known concrete system";
630 return std::string();
633 const std::string
& type
= key_system_iter
->second
.pepper_type
;
634 DLOG_IF(FATAL
, type
.empty()) << concrete_key_system
<< " is not Pepper-based";
639 void KeySystemsImpl::AddContainerMask(
640 const std::string
& container
,
642 DCHECK(thread_checker_
.CalledOnValidThread());
643 DCHECK(!container_to_codec_mask_map_
.count(container
));
644 container_to_codec_mask_map_
[container
] = static_cast<EmeCodec
>(mask
);
647 void KeySystemsImpl::AddCodecMask(
648 EmeMediaType media_type
,
649 const std::string
& codec
,
651 DCHECK(thread_checker_
.CalledOnValidThread());
652 DCHECK(!codec_string_map_
.count(codec
));
653 codec_string_map_
[codec
] = static_cast<EmeCodec
>(mask
);
654 if (media_type
== EmeMediaType::AUDIO
) {
655 audio_codec_mask_
|= mask
;
657 video_codec_mask_
|= mask
;
661 bool KeySystemsImpl::IsSupportedKeySystem(const std::string
& key_system
) const {
662 DCHECK(thread_checker_
.CalledOnValidThread());
663 return concrete_key_system_map_
.count(key_system
) != 0;
666 EmeConfigRule
KeySystemsImpl::GetContentTypeConfigRule(
667 const std::string
& key_system
,
668 EmeMediaType media_type
,
669 const std::string
& container_mime_type
,
670 const std::vector
<std::string
>& codecs
) const {
671 DCHECK(thread_checker_
.CalledOnValidThread());
673 // Make sure the container matches |media_type|.
674 SupportedCodecs media_type_codec_mask
= EME_CODEC_NONE
;
675 switch (media_type
) {
676 case EmeMediaType::AUDIO
:
677 if (!base::StartsWith(container_mime_type
, "audio/",
678 base::CompareCase::SENSITIVE
))
679 return EmeConfigRule::NOT_SUPPORTED
;
680 media_type_codec_mask
= audio_codec_mask_
;
682 case EmeMediaType::VIDEO
:
683 if (!base::StartsWith(container_mime_type
, "video/",
684 base::CompareCase::SENSITIVE
))
685 return EmeConfigRule::NOT_SUPPORTED
;
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()) {
695 return EmeConfigRule::NOT_SUPPORTED
;
697 SupportedCodecs key_system_codec_mask
=
698 key_system_iter
->second
.supported_codecs
;
699 #if defined(OS_ANDROID)
700 SupportedCodecs key_system_secure_codec_mask
=
701 key_system_iter
->second
.supported_secure_codecs
;
702 #endif // defined(OS_ANDROID)
705 // Check that the container is supported by the key system. (This check is
706 // necessary because |codecs| may be empty.)
707 SupportedCodecs container_codec_mask
=
708 GetCodecMaskForContainer(container_mime_type
) & media_type_codec_mask
;
709 if ((key_system_codec_mask
& container_codec_mask
) == 0)
710 return EmeConfigRule::NOT_SUPPORTED
;
712 // Check that the codecs are supported by the key system and container.
713 EmeConfigRule support
= EmeConfigRule::SUPPORTED
;
714 for (size_t i
= 0; i
< codecs
.size(); i
++) {
715 SupportedCodecs codec
= GetCodecForString(codecs
[i
]);
716 if ((codec
& key_system_codec_mask
& container_codec_mask
) == 0)
717 return EmeConfigRule::NOT_SUPPORTED
;
718 #if defined(OS_ANDROID)
719 // Check whether the codec supports a hardware-secure mode. The goal is to
720 // prevent mixing of non-hardware-secure codecs with hardware-secure codecs,
721 // since the mode is fixed at CDM creation.
723 // Because the check for regular codec support is early-exit, we don't have
724 // to consider codecs that are only supported in hardware-secure mode. We
725 // could do so, and make use of HW_SECURE_CODECS_REQUIRED, if it turns out
726 // that hardware-secure-only codecs actually exist and are useful.
727 if ((codec
& key_system_secure_codec_mask
) == 0)
728 support
= EmeConfigRule::HW_SECURE_CODECS_NOT_ALLOWED
;
729 #endif // defined(OS_ANDROID)
735 EmeConfigRule
KeySystemsImpl::GetRobustnessConfigRule(
736 const std::string
& key_system
,
737 EmeMediaType media_type
,
738 const std::string
& requested_robustness
) const {
739 DCHECK(thread_checker_
.CalledOnValidThread());
741 EmeRobustness robustness
= ConvertRobustness(requested_robustness
);
742 if (robustness
== EmeRobustness::INVALID
)
743 return EmeConfigRule::NOT_SUPPORTED
;
744 if (robustness
== EmeRobustness::EMPTY
)
745 return EmeConfigRule::SUPPORTED
;
747 KeySystemInfoMap::const_iterator key_system_iter
=
748 concrete_key_system_map_
.find(key_system
);
749 if (key_system_iter
== concrete_key_system_map_
.end()) {
751 return EmeConfigRule::NOT_SUPPORTED
;
754 EmeRobustness max_robustness
= EmeRobustness::INVALID
;
755 switch (media_type
) {
756 case EmeMediaType::AUDIO
:
757 max_robustness
= key_system_iter
->second
.max_audio_robustness
;
759 case EmeMediaType::VIDEO
:
760 max_robustness
= key_system_iter
->second
.max_video_robustness
;
764 // We can compare robustness levels whenever they are not HW_SECURE_CRYPTO
765 // and SW_SECURE_DECODE in some order. If they are exactly those two then the
766 // robustness requirement is not supported.
767 if ((max_robustness
== EmeRobustness::HW_SECURE_CRYPTO
&&
768 robustness
== EmeRobustness::SW_SECURE_DECODE
) ||
769 (max_robustness
== EmeRobustness::SW_SECURE_DECODE
&&
770 robustness
== EmeRobustness::HW_SECURE_CRYPTO
) ||
771 robustness
> max_robustness
) {
772 return EmeConfigRule::NOT_SUPPORTED
;
775 if (key_system
== kWidevineKeySystem
) {
776 #if defined(OS_CHROMEOS)
777 // Hardware security requires remote attestation.
778 if (robustness
>= EmeRobustness::HW_SECURE_CRYPTO
)
779 return EmeConfigRule::IDENTIFIER_REQUIRED
;
781 // For video, recommend remote attestation if HW_SECURE_ALL is available,
782 // because it enables hardware accelerated decoding.
783 // TODO(sandersd): Only do this when hardware accelerated decoding is
784 // available for the requested codecs.
785 if (media_type
== EmeMediaType::VIDEO
&&
786 max_robustness
== EmeRobustness::HW_SECURE_ALL
) {
787 return EmeConfigRule::IDENTIFIER_RECOMMENDED
;
789 #elif defined(OS_ANDROID)
790 if (robustness
> EmeRobustness::SW_SECURE_CRYPTO
)
791 return EmeConfigRule::HW_SECURE_CODECS_REQUIRED
;
792 #endif // defined(OS_CHROMEOS)
795 return EmeConfigRule::SUPPORTED
;
798 EmeSessionTypeSupport
KeySystemsImpl::GetPersistentLicenseSessionSupport(
799 const std::string
& key_system
) const {
800 DCHECK(thread_checker_
.CalledOnValidThread());
802 KeySystemInfoMap::const_iterator key_system_iter
=
803 concrete_key_system_map_
.find(key_system
);
804 if (key_system_iter
== concrete_key_system_map_
.end()) {
806 return EmeSessionTypeSupport::INVALID
;
808 return key_system_iter
->second
.persistent_license_support
;
811 EmeSessionTypeSupport
KeySystemsImpl::GetPersistentReleaseMessageSessionSupport(
812 const std::string
& key_system
) const {
813 DCHECK(thread_checker_
.CalledOnValidThread());
815 KeySystemInfoMap::const_iterator key_system_iter
=
816 concrete_key_system_map_
.find(key_system
);
817 if (key_system_iter
== concrete_key_system_map_
.end()) {
819 return EmeSessionTypeSupport::INVALID
;
821 return key_system_iter
->second
.persistent_release_message_support
;
824 EmeFeatureSupport
KeySystemsImpl::GetPersistentStateSupport(
825 const std::string
& key_system
) const {
826 DCHECK(thread_checker_
.CalledOnValidThread());
828 KeySystemInfoMap::const_iterator key_system_iter
=
829 concrete_key_system_map_
.find(key_system
);
830 if (key_system_iter
== concrete_key_system_map_
.end()) {
832 return EmeFeatureSupport::INVALID
;
834 return key_system_iter
->second
.persistent_state_support
;
837 EmeFeatureSupport
KeySystemsImpl::GetDistinctiveIdentifierSupport(
838 const std::string
& key_system
) const {
839 DCHECK(thread_checker_
.CalledOnValidThread());
841 KeySystemInfoMap::const_iterator key_system_iter
=
842 concrete_key_system_map_
.find(key_system
);
843 if (key_system_iter
== concrete_key_system_map_
.end()) {
845 return EmeFeatureSupport::INVALID
;
847 return key_system_iter
->second
.distinctive_identifier_support
;
850 KeySystems
* KeySystems::GetInstance() {
851 return KeySystemsImpl::GetInstance();
854 //------------------------------------------------------------------------------
856 std::string
GetUnprefixedKeySystemName(const std::string
& key_system
) {
857 if (key_system
== kClearKeyKeySystem
)
858 return kUnsupportedClearKeyKeySystem
;
860 if (key_system
== kPrefixedClearKeyKeySystem
)
861 return kClearKeyKeySystem
;
866 std::string
GetPrefixedKeySystemName(const std::string
& key_system
) {
867 DCHECK_NE(key_system
, kPrefixedClearKeyKeySystem
);
869 if (key_system
== kClearKeyKeySystem
)
870 return kPrefixedClearKeyKeySystem
;
875 bool PrefixedIsSupportedConcreteKeySystem(const std::string
& key_system
) {
876 return KeySystemsImpl::GetInstance()->IsConcreteSupportedKeySystem(
880 bool IsSupportedKeySystem(const std::string
& key_system
) {
881 if (!KeySystemsImpl::GetInstance()->IsSupportedKeySystem(key_system
))
884 // TODO(ddorwin): Move this to where we add key systems when prefixed EME is
885 // removed (crbug.com/249976).
886 if (!IsPotentiallySupportedKeySystem(key_system
)) {
887 // If you encounter this path, see the comments for the above function.
888 NOTREACHED() << "Unrecognized key system " << key_system
889 << ". See code comments.";
896 bool IsSupportedKeySystemWithInitDataType(const std::string
& key_system
,
897 EmeInitDataType init_data_type
) {
898 return KeySystemsImpl::GetInstance()->IsSupportedInitDataType(key_system
,
902 bool PrefixedIsSupportedKeySystemWithMediaMimeType(
903 const std::string
& mime_type
,
904 const std::vector
<std::string
>& codecs
,
905 const std::string
& key_system
) {
906 return KeySystemsImpl::GetInstance()
907 ->PrefixedIsSupportedKeySystemWithMediaMimeType(mime_type
, codecs
,
911 std::string
GetKeySystemNameForUMA(const std::string
& key_system
) {
912 return KeySystemsImpl::GetInstance()->GetKeySystemNameForUMA(key_system
);
915 bool CanUseAesDecryptor(const std::string
& concrete_key_system
) {
916 return KeySystemsImpl::GetInstance()->UseAesDecryptor(concrete_key_system
);
919 #if defined(ENABLE_PEPPER_CDMS)
920 std::string
GetPepperType(const std::string
& concrete_key_system
) {
921 return KeySystemsImpl::GetInstance()->GetPepperType(concrete_key_system
);
925 // These two functions are for testing purpose only. The declaration in the
926 // header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
927 // by tests but not non-test code. However, this .cc file is compiled as part of
928 // "media" where "UNIT_TEST" is not defined. So we need to specify
929 // "MEDIA_EXPORT" here again so that they are visible to tests.
931 MEDIA_EXPORT
void AddContainerMask(const std::string
& container
, uint32 mask
) {
932 KeySystemsImpl::GetInstance()->AddContainerMask(container
, mask
);
935 MEDIA_EXPORT
void AddCodecMask(
936 EmeMediaType media_type
,
937 const std::string
& codec
,
939 KeySystemsImpl::GetInstance()->AddCodecMask(media_type
, codec
, mask
);