Remove INJECT_EVENTS permissions from test APKs.
[chromium-blink-merge.git] / media / blink / encrypted_media_player_support.cc
blob39ae48f113c776e37386fa58bf53357954972129
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 "media/blink/encrypted_media_player_support.h"
8 #include "base/bind.h"
9 #include "base/callback_helpers.h"
10 #include "base/metrics/histogram.h"
11 #include "base/numerics/safe_conversions.h"
12 #include "base/strings/string_number_conversions.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/key_systems.h"
17 #include "media/blink/webcontentdecryptionmodule_impl.h"
18 #include "third_party/WebKit/public/platform/WebContentDecryptionModule.h"
19 #include "third_party/WebKit/public/platform/WebMediaPlayerClient.h"
20 #include "third_party/WebKit/public/web/WebDocument.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
23 using blink::WebMediaPlayer;
24 using blink::WebMediaPlayerClient;
25 using blink::WebString;
27 namespace media {
29 #define BIND_TO_RENDER_LOOP(function) \
30 (BindToCurrentLoop(base::Bind(function, AsWeakPtr())))
32 #define BIND_TO_RENDER_LOOP1(function, arg1) \
33 (BindToCurrentLoop(base::Bind(function, AsWeakPtr(), arg1)))
35 // Prefix for histograms related to Encrypted Media Extensions.
36 static const char* kMediaEme = "Media.EME.";
38 // Convert a WebString to ASCII, falling back on an empty string in the case
39 // of a non-ASCII string.
40 static std::string ToASCIIOrEmpty(const WebString& string) {
41 return base::IsStringASCII(string) ? base::UTF16ToASCII(string)
42 : std::string();
45 // Helper functions to report media EME related stats to UMA. They follow the
46 // convention of more commonly used macros UMA_HISTOGRAM_ENUMERATION and
47 // UMA_HISTOGRAM_COUNTS. The reason that we cannot use those macros directly is
48 // that UMA_* macros require the names to be constant throughout the process'
49 // lifetime.
50 static void EmeUMAHistogramEnumeration(const std::string& key_system,
51 const std::string& method,
52 int sample,
53 int boundary_value) {
54 base::LinearHistogram::FactoryGet(
55 kMediaEme + GetKeySystemNameForUMA(key_system) + "." + method,
56 1, boundary_value, boundary_value + 1,
57 base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
60 static void EmeUMAHistogramCounts(const std::string& key_system,
61 const std::string& method,
62 int sample) {
63 // Use the same parameters as UMA_HISTOGRAM_COUNTS.
64 base::Histogram::FactoryGet(
65 kMediaEme + GetKeySystemNameForUMA(key_system) + "." + method,
66 1, 1000000, 50, base::Histogram::kUmaTargetedHistogramFlag)->Add(sample);
69 // Helper enum for reporting generateKeyRequest/addKey histograms.
70 enum MediaKeyException {
71 kUnknownResultId,
72 kSuccess,
73 kKeySystemNotSupported,
74 kInvalidPlayerState,
75 kMaxMediaKeyException
78 static MediaKeyException MediaKeyExceptionForUMA(
79 WebMediaPlayer::MediaKeyException e) {
80 switch (e) {
81 case WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported:
82 return kKeySystemNotSupported;
83 case WebMediaPlayer::MediaKeyExceptionInvalidPlayerState:
84 return kInvalidPlayerState;
85 case WebMediaPlayer::MediaKeyExceptionNoError:
86 return kSuccess;
87 default:
88 return kUnknownResultId;
92 // Helper for converting |key_system| name and exception |e| to a pair of enum
93 // values from above, for reporting to UMA.
94 static void ReportMediaKeyExceptionToUMA(const std::string& method,
95 const std::string& key_system,
96 WebMediaPlayer::MediaKeyException e) {
97 MediaKeyException result_id = MediaKeyExceptionForUMA(e);
98 DCHECK_NE(result_id, kUnknownResultId) << e;
99 EmeUMAHistogramEnumeration(
100 key_system, method, result_id, kMaxMediaKeyException);
103 // Guess the type of |init_data|. This is only used to handle some corner cases
104 // so we keep it as simple as possible without breaking major use cases.
105 static EmeInitDataType GuessInitDataType(const unsigned char* init_data,
106 unsigned init_data_length) {
107 #if defined(USE_PROPRIETARY_CODECS)
108 // Most WebM files use KeyId of 16 bytes. CENC init data is always >16 bytes.
109 if (init_data_length > 16)
110 return EmeInitDataType::CENC;
111 #endif
113 return EmeInitDataType::WEBM;
116 EncryptedMediaPlayerSupport::EncryptedMediaPlayerSupport(
117 CdmFactory* cdm_factory,
118 blink::WebMediaPlayerClient* client,
119 MediaPermission* media_permission,
120 const CdmContextReadyCB& cdm_context_ready_cb)
121 : cdm_factory_(cdm_factory),
122 client_(client),
123 media_permission_(media_permission),
124 init_data_type_(EmeInitDataType::UNKNOWN),
125 cdm_context_ready_cb_(cdm_context_ready_cb) {
128 EncryptedMediaPlayerSupport::~EncryptedMediaPlayerSupport() {
131 WebMediaPlayer::MediaKeyException
132 EncryptedMediaPlayerSupport::GenerateKeyRequest(
133 blink::WebLocalFrame* frame,
134 const WebString& key_system,
135 const unsigned char* init_data,
136 unsigned init_data_length) {
137 DVLOG(1) << "generateKeyRequest: " << base::string16(key_system) << ": "
138 << std::string(reinterpret_cast<const char*>(init_data),
139 static_cast<size_t>(init_data_length));
141 std::string ascii_key_system =
142 GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
144 WebMediaPlayer::MediaKeyException e = GenerateKeyRequestInternal(
145 frame, ascii_key_system, init_data, init_data_length);
146 ReportMediaKeyExceptionToUMA("generateKeyRequest", ascii_key_system, e);
147 return e;
150 WebMediaPlayer::MediaKeyException
151 EncryptedMediaPlayerSupport::GenerateKeyRequestInternal(
152 blink::WebLocalFrame* frame,
153 const std::string& key_system,
154 const unsigned char* init_data,
155 unsigned init_data_length) {
156 if (!PrefixedIsSupportedConcreteKeySystem(key_system))
157 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
159 // |use_hw_secure_codecs| is only supported on Android, and Android (WMPA)
160 // does not use EncryptedMediaPlayerSupport.
161 bool use_hw_secure_codecs = false;
163 if (!proxy_decryptor_) {
164 DCHECK(current_key_system_.empty());
165 DCHECK(!cdm_context_ready_cb_.is_null());
166 proxy_decryptor_.reset(new ProxyDecryptor(
167 media_permission_, use_hw_secure_codecs,
168 BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyAdded),
169 BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyError),
170 BIND_TO_RENDER_LOOP(&EncryptedMediaPlayerSupport::OnKeyMessage)));
172 GURL security_origin(frame->document().securityOrigin().toString());
173 proxy_decryptor_->CreateCdm(cdm_factory_, key_system, security_origin,
174 cdm_context_ready_cb_);
175 current_key_system_ = key_system;
178 // We do not support run-time switching between key systems for now.
179 DCHECK(!current_key_system_.empty());
180 if (key_system != current_key_system_)
181 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
183 EmeInitDataType init_data_type = init_data_type_;
184 if (init_data_type == EmeInitDataType::UNKNOWN)
185 init_data_type = GuessInitDataType(init_data, init_data_length);
187 proxy_decryptor_->GenerateKeyRequest(init_data_type, init_data,
188 init_data_length);
190 return WebMediaPlayer::MediaKeyExceptionNoError;
193 WebMediaPlayer::MediaKeyException EncryptedMediaPlayerSupport::AddKey(
194 const WebString& key_system,
195 const unsigned char* key,
196 unsigned key_length,
197 const unsigned char* init_data,
198 unsigned init_data_length,
199 const WebString& session_id) {
200 DVLOG(1) << "addKey: " << base::string16(key_system) << ": "
201 << std::string(reinterpret_cast<const char*>(key),
202 static_cast<size_t>(key_length)) << ", "
203 << std::string(reinterpret_cast<const char*>(init_data),
204 static_cast<size_t>(init_data_length)) << " ["
205 << base::string16(session_id) << "]";
207 std::string ascii_key_system =
208 GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
209 std::string ascii_session_id = ToASCIIOrEmpty(session_id);
211 WebMediaPlayer::MediaKeyException e = AddKeyInternal(ascii_key_system,
212 key,
213 key_length,
214 init_data,
215 init_data_length,
216 ascii_session_id);
217 ReportMediaKeyExceptionToUMA("addKey", ascii_key_system, e);
218 return e;
221 WebMediaPlayer::MediaKeyException
222 EncryptedMediaPlayerSupport::AddKeyInternal(
223 const std::string& key_system,
224 const unsigned char* key,
225 unsigned key_length,
226 const unsigned char* init_data,
227 unsigned init_data_length,
228 const std::string& session_id) {
229 DCHECK(key);
230 DCHECK_GT(key_length, 0u);
232 if (!PrefixedIsSupportedConcreteKeySystem(key_system))
233 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
235 if (current_key_system_.empty() || key_system != current_key_system_)
236 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
238 proxy_decryptor_->AddKey(
239 key, key_length, init_data, init_data_length, session_id);
240 return WebMediaPlayer::MediaKeyExceptionNoError;
243 WebMediaPlayer::MediaKeyException
244 EncryptedMediaPlayerSupport::CancelKeyRequest(
245 const WebString& key_system,
246 const WebString& session_id) {
247 DVLOG(1) << "cancelKeyRequest: " << base::string16(key_system) << ": "
248 << " [" << base::string16(session_id) << "]";
250 std::string ascii_key_system =
251 GetUnprefixedKeySystemName(ToASCIIOrEmpty(key_system));
252 std::string ascii_session_id = ToASCIIOrEmpty(session_id);
254 WebMediaPlayer::MediaKeyException e =
255 CancelKeyRequestInternal(ascii_key_system, ascii_session_id);
256 ReportMediaKeyExceptionToUMA("cancelKeyRequest", ascii_key_system, e);
257 return e;
260 WebMediaPlayer::MediaKeyException
261 EncryptedMediaPlayerSupport::CancelKeyRequestInternal(
262 const std::string& key_system,
263 const std::string& session_id) {
264 if (!PrefixedIsSupportedConcreteKeySystem(key_system))
265 return WebMediaPlayer::MediaKeyExceptionKeySystemNotSupported;
267 if (current_key_system_.empty() || key_system != current_key_system_)
268 return WebMediaPlayer::MediaKeyExceptionInvalidPlayerState;
270 proxy_decryptor_->CancelKeyRequest(session_id);
271 return WebMediaPlayer::MediaKeyExceptionNoError;
274 void EncryptedMediaPlayerSupport::SetInitDataType(
275 EmeInitDataType init_data_type) {
276 DCHECK(init_data_type != EmeInitDataType::UNKNOWN);
277 DLOG_IF(WARNING, init_data_type_ != EmeInitDataType::UNKNOWN &&
278 init_data_type != init_data_type_)
279 << "Mixed init data type not supported. The new type is ignored.";
280 if (init_data_type_ == EmeInitDataType::UNKNOWN)
281 init_data_type_ = init_data_type;
284 void EncryptedMediaPlayerSupport::OnKeyAdded(const std::string& session_id) {
285 EmeUMAHistogramCounts(current_key_system_, "KeyAdded", 1);
286 client_->keyAdded(
287 WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
288 WebString::fromUTF8(session_id));
291 void EncryptedMediaPlayerSupport::OnKeyError(const std::string& session_id,
292 MediaKeys::KeyError error_code,
293 uint32 system_code) {
294 EmeUMAHistogramEnumeration(current_key_system_, "KeyError",
295 error_code, MediaKeys::kMaxKeyError);
297 uint16 short_system_code = 0;
298 if (system_code > std::numeric_limits<uint16>::max()) {
299 LOG(WARNING) << "system_code exceeds unsigned short limit.";
300 short_system_code = std::numeric_limits<uint16>::max();
301 } else {
302 short_system_code = static_cast<uint16>(system_code);
305 client_->keyError(
306 WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
307 WebString::fromUTF8(session_id),
308 static_cast<WebMediaPlayerClient::MediaKeyErrorCode>(error_code),
309 short_system_code);
312 void EncryptedMediaPlayerSupport::OnKeyMessage(
313 const std::string& session_id,
314 const std::vector<uint8>& message,
315 const GURL& destination_url) {
316 DCHECK(destination_url.is_empty() || destination_url.is_valid());
318 client_->keyMessage(
319 WebString::fromUTF8(GetPrefixedKeySystemName(current_key_system_)),
320 WebString::fromUTF8(session_id),
321 message.empty() ? NULL : &message[0],
322 base::saturated_cast<unsigned int>(message.size()),
323 destination_url);
326 } // namespace media