OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "webencryptedmediaclient_impl.h" | 5 #include "webencryptedmediaclient_impl.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "base/metrics/histogram.h" | |
8 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
9 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
10 #include "media/base/key_systems.h" | 11 #include "media/base/key_systems.h" |
11 #include "net/base/mime_util.h" | 12 #include "net/base/mime_util.h" |
12 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h" | 13 #include "third_party/WebKit/public/platform/WebEncryptedMediaRequest.h" |
13 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h" | 14 #include "third_party/WebKit/public/platform/WebMediaKeySystemConfiguration.h" |
14 #include "third_party/WebKit/public/platform/WebString.h" | 15 #include "third_party/WebKit/public/platform/WebString.h" |
15 #include "third_party/WebKit/public/platform/WebVector.h" | 16 #include "third_party/WebKit/public/platform/WebVector.h" |
16 #include "webcontentdecryptionmoduleaccess_impl.h" | 17 #include "webcontentdecryptionmoduleaccess_impl.h" |
17 | 18 |
18 namespace media { | 19 namespace media { |
19 | 20 |
21 // These names are used by UMA. | |
22 const char kKeySystemSupportUMAPrefix[] = | |
23 "Media.EME.RequestMediaKeySystemAccess."; | |
24 const char kClearKeyKeySystemNameForUMA[] = "ClearKey"; | |
25 const char kUnknownKeySystemNameForUMA[] = "Unknown"; | |
26 const char kWidevineKeySystemNameForUMA[] = "Widevine"; | |
xhwang
2015/01/29 05:23:26
Can you use GetKeySystemNameForUMA(const std::stri
jrummell
2015/01/29 22:16:06
My concern was that histograms.xml needs to know a
| |
27 | |
20 static bool IsSupportedContentType( | 28 static bool IsSupportedContentType( |
21 const std::string& key_system, | 29 const std::string& key_system, |
22 const std::string& mime_type, | 30 const std::string& mime_type, |
23 const std::string& codecs) { | 31 const std::string& codecs) { |
24 // Per RFC 6838, "Both top-level type and subtype names are case-insensitive." | 32 // Per RFC 6838, "Both top-level type and subtype names are case-insensitive." |
25 // TODO(sandersd): Check that |container| matches the capability: | 33 // TODO(sandersd): Check that |container| matches the capability: |
26 // - audioCapabilitys: audio/mp4 or audio/webm. | 34 // - audioCapabilitys: audio/mp4 or audio/webm. |
27 // - videoCapabilitys: video/mp4 or video/webm. | 35 // - videoCapabilitys: video/mp4 or video/webm. |
28 // http://crbug.com/429781. | 36 // http://crbug.com/429781. |
29 std::string container = base::StringToLowerASCII(mime_type); | 37 std::string container = base::StringToLowerASCII(mime_type); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
123 accumulated_configuration->videoCapabilities = video_capabilities; | 131 accumulated_configuration->videoCapabilities = video_capabilities; |
124 } | 132 } |
125 | 133 |
126 // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state | 134 // TODO(sandersd): Prompt for distinctive identifiers and/or persistent state |
127 // if required. Make sure that future checks are silent. | 135 // if required. Make sure that future checks are silent. |
128 // http://crbug.com/446263. | 136 // http://crbug.com/446263. |
129 | 137 |
130 return true; | 138 return true; |
131 } | 139 } |
132 | 140 |
141 // Report usage of key system to UMA. There are 2 different counts logged: | |
142 // 1. The key system is requested. | |
143 // 2. The requested key system and options are supported. | |
144 // Each stat is only reported once per renderer process per key system. | |
145 // Note that WebEncryptedMediaClientImpl is only created once by each | |
146 // renderer process. | |
xhwang
2015/01/29 05:23:25
hmm, this is not true. WebEncryptedMediaClientImpl
jrummell
2015/01/29 22:16:06
As discussed offline, once per render frame is OK.
| |
147 class WebEncryptedMediaClientImpl::Reporter { | |
xhwang
2015/01/29 05:23:26
KeySystemsSupportUMA::Reporter is currently using
jrummell
2015/01/29 22:16:07
Acknowledged.
| |
148 public: | |
149 enum KeySystemSupportStatus { | |
150 KEY_SYSTEM_REQUESTED = 0, | |
151 KEY_SYSTEM_SUPPORTED = 1, | |
152 KEY_SYSTEM_COUNT | |
xhwang
2015/01/29 05:23:26
KEY_SYSTEM_COUNT is misleading, it's really KEY_SY
jrummell
2015/01/29 22:16:06
Done.
| |
153 }; | |
154 | |
155 explicit Reporter(const std::string& key_system_for_uma) | |
156 : uma_name_(kKeySystemSupportUMAPrefix + key_system_for_uma), | |
157 is_requested_reported_(false), | |
158 is_supported_reported_(false) {} | |
xhwang
2015/01/29 05:23:26
s/requested/request
s/supported/support
jrummell
2015/01/29 22:16:07
Done.
| |
159 ~Reporter() {} | |
160 | |
161 void ReportRequested() { | |
162 if (is_requested_reported_) | |
163 return; | |
164 Report(KEY_SYSTEM_REQUESTED); | |
165 is_requested_reported_ = true; | |
166 } | |
167 | |
168 void ReportSupported() { | |
xhwang
2015/01/29 05:23:26
DCHECK(is_requested_reported_) to make sure this i
jrummell
2015/01/29 22:16:07
Done.
| |
169 if (is_supported_reported_) | |
170 return; | |
171 Report(KEY_SYSTEM_SUPPORTED); | |
172 is_supported_reported_ = true; | |
173 } | |
174 | |
175 private: | |
176 void Report(KeySystemSupportStatus status) { | |
177 // Not using UMA_HISTOGRAM_ENUMERATION directly because UMA_* macros | |
178 // require the names to be constant throughout the process' lifetime. | |
179 base::LinearHistogram::FactoryGet( | |
180 uma_name_, 1, KEY_SYSTEM_COUNT, KEY_SYSTEM_COUNT + 1, | |
181 base::Histogram::kUmaTargetedHistogramFlag)->Add(status); | |
182 } | |
183 | |
184 const std::string uma_name_; | |
185 bool is_requested_reported_; | |
186 bool is_supported_reported_; | |
187 }; | |
188 | |
133 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl( | 189 WebEncryptedMediaClientImpl::WebEncryptedMediaClientImpl( |
134 scoped_ptr<CdmFactory> cdm_factory) | 190 scoped_ptr<CdmFactory> cdm_factory) |
135 : cdm_factory_(cdm_factory.Pass()) { | 191 : cdm_factory_(cdm_factory.Pass()) { |
192 // Generate the possible set of UMA reporters. If this list is updated | |
193 // then the appropriate list in histograms.xml needs to be updated. | |
194 AddReporter(kClearKeyKeySystemNameForUMA); | |
195 AddReporter(kUnknownKeySystemNameForUMA); | |
196 AddReporter(kWidevineKeySystemNameForUMA); | |
xhwang
2015/01/29 05:23:26
See comment below about lazy adding these.
jrummell
2015/01/29 22:16:07
Done.
| |
136 } | 197 } |
137 | 198 |
138 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() { | 199 WebEncryptedMediaClientImpl::~WebEncryptedMediaClientImpl() { |
139 } | 200 } |
140 | 201 |
141 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( | 202 void WebEncryptedMediaClientImpl::requestMediaKeySystemAccess( |
142 blink::WebEncryptedMediaRequest request) { | 203 blink::WebEncryptedMediaRequest request) { |
143 // TODO(jrummell): This should be asynchronous. | 204 // TODO(jrummell): This should be asynchronous. |
144 | 205 |
145 // Continued from requestMediaKeySystemAccess(), step 7, from | 206 // Continued from requestMediaKeySystemAccess(), step 7, from |
146 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess | 207 // https://w3c.github.io/encrypted-media/#requestmediakeysystemaccess |
147 // | 208 // |
148 // 7.1 If keySystem is not one of the Key Systems supported by the user | 209 // 7.1 If keySystem is not one of the Key Systems supported by the user |
149 // agent, reject promise with with a new DOMException whose name is | 210 // agent, reject promise with with a new DOMException whose name is |
150 // NotSupportedError. String comparison is case-sensitive. | 211 // NotSupportedError. String comparison is case-sensitive. |
151 if (!base::IsStringASCII(request.keySystem())) { | 212 if (!base::IsStringASCII(request.keySystem())) { |
152 request.requestNotSupported("Only ASCII keySystems are supported"); | 213 request.requestNotSupported("Only ASCII keySystems are supported"); |
153 return; | 214 return; |
154 } | 215 } |
155 | 216 |
156 std::string key_system = base::UTF16ToASCII(request.keySystem()); | 217 std::string key_system = base::UTF16ToASCII(request.keySystem()); |
218 | |
219 // Report this request to the appropriate Reporter. | |
220 Reporter* reporter = GetReporter(key_system); | |
221 reporter->ReportRequested(); | |
222 | |
157 if (!IsConcreteSupportedKeySystem(key_system)) { | 223 if (!IsConcreteSupportedKeySystem(key_system)) { |
158 request.requestNotSupported("Unsupported keySystem"); | 224 request.requestNotSupported("Unsupported keySystem"); |
159 return; | 225 return; |
160 } | 226 } |
161 | 227 |
162 // 7.2 Let implementation be the implementation of keySystem. | 228 // 7.2 Let implementation be the implementation of keySystem. |
163 // 7.3 Follow the steps for the first matching condition from the following | 229 // 7.3 Follow the steps for the first matching condition from the following |
164 // list: | 230 // list: |
165 // - If supportedConfigurations was not provided, run the Is Key System | 231 // - If supportedConfigurations was not provided, run the Is Key System |
166 // Supported? algorithm and if successful, resolve promise with access | 232 // Supported? algorithm and if successful, resolve promise with access |
167 // and abort these steps. | 233 // and abort these steps. |
168 // TODO(sandersd): Remove pending the resolution of | 234 // TODO(sandersd): Remove pending the resolution of |
169 // https://github.com/w3c/encrypted-media/issues/1. | 235 // https://github.com/w3c/encrypted-media/issues/1. |
170 const blink::WebVector<blink::WebMediaKeySystemConfiguration>& | 236 const blink::WebVector<blink::WebMediaKeySystemConfiguration>& |
171 configurations = request.supportedConfigurations(); | 237 configurations = request.supportedConfigurations(); |
172 if (configurations.isEmpty()) { | 238 if (configurations.isEmpty()) { |
173 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( | 239 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( |
174 request.keySystem(), request.securityOrigin(), cdm_factory_.get())); | 240 request.keySystem(), request.securityOrigin(), cdm_factory_.get())); |
241 reporter->ReportSupported(); | |
xhwang
2015/01/29 05:23:26
nit: report first, then resolve the request.
jrummell
2015/01/29 22:16:06
Done.
| |
175 return; | 242 return; |
176 } | 243 } |
177 | 244 |
178 // - Otherwise, for each value in supportedConfigurations, run the | 245 // - Otherwise, for each value in supportedConfigurations, run the |
179 // GetSuppored Configuration algorithm and if successful, resolve | 246 // GetSuppored Configuration algorithm and if successful, resolve |
180 // promise with access and abort these steps. | 247 // promise with access and abort these steps. |
181 for (size_t i = 0; i < configurations.size(); i++) { | 248 for (size_t i = 0; i < configurations.size(); i++) { |
182 const blink::WebMediaKeySystemConfiguration& candidate = configurations[i]; | 249 const blink::WebMediaKeySystemConfiguration& candidate = configurations[i]; |
183 blink::WebMediaKeySystemConfiguration accumulated_configuration; | 250 blink::WebMediaKeySystemConfiguration accumulated_configuration; |
184 if (GetSupportedConfiguration(key_system, candidate, | 251 if (GetSupportedConfiguration(key_system, candidate, |
185 request.securityOrigin(), | 252 request.securityOrigin(), |
186 &accumulated_configuration)) { | 253 &accumulated_configuration)) { |
187 // TODO(sandersd): Pass the accumulated configuration along. | 254 // TODO(sandersd): Pass the accumulated configuration along. |
188 // http://crbug.com/447059. | 255 // http://crbug.com/447059. |
189 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( | 256 request.requestSucceeded(WebContentDecryptionModuleAccessImpl::Create( |
190 request.keySystem(), request.securityOrigin(), cdm_factory_.get())); | 257 request.keySystem(), request.securityOrigin(), cdm_factory_.get())); |
258 reporter->ReportSupported(); | |
xhwang
2015/01/29 05:23:26
ditto.
jrummell
2015/01/29 22:16:06
Done.
| |
191 return; | 259 return; |
192 } | 260 } |
193 } | 261 } |
194 | 262 |
195 // 7.4 Reject promise with a new DOMException whose name is NotSupportedError. | 263 // 7.4 Reject promise with a new DOMException whose name is NotSupportedError. |
196 request.requestNotSupported( | 264 request.requestNotSupported( |
197 "None of the requested configurations were supported."); | 265 "None of the requested configurations were supported."); |
198 } | 266 } |
199 | 267 |
268 void WebEncryptedMediaClientImpl::AddReporter(const std::string& key_system) { | |
269 reporters_.set(key_system, scoped_ptr<Reporter>(new Reporter(key_system))); | |
xhwang
2015/01/29 05:23:26
nit: You can use make_scoped_ptr.
jrummell
2015/01/29 22:16:06
Not needed now.
| |
270 } | |
271 | |
272 WebEncryptedMediaClientImpl::Reporter* WebEncryptedMediaClientImpl::GetReporter( | |
273 const std::string& key_system) { | |
274 Reporters::iterator reporter_lookup = | |
275 reporters_.find(GetKeySystemNameForUMA(key_system)); | |
276 | |
277 if (reporter_lookup == reporters_.end()) { | |
278 // All valid names should have been registered. Since we can't find one, | |
279 // assume |key_system| becomes "Unknown". | |
280 NOTREACHED() << "Unable to locate Reporter for " << key_system; | |
281 reporter_lookup = reporters_.find(kUnknownKeySystemNameForUMA); | |
xhwang
2015/01/29 05:23:25
If you use GetKeySystemNameForUMA(), you'll get kU
jrummell
2015/01/29 22:16:07
Done.
| |
282 } | |
283 | |
284 return reporter_lookup->second; | |
285 } | |
286 | |
200 } // namespace media | 287 } // namespace media |
OLD | NEW |