| 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 |