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