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 "content/renderer/media/crypto/key_systems.h"
9 #include "base/lazy_instance.h"
10 #include "base/logging.h"
11 #include "base/strings/string_util.h"
12 #include "content/public/common/content_client.h"
13 #include "content/public/renderer/content_renderer_client.h"
14 #include "content/public/renderer/key_system_info.h"
15 #include "content/renderer/media/crypto/key_systems_info.h"
16 #include "net/base/mime_util.h"
17 #include "third_party/WebKit/public/platform/WebCString.h"
18 #include "third_party/WebKit/public/platform/WebString.h"
22 // Convert a WebString to ASCII, falling back on an empty string in the case
23 // of a non-ASCII string.
24 static std::string ToASCIIOrEmpty(const WebKit::WebString& string) {
25 return IsStringASCII(string) ? UTF16ToASCII(string) : std::string();
28 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
30 const char kAudioWebM[] = "audio/webm";
31 const char kVideoWebM[] = "video/webm";
32 const char kVorbis[] = "vorbis";
33 const char kVorbisVP8[] = "vorbis,vp8,vp8.0";
35 #if defined(USE_PROPRIETARY_CODECS)
36 const char kAudioMp4[] = "audio/mp4";
37 const char kVideoMp4[] = "video/mp4";
38 const char kMp4a[] = "mp4a";
39 const char kMp4aAvc1Avc3[] = "mp4a,avc1,avc3";
40 #endif // defined(USE_PROPRIETARY_CODECS)
42 static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
43 KeySystemInfo info(kClearKeyKeySystem);
45 info.supported_types.push_back(std::make_pair(kAudioWebM, kVorbis));
46 info.supported_types.push_back(std::make_pair(kVideoWebM, kVorbisVP8));
47 #if defined(USE_PROPRIETARY_CODECS)
48 info.supported_types.push_back(std::make_pair(kAudioMp4, kMp4a));
49 info.supported_types.push_back(std::make_pair(kVideoMp4, kMp4aAvc1Avc3));
50 #endif // defined(USE_PROPRIETARY_CODECS)
52 info.use_aes_decryptor = true;
54 concrete_key_systems->push_back(info);
59 static KeySystems& GetInstance();
61 bool IsConcreteSupportedKeySystem(const std::string& key_system);
63 bool IsSupportedKeySystemWithMediaMimeType(
64 const std::string& mime_type,
65 const std::vector<std::string>& codecs,
66 const std::string& key_system);
68 bool UseAesDecryptor(const std::string& concrete_key_system);
70 #if defined(ENABLE_PEPPER_CDMS)
71 std::string GetPepperType(const std::string& concrete_key_system);
72 #elif defined(OS_ANDROID)
73 std::vector<uint8> GetUUID(const std::string& concrete_key_system);
77 void AddConcreteSupportedKeySystems(
78 const std::vector<KeySystemInfo>& concrete_key_systems);
80 void AddConcreteSupportedKeySystem(
81 const std::string& key_system,
82 bool use_aes_decryptor,
83 #if defined(ENABLE_PEPPER_CDMS)
84 const std::string& pepper_type,
85 #elif defined(OS_ANDROID)
86 const std::vector<uint8>& uuid,
88 const std::vector<KeySystemInfo::ContainerCodecsPair>& supported_types,
89 const std::string& parent_key_system);
92 friend struct base::DefaultLazyInstanceTraits<KeySystems>;
94 typedef base::hash_set<std::string> CodecSet;
95 typedef std::map<std::string, CodecSet> MimeTypeMap;
97 struct KeySystemProperties {
98 KeySystemProperties() : use_aes_decryptor(false) {}
100 bool use_aes_decryptor;
101 #if defined(ENABLE_PEPPER_CDMS)
102 std::string pepper_type;
103 #elif defined(OS_ANDROID)
104 std::vector<uint8> uuid;
109 typedef std::map<std::string, KeySystemProperties> KeySystemPropertiesMap;
111 typedef std::map<std::string, std::string> ParentKeySystemMap;
116 void AddSupportedType(const std::string& mime_type,
117 const std::string& codecs_list,
118 KeySystemProperties* properties);
120 bool IsSupportedKeySystemWithContainerAndCodec(
121 const std::string& mime_type,
122 const std::string& codec,
123 const std::string& key_system);
125 // Map from key system string to capabilities.
126 KeySystemPropertiesMap concrete_key_system_map_;
128 // Map from parent key system to the concrete key system that should be used
129 // to represent its capabilities.
130 ParentKeySystemMap parent_key_system_map_;
132 DISALLOW_COPY_AND_ASSIGN(KeySystems);
135 static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER;
137 KeySystems& KeySystems::GetInstance() {
138 return g_key_systems.Get();
141 // Because we use a LazyInstance, the key systems info must be populated when
142 // the instance is lazily initiated.
143 KeySystems::KeySystems() {
144 std::vector<KeySystemInfo> key_systems_info;
145 GetContentClient()->renderer()->AddKeySystems(&key_systems_info);
146 // Clear Key is always supported.
147 AddClearKey(&key_systems_info);
148 AddConcreteSupportedKeySystems(key_systems_info);
151 void KeySystems::AddConcreteSupportedKeySystems(
152 const std::vector<KeySystemInfo>& concrete_key_systems) {
153 for (size_t i = 0; i < concrete_key_systems.size(); ++i) {
154 const KeySystemInfo& key_system_info = concrete_key_systems[i];
155 AddConcreteSupportedKeySystem(key_system_info.key_system,
156 key_system_info.use_aes_decryptor,
157 #if defined(ENABLE_PEPPER_CDMS)
158 key_system_info.pepper_type,
159 #elif defined(OS_ANDROID)
160 key_system_info.uuid,
162 key_system_info.supported_types,
163 key_system_info.parent_key_system);
167 void KeySystems::AddConcreteSupportedKeySystem(
168 const std::string& concrete_key_system,
169 bool use_aes_decryptor,
170 #if defined(ENABLE_PEPPER_CDMS)
171 const std::string& pepper_type,
172 #elif defined(OS_ANDROID)
173 const std::vector<uint8>& uuid,
175 const std::vector<KeySystemInfo::ContainerCodecsPair>& supported_types,
176 const std::string& parent_key_system) {
177 DCHECK(!IsConcreteSupportedKeySystem(concrete_key_system))
178 << "Key system '" << concrete_key_system << "' already registered";
179 DCHECK(parent_key_system_map_.find(concrete_key_system) ==
180 parent_key_system_map_.end())
181 << "'" << concrete_key_system << " is already registered as a parent";
183 KeySystemProperties properties;
184 properties.use_aes_decryptor = use_aes_decryptor;
185 #if defined(ENABLE_PEPPER_CDMS)
186 DCHECK_EQ(use_aes_decryptor, pepper_type.empty());
187 properties.pepper_type = pepper_type;
188 #elif defined(OS_ANDROID)
189 DCHECK_EQ(use_aes_decryptor, uuid.empty());
190 DCHECK(use_aes_decryptor || uuid.size() == 16);
191 properties.uuid = uuid;
194 for (size_t i = 0; i < supported_types.size(); ++i) {
195 const KeySystemInfo::ContainerCodecsPair& pair = supported_types[i];
196 const std::string& mime_type = pair.first;
197 const std::string& codecs_list = pair.second;
198 AddSupportedType(mime_type, codecs_list, &properties);
201 concrete_key_system_map_[concrete_key_system] = properties;
203 if (!parent_key_system.empty()) {
204 DCHECK(!IsConcreteSupportedKeySystem(parent_key_system))
205 << "Parent '" << parent_key_system << "' already registered concrete";
206 DCHECK(parent_key_system_map_.find(parent_key_system) ==
207 parent_key_system_map_.end())
208 << "Parent '" << parent_key_system << "' already registered";
209 parent_key_system_map_[parent_key_system] = concrete_key_system;
213 void KeySystems::AddSupportedType(const std::string& mime_type,
214 const std::string& codecs_list,
215 KeySystemProperties* properties) {
216 std::vector<std::string> mime_type_codecs;
217 net::ParseCodecString(codecs_list, &mime_type_codecs, false);
219 CodecSet codecs(mime_type_codecs.begin(), mime_type_codecs.end());
220 // Support the MIME type string alone, without codec(s) specified.
221 codecs.insert(std::string());
223 MimeTypeMap& mime_types_map = properties->types;
224 // mime_types_map must not be repeated for a given key system.
225 DCHECK(mime_types_map.find(mime_type) == mime_types_map.end());
226 mime_types_map[mime_type] = codecs;
229 bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) {
230 return concrete_key_system_map_.find(key_system) !=
231 concrete_key_system_map_.end();
234 bool KeySystems::IsSupportedKeySystemWithContainerAndCodec(
235 const std::string& mime_type,
236 const std::string& codec,
237 const std::string& key_system) {
238 KeySystemPropertiesMap::const_iterator key_system_iter =
239 concrete_key_system_map_.find(key_system);
240 if (key_system_iter == concrete_key_system_map_.end())
243 const MimeTypeMap& mime_types_map = key_system_iter->second.types;
244 MimeTypeMap::const_iterator mime_iter = mime_types_map.find(mime_type);
245 if (mime_iter == mime_types_map.end())
248 const CodecSet& codecs = mime_iter->second;
249 return (codecs.find(codec) != codecs.end());
252 bool KeySystems::IsSupportedKeySystemWithMediaMimeType(
253 const std::string& mime_type,
254 const std::vector<std::string>& codecs,
255 const std::string& key_system) {
256 // If |key_system| is a parent key_system, use its concrete child.
257 // Otherwise, use |key_system|.
258 std::string concrete_key_system;
259 ParentKeySystemMap::iterator parent_key_system_iter =
260 parent_key_system_map_.find(key_system);
261 if (parent_key_system_iter != parent_key_system_map_.end())
262 concrete_key_system = parent_key_system_iter->second;
264 concrete_key_system = key_system;
266 if (codecs.empty()) {
267 return IsSupportedKeySystemWithContainerAndCodec(
268 mime_type, std::string(), concrete_key_system);
271 for (size_t i = 0; i < codecs.size(); ++i) {
272 if (!IsSupportedKeySystemWithContainerAndCodec(
273 mime_type, codecs[i], concrete_key_system)) {
281 bool KeySystems::UseAesDecryptor(const std::string& concrete_key_system) {
282 KeySystemPropertiesMap::iterator key_system_iter =
283 concrete_key_system_map_.find(concrete_key_system);
284 if (key_system_iter == concrete_key_system_map_.end()) {
285 DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
289 return key_system_iter->second.use_aes_decryptor;
292 #if defined(ENABLE_PEPPER_CDMS)
293 std::string KeySystems::GetPepperType(const std::string& concrete_key_system) {
294 KeySystemPropertiesMap::iterator key_system_iter =
295 concrete_key_system_map_.find(concrete_key_system);
296 if (key_system_iter == concrete_key_system_map_.end()) {
297 DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
298 return std::string();
301 const std::string& type = key_system_iter->second.pepper_type;
302 DLOG_IF(FATAL, type.empty()) << concrete_key_system << " is not Pepper-based";
305 #elif defined(OS_ANDROID)
306 std::vector<uint8> KeySystems::GetUUID(const std::string& concrete_key_system) {
307 KeySystemPropertiesMap::iterator key_system_iter =
308 concrete_key_system_map_.find(concrete_key_system);
309 if (key_system_iter == concrete_key_system_map_.end()) {
310 DLOG(FATAL) << concrete_key_system << " is not a known concrete system";
311 return std::vector<uint8>();
314 return key_system_iter->second.uuid;
318 //------------------------------------------------------------------------------
320 bool IsConcreteSupportedKeySystem(const WebKit::WebString& key_system) {
321 return KeySystems::GetInstance().IsConcreteSupportedKeySystem(
322 ToASCIIOrEmpty(key_system));
325 bool IsSupportedKeySystemWithMediaMimeType(
326 const std::string& mime_type,
327 const std::vector<std::string>& codecs,
328 const std::string& key_system) {
329 return KeySystems::GetInstance().IsSupportedKeySystemWithMediaMimeType(
330 mime_type, codecs, key_system);
333 std::string KeySystemNameForUMA(const WebKit::WebString& key_system) {
334 return KeySystemNameForUMAInternal(key_system);
337 bool CanUseAesDecryptor(const std::string& concrete_key_system) {
338 return KeySystems::GetInstance().UseAesDecryptor(concrete_key_system);
341 #if defined(ENABLE_PEPPER_CDMS)
342 std::string GetPepperType(const std::string& concrete_key_system) {
343 return KeySystems::GetInstance().GetPepperType(concrete_key_system);
345 #elif defined(OS_ANDROID)
346 std::vector<uint8> GetUUID(const std::string& concrete_key_system) {
347 return KeySystems::GetInstance().GetUUID(concrete_key_system);
351 } // namespace content