Index: Source/modules/encryptedmedia/MediaKeys.cpp |
diff --git a/Source/modules/encryptedmedia/MediaKeys.cpp b/Source/modules/encryptedmedia/MediaKeys.cpp |
index 462eef5c603456349d44dba35b48696ece90ca1c..b9196ae81bc8d27289604bbec963e4c333fd8486 100644 |
--- a/Source/modules/encryptedmedia/MediaKeys.cpp |
+++ b/Source/modules/encryptedmedia/MediaKeys.cpp |
@@ -35,6 +35,7 @@ |
#include "modules/encryptedmedia/MediaKeyMessageEvent.h" |
#include "modules/encryptedmedia/MediaKeySession.h" |
#include "modules/encryptedmedia/MediaKeysController.h" |
+#include "modules/encryptedmedia/SimpleContentDecryptionModuleResult.h" |
#include "platform/ContentType.h" |
#include "platform/Logging.h" |
#include "platform/MIMETypeRegistry.h" |
@@ -72,6 +73,46 @@ static ScriptPromise createRejectedPromise(ScriptState* scriptState, ExceptionCo |
return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(error, errorMessage)); |
} |
+// A class holding a pending action. |
+class MediaKeys::PendingAction : public GarbageCollectedFinalized<MediaKeys::PendingAction> { |
+public: |
+ const Persistent<ContentDecryptionModuleResult> result() const |
+ { |
+ return m_result; |
+ } |
+ |
+ const RefPtr<ArrayBuffer> data() const |
+ { |
+ return m_data; |
+ } |
+ |
+ static PendingAction* CreatePendingSetServerCertificate(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> serverCertificate) |
+ { |
+ ASSERT(result); |
+ ASSERT(serverCertificate); |
+ return new PendingAction(result, serverCertificate); |
+ } |
+ |
+ ~PendingAction() |
+ { |
+ } |
+ |
+ void trace(Visitor* visitor) |
+ { |
+ visitor->trace(m_result); |
+ } |
+ |
+private: |
+ PendingAction(ContentDecryptionModuleResult* result, PassRefPtr<ArrayBuffer> data) |
+ : m_result(result) |
+ , m_data(data) |
+ { |
+ } |
+ |
+ const Member<ContentDecryptionModuleResult> m_result; |
+ const RefPtr<ArrayBuffer> m_data; |
+}; |
+ |
// This class allows a MediaKeys object to be created asynchronously. |
class MediaKeysInitializer : public ScriptPromiseResolver { |
WTF_MAKE_NONCOPYABLE(MediaKeysInitializer); |
@@ -177,6 +218,7 @@ MediaKeys::MediaKeys(ExecutionContext* context, const String& keySystem, PassOwn |
: ContextLifecycleObserver(context) |
, m_keySystem(keySystem) |
, m_cdm(cdm) |
+ , m_timer(this, &MediaKeys::timerFired) |
{ |
WTF_LOG(Media, "MediaKeys(%p)::MediaKeys", this); |
@@ -210,6 +252,53 @@ MediaKeySession* MediaKeys::createSession(ScriptState* scriptState, const String |
return MediaKeySession::create(scriptState, this, sessionType); |
} |
+ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBuffer* serverCertificate) |
+{ |
+ RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertificate->data(), serverCertificate->byteLength()); |
+ return setServerCertificateInternal(scriptState, serverCertificateCopy.release()); |
+} |
+ |
+ScriptPromise MediaKeys::setServerCertificate(ScriptState* scriptState, ArrayBufferView* serverCertificate) |
+{ |
+ RefPtr<ArrayBuffer> serverCertificateCopy = ArrayBuffer::create(serverCertificate->baseAddress(), serverCertificate->byteLength()); |
+ return setServerCertificateInternal(scriptState, serverCertificateCopy.release()); |
+} |
+ |
+ScriptPromise MediaKeys::setServerCertificateInternal(ScriptState* scriptState, PassRefPtr<ArrayBuffer> serverCertificate) |
+{ |
+ // From https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html#dom-setservercertificate: |
+ // The setServerCertificate(serverCertificate) method provides a server |
+ // certificate to be used to encrypt messages to the license server. |
+ // It must run the following steps: |
+ // 1. If serverCertificate is an empty array, return a promise rejected |
+ // with a new DOMException whose name is "InvalidAccessError". |
+ if (!serverCertificate->byteLength()) { |
+ return ScriptPromise::rejectWithDOMException( |
+ scriptState, DOMException::create(InvalidAccessError, "The serverCertificate parameter is empty.")); |
+ } |
+ |
+ // 2. If the keySystem does not support server certificates, return a |
+ // promise rejected with a new DOMException whose name is |
+ // "NotSupportedError". |
+ // (Let the CDM decide whether to support this or not.) |
+ |
+ // 3. Let certificate be a copy of the contents of the serverCertificate |
+ // parameter. |
+ // (Done in caller.) |
+ |
+ // 4. Let promise be a new promise. |
+ SimpleContentDecryptionModuleResult* result = new SimpleContentDecryptionModuleResult(scriptState); |
+ ScriptPromise promise = result->promise(); |
+ |
+ // 5. Run the following steps asynchronously (documented in timerFired()). |
+ m_pendingActions.append(PendingAction::CreatePendingSetServerCertificate(result, serverCertificate)); |
sandersd (OOO until July 31)
2014/09/11 23:37:13
If the Chromium promises implementation is correct
jrummell
2014/09/12 20:49:03
The problem is that ClearKey will resolve the prom
ddorwin
2014/09/15 23:10:56
As discussed, let's keep it simple, consistent wit
jrummell
2014/09/17 23:39:24
Acknowledged.
|
+ if (!m_timer.isActive()) |
+ m_timer.startOneShot(0, FROM_HERE); |
+ |
+ // 6. Return promise. |
+ return promise; |
+} |
+ |
bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentType) |
{ |
WTF_LOG(Media, "MediaKeys::isTypeSupported(%s, %s)", keySystem.ascii().data(), contentType.ascii().data()); |
@@ -232,6 +321,32 @@ bool MediaKeys::isTypeSupported(const String& keySystem, const String& contentTy |
return isKeySystemSupportedWithContentType(keySystem, contentType); |
} |
+void MediaKeys::timerFired(Timer<MediaKeys>*) |
+{ |
+ ASSERT(m_pendingActions.size()); |
+ |
+ // Resolving promises now run synchronously and may result in additional |
ddorwin
2014/09/15 23:10:56
"now"? I assume this was inspired by the change in
jrummell
2014/09/17 23:39:24
Comment removed.
|
+ // actions getting added to the queue. As a result, swap the queue to |
ddorwin
2014/09/15 23:10:56
nit: s/As a result,/Therefore,/
jrummell
2014/09/17 23:39:24
Changed.
|
+ // a local copy to avoid problems if this happens. |
+ HeapDeque<Member<PendingAction> > pendingActions; |
+ pendingActions.swap(m_pendingActions); |
+ |
+ while (!pendingActions.isEmpty()) { |
+ PendingAction* action = pendingActions.takeFirst(); |
+ WTF_LOG(Media, "MediaKeys(%p)::timerFired: Certificate", this); |
+ |
+ // 5.1 Let cdm be the cdm during the initialization of this object. |
+ WebContentDecryptionModule* cdm = contentDecryptionModule(); |
+ |
+ // 5.2 Use the cdm to process certificate. |
+ cdm->setServerCertificate(static_cast<unsigned char*>(action->data()->data()), action->data()->byteLength(), action->result()->result()); |
+ // 5.3 If any of the preceding steps failed, reject promise with a |
+ // new DOMException whose name is the appropriate error name. |
+ // 5.4 Resolve promise. |
+ // These are handled by Chromium and the CDM. |
ddorwin
2014/09/15 23:10:56
Add () as elsewhere?
jrummell
2014/09/17 23:39:24
Done.
|
+ } |
+} |
+ |
WebContentDecryptionModule* MediaKeys::contentDecryptionModule() |
{ |
return m_cdm.get(); |
@@ -239,6 +354,7 @@ WebContentDecryptionModule* MediaKeys::contentDecryptionModule() |
void MediaKeys::trace(Visitor* visitor) |
{ |
+ visitor->trace(m_pendingActions); |
} |
void MediaKeys::contextDestroyed() |