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 #include <string> 9 10 #include "base/lazy_instance.h" 11 #include "base/logging.h" 12 #include "base/strings/string_util.h" 13 #include "content/public/common/content_client.h" 14 #include "content/public/renderer/content_renderer_client.h" 15 #include "content/public/renderer/key_system_info.h" 16 #include "content/renderer/media/crypto/key_systems_support_uma.h" 17 #include "net/base/mime_util.h" 18 #include "third_party/WebKit/public/platform/WebCString.h" 19 #include "third_party/WebKit/public/platform/WebString.h" 20 21 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. 22 23 namespace content { 24 25 const char kClearKeyKeySystem[] = "webkit-org.w3.clearkey"; 26 27 const char kAudioWebM[] = "audio/webm"; 28 const char kVideoWebM[] = "video/webm"; 29 const char kVorbis[] = "vorbis"; 30 const char kVorbisVP8[] = "vorbis,vp8,vp8.0"; 31 32 #if defined(USE_PROPRIETARY_CODECS) 33 const char kAudioMp4[] = "audio/mp4"; 34 const char kVideoMp4[] = "video/mp4"; 35 const char kMp4a[] = "mp4a"; 36 const char kMp4aAvc1Avc3[] = "mp4a,avc1,avc3"; 37 #endif // defined(USE_PROPRIETARY_CODECS) 38 39 #if !defined(GOOGLE_TV) 40 inline std::string KeySystemNameForUMAInternal( 41 const blink::WebString& key_system) { 42 if (key_system == kClearKeyKeySystem) 43 return "ClearKey"; 44 #if defined(WIDEVINE_CDM_AVAILABLE) 45 if (key_system == kWidevineKeySystem) 46 return "Widevine"; 47 #endif // WIDEVINE_CDM_AVAILABLE 48 return "Unknown"; 49 } 50 #else 51 // Declares the function, which is defined in another file. 52 std::string KeySystemNameForUMAInternal(const blink::WebString& key_system); 53 #endif // !defined(GOOGLE_TV) 54 55 // Convert a WebString to ASCII, falling back on an empty string in the case 56 // of a non-ASCII string. 57 static std::string ToASCIIOrEmpty(const blink::WebString& string) { 58 return IsStringASCII(string) ? UTF16ToASCII(string) : std::string(); 59 } 60 61 static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) { 62 KeySystemInfo info(kClearKeyKeySystem); 63 64 info.supported_types.push_back(std::make_pair(kAudioWebM, kVorbis)); 65 info.supported_types.push_back(std::make_pair(kVideoWebM, kVorbisVP8)); 66 #if defined(USE_PROPRIETARY_CODECS) 67 info.supported_types.push_back(std::make_pair(kAudioMp4, kMp4a)); 68 info.supported_types.push_back(std::make_pair(kVideoMp4, kMp4aAvc1Avc3)); 69 #endif // defined(USE_PROPRIETARY_CODECS) 70 71 info.use_aes_decryptor = true; 72 73 concrete_key_systems->push_back(info); 74 } 75 76 class KeySystems { 77 public: 78 static KeySystems& GetInstance(); 79 80 bool IsConcreteSupportedKeySystem(const std::string& key_system); 81 82 bool IsSupportedKeySystemWithMediaMimeType( 83 const std::string& mime_type, 84 const std::vector<std::string>& codecs, 85 const std::string& key_system); 86 87 bool UseAesDecryptor(const std::string& concrete_key_system); 88 89 #if defined(ENABLE_PEPPER_CDMS) 90 std::string GetPepperType(const std::string& concrete_key_system); 91 #elif defined(OS_ANDROID) 92 std::vector<uint8> GetUUID(const std::string& concrete_key_system); 93 #endif 94 95 private: 96 void AddConcreteSupportedKeySystems( 97 const std::vector<KeySystemInfo>& concrete_key_systems); 98 99 void AddConcreteSupportedKeySystem( 100 const std::string& key_system, 101 bool use_aes_decryptor, 102 #if defined(ENABLE_PEPPER_CDMS) 103 const std::string& pepper_type, 104 #elif defined(OS_ANDROID) 105 const std::vector<uint8>& uuid, 106 #endif 107 const std::vector<KeySystemInfo::ContainerCodecsPair>& supported_types, 108 const std::string& parent_key_system); 109 110 111 friend struct base::DefaultLazyInstanceTraits<KeySystems>; 112 113 typedef base::hash_set<std::string> CodecSet; 114 typedef std::map<std::string, CodecSet> MimeTypeMap; 115 116 struct KeySystemProperties { 117 KeySystemProperties() : use_aes_decryptor(false) {} 118 119 bool use_aes_decryptor; 120 #if defined(ENABLE_PEPPER_CDMS) 121 std::string pepper_type; 122 #elif defined(OS_ANDROID) 123 std::vector<uint8> uuid; 124 #endif 125 MimeTypeMap types; 126 }; 127 128 typedef std::map<std::string, KeySystemProperties> KeySystemPropertiesMap; 129 130 typedef std::map<std::string, std::string> ParentKeySystemMap; 131 132 KeySystems(); 133 ~KeySystems() {} 134 135 void AddSupportedType(const std::string& mime_type, 136 const std::string& codecs_list, 137 KeySystemProperties* properties); 138 139 bool IsSupportedKeySystemWithContainerAndCodec(const std::string& mime_type, 140 const std::string& codec, 141 const std::string& key_system); 142 143 // Map from key system string to capabilities. 144 KeySystemPropertiesMap concrete_key_system_map_; 145 146 // Map from parent key system to the concrete key system that should be used 147 // to represent its capabilities. 148 ParentKeySystemMap parent_key_system_map_; 149 150 KeySystemsSupportUMA key_systems_support_uma_; 151 152 DISALLOW_COPY_AND_ASSIGN(KeySystems); 153 }; 154 155 static base::LazyInstance<KeySystems> g_key_systems = LAZY_INSTANCE_INITIALIZER; 156 157 KeySystems& KeySystems::GetInstance() { 158 return g_key_systems.Get(); 159 } 160 161 // Because we use a LazyInstance, the key systems info must be populated when 162 // the instance is lazily initiated. 163 KeySystems::KeySystems() { 164 std::vector<KeySystemInfo> key_systems_info; 165 GetContentClient()->renderer()->AddKeySystems(&key_systems_info); 166 // Clear Key is always supported. 167 AddClearKey(&key_systems_info); 168 AddConcreteSupportedKeySystems(key_systems_info); 169 #if defined(WIDEVINE_CDM_AVAILABLE) 170 key_systems_support_uma_.AddKeySystemToReport(kWidevineKeySystem); 171 #endif // defined(WIDEVINE_CDM_AVAILABLE) 172 } 173 174 void KeySystems::AddConcreteSupportedKeySystems( 175 const std::vector<KeySystemInfo>& concrete_key_systems) { 176 for (size_t i = 0; i < concrete_key_systems.size(); ++i) { 177 const KeySystemInfo& key_system_info = concrete_key_systems[i]; 178 AddConcreteSupportedKeySystem(key_system_info.key_system, 179 key_system_info.use_aes_decryptor, 180 #if defined(ENABLE_PEPPER_CDMS) 181 key_system_info.pepper_type, 182 #elif defined(OS_ANDROID) 183 key_system_info.uuid, 184 #endif 185 key_system_info.supported_types, 186 key_system_info.parent_key_system); 187 } 188 } 189 190 void KeySystems::AddConcreteSupportedKeySystem( 191 const std::string& concrete_key_system, 192 bool use_aes_decryptor, 193 #if defined(ENABLE_PEPPER_CDMS) 194 const std::string& pepper_type, 195 #elif defined(OS_ANDROID) 196 const std::vector<uint8>& uuid, 197 #endif 198 const std::vector<KeySystemInfo::ContainerCodecsPair>& supported_types, 199 const std::string& parent_key_system) { 200 DCHECK(!IsConcreteSupportedKeySystem(concrete_key_system)) 201 << "Key system '" << concrete_key_system << "' already registered"; 202 DCHECK(parent_key_system_map_.find(concrete_key_system) == 203 parent_key_system_map_.end()) 204 << "'" << concrete_key_system << " is already registered as a parent"; 205 206 KeySystemProperties properties; 207 properties.use_aes_decryptor = use_aes_decryptor; 208 #if defined(ENABLE_PEPPER_CDMS) 209 DCHECK_EQ(use_aes_decryptor, pepper_type.empty()); 210 properties.pepper_type = pepper_type; 211 #elif defined(OS_ANDROID) 212 DCHECK_EQ(use_aes_decryptor, uuid.empty()); 213 DCHECK(use_aes_decryptor || uuid.size() == 16); 214 properties.uuid = uuid; 215 #endif 216 217 for (size_t i = 0; i < supported_types.size(); ++i) { 218 const KeySystemInfo::ContainerCodecsPair& pair = supported_types[i]; 219 const std::string& mime_type = pair.first; 220 const std::string& codecs_list = pair.second; 221 AddSupportedType(mime_type, codecs_list, &properties); 222 } 223 224 concrete_key_system_map_[concrete_key_system] = properties; 225 226 if (!parent_key_system.empty()) { 227 DCHECK(!IsConcreteSupportedKeySystem(parent_key_system)) 228 << "Parent '" << parent_key_system << "' already registered concrete"; 229 DCHECK(parent_key_system_map_.find(parent_key_system) == 230 parent_key_system_map_.end()) 231 << "Parent '" << parent_key_system << "' already registered"; 232 parent_key_system_map_[parent_key_system] = concrete_key_system; 233 } 234 } 235 236 void KeySystems::AddSupportedType(const std::string& mime_type, 237 const std::string& codecs_list, 238 KeySystemProperties* properties) { 239 std::vector<std::string> mime_type_codecs; 240 net::ParseCodecString(codecs_list, &mime_type_codecs, false); 241 242 CodecSet codecs(mime_type_codecs.begin(), mime_type_codecs.end()); 243 244 MimeTypeMap& mime_types_map = properties->types; 245 // mime_types_map must not be repeated for a given key system. 246 DCHECK(mime_types_map.find(mime_type) == mime_types_map.end()); 247 mime_types_map[mime_type] = codecs; 248 } 249 250 bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) { 251 return concrete_key_system_map_.find(key_system) != 252 concrete_key_system_map_.end(); 253 } 254 255 bool KeySystems::IsSupportedKeySystemWithContainerAndCodec( 256 const std::string& mime_type, 257 const std::string& codec, 258 const std::string& key_system) { 259 bool has_type = !mime_type.empty(); 260 DCHECK(has_type || codec.empty()); 261 262 key_systems_support_uma_.ReportKeySystemQuery(key_system, has_type); 263 264 KeySystemPropertiesMap::const_iterator key_system_iter = 265 concrete_key_system_map_.find(key_system); 266 if (key_system_iter == concrete_key_system_map_.end()) 267 return false; 268 269 key_systems_support_uma_.ReportKeySystemSupport(key_system, false); 270 271 if (mime_type.empty()) 272 return true; 273 274 const MimeTypeMap& mime_types_map = key_system_iter->second.types; 275 MimeTypeMap::const_iterator mime_iter = mime_types_map.find(mime_type); 276 if (mime_iter == mime_types_map.end()) 277 return false; 278 279 if (codec.empty()) { 280 key_systems_support_uma_.ReportKeySystemSupport(key_system, true); 281 return true; 282 } 283 284 const CodecSet& codecs = mime_iter->second; 285 if (codecs.find(codec) == codecs.end()) 286 return false; 287 288 key_systems_support_uma_.ReportKeySystemSupport(key_system, true); 289 return true; 290 } 291 292 bool KeySystems::IsSupportedKeySystemWithMediaMimeType( 293 const std::string& mime_type, 294 const std::vector<std::string>& codecs, 295 const std::string& key_system) { 296 // If |key_system| is a parent key_system, use its concrete child. 297 // Otherwise, use |key_system|. 298 std::string concrete_key_system; 299 ParentKeySystemMap::iterator parent_key_system_iter = 300 parent_key_system_map_.find(key_system); 301 if (parent_key_system_iter != parent_key_system_map_.end()) 302 concrete_key_system = parent_key_system_iter->second; 303 else 304 concrete_key_system = key_system; 305 306 if (codecs.empty()) { 307 return IsSupportedKeySystemWithContainerAndCodec( 308 mime_type, std::string(), concrete_key_system); 309 } 310 311 for (size_t i = 0; i < codecs.size(); ++i) { 312 if (!IsSupportedKeySystemWithContainerAndCodec( 313 mime_type, codecs[i], concrete_key_system)) { 314 return false; 315 } 316 } 317 318 return true; 319 } 320 321 bool KeySystems::UseAesDecryptor(const std::string& concrete_key_system) { 322 KeySystemPropertiesMap::iterator key_system_iter = 323 concrete_key_system_map_.find(concrete_key_system); 324 if (key_system_iter == concrete_key_system_map_.end()) { 325 DLOG(FATAL) << concrete_key_system << " is not a known concrete system"; 326 return false; 327 } 328 329 return key_system_iter->second.use_aes_decryptor; 330 } 331 332 #if defined(ENABLE_PEPPER_CDMS) 333 std::string KeySystems::GetPepperType(const std::string& concrete_key_system) { 334 KeySystemPropertiesMap::iterator key_system_iter = 335 concrete_key_system_map_.find(concrete_key_system); 336 if (key_system_iter == concrete_key_system_map_.end()) { 337 DLOG(FATAL) << concrete_key_system << " is not a known concrete system"; 338 return std::string(); 339 } 340 341 const std::string& type = key_system_iter->second.pepper_type; 342 DLOG_IF(FATAL, type.empty()) << concrete_key_system << " is not Pepper-based"; 343 return type; 344 } 345 #elif defined(OS_ANDROID) 346 std::vector<uint8> KeySystems::GetUUID(const std::string& concrete_key_system) { 347 KeySystemPropertiesMap::iterator key_system_iter = 348 concrete_key_system_map_.find(concrete_key_system); 349 if (key_system_iter == concrete_key_system_map_.end()) { 350 DLOG(FATAL) << concrete_key_system << " is not a known concrete system"; 351 return std::vector<uint8>(); 352 } 353 354 return key_system_iter->second.uuid; 355 } 356 #endif 357 358 //------------------------------------------------------------------------------ 359 360 bool IsConcreteSupportedKeySystem(const blink::WebString& key_system) { 361 return KeySystems::GetInstance().IsConcreteSupportedKeySystem( 362 ToASCIIOrEmpty(key_system)); 363 } 364 365 bool IsSupportedKeySystemWithMediaMimeType( 366 const std::string& mime_type, 367 const std::vector<std::string>& codecs, 368 const std::string& key_system) { 369 return KeySystems::GetInstance().IsSupportedKeySystemWithMediaMimeType( 370 mime_type, codecs, key_system); 371 } 372 373 std::string KeySystemNameForUMA(const blink::WebString& key_system) { 374 return KeySystemNameForUMAInternal(key_system); 375 } 376 377 std::string KeySystemNameForUMA(const std::string& key_system) { 378 return KeySystemNameForUMAInternal(blink::WebString::fromUTF8(key_system)); 379 } 380 381 bool CanUseAesDecryptor(const std::string& concrete_key_system) { 382 return KeySystems::GetInstance().UseAesDecryptor(concrete_key_system); 383 } 384 385 #if defined(ENABLE_PEPPER_CDMS) 386 std::string GetPepperType(const std::string& concrete_key_system) { 387 return KeySystems::GetInstance().GetPepperType(concrete_key_system); 388 } 389 #elif defined(OS_ANDROID) 390 std::vector<uint8> GetUUID(const std::string& concrete_key_system) { 391 return KeySystems::GetInstance().GetUUID(concrete_key_system); 392 } 393 #endif 394 395 } // namespace content 396