| Index: Source/modules/encryptedmedia/MediaKeySession.cpp
|
| diff --git a/Source/modules/encryptedmedia/MediaKeySession.cpp b/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| index 42cd37150c9b8856b6950f2b09a7ff68e2ccb3ad..9a4794dc39dfcde0720df3b46aa0b40cccc2020e 100644
|
| --- a/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| +++ b/Source/modules/encryptedmedia/MediaKeySession.cpp
|
| @@ -50,6 +50,16 @@
|
| #include "wtf/ArrayBuffer.h"
|
| #include "wtf/ArrayBufferView.h"
|
|
|
| +namespace {
|
| +
|
| +// The list of possible values for |sessionType| passed to createSession().
|
| +#if ENABLE(ASSERT)
|
| +const char* kTemporary = "temporary";
|
| +#endif
|
| +const char* kPersistent = "persistent";
|
| +
|
| +} // namespace
|
| +
|
| namespace blink {
|
|
|
| static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType)
|
| @@ -75,7 +85,8 @@ public:
|
| enum Type {
|
| GenerateRequest,
|
| Update,
|
| - Release
|
| + Close,
|
| + Remove
|
| };
|
|
|
| Type type() const { return m_type; }
|
| @@ -111,10 +122,16 @@ public:
|
| return new PendingAction(Update, result, String(), data);
|
| }
|
|
|
| - static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* result)
|
| + static PendingAction* CreatePendingClose(ContentDecryptionModuleResult* result)
|
| {
|
| ASSERT(result);
|
| - return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuffer>());
|
| + return new PendingAction(Close, result, String(), PassRefPtr<ArrayBuffer>());
|
| + }
|
| +
|
| + static PendingAction* CreatePendingRemove(ContentDecryptionModuleResult* result)
|
| + {
|
| + ASSERT(result);
|
| + return new PendingAction(Remove, result, String(), PassRefPtr<ArrayBuffer>());
|
| }
|
|
|
| ~PendingAction()
|
| @@ -207,6 +224,7 @@ private:
|
|
|
| MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType)
|
| {
|
| + ASSERT(sessionType == kTemporary || sessionType == kPersistent);
|
| RefPtrWillBeRawPtr<MediaKeySession> session = new MediaKeySession(scriptState, mediaKeys, sessionType);
|
| session->suspendIfNeeded();
|
| return session.get();
|
| @@ -402,36 +420,84 @@ ScriptPromise MediaKeySession::updateInternal(ScriptState* scriptState, PassRefP
|
| return promise;
|
| }
|
|
|
| -ScriptPromise MediaKeySession::release(ScriptState* scriptState)
|
| +ScriptPromise MediaKeySession::close(ScriptState* scriptState)
|
| {
|
| - WTF_LOG(Media, "MediaKeySession(%p)::release", this);
|
| - SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState);
|
| - ScriptPromise promise = result->promise();
|
| + WTF_LOG(Media, "MediaKeySession(%p)::close", this);
|
|
|
| - // From <https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-close>:
|
| + // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-close:
|
| // The close() method allows an application to indicate that it no longer
|
| // needs the session and the CDM should release any resources associated
|
| // with this object and close it. The returned promise is resolved when the
|
| // request has been processed, and the closed attribute promise is resolved
|
| // when the session is closed. It must run the following steps:
|
| //
|
| - // 1. If the Session Close algorithm has been run on this object, return a
|
| - // promise fulfilled with undefined.
|
| + // 1. If this object's callable value is false, return a promise rejected
|
| + // with a new DOMException whose name is "InvalidStateError".
|
| + if (!m_isCallable) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(InvalidStateError, "The session is not callable."));
|
| + }
|
| +
|
| + // 2. If the Session Close algorithm has been run on this object,
|
| + // return a resolved promise.
|
| + if (m_isClosed)
|
| + return ScriptPromise::cast(scriptState, ScriptValue());
|
| +
|
| + // 3. Let promise be a new promise.
|
| + SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState);
|
| + ScriptPromise promise = result->promise();
|
| +
|
| + // 4. Run the following steps asynchronously (documented in
|
| + // actionTimerFired()).
|
| + m_pendingActions.append(PendingAction::CreatePendingClose(result));
|
| + if (!m_actionTimer.isActive())
|
| + m_actionTimer.startOneShot(0, FROM_HERE);
|
| +
|
| + // 5. Return promise.
|
| + return promise;
|
| +}
|
| +
|
| +ScriptPromise MediaKeySession::remove(ScriptState* scriptState)
|
| +{
|
| + WTF_LOG(Media, "MediaKeySession(%p)::remove", this);
|
| +
|
| + // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-remove:
|
| + // The remove() method allows an application to remove stored session data
|
| + // associated with this object. It must run the following steps:
|
| +
|
| + // 1. If this object's callable value is false, return a promise rejected
|
| + // with a new DOMException whose name is "InvalidStateError".
|
| + if (!m_isCallable) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(InvalidStateError, "The session is not callable."));
|
| + }
|
| +
|
| + // 2. If this object's session type is not "persistent", return a promise
|
| + // rejected with a new DOMException whose name is "InvalidAccessError".
|
| + if (m_sessionType != kPersistent) {
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(InvalidAccessError, "The session type is not 'persistent'."));
|
| + }
|
| +
|
| + // 3. If the Session Close algorithm has been run on this object, return a
|
| + // promise rejected with a new DOMException whose name is
|
| + // "InvalidStateError".
|
| if (m_isClosed) {
|
| - result->complete();
|
| - return promise;
|
| + return ScriptPromise::rejectWithDOMException(
|
| + scriptState, DOMException::create(InvalidStateError, "The session is already closed."));
|
| }
|
|
|
| - // 2. Let promise be a new promise.
|
| - // (Created earlier so it was available in step 1.)
|
| + // 4. Let promise be a new promise.
|
| + SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState);
|
| + ScriptPromise promise = result->promise();
|
|
|
| - // 3. Run the following steps asynchronously (documented in
|
| + // 5. Run the following steps asynchronously (documented in
|
| // actionTimerFired()).
|
| - m_pendingActions.append(PendingAction::CreatePendingRelease(result));
|
| + m_pendingActions.append(PendingAction::CreatePendingRemove(result));
|
| if (!m_actionTimer.isActive())
|
| m_actionTimer.startOneShot(0, FROM_HERE);
|
|
|
| - // 4. Return promise.
|
| + // 6. Return promise.
|
| return promise;
|
| }
|
|
|
| @@ -479,16 +545,43 @@ void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*)
|
| m_session->update(static_cast<unsigned char*>(action->data()->data()), action->data()->byteLength(), action->result()->result());
|
| break;
|
|
|
| - case PendingAction::Release:
|
| - WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Release", this);
|
| - // NOTE: Continued from step 3 of MediaKeySession::release().
|
| - // 3.1 Let cdm be the cdm loaded in create().
|
| - // 3.2 Use the cdm to execute the following steps:
|
| - // 3.2.1 Process the close request. Do not remove stored session data.
|
| - // 3.2.2 If the previous step caused the session to be closed, run the
|
| - // Session Close algorithm on this object.
|
| - // 3.3 Resolve promise with undefined.
|
| - m_session->release(action->result()->result());
|
| + case PendingAction::Close:
|
| + WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Close", this);
|
| + // NOTE: Continued from step 4 of MediaKeySession::close().
|
| + // 4.1 Let cdm be the CDM loaded during the initialization of the
|
| + // MediaKeys object that created this object.
|
| + // (Already captured when creating m_session).
|
| + // 4.2 Use the cdm to execute the following steps:
|
| + // 4.2.1 Process the close request. Do not remove stored session
|
| + // data.
|
| + // 4.2.3 If the previous step caused the session to be closed,
|
| + // run the Session Close algorithm on this object.
|
| + // 4.3 Resolve promise.
|
| + m_session->close(action->result()->result());
|
| + break;
|
| +
|
| + case PendingAction::Remove:
|
| + WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Remove", this);
|
| + // NOTE: Continued from step 5 of MediaKeySession::remove().
|
| + // 5.1 Let cdm be the CDM loaded during the initialization of the
|
| + // MediaKeys object that created this object.
|
| + // (Already captured when creating m_session).
|
| + // 5.2 Use the cdm to execute the following steps:
|
| + // 5.2.1 Process the remove request. This may involve exchanging
|
| + // message(s) with the application. Unless this step fails,
|
| + // the CDM must have cleared all stored session data
|
| + // associated with this object, including the sessionId,
|
| + // before proceeding to the next step. (A subsequent call
|
| + // to load() with sessionId would fail because there is no
|
| + // data stored for the sessionId.)
|
| + // 5.3 Run the following steps asynchronously once the above step
|
| + // has completed:
|
| + // 5.3.1 If any of the preceding steps failed, reject promise
|
| + // with a new DOMException whose name is the appropriate
|
| + // error name.
|
| + // 5.3.2 Run the Session Close algorithm on this object.
|
| + // 5.3.3 Resolve promise.
|
| + m_session->remove(action->result()->result());
|
| break;
|
| }
|
| }
|
|
|