[EME] Implement MediaKeySession::sessionClosed()
https://bugs.webkit.org/show_bug.cgi?id=168039
Reviewed by Xabier Rodriguez-Calvar.
Source/WebCore:
Implement the 'session closed' algorithm for MediaKeySession by
following the specified steps. After this algorithm is run, the
session should be considered closed, which we track via the m_closed
member variable on the class. This is set to true before the promise
that's accessible through the 'closed' attribute is resolved.
Because the algorithm requires the CDM instance to store any record
of key usage when the session's type is 'persistent-usage-record', the
storeRecordOfKeyUsage() virtual method is added to the CDMInstance
interface. MockCDMInstance implementation is left unimplemented for now.
JSMediaKeySession::closed() accessor now has a custom implementation
that creates a deferred promise for that object if there's none yet, and
shares it with the wrapped class through the registerClosedPromise()
method, storing a reference to the promise in the m_closedPromise
member variable, or resolving the promise immediately if the session was
already closed.
Test cases added to media/encrypted-media/mock-MediaKeySession-close.html.
* Modules/encryptedmedia/CDMInstance.h:
* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::MediaKeySession::registerClosedPromise):
(WebCore::MediaKeySession::sessionClosed):
* Modules/encryptedmedia/MediaKeySession.h:
* bindings/js/JSMediaKeySessionCustom.cpp:
(WebCore::JSMediaKeySession::closed):
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMInstance::storeRecordOfKeyUsage):
* testing/MockCDMFactory.h:
LayoutTests:
Enhance the mock-MediaKeySession-close.html test by adding test cases
covering the dispatch of the promise that's accessible through the
'closed' attribute and covering the session closure status, making
sure that various operations properly resolve or reject after the
session object was closed.
* media/encrypted-media/mock-MediaKeySession-close-expected.txt:
* media/encrypted-media/mock-MediaKeySession-close.html:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@212109 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/Modules/encryptedmedia/CDMInstance.h b/Source/WebCore/Modules/encryptedmedia/CDMInstance.h
index 8e621b2..22f542c 100644
--- a/Source/WebCore/Modules/encryptedmedia/CDMInstance.h
+++ b/Source/WebCore/Modules/encryptedmedia/CDMInstance.h
@@ -72,6 +72,8 @@
using RemoveSessionDataCallback = Function<void(KeyStatusVector&&, std::optional<Ref<SharedBuffer>>&&, SuccessValue)>;
virtual void removeSessionData(const String& sessionId, LicenseType, RemoveSessionDataCallback) = 0;
+
+ virtual void storeRecordOfKeyUsage(const String& sessionId) = 0;
};
}
diff --git a/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp b/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp
index e17165d..0e1dd37 100644
--- a/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp
+++ b/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp
@@ -469,6 +469,16 @@
// 5. Return promise.
}
+void MediaKeySession::registerClosedPromise(ClosedPromise&& promise)
+{
+ ASSERT(!m_closedPromise);
+ if (m_closed) {
+ promise.resolve();
+ return;
+ }
+ m_closedPromise = WTFMove(promise);
+}
+
void MediaKeySession::enqueueMessage(MediaKeyMessageType messageType, const SharedBuffer& message)
{
// 6.4.1 Queue a "message" Event
@@ -536,7 +546,30 @@
void MediaKeySession::sessionClosed()
{
- notImplemented();
+ // https://w3c.github.io/encrypted-media/#session-closed
+ // W3C Editor's Draft 09 November 2016
+
+ // 1. Let session be the associated MediaKeySession object.
+ // 2. If session's session type is "persistent-usage-record", execute the following steps in parallel:
+ if (m_sessionType == MediaKeySessionType::PersistentUsageRecord) {
+ // 2.1. Let cdm be the CDM instance represented by session's cdm instance value.
+ // 2.2. Use cdm to store session's record of key usage, if it exists.
+ m_instance->storeRecordOfKeyUsage(m_sessionId);
+ }
+
+ // 3. Run the Update Key Statuses algorithm on the session, providing an empty sequence.
+ updateKeyStatuses({ });
+
+ // 4. Run the Update Expiration algorithm on the session, providing NaN.
+ updateExpiration(std::numeric_limits<double>::quiet_NaN());
+
+ // Let's consider the session closed before any promise on the 'closed' attribute is resolved.
+ m_closed = true;
+
+ // 5. Let promise be the closed attribute of the session.
+ // 6. Resolve promise.
+ if (m_closedPromise)
+ m_closedPromise->resolve();
}
bool MediaKeySession::hasPendingActivity() const
diff --git a/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h b/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h
index aaf6e11..0ce875d 100644
--- a/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h
+++ b/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h
@@ -70,6 +70,9 @@
void close(Ref<DeferredPromise>&&);
void remove(Ref<DeferredPromise>&&);
+ using ClosedPromise = DOMPromise<void>;
+ void registerClosedPromise(ClosedPromise&&);
+
const Vector<std::pair<Ref<SharedBuffer>, MediaKeyStatus>>& statuses() const { return m_statuses; }
private:
@@ -93,6 +96,7 @@
String m_sessionId;
double m_expiration;
+ std::optional<ClosedPromise> m_closedPromise;
Ref<MediaKeyStatusMap> m_keyStatuses;
bool m_closed { false };
bool m_uninitialized { true };