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

Unified Diff: Source/modules/encryptedmedia/MediaKeySession.cpp

Issue 543173002: Implement MediaKeySession.generateRequest() (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: 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 side-by-side diff with in-line comments
Download patch
Index: Source/modules/encryptedmedia/MediaKeySession.cpp
diff --git a/Source/modules/encryptedmedia/MediaKeySession.cpp b/Source/modules/encryptedmedia/MediaKeySession.cpp
index 7c2f1ae23f82e74fa9a98c62ef4ac74724f23920..4c6cc2cf58c101db1a22fc1759825dd4e5e0e791 100644
--- a/Source/modules/encryptedmedia/MediaKeySession.cpp
+++ b/Source/modules/encryptedmedia/MediaKeySession.cpp
@@ -38,7 +38,9 @@
#include "modules/encryptedmedia/MediaKeys.h"
#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h"
#include "platform/ContentDecryptionModuleResult.h"
+#include "platform/ContentType.h"
#include "platform/Logging.h"
+#include "platform/MIMETypeRegistry.h"
#include "platform/Timer.h"
#include "public/platform/WebContentDecryptionModule.h"
#include "public/platform/WebContentDecryptionModuleException.h"
@@ -47,55 +49,74 @@
#include "public/platform/WebURL.h"
#include "wtf/ArrayBuffer.h"
#include "wtf/ArrayBufferView.h"
+#include <cmath>
namespace blink {
+static bool isKeySystemSupportedWithInitDataType(const String& keySystem, const String& initDataType)
+{
+ ASSERT(!keySystem.isEmpty());
+
+ // FIXME: initDataType != contentType. Implement this properly.
+ // http://crbug.com/385874.
+ String contentType = initDataType;
+ if (initDataType == "webm") {
+ contentType = "video/webm";
+ } else if (initDataType == "cenc") {
+ contentType = "video/mp4";
+ }
+
+ ContentType type(contentType);
+ String codecs = type.parameter("codecs");
ddorwin 2014/09/09 00:44:35 nit: Do we need the local variable?
jrummell 2014/09/09 19:55:59 Done.
+ return MIMETypeRegistry::isSupportedEncryptedMediaMIMEType(keySystem, type.type(), codecs);
+}
+
// A class holding a pending action.
class MediaKeySession::PendingAction : public GarbageCollectedFinalized<MediaKeySession::PendingAction> {
public:
enum Type {
+ GenerateRequest,
Update,
- Release,
- Message
+ Release
};
Type type() const { return m_type; }
const Persistent<ContentDecryptionModuleResult> result() const
{
- ASSERT(m_type == Update || m_type == Release);
return m_result;
}
const RefPtr<ArrayBuffer> data() const
{
- ASSERT(m_type == Update);
+ ASSERT(m_type == GenerateRequest || m_type == Update);
return m_data;
}
- RefPtrWillBeRawPtr<Event> event()
+ const String& initDataType() const
{
- ASSERT(m_type == Message);
- return m_event;
+ ASSERT(m_type == GenerateRequest);
+ return m_initDataType;
}
- static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> data)
+ static PendingAction* CreatePendingGenerateRequest(ContentDecryptionModuleResult* result, const String& initDataType, PassRefPtr<ArrayBuffer> initData)
{
ASSERT(result);
- ASSERT(data);
- return new PendingAction(Update, result, data);
+ ASSERT(initData);
+ return new PendingAction(GenerateRequest, result, initDataType, initData);
}
- static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* result)
+ static PendingAction* CreatePendingUpdate(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> data)
{
ASSERT(result);
- return new PendingAction(Release, result, PassRefPtr<ArrayBuffer>());
+ ASSERT(data);
+ return new PendingAction(Update, result, String(), data);
}
- static PendingAction* CreatePendingMessage(PassRefPtrWillBeRawPtr<Event> event)
+ static PendingAction* CreatePendingRelease(ContentDecryptionModuleResult* result)
{
- ASSERT(event);
- return new PendingAction(Message, event);
+ ASSERT(result);
+ return new PendingAction(Release, result, String(), PassRefPtr<ArrayBuffer>());
}
~PendingAction()
@@ -105,235 +126,128 @@ public:
void trace(Visitor* visitor)
{
visitor->trace(m_result);
- visitor->trace(m_event);
}
private:
- PendingAction(Type type, ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> data)
+ PendingAction(Type type, ContentDecryptionModuleResult* result, const String& initDataType, PassRefPtr<ArrayBuffer> data)
: m_type(type)
, m_result(result)
+ , m_initDataType(initDataType)
, m_data(data)
{
}
- PendingAction(Type type, PassRefPtrWillBeRawPtr<Event> event)
- : m_type(type)
- , m_event(event)
- {
- }
-
const Type m_type;
const Member<ContentDecryptionModuleResult> m_result;
+ const String m_initDataType;
const RefPtr<ArrayBuffer> m_data;
- const RefPtrWillBeMember<Event> m_event;
};
-// This class allows a MediaKeySession object to be created asynchronously.
-class MediaKeySessionInitializer : public ScriptPromiseResolver {
- WTF_MAKE_NONCOPYABLE(MediaKeySessionInitializer);
-
+// This class wraps the promise resolver used when initializing a new session
+// and is passed to Chromium to fullfill the promise. This implementation of
+// completeWithSession() will resolve the promise with undefined, while
ddorwin 2014/09/09 00:44:35 "undefined" is not specified by the spec. Please a
jrummell 2014/09/09 19:55:59 I asked yhirano@ a while back, and he responded "c
+// completeWithError() will reject the promise with an exception. complete()
+// is not expected to be called, and will reject the promise.
+class NewSessionResult : public ContentDecryptionModuleResult {
public:
- static ScriptPromise create(ScriptState*, MediaKeys*, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String& sessionType);
- virtual ~MediaKeySessionInitializer();
-
- void completeWithSession(WebContentDecryptionModuleResult::SessionStatus);
- void completeWithDOMException(ExceptionCode, const String& errorMessage);
-
-private:
- MediaKeySessionInitializer(ScriptState*, MediaKeys*, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String& sessionType);
- void timerFired(Timer<MediaKeySessionInitializer>*);
-
- Persistent<MediaKeys> m_mediaKeys;
- OwnPtr<WebContentDecryptionModuleSession> m_cdmSession;
-
- // The next 3 values are simply the initialization data saved so that the
- // asynchronous creation has the data needed.
- String m_initDataType;
- RefPtr<ArrayBuffer> m_initData;
- String m_sessionType;
-
- Timer<MediaKeySessionInitializer> m_timer;
-};
+ NewSessionResult(ScriptState* scriptState, MediaKeySession* session)
+ : m_resolver(ScriptPromiseResolver::create(scriptState))
+ , m_session(session)
+ {
+ WTF_LOG(Media, "NewSessionResult(%p)", this);
+ }
-// Represents the result used when a new WebContentDecryptionModuleSession
-// object has been created. Needed as MediaKeySessionInitializer can't be both
-// a ScriptPromiseResolver and ContentDecryptionModuleResult at the same time.
-class NewMediaKeySessionResult FINAL : public ContentDecryptionModuleResult {
-public:
- NewMediaKeySessionResult(MediaKeySessionInitializer* initializer)
- : m_initializer(initializer)
+ ~NewSessionResult()
ddorwin 2014/09/09 00:44:36 If any superclass's destructor is virtual, make th
jrummell 2014/09/09 19:55:59 Done.
{
+ WTF_LOG(Media, "~NewSessionResult(%p)", this);
}
// ContentDecryptionModuleResult implementation.
virtual void complete() OVERRIDE
{
ASSERT_NOT_REACHED();
- m_initializer->completeWithDOMException(InvalidStateError, "Unexpected completion.");
+ completeWithDOMException(InvalidStateError, "Unexpected completion.");
}
virtual void completeWithSession(WebContentDecryptionModuleResult::SessionStatus status) OVERRIDE
{
- m_initializer->completeWithSession(status);
+ if (status != WebContentDecryptionModuleResult::NewSession) {
+ ASSERT_NOT_REACHED();
+ completeWithDOMException(InvalidStateError, "Unexpected completion.");
+ }
+
+ m_session->finishGenerateRequest();
+ m_resolver->resolve(V8UndefinedType());
ddorwin 2014/09/09 00:44:35 See the comment on 148.
jrummell 2014/09/09 19:55:59 Added comment.
+ m_resolver.clear();
}
- virtual void completeWithError(WebContentDecryptionModuleException code, unsigned long systemCode, const WebString& message) OVERRIDE
+ virtual void completeWithError(WebContentDecryptionModuleException exceptionCode, unsigned long systemCode, const WebString& errorMessage) OVERRIDE
{
- m_initializer->completeWithDOMException(WebCdmExceptionToExceptionCode(code), message);
+ completeWithDOMException(WebCdmExceptionToExceptionCode(exceptionCode), errorMessage);
}
-private:
- MediaKeySessionInitializer* m_initializer;
-};
-
-ScriptPromise MediaKeySessionInitializer::create(ScriptState* scriptState, MediaKeys* mediaKeys, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String& sessionType)
-{
- RefPtr<MediaKeySessionInitializer> initializer = adoptRef(new MediaKeySessionInitializer(scriptState, mediaKeys, initDataType, initData, sessionType));
- initializer->suspendIfNeeded();
- initializer->keepAliveWhilePending();
- return initializer->promise();
-}
-
-MediaKeySessionInitializer::MediaKeySessionInitializer(ScriptState* scriptState, MediaKeys* mediaKeys, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String& sessionType)
- : ScriptPromiseResolver(scriptState)
- , m_mediaKeys(mediaKeys)
- , m_initDataType(initDataType)
- , m_initData(initData)
- , m_sessionType(sessionType)
- , m_timer(this, &MediaKeySessionInitializer::timerFired)
-{
- WTF_LOG(Media, "MediaKeySessionInitializer::MediaKeySessionInitializer");
+ // It is only valid to call this before completion.
+ ScriptPromise promise() { return m_resolver->promise(); }
- // Start the timer so that MediaKeySession can be created asynchronously.
- m_timer.startOneShot(0, FROM_HERE);
-}
-
-MediaKeySessionInitializer::~MediaKeySessionInitializer()
-{
- WTF_LOG(Media, "MediaKeySessionInitializer::~MediaKeySessionInitializer");
-}
-
-void MediaKeySessionInitializer::timerFired(Timer<MediaKeySessionInitializer>*)
-{
- WTF_LOG(Media, "MediaKeySessionInitializer::timerFired");
-
- // Continue MediaKeys::createSession() at step 7.
- // 7.1 Let request be null. (Request provided by cdm in message event).
- // 7.2 Let default URL be null. (Also provided by cdm in message event).
-
- // 7.3 Let cdm be the cdm loaded in create().
- WebContentDecryptionModule* cdm = m_mediaKeys->contentDecryptionModule();
-
- // 7.4 Use the cdm to execute the following steps:
- // 7.4.1 If the init data is not valid for initDataType, reject promise
- // with a new DOMException whose name is "InvalidAccessError".
- // 7.4.2 If the init data is not supported by the cdm, reject promise with
- // a new DOMException whose name is "NotSupportedError".
- // 7.4.3 Let request be a request (e.g. a license request) generated based
- // on the init data, which is interpreteted per initDataType, and
- // sessionType. If sessionType is "temporary", the request is for a
- // temporary non-persisted license. If sessionType is "persistent",
- // the request is for a persistable license.
- // 7.4.4 If the init data indicates a default URL, let default URL be
- // that URL. The URL may be validated and/or normalized.
- m_cdmSession = adoptPtr(cdm->createSession());
- NewMediaKeySessionResult* result = new NewMediaKeySessionResult(this);
- m_cdmSession->initializeNewSession(m_initDataType, static_cast<unsigned char*>(m_initData->data()), m_initData->byteLength(), m_sessionType, result->result());
-
- WTF_LOG(Media, "MediaKeySessionInitializer::timerFired done");
- // Note: As soon as the promise is resolved (or rejected), the
- // ScriptPromiseResolver object (|this|) is freed. So if
- // initializeNewSession() is synchronous, access to any members will crash.
-}
-
-void MediaKeySessionInitializer::completeWithSession(WebContentDecryptionModuleResult::SessionStatus status)
-{
- WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession");
-
- switch (status) {
- case WebContentDecryptionModuleResult::NewSession: {
- // Resume MediaKeys::createSession().
- // 7.5 Let the session ID be a unique Session ID string. It may be
- // obtained from cdm (it is).
- // 7.6 Let session be a new MediaKeySession object, and initialize it.
- // (Object was created previously, complete the steps for 7.6).
- RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollectedWillBeNoop(new MediaKeySession(executionContext(), m_mediaKeys, m_cdmSession.release()));
- session->suspendIfNeeded();
-
- // 7.7 If any of the preceding steps failed, reject promise with a
- // new DOMException whose name is the appropriate error name
- // and that has an appropriate message.
- // (Implemented by CDM/Chromium calling completeWithError()).
-
- // 7.8 Add an entry for the value of the sessionId attribute to the
- // list of active session IDs for this object.
- // (Implemented in SessionIdAdapter).
-
- // 7.9 Run the Queue a "message" Event algorithm on the session,
- // providing request and default URL.
- // (Done by the CDM).
-
- // 7.10 Resolve promise with session.
- resolve(session.release());
- WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/session");
- return;
+ void trace(Visitor* visitor)
+ {
+ visitor->trace(m_session);
+ ContentDecryptionModuleResult::trace(visitor);
}
- case WebContentDecryptionModuleResult::SessionNotFound:
- // Step 4.7.1 of MediaKeys::loadSession(): If there is no data
- // stored for the sessionId in the origin, resolve promise with
- // undefined.
- resolve(V8UndefinedType());
- WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/undefined");
- return;
-
- case WebContentDecryptionModuleResult::SessionAlreadyExists:
- // If a session already exists, resolve the promise with null.
- resolve(V8NullType());
- WTF_LOG(Media, "MediaKeySessionInitializer::completeWithSession done w/null");
- return;
+private:
+ // Reject the promise with a DOMException.
+ void completeWithDOMException(ExceptionCode code, const String& errorMessage)
+ {
+ m_resolver->reject(DOMException::create(code, errorMessage));
+ m_resolver.clear();
}
- ASSERT_NOT_REACHED();
-}
-void MediaKeySessionInitializer::completeWithDOMException(ExceptionCode code, const String& errorMessage)
-{
- WTF_LOG(Media, "MediaKeySessionInitializer::completeWithDOMException");
- reject(DOMException::create(code, errorMessage));
-}
+ RefPtr<ScriptPromiseResolver> m_resolver;
ddorwin 2014/09/09 00:44:36 OOC, why is this still a RefPtr?
jrummell 2014/09/09 19:55:58 ScriptPromiseResolver::create() returns PassRefPtr
+ Member<MediaKeySession> m_session;
+};
-ScriptPromise MediaKeySession::create(ScriptState* scriptState, MediaKeys* mediaKeys, const String& initDataType, PassRefPtr<ArrayBuffer> initData, const String& sessionType)
+MediaKeySession* MediaKeySession::create(ScriptState* scriptState, MediaKeys* mediaKeys, const String& sessionType)
{
- // Since creation is done asynchronously, use MediaKeySessionInitializer
- // to do it.
- return MediaKeySessionInitializer::create(scriptState, mediaKeys, initDataType, initData, sessionType);
+ RefPtrWillBeRawPtr<MediaKeySession> session = adoptRefCountedGarbageCollectedWillBeNoop(new MediaKeySession(scriptState, mediaKeys, sessionType));
+ session->suspendIfNeeded();
+ return session.get();
}
-MediaKeySession::MediaKeySession(ExecutionContext* context, MediaKeys* keys, PassOwnPtr<WebContentDecryptionModuleSession> cdmSession)
- : ActiveDOMObject(context)
+MediaKeySession::MediaKeySession(ScriptState* scriptState, MediaKeys* keys, const String& sessionType)
ddorwin 2014/09/09 00:44:36 nit: media_keys. keys seems a bit ambiguous.
jrummell 2014/09/09 19:55:58 Done.
+ : ActiveDOMObject(scriptState->executionContext())
, m_keySystem(keys->keySystem())
ddorwin 2014/09/09 00:44:36 We should not be saving this - it's no longer a me
jrummell 2014/09/09 19:55:58 Will be done in a CL that cleans up this class.
, m_asyncEventQueue(GenericEventQueue::create(this))
- , m_session(cdmSession)
- , m_keys(keys)
+ , m_mediaKeys(keys)
+ , m_expiration(nan(""))
ddorwin 2014/09/09 00:44:35 Why does this take a string? FYI, I also see NaN()
jrummell 2014/09/09 19:55:59 I just did a search for C++ nan, and it pointed to
ddorwin 2014/09/09 21:35:24 double.h is in Blink's WTF IIRC.
jrummell 2014/09/10 01:18:24 But that is for "class Double", which is different
+ , m_sessionType(sessionType)
+ , m_uninitialized(true)
+ , m_callable(false)
, m_isClosed(false)
- , m_closedPromise(new ClosedPromise(context, this, ClosedPromise::Closed))
+ , m_closedPromise(new ClosedPromise(scriptState->executionContext(), this, ClosedPromise::Closed))
, m_actionTimer(this, &MediaKeySession::actionTimerFired)
{
WTF_LOG(Media, "MediaKeySession(%p)::MediaKeySession", this);
ScriptWrappable::init(this);
- m_session->setClientInterface(this);
- // Resume MediaKeys::createSession() at step 7.6.
- // 7.6.1 Set the error attribute to null.
- ASSERT(!m_error);
+ // MediaKeys::createSession(), step 2.
+ // 2.1 Let the sessionId attribute be the empty string.
+ ASSERT(sessionId().isEmpty());
ddorwin 2014/09/09 00:44:36 nit: If we are going to keep these as members, we
jrummell 2014/09/09 19:55:59 Now that m_session is created above, member is gon
+
+ // 2.2 Let the expiration attribute be NaN.
+ ASSERT(isnan(expiration()));
+
+ // 2.3 Let the closed attribute be a new promise.
+ ASSERT(!closed(scriptState).isUndefinedOrNull());
+
+ // 2.4 Let the session type be sessionType.
+ ASSERT(sessionType == m_sessionType);
- // 7.6.2 Set the sessionId attribute to session ID.
- ASSERT(!sessionId().isEmpty());
+ // 2.5 Let uninitialized be true.
+ ASSERT(m_uninitialized);
- // 7.6.3 Let expiration be NaN.
- // 7.6.4 Let closed be a new promise.
- // 7.6.5 Let the session type be sessionType.
- // FIXME: Implement the previous 3 values.
+ // 2.6 Let callable be false.
+ ASSERT(!m_callable);
}
MediaKeySession::~MediaKeySession()
@@ -353,14 +267,85 @@ void MediaKeySession::setError(MediaKeyError* error)
m_error = error;
}
-String MediaKeySession::sessionId() const
+ScriptPromise MediaKeySession::closed(ScriptState* scriptState)
{
- return m_session->sessionId();
+ return m_closedPromise->promise(scriptState->world());
}
-ScriptPromise MediaKeySession::closed(ScriptState* scriptState)
+ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, const String& initDataType, ArrayBuffer* initData)
{
- return m_closedPromise->promise(scriptState->world());
+ RefPtr<ArrayBuffer> initDataCopy = ArrayBuffer::create(initData->data(), initData->byteLength());
+ return generateRequestInternal(scriptState, initDataType, initDataCopy.release());
+}
+
+ScriptPromise MediaKeySession::generateRequest(ScriptState* scriptState, const String& initDataType, ArrayBufferView* initData)
+{
+ RefPtr<ArrayBuffer> initDataCopy = ArrayBuffer::create(initData->baseAddress(), initData->byteLength());
+ return generateRequestInternal(scriptState, initDataType, initDataCopy.release());
+}
+
+ScriptPromise MediaKeySession::generateRequestInternal(ScriptState* scriptState, const String& initDataType, PassRefPtr<ArrayBuffer> initData)
+{
+ WTF_LOG(Media, "MediaKeySession(%p)::generateRequest %s", this, initDataType.ascii().data());
+
+ // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-generaterequest:
ddorwin 2014/09/09 00:44:35 nit: Why the URL here? I don't think we have these
jrummell 2014/09/09 19:55:59 Just followed the existing pattern in update() and
+ // The generateRequest(initDataType, initData) method creates a new session
+ // for the specified initData. It must run the following steps:
+
+ // 1. If this object's uninitialized value is false, return a promise rejected
+ // with a new DOMException whose name is "InvalidStateError".
+ if (!m_uninitialized) {
+ return ScriptPromise::rejectWithDOMException(
+ scriptState, DOMException::create(InvalidStateError, "The session already exists."));
ddorwin 2014/09/09 00:44:36 s/exists/initialized/ OR s/already exists/has alre
jrummell 2014/09/09 19:55:58 Done.
+ }
+
+ // 2. Let this object's uninitialized be false.
+ m_uninitialized = false;
+
+ // 3. If initDataType is an empty string, return a promise rejected with a
+ // new DOMException whose name is "InvalidAccessError".
+ if (initDataType.isEmpty()) {
+ return ScriptPromise::rejectWithDOMException(
+ scriptState, DOMException::create(InvalidAccessError, "The initDataType parameter is empty."));
+ }
+
+ // 4. If initData is an empty array, return a promise rejected with a new
+ // DOMException whose name is"InvalidAccessError".
+ if (!initData->byteLength()) {
+ return ScriptPromise::rejectWithDOMException(
+ scriptState, DOMException::create(InvalidAccessError, "The initData parameter is empty."));
+ }
+
+ // 5. Let media keys be the MediaKeys object that created this object.
+ // (Done in constructor.)
ddorwin 2014/09/09 00:44:36 nit: This isn't actually about saving it as a memb
jrummell 2014/09/09 19:55:58 Done.
+
+ // 6. If the content decryption module corresponding to media keys's keySystem
+ // attribute does not support initDataType as an initialization data type,
+ // return a promise rejected with a new DOMException whose name is
+ // "NotSupportedError". String comparison is case-sensitive.
+ if (!isKeySystemSupportedWithInitDataType(m_keySystem, initDataType)) {
ddorwin 2014/09/09 00:44:35 Per earlier comments and the algorithm, this shoul
jrummell 2014/09/09 19:55:59 But then we would have the issue that it is possib
ddorwin 2014/09/09 21:35:24 Good point! I probably need to update the spec too
+ return ScriptPromise::rejectWithDOMException(
+ scriptState, DOMException::create(NotSupportedError, "The initialization data type '" + initDataType + "' is not supported by the key system."));
+ }
+
+ // 7. Let init data be a copy of the contents of the initData parameter.
+ // (Done before calling this method.)
+
+ // 8. Let session type be this object's session type.
+ // (Done in constructor.)
+
+ // 9. Let promise be a new promise.
+ NewSessionResult* result = new NewSessionResult(scriptState, this);
+ ScriptPromise promise = result->promise();
+
+ // 10. Run the following steps asynchronously (documented in
+ // actionTimerFired())
+ m_pendingActions.append(PendingAction::CreatePendingGenerateRequest(result, initDataType, initData));
+ if (!m_actionTimer.isActive())
ddorwin 2014/09/09 00:44:36 I think this is an ASSERT - nothing else should ha
jrummell 2014/09/09 19:55:59 Done.
+ m_actionTimer.startOneShot(0, FROM_HERE);
+
+ // 11. Return promise.
+ return promise;
}
ScriptPromise MediaKeySession::update(ScriptState* scriptState, ArrayBuffer* response)
@@ -456,6 +441,34 @@ void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*)
PendingAction* action = pendingActions.takeFirst();
switch (action->type()) {
+ case PendingAction::GenerateRequest:
+ WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: GenerateRequest", this);
+
+ {
+ // 10.1 Let request be null.
+ // 10.2 Let cdm be the CDM loaded during the initialization of
+ // media keys.
+ WebContentDecryptionModule* cdm = m_mediaKeys->contentDecryptionModule();
+
+ // 10.3 Use the cdm to execute the following steps:
+ // 10.3.1 If the init data is not valid for initDataType, reject
+ // promise with a new DOMException whose name is
+ // "InvalidAccessError".
+ // 10.3.2 If the init data is not supported by the cdm, reject
+ // promise with a new DOMException whose name is
+ // "NotSupportedError".
+ // 10.3.3 Let request be a request (e.g. a license request)
+ // generated based on the init data, which is interpreted
+ // per initDataType, and session type.
+ m_session = adoptPtr(cdm->createSession());
ddorwin 2014/09/09 00:44:36 We should do this during creation.
jrummell 2014/09/09 19:55:58 Done.
+ m_session->setClientInterface(this);
+ m_session->initializeNewSession(action->initDataType(), static_cast<unsigned char*>(action->data()->data()), action->data()->byteLength(), m_sessionType, action->result()->result());
+ }
+
+ // Remainder of steps executed in finishGenerateRequest(), called
+ // when |result| is resolved.
+ break;
+
case PendingAction::Update:
WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Update", this);
// NOTE: Continued from step 4 of MediaKeySession::update().
@@ -463,6 +476,7 @@ void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*)
// completed, it will resolve/reject the promise.
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().
@@ -474,14 +488,37 @@ void MediaKeySession::actionTimerFired(Timer<MediaKeySession>*)
// 3.3 Resolve promise with undefined.
m_session->release(action->result()->result());
break;
- case PendingAction::Message:
- WTF_LOG(Media, "MediaKeySession(%p)::actionTimerFired: Message", this);
- m_asyncEventQueue->enqueueEvent(action->event().release());
- break;
}
}
}
+void MediaKeySession::finishGenerateRequest()
+{
+ // 10.4 Set the sessionId attribute to a unique Session ID string.
+ // It may be obtained from cdm.
+ m_sessionId = m_session->sessionId();
ddorwin 2014/09/09 00:44:35 ASSERT(!empty()) Also, I'm not sure we should save
jrummell 2014/09/09 19:55:59 sessionId() now calls this function as needed.
+
+ // 10.5 If any of the preceding steps failed, reject promise with a new
+ // DOMException whose name is the appropriate error name.
+ // (Done by call to completeWithError()).
+
+ // 10.6 Add an entry for the value of the sessionId attribute to
+ // media keys's list of active session IDs.
+ // FIXME: Is this required?
ddorwin 2014/09/09 00:44:35 Probably not: https://www.w3.org/Bugs/Public/show_
jrummell 2014/09/09 19:55:59 Acknowledged.
+
+ // 10.7 Run the Queue a "message" Event algorithm on the session,
+ // providing request and null.
+ // (Done by the CDM).
ddorwin 2014/09/09 00:44:35 Hmm. We need to somehow guarantee that this messag
jrummell 2014/09/09 19:55:59 Added ASSERT in message() to verify this.
+
+ // 10.8 Let this object's callable be true.
+ m_callable = true;
+
+ // Additionally, we no longer need to keep MediaKeys around. Switch to
+ // WeakMember.
+ m_keys = m_mediaKeys;
+ m_mediaKeys.clear();
+}
+
// Queue a task to fire a simple event named keymessage at the new object
void MediaKeySession::message(const unsigned char* message, size_t messageLength, const WebURL& destinationURL)
{
@@ -495,21 +532,6 @@ void MediaKeySession::message(const unsigned char* message, size_t messageLength
RefPtrWillBeRawPtr<MediaKeyMessageEvent> event = MediaKeyMessageEvent::create(EventTypeNames::message, init);
event->setTarget(this);
-
- if (!hasEventListeners()) {
- // Since this event may be generated immediately after resolving the
- // CreateSession() promise, it is possible that the JavaScript hasn't
- // had time to run the .then() action and bind any necessary event
- // handlers. If there are no event handlers connected, delay enqueuing
- // this message to provide time for the JavaScript to run. This will
- // also affect the (rare) case where there is no message handler
- // attched during normal operation.
- m_pendingActions.append(PendingAction::CreatePendingMessage(event.release()));
- if (!m_actionTimer.isActive())
- m_actionTimer.startOneShot(0, FROM_HERE);
- return;
- }
-
m_asyncEventQueue->enqueueEvent(event.release());
}
@@ -625,6 +647,7 @@ void MediaKeySession::trace(Visitor* visitor)
visitor->trace(m_error);
visitor->trace(m_asyncEventQueue);
visitor->trace(m_pendingActions);
+ visitor->trace(m_mediaKeys);
visitor->trace(m_keys);
visitor->trace(m_closedPromise);
EventTargetWithInlineData::trace(visitor);

Powered by Google App Engine
This is Rietveld 408576698