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 #include <vector> 9 10 #include "base/logging.h" 11 #include "base/strings/string16.h" 12 #include "base/strings/string_split.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "chrome/common/render_messages.h" 15 #include "components/cdm/renderer/widevine_key_systems.h" 16 #include "content/public/renderer/render_thread.h" 17 18 #if defined(OS_ANDROID) 19 #include "components/cdm/renderer/android_key_systems.h" 20 #endif 21 22 #include "widevine_cdm_version.h" // In SHARED_INTERMEDIATE_DIR. 23 24 // The following must be after widevine_cdm_version.h. 25 26 #if defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 27 #include <gnu/libc-version.h> 28 #include "base/version.h" 29 #endif 30 31 using content::KeySystemInfo; 32 using content::SupportedCodecs; 33 34 #if defined(ENABLE_PEPPER_CDMS) 35 static bool IsPepperCdmAvailable( 36 const std::string& pepper_type, 37 std::vector<base::string16>* additional_param_names, 38 std::vector<base::string16>* additional_param_values) { 39 bool is_available = false; 40 content::RenderThread::Get()->Send( 41 new ChromeViewHostMsg_IsInternalPluginAvailableForMimeType( 42 pepper_type, 43 &is_available, 44 additional_param_names, 45 additional_param_values)); 46 47 return is_available; 48 } 49 50 // External Clear Key (used for testing). 51 static void AddExternalClearKey( 52 std::vector<KeySystemInfo>* concrete_key_systems) { 53 static const char kExternalClearKeyKeySystem[] = 54 "org.chromium.externalclearkey"; 55 static const char kExternalClearKeyDecryptOnlyKeySystem[] = 56 "org.chromium.externalclearkey.decryptonly"; 57 static const char kExternalClearKeyFileIOTestKeySystem[] = 58 "org.chromium.externalclearkey.fileiotest"; 59 static const char kExternalClearKeyInitializeFailKeySystem[] = 60 "org.chromium.externalclearkey.initializefail"; 61 static const char kExternalClearKeyCrashKeySystem[] = 62 "org.chromium.externalclearkey.crash"; 63 static const char kExternalClearKeyPepperType[] = 64 "application/x-ppapi-clearkey-cdm"; 65 66 std::vector<base::string16> additional_param_names; 67 std::vector<base::string16> additional_param_values; 68 if (!IsPepperCdmAvailable(kExternalClearKeyPepperType, 69 &additional_param_names, 70 &additional_param_values)) { 71 return; 72 } 73 74 KeySystemInfo info(kExternalClearKeyKeySystem); 75 76 info.supported_codecs = content::EME_CODEC_WEBM_ALL; 77 #if defined(USE_PROPRIETARY_CODECS) 78 info.supported_codecs |= content::EME_CODEC_MP4_ALL; 79 #endif // defined(USE_PROPRIETARY_CODECS) 80 81 info.pepper_type = kExternalClearKeyPepperType; 82 83 concrete_key_systems->push_back(info); 84 85 // Add support of decrypt-only mode in ClearKeyCdm. 86 info.key_system = kExternalClearKeyDecryptOnlyKeySystem; 87 concrete_key_systems->push_back(info); 88 89 // A key system that triggers FileIO test in ClearKeyCdm. 90 info.key_system = kExternalClearKeyFileIOTestKeySystem; 91 concrete_key_systems->push_back(info); 92 93 // A key system that Chrome thinks is supported by ClearKeyCdm, but actually 94 // will be refused by ClearKeyCdm. This is to test the CDM initialization 95 // failure case. 96 info.key_system = kExternalClearKeyInitializeFailKeySystem; 97 concrete_key_systems->push_back(info); 98 99 // A key system that triggers a crash in ClearKeyCdm. 100 info.key_system = kExternalClearKeyCrashKeySystem; 101 concrete_key_systems->push_back(info); 102 } 103 104 #if defined(WIDEVINE_CDM_AVAILABLE) 105 // This function finds "codecs" and parses the value into the vector |codecs|. 106 // Converts the codec strings to UTF-8 since we only expect ASCII strings and 107 // this simplifies the rest of the code in this file. 108 void GetSupportedCodecsForPepperCdm( 109 const std::vector<base::string16>& additional_param_names, 110 const std::vector<base::string16>& additional_param_values, 111 std::vector<std::string>* codecs) { 112 DCHECK(codecs->empty()); 113 DCHECK_EQ(additional_param_names.size(), additional_param_values.size()); 114 for (size_t i = 0; i < additional_param_names.size(); ++i) { 115 if (additional_param_names[i] == 116 base::ASCIIToUTF16(kCdmSupportedCodecsParamName)) { 117 const base::string16& codecs_string16 = additional_param_values[i]; 118 std::string codecs_string; 119 if (!base::UTF16ToUTF8(codecs_string16.c_str(), 120 codecs_string16.length(), 121 &codecs_string)) { 122 DLOG(WARNING) << "Non-UTF-8 codecs string."; 123 // Continue using the best effort conversion. 124 } 125 base::SplitString(codecs_string, 126 kCdmSupportedCodecsValueDelimiter, 127 codecs); 128 break; 129 } 130 } 131 } 132 133 static void AddPepperBasedWidevine( 134 std::vector<KeySystemInfo>* concrete_key_systems) { 135 #if defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 136 Version glibc_version(gnu_get_libc_version()); 137 DCHECK(glibc_version.IsValid()); 138 if (glibc_version.IsOlderThan(WIDEVINE_CDM_MIN_GLIBC_VERSION)) 139 return; 140 #endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) 141 142 std::vector<base::string16> additional_param_names; 143 std::vector<base::string16> additional_param_values; 144 if (!IsPepperCdmAvailable(kWidevineCdmPluginMimeType, 145 &additional_param_names, 146 &additional_param_values)) { 147 DVLOG(1) << "Widevine CDM is not currently available."; 148 return; 149 } 150 151 std::vector<std::string> codecs; 152 GetSupportedCodecsForPepperCdm(additional_param_names, 153 additional_param_values, 154 &codecs); 155 156 SupportedCodecs supported_codecs = content::EME_CODEC_NONE; 157 for (size_t i = 0; i < codecs.size(); ++i) { 158 if (codecs[i] == kCdmSupportedCodecVorbis) 159 supported_codecs |= content::EME_CODEC_WEBM_VORBIS; 160 if (codecs[i] == kCdmSupportedCodecVp8) 161 supported_codecs |= content::EME_CODEC_WEBM_VP8; 162 if (codecs[i] == kCdmSupportedCodecVp9) 163 supported_codecs |= content::EME_CODEC_WEBM_VP9; 164 #if defined(USE_PROPRIETARY_CODECS) 165 if (codecs[i] == kCdmSupportedCodecAac) 166 supported_codecs |= content::EME_CODEC_MP4_AAC; 167 if (codecs[i] == kCdmSupportedCodecAvc1) 168 supported_codecs |= content::EME_CODEC_MP4_AVC1; 169 #endif // defined(USE_PROPRIETARY_CODECS) 170 } 171 172 cdm::AddWidevineWithCodecs(cdm::WIDEVINE, 173 supported_codecs, 174 concrete_key_systems); 175 } 176 #endif // defined(WIDEVINE_CDM_AVAILABLE) 177 #endif // defined(ENABLE_PEPPER_CDMS) 178 179 void AddChromeKeySystems(std::vector<KeySystemInfo>* key_systems_info) { 180 #if defined(ENABLE_PEPPER_CDMS) 181 AddExternalClearKey(key_systems_info); 182 183 #if defined(WIDEVINE_CDM_AVAILABLE) 184 AddPepperBasedWidevine(key_systems_info); 185 #endif // defined(WIDEVINE_CDM_AVAILABLE) 186 #endif // defined(ENABLE_PEPPER_CDMS) 187 188 #if defined(OS_ANDROID) 189 cdm::AddAndroidWidevine(key_systems_info); 190 #endif // defined(OS_ANDROID) 191 } 192