Add "" as a valid value for --builder_type in bisect_perf_regression.py.
[chromium-blink-merge.git] / media / blink / webencryptedmediaclient_impl.cc
blob462a3e830105b17981a6021aabf76271e0c447ba
1 // Copyright 2014 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.
5 #include "webencryptedmediaclient_impl.h"
7 #include "base/logging.h"
8 #include "base/metrics/histogram.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "media/base/key_systems.h"
12 #include "media/base/media_permission.h"
13 #include "net/base/mime_util.h"
14 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h"
15 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h"
16 #include "third_party/WebKit/public/platform/WebString.h"
17 #include "third_party/WebKit/public/platform/WebVector.h"
18 #include "webcontentdecryptionmodule_impl.h"
19 #include "webcontentdecryptionmoduleaccess_impl.h"
21 namespace media {
23 // These names are used by UMA.
24 const char kKeySystemSupportUMAPrefix[] =
25 "Media.EME.RequestMediaKeySystemAccess.";
27 static bool IsSupportedContentType(
28 const std::string& key_system,
29 const std::string& mime_type,
30 const std::string& codecs) {
31 // Per RFC 6838, "Both top-level type and subtype names are case-insensitive."
32 // TODO(sandersd): Check that |container| matches the capability:
33 // - audioCapabilitys: audio/mp4 or audio/webm.
34 // - videoCapabilitys: video/mp4 or video/webm.
35 // http://crbug.com/457384.
36 std::string container = base::StringToLowerASCII(mime_type);
38 // Check that |codecs| are supported as specified (e.g. "mp4a.40.2").
39 std::vector<std::string> codec_vector;
40 net::ParseCodecString(codecs, &codec_vector, false);
41 if (!net::AreSupportedMediaCodecs(codec_vector))
42 return false;
44 // IsSupportedKeySystemWithMediaMimeType() only works with base codecs
45 // (e.g. "mp4a"), so reparse |codecs| to get the base only.
46 codec_vector.clear();
47 net::ParseCodecString(codecs, &codec_vector, true);
48 return IsSupportedKeySystemWithMediaMimeType(container, codec_vector,
49 key_system);
52 static bool GetSupportedConfiguration(
53 const std::string& key_system,
54 const blink::WebMediaKeySystemConfiguration& candidate,
55 const blink::WebSecurityOrigin& security_origin,
56 blink::WebMediaKeySystemConfiguration* accumulated_configuration) {
57 if (!candidate.initDataTypes.isEmpty()) {
58 std::vector<blink::WebString> init_data_types;
60 for (size_t i = 0; i < candidate.initDataTypes.size(); i++) {
61 const blink::WebString& init_data_type = candidate.initDataTypes[i];
62 if (init_data_type.isEmpty())
63 return false;
64 if (base::IsStringASCII(init_data_type) &&
65 IsSupportedKeySystemWithInitDataType(
66 key_system, base::UTF16ToASCII(init_data_type))) {
67 init_data_types.push_back(init_data_type);
71 if (init_data_types.empty())
72 return false;
74 accumulated_configuration->initDataTypes = init_data_types;
77 // TODO(sandersd): Implement distinctiveIdentifier and persistentState checks.
78 if (candidate.distinctiveIdentifier !=
79 blink::WebMediaKeySystemConfiguration::Requirement::Optional ||
80 candidate.persistentState !=
81 blink::WebMediaKeySystemConfiguration::Requirement::Optional) {
82 return false;
85 if (!candidate.audioCapabilities.isEmpty()) {
86 std::vector<blink::WebMediaKeySystemMediaCapability> audio_capabilities;
88 for (size_t i = 0; i < candidate.audioCapabilities.size(); i++) {
89 const blink::WebMediaKeySystemMediaCapability& capabilities =
90 candidate.audioCapabilities[i];
91 if (capabilities.mimeType.isEmpty())
92 return false;
93 if (!base::IsStringASCII(capabilities.mimeType) ||
94 !base::IsStringASCII(capabilities.codecs) ||
95 !IsSupportedContentType(
96 key_system, base::UTF16ToASCII(capabilities.mimeType),
97 base::UTF16ToASCII(capabilities.codecs))) {
98 continue;
100 // TODO(sandersd): Support robustness.
101 if (!capabilities.robustness.isEmpty())
102 continue;
103 audio_capabilities.push_back(capabilities);
106 if (audio_capabilities.empty())
107 return false;
109 accumulated_configuration->audioCapabilities = audio_capabilities;
112 if (!candidate.videoCapabilities.isEmpty()) {
113 std::vector<blink::WebMediaKeySystemMediaCapability> video_capabilities;
115 for (size_t i = 0; i < candidate.videoCapabilities.size(); i++) {
116 const blink::WebMediaKeySystemMediaCapability& capabilities =
117 candidate.videoCapabilities[i];
118 if (capabilities.mimeType.isEmpty())
119 return false;
120 if (!base::IsStringASCII(capabilities.mimeType) ||
121 !base::IsStringASCII(capabilities.codecs) ||
122 !IsSupportedContentType(
123 key_system, base::UTF16ToASCII(capabilities.mimeType),
124 base::UTF16ToASCII(capabilities.codecs))) {
125 continue;
127 // TODO(sandersd): Support robustness.
128 if (!capabilities.robustness.isEmpty())
129 continue;
130 video_capabilities.push_back(capabilities);
133 if (video_capabilities.empty())
134 return false;
136 accumulated_configuration->videoCapabilities = video_capabilities;
139 // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state
140 // if required. Make sure that future checks are silent.
141 // http://crbug.com/446263.
143 return true;
146 // Report usage of key system to UMA. There are 2 different counts logged:
147 // 1. The key system is requested.
148 // 2. The requested key system and options are supported.
149 // Each stat is only reported once per renderer frame per key system.
150 // Note that WebEncryptedMediaClientImpl is only created once by each
151 // renderer frame.
152 class WebEncryptedMediaClientImpl::Reporter {
153 public:
154 enum KeySystemSupportStatus {
155 KEY_SYSTEM_REQUESTED = 0,
156 KEY_SYSTEM_SUPPORTED = 1,
157 KEY_SYSTEM_SUPPORT_STATUS_COUNT
160 explicit Reporter(const std::string& key_system_for_uma)
161 : uma_name_(kKeySystemSupportUMAPrefix + key_system_for_uma),
162 is_request_reported_(false),
163 is_support_reported_(false) {}
164 ~Reporter() {}
166 void ReportRequested() {
167 if (is_request_reported_)
168 return;
169 Report(KEY_SYSTEM_REQUESTED);
170 is_request_reported_ = true;
173 void ReportSupported() {
174 DCHECK(is_request_reported_);
175 if (is_support_reported_)
176 return;
177 Report(KEY_SYSTEM_SUPPORTED);
178 is_support_reported_ = true;
181 private:
182 void Report(KeySystemSupportStatus status) {
183 // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros
184 // require the names to be constant throughout the process' lifetime.
185 base::LinearHistogram::FactoryGet(
186 uma_name_, 1, KEY_SYSTEM_SUPPORT_STATUS_COUNT,
187 KEY_SYSTEM_SUPPORT_STATUS_COUNT + 1,
188 base::Histogram::kUmaTargetedHistogramFlag)->Add(status);
191 const std::string uma_name_;
192 bool is_request_reported_;
193 bool is_support_reported_;
196 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl(
197 scoped_ptr<CdmFactory> cdm_factory,
198 MediaPermission* media_permission)
199 : cdm_factory_(cdm_factory.Pass()), weak_factory_(this) {
200 // TODO(sandersd): Use |media_permission| to check for media permissions in
201 // this class.
202 DCHECK(media_permission);
205 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() {
208 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess(
209 blink::WebEncryptedMediaRequest request) {
210 // TODO(jrummell): This should be asynchronous.
212 // Continued from requestMediaKeySystemAccess(), step 7, from
213 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess
215 // 7.1 If keySystem is not one of the Key Systems supported by the user
216 // agent, reject promise with with a new DOMException whose name is
217 // NotSupportedError. String comparison is case-sensitive.
218 if (!base::IsStringASCII(request.keySystem())) {
219 request.requestNotSupported("Only ASCII keySystems are supported");
220 return;
223 std::string key_system = base::UTF16ToASCII(request.keySystem());
225 // Report this request to the appropriate Reporter.
226 Reporter* reporter = GetReporter(key_system);
227 reporter->ReportRequested();
229 if (!IsConcreteSupportedKeySystem(key_system)) {
230 request.requestNotSupported("Unsupported keySystem");
231 return;
234 // 7.2 Let implementation be the implementation of keySystem.
235 // 7.3 For each value in supportedConfigurations, run the GetSupported
236 // Configuration algorithm and if successful, resolve promise with access
237 // and abort these steps.
238 const blink::WebVector<blink::WebMediaKeySystemConfiguration>&
239 configurations = request.supportedConfigurations();
241 // TODO(sandersd): Remove once Blink requires the configurations parameter for
242 // requestMediaKeySystemAccess().
243 if (configurations.isEmpty()) {
244 reporter->ReportSupported();
245 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
246 request.keySystem(), blink::WebMediaKeySystemConfiguration(),
247 request.securityOrigin(), weak_factory_.GetWeakPtr()));
248 return;
251 for (size_t i = 0; i < configurations.size(); i++) {
252 const blink::WebMediaKeySystemConfiguration& candidate = configurations[i];
253 blink::WebMediaKeySystemConfiguration accumulated_configuration;
254 if (GetSupportedConfiguration(key_system, candidate,
255 request.securityOrigin(),
256 &accumulated_configuration)) {
257 reporter->ReportSupported();
258 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create(
259 request.keySystem(), accumulated_configuration,
260 request.securityOrigin(), weak_factory_.GetWeakPtr()));
261 return;
265 // 7.4 Reject promise with a new DOMException whose name is NotSupportedError.
266 request.requestNotSupported(
267 "None of the requested configurations were supported.");
270 void WebEncryptedMediaClientImpl::CreateCdm(
271 const blink::WebString& key_system,
272 const blink::WebSecurityOrigin& security_origin,
273 blink::WebContentDecryptionModuleResult result) {
274 WebContentDecryptionModuleImpl::Create(cdm_factory_.get(), security_origin,
275 key_system, result);
278 // Lazily create Reporters.
279 WebEncryptedMediaClientImpl::Reporter* WebEncryptedMediaClientImpl::GetReporter(
280 const std::string& key_system) {
281 std::string uma_name = GetKeySystemNameForUMA(key_system);
282 Reporter* reporter = reporters_.get(uma_name);
283 if (reporter != nullptr)
284 return reporter;
286 // Reporter not found, so create one.
287 auto result =
288 reporters_.add(uma_name, make_scoped_ptr(new Reporter(uma_name)));
289 DCHECK(result.second);
290 return result.first->second;
293 } // namespace media