Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(605)

Side by Side Diff: media/cdm/ppapi/external_clear_key/clear_key_cdm.cc

Issue 265993002: Add Promises for EME (Chromium side) (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 #include <string> 10 #include <string>
11 #include <vector> 11 #include <vector>
12 12
13 #include "base/bind.h" 13 #include "base/bind.h"
14 #include "base/debug/trace_event.h" 14 #include "base/debug/trace_event.h"
15 #include "base/logging.h" 15 #include "base/logging.h"
16 #include "base/time/time.h" 16 #include "base/time/time.h"
17 #include "media/base/decoder_buffer.h" 17 #include "media/base/decoder_buffer.h"
18 #include "media/base/decrypt_config.h" 18 #include "media/base/decrypt_config.h"
19 #include "media/base/media_keys_session_promise.h"
19 #include "media/cdm/json_web_key.h" 20 #include "media/cdm/json_web_key.h"
20 #include "media/cdm/ppapi/cdm_file_io_test.h" 21 #include "media/cdm/ppapi/cdm_file_io_test.h"
21 #include "media/cdm/ppapi/external_clear_key/cdm_video_decoder.h" 22 #include "media/cdm/ppapi/external_clear_key/cdm_video_decoder.h"
22 23
23 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 24 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
24 #include "base/basictypes.h" 25 #include "base/basictypes.h"
25 const int64 kNoTimestamp = kint64min; 26 const int64 kNoTimestamp = kint64min;
26 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 27 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
27 28
28 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER) 29 #if defined(CLEAR_KEY_CDM_USE_FFMPEG_DECODER)
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 } 181 }
181 182
182 const char* GetCdmVersion() { 183 const char* GetCdmVersion() {
183 return kClearKeyCdmVersion; 184 return kClearKeyCdmVersion;
184 } 185 }
185 186
186 namespace media { 187 namespace media {
187 188
188 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system) 189 ClearKeyCdm::ClearKeyCdm(ClearKeyCdmHost* host, const std::string& key_system)
189 : decryptor_( 190 : decryptor_(
190 base::Bind(&ClearKeyCdm::OnSessionCreated, base::Unretained(this)), 191 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this))),
191 base::Bind(&ClearKeyCdm::OnSessionMessage, base::Unretained(this)),
192 base::Bind(&ClearKeyCdm::OnSessionReady, base::Unretained(this)),
193 base::Bind(&ClearKeyCdm::OnSessionClosed, base::Unretained(this)),
194 base::Bind(&ClearKeyCdm::OnSessionError, base::Unretained(this))),
195 host_(host), 192 host_(host),
196 key_system_(key_system), 193 key_system_(key_system),
197 last_session_id_(MediaKeys::kInvalidSessionId),
198 session_id_for_emulated_loadsession_(MediaKeys::kInvalidSessionId),
199 timer_delay_ms_(kInitialTimerDelayMs), 194 timer_delay_ms_(kInitialTimerDelayMs),
200 heartbeat_timer_set_(false) { 195 heartbeat_timer_set_(false) {
201 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 196 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
202 channel_count_ = 0; 197 channel_count_ = 0;
203 bits_per_channel_ = 0; 198 bits_per_channel_ = 0;
204 samples_per_second_ = 0; 199 samples_per_second_ = 0;
205 output_timestamp_base_in_microseconds_ = kNoTimestamp; 200 output_timestamp_base_in_microseconds_ = kNoTimestamp;
206 total_samples_generated_ = 0; 201 total_samples_generated_ = 0;
207 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER 202 #endif // CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER
208 } 203 }
209 204
210 ClearKeyCdm::~ClearKeyCdm() {} 205 ClearKeyCdm::~ClearKeyCdm() {}
211 206
212 void ClearKeyCdm::CreateSession(uint32 session_id, 207 #define COMPILE_ASSERT_MATCHING_ENUM(name) \
213 const char* type, 208 COMPILE_ASSERT(static_cast<int>(cdm::SessionType::name) == \
214 uint32 type_size, 209 static_cast<int>(MediaKeys::SessionType::name), \
210 mismatching_enums)
211 COMPILE_ASSERT_MATCHING_ENUM(kTemporary);
212 COMPILE_ASSERT_MATCHING_ENUM(kPersistent);
213 #undef COMPILE_ASSERT_MATCHING_ENUM
214
215 void ClearKeyCdm::CreateSession(uint32 promise_id,
216 const char* init_data_type,
217 uint32 init_data_type_size,
215 const uint8* init_data, 218 const uint8* init_data,
216 uint32 init_data_size) { 219 uint32 init_data_size,
220 cdm::SessionType session_type) {
217 DVLOG(1) << __FUNCTION__; 221 DVLOG(1) << __FUNCTION__;
218 decryptor_.CreateSession(
219 session_id, std::string(type, type_size), init_data, init_data_size);
220 222
221 // Save the latest session ID for heartbeat and file IO test messages. 223 scoped_ptr<media::MediaKeysSessionPromise> promise(
222 last_session_id_ = session_id; 224 new media::MediaKeysSessionPromise(
225 media::PromiseResolvedCB(),
226 base::Bind(&ClearKeyCdm::OnSessionCreated,
227 base::Unretained(this),
228 promise_id),
229 base::Bind(&ClearKeyCdm::OnSessionError,
230 base::Unretained(this),
231 promise_id)));
232 decryptor_.CreateSession(std::string(init_data_type, init_data_type_size),
233 init_data,
234 init_data_size,
235 static_cast<MediaKeys::SessionType>(session_type),
236 promise.Pass());
223 237
224 if (key_system_ == kExternalClearKeyFileIOTestKeySystem) 238 if (key_system_ == kExternalClearKeyFileIOTestKeySystem)
225 StartFileIOTest(); 239 StartFileIOTest();
226 } 240 }
227 241
228 // Loads a emulated stored session. Currently only |kLoadableWebSessionId| 242 // Loads a emulated stored session. Currently only |kLoadableWebSessionId|
229 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is 243 // (containing a |kLoadableSessionKey| for |kLoadableSessionKeyId|) is
230 // supported. 244 // supported.
231 void ClearKeyCdm::LoadSession(uint32_t session_id, 245 void ClearKeyCdm::LoadSession(uint32 promise_id,
232 const char* web_session_id, 246 const char* web_session_id,
233 uint32_t web_session_id_length) { 247 uint32_t web_session_id_length) {
234 DVLOG(1) << __FUNCTION__; 248 DVLOG(1) << __FUNCTION__;
235 249
236 if (std::string(kLoadableWebSessionId) != 250 if (std::string(kLoadableWebSessionId) !=
237 std::string(web_session_id, web_session_id_length)) { 251 std::string(web_session_id, web_session_id_length)) {
238 // TODO(xhwang): Report "NotFoundError" when we support DOMError style. 252 std::string error("NotFoundError");
239 OnSessionError(session_id, MediaKeys::kUnknownError, 0); 253 std::string message("Incorrect session id specified for LoadSession().");
254 host_->OnRejectPromise(promise_id,
255 error.data(),
256 error.length(),
257 0,
258 message.data(),
259 message.length());
240 return; 260 return;
241 } 261 }
242 262
243 session_id_for_emulated_loadsession_ = session_id; 263 scoped_ptr<media::MediaKeysSessionPromise> promise(
244 264 new media::MediaKeysSessionPromise(
245 decryptor_.CreateSession(session_id, kLoadableSessionContentType, NULL, 0); 265 media::PromiseResolvedCB(),
266 base::Bind(&ClearKeyCdm::OnSessionLoaded,
267 base::Unretained(this),
268 promise_id),
269 base::Bind(&ClearKeyCdm::OnSessionError,
270 base::Unretained(this),
271 promise_id)));
272 decryptor_.CreateSession(std::string(kLoadableSessionContentType),
273 NULL,
274 0,
275 MediaKeys::SessionType::kTemporary,
276 promise.Pass());
246 } 277 }
247 278
248 void ClearKeyCdm::UpdateSession(uint32 session_id, 279 void ClearKeyCdm::UpdateSession(uint32 promise_id,
280 const char* web_session_id,
281 uint32_t web_session_id_size,
249 const uint8* response, 282 const uint8* response,
250 uint32 response_size) { 283 uint32 response_size) {
251 DVLOG(1) << __FUNCTION__; 284 DVLOG(1) << __FUNCTION__;
252 decryptor_.UpdateSession(session_id, response, response_size); 285 std::string web_session_str(web_session_id, web_session_id_size);
286
287 scoped_ptr<media::MediaKeysSessionPromise> promise(
288 new media::MediaKeysSessionPromise(
289 base::Bind(&ClearKeyCdm::OnSessionReady,
290 base::Unretained(this),
291 promise_id,
292 web_session_str),
293 media::PromiseResolvedWithSessionCB(),
294 base::Bind(&ClearKeyCdm::OnSessionError,
295 base::Unretained(this),
296 promise_id)));
297 decryptor_.UpdateSession(
298 web_session_str, response, response_size, promise.Pass());
253 299
254 if (!heartbeat_timer_set_) { 300 if (!heartbeat_timer_set_) {
255 ScheduleNextHeartBeat(); 301 ScheduleNextHeartBeat();
256 heartbeat_timer_set_ = true; 302 heartbeat_timer_set_ = true;
257 } 303 }
258 } 304 }
259 305
260 void ClearKeyCdm::ReleaseSession(uint32 session_id) { 306 void ClearKeyCdm::ReleaseSession(uint32 promise_id,
307 const char* web_session_id,
308 uint32_t web_session_id_size) {
261 DVLOG(1) << __FUNCTION__; 309 DVLOG(1) << __FUNCTION__;
262 decryptor_.ReleaseSession(session_id); 310 std::string web_session_str(web_session_id, web_session_id_size);
311
312 scoped_ptr<media::MediaKeysSessionPromise> promise(
313 new media::MediaKeysSessionPromise(
314 base::Bind(&ClearKeyCdm::OnSessionClosed,
315 base::Unretained(this),
316 promise_id,
317 web_session_str),
318 media::PromiseResolvedWithSessionCB(),
319 base::Bind(&ClearKeyCdm::OnSessionError,
320 base::Unretained(this),
321 promise_id)));
322 decryptor_.ReleaseSession(web_session_str, promise.Pass());
263 } 323 }
264 324
265 void ClearKeyCdm::TimerExpired(void* context) { 325 void ClearKeyCdm::TimerExpired(void* context) {
266 if (context == &session_id_for_emulated_loadsession_) { 326 if (context == &session_id_for_emulated_loadsession_) {
267 LoadLoadableSession(); 327 LoadLoadableSession();
268 return; 328 return;
269 } 329 }
270 330
271 DCHECK(heartbeat_timer_set_); 331 DCHECK(heartbeat_timer_set_);
272 std::string heartbeat_message; 332 std::string heartbeat_message;
273 if (!next_heartbeat_message_.empty() && 333 if (!next_heartbeat_message_.empty() &&
274 context == &next_heartbeat_message_[0]) { 334 context == &next_heartbeat_message_[0]) {
275 heartbeat_message = next_heartbeat_message_; 335 heartbeat_message = next_heartbeat_message_;
276 } else { 336 } else {
277 heartbeat_message = "ERROR: Invalid timer context found!"; 337 heartbeat_message = "ERROR: Invalid timer context found!";
278 } 338 }
279 339
280 // This URL is only used for testing the code path for defaultURL. 340 // This URL is only used for testing the code path for defaultURL.
281 // There is no service at this URL, so applications should ignore it. 341 // There is no service at this URL, so applications should ignore it.
282 const char url[] = "http://test.externalclearkey.chromium.org"; 342 const char url[] = "http://test.externalclearkey.chromium.org";
283 343
284 host_->OnSessionMessage(last_session_id_, 344 host_->OnSessionMessage(last_session_id_.data(),
345 last_session_id_.length(),
285 heartbeat_message.data(), 346 heartbeat_message.data(),
286 heartbeat_message.size(), 347 heartbeat_message.length(),
287 url, 348 url,
288 arraysize(url) - 1); 349 arraysize(url) - 1);
289 350
290 ScheduleNextHeartBeat(); 351 ScheduleNextHeartBeat();
291 } 352 }
292 353
293 static void CopyDecryptResults( 354 static void CopyDecryptResults(
294 media::Decryptor::Status* status_copy, 355 media::Decryptor::Status* status_copy,
295 scoped_refptr<media::DecoderBuffer>* buffer_copy, 356 scoped_refptr<media::DecoderBuffer>* buffer_copy,
296 media::Decryptor::Status status, 357 media::Decryptor::Status status,
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after
528 NOTIMPLEMENTED(); 589 NOTIMPLEMENTED();
529 }; 590 };
530 591
531 void ClearKeyCdm::LoadLoadableSession() { 592 void ClearKeyCdm::LoadLoadableSession() {
532 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey, 593 std::string jwk_set = GenerateJWKSet(kLoadableSessionKey,
533 sizeof(kLoadableSessionKey), 594 sizeof(kLoadableSessionKey),
534 kLoadableSessionKeyId, 595 kLoadableSessionKeyId,
535 sizeof(kLoadableSessionKeyId) - 1); 596 sizeof(kLoadableSessionKeyId) - 1);
536 // TODO(xhwang): This triggers OnSessionUpdated(). For prefixed EME support, 597 // TODO(xhwang): This triggers OnSessionUpdated(). For prefixed EME support,
537 // this is okay. Check WD EME support. 598 // this is okay. Check WD EME support.
599 scoped_ptr<media::MediaKeysSessionPromise> promise(
600 new media::MediaKeysSessionPromise(
601 base::Bind(&ClearKeyCdm::OnSessionReady,
602 base::Unretained(this),
603 promise_id_for_emulated_loadsession_,
604 session_id_for_emulated_loadsession_),
605 media::PromiseResolvedWithSessionCB(),
606 base::Bind(&ClearKeyCdm::OnSessionError,
607 base::Unretained(this),
608 promise_id_for_emulated_loadsession_)));
538 decryptor_.UpdateSession(session_id_for_emulated_loadsession_, 609 decryptor_.UpdateSession(session_id_for_emulated_loadsession_,
539 reinterpret_cast<const uint8*>(jwk_set.data()), 610 reinterpret_cast<const uint8*>(jwk_set.data()),
540 jwk_set.size()); 611 jwk_set.size(),
612 promise.Pass());
541 } 613 }
542 614
543 void ClearKeyCdm::OnSessionCreated(uint32 session_id, 615 void ClearKeyCdm::OnSessionMessage(const std::string& web_session_id,
544 const std::string& web_session_id) {
545 std::string new_web_session_id = web_session_id;
546
547 if (session_id == session_id_for_emulated_loadsession_) {
548 // Delay LoadLoadableSession() to test the case where Decrypt*() calls are
549 // made before the session is fully loaded.
550 const int64 kDelayToLoadSessionMs = 500;
551 // Use the address of |session_id_for_emulated_loadsession_| as the timer
552 // context so that we can call LoadLoadableSession() when the timer expires.
553 host_->SetTimer(kDelayToLoadSessionMs,
554 &session_id_for_emulated_loadsession_);
555 // Defer OnSessionCreated() until the session is loaded.
556 return;
557 }
558
559 host_->OnSessionCreated(
560 session_id, web_session_id.data(), web_session_id.size());
561 }
562
563 void ClearKeyCdm::OnSessionMessage(uint32 session_id,
564 const std::vector<uint8>& message, 616 const std::vector<uint8>& message,
565 const std::string& destination_url) { 617 const std::string& destination_url) {
566 DVLOG(1) << "OnSessionMessage: " << message.size(); 618 DVLOG(1) << "OnSessionMessage: " << message.size();
567 619
568 // Ignore the message when we are waiting to update the loadable session. 620 // Ignore the message when we are waiting to update the loadable session.
569 if (session_id == session_id_for_emulated_loadsession_) 621 if (web_session_id == session_id_for_emulated_loadsession_)
570 return; 622 return;
571 623
572 host_->OnSessionMessage(session_id, 624 // OnSessionMessage() only called during CreateSession(), so no promise
625 // involved (OnSessionCreated() called to resolve the CreateSession()
626 // promise).
627 host_->OnSessionMessage(web_session_id.data(),
628 web_session_id.length(),
573 reinterpret_cast<const char*>(message.data()), 629 reinterpret_cast<const char*>(message.data()),
574 message.size(), 630 message.size(),
575 destination_url.data(), 631 destination_url.data(),
576 destination_url.size()); 632 destination_url.length());
577 } 633 }
578 634
579 void ClearKeyCdm::OnSessionReady(uint32 session_id) { 635 void ClearKeyCdm::OnSessionCreated(uint32 promise_id,
580 if (session_id == session_id_for_emulated_loadsession_) { 636 const std::string& web_session_id) {
581 session_id_for_emulated_loadsession_ = MediaKeys::kInvalidSessionId; 637 // Save the latest session ID for heartbeat and file IO test messages.
582 host_->OnSessionCreated( 638 last_session_id_ = web_session_id;
583 session_id, kLoadableWebSessionId, strlen(kLoadableWebSessionId)); 639
640 host_->OnResolveNewSessionPromise(
641 promise_id, web_session_id.data(), web_session_id.length());
642 }
643
644 void ClearKeyCdm::OnSessionLoaded(uint32 promise_id,
645 const std::string& web_session_id) {
646 // Save the latest session ID for heartbeat and file IO test messages.
647 last_session_id_ = web_session_id;
648
649 // |decryptor_| created some session as |web_session_id|, but going forward
650 // we need to map that to |kLoadableWebSessionId|, as that is what callers
651 // expect.
652 session_id_for_emulated_loadsession_ = web_session_id;
653
654 // Delay LoadLoadableSession() to test the case where Decrypt*() calls are
655 // made before the session is fully loaded.
656 const int64 kDelayToLoadSessionMs = 500;
657
658 // Defer resolving the promise until the session is loaded.
659 promise_id_for_emulated_loadsession_ = promise_id;
660
661 // Use the address of |session_id_for_emulated_loadsession_| as the timer
662 // context so that we can call LoadLoadableSession() when the timer expires.
663 host_->SetTimer(kDelayToLoadSessionMs, &session_id_for_emulated_loadsession_);
664 }
665
666 void ClearKeyCdm::OnSessionReady(uint32 promise_id,
667 const std::string& web_session_id) {
668 // OnSessionReady() only called as success for UpdateSession(). However,
669 // UpdateSession() also called to finish loading sessions, so handle
670 // appropriately.
671 if (web_session_id == session_id_for_emulated_loadsession_) {
672 session_id_for_emulated_loadsession_ = std::string();
673 // |promise_id| is the LoadSession() promise, so resolve appropriately.
674 host_->OnResolveNewSessionPromise(
675 promise_id, kLoadableWebSessionId, strlen(kLoadableWebSessionId));
676 host_->OnSessionReady(kLoadableWebSessionId, strlen(kLoadableWebSessionId));
677 return;
584 } 678 }
585 679
586 host_->OnSessionReady(session_id); 680 host_->OnResolvePromise(promise_id);
587 } 681 }
588 682
589 void ClearKeyCdm::OnSessionClosed(uint32 session_id) { 683 void ClearKeyCdm::OnSessionClosed(uint32 promise_id,
590 host_->OnSessionClosed(session_id); 684 const std::string& web_session_id) {
685 host_->OnResolvePromise(promise_id);
591 } 686 }
592 687
593 void ClearKeyCdm::OnSessionError(uint32 session_id, 688 void ClearKeyCdm::OnSessionError(uint32 promise_id,
594 media::MediaKeys::KeyError error_code, 689 const std::string& error_name,
595 uint32 system_code) { 690 uint32 system_code,
596 host_->OnSessionError( 691 const std::string& error_message) {
597 session_id, static_cast<cdm::MediaKeyError>(error_code), system_code); 692 host_->OnRejectPromise(promise_id,
693 error_name.data(),
694 error_name.length(),
695 system_code,
696 error_message.data(),
697 error_message.length());
598 } 698 }
599 699
600 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER) 700 #if defined(CLEAR_KEY_CDM_USE_FAKE_AUDIO_DECODER)
601 int64 ClearKeyCdm::CurrentTimeStampInMicroseconds() const { 701 int64 ClearKeyCdm::CurrentTimeStampInMicroseconds() const {
602 return output_timestamp_base_in_microseconds_ + 702 return output_timestamp_base_in_microseconds_ +
603 base::Time::kMicrosecondsPerSecond * 703 base::Time::kMicrosecondsPerSecond *
604 total_samples_generated_ / samples_per_second_; 704 total_samples_generated_ / samples_per_second_;
605 } 705 }
606 706
607 int ClearKeyCdm::GenerateFakeAudioFramesFromDuration( 707 int ClearKeyCdm::GenerateFakeAudioFramesFromDuration(
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 void ClearKeyCdm::StartFileIOTest() { 759 void ClearKeyCdm::StartFileIOTest() {
660 file_io_test_runner_.reset(new FileIOTestRunner( 760 file_io_test_runner_.reset(new FileIOTestRunner(
661 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_)))); 761 base::Bind(&ClearKeyCdmHost::CreateFileIO, base::Unretained(host_))));
662 file_io_test_runner_->RunAllTests( 762 file_io_test_runner_->RunAllTests(
663 base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this))); 763 base::Bind(&ClearKeyCdm::OnFileIOTestComplete, base::Unretained(this)));
664 } 764 }
665 765
666 void ClearKeyCdm::OnFileIOTestComplete(bool success) { 766 void ClearKeyCdm::OnFileIOTestComplete(bool success) {
667 DVLOG(1) << __FUNCTION__ << ": " << success; 767 DVLOG(1) << __FUNCTION__ << ": " << success;
668 std::string message = GetFileIOTestResultMessage(success); 768 std::string message = GetFileIOTestResultMessage(success);
669 host_->OnSessionMessage( 769 host_->OnSessionMessage(last_session_id_.data(),
670 last_session_id_, message.data(), message.size(), NULL, 0); 770 last_session_id_.length(),
771 message.data(),
772 message.length(),
773 NULL,
774 0);
671 file_io_test_runner_.reset(); 775 file_io_test_runner_.reset();
672 } 776 }
673 777
674 } // namespace media 778 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698