summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp')
-rw-r--r--Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp256
1 files changed, 256 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp b/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp
new file mode 100644
index 000000000..7e9e68cd2
--- /dev/null
+++ b/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeySession.cpp
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "WebKitMediaKeySession.h"
+
+#if ENABLE(LEGACY_ENCRYPTED_MEDIA)
+
+#include "Document.h"
+#include "EventNames.h"
+#include "ExceptionCode.h"
+#include "FileSystem.h"
+#include "SecurityOriginData.h"
+#include "Settings.h"
+#include "WebKitMediaKeyError.h"
+#include "WebKitMediaKeyMessageEvent.h"
+#include "WebKitMediaKeys.h"
+
+namespace WebCore {
+
+Ref<WebKitMediaKeySession> WebKitMediaKeySession::create(ScriptExecutionContext& context, WebKitMediaKeys& keys, const String& keySystem)
+{
+ auto session = adoptRef(*new WebKitMediaKeySession(context, keys, keySystem));
+ session->suspendIfNeeded();
+ return session;
+}
+
+WebKitMediaKeySession::WebKitMediaKeySession(ScriptExecutionContext& context, WebKitMediaKeys& keys, const String& keySystem)
+ : ActiveDOMObject(&context)
+ , m_keys(&keys)
+ , m_keySystem(keySystem)
+ , m_asyncEventQueue(*this)
+ , m_session(keys.cdm().createSession(*this))
+ , m_keyRequestTimer(*this, &WebKitMediaKeySession::keyRequestTimerFired)
+ , m_addKeyTimer(*this, &WebKitMediaKeySession::addKeyTimerFired)
+{
+}
+
+WebKitMediaKeySession::~WebKitMediaKeySession()
+{
+ if (m_session)
+ m_session->setClient(nullptr);
+
+ m_asyncEventQueue.cancelAllEvents();
+}
+
+void WebKitMediaKeySession::close()
+{
+ if (m_session)
+ m_session->releaseKeys();
+}
+
+RefPtr<ArrayBuffer> WebKitMediaKeySession::cachedKeyForKeyId(const String& keyId) const
+{
+ return m_session ? m_session->cachedKeyForKeyID(keyId) : nullptr;
+}
+
+const String& WebKitMediaKeySession::sessionId() const
+{
+ return m_session->sessionId();
+}
+
+void WebKitMediaKeySession::generateKeyRequest(const String& mimeType, Ref<Uint8Array>&& initData)
+{
+ m_pendingKeyRequests.append({ mimeType, WTFMove(initData) });
+ m_keyRequestTimer.startOneShot(0);
+}
+
+void WebKitMediaKeySession::keyRequestTimerFired()
+{
+ ASSERT(m_pendingKeyRequests.size());
+ if (!m_session)
+ return;
+
+ while (!m_pendingKeyRequests.isEmpty()) {
+ auto request = m_pendingKeyRequests.takeFirst();
+
+ // NOTE: Continued from step 5 in MediaKeys::createSession().
+ // The user agent will asynchronously execute the following steps in the task:
+
+ // 1. Let cdm be the cdm loaded in the MediaKeys constructor.
+ // 2. Let destinationURL be null.
+ String destinationURL;
+ WebKitMediaKeyError::Code errorCode = 0;
+ uint32_t systemCode = 0;
+
+ // 3. Use cdm to generate a key request and follow the steps for the first matching condition from the following list:
+
+ auto keyRequest = m_session->generateKeyRequest(request.mimeType, request.initData.ptr(), destinationURL, errorCode, systemCode);
+
+ // Otherwise [if a request is not successfully generated]:
+ if (errorCode) {
+ // 3.1. Create a new MediaKeyError object with the following attributes:
+ // code = the appropriate MediaKeyError code
+ // systemCode = a Key System-specific value, if provided, and 0 otherwise
+ // 3.2. Set the MediaKeySession object's error attribute to the error object created in the previous step.
+ // 3.3. queue a task to fire a simple event named keyerror at the MediaKeySession object.
+ sendError(errorCode, systemCode);
+ // 3.4. Abort the task.
+ continue;
+ }
+
+ // 4. queue a task to fire a simple event named keymessage at the new object
+ // The event is of type MediaKeyMessageEvent and has:
+ // message = key request
+ // destinationURL = destinationURL
+ if (keyRequest)
+ sendMessage(keyRequest.get(), destinationURL);
+ }
+}
+
+ExceptionOr<void> WebKitMediaKeySession::update(Ref<Uint8Array>&& key)
+{
+ // From <http://dvcs.w3.org/hg/html-media/raw-file/tip/encrypted-media/encrypted-media.html#dom-addkey>:
+ // The addKey(key) method must run the following steps:
+ // 1. If the first or second argument [sic] is an empty array, throw an INVALID_ACCESS_ERR.
+ // NOTE: the reference to a "second argument" is a spec bug.
+ if (!key->length())
+ return Exception { INVALID_ACCESS_ERR };
+
+ // 2. Schedule a task to handle the call, providing key.
+ m_pendingKeys.append(WTFMove(key));
+ m_addKeyTimer.startOneShot(0);
+
+ return { };
+}
+
+void WebKitMediaKeySession::addKeyTimerFired()
+{
+ ASSERT(m_pendingKeys.size());
+ if (!m_session)
+ return;
+
+ while (!m_pendingKeys.isEmpty()) {
+ auto pendingKey = m_pendingKeys.takeFirst();
+ unsigned short errorCode = 0;
+ uint32_t systemCode = 0;
+
+ // NOTE: Continued from step 2. of MediaKeySession::update()
+ // 2.1. Let cdm be the cdm loaded in the MediaKeys constructor.
+ // NOTE: This is m_session.
+ // 2.2. Let 'did store key' be false.
+ bool didStoreKey = false;
+ // 2.3. Let 'next message' be null.
+ RefPtr<Uint8Array> nextMessage;
+ // 2.4. Use cdm to handle key.
+ didStoreKey = m_session->update(pendingKey.ptr(), nextMessage, errorCode, systemCode);
+ // 2.5. If did store key is true and the media element is waiting for a key, queue a task to attempt to resume playback.
+ // TODO: Find and restart the media element
+
+ // 2.6. If next message is not null, queue a task to fire a simple event named keymessage at the MediaKeySession object.
+ // The event is of type MediaKeyMessageEvent and has:
+ // message = next message
+ // destinationURL = null
+ if (nextMessage)
+ sendMessage(nextMessage.get(), emptyString());
+
+ // 2.7. If did store key is true, queue a task to fire a simple event named keyadded at the MediaKeySession object.
+ if (didStoreKey) {
+ auto keyaddedEvent = Event::create(eventNames().webkitkeyaddedEvent, false, false);
+ keyaddedEvent->setTarget(this);
+ m_asyncEventQueue.enqueueEvent(WTFMove(keyaddedEvent));
+
+ ASSERT(m_keys);
+ m_keys->keyAdded();
+ }
+
+ // 2.8. If any of the preceding steps in the task failed
+ if (errorCode) {
+ // 2.8.1. Create a new MediaKeyError object with the following attributes:
+ // code = the appropriate MediaKeyError code
+ // systemCode = a Key System-specific value, if provided, and 0 otherwise
+ // 2.8.2. Set the MediaKeySession object's error attribute to the error object created in the previous step.
+ // 2.8.3. queue a task to fire a simple event named keyerror at the MediaKeySession object.
+ sendError(errorCode, systemCode);
+ // 2.8.4. Abort the task.
+ // NOTE: no-op
+ }
+ }
+}
+
+void WebKitMediaKeySession::sendMessage(Uint8Array* message, String destinationURL)
+{
+ auto event = WebKitMediaKeyMessageEvent::create(eventNames().webkitkeymessageEvent, message, destinationURL);
+ event->setTarget(this);
+ m_asyncEventQueue.enqueueEvent(WTFMove(event));
+}
+
+void WebKitMediaKeySession::sendError(MediaKeyErrorCode errorCode, uint32_t systemCode)
+{
+ m_error = WebKitMediaKeyError::create(errorCode, systemCode);
+
+ auto keyerrorEvent = Event::create(eventNames().webkitkeyerrorEvent, false, false);
+ keyerrorEvent->setTarget(this);
+ m_asyncEventQueue.enqueueEvent(WTFMove(keyerrorEvent));
+}
+
+String WebKitMediaKeySession::mediaKeysStorageDirectory() const
+{
+ auto* document = downcast<Document>(scriptExecutionContext());
+ if (!document)
+ return emptyString();
+
+ auto storageDirectory = document->settings().mediaKeysStorageDirectory();
+ if (storageDirectory.isEmpty())
+ return emptyString();
+
+ return pathByAppendingComponent(storageDirectory, SecurityOriginData::fromSecurityOrigin(document->securityOrigin()).databaseIdentifier());
+}
+
+bool WebKitMediaKeySession::hasPendingActivity() const
+{
+ return (m_keys && m_session) || m_asyncEventQueue.hasPendingEvents();
+}
+
+void WebKitMediaKeySession::stop()
+{
+ close();
+}
+
+const char* WebKitMediaKeySession::activeDOMObjectName() const
+{
+ return "WebKitMediaKeySession";
+}
+
+bool WebKitMediaKeySession::canSuspendForDocumentSuspension() const
+{
+ // FIXME: We should try and do better here.
+ return false;
+}
+
+}
+
+#endif