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 "chrome/renderer/media/chrome_key_systems.h"
10 #include "base/logging.h"
11 #include "base/strings/string16.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "chrome/common/render_messages.h"
15 #include "content/public/renderer/render_thread.h"
17 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
19 // The following must be after widevine_cdm_version.h.
21 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
22 #include <gnu/libc-version.h>
23 #include "base/version.h"
26 #if defined(OS_ANDROID)
27 #include "chrome/common/encrypted_media_messages_android.h"
30 using content::KeySystemInfo
;
31 using content::SupportedCodecs
;
33 #if defined(ENABLE_PEPPER_CDMS)
34 static bool IsPepperCdmRegistered(
35 const std::string
& pepper_type
,
36 std::vector
<base::string16
>* additional_param_names
,
37 std::vector
<base::string16
>* additional_param_values
) {
38 bool is_registered
= false;
39 content::RenderThread::Get()->Send(
40 new ChromeViewHostMsg_IsInternalPluginRegisteredForMimeType(
43 additional_param_names
,
44 additional_param_values
));
49 // External Clear Key (used for testing).
50 static void AddExternalClearKey(
51 std::vector
<KeySystemInfo
>* concrete_key_systems
) {
52 static const char kExternalClearKeyKeySystem
[] =
53 "org.chromium.externalclearkey";
54 static const char kExternalClearKeyDecryptOnlyKeySystem
[] =
55 "org.chromium.externalclearkey.decryptonly";
56 static const char kExternalClearKeyFileIOTestKeySystem
[] =
57 "org.chromium.externalclearkey.fileiotest";
58 static const char kExternalClearKeyInitializeFailKeySystem
[] =
59 "org.chromium.externalclearkey.initializefail";
60 static const char kExternalClearKeyCrashKeySystem
[] =
61 "org.chromium.externalclearkey.crash";
62 static const char kExternalClearKeyPepperType
[] =
63 "application/x-ppapi-clearkey-cdm";
65 std::vector
<base::string16
> additional_param_names
;
66 std::vector
<base::string16
> additional_param_values
;
67 if (!IsPepperCdmRegistered(kExternalClearKeyPepperType
,
68 &additional_param_names
,
69 &additional_param_values
)) {
73 KeySystemInfo
info(kExternalClearKeyKeySystem
);
75 info
.supported_codecs
= content::EME_CODEC_WEBM_ALL
;
76 #if defined(USE_PROPRIETARY_CODECS)
77 info
.supported_codecs
|= content::EME_CODEC_MP4_ALL
;
78 #endif // defined(USE_PROPRIETARY_CODECS)
80 info
.pepper_type
= kExternalClearKeyPepperType
;
82 concrete_key_systems
->push_back(info
);
84 // Add support of decrypt-only mode in ClearKeyCdm.
85 info
.key_system
= kExternalClearKeyDecryptOnlyKeySystem
;
86 concrete_key_systems
->push_back(info
);
88 // A key system that triggers FileIO test in ClearKeyCdm.
89 info
.key_system
= kExternalClearKeyFileIOTestKeySystem
;
90 concrete_key_systems
->push_back(info
);
92 // A key system that Chrome thinks is supported by ClearKeyCdm, but actually
93 // will be refused by ClearKeyCdm. This is to test the CDM initialization
95 info
.key_system
= kExternalClearKeyInitializeFailKeySystem
;
96 concrete_key_systems
->push_back(info
);
98 // A key system that triggers a crash in ClearKeyCdm.
99 info
.key_system
= kExternalClearKeyCrashKeySystem
;
100 concrete_key_systems
->push_back(info
);
102 #endif // defined(ENABLE_PEPPER_CDMS)
105 #if defined(WIDEVINE_CDM_AVAILABLE)
106 enum WidevineCdmType
{
109 #if defined(OS_ANDROID)
110 WIDEVINE_HR_NON_COMPOSITING
,
114 #if !defined(OS_ANDROID)
115 static bool IsWidevineHrSupported() {
116 // TODO(jrummell): Need to call CheckPlatformState() but it is
117 // asynchronous, and needs to be done in the browser.
122 // Return |name|'s parent key system.
123 static std::string
GetDirectParentName(std::string name
) {
124 int last_period
= name
.find_last_of('.');
125 DCHECK_GT(last_period
, 0);
126 return name
.substr(0, last_period
);
129 static void AddWidevineWithCodecs(
130 WidevineCdmType widevine_cdm_type
,
131 SupportedCodecs supported_codecs
,
132 std::vector
<KeySystemInfo
>* concrete_key_systems
) {
133 KeySystemInfo
info(kWidevineKeySystem
);
135 switch (widevine_cdm_type
) {
137 // For standard Widevine, add parent name.
138 info
.parent_key_system
= GetDirectParentName(kWidevineKeySystem
);
141 info
.key_system
.append(".hr");
143 #if defined(OS_ANDROID)
144 case WIDEVINE_HR_NON_COMPOSITING
:
145 info
.key_system
.append(".hrnoncompositing");
152 // TODO(xhwang): A container or an initDataType may be supported even though
153 // there are no codecs supported in that container. Fix this when we support
155 info
.supported_codecs
= supported_codecs
;
157 #if defined(ENABLE_PEPPER_CDMS)
158 info
.pepper_type
= kWidevineCdmPluginMimeType
;
159 #endif // defined(ENABLE_PEPPER_CDMS)
161 concrete_key_systems
->push_back(info
);
164 #if defined(ENABLE_PEPPER_CDMS)
165 // When the adapter is registered, a name-value pair is inserted in
166 // additional_param_* that lists the supported codecs. The name is "codecs" and
167 // the value is a comma-delimited list of codecs.
168 // This function finds "codecs" and parses the value into the vector |codecs|.
169 // Converts the codec strings to UTF-8 since we only expect ASCII strings and
170 // this simplifies the rest of the code in this file.
171 void GetSupportedCodecs(
172 const std::vector
<base::string16
>& additional_param_names
,
173 const std::vector
<base::string16
>& additional_param_values
,
174 std::vector
<std::string
>* codecs
) {
175 DCHECK(codecs
->empty());
176 DCHECK_EQ(additional_param_names
.size(), additional_param_values
.size());
177 for (size_t i
= 0; i
< additional_param_names
.size(); ++i
) {
178 if (additional_param_names
[i
] ==
179 base::ASCIIToUTF16(kCdmSupportedCodecsParamName
)) {
180 const base::string16
& codecs_string16
= additional_param_values
[i
];
181 std::string codecs_string
;
182 if (!base::UTF16ToUTF8(codecs_string16
.c_str(),
183 codecs_string16
.length(),
185 DLOG(WARNING
) << "Non-UTF-8 codecs string.";
186 // Continue using the best effort conversion.
188 base::SplitString(codecs_string
,
189 kCdmSupportedCodecsValueDelimiter
,
196 static void AddPepperBasedWidevine(
197 std::vector
<KeySystemInfo
>* concrete_key_systems
) {
198 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
199 Version
glibc_version(gnu_get_libc_version());
200 DCHECK(glibc_version
.IsValid());
201 if (glibc_version
.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION
))
203 #endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
205 std::vector
<base::string16
> additional_param_names
;
206 std::vector
<base::string16
> additional_param_values
;
207 if (!IsPepperCdmRegistered(kWidevineCdmPluginMimeType
,
208 &additional_param_names
,
209 &additional_param_values
)) {
210 DVLOG(1) << "Widevine CDM is not currently available.";
214 std::vector
<std::string
> codecs
;
215 GetSupportedCodecs(additional_param_names
, additional_param_values
, &codecs
);
217 SupportedCodecs supported_codecs
= content::EME_CODEC_NONE
;
218 for (size_t i
= 0; i
< codecs
.size(); ++i
) {
219 if (codecs
[i
] == kCdmSupportedCodecVorbis
)
220 supported_codecs
|= content::EME_CODEC_WEBM_VORBIS
;
221 if (codecs
[i
] == kCdmSupportedCodecVp8
)
222 supported_codecs
|= content::EME_CODEC_WEBM_VP8
;
223 if (codecs
[i
] == kCdmSupportedCodecVp9
)
224 supported_codecs
|= content::EME_CODEC_WEBM_VP9
;
225 #if defined(USE_PROPRIETARY_CODECS)
226 if (codecs
[i
] == kCdmSupportedCodecAac
)
227 supported_codecs
|= content::EME_CODEC_MP4_AAC
;
228 if (codecs
[i
] == kCdmSupportedCodecAvc1
)
229 supported_codecs
|= content::EME_CODEC_MP4_AVC1
;
230 #endif // defined(USE_PROPRIETARY_CODECS)
233 AddWidevineWithCodecs(WIDEVINE
, supported_codecs
, concrete_key_systems
);
235 if (IsWidevineHrSupported())
236 AddWidevineWithCodecs(WIDEVINE_HR
, supported_codecs
, concrete_key_systems
);
238 #elif defined(OS_ANDROID)
239 static void AddAndroidWidevine(
240 std::vector
<KeySystemInfo
>* concrete_key_systems
) {
241 SupportedKeySystemRequest request
;
242 SupportedKeySystemResponse response
;
244 request
.key_system
= kWidevineKeySystem
;
245 request
.codecs
= content::EME_CODEC_WEBM_ALL
| content::EME_CODEC_MP4_ALL
;
246 content::RenderThread::Get()->Send(
247 new ChromeViewHostMsg_GetSupportedKeySystems(request
, &response
));
248 DCHECK(response
.compositing_codecs
& content::EME_CODEC_ALL
)
249 << "unrecognized codec";
250 DCHECK(response
.non_compositing_codecs
& content::EME_CODEC_ALL
)
251 << "unrecognized codec";
252 if (response
.compositing_codecs
!= content::EME_CODEC_NONE
) {
253 AddWidevineWithCodecs(
255 static_cast<SupportedCodecs
>(response
.compositing_codecs
),
256 concrete_key_systems
);
259 if (response
.non_compositing_codecs
!= content::EME_CODEC_NONE
) {
260 AddWidevineWithCodecs(
261 WIDEVINE_HR_NON_COMPOSITING
,
262 static_cast<SupportedCodecs
>(response
.non_compositing_codecs
),
263 concrete_key_systems
);
266 #endif // defined(ENABLE_PEPPER_CDMS)
267 #endif // defined(WIDEVINE_CDM_AVAILABLE)
269 void AddChromeKeySystems(std::vector
<KeySystemInfo
>* key_systems_info
) {
270 #if defined(ENABLE_PEPPER_CDMS)
271 AddExternalClearKey(key_systems_info
);
274 #if defined(WIDEVINE_CDM_AVAILABLE)
275 #if defined(ENABLE_PEPPER_CDMS)
276 AddPepperBasedWidevine(key_systems_info
);
277 #elif defined(OS_ANDROID)
278 AddAndroidWidevine(key_systems_info
);