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 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 test_file_io_(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 (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 cdm_file_io_test_.reset(new FileIOTestRunner( |
| 648 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_)))); |
| 649 cdm_file_io_test_->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 cdm_file_io_test_.reset(); |
| 660 } |
| 661 |
624 } // namespace media | 662 } // namespace media |
OLD | NEW |