OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "media/cdm/proxy_decryptor.h" | 5 #include "media/cdm/proxy_decryptor.h" |
6 | 6 |
7 #include <cstring> | 7 #include <cstring> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 | 21 |
22 namespace media { | 22 namespace media { |
23 | 23 |
24 // Special system code to signal a closed persistent session in a SessionError() | 24 // Special system code to signal a closed persistent session in a SessionError() |
25 // call. This is needed because there is no SessionClosed() call in the prefixed | 25 // call. This is needed because there is no SessionClosed() call in the prefixed |
26 // EME API. | 26 // EME API. |
27 const int kSessionClosedSystemCode = 29127; | 27 const int kSessionClosedSystemCode = 29127; |
28 | 28 |
29 ProxyDecryptor::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData( | 29 ProxyDecryptor::PendingGenerateKeyRequestData::PendingGenerateKeyRequestData( |
30 EmeInitDataType init_data_type, | 30 EmeInitDataType init_data_type, |
31 const std::vector<uint8>& init_data) | 31 const std::vector<uint8_t>& init_data) |
32 : init_data_type(init_data_type), init_data(init_data) { | 32 : init_data_type(init_data_type), init_data(init_data) {} |
33 } | |
34 | 33 |
35 ProxyDecryptor::PendingGenerateKeyRequestData:: | 34 ProxyDecryptor::PendingGenerateKeyRequestData:: |
36 ~PendingGenerateKeyRequestData() { | 35 ~PendingGenerateKeyRequestData() { |
37 } | 36 } |
38 | 37 |
39 ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission, | 38 ProxyDecryptor::ProxyDecryptor(MediaPermission* media_permission, |
40 bool use_hw_secure_codecs, | 39 bool use_hw_secure_codecs, |
41 const KeyAddedCB& key_added_cb, | 40 const KeyAddedCB& key_added_cb, |
42 const KeyErrorCB& key_error_cb, | 41 const KeyErrorCB& key_error_cb, |
43 const KeyMessageCB& key_message_cb) | 42 const KeyMessageCB& key_message_cb) |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 cdm_context_ready_cb.Run(media_keys_->GetCdmContext()); | 109 cdm_context_ready_cb.Run(media_keys_->GetCdmContext()); |
111 } | 110 } |
112 | 111 |
113 for (const auto& request : pending_requests_) | 112 for (const auto& request : pending_requests_) |
114 GenerateKeyRequestInternal(request->init_data_type, request->init_data); | 113 GenerateKeyRequestInternal(request->init_data_type, request->init_data); |
115 | 114 |
116 pending_requests_.clear(); | 115 pending_requests_.clear(); |
117 } | 116 } |
118 | 117 |
119 void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type, | 118 void ProxyDecryptor::GenerateKeyRequest(EmeInitDataType init_data_type, |
120 const uint8* init_data, | 119 const uint8_t* init_data, |
121 int init_data_length) { | 120 int init_data_length) { |
122 std::vector<uint8> init_data_vector(init_data, init_data + init_data_length); | 121 std::vector<uint8_t> init_data_vector(init_data, |
| 122 init_data + init_data_length); |
123 | 123 |
124 if (is_creating_cdm_) { | 124 if (is_creating_cdm_) { |
125 pending_requests_.push_back( | 125 pending_requests_.push_back( |
126 new PendingGenerateKeyRequestData(init_data_type, init_data_vector)); | 126 new PendingGenerateKeyRequestData(init_data_type, init_data_vector)); |
127 return; | 127 return; |
128 } | 128 } |
129 | 129 |
130 GenerateKeyRequestInternal(init_data_type, init_data_vector); | 130 GenerateKeyRequestInternal(init_data_type, init_data_vector); |
131 } | 131 } |
132 | 132 |
133 // Returns true if |data| is prefixed with |header| and has data after the | 133 // Returns true if |data| is prefixed with |header| and has data after the |
134 // |header|. | 134 // |header|. |
135 static bool HasHeader(const std::vector<uint8>& data, | 135 static bool HasHeader(const std::vector<uint8_t>& data, |
136 const std::string& header) { | 136 const std::string& header) { |
137 return data.size() > header.size() && | 137 return data.size() > header.size() && |
138 std::equal(header.begin(), header.end(), data.begin()); | 138 std::equal(header.begin(), header.end(), data.begin()); |
139 } | 139 } |
140 | 140 |
141 // Removes the first |length| items from |data|. | 141 // Removes the first |length| items from |data|. |
142 static void StripHeader(std::vector<uint8>& data, size_t length) { | 142 static void StripHeader(std::vector<uint8_t>& data, size_t length) { |
143 data.erase(data.begin(), data.begin() + length); | 143 data.erase(data.begin(), data.begin() + length); |
144 } | 144 } |
145 | 145 |
146 void ProxyDecryptor::GenerateKeyRequestInternal( | 146 void ProxyDecryptor::GenerateKeyRequestInternal( |
147 EmeInitDataType init_data_type, | 147 EmeInitDataType init_data_type, |
148 const std::vector<uint8>& init_data) { | 148 const std::vector<uint8_t>& init_data) { |
149 DVLOG(1) << __FUNCTION__; | 149 DVLOG(1) << __FUNCTION__; |
150 DCHECK(!is_creating_cdm_); | 150 DCHECK(!is_creating_cdm_); |
151 | 151 |
152 if (!media_keys_) { | 152 if (!media_keys_) { |
153 OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0, | 153 OnLegacySessionError(std::string(), MediaKeys::NOT_SUPPORTED_ERROR, 0, |
154 "CDM creation failed."); | 154 "CDM creation failed."); |
155 return; | 155 return; |
156 } | 156 } |
157 | 157 |
158 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; | 158 const char kPrefixedApiPersistentSessionHeader[] = "PERSISTENT|"; |
159 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; | 159 const char kPrefixedApiLoadSessionHeader[] = "LOAD_SESSION|"; |
160 | 160 |
161 SessionCreationType session_creation_type = TemporarySession; | 161 SessionCreationType session_creation_type = TemporarySession; |
162 std::vector<uint8> stripped_init_data = init_data; | 162 std::vector<uint8_t> stripped_init_data = init_data; |
163 if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) { | 163 if (HasHeader(init_data, kPrefixedApiLoadSessionHeader)) { |
164 session_creation_type = LoadSession; | 164 session_creation_type = LoadSession; |
165 StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader)); | 165 StripHeader(stripped_init_data, strlen(kPrefixedApiLoadSessionHeader)); |
166 } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) { | 166 } else if (HasHeader(init_data, kPrefixedApiPersistentSessionHeader)) { |
167 session_creation_type = PersistentSession; | 167 session_creation_type = PersistentSession; |
168 StripHeader(stripped_init_data, | 168 StripHeader(stripped_init_data, |
169 strlen(kPrefixedApiPersistentSessionHeader)); | 169 strlen(kPrefixedApiPersistentSessionHeader)); |
170 } | 170 } |
171 | 171 |
172 scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>( | 172 scoped_ptr<NewSessionCdmPromise> promise(new CdmCallbackPromise<std::string>( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 stripped_init_data, base::Passed(&promise))); | 207 stripped_init_data, base::Passed(&promise))); |
208 #else | 208 #else |
209 OnPermissionStatus(session_type, init_data_type, stripped_init_data, | 209 OnPermissionStatus(session_type, init_data_type, stripped_init_data, |
210 promise.Pass(), true /* granted */); | 210 promise.Pass(), true /* granted */); |
211 #endif | 211 #endif |
212 } | 212 } |
213 | 213 |
214 void ProxyDecryptor::OnPermissionStatus( | 214 void ProxyDecryptor::OnPermissionStatus( |
215 MediaKeys::SessionType session_type, | 215 MediaKeys::SessionType session_type, |
216 EmeInitDataType init_data_type, | 216 EmeInitDataType init_data_type, |
217 const std::vector<uint8>& init_data, | 217 const std::vector<uint8_t>& init_data, |
218 scoped_ptr<NewSessionCdmPromise> promise, | 218 scoped_ptr<NewSessionCdmPromise> promise, |
219 bool granted) { | 219 bool granted) { |
220 // ProxyDecryptor is only used by Prefixed EME, where RequestPermission() is | 220 // ProxyDecryptor is only used by Prefixed EME, where RequestPermission() is |
221 // only for triggering the permission UI. Later CheckPermission() will be | 221 // only for triggering the permission UI. Later CheckPermission() will be |
222 // called (e.g. in PlatformVerificationFlow on ChromeOS; in BrowserCdmManager | 222 // called (e.g. in PlatformVerificationFlow on ChromeOS; in BrowserCdmManager |
223 // on Android) and the permission status will be evaluated then. | 223 // on Android) and the permission status will be evaluated then. |
224 DVLOG_IF(1, !granted) << "Permission request rejected."; | 224 DVLOG_IF(1, !granted) << "Permission request rejected."; |
225 | 225 |
226 media_keys_->CreateSessionAndGenerateRequest(session_type, init_data_type, | 226 media_keys_->CreateSessionAndGenerateRequest(session_type, init_data_type, |
227 init_data, promise.Pass()); | 227 init_data, promise.Pass()); |
228 } | 228 } |
229 | 229 |
230 void ProxyDecryptor::AddKey(const uint8* key, | 230 void ProxyDecryptor::AddKey(const uint8_t* key, |
231 int key_length, | 231 int key_length, |
232 const uint8* init_data, | 232 const uint8_t* init_data, |
233 int init_data_length, | 233 int init_data_length, |
234 const std::string& session_id) { | 234 const std::string& session_id) { |
235 DVLOG(1) << "AddKey()"; | 235 DVLOG(1) << "AddKey()"; |
236 | 236 |
237 if (!media_keys_) { | 237 if (!media_keys_) { |
238 OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0, | 238 OnLegacySessionError(std::string(), MediaKeys::INVALID_STATE_ERROR, 0, |
239 "CDM is not available."); | 239 "CDM is not available."); |
240 return; | 240 return; |
241 } | 241 } |
242 | 242 |
(...skipping 18 matching lines...) Expand all Loading... |
261 weak_ptr_factory_.GetWeakPtr(), session_id))); | 261 weak_ptr_factory_.GetWeakPtr(), session_id))); |
262 | 262 |
263 // EME WD spec only supports a single array passed to the CDM. For | 263 // EME WD spec only supports a single array passed to the CDM. For |
264 // Clear Key using v0.1b, both arrays are used (|init_data| is key_id). | 264 // Clear Key using v0.1b, both arrays are used (|init_data| is key_id). |
265 // Since the EME WD spec supports the key as a JSON Web Key, | 265 // Since the EME WD spec supports the key as a JSON Web Key, |
266 // convert the 2 arrays to a JWK and pass it as the single array. | 266 // convert the 2 arrays to a JWK and pass it as the single array. |
267 if (is_clear_key_) { | 267 if (is_clear_key_) { |
268 // Decryptor doesn't support empty key ID (see http://crbug.com/123265). | 268 // Decryptor doesn't support empty key ID (see http://crbug.com/123265). |
269 // So ensure a non-empty value is passed. | 269 // So ensure a non-empty value is passed. |
270 if (!init_data) { | 270 if (!init_data) { |
271 static const uint8 kDummyInitData[1] = {0}; | 271 static const uint8_t kDummyInitData[1] = {0}; |
272 init_data = kDummyInitData; | 272 init_data = kDummyInitData; |
273 init_data_length = arraysize(kDummyInitData); | 273 init_data_length = arraysize(kDummyInitData); |
274 } | 274 } |
275 | 275 |
276 std::string jwk = | 276 std::string jwk = |
277 GenerateJWKSet(key, key_length, init_data, init_data_length); | 277 GenerateJWKSet(key, key_length, init_data, init_data_length); |
278 DCHECK(!jwk.empty()); | 278 DCHECK(!jwk.empty()); |
279 media_keys_->UpdateSession(new_session_id, | 279 media_keys_->UpdateSession(new_session_id, |
280 std::vector<uint8_t>(jwk.begin(), jwk.end()), | 280 std::vector<uint8_t>(jwk.begin(), jwk.end()), |
281 promise.Pass()); | 281 promise.Pass()); |
(...skipping 17 matching lines...) Expand all Loading... |
299 scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>( | 299 scoped_ptr<SimpleCdmPromise> promise(new CdmCallbackPromise<>( |
300 base::Bind(&ProxyDecryptor::OnSessionClosed, | 300 base::Bind(&ProxyDecryptor::OnSessionClosed, |
301 weak_ptr_factory_.GetWeakPtr(), session_id), | 301 weak_ptr_factory_.GetWeakPtr(), session_id), |
302 base::Bind(&ProxyDecryptor::OnLegacySessionError, | 302 base::Bind(&ProxyDecryptor::OnLegacySessionError, |
303 weak_ptr_factory_.GetWeakPtr(), session_id))); | 303 weak_ptr_factory_.GetWeakPtr(), session_id))); |
304 media_keys_->RemoveSession(session_id, promise.Pass()); | 304 media_keys_->RemoveSession(session_id, promise.Pass()); |
305 } | 305 } |
306 | 306 |
307 void ProxyDecryptor::OnSessionMessage(const std::string& session_id, | 307 void ProxyDecryptor::OnSessionMessage(const std::string& session_id, |
308 MediaKeys::MessageType message_type, | 308 MediaKeys::MessageType message_type, |
309 const std::vector<uint8>& message, | 309 const std::vector<uint8_t>& message, |
310 const GURL& legacy_destination_url) { | 310 const GURL& legacy_destination_url) { |
311 // Assumes that OnSessionCreated() has been called before this. | 311 // Assumes that OnSessionCreated() has been called before this. |
312 | 312 |
313 // For ClearKey, convert the message from JSON into just passing the key | 313 // For ClearKey, convert the message from JSON into just passing the key |
314 // as the message. If unable to extract the key, return the message unchanged. | 314 // as the message. If unable to extract the key, return the message unchanged. |
315 if (is_clear_key_) { | 315 if (is_clear_key_) { |
316 std::vector<uint8> key; | 316 std::vector<uint8_t> key; |
317 if (ExtractFirstKeyIdFromLicenseRequest(message, &key)) { | 317 if (ExtractFirstKeyIdFromLicenseRequest(message, &key)) { |
318 key_message_cb_.Run(session_id, key, legacy_destination_url); | 318 key_message_cb_.Run(session_id, key, legacy_destination_url); |
319 return; | 319 return; |
320 } | 320 } |
321 } | 321 } |
322 | 322 |
323 key_message_cb_.Run(session_id, message, legacy_destination_url); | 323 key_message_cb_.Run(session_id, message, legacy_destination_url); |
324 } | 324 } |
325 | 325 |
326 void ProxyDecryptor::OnSessionKeysChange(const std::string& session_id, | 326 void ProxyDecryptor::OnSessionKeysChange(const std::string& session_id, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 if (it->second) { | 359 if (it->second) { |
360 OnLegacySessionError(session_id, MediaKeys::NOT_SUPPORTED_ERROR, | 360 OnLegacySessionError(session_id, MediaKeys::NOT_SUPPORTED_ERROR, |
361 kSessionClosedSystemCode, | 361 kSessionClosedSystemCode, |
362 "Do not close persistent sessions."); | 362 "Do not close persistent sessions."); |
363 } | 363 } |
364 active_sessions_.erase(it); | 364 active_sessions_.erase(it); |
365 } | 365 } |
366 | 366 |
367 void ProxyDecryptor::OnLegacySessionError(const std::string& session_id, | 367 void ProxyDecryptor::OnLegacySessionError(const std::string& session_id, |
368 MediaKeys::Exception exception_code, | 368 MediaKeys::Exception exception_code, |
369 uint32 system_code, | 369 uint32_t system_code, |
370 const std::string& error_message) { | 370 const std::string& error_message) { |
371 // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed | 371 // Convert |error_name| back to MediaKeys::KeyError if possible. Prefixed |
372 // EME has different error message, so all the specific error events will | 372 // EME has different error message, so all the specific error events will |
373 // get lost. | 373 // get lost. |
374 MediaKeys::KeyError error_code; | 374 MediaKeys::KeyError error_code; |
375 switch (exception_code) { | 375 switch (exception_code) { |
376 case MediaKeys::CLIENT_ERROR: | 376 case MediaKeys::CLIENT_ERROR: |
377 error_code = MediaKeys::kClientError; | 377 error_code = MediaKeys::kClientError; |
378 break; | 378 break; |
379 case MediaKeys::OUTPUT_ERROR: | 379 case MediaKeys::OUTPUT_ERROR: |
(...skipping 22 matching lines...) Expand all Loading... |
402 bool is_persistent = | 402 bool is_persistent = |
403 session_type == PersistentSession || session_type == LoadSession; | 403 session_type == PersistentSession || session_type == LoadSession; |
404 active_sessions_.insert(std::make_pair(session_id, is_persistent)); | 404 active_sessions_.insert(std::make_pair(session_id, is_persistent)); |
405 | 405 |
406 // For LoadSession(), generate the KeyAdded event. | 406 // For LoadSession(), generate the KeyAdded event. |
407 if (session_type == LoadSession) | 407 if (session_type == LoadSession) |
408 GenerateKeyAdded(session_id); | 408 GenerateKeyAdded(session_id); |
409 } | 409 } |
410 | 410 |
411 } // namespace media | 411 } // namespace media |
OLD | NEW |