| 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/clear_key_cdm.h" | 5 #include "media/cdm/ppapi/clear_key_cdm.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/debug/trace_event.h" | 13 #include "base/debug/trace_event.h" |
| 14 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/time/time.h" | 15 #include "base/time/time.h" |
| 16 #include "media/base/decoder_buffer.h" | 16 #include "media/base/decoder_buffer.h" |
| 17 #include "media/base/decrypt_config.h" | 17 #include "media/base/decrypt_config.h" |
| 18 #include "media/cdm/ppapi/cdm_file_io_test.h" |
| 18 #include "media/cdm/ppapi/cdm_video_decoder.h" | 19 #include "media/cdm/ppapi/cdm_video_decoder.h" |
| 19 | 20 |
| 20 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) | 21 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
| 21 #include "base/basictypes.h" | 22 #include "base/basictypes.h" |
| 22 const int64 kNoTimestamp = kint64min; | 23 const int64 kNoTimestamp = kint64min; |
| 23 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER | 24 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| 24 | 25 |
| 25 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) | 26 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) |
| 26 #include "base/at_exit.h" | 27 #include "base/at_exit.h" |
| 27 #include "base/files/file_path.h" | 28 #include "base/files/file_path.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 56 return true; | 57 return true; |
| 57 } | 58 } |
| 58 | 59 |
| 59 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries(); | 60 static bool g_ffmpeg_lib_initialized = InitializeFFmpegLibraries(); |
| 60 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER | 61 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER |
| 61 | 62 |
| 62 const char kClearKeyCdmVersion[] = "0.1.0.1"; | 63 const char kClearKeyCdmVersion[] = "0.1.0.1"; |
| 63 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey"; | 64 const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey"; |
| 64 const char kExternalClearKeyDecryptOnlyKeySystem[] = | 65 const char kExternalClearKeyDecryptOnlyKeySystem[] = |
| 65 "org.chromium.externalclearkey.decryptonly"; | 66 "org.chromium.externalclearkey.decryptonly"; |
| 67 const char kExternalClearKeyFileIOTestKeySystem[] = |
| 68 "org.chromium.externalclearkey.fileiotest"; |
| 66 const int64 kSecondsPerMinute = 60; | 69 const int64 kSecondsPerMinute = 60; |
| 67 const int64 kMsPerSecond = 1000; | 70 const int64 kMsPerSecond = 1000; |
| 68 const int64 kInitialTimerDelayMs = 200; | 71 const int64 kInitialTimerDelayMs = 200; |
| 69 const int64 kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond; | 72 const int64 kMaxTimerDelayMs = 1 * kSecondsPerMinute * kMsPerSecond; |
| 70 // Heart beat message header. If a key message starts with |kHeartBeatHeader|, | 73 // Heart beat message header. If a key message starts with |kHeartBeatHeader|, |
| 71 // it's a heart beat message. Otherwise, it's a key request. | 74 // it's a heart beat message. Otherwise, it's a key request. |
| 72 const char kHeartBeatHeader[] = "HEARTBEAT"; | 75 const char kHeartBeatHeader[] = "HEARTBEAT"; |
| 76 // CDM file IO test result header. |
| 77 const char kFileIOTestResultHeader[] = "FILEIOTESTRESULT"; |
| 73 | 78 |
| 74 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is | 79 // Copies |input_buffer| into a media::DecoderBuffer. If the |input_buffer| is |
| 75 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. | 80 // empty, an empty (end-of-stream) media::DecoderBuffer is returned. |
| 76 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( | 81 static scoped_refptr<media::DecoderBuffer> CopyDecoderBufferFrom( |
| 77 const cdm::InputBuffer& input_buffer) { | 82 const cdm::InputBuffer& input_buffer) { |
| 78 if (!input_buffer.data) { | 83 if (!input_buffer.data) { |
| 79 DCHECK(!input_buffer.data_size); | 84 DCHECK(!input_buffer.data_size); |
| 80 return media::DecoderBuffer::CreateEOSBuffer(); | 85 return media::DecoderBuffer::CreateEOSBuffer(); |
| 81 } | 86 } |
| 82 | 87 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 100 input_buffer.data_offset, | 105 input_buffer.data_offset, |
| 101 subsamples)); | 106 subsamples)); |
| 102 | 107 |
| 103 output_buffer->set_decrypt_config(decrypt_config.Pass()); | 108 output_buffer->set_decrypt_config(decrypt_config.Pass()); |
| 104 output_buffer->set_timestamp( | 109 output_buffer->set_timestamp( |
| 105 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); | 110 base::TimeDelta::FromMicroseconds(input_buffer.timestamp)); |
| 106 | 111 |
| 107 return output_buffer; | 112 return output_buffer; |
| 108 } | 113 } |
| 109 | 114 |
| 115 static std::string GetFileIOTestResultMessage(bool success) { |
| 116 std::string message(kFileIOTestResultHeader); |
| 117 message += success ? '1' : '0'; |
| 118 return message; |
| 119 } |
| 120 |
| 110 template<typename Type> | 121 template<typename Type> |
| 111 class ScopedResetter { | 122 class ScopedResetter { |
| 112 public: | 123 public: |
| 113 explicit ScopedResetter(Type* object) : object_(object) {} | 124 explicit ScopedResetter(Type* object) : object_(object) {} |
| 114 ~ScopedResetter() { object_->Reset(); } | 125 ~ScopedResetter() { object_->Reset(); } |
| 115 | 126 |
| 116 private: | 127 private: |
| 117 Type* const object_; | 128 Type* const object_; |
| 118 }; | 129 }; |
| 119 | 130 |
| 120 void INITIALIZE_CDM_MODULE() { | 131 void INITIALIZE_CDM_MODULE() { |
| 121 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) | 132 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) |
| 122 DVLOG(2) << "FFmpeg libraries initialized: " << g_ffmpeg_lib_initialized; | 133 DVLOG(2) << "FFmpeg libraries initialized: " << g_ffmpeg_lib_initialized; |
| 123 av_register_all(); | 134 av_register_all(); |
| 124 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER | 135 #endif // CLEAR_KEY_CDM_USE_FFMPEG_DECODER |
| 125 } | 136 } |
| 126 | 137 |
| 127 void DeinitializeCdmModule() { | 138 void DeinitializeCdmModule() { |
| 128 } | 139 } |
| 129 | 140 |
| 130 void* CreateCdmInstance(int cdm_interface_version, | 141 void* CreateCdmInstance(int cdm_interface_version, |
| 131 const char* key_system, uint32_t key_system_size, | 142 const char* key_system, uint32_t key_system_size, |
| 132 GetCdmHostFunc get_cdm_host_func, | 143 GetCdmHostFunc get_cdm_host_func, |
| 133 void* user_data) { | 144 void* user_data) { |
| 134 DVLOG(1) << "CreateCdmInstance()"; | 145 DVLOG(1) << "CreateCdmInstance()"; |
| 135 | 146 |
| 136 std::string key_system_string(key_system, key_system_size); | 147 std::string key_system_string(key_system, key_system_size); |
| 137 if (key_system_string != kExternalClearKeyKeySystem && | 148 if (key_system_string != kExternalClearKeyKeySystem && |
| 138 key_system_string != kExternalClearKeyDecryptOnlyKeySystem) { | 149 key_system_string != kExternalClearKeyDecryptOnlyKeySystem && |
| 150 key_system_string != kExternalClearKeyFileIOTestKeySystem) { |
| 139 DVLOG(1) << "Unsupported key system:" << key_system_string; | 151 DVLOG(1) << "Unsupported key system:" << key_system_string; |
| 140 return NULL; | 152 return NULL; |
| 141 } | 153 } |
| 142 | 154 |
| 143 if (cdm_interface_version != media::ClearKeyCdmInterface::kVersion) | 155 if (cdm_interface_version != media::ClearKeyCdmInterface::kVersion) |
| 144 return NULL; | 156 return NULL; |
| 145 | 157 |
| 146 media::ClearKeyCdmHost* host = static_cast<media::ClearKeyCdmHost*>( | 158 media::ClearKeyCdmHost* host = static_cast<media::ClearKeyCdmHost*>( |
| 147 get_cdm_host_func(media::ClearKeyCdmHost::kVersion, user_data)); | 159 get_cdm_host_func(media::ClearKeyCdmHost::kVersion, user_data)); |
| 148 if (!host) | 160 if (!host) |
| 149 return NULL; | 161 return NULL; |
| 150 | 162 |
| 151 return new media::ClearKeyCdm( | 163 return new media::ClearKeyCdm( |
| 152 host, key_system_string == kExternalClearKeyDecryptOnlyKeySystem); | 164 host, |
| 165 key_system_string == kExternalClearKeyDecryptOnlyKeySystem, |
| 166 key_system_string == kExternalClearKeyFileIOTestKeySystem); |
| 153 } | 167 } |
| 154 | 168 |
| 155 const char* GetCdmVersion() { | 169 const char* GetCdmVersion() { |
| 156 return kClearKeyCdmVersion; | 170 return kClearKeyCdmVersion; |
| 157 } | 171 } |
| 158 | 172 |
| 159 namespace media { | 173 namespace media { |
| 160 | 174 |
| 161 // Since all the calls to AesDecryptor are synchronous, pass a dummy value for | 175 // Since all the calls to AesDecryptor are synchronous, pass a dummy value for |
| 162 // session_id that is never exposed outside this class. | 176 // session_id that is never exposed outside this class. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 } | 214 } |
| 201 | 215 |
| 202 void ClearKeyCdm::Client::OnSessionError(uint32 session_id, | 216 void ClearKeyCdm::Client::OnSessionError(uint32 session_id, |
| 203 media::MediaKeys::KeyError error_code, | 217 media::MediaKeys::KeyError error_code, |
| 204 int system_code) { | 218 int system_code) { |
| 205 status_ = static_cast<Status>(status_ | kError); | 219 status_ = static_cast<Status>(status_ | kError); |
| 206 error_code_ = error_code; | 220 error_code_ = error_code; |
| 207 system_code_ = system_code; | 221 system_code_ = system_code; |
| 208 } | 222 } |
| 209 | 223 |
| 210 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, bool is_decrypt_only) | 224 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, |
| 225 bool is_decrypt_only, |
| 226 bool should_test_file_io) |
| 211 : decryptor_( | 227 : decryptor_( |
| 212 base::Bind(&Client::OnSessionCreated, base::Unretained(&client_)), | 228 base::Bind(&Client::OnSessionCreated, base::Unretained(&client_)), |
| 213 base::Bind(&Client::OnSessionMessage, base::Unretained(&client_)), | 229 base::Bind(&Client::OnSessionMessage, base::Unretained(&client_)), |
| 214 base::Bind(&Client::OnSessionReady, base::Unretained(&client_)), | 230 base::Bind(&Client::OnSessionReady, base::Unretained(&client_)), |
| 215 base::Bind(&Client::OnSessionClosed, base::Unretained(&client_)), | 231 base::Bind(&Client::OnSessionClosed, base::Unretained(&client_)), |
| 216 base::Bind(&Client::OnSessionError, base::Unretained(&client_))), | 232 base::Bind(&Client::OnSessionError, base::Unretained(&client_))), |
| 217 host_(host), | 233 host_(host), |
| 218 is_decrypt_only_(is_decrypt_only), | 234 is_decrypt_only_(is_decrypt_only), |
| 235 should_test_file_io_(should_test_file_io), |
| 219 timer_delay_ms_(kInitialTimerDelayMs), | 236 timer_delay_ms_(kInitialTimerDelayMs), |
| 220 timer_set_(false) { | 237 timer_set_(false) { |
| 221 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) | 238 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) |
| 222 channel_count_ = 0; | 239 channel_count_ = 0; |
| 223 bits_per_channel_ = 0; | 240 bits_per_channel_ = 0; |
| 224 samples_per_second_ = 0; | 241 samples_per_second_ = 0; |
| 225 output_timestamp_base_in_microseconds_ = kNoTimestamp; | 242 output_timestamp_base_in_microseconds_ = kNoTimestamp; |
| 226 total_samples_generated_ = 0; | 243 total_samples_generated_ = 0; |
| 227 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER | 244 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| 228 } | 245 } |
| (...skipping 13 matching lines...) Expand all Loading... |
| 242 | 259 |
| 243 if (client_.status() != (Client::kMessage | Client::kCreated)) { | 260 if (client_.status() != (Client::kMessage | Client::kCreated)) { |
| 244 // Use values returned to client if possible. | 261 // Use values returned to client if possible. |
| 245 host_->SendKeyError(client_.web_session_id().data(), | 262 host_->SendKeyError(client_.web_session_id().data(), |
| 246 client_.web_session_id().size(), | 263 client_.web_session_id().size(), |
| 247 static_cast<cdm::MediaKeyError>(client_.error_code()), | 264 static_cast<cdm::MediaKeyError>(client_.error_code()), |
| 248 client_.system_code()); | 265 client_.system_code()); |
| 249 return cdm::kSessionError; | 266 return cdm::kSessionError; |
| 250 } | 267 } |
| 251 | 268 |
| 269 std::string web_session_id = client_.web_session_id(); |
| 270 |
| 252 host_->SendKeyMessage( | 271 host_->SendKeyMessage( |
| 253 client_.web_session_id().data(), client_.web_session_id().size(), | 272 web_session_id.data(), web_session_id.size(), |
| 254 reinterpret_cast<const char*>(&client_.message()[0]), | 273 reinterpret_cast<const char*>(&client_.message()[0]), |
| 255 client_.message().size(), | 274 client_.message().size(), |
| 256 client_.destination_url().data(), client_.destination_url().size()); | 275 client_.destination_url().data(), client_.destination_url().size()); |
| 257 | 276 |
| 258 // Only save the latest session ID for heartbeat messages. | 277 // Save the latest session ID for heartbeat and file IO test messages. |
| 259 heartbeat_session_id_ = client_.web_session_id(); | 278 last_session_id_ = web_session_id; |
| 279 |
| 280 if (should_test_file_io_) |
| 281 StartFileIOTest(); |
| 260 | 282 |
| 261 return cdm::kSuccess; | 283 return cdm::kSuccess; |
| 262 } | 284 } |
| 263 | 285 |
| 264 cdm::Status ClearKeyCdm::AddKey(const char* session_id, | 286 cdm::Status ClearKeyCdm::AddKey(const char* session_id, |
| 265 uint32_t session_id_size, | 287 uint32_t session_id_size, |
| 266 const uint8_t* key, | 288 const uint8_t* key, |
| 267 uint32_t key_size, | 289 uint32_t key_size, |
| 268 const uint8_t* key_id, | 290 const uint8_t* key_id, |
| 269 uint32_t key_id_size) { | 291 uint32_t key_id_size) { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 heartbeat_message = next_heartbeat_message_; | 336 heartbeat_message = next_heartbeat_message_; |
| 315 } else { | 337 } else { |
| 316 heartbeat_message = "ERROR: Invalid timer context found!"; | 338 heartbeat_message = "ERROR: Invalid timer context found!"; |
| 317 } | 339 } |
| 318 | 340 |
| 319 // This URL is only used for testing the code path for defaultURL. | 341 // This URL is only used for testing the code path for defaultURL. |
| 320 // There is no service at this URL, so applications should ignore it. | 342 // There is no service at this URL, so applications should ignore it. |
| 321 const char url[] = "http://test.externalclearkey.chromium.org"; | 343 const char url[] = "http://test.externalclearkey.chromium.org"; |
| 322 | 344 |
| 323 host_->SendKeyMessage( | 345 host_->SendKeyMessage( |
| 324 heartbeat_session_id_.data(), heartbeat_session_id_.size(), | 346 last_session_id_.data(), last_session_id_.size(), |
| 325 heartbeat_message.data(), heartbeat_message.size(), | 347 heartbeat_message.data(), heartbeat_message.size(), |
| 326 url, arraysize(url) - 1); | 348 url, arraysize(url) - 1); |
| 327 | 349 |
| 328 ScheduleNextHeartBeat(); | 350 ScheduleNextHeartBeat(); |
| 329 } | 351 } |
| 330 | 352 |
| 331 static void CopyDecryptResults( | 353 static void CopyDecryptResults( |
| 332 media::Decryptor::Status* status_copy, | 354 media::Decryptor::Status* status_copy, |
| 333 scoped_refptr<media::DecoderBuffer>* buffer_copy, | 355 scoped_refptr<media::DecoderBuffer>* buffer_copy, |
| 334 media::Decryptor::Status status, | 356 media::Decryptor::Status status, |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 614 | 636 |
| 615 int samples_generated = GenerateFakeAudioFramesFromDuration( | 637 int samples_generated = GenerateFakeAudioFramesFromDuration( |
| 616 timestamp_in_microseconds - CurrentTimeStampInMicroseconds(), | 638 timestamp_in_microseconds - CurrentTimeStampInMicroseconds(), |
| 617 audio_frames); | 639 audio_frames); |
| 618 total_samples_generated_ += samples_generated; | 640 total_samples_generated_ += samples_generated; |
| 619 | 641 |
| 620 return samples_generated == 0 ? cdm::kNeedMoreData : cdm::kSuccess; | 642 return samples_generated == 0 ? cdm::kNeedMoreData : cdm::kSuccess; |
| 621 } | 643 } |
| 622 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER | 644 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER |
| 623 | 645 |
| 646 void ClearKeyCdm::StartFileIOTest() { |
| 647 file_io_test_runner_.reset(new FileIOTestRunner( |
| 648 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_)))); |
| 649 file_io_test_runner_->RunAllTests( |
| 650 base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this))); |
| 651 } |
| 652 |
| 653 void ClearKeyCdm::OnFileIOTestComplete(bool success) { |
| 654 DVLOG(1) << __FUNCTION__ << ": " << success; |
| 655 std::string message = GetFileIOTestResultMessage(success); |
| 656 host_->SendKeyMessage(last_session_id_.data(), last_session_id_.size(), |
| 657 message.data(), message.size(), |
| 658 NULL, 0); |
| 659 file_io_test_runner_.reset(); |
| 660 } |
| 661 |
| 624 } // namespace media | 662 } // namespace media |
| OLD | NEW |