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 9 #include "base/logging.h" 10 #include "base/strings/string16.h" 11 #include "base/strings/string_split.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "chrome/common/render_messages.h" 14 #include "content/public/renderer/render_thread.h" 15 16 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. 17 18 // The following must be after widevine_cdm_version.h. 19 20 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 21 #include <gnu/libc-version.h> 22 #include "base/version.h" 23 #endif 24 25 #if defined(OS_ANDROID) 26 #include "chrome/common/encrypted_media_messages_android.h" 27 #endif 28 29 using content::KeySystemInfo; 30 31 const char kAudioWebM[] = "audio/webm"; 32 const char kVideoWebM[] = "video/webm"; 33 const char kVorbis[] = "vorbis"; 34 const char kVorbisVP8[] = "vorbis,vp8,vp8.0"; 35 36 #if defined(USE_PROPRIETARY_CODECS) 37 const char kAudioMp4[] = "audio/mp4"; 38 const char kVideoMp4[] = "video/mp4"; 39 const char kMp4a[] = "mp4a"; 40 #if defined(WIDEVINE_CDM_AVAILABLE) 41 const char kAvc1Avc3[] = "avc1,avc3"; 42 #endif // WIDEVINE_CDM_AVAILABLE 43 const char kMp4aAvc1Avc3[] = "mp4a,avc1,avc3"; 44 #endif // defined(USE_PROPRIETARY_CODECS) 45 46 #if defined(ENABLE_PEPPER_CDMS) 47 static bool IsPepperCdmRegistered( 48 const std::string& pepper_type, 49 std::vector<base::string16>* additional_param_names, 50 std::vector<base::string16>* additional_param_values) { 51 bool is_registered = false; 52 content::RenderThread::Get()->Send( 53 new ChromeViewHostMsg_IsInternalPluginRegisteredForMimeType( 54 pepper_type, 55 &is_registered, 56 additional_param_names, 57 additional_param_values)); 58 59 return is_registered; 60 } 61 62 // External Clear Key (used for testing). 63 static void AddExternalClearKey( 64 std::vector<KeySystemInfo>* concrete_key_systems) { 65 static const char kExternalClearKeyKeySystem[] = 66 "org.chromium.externalclearkey"; 67 static const char kExternalClearKeyDecryptOnlyKeySystem[] = 68 "org.chromium.externalclearkey.decryptonly"; 69 static const char kExternalClearKeyInitializeFailKeySystem[] = 70 "org.chromium.externalclearkey.initializefail"; 71 static const char kExternalClearKeyPepperType[] = 72 "application/x-ppapi-clearkey-cdm"; 73 74 std::vector<base::string16> additional_param_names; 75 std::vector<base::string16> additional_param_values; 76 if (!IsPepperCdmRegistered(kExternalClearKeyPepperType, 77 &additional_param_names, 78 &additional_param_values)) { 79 return; 80 } 81 82 KeySystemInfo info(kExternalClearKeyKeySystem); 83 84 info.supported_types.push_back(std::make_pair(kAudioWebM, kVorbis)); 85 info.supported_types.push_back(std::make_pair(kVideoWebM, kVorbisVP8)); 86 #if defined(USE_PROPRIETARY_CODECS) 87 info.supported_types.push_back(std::make_pair(kAudioMp4, kMp4a)); 88 info.supported_types.push_back(std::make_pair(kVideoMp4, kMp4aAvc1Avc3)); 89 #endif // defined(USE_PROPRIETARY_CODECS) 90 info.pepper_type = kExternalClearKeyPepperType; 91 92 concrete_key_systems->push_back(info); 93 94 // A key system that Chrome thinks is supported by ClearKeyCdm, but actually 95 // will be refused by ClearKeyCdm. This is to test the CDM initialization 96 // failure case. 97 info.key_system = kExternalClearKeyInitializeFailKeySystem; 98 concrete_key_systems->push_back(info); 99 100 // Add support of decrypt-only mode in ClearKeyCdm. 101 info.key_system = kExternalClearKeyDecryptOnlyKeySystem; 102 concrete_key_systems->push_back(info); 103 } 104 #endif // defined(ENABLE_PEPPER_CDMS) 105 106 107 #if defined(WIDEVINE_CDM_AVAILABLE) 108 enum WidevineCdmType { 109 WIDEVINE, 110 WIDEVINE_HR, 111 #if defined(OS_ANDROID) 112 WIDEVINE_HR_NON_COMPOSITING, 113 #endif 114 }; 115 116 // Defines bitmask values used to specify supported codecs. 117 // Each value represents a codec within a specific container. 118 // The mask values are stored in a SupportedCodecs. 119 typedef uint32 SupportedCodecs; 120 enum SupportedCodecMasks { 121 NO_CODECS = 0, 122 WEBM_VP8_AND_VORBIS = 1 << 0, 123 #if defined(USE_PROPRIETARY_CODECS) 124 MP4_AAC = 1 << 1, 125 MP4_AVC1 = 1 << 2, 126 MP4_CODECS = (MP4_AAC | MP4_AVC1), 127 #endif // defined(USE_PROPRIETARY_CODECS) 128 }; 129 130 #if defined(OS_ANDROID) 131 #define COMPILE_ASSERT_MATCHING_ENUM(name) \ 132 COMPILE_ASSERT(static_cast<int>(name) == \ 133 static_cast<int>(android::name), \ 134 mismatching_enums) 135 COMPILE_ASSERT_MATCHING_ENUM(WEBM_VP8_AND_VORBIS); 136 COMPILE_ASSERT_MATCHING_ENUM(MP4_AAC); 137 COMPILE_ASSERT_MATCHING_ENUM(MP4_AVC1); 138 #undef COMPILE_ASSERT_MATCHING_ENUM 139 140 static const uint8 kWidevineUuid[16] = { 141 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, 142 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED }; 143 #else 144 static bool IsWidevineHrSupported() { 145 // TODO(jrummell): Need to call CheckPlatformState() but it is 146 // asynchronous, and needs to be done in the browser. 147 return false; 148 } 149 #endif 150 151 // Return |name|'s parent key system. 152 static std::string GetDirectParentName(std::string name) { 153 int last_period = name.find_last_of('.'); 154 DCHECK_GT(last_period, 0); 155 return name.substr(0, last_period); 156 } 157 158 static void AddWidevineWithCodecs( 159 WidevineCdmType widevine_cdm_type, 160 SupportedCodecs supported_codecs, 161 std::vector<KeySystemInfo>* concrete_key_systems) { 162 163 KeySystemInfo info(kWidevineKeySystem); 164 165 switch (widevine_cdm_type) { 166 case WIDEVINE: 167 // For standard Widevine, add parent name. 168 info.parent_key_system = GetDirectParentName(kWidevineKeySystem); 169 break; 170 case WIDEVINE_HR: 171 info.key_system.append(".hr"); 172 break; 173 #if defined(OS_ANDROID) 174 case WIDEVINE_HR_NON_COMPOSITING: 175 info.key_system.append(".hrnoncompositing"); 176 break; 177 #endif 178 default: 179 NOTREACHED(); 180 } 181 182 if (supported_codecs & WEBM_VP8_AND_VORBIS) { 183 info.supported_types.push_back(std::make_pair(kAudioWebM, kVorbis)); 184 info.supported_types.push_back(std::make_pair(kVideoWebM, kVorbisVP8)); 185 } 186 187 #if defined(USE_PROPRIETARY_CODECS) 188 if (supported_codecs & MP4_CODECS) { 189 // MP4 container is supported for audio and video if any codec is supported. 190 bool is_aac_supported = (supported_codecs & MP4_AAC) != NO_CODECS; 191 bool is_avc1_supported = (supported_codecs & MP4_AVC1) != NO_CODECS; 192 const char* video_codecs = is_avc1_supported ? 193 (is_aac_supported ? kMp4aAvc1Avc3 : kAvc1Avc3) : 194 ""; 195 const char* audio_codecs = is_aac_supported ? kMp4a : ""; 196 197 info.supported_types.push_back(std::make_pair(kAudioMp4, audio_codecs)); 198 info.supported_types.push_back(std::make_pair(kVideoMp4, video_codecs)); 199 } 200 #endif // defined(USE_PROPRIETARY_CODECS) 201 202 #if defined(ENABLE_PEPPER_CDMS) 203 info.pepper_type = kWidevineCdmPluginMimeType; 204 #elif defined(OS_ANDROID) 205 info.uuid.assign(kWidevineUuid, kWidevineUuid + arraysize(kWidevineUuid)); 206 #endif // defined(ENABLE_PEPPER_CDMS) 207 208 concrete_key_systems->push_back(info); 209 } 210 211 #if defined(ENABLE_PEPPER_CDMS) 212 // When the adapter is registered, a name-value pair is inserted in 213 // additional_param_* that lists the supported codecs. The name is "codecs" and 214 // the value is a comma-delimited list of codecs. 215 // This function finds "codecs" and parses the value into the vector |codecs|. 216 // Converts the codec strings to UTF-8 since we only expect ASCII strings and 217 // this simplifies the rest of the code in this file. 218 void GetSupportedCodecs( 219 const std::vector<base::string16>& additional_param_names, 220 const std::vector<base::string16>& additional_param_values, 221 std::vector<std::string>* codecs) { 222 DCHECK(codecs->empty()); 223 DCHECK_EQ(additional_param_names.size(), additional_param_values.size()); 224 for (size_t i = 0; i < additional_param_names.size(); ++i) { 225 if (additional_param_names[i] == 226 base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) { 227 const base::string16& codecs_string16 = additional_param_values[i]; 228 std::string codecs_string; 229 if (!base::UTF16ToUTF8(codecs_string16.c_str(), 230 codecs_string16.length(), 231 &codecs_string)) { 232 DLOG(WARNING) << "Non-UTF-8 codecs string."; 233 // Continue using the best effort conversion. 234 } 235 base::SplitString(codecs_string, 236 kCdmSupportedCodecsValueDelimiter, 237 codecs); 238 break; 239 } 240 } 241 } 242 243 static void AddPepperBasedWidevine( 244 std::vector<KeySystemInfo>* concrete_key_systems) { 245 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 246 Version glibc_version(gnu_get_libc_version()); 247 DCHECK(glibc_version.IsValid()); 248 if (glibc_version.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION)) 249 return; 250 #endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 251 252 std::vector<base::string16> additional_param_names; 253 std::vector<base::string16> additional_param_values; 254 if (!IsPepperCdmRegistered(kWidevineCdmPluginMimeType, 255 &additional_param_names, 256 &additional_param_values)) { 257 DVLOG(1) << "Widevine CDM is not currently available."; 258 return; 259 } 260 261 std::vector<std::string> codecs; 262 GetSupportedCodecs(additional_param_names, additional_param_values, &codecs); 263 264 SupportedCodecs supported_codecs = NO_CODECS; 265 for (size_t i = 0; i < codecs.size(); ++i) { 266 // TODO(ddorwin): Break up VP8 and Vorbis. For now, "vp8" implies both. 267 if (codecs[i] == kCdmSupportedCodecVp8) 268 supported_codecs |= WEBM_VP8_AND_VORBIS; 269 #if defined(USE_PROPRIETARY_CODECS) 270 if (codecs[i] == kCdmSupportedCodecAac) 271 supported_codecs |= MP4_AAC; 272 if (codecs[i] == kCdmSupportedCodecAvc1) 273 supported_codecs |= MP4_AVC1; 274 #endif // defined(USE_PROPRIETARY_CODECS) 275 } 276 277 AddWidevineWithCodecs(WIDEVINE, supported_codecs, concrete_key_systems); 278 279 if (IsWidevineHrSupported()) 280 AddWidevineWithCodecs(WIDEVINE_HR, supported_codecs, concrete_key_systems); 281 } 282 #elif defined(OS_ANDROID) 283 static void AddAndroidWidevine( 284 std::vector<KeySystemInfo>* concrete_key_systems) { 285 SupportedKeySystemRequest request; 286 SupportedKeySystemResponse response; 287 288 request.uuid.insert(request.uuid.begin(), kWidevineUuid, 289 kWidevineUuid + arraysize(kWidevineUuid)); 290 #if defined(USE_PROPRIETARY_CODECS) 291 request.codecs = static_cast<android::SupportedCodecs>( 292 android::MP4_AAC | android::MP4_AVC1); 293 #endif // defined(USE_PROPRIETARY_CODECS) 294 content::RenderThread::Get()->Send( 295 new ChromeViewHostMsg_GetSupportedKeySystems(request, &response)); 296 DCHECK_EQ(response.compositing_codecs >> 3, 0) << "unrecognized codec"; 297 DCHECK_EQ(response.non_compositing_codecs >> 3, 0) << "unrecognized codec"; 298 if (response.compositing_codecs != android::NO_SUPPORTED_CODECS) { 299 AddWidevineWithCodecs( 300 WIDEVINE, 301 static_cast<SupportedCodecs>(response.compositing_codecs), 302 concrete_key_systems); 303 } 304 305 if (response.non_compositing_codecs != android::NO_SUPPORTED_CODECS) { 306 AddWidevineWithCodecs( 307 WIDEVINE_HR_NON_COMPOSITING, 308 static_cast<SupportedCodecs>(response.non_compositing_codecs), 309 concrete_key_systems); 310 } 311 } 312 #endif // defined(ENABLE_PEPPER_CDMS) 313 #endif // defined(WIDEVINE_CDM_AVAILABLE) 314 315 void AddChromeKeySystems(std::vector<KeySystemInfo>* key_systems_info) { 316 #if defined(ENABLE_PEPPER_CDMS) 317 AddExternalClearKey(key_systems_info); 318 #endif 319 320 #if defined(WIDEVINE_CDM_AVAILABLE) 321 #if defined(ENABLE_PEPPER_CDMS) 322 AddPepperBasedWidevine(key_systems_info); 323 #elif defined(OS_ANDROID) 324 AddAndroidWidevine(key_systems_info); 325 #endif 326 #endif 327 } 328