OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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); | |
ddorwin
2014/09/17 23:26:41
Future improvement: We should change m_sessionType
jrummell
2014/09/18 00:15:03
Acknowledged.
| |
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 Loading... | |
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". |
436 if (!m_isCallable) { | |
437 return ScriptPromise::rejectWithDOMException( | |
438 scriptState, DOMException::create(InvalidStateError, "The session is not callable.")); | |
439 } | |
440 | |
441 // 2. If the Session Close algorithm has been run on this object, | |
442 // return a resolved promise. | |
443 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod uleResult(scriptState); | |
ddorwin
2014/09/17 23:26:41
Is there a generic way to return a resolved promis
jrummell
2014/09/18 00:15:03
There is ScriptPromise::cast(), so changed to use
| |
444 ScriptPromise promise = result->promise(); | |
420 if (m_isClosed) { | 445 if (m_isClosed) { |
421 result->complete(); | 446 result->complete(); |
422 return promise; | 447 return promise; |
423 } | 448 } |
424 | 449 |
425 // 2. Let promise be a new promise. | 450 // 3. Let promise be a new promise. |
426 // (Created earlier so it was available in step 1.) | 451 // (Created earlier so it was available in step 3.) |
427 | 452 |
428 // 3. Run the following steps asynchronously (documented in | 453 // 4. Run the following steps asynchronously (documented in |
429 // actionTimerFired()). | 454 // actionTimerFired()). |
430 m_pendingActions.append(PendingAction::CreatePendingRelease(result)); | 455 m_pendingActions.append(PendingAction::CreatePendingClose(result)); |
431 if (!m_actionTimer.isActive()) | 456 if (!m_actionTimer.isActive()) |
432 m_actionTimer.startOneShot(0, FROM_HERE); | 457 m_actionTimer.startOneShot(0, FROM_HERE); |
433 | 458 |
434 // 4. Return promise. | 459 // 5. Return promise. |
435 return promise; | 460 return promise; |
436 } | 461 } |
437 | 462 |
463 ScriptPromise MediaKeySession::remove(ScriptState* scriptState) | |
464 { | |
465 WTF_LOG(Media, "MediaKeySession(%p)::remove", this); | |
466 | |
467 // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/e ncrypted-media.html#dom-remove: | |
468 // The remove() method allows an application to remove stored session data | |
469 // associated with this object. It must run the following steps: | |
470 | |
471 // 1. If this object's callable value is false, return a promise rejected | |
472 // with a new DOMException whose name is "InvalidStateError". | |
473 if (!m_isCallable) { | |
474 return ScriptPromise::rejectWithDOMException( | |
475 scriptState, DOMException::create(InvalidStateError, "The session is not callable.")); | |
476 } | |
477 | |
478 // 2. If this object's session type is not "persistent", return a promise | |
479 // rejected with a new DOMException whose name is "InvalidAccessError". | |
480 if (m_sessionType != kPersistent) { | |
481 return ScriptPromise::rejectWithDOMException( | |
482 scriptState, DOMException::create(InvalidAccessError, "The session t ype is not 'persistent'.")); | |
483 } | |
484 | |
485 // 3. If the Session Close algorithm has been run on this object, return a | |
486 // promise rejected with a new DOMException whose name is | |
487 // "InvalidStateError". | |
488 if (m_isClosed) { | |
489 return ScriptPromise::rejectWithDOMException( | |
490 scriptState, DOMException::create(InvalidStateError, "The session is already closed.")); | |
491 } | |
492 | |
493 // 4. Let promise be a new promise. | |
494 SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionMod uleResult(scriptState); | |
495 ScriptPromise promise = result->promise(); | |
496 | |
497 // 5. Run the following steps asynchronously (documented in | |
498 // actionTimerFired()). | |
499 m_pendingActions.append(PendingAction::CreatePendingRemove(result)); | |
500 if (!m_actionTimer.isActive()) | |
501 m_actionTimer.startOneShot(0, FROM_HERE); | |
502 | |
503 // 6. Return promise. | |
504 return promise; | |
505 } | |
506 | |
438 void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*) | 507 void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*) |
439 { | 508 { |
440 ASSERT(m_pendingActions.size()); | 509 ASSERT(m_pendingActions.size()); |
441 | 510 |
442 // Resolving promises now run synchronously and may result in additional | 511 // Resolving promises now run synchronously and may result in additional |
443 // actions getting added to the queue. As a result, swap the queue to | 512 // actions getting added to the queue. As a result, swap the queue to |
444 // a local copy to avoid problems if this happens. | 513 // a local copy to avoid problems if this happens. |
445 HeapDeque<Member<PendingAction> > pendingActions; | 514 HeapDeque<Member<PendingAction> > pendingActions; |
446 pendingActions.swap(m_pendingActions); | 515 pendingActions.swap(m_pendingActions); |
447 | 516 |
(...skipping 24 matching lines...) Expand all Loading... | |
472 break; | 541 break; |
473 | 542 |
474 case PendingAction::Update: | 543 case PendingAction::Update: |
475 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); | 544 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this ); |
476 // NOTE: Continued from step 4 of MediaKeySession::update(). | 545 // NOTE: Continued from step 4 of MediaKeySession::update(). |
477 // Continue the update call by passing message to the cdm. Once | 546 // Continue the update call by passing message to the cdm. Once |
478 // completed, it will resolve/reject the promise. | 547 // completed, it will resolve/reject the promise. |
479 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); | 548 m_session->update(static_cast<unsigned char*>(action->data()->data() ), action->data()->byteLength(), action->result()->result()); |
480 break; | 549 break; |
481 | 550 |
482 case PendingAction::Release: | 551 case PendingAction::Close: |
483 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", thi s); | 552 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Close", this) ; |
484 // NOTE: Continued from step 3 of MediaKeySession::release(). | 553 // NOTE: Continued from step 4 of MediaKeySession::close(). |
485 // 3.1 Let cdm be the cdm loaded in create(). | 554 // 4.1 Let cdm be the CDM loaded during the initialization of the |
486 // 3.2 Use the cdm to execute the following steps: | 555 // MediaKeys object that created this object. |
487 // 3.2.1 Process the close request. Do not remove stored session dat a. | 556 // (Already captured when creating m_session). |
488 // 3.2.2 If the previous step caused the session to be closed, run t he | 557 // 4.2 Use the cdm to execute the following steps: |
489 // Session Close algorithm on this object. | 558 // 4.2.1 Process the close request. Do not remove stored session |
490 // 3.3 Resolve promise with undefined. | 559 // data. |
491 m_session->release(action->result()->result()); | 560 // 4.2.3 If the previous step caused the session to be closed, |
561 // run the Session Close algorithm on this object. | |
562 // 4.3 Resolve promise. | |
563 m_session->close(action->result()->result()); | |
564 break; | |
565 | |
566 case PendingAction::Remove: | |
567 WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Remove", this ); | |
568 // NOTE: Continued from step 5 of MediaKeySession::remove(). | |
569 // 5.1 Let cdm be the CDM loaded during the initialization of the | |
570 // MediaKeys object that created this object. | |
571 // (Already captured when creating m_session). | |
572 // 5.2 Use the cdm to execute the following steps: | |
573 // 5.2.1 Process the remove request. This may involve exchanging | |
574 // message(s) with the application. Unless this step fails, | |
575 // the CDM must have cleared all stored session data | |
576 // associated with this object, including the sessionId, | |
577 // before proceeding to the next step. (A subsequent call | |
578 // to load() with sessionId would fail because there is no | |
579 // data stored for the sessionId.) | |
580 // 5.3 Run the following steps asynchronously once the above step | |
581 // has completed: | |
582 // 5.3.1 If any of the preceding steps failed, reject promise | |
583 // with a new DOMException whose name is the appropriate | |
584 // error name. | |
585 // 5.3.2 Run the Session Close algorithm on this object. | |
586 // 5.3.3 Resolve promise. | |
587 m_session->remove(action->result()->result()); | |
492 break; | 588 break; |
493 } | 589 } |
494 } | 590 } |
495 } | 591 } |
496 | 592 |
497 void MediaKeySession::finishGenerateRequest() | 593 void MediaKeySession::finishGenerateRequest() |
498 { | 594 { |
499 // 10.4 Set the sessionId attribute to a unique Session ID string. | 595 // 10.4 Set the sessionId attribute to a unique Session ID string. |
500 // It may be obtained from cdm. | 596 // It may be obtained from cdm. |
501 ASSERT(!sessionId().isEmpty()); | 597 ASSERT(!sessionId().isEmpty()); |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
647 { | 743 { |
648 visitor->trace(m_error); | 744 visitor->trace(m_error); |
649 visitor->trace(m_asyncEventQueue); | 745 visitor->trace(m_asyncEventQueue); |
650 visitor->trace(m_pendingActions); | 746 visitor->trace(m_pendingActions); |
651 visitor->trace(m_mediaKeys); | 747 visitor->trace(m_mediaKeys); |
652 visitor->trace(m_closedPromise); | 748 visitor->trace(m_closedPromise); |
653 EventTargetWithInlineData::trace(visitor); | 749 EventTargetWithInlineData::trace(visitor); |
654 } | 750 } |
655 | 751 |
656 } // namespace blink | 752 } // namespace blink |
OLD | NEW |