- add sources.
[platform/framework/web/crosswalk.git] / src / content / renderer / media / crypto / key_systems.cc
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 "content/renderer/media/crypto/key_systems.h"
6
7 #include <map>
8
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"
19
20 namespace content {
21
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();
26 }
27
28 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey";
29
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";
34
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)
41
42 static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
43   KeySystemInfo info(kClearKeyKeySystem);
44
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)
51
52   info.use_aes_decryptor = true;
53
54   concrete_key_systems->push_back(info);
55 }
56
57 class KeySystems {
58  public:
59   static KeySystems& GetInstance();
60
61   bool IsConcreteSupportedKeySystem(const std::string& key_system);
62
63   bool IsSupportedKeySystemWithMediaMimeType(
64       const std::string& mime_type,
65       const std::vector<std::string>& codecs,
66       const std::string& key_system);
67
68   bool UseAesDecryptor(const std::string& concrete_key_system);
69
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);
74 #endif
75
76  private:
77   void AddConcreteSupportedKeySystems(
78       const std::vector<KeySystemInfo>& concrete_key_systems);
79
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,
87 #endif
88       const std::vector<KeySystemInfo::ContainerCodecsPair>& supported_types,
89       const std::string& parent_key_system);
90
91
92   friend struct base::DefaultLazyInstanceTraits<KeySystems>;
93
94   typedef base::hash_set<std::string> CodecSet;
95   typedef std::map<std::string, CodecSet> MimeTypeMap;
96
97   struct KeySystemProperties {
98     KeySystemProperties() : use_aes_decryptor(false) {}
99
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;
105 #endif
106     MimeTypeMap types;
107   };
108
109   typedef std::map<std::string, KeySystemProperties> KeySystemPropertiesMap;
110
111   typedef std::map<std::string, std::string> ParentKeySystemMap;
112
113   KeySystems();
114   ~KeySystems() {}
115
116   void AddSupportedType(const std::string& mime_type,
117                         const std::string& codecs_list,
118                         KeySystemProperties* properties);
119
120   bool IsSupportedKeySystemWithContainerAndCodec(
121       const std::string& mime_type,
122       const std::string& codec,
123       const std::string& key_system);
124
125   // Map from key system string to capabilities.
126   KeySystemPropertiesMap concrete_key_system_map_;
127
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_;
131
132   DISALLOW_COPY_AND_ASSIGN(KeySystems);
133 };
134
135 static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER;
136
137 KeySystems& KeySystems::GetInstance() {
138   return g_key_systems.Get();
139 }
140
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);
149 }
150
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,
161 #endif
162                                   key_system_info.supported_types,
163                                   key_system_info.parent_key_system);
164   }
165 }
166
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,
174 #endif
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";
182
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;
192 #endif
193
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);
199   }
200
201   concrete_key_system_map_[concrete_key_system] = properties;
202
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;
210   }
211 }
212
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);
218
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());
222
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;
227 }
228
229 bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) {
230   return concrete_key_system_map_.find(key_system) !=
231       concrete_key_system_map_.end();
232 }
233
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())
241     return false;
242
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())
246     return false;
247
248   const CodecSet& codecs = mime_iter->second;
249   return (codecs.find(codec) != codecs.end());
250 }
251
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;
263   else
264     concrete_key_system = key_system;
265
266   if (codecs.empty()) {
267     return IsSupportedKeySystemWithContainerAndCodec(
268         mime_type, std::string(), concrete_key_system);
269   }
270
271   for (size_t i = 0; i < codecs.size(); ++i) {
272     if (!IsSupportedKeySystemWithContainerAndCodec(
273             mime_type, codecs[i], concrete_key_system)) {
274       return false;
275     }
276   }
277
278   return true;
279 }
280
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";
286       return false;
287   }
288
289   return key_system_iter->second.use_aes_decryptor;
290 }
291
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();
299   }
300
301   const std::string& type = key_system_iter->second.pepper_type;
302   DLOG_IF(FATAL, type.empty()) << concrete_key_system << " is not Pepper-based";
303   return type;
304 }
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>();
312   }
313
314   return key_system_iter->second.uuid;
315 }
316 #endif
317
318 //------------------------------------------------------------------------------
319
320 bool IsConcreteSupportedKeySystem(const WebKit::WebString& key_system) {
321   return KeySystems::GetInstance().IsConcreteSupportedKeySystem(
322       ToASCIIOrEmpty(key_system));
323 }
324
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);
331 }
332
333 std::string KeySystemNameForUMA(const WebKit::WebString& key_system) {
334   return KeySystemNameForUMAInternal(key_system);
335 }
336
337 bool CanUseAesDecryptor(const std::string& concrete_key_system) {
338   return KeySystems::GetInstance().UseAesDecryptor(concrete_key_system);
339 }
340
341 #if defined(ENABLE_PEPPER_CDMS)
342 std::string GetPepperType(const std::string& concrete_key_system) {
343   return KeySystems::GetInstance().GetPepperType(concrete_key_system);
344 }
345 #elif defined(OS_ANDROID)
346 std::vector<uint8> GetUUID(const std::string& concrete_key_system) {
347   return KeySystems::GetInstance().GetUUID(concrete_key_system);
348 }
349 #endif
350
351 }  // namespace content