Chromium Code Reviews| 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 |