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

Side by Side Diff: Source/modules/encryptedmedia/MediaKeySession.cpp

Issue 568033003: Implement MediaKeySession close() and remove() (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: ScriptPromise Created 6 years, 3 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 /* 1 /*
2 * Copyright (C) 2013 Apple Inc. All rights reserved. 2 * Copyright (C) 2013 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
43 #include "platform/MIMETypeRegistry.h" 43 #include "platform/MIMETypeRegistry.h"
44 #include "platform/Timer.h" 44 #include "platform/Timer.h"
45 #include "public/platform/WebContentDecryptionModule.h" 45 #include "public/platform/WebContentDecryptionModule.h"
46 #include "public/platform/WebContentDecryptionModuleException.h" 46 #include "public/platform/WebContentDecryptionModuleException.h"
47 #include "public/platform/WebContentDecryptionModuleSession.h" 47 #include "public/platform/WebContentDecryptionModuleSession.h"
48 #include "public/platform/WebString.h" 48 #include "public/platform/WebString.h"
49 #include "public/platform/WebURL.h" 49 #include "public/platform/WebURL.h"
50 #include "wtf/ArrayBuffer.h" 50 #include "wtf/ArrayBuffer.h"
51 #include "wtf/ArrayBufferView.h" 51 #include "wtf/ArrayBufferView.h"
52 52
53 namespace {
54
55 // The list of possible values for |sessionType| passed to createSession().
56 #if ENABLE(ASSERT)
57 const char* kTemporary = "temporary";
58 #endif
59 const char* kPersistent = "persistent";
60
61 } // namespace
62
53 namespace blink { 63 namespace blink {
54 64
55 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType) 65 static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType)
56 { 66 {
57 ASSERT(!keySystem.isEmpty()); 67 ASSERT(!keySystem.isEmpty());
58 68
59 // FIXME: initDataType != contentType. Implement this properly. 69 // FIXME: initDataType != contentType. Implement this properly.
60 // http://crbug.com/385874. 70 // http://crbug.com/385874.
61 String contentType = initDataType; 71 String contentType = initDataType;
62 if (initDataType == "webm") { 72 if (initDataType == "webm") {
63 contentType = "video/webm"; 73 contentType = "video/webm";
64 } else if (initDataType == "cenc") { 74 } else if (initDataType == "cenc") {
65 contentType = "video/mp4"; 75 contentType = "video/mp4";
66 } 76 }
67 77
68 ContentType type(contentType); 78 ContentType type(contentType);
69 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), type.parameter("codecs")); 79 return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.t ype(), type.parameter("codecs"));
70 } 80 }
71 81
72 // A class holding a pending action. 82 // A class holding a pending action.
73 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> { 83 class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKey Session::PendingAction> {
74 public: 84 public:
75 enum Type { 85 enum Type {
76 GenerateRequest, 86 GenerateRequest,
77 Update, 87 Update,
78 Release 88 Close,
89 Remove
79 }; 90 };
80 91
81 Type type() const { return m_type; } 92 Type type() const { return m_type; }
82 93
83 const Persistent<ContentDecryptionModuleResult> result() const 94 const Persistent<ContentDecryptionModuleResult> result() const
84 { 95 {
85 return m_result; 96 return m_result;
86 } 97 }
87 98
88 const RefPtr<ArrayBuffer> data() const 99 const RefPtr<ArrayBuffer> data() const
(...skipping 15 matching lines...) Expand all
104 return new PendingAction(GenerateRequest, result, initDataType, initData ); 115 return new PendingAction(GenerateRequest, result, initDataType, initData );
105 } 116 }
106 117
107 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data) 118 static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* res ult, PassRefPtr<ArrayBuffer> data)
108 { 119 {
109 ASSERT(result); 120 ASSERT(result);
110 ASSERT(data); 121 ASSERT(data);
111 return new PendingAction(Update, result, String(), data); 122 return new PendingAction(Update, result, String(), data);
112 } 123 }
113 124
114 static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* re sult) 125 static PendingAction* CreatePendingClose(ContentDecryptionModuleResult* resu lt)
115 { 126 {
116 ASSERT(result); 127 ASSERT(result);
117 return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuff er>()); 128 return new PendingAction(Close, result, String(), PassRefPtr<ArrayBuffer >());
129 }
130
131 static PendingAction* CreatePendingRemove(ContentDecryptionModuleResult* res ult)
132 {
133 ASSERT(result);
134 return new PendingAction(Remove, result, String(), PassRefPtr<ArrayBuffe r>());
118 } 135 }
119 136
120 ~PendingAction() 137 ~PendingAction()
121 { 138 {
122 } 139 }
123 140
124 void trace(Visitor* visitor) 141 void trace(Visitor* visitor)
125 { 142 {
126 visitor->trace(m_result); 143 visitor->trace(m_result);
127 } 144 }
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 m_resolver->reject(DOMException::create(code, errorMessage)); 217 m_resolver->reject(DOMException::create(code, errorMessage));
201 m_resolver.clear(); 218 m_resolver.clear();
202 } 219 }
203 220
204 RefPtr<ScriptPromiseResolver> m_resolver; 221 RefPtr<ScriptPromiseResolver> m_resolver;
205 Member<MediaKeySession> m_session; 222 Member<MediaKeySession> m_session;
206 }; 223 };
207 224
208 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me diaKeys, const String& sessionType) 225 MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* me diaKeys, const String& sessionType)
209 { 226 {
227 ASSERT(sessionType == kTemporary || sessionType == kPersistent);
210 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollecte dWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType)); 228 RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollecte dWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType));
211 session->suspendIfNeeded(); 229 session->suspendIfNeeded();
212 return session.get(); 230 return session.get();
213 } 231 }
214 232
215 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType) 233 MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType)
216 : ActiveDOMObject(scriptState->executionContext()) 234 : ActiveDOMObject(scriptState->executionContext())
217 , m_keySystem(mediaKeys->keySystem()) 235 , m_keySystem(mediaKeys->keySystem())
218 , m_asyncEventQueue(GenericEventQueue::create(this)) 236 , m_asyncEventQueue(GenericEventQueue::create(this))
219 , m_mediaKeys(mediaKeys) 237 , m_mediaKeys(mediaKeys)
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 // 4. Run the following steps asynchronously (documented in 413 // 4. Run the following steps asynchronously (documented in
396 // actionTimerFired()) 414 // actionTimerFired())
397 m_pendingActions.append(PendingAction::CreatePendingUpdate(result, response) ); 415 m_pendingActions.append(PendingAction::CreatePendingUpdate(result, response) );
398 if (!m_actionTimer.isActive()) 416 if (!m_actionTimer.isActive())
399 m_actionTimer.startOneShot(0, FROM_HERE); 417 m_actionTimer.startOneShot(0, FROM_HERE);
400 418
401 // 5. Return promise. 419 // 5. Return promise.
402 return promise; 420 return promise;
403 } 421 }
404 422
405 ScriptPromise MediaKeySession::release(ScriptState* scriptState) 423 ScriptPromise MediaKeySession::close(ScriptState* scriptState)
406 { 424 {
407 WTF_LOG(Media, "MediaKeySession(%p)::release", this); 425 WTF_LOG(Media, "MediaKeySession(%p)::close", this);
408 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod uleResult(scriptState);
409 ScriptPromise promise = result->promise();
410 426
411 // From <https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/ encrypted-media.html#dom-close>: 427 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#dom-close:
412 // The close() method allows an application to indicate that it no longer 428 // The close() method allows an application to indicate that it no longer
413 // needs the session and the CDM should release any resources associated 429 // needs the session and the CDM should release any resources associated
414 // with this object and close it. The returned promise is resolved when the 430 // with this object and close it. The returned promise is resolved when the
415 // request has been processed, and the closed attribute promise is resolved 431 // request has been processed, and the closed attribute promise is resolved
416 // when the session is closed. It must run the following steps: 432 // when the session is closed. It must run the following steps:
417 // 433 //
418 // 1. If the Session Close algorithm has been run on this object, return a 434 // 1. If this object's callable value is false, return a promise rejected
419 // promise fulfilled with undefined. 435 // with a new DOMException whose name is "InvalidStateError".
420 if (m_isClosed) { 436 if (!m_isCallable) {
421 result->complete(); 437 return ScriptPromise::rejectWithDOMException(
422 return promise; 438 scriptState, DOMException::create(InvalidStateError, "The session is not callable."));
423 } 439 }
424 440
425 // 2. Let promise be a new promise. 441 // 2. If the Session Close algorithm has been run on this object,
426 // (Created earlier so it was available in step 1.) 442 // return a resolved promise.
443 if (m_isClosed)
444 return ScriptPromise::cast(scriptState, ScriptValue());
ddorwin 2014/09/18 00:33:02 Hmm. I wonder why there isn't also a resolve() wra
427 445
428 // 3. Run the following steps asynchronously (documented in 446 // 3. Let promise be a new promise.
447 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod uleResult(scriptState);
448 ScriptPromise promise = result->promise();
449
450 // 4. Run the following steps asynchronously (documented in
429 // actionTimerFired()). 451 // actionTimerFired()).
430 m_pendingActions.append(PendingAction::CreatePendingRelease(result)); 452 m_pendingActions.append(PendingAction::CreatePendingClose(result));
431 if (!m_actionTimer.isActive()) 453 if (!m_actionTimer.isActive())
432 m_actionTimer.startOneShot(0, FROM_HERE); 454 m_actionTimer.startOneShot(0, FROM_HERE);
433 455
434 // 4. Return promise. 456 // 5. Return promise.
435 return promise; 457 return promise;
436 } 458 }
437 459
460 ScriptPromise MediaKeySession::remove(ScriptState* scriptState)
461 {
462 WTF_LOG(Media, "MediaKeySession(%p)::remove", this);
463
464 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#dom-remove:
465 // The remove() method allows an application to remove stored session data
466 // associated with this object. It must run the following steps:
467
468 // 1. If this object's callable value is false, return a promise rejected
469 // with a new DOMException whose name is "InvalidStateError".
470 if (!m_isCallable) {
471 return ScriptPromise::rejectWithDOMException(
472 scriptState, DOMException::create(InvalidStateError, "The session is not callable."));
473 }
474
475 // 2. If this object's session type is not "persistent", return a promise
476 // rejected with a new DOMException whose name is "InvalidAccessError".
477 if (m_sessionType != kPersistent) {
478 return ScriptPromise::rejectWithDOMException(
479 scriptState, DOMException::create(InvalidAccessError, "The session t ype is not 'persistent'."));
480 }
481
482 // 3. If the Session Close algorithm has been run on this object, return a
483 // promise rejected with a new DOMException whose name is
484 // "InvalidStateError".
485 if (m_isClosed) {
486 return ScriptPromise::rejectWithDOMException(
487 scriptState, DOMException::create(InvalidStateError, "The session is already closed."));
488 }
489
490 // 4. Let promise be a new promise.
491 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod uleResult(scriptState);
492 ScriptPromise promise = result->promise();
493
494 // 5. Run the following steps asynchronously (documented in
495 // actionTimerFired()).
496 m_pendingActions.append(PendingAction::CreatePendingRemove(result));
497 if (!m_actionTimer.isActive())
498 m_actionTimer.startOneShot(0, FROM_HERE);
499
500 // 6. Return promise.
501 return promise;
502 }
503
438 void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*) 504 void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*)
439 { 505 {
440 ASSERT(m_pendingActions.size()); 506 ASSERT(m_pendingActions.size());
441 507
442 // Resolving promises now run synchronously and may result in additional 508 // Resolving promises now run synchronously and may result in additional
443 // actions getting added to the queue. As a result, swap the queue to 509 // actions getting added to the queue. As a result, swap the queue to
444 // a local copy to avoid problems if this happens. 510 // a local copy to avoid problems if this happens.
445 HeapDeque<Member<PendingAction> > pendingActions; 511 HeapDeque<Member<PendingAction> > pendingActions;
446 pendingActions.swap(m_pendingActions); 512 pendingActions.swap(m_pendingActions);
447 513
(...skipping 24 matching lines...) Expand all
472 break; 538 break;
473 539
474 case PendingAction::Update: 540 case PendingAction::Update:
475 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); 541 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this );
476 // NOTE: Continued from step 4 of MediaKeySession::update(). 542 // NOTE: Continued from step 4 of MediaKeySession::update().
477 // Continue the update call by passing message to the cdm. Once 543 // Continue the update call by passing message to the cdm. Once
478 // completed, it will resolve/reject the promise. 544 // completed, it will resolve/reject the promise.
479 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); 545 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result());
480 break; 546 break;
481 547
482 case PendingAction::Release: 548 case PendingAction::Close:
483 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s); 549 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Close", this) ;
484 // NOTE: Continued from step 3 of MediaKeySession::release(). 550 // NOTE: Continued from step 4 of MediaKeySession::close().
485 // 3.1 Let cdm be the cdm loaded in create(). 551 // 4.1 Let cdm be the CDM loaded during the initialization of the
486 // 3.2 Use the cdm to execute the following steps: 552 // MediaKeys object that created this object.
487 // 3.2.1 Process the close request. Do not remove stored session dat a. 553 // (Already captured when creating m_session).
488 // 3.2.2 If the previous step caused the session to be closed, run t he 554 // 4.2 Use the cdm to execute the following steps:
489 // Session Close algorithm on this object. 555 // 4.2.1 Process the close request. Do not remove stored session
490 // 3.3 Resolve promise with undefined. 556 // data.
491 m_session->release(action->result()->result()); 557 // 4.2.3 If the previous step caused the session to be closed,
558 // run the Session Close algorithm on this object.
559 // 4.3 Resolve promise.
560 m_session->close(action->result()->result());
561 break;
562
563 case PendingAction::Remove:
564 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Remove", this );
565 // NOTE: Continued from step 5 of MediaKeySession::remove().
566 // 5.1 Let cdm be the CDM loaded during the initialization of the
567 // MediaKeys object that created this object.
568 // (Already captured when creating m_session).
569 // 5.2 Use the cdm to execute the following steps:
570 // 5.2.1 Process the remove request. This may involve exchanging
571 // message(s) with the application. Unless this step fails,
572 // the CDM must have cleared all stored session data
573 // associated with this object, including the sessionId,
574 // before proceeding to the next step. (A subsequent call
575 // to load() with sessionId would fail because there is no
576 // data stored for the sessionId.)
577 // 5.3 Run the following steps asynchronously once the above step
578 // has completed:
579 // 5.3.1 If any of the preceding steps failed, reject promise
580 // with a new DOMException whose name is the appropriate
581 // error name.
582 // 5.3.2 Run the Session Close algorithm on this object.
583 // 5.3.3 Resolve promise.
584 m_session->remove(action->result()->result());
492 break; 585 break;
493 } 586 }
494 } 587 }
495 } 588 }
496 589
497 void MediaKeySession::finishGenerateRequest() 590 void MediaKeySession::finishGenerateRequest()
498 { 591 {
499 // 10.4 Set the sessionId attribute to a unique Session ID string. 592 // 10.4 Set the sessionId attribute to a unique Session ID string.
500 // It may be obtained from cdm. 593 // It may be obtained from cdm.
501 ASSERT(!sessionId().isEmpty()); 594 ASSERT(!sessionId().isEmpty());
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
647 { 740 {
648 visitor->trace(m_error); 741 visitor->trace(m_error);
649 visitor->trace(m_asyncEventQueue); 742 visitor->trace(m_asyncEventQueue);
650 visitor->trace(m_pendingActions); 743 visitor->trace(m_pendingActions);
651 visitor->trace(m_mediaKeys); 744 visitor->trace(m_mediaKeys);
652 visitor->trace(m_closedPromise); 745 visitor->trace(m_closedPromise);
653 EventTargetWithInlineData::trace(visitor); 746 EventTargetWithInlineData::trace(visitor);
654 } 747 }
655 748
656 } // namespace blink 749 } // namespace blink
OLDNEW
« no previous file with comments | « Source/modules/encryptedmedia/MediaKeySession.h ('k') | Source/modules/encryptedmedia/MediaKeySession.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698