https://bugs.webkit.org/show_bug.cgi?id=167869
Reviewed by Xabier Rodriguez-Calvar.
Source/WebCore:
Implement MediaKeySession::close() as outlined in the specification.
The CDMInstance::closeSession() virtual method, when called, should
close the session that's represented by the passed-in session ID on
the CDMInstance implementor object. That's the same session ID that
the CDMInstance object passes to the MediaKeySession class through
the callback that's provided to the updateLicense call.
The CloseSessionCallback, passed to CDMInstance::closeSession(),
should be invoked by the CDMInstance implementor once the session
is closed. When that is invoked, another task is queued for the
MediaKeySession object that runs the `session closed` algorithm
and resolves the promise.
MockCDMInstance::closeSession() is defined to remove the session
from the MockCDMFactory object and invoke the CloseSessionCallback.
Test: media/encrypted-media/mock-MediaKeySession-close.html
* Modules/encryptedmedia/CDMInstance.h:
* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::MediaKeySession::close):
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMInstance::closeSession):
* testing/MockCDMFactory.h:
LayoutTests:
Add the mock-MediaKeySession-close.html test case which checks proper
behavior of MediaKeySession::close(), specifically that under specific
conditions the promise returned by that method is properly resolved or
rejected. The test is skipped on all platforms for now.
* media/encrypted-media/mock-MediaKeySession-close-expected.txt: Added.
* media/encrypted-media/mock-MediaKeySession-close.html: Added.
* platform/efl/TestExpectations:
* platform/mac/TestExpectations:
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211856
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2017-02-08 Zan Dobersek <zdobersek@igalia.com>
+
+ [EME] Implement MediaKeySession::close()
+ https://bugs.webkit.org/show_bug.cgi?id=167869
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ Add the mock-MediaKeySession-close.html test case which checks proper
+ behavior of MediaKeySession::close(), specifically that under specific
+ conditions the promise returned by that method is properly resolved or
+ rejected. The test is skipped on all platforms for now.
+
+ * media/encrypted-media/mock-MediaKeySession-close-expected.txt: Added.
+ * media/encrypted-media/mock-MediaKeySession-close.html: Added.
+ * platform/efl/TestExpectations:
+ * platform/mac/TestExpectations:
+
2017-02-07 Ryosuke Niwa <rniwa@webkit.org>
WebContent process repeatedly jetsams on BuzzFeed's Another Round page
--- /dev/null
+RUN(internals.initializeMockMediaSource())
+RUN(mock = internals.registerMockCDM())
+RUN(mock.supportedDataTypes = ["keyids"])
+RUN(capabilities.initDataTypes = ["keyids"])
+RUN(capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] )
+RUN(promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities]))
+Promise resolved OK
+
+RUN(promise = mediaKeySystemAccess.createMediaKeys())
+Promise resolved OK
+
+Closing a non-callable MediaKeySession should reject.
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+EXPECTED (typeof mediaKeySession == 'object') OK
+RUN(promise = mediaKeySession.close())
+Promise rejected correctly OK
+
+Closing a failed MediaKeySession should reject.
+RUN(kids = JSON.stringify({ invalid: "invalid" }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids)))
+Promise rejected correctly OK
+RUN(promise = mediaKeySession.close())
+Promise rejected correctly OK
+
+Closing a valid MediaKeySession should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.close())
+Promise resolved OK
+
+Closing a closed MediaKeySession should resolve.
+RUN(kids = JSON.stringify({ kids: [ "MTIzNDU=" ] }))
+RUN(mediaKeySession = mediaKeys.createSession("temporary"))
+RUN(promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids)))
+Promise resolved OK
+RUN(promise = mediaKeySession.close())
+Promise resolved OK
+RUN(promise = mediaKeySession.close())
+Promise resolved OK
+END OF TEST
+
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <script src=../video-test.js></script>
+ <script type="text/javascript">
+ var mock;
+ var promise;
+ var mediaKeySystemAccess;
+ var mediaKeys;
+ var mediaKeySession;
+ var capabilities = {};
+ var kids;
+ var encoder = new TextEncoder();
+
+ function doTest()
+ {
+ if (!window.internals) {
+ failTest("Internals is required for this test.")
+ return;
+ }
+
+ run('internals.initializeMockMediaSource()');
+ run('mock = internals.registerMockCDM()');
+ run('mock.supportedDataTypes = ["keyids"]');
+ run('capabilities.initDataTypes = ["keyids"]');
+ run(`capabilities.videoCapabilities = [{ contentType: 'video/mock; codecs="mock"' }] `);
+ run('promise = navigator.requestMediaKeySystemAccess("org.webkit.mock", [capabilities])');
+ shouldResolve(promise).then(gotMediaKeySystemAccess, failTest);
+ }
+
+ function next() {
+ if (!tests.length) {
+ mock.unregister();
+ endTest()
+ return;
+ }
+
+ var nextTest = tests.shift();
+ consoleWrite('');
+ nextTest();
+ }
+
+ function gotMediaKeySystemAccess(result) {
+ mediaKeySystemAccess = result;
+ next();
+ }
+
+ function gotMediaKeys(result) {
+ mediaKeys = result;
+ next();
+ }
+
+ tests = [
+ function() {
+ run('promise = mediaKeySystemAccess.createMediaKeys()');
+ shouldResolve(promise).then(gotMediaKeys, failTest);
+ },
+
+ function() {
+ consoleWrite('Closing a non-callable MediaKeySession should reject.');
+ run('mediaKeySession = mediaKeys.createSession("temporary")');
+ testExpected('typeof mediaKeySession', 'object');
+ run('promise = mediaKeySession.close()');
+ shouldReject(promise).then(next, next);
+ },
+
+ function() {
+ consoleWrite('Closing a failed MediaKeySession should reject.')
+ run('kids = JSON.stringify({ invalid: "invalid" })');
+ run('mediaKeySession = mediaKeys.createSession("temporary")');
+ run('promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids))');
+ shouldReject(promise).then(function() {
+ run('promise = mediaKeySession.close()');
+ shouldReject(promise).then(next, next);
+ }, next);
+ },
+
+ function() {
+ consoleWrite('Closing a valid MediaKeySession should resolve.')
+ run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+ run('mediaKeySession = mediaKeys.createSession("temporary")');
+ run('promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids))');
+ shouldResolve(promise).then(function() {
+ run('promise = mediaKeySession.close()');
+ shouldResolve(promise).then(next, next);
+ }, next);
+ },
+
+ function() {
+ consoleWrite('Closing a closed MediaKeySession should resolve.')
+ run('kids = JSON.stringify({ kids: [ "MTIzNDU=" ] })');
+ run('mediaKeySession = mediaKeys.createSession("temporary")');
+ run('promise = mediaKeySession.generateRequest("keyids", encoder.encode(kids))');
+ shouldResolve(promise).then(function() {
+ run('promise = mediaKeySession.close()');
+ shouldResolve(promise).then(function() {
+ run('promise = mediaKeySession.close()');
+ shouldResolve(promise).then(next, next);
+ }, next);
+ }, next);
+ },
+ ];
+ </script>
+</head>
+<body onload="doTest()">
+</body>
+</html>
Bug(EFL) media/encrypted-media/encrypted-media-is-type-supported.html [ Failure ]
Bug(EFL) media/encrypted-media/encrypted-media-not-loaded.html [ Failure ]
Bug(EFL) media/encrypted-media/encrypted-media-syntax.html [ Failure ]
+Bug(EFL) media/encrypted-media/mock-MediaKeySession-close.html [ Failure ]
Bug(EFL) media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Failure ]
Bug(EFL) media/encrypted-media/mock-MediaKeySession-update.html [ Failure ]
Bug(EFL) media/encrypted-media/mock-MediaKeySystemAccess.html [ Failure ]
media/encrypted-media/mock-MediaKeySystemAccess.html [ Skip ]
media/encrypted-media/mock-MediaKeys-setServerCertificate.html [ Skip ]
media/encrypted-media/mock-MediaKeys-createSession.html [ Skip ]
+media/encrypted-media/mock-MediaKeySession-close.html [ Skip ]
media/encrypted-media/mock-MediaKeySession-generateRequest.html [ Skip ]
media/encrypted-media/mock-MediaKeySession-update.html [ Skip ]
2017-02-08 Zan Dobersek <zdobersek@igalia.com>
+ [EME] Implement MediaKeySession::close()
+ https://bugs.webkit.org/show_bug.cgi?id=167869
+
+ Reviewed by Xabier Rodriguez-Calvar.
+
+ Implement MediaKeySession::close() as outlined in the specification.
+
+ The CDMInstance::closeSession() virtual method, when called, should
+ close the session that's represented by the passed-in session ID on
+ the CDMInstance implementor object. That's the same session ID that
+ the CDMInstance object passes to the MediaKeySession class through
+ the callback that's provided to the updateLicense call.
+
+ The CloseSessionCallback, passed to CDMInstance::closeSession(),
+ should be invoked by the CDMInstance implementor once the session
+ is closed. When that is invoked, another task is queued for the
+ MediaKeySession object that runs the `session closed` algorithm
+ and resolves the promise.
+
+ MockCDMInstance::closeSession() is defined to remove the session
+ from the MockCDMFactory object and invoke the CloseSessionCallback.
+
+ Test: media/encrypted-media/mock-MediaKeySession-close.html
+
+ * Modules/encryptedmedia/CDMInstance.h:
+ * Modules/encryptedmedia/MediaKeySession.cpp:
+ (WebCore::MediaKeySession::close):
+ * testing/MockCDMFactory.cpp:
+ (WebCore::MockCDMInstance::closeSession):
+ * testing/MockCDMFactory.h:
+
+2017-02-08 Zan Dobersek <zdobersek@igalia.com>
+
[EME] Alias CDMInstance enums to the specification-defined enums
https://bugs.webkit.org/show_bug.cgi?id=167896
using Message = std::pair<MessageType, Ref<SharedBuffer>>;
using LicenseUpdateCallback = Function<void(bool sessionWasClosed, std::optional<KeyStatusVector>&& changedKeys, std::optional<double>&& changedExpiration, std::optional<Message>&& message, SuccessValue succeeded)>;
virtual void updateLicense(LicenseType, const SharedBuffer& response, LicenseUpdateCallback) = 0;
+
+ using CloseSessionCallback = Function<void()>;
+ virtual void closeSession(const String& sessionId, CloseSessionCallback) = 0;
};
}
// 7. Return promise.
}
-void MediaKeySession::close(Ref<DeferredPromise>&&)
+void MediaKeySession::close(Ref<DeferredPromise>&& promise)
{
- notImplemented();
+ // https://w3c.github.io/encrypted-media/#dom-mediakeysession-close
+ // W3C Editor's Draft 09 November 2016
+
+ // 1. Let session be the associated MediaKeySession object.
+ // 2. If session is closed, return a resolved promise.
+ if (m_closed) {
+ promise->resolve();
+ return;
+ }
+
+ // 3. If session's callable value is false, return a promise rejected with an InvalidStateError.
+ if (!m_callable) {
+ promise->reject(INVALID_STATE_ERR);
+ return;
+ }
+
+ // 4. Let promise be a new promise.
+ // 5. Run the following steps in parallel:
+ m_taskQueue.enqueueTask([this, promise = WTFMove(promise)] () mutable {
+ // 5.1. Let cdm be the CDM instance represented by session's cdm instance value.
+ // 5.2. Use cdm to close the key session associated with session.
+ m_instance->closeSession(m_sessionId, [this, weakThis = m_weakPtrFactory.createWeakPtr(), promise = WTFMove(promise)] () mutable {
+ if (!weakThis)
+ return;
+
+ // 5.3. Queue a task to run the following steps:
+ m_taskQueue.enqueueTask([this, promise = WTFMove(promise)] () mutable {
+ // 5.3.1. Run the Session Closed algorithm on the session.
+ sessionClosed();
+
+ // 5.3.2. Resolve promise.
+ promise->resolve();
+ });
+ });
+ });
+
+ // 6. Return promise.
}
void MediaKeySession::remove(Ref<DeferredPromise>&&)
callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Succeeded);
}
+void MockCDMInstance::closeSession(const String& sessionID, CloseSessionCallback callback)
+{
+ MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+ if (!factory) {
+ callback();
+ return;
+ }
+
+ factory->removeSessionWithID(sessionID);
+ callback();
+}
+
}
#endif
SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final;
void updateLicense(LicenseType, const SharedBuffer&, LicenseUpdateCallback) final;
+ void closeSession(const String&, CloseSessionCallback) final;
WeakPtr<MockCDM> m_cdm;
bool m_distinctiveIdentifiersAllowed { true };