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