| 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/ppapi/external_clear_key/clear_key_cdm.h" | 5 #include "media/cdm/ppapi/external_clear_key/clear_key_cdm.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <cstring> | 8 #include <cstring> |
| 9 #include <sstream> | 9 #include <sstream> |
| 10 | 10 |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 260 | 260 |
| 261 const char* GetCdmVersion() { | 261 const char* GetCdmVersion() { |
| 262 return kClearKeyCdmVersion; | 262 return kClearKeyCdmVersion; |
| 263 } | 263 } |
| 264 | 264 |
| 265 namespace media { | 265 namespace media { |
| 266 | 266 |
| 267 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, | 267 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, |
| 268 const std::string& key_system, | 268 const std::string& key_system, |
| 269 const GURL& origin) | 269 const GURL& origin) |
| 270 : decryptor_( | 270 : decryptor_(new AesDecryptor( |
| 271 origin, | 271 origin, |
| 272 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), | 272 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)), |
| 273 base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)), | 273 base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)), |
| 274 base::Bind(&ClearKeyCdm::OnSessionKeysChange, | 274 base::Bind(&ClearKeyCdm::OnSessionKeysChange, |
| 275 base::Unretained(this))), | 275 base::Unretained(this)))), |
| 276 host_(host), | 276 host_(host), |
| 277 key_system_(key_system), | 277 key_system_(key_system), |
| 278 has_received_keys_change_event_for_emulated_loadsession_(false), | 278 has_received_keys_change_event_for_emulated_loadsession_(false), |
| 279 timer_delay_ms_(kInitialTimerDelayMs), | 279 timer_delay_ms_(kInitialTimerDelayMs), |
| 280 renewal_timer_set_(false) { | 280 renewal_timer_set_(false) { |
| 281 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) | 281 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
| 282 channel_count_ = 0; | 282 channel_count_ = 0; |
| 283 bits_per_channel_ = 0; | 283 bits_per_channel_ = 0; |
| 284 samples_per_second_ = 0; | 284 samples_per_second_ = 0; |
| 285 output_timestamp_base_in_microseconds_ = kNoTimestamp; | 285 output_timestamp_base_in_microseconds_ = kNoTimestamp; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 304 DVLOG(1) << __FUNCTION__; | 304 DVLOG(1) << __FUNCTION__; |
| 305 | 305 |
| 306 scoped_ptr<media::NewSessionCdmPromise> promise( | 306 scoped_ptr<media::NewSessionCdmPromise> promise( |
| 307 new media::CdmCallbackPromise<std::string>( | 307 new media::CdmCallbackPromise<std::string>( |
| 308 base::Bind(&ClearKeyCdm::OnSessionCreated, | 308 base::Bind(&ClearKeyCdm::OnSessionCreated, |
| 309 base::Unretained(this), | 309 base::Unretained(this), |
| 310 promise_id), | 310 promise_id), |
| 311 base::Bind(&ClearKeyCdm::OnPromiseFailed, | 311 base::Bind(&ClearKeyCdm::OnPromiseFailed, |
| 312 base::Unretained(this), | 312 base::Unretained(this), |
| 313 promise_id))); | 313 promise_id))); |
| 314 decryptor_.CreateSessionAndGenerateRequest( | 314 decryptor_->CreateSessionAndGenerateRequest( |
| 315 ConvertSessionType(session_type), ConvertInitDataType(init_data_type), | 315 ConvertSessionType(session_type), ConvertInitDataType(init_data_type), |
| 316 std::vector<uint8_t>(init_data, init_data + init_data_size), | 316 std::vector<uint8_t>(init_data, init_data + init_data_size), |
| 317 promise.Pass()); | 317 promise.Pass()); |
| 318 | 318 |
| 319 if (key_system_ == kExternalClearKeyFileIOTestKeySystem) | 319 if (key_system_ == kExternalClearKeyFileIOTestKeySystem) |
| 320 StartFileIOTest(); | 320 StartFileIOTest(); |
| 321 } | 321 } |
| 322 | 322 |
| 323 // Loads a emulated stored session. Currently only |kLoadableSessionId| | 323 // Loads a emulated stored session. Currently only |kLoadableSessionId| |
| 324 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is | 324 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is |
| (...skipping 15 matching lines...) Expand all Loading... |
| 340 DCHECK(session_id_for_emulated_loadsession_.empty()); | 340 DCHECK(session_id_for_emulated_loadsession_.empty()); |
| 341 | 341 |
| 342 scoped_ptr<media::NewSessionCdmPromise> promise( | 342 scoped_ptr<media::NewSessionCdmPromise> promise( |
| 343 new media::CdmCallbackPromise<std::string>( | 343 new media::CdmCallbackPromise<std::string>( |
| 344 base::Bind(&ClearKeyCdm::OnSessionLoaded, | 344 base::Bind(&ClearKeyCdm::OnSessionLoaded, |
| 345 base::Unretained(this), | 345 base::Unretained(this), |
| 346 promise_id), | 346 promise_id), |
| 347 base::Bind(&ClearKeyCdm::OnPromiseFailed, | 347 base::Bind(&ClearKeyCdm::OnPromiseFailed, |
| 348 base::Unretained(this), | 348 base::Unretained(this), |
| 349 promise_id))); | 349 promise_id))); |
| 350 decryptor_.CreateSessionAndGenerateRequest( | 350 decryptor_->CreateSessionAndGenerateRequest( |
| 351 MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, | 351 MediaKeys::TEMPORARY_SESSION, EmeInitDataType::WEBM, |
| 352 std::vector<uint8_t>(), promise.Pass()); | 352 std::vector<uint8_t>(), promise.Pass()); |
| 353 } | 353 } |
| 354 | 354 |
| 355 void ClearKeyCdm::UpdateSession(uint32 promise_id, | 355 void ClearKeyCdm::UpdateSession(uint32 promise_id, |
| 356 const char* session_id, | 356 const char* session_id, |
| 357 uint32_t session_id_length, | 357 uint32_t session_id_length, |
| 358 const uint8* response, | 358 const uint8* response, |
| 359 uint32 response_size) { | 359 uint32 response_size) { |
| 360 DVLOG(1) << __FUNCTION__; | 360 DVLOG(1) << __FUNCTION__; |
| 361 std::string web_session_str(session_id, session_id_length); | 361 std::string web_session_str(session_id, session_id_length); |
| 362 | 362 |
| 363 // If updating the loadable session, use the actual session id generated. | 363 // If updating the loadable session, use the actual session id generated. |
| 364 if (web_session_str == std::string(kLoadableSessionId)) | 364 if (web_session_str == std::string(kLoadableSessionId)) |
| 365 web_session_str = session_id_for_emulated_loadsession_; | 365 web_session_str = session_id_for_emulated_loadsession_; |
| 366 | 366 |
| 367 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( | 367 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( |
| 368 base::Bind(&ClearKeyCdm::OnPromiseResolved, base::Unretained(this), | 368 base::Bind(&ClearKeyCdm::OnPromiseResolved, base::Unretained(this), |
| 369 promise_id), | 369 promise_id), |
| 370 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), | 370 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), |
| 371 promise_id))); | 371 promise_id))); |
| 372 decryptor_.UpdateSession( | 372 decryptor_->UpdateSession( |
| 373 web_session_str, std::vector<uint8_t>(response, response + response_size), | 373 web_session_str, std::vector<uint8_t>(response, response + response_size), |
| 374 promise.Pass()); | 374 promise.Pass()); |
| 375 | 375 |
| 376 if (!renewal_timer_set_) { | 376 if (!renewal_timer_set_) { |
| 377 ScheduleNextRenewal(); | 377 ScheduleNextRenewal(); |
| 378 renewal_timer_set_ = true; | 378 renewal_timer_set_ = true; |
| 379 } | 379 } |
| 380 } | 380 } |
| 381 | 381 |
| 382 void ClearKeyCdm::CloseSession(uint32 promise_id, | 382 void ClearKeyCdm::CloseSession(uint32 promise_id, |
| 383 const char* session_id, | 383 const char* session_id, |
| 384 uint32_t session_id_length) { | 384 uint32_t session_id_length) { |
| 385 DVLOG(1) << __FUNCTION__; | 385 DVLOG(1) << __FUNCTION__; |
| 386 std::string web_session_str(session_id, session_id_length); | 386 std::string web_session_str(session_id, session_id_length); |
| 387 | 387 |
| 388 // If closing the loadable session, use the actual session id generated. | 388 // If closing the loadable session, use the actual session id generated. |
| 389 if (web_session_str == std::string(kLoadableSessionId)) | 389 if (web_session_str == std::string(kLoadableSessionId)) |
| 390 web_session_str = session_id_for_emulated_loadsession_; | 390 web_session_str = session_id_for_emulated_loadsession_; |
| 391 | 391 |
| 392 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( | 392 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( |
| 393 base::Bind( | 393 base::Bind( |
| 394 &ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id), | 394 &ClearKeyCdm::OnPromiseResolved, base::Unretained(this), promise_id), |
| 395 base::Bind( | 395 base::Bind( |
| 396 &ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id))); | 396 &ClearKeyCdm::OnPromiseFailed, base::Unretained(this), promise_id))); |
| 397 decryptor_.CloseSession(web_session_str, promise.Pass()); | 397 decryptor_->CloseSession(web_session_str, promise.Pass()); |
| 398 } | 398 } |
| 399 | 399 |
| 400 void ClearKeyCdm::RemoveSession(uint32 promise_id, | 400 void ClearKeyCdm::RemoveSession(uint32 promise_id, |
| 401 const char* session_id, | 401 const char* session_id, |
| 402 uint32_t session_id_length) { | 402 uint32_t session_id_length) { |
| 403 DVLOG(1) << __FUNCTION__; | 403 DVLOG(1) << __FUNCTION__; |
| 404 std::string web_session_str(session_id, session_id_length); | 404 std::string web_session_str(session_id, session_id_length); |
| 405 | 405 |
| 406 // RemoveSession only allowed for the loadable session. | 406 // RemoveSession only allowed for the loadable session. |
| 407 if (web_session_str == std::string(kLoadableSessionId)) { | 407 if (web_session_str == std::string(kLoadableSessionId)) { |
| 408 web_session_str = session_id_for_emulated_loadsession_; | 408 web_session_str = session_id_for_emulated_loadsession_; |
| 409 } else { | 409 } else { |
| 410 // TODO(jrummell): This should be a DCHECK once blink does the proper | 410 // TODO(jrummell): This should be a DCHECK once blink does the proper |
| 411 // checks. | 411 // checks. |
| 412 std::string message("Not supported for non-persistent sessions."); | 412 std::string message("Not supported for non-persistent sessions."); |
| 413 host_->OnRejectPromise(promise_id, | 413 host_->OnRejectPromise(promise_id, |
| 414 cdm::kInvalidAccessError, | 414 cdm::kInvalidAccessError, |
| 415 0, | 415 0, |
| 416 message.data(), | 416 message.data(), |
| 417 message.length()); | 417 message.length()); |
| 418 return; | 418 return; |
| 419 } | 419 } |
| 420 | 420 |
| 421 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( | 421 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( |
| 422 base::Bind(&ClearKeyCdm::OnPromiseResolved, base::Unretained(this), | 422 base::Bind(&ClearKeyCdm::OnPromiseResolved, base::Unretained(this), |
| 423 promise_id), | 423 promise_id), |
| 424 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), | 424 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), |
| 425 promise_id))); | 425 promise_id))); |
| 426 decryptor_.RemoveSession(web_session_str, promise.Pass()); | 426 decryptor_->RemoveSession(web_session_str, promise.Pass()); |
| 427 } | 427 } |
| 428 | 428 |
| 429 void ClearKeyCdm::SetServerCertificate(uint32 promise_id, | 429 void ClearKeyCdm::SetServerCertificate(uint32 promise_id, |
| 430 const uint8_t* server_certificate_data, | 430 const uint8_t* server_certificate_data, |
| 431 uint32_t server_certificate_data_size) { | 431 uint32_t server_certificate_data_size) { |
| 432 // ClearKey doesn't use a server certificate. | 432 // ClearKey doesn't use a server certificate. |
| 433 host_->OnResolvePromise(promise_id); | 433 host_->OnResolvePromise(promise_id); |
| 434 } | 434 } |
| 435 | 435 |
| 436 void ClearKeyCdm::TimerExpired(void* context) { | 436 void ClearKeyCdm::TimerExpired(void* context) { |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 664 | 664 |
| 665 if (buffer->end_of_stream()) { | 665 if (buffer->end_of_stream()) { |
| 666 *decrypted_buffer = buffer; | 666 *decrypted_buffer = buffer; |
| 667 return cdm::kSuccess; | 667 return cdm::kSuccess; |
| 668 } | 668 } |
| 669 | 669 |
| 670 // Callback is called synchronously, so we can use variables on the stack. | 670 // Callback is called synchronously, so we can use variables on the stack. |
| 671 media::Decryptor::Status status = media::Decryptor::kError; | 671 media::Decryptor::Status status = media::Decryptor::kError; |
| 672 // The AesDecryptor does not care what the stream type is. Pass kVideo | 672 // The AesDecryptor does not care what the stream type is. Pass kVideo |
| 673 // for both audio and video decryption. | 673 // for both audio and video decryption. |
| 674 decryptor_.Decrypt( | 674 decryptor_->Decrypt( |
| 675 media::Decryptor::kVideo, | 675 media::Decryptor::kVideo, buffer, |
| 676 buffer, | |
| 677 base::Bind(&CopyDecryptResults, &status, decrypted_buffer)); | 676 base::Bind(&CopyDecryptResults, &status, decrypted_buffer)); |
| 678 | 677 |
| 679 if (status == media::Decryptor::kError) | 678 if (status == media::Decryptor::kError) |
| 680 return cdm::kDecryptError; | 679 return cdm::kDecryptError; |
| 681 | 680 |
| 682 if (status == media::Decryptor::kNoKey) | 681 if (status == media::Decryptor::kNoKey) |
| 683 return cdm::kNoKey; | 682 return cdm::kNoKey; |
| 684 | 683 |
| 685 DCHECK_EQ(status, media::Decryptor::kSuccess); | 684 DCHECK_EQ(status, media::Decryptor::kSuccess); |
| 686 return cdm::kSuccess; | 685 return cdm::kSuccess; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 700 | 699 |
| 701 void ClearKeyCdm::LoadLoadableSession() { | 700 void ClearKeyCdm::LoadLoadableSession() { |
| 702 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey, | 701 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey, |
| 703 sizeof(kLoadableSessionKey), | 702 sizeof(kLoadableSessionKey), |
| 704 kLoadableSessionKeyId, | 703 kLoadableSessionKeyId, |
| 705 sizeof(kLoadableSessionKeyId) - 1); | 704 sizeof(kLoadableSessionKeyId) - 1); |
| 706 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( | 705 scoped_ptr<media::SimpleCdmPromise> promise(new media::CdmCallbackPromise<>( |
| 707 base::Bind(&ClearKeyCdm::OnLoadSessionUpdated, base::Unretained(this)), | 706 base::Bind(&ClearKeyCdm::OnLoadSessionUpdated, base::Unretained(this)), |
| 708 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), | 707 base::Bind(&ClearKeyCdm::OnPromiseFailed, base::Unretained(this), |
| 709 promise_id_for_emulated_loadsession_))); | 708 promise_id_for_emulated_loadsession_))); |
| 710 decryptor_.UpdateSession(session_id_for_emulated_loadsession_, | 709 decryptor_->UpdateSession( |
| 711 std::vector<uint8_t>(jwk_set.begin(), jwk_set.end()), | 710 session_id_for_emulated_loadsession_, |
| 712 promise.Pass()); | 711 std::vector<uint8_t>(jwk_set.begin(), jwk_set.end()), promise.Pass()); |
| 713 } | 712 } |
| 714 | 713 |
| 715 void ClearKeyCdm::OnSessionMessage(const std::string& session_id, | 714 void ClearKeyCdm::OnSessionMessage(const std::string& session_id, |
| 716 MediaKeys::MessageType message_type, | 715 MediaKeys::MessageType message_type, |
| 717 const std::vector<uint8>& message, | 716 const std::vector<uint8>& message, |
| 718 const GURL& legacy_destination_url) { | 717 const GURL& legacy_destination_url) { |
| 719 DVLOG(1) << "OnSessionMessage: " << message.size(); | 718 DVLOG(1) << "OnSessionMessage: " << message.size(); |
| 720 | 719 |
| 721 // Ignore the message when we are waiting to update the loadable session. | 720 // Ignore the message when we are waiting to update the loadable session. |
| 722 if (session_id == session_id_for_emulated_loadsession_) | 721 if (session_id == session_id_for_emulated_loadsession_) |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 void ClearKeyCdm::OnFileIOTestComplete(bool success) { | 909 void ClearKeyCdm::OnFileIOTestComplete(bool success) { |
| 911 DVLOG(1) << __FUNCTION__ << ": " << success; | 910 DVLOG(1) << __FUNCTION__ << ": " << success; |
| 912 std::string message = GetFileIOTestResultMessage(success); | 911 std::string message = GetFileIOTestResultMessage(success); |
| 913 host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(), | 912 host_->OnSessionMessage(last_session_id_.data(), last_session_id_.length(), |
| 914 cdm::kLicenseRequest, message.data(), | 913 cdm::kLicenseRequest, message.data(), |
| 915 message.length(), NULL, 0); | 914 message.length(), NULL, 0); |
| 916 file_io_test_runner_.reset(); | 915 file_io_test_runner_.reset(); |
| 917 } | 916 } |
| 918 | 917 |
| 919 } // namespace media | 918 } // namespace media |
| OLD | NEW |