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.
4
5 #include "chrome/renderer/media/chrome_key_systems.h"
6
7 #include <string>
8 #include <vector>
9
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 "components/cdm/renderer/widevine_key_systems.h"
16 #include "content/public/renderer/render_thread.h"
17
18 #if defined(OS_ANDROID)
19 #include "components/cdm/renderer/android_key_systems.h"
20 #endif
21
22 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR.
23
24 // The following must be after widevine_cdm_version.h.
25
26 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
27 #include <gnu/libc-version.h>
28 #include "base/version.h"
29 #endif
30
31 using content::KeySystemInfo;
32 using content::SupportedCodecs;
33
34 #if defined(ENABLE_PEPPER_CDMS)
IsPepperCdmAvailable(const std::string & pepper_type,std::vector<base::string16> * additional_param_names,std::vector<base::string16> * additional_param_values)35 static bool IsPepperCdmAvailable(
36 const std::string& pepper_type,
37 std::vector<base::string16>* additional_param_names,
38 std::vector<base::string16>* additional_param_values) {
39 bool is_available = false;
40 content::RenderThread::Get()->Send(
41 new ChromeViewHostMsg_IsInternalPluginAvailableForMimeType(
42 pepper_type,
43 &is_available,
44 additional_param_names,
45 additional_param_values));
46
47 return is_available;
48 }
49
50 // External Clear Key (used for testing).
AddExternalClearKey(std::vector<KeySystemInfo> * concrete_key_systems)51 static void AddExternalClearKey(
52 std::vector<KeySystemInfo>* concrete_key_systems) {
53 static const char kExternalClearKeyKeySystem[] =
54 "org.chromium.externalclearkey";
55 static const char kExternalClearKeyDecryptOnlyKeySystem[] =
56 "org.chromium.externalclearkey.decryptonly";
57 static const char kExternalClearKeyFileIOTestKeySystem[] =
58 "org.chromium.externalclearkey.fileiotest";
59 static const char kExternalClearKeyInitializeFailKeySystem[] =
60 "org.chromium.externalclearkey.initializefail";
61 static const char kExternalClearKeyCrashKeySystem[] =
62 "org.chromium.externalclearkey.crash";
63 static const char kExternalClearKeyPepperType[] =
64 "application/x-ppapi-clearkey-cdm";
65
66 std::vector<base::string16> additional_param_names;
67 std::vector<base::string16> additional_param_values;
68 if (!IsPepperCdmAvailable(kExternalClearKeyPepperType,
69 &additional_param_names,
70 &additional_param_values)) {
71 return;
72 }
73
74 KeySystemInfo info(kExternalClearKeyKeySystem);
75
76 info.supported_codecs = content::EME_CODEC_WEBM_ALL;
77 #if defined(USE_PROPRIETARY_CODECS)
78 info.supported_codecs |= content::EME_CODEC_MP4_ALL;
79 #endif // defined(USE_PROPRIETARY_CODECS)
80
81 info.pepper_type = kExternalClearKeyPepperType;
82
83 concrete_key_systems->push_back(info);
84
85 // Add support of decrypt-only mode in ClearKeyCdm.
86 info.key_system = kExternalClearKeyDecryptOnlyKeySystem;
87 concrete_key_systems->push_back(info);
88
89 // A key system that triggers FileIO test in ClearKeyCdm.
90 info.key_system = kExternalClearKeyFileIOTestKeySystem;
91 concrete_key_systems->push_back(info);
92
93 // A key system that Chrome thinks is supported by ClearKeyCdm, but actually
94 // will be refused by ClearKeyCdm. This is to test the CDM initialization
95 // failure case.
96 info.key_system = kExternalClearKeyInitializeFailKeySystem;
97 concrete_key_systems->push_back(info);
98
99 // A key system that triggers a crash in ClearKeyCdm.
100 info.key_system = kExternalClearKeyCrashKeySystem;
101 concrete_key_systems->push_back(info);
102 }
103
104 #if defined(WIDEVINE_CDM_AVAILABLE)
105 // This function finds "codecs" and parses the value into the vector |codecs|.
106 // Converts the codec strings to UTF-8 since we only expect ASCII strings and
107 // this simplifies the rest of the code in this file.
GetSupportedCodecsForPepperCdm(const std::vector<base::string16> & additional_param_names,const std::vector<base::string16> & additional_param_values,std::vector<std::string> * codecs)108 void GetSupportedCodecsForPepperCdm(
109 const std::vector<base::string16>& additional_param_names,
110 const std::vector<base::string16>& additional_param_values,
111 std::vector<std::string>* codecs) {
112 DCHECK(codecs->empty());
113 DCHECK_EQ(additional_param_names.size(), additional_param_values.size());
114 for (size_t i = 0; i < additional_param_names.size(); ++i) {
115 if (additional_param_names[i] ==
116 base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) {
117 const base::string16& codecs_string16 = additional_param_values[i];
118 std::string codecs_string;
119 if (!base::UTF16ToUTF8(codecs_string16.c_str(),
120 codecs_string16.length(),
121 &codecs_string)) {
122 DLOG(WARNING) << "Non-UTF-8 codecs string.";
123 // Continue using the best effort conversion.
124 }
125 base::SplitString(codecs_string,
126 kCdmSupportedCodecsValueDelimiter,
127 codecs);
128 break;
129 }
130 }
131 }
132
AddPepperBasedWidevine(std::vector<KeySystemInfo> * concrete_key_systems)133 static void AddPepperBasedWidevine(
134 std::vector<KeySystemInfo>* concrete_key_systems) {
135 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
136 Version glibc_version(gnu_get_libc_version());
137 DCHECK(glibc_version.IsValid());
138 if (glibc_version.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION))
139 return;
140 #endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
141
142 std::vector<base::string16> additional_param_names;
143 std::vector<base::string16> additional_param_values;
144 if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType,
145 &additional_param_names,
146 &additional_param_values)) {
147 DVLOG(1) << "Widevine CDM is not currently available.";
148 return;
149 }
150
151 std::vector<std::string> codecs;
152 GetSupportedCodecsForPepperCdm(additional_param_names,
153 additional_param_values,
154 &codecs);
155
156 SupportedCodecs supported_codecs = content::EME_CODEC_NONE;
157 for (size_t i = 0; i < codecs.size(); ++i) {
158 if (codecs[i] == kCdmSupportedCodecVorbis)
159 supported_codecs |= content::EME_CODEC_WEBM_VORBIS;
160 if (codecs[i] == kCdmSupportedCodecVp8)
161 supported_codecs |= content::EME_CODEC_WEBM_VP8;
162 if (codecs[i] == kCdmSupportedCodecVp9)
163 supported_codecs |= content::EME_CODEC_WEBM_VP9;
164 #if defined(USE_PROPRIETARY_CODECS)
165 if (codecs[i] == kCdmSupportedCodecAac)
166 supported_codecs |= content::EME_CODEC_MP4_AAC;
167 if (codecs[i] == kCdmSupportedCodecAvc1)
168 supported_codecs |= content::EME_CODEC_MP4_AVC1;
169 #endif // defined(USE_PROPRIETARY_CODECS)
170 }
171
172 cdm::AddWidevineWithCodecs(cdm::WIDEVINE,
173 supported_codecs,
174 concrete_key_systems);
175 }
176 #endif // defined(WIDEVINE_CDM_AVAILABLE)
177 #endif // defined(ENABLE_PEPPER_CDMS)
178
AddChromeKeySystems(std::vector<KeySystemInfo> * key_systems_info)179 void AddChromeKeySystems(std::vector<KeySystemInfo>* key_systems_info) {
180 #if defined(ENABLE_PEPPER_CDMS)
181 AddExternalClearKey(key_systems_info);
182
183 #if defined(WIDEVINE_CDM_AVAILABLE)
184 AddPepperBasedWidevine(key_systems_info);
185 #endif // defined(WIDEVINE_CDM_AVAILABLE)
186 #endif // defined(ENABLE_PEPPER_CDMS)
187
188 #if defined(OS_ANDROID)
189 cdm::AddAndroidWidevine(key_systems_info);
190 #endif // defined(OS_ANDROID)
191 }
192