[EME] Introduce the concept of CDMInstanceSession.
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Sep 2018 15:08:35 +0000 (15:08 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Sep 2018 15:08:35 +0000 (15:08 +0000)
https://bugs.webkit.org/show_bug.cgi?id=189725

Reviewed by Eric Carlson.

Currently, the same CDMInstance owned by a MediaKeys object is passed to every MediaKeySession created by that
MediaKeys, and since the CDMInstance has only a single CDMInstanceClient, subsequent MediaKeySessions prevent
previous ones from getting updates.

Add a new virtual interface, CDMInstanceSession, to be passed to MediaKeySession upon creation. Refactor
CDMInstanceClearKey and CDMInstanceFairPlayStreamingAVFObjC to adopt this new interface.

Drive-by fixes: Made a number of virtual overrides in final classes final themselves.

* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::MediaKeySession::create):
(WebCore::MediaKeySession::MediaKeySession):
(WebCore::MediaKeySession::generateRequest):
(WebCore::MediaKeySession::load):
(WebCore::MediaKeySession::update):
(WebCore::MediaKeySession::remove):
(WebCore::MediaKeySession::updateKeyStatuses):
* Modules/encryptedmedia/MediaKeySession.h:
* Modules/encryptedmedia/MediaKeys.cpp:
(WebCore::MediaKeys::createSession):
* WebCore.xcodeproj/project.pbxproj:
* platform/encryptedmedia/CDMInstance.h:
(WebCore::CDMInstance::setHDCPStatus):
(WebCore::CDMInstance::setClient): Deleted.
(WebCore::CDMInstance::clearClient): Deleted.
* platform/encryptedmedia/CDMInstanceSession.h: Copied from Source/WebCore/platform/encryptedmedia/CDMInstance.h.
(WebCore::CDMInstanceSession::setClient):
(WebCore::CDMInstanceSession::clearClient):
* platform/encryptedmedia/clearkey/CDMClearKey.cpp:
(WebCore::parseLicenseFormat):
(WebCore::CDMInstanceClearKey::keySystem const):
(WebCore::CDMInstanceClearKey::createSession):
(WebCore::CDMInstanceSessionClearKey::requestLicense):
(WebCore::CDMInstanceSessionClearKey::keys const):
(WebCore::CDMInstanceSessionClearKey::updateLicense):
(WebCore::CDMInstanceSessionClearKey::loadSession):
(WebCore::CDMInstanceSessionClearKey::closeSession):
(WebCore::CDMInstanceSessionClearKey::removeSessionData):
(WebCore::CDMInstanceSessionClearKey::storeRecordOfKeyUsage):
(WebCore::CDMInstanceClearKey::requestLicense): Deleted.
(WebCore::CDMInstanceClearKey::keys const): Deleted.
(WebCore::CDMInstanceClearKey::updateLicense): Deleted.
(WebCore::CDMInstanceClearKey::loadSession): Deleted.
(WebCore::CDMInstanceClearKey::closeSession): Deleted.
(WebCore::CDMInstanceClearKey::removeSessionData): Deleted.
(WebCore::CDMInstanceClearKey::storeRecordOfKeyUsage): Deleted.
* platform/encryptedmedia/clearkey/CDMClearKey.h:
* platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
* platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::createSession):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::processContentKeyRequestForSession):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::processNextContentKeyRequest):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::keySystem const):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRenewingRequest):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvidePersistableRequest):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::didFailToProvideRequest):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::shouldRetryRequestForReason):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::sessionIdentifierChanged):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyIDs):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestLicense):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateLicense):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::loadSession):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::closeSession):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::removeSessionData):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::storeRecordOfKeyUsage):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::setClient):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::clearClient):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRequest):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRenewingRequest):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvidePersistableRequest):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didFailToProvideRequest):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::shouldRetryRequestForReason):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::sessionIdentifierChanged):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::isLicenseTypeSupported const):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::isLicenseTypeSupported const): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::keyIDs): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestLicense): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::updateLicense): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::loadSession): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::closeSession): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::removeSessionData): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::storeRecordOfKeyUsage): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::setClient): Deleted.
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::clearClient): Deleted.
* testing/MockCDMFactory.cpp:
(WebCore::MockCDMInstance::keySystem const):
(WebCore::MockCDMInstance::createSession):
(WebCore::MockCDMInstanceSession::MockCDMInstanceSession):
(WebCore::MockCDMInstanceSession::requestLicense):
(WebCore::MockCDMInstanceSession::updateLicense):
(WebCore::MockCDMInstanceSession::loadSession):
(WebCore::MockCDMInstanceSession::closeSession):
(WebCore::MockCDMInstanceSession::removeSessionData):
(WebCore::MockCDMInstanceSession::storeRecordOfKeyUsage):
(WebCore::MockCDMInstance::requestLicense): Deleted.
(WebCore::MockCDMInstance::updateLicense): Deleted.
(WebCore::MockCDMInstance::loadSession): Deleted.
(WebCore::MockCDMInstance::closeSession): Deleted.
(WebCore::MockCDMInstance::removeSessionData): Deleted.
(WebCore::MockCDMInstance::storeRecordOfKeyUsage): Deleted.
* testing/MockCDMFactory.h:
(WebCore::MockCDMInstance::factory const):
(WebCore::MockCDMInstance::distinctiveIdentifiersAllowed const):
(WebCore::MockCDMInstance::persistentStateAllowed const):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@236317 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
Source/WebCore/ChangeLog
Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp
Source/WebCore/Modules/encryptedmedia/MediaKeySession.h
Source/WebCore/Modules/encryptedmedia/MediaKeys.cpp
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/encryptedmedia/CDMInstance.h
Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h [new file with mode: 0644]
Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.cpp
Source/WebCore/platform/encryptedmedia/clearkey/CDMClearKey.h
Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h
Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm
Source/WebCore/testing/MockCDMFactory.cpp
Source/WebCore/testing/MockCDMFactory.h

index 40168b0..7d7e73e 100644 (file)
@@ -1,3 +1,121 @@
+2018-09-21  Jer Noble  <jer.noble@apple.com>
+
+        [EME] Introduce the concept of CDMInstanceSession.
+        https://bugs.webkit.org/show_bug.cgi?id=189725
+
+        Reviewed by Eric Carlson.
+
+        Currently, the same CDMInstance owned by a MediaKeys object is passed to every MediaKeySession created by that
+        MediaKeys, and since the CDMInstance has only a single CDMInstanceClient, subsequent MediaKeySessions prevent
+        previous ones from getting updates.
+
+        Add a new virtual interface, CDMInstanceSession, to be passed to MediaKeySession upon creation. Refactor
+        CDMInstanceClearKey and CDMInstanceFairPlayStreamingAVFObjC to adopt this new interface.
+
+        Drive-by fixes: Made a number of virtual overrides in final classes final themselves.
+
+        * Modules/encryptedmedia/MediaKeySession.cpp:
+        (WebCore::MediaKeySession::create):
+        (WebCore::MediaKeySession::MediaKeySession):
+        (WebCore::MediaKeySession::generateRequest):
+        (WebCore::MediaKeySession::load):
+        (WebCore::MediaKeySession::update):
+        (WebCore::MediaKeySession::remove):
+        (WebCore::MediaKeySession::updateKeyStatuses):
+        * Modules/encryptedmedia/MediaKeySession.h:
+        * Modules/encryptedmedia/MediaKeys.cpp:
+        (WebCore::MediaKeys::createSession):
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/encryptedmedia/CDMInstance.h:
+        (WebCore::CDMInstance::setHDCPStatus):
+        (WebCore::CDMInstance::setClient): Deleted.
+        (WebCore::CDMInstance::clearClient): Deleted.
+        * platform/encryptedmedia/CDMInstanceSession.h: Copied from Source/WebCore/platform/encryptedmedia/CDMInstance.h.
+        (WebCore::CDMInstanceSession::setClient):
+        (WebCore::CDMInstanceSession::clearClient):
+        * platform/encryptedmedia/clearkey/CDMClearKey.cpp:
+        (WebCore::parseLicenseFormat):
+        (WebCore::CDMInstanceClearKey::keySystem const):
+        (WebCore::CDMInstanceClearKey::createSession):
+        (WebCore::CDMInstanceSessionClearKey::requestLicense):
+        (WebCore::CDMInstanceSessionClearKey::keys const):
+        (WebCore::CDMInstanceSessionClearKey::updateLicense):
+        (WebCore::CDMInstanceSessionClearKey::loadSession):
+        (WebCore::CDMInstanceSessionClearKey::closeSession):
+        (WebCore::CDMInstanceSessionClearKey::removeSessionData):
+        (WebCore::CDMInstanceSessionClearKey::storeRecordOfKeyUsage):
+        (WebCore::CDMInstanceClearKey::requestLicense): Deleted.
+        (WebCore::CDMInstanceClearKey::keys const): Deleted.
+        (WebCore::CDMInstanceClearKey::updateLicense): Deleted.
+        (WebCore::CDMInstanceClearKey::loadSession): Deleted.
+        (WebCore::CDMInstanceClearKey::closeSession): Deleted.
+        (WebCore::CDMInstanceClearKey::removeSessionData): Deleted.
+        (WebCore::CDMInstanceClearKey::storeRecordOfKeyUsage): Deleted.
+        * platform/encryptedmedia/clearkey/CDMClearKey.h:
+        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
+        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::createSession):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::processContentKeyRequestForSession):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::processNextContentKeyRequest):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::keySystem const):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvideRenewingRequest):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::didProvidePersistableRequest):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::didFailToProvideRequest):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::shouldRetryRequestForReason):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::sessionIdentifierChanged):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyIDs):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestLicense):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateLicense):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::loadSession):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::closeSession):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::removeSessionData):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::storeRecordOfKeyUsage):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::setClient):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::clearClient):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRequest):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRenewingRequest):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvidePersistableRequest):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didFailToProvideRequest):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::shouldRetryRequestForReason):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::sessionIdentifierChanged):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::isLicenseTypeSupported const):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::isLicenseTypeSupported const): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::keyIDs): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::requestLicense): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::updateLicense): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::loadSession): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::closeSession): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::removeSessionData): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::storeRecordOfKeyUsage): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::setClient): Deleted.
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::clearClient): Deleted.
+        * testing/MockCDMFactory.cpp:
+        (WebCore::MockCDMInstance::keySystem const):
+        (WebCore::MockCDMInstance::createSession):
+        (WebCore::MockCDMInstanceSession::MockCDMInstanceSession):
+        (WebCore::MockCDMInstanceSession::requestLicense):
+        (WebCore::MockCDMInstanceSession::updateLicense):
+        (WebCore::MockCDMInstanceSession::loadSession):
+        (WebCore::MockCDMInstanceSession::closeSession):
+        (WebCore::MockCDMInstanceSession::removeSessionData):
+        (WebCore::MockCDMInstanceSession::storeRecordOfKeyUsage):
+        (WebCore::MockCDMInstance::requestLicense): Deleted.
+        (WebCore::MockCDMInstance::updateLicense): Deleted.
+        (WebCore::MockCDMInstance::loadSession): Deleted.
+        (WebCore::MockCDMInstance::closeSession): Deleted.
+        (WebCore::MockCDMInstance::removeSessionData): Deleted.
+        (WebCore::MockCDMInstance::storeRecordOfKeyUsage): Deleted.
+        * testing/MockCDMFactory.h:
+        (WebCore::MockCDMInstance::factory const):
+        (WebCore::MockCDMInstance::distinctiveIdentifiersAllowed const):
+        (WebCore::MockCDMInstance::persistentStateAllowed const):
+
 2018-09-21  Alicia Boya GarcĂ­a  <aboya@igalia.com>
 
         [MSE] Fix comparsion with uninitialized greatestDecodeDuration
index eb72ce0..da0f095 100644 (file)
 
 namespace WebCore {
 
-Ref<MediaKeySession> MediaKeySession::create(ScriptExecutionContext& context, WeakPtr<MediaKeys>&& keys, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref<CDM>&& implementation, Ref<CDMInstance>&& instance)
+Ref<MediaKeySession> MediaKeySession::create(ScriptExecutionContext& context, WeakPtr<MediaKeys>&& keys, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref<CDM>&& implementation, Ref<CDMInstanceSession>&& instanceSession)
 {
-    auto session = adoptRef(*new MediaKeySession(context, WTFMove(keys), sessionType, useDistinctiveIdentifier, WTFMove(implementation), WTFMove(instance)));
+    auto session = adoptRef(*new MediaKeySession(context, WTFMove(keys), sessionType, useDistinctiveIdentifier, WTFMove(implementation), WTFMove(instanceSession)));
     session->suspendIfNeeded();
     return session;
 }
 
-MediaKeySession::MediaKeySession(ScriptExecutionContext& context, WeakPtr<MediaKeys>&& keys, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref<CDM>&& implementation, Ref<CDMInstance>&& instance)
+MediaKeySession::MediaKeySession(ScriptExecutionContext& context, WeakPtr<MediaKeys>&& keys, MediaKeySessionType sessionType, bool useDistinctiveIdentifier, Ref<CDM>&& implementation, Ref<CDMInstanceSession>&& instanceSession)
     : ActiveDOMObject(&context)
     , m_keys(WTFMove(keys))
     , m_expiration(std::numeric_limits<double>::quiet_NaN())
@@ -63,10 +63,10 @@ MediaKeySession::MediaKeySession(ScriptExecutionContext& context, WeakPtr<MediaK
     , m_useDistinctiveIdentifier(useDistinctiveIdentifier)
     , m_sessionType(sessionType)
     , m_implementation(WTFMove(implementation))
-    , m_instance(WTFMove(instance))
+    , m_instanceSession(WTFMove(instanceSession))
     , m_eventQueue(*this)
 {
-    // https://w3c.github.io/encrypted-media/#dom-mediakeys-setservercertificate
+    // https://w3c.github.io/encrypted-media/#dom-mediakeys-createsession
     // W3C Editor's Draft 09 November 2016
     // createSession(), ctd.
 
@@ -88,13 +88,13 @@ MediaKeySession::MediaKeySession(ScriptExecutionContext& context, WeakPtr<MediaK
     UNUSED_PARAM(m_closed);
     UNUSED_PARAM(m_uninitialized);
 
-    m_instance->setClient(*this);
+    m_instanceSession->setClient(m_cdmInstanceClientWeakPtrFactory.createWeakPtr(*this));
 }
 
 MediaKeySession::~MediaKeySession()
 {
     m_keyStatuses->detachSession();
-    m_instance->clearClient();
+    m_instanceSession->clearClient();
 }
 
 const String& MediaKeySession::sessionId() const
@@ -194,7 +194,7 @@ void MediaKeySession::generateRequest(const AtomicString& initDataType, const Bu
             m_latestDecryptTime = 0;
         }
 
-        m_instance->requestLicense(m_sessionType, initDataType, WTFMove(initData), [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, CDMInstance::SuccessValue succeeded) mutable {
+        m_instanceSession->requestLicense(m_sessionType, initDataType, WTFMove(initData), [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, CDMInstanceSession::SuccessValue succeeded) mutable {
             if (!weakThis)
                 return;
 
@@ -217,7 +217,7 @@ void MediaKeySession::generateRequest(const AtomicString& initDataType, const Bu
             // 10.10. Queue a task to run the following steps:
             m_taskQueue.enqueueTask([this, promise = WTFMove(promise), message = WTFMove(message), messageType, sessionId, succeeded] () mutable {
                 // 10.10.1. If any of the preceding steps failed, reject promise with a new DOMException whose name is the appropriate error name.
-                if (succeeded == CDMInstance::SuccessValue::Failed) {
+                if (succeeded == CDMInstanceSession::SuccessValue::Failed) {
                     promise->reject(NotSupportedError);
                     return;
                 }
@@ -287,7 +287,7 @@ void MediaKeySession::load(const String& sessionId, Ref<DeferredPromise>&& promi
         // 8.6. Let message type be null.
         // 8.7. Let cdm be the CDM instance represented by this object's cdm instance value.
         // 8.8. Use the cdm to execute the following steps:
-        m_instance->loadSession(m_sessionType, *sanitizedSessionId, origin, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise), sanitizedSessionId = *sanitizedSessionId] (std::optional<CDMInstance::KeyStatusVector>&& knownKeys, std::optional<double>&& expiration, std::optional<CDMInstance::Message>&& message, CDMInstance::SuccessValue succeeded, CDMInstance::SessionLoadFailure failure) mutable {
+        m_instanceSession->loadSession(m_sessionType, *sanitizedSessionId, origin, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise), sanitizedSessionId = *sanitizedSessionId] (std::optional<CDMInstanceSession::KeyStatusVector>&& knownKeys, std::optional<double>&& expiration, std::optional<CDMInstanceSession::Message>&& message, CDMInstanceSession::SuccessValue succeeded, CDMInstanceSession::SessionLoadFailure failure) mutable {
             // 8.8.1. If there is no data stored for the sanitized session ID in the origin, resolve promise with false and abort these steps.
             // 8.8.2. If the stored session's session type is not the same as the current MediaKeySession session type, reject promise with a newly created TypeError.
             // 8.8.3. Let session data be the data stored for the sanitized session ID in the origin. This must not include data from other origin(s) or that is not associated with an origin.
@@ -299,19 +299,19 @@ void MediaKeySession::load(const String& sessionId, Ref<DeferredPromise>&& promi
             //   8.8.7.2. Let message type be the appropriate MediaKeyMessageType for the message.
             // NOTE: Steps 8.8.1. through 8.8.7. should be implemented in CDMInstance.
 
-            if (succeeded == CDMInstance::SuccessValue::Failed) {
+            if (succeeded == CDMInstanceSession::SuccessValue::Failed) {
                 switch (failure) {
-                case CDMInstance::SessionLoadFailure::NoSessionData:
+                case CDMInstanceSession::SessionLoadFailure::NoSessionData:
                     promise->resolve<IDLBoolean>(false);
                     return;
-                case CDMInstance::SessionLoadFailure::MismatchedSessionType:
+                case CDMInstanceSession::SessionLoadFailure::MismatchedSessionType:
                     promise->reject(TypeError);
                     return;
-                case CDMInstance::SessionLoadFailure::QuotaExceeded:
+                case CDMInstanceSession::SessionLoadFailure::QuotaExceeded:
                     promise->reject(QuotaExceededError);
                     return;
-                case CDMInstance::SessionLoadFailure::None:
-                case CDMInstance::SessionLoadFailure::Other:
+                case CDMInstanceSession::SessionLoadFailure::None:
+                case CDMInstanceSession::SessionLoadFailure::Other:
                     // In any other case, the session load failure will cause a rejection in the following task.
                     break;
                 }
@@ -320,7 +320,7 @@ void MediaKeySession::load(const String& sessionId, Ref<DeferredPromise>&& promi
             // 8.9. Queue a task to run the following steps:
             m_taskQueue.enqueueTask([this, knownKeys = WTFMove(knownKeys), expiration = WTFMove(expiration), message = WTFMove(message), sanitizedSessionId, succeeded, promise = WTFMove(promise)] () mutable {
                 // 8.9.1. If any of the preceding steps failed, reject promise with a the appropriate error name.
-                if (succeeded == CDMInstance::SuccessValue::Failed) {
+                if (succeeded == CDMInstanceSession::SuccessValue::Failed) {
                     promise->reject(NotSupportedError);
                     return;
                 }
@@ -388,7 +388,7 @@ void MediaKeySession::update(const BufferSource& response, Ref<DeferredPromise>&
         // 6.5. Let session closed be false.
         // 6.6. Let cdm be the CDM instance represented by this object's cdm instance value.
         // 6.7. Use the cdm to execute the following steps:
-        m_instance->updateLicense(m_sessionId, m_sessionType, *sanitizedResponse, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (bool sessionWasClosed, std::optional<CDMInstance::KeyStatusVector>&& changedKeys, std::optional<double>&& changedExpiration, std::optional<CDMInstance::Message>&& message, CDMInstance::SuccessValue succeeded) mutable {
+        m_instanceSession->updateLicense(m_sessionId, m_sessionType, *sanitizedResponse, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (bool sessionWasClosed, std::optional<CDMInstanceSession::KeyStatusVector>&& changedKeys, std::optional<double>&& changedExpiration, std::optional<CDMInstanceSession::Message>&& message, CDMInstanceSession::SuccessValue succeeded) mutable {
             if (!weakThis)
                 return;
 
@@ -414,7 +414,7 @@ void MediaKeySession::update(const BufferSource& response, Ref<DeferredPromise>&
             //     Process sanitized response, not storing any session data.
             // NOTE: Steps 6.7.1. and 6.7.2. should be implemented in CDMInstance.
 
-            if (succeeded == CDMInstance::SuccessValue::Failed) {
+            if (succeeded == CDMInstanceSession::SuccessValue::Failed) {
                 promise->reject(TypeError);
                 return;
             }
@@ -450,16 +450,16 @@ void MediaKeySession::update(const BufferSource& response, Ref<DeferredPromise>&
                     if (message) {
                         MediaKeyMessageType messageType;
                         switch (message->first) {
-                        case CDMInstance::MessageType::LicenseRequest:
+                        case CDMInstanceSession::MessageType::LicenseRequest:
                             messageType = MediaKeyMessageType::LicenseRequest;
                             break;
-                        case CDMInstance::MessageType::LicenseRenewal:
+                        case CDMInstanceSession::MessageType::LicenseRenewal:
                             messageType = MediaKeyMessageType::LicenseRenewal;
                             break;
-                        case CDMInstance::MessageType::LicenseRelease:
+                        case CDMInstanceSession::MessageType::LicenseRelease:
                             messageType = MediaKeyMessageType::LicenseRelease;
                             break;
-                        case CDMInstance::MessageType::IndividualizationRequest:
+                        case CDMInstanceSession::MessageType::IndividualizationRequest:
                             messageType = MediaKeyMessageType::IndividualizationRequest;
                             break;
                         }
@@ -500,7 +500,7 @@ void MediaKeySession::close(Ref<DeferredPromise>&& promise)
     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 = makeWeakPtr(*this), promise = WTFMove(promise)] () mutable {
+        m_instanceSession->closeSession(m_sessionId, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] () mutable {
             if (!weakThis)
                 return;
 
@@ -538,7 +538,7 @@ void MediaKeySession::remove(Ref<DeferredPromise>&& promise)
         // 4.3. Let message type be null.
 
         // 4.4. Use the cdm to execute the following steps:
-        m_instance->removeSessionData(m_sessionId, m_sessionType, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (CDMInstance::KeyStatusVector&& keys, std::optional<Ref<SharedBuffer>>&& message, CDMInstance::SuccessValue succeeded) mutable {
+        m_instanceSession->removeSessionData(m_sessionId, m_sessionType, [this, weakThis = makeWeakPtr(*this), promise = WTFMove(promise)] (CDMInstanceSession::KeyStatusVector&& keys, std::optional<Ref<SharedBuffer>>&& message, CDMInstanceSession::SuccessValue succeeded) mutable {
             if (!weakThis)
                 return;
 
@@ -565,7 +565,7 @@ void MediaKeySession::remove(Ref<DeferredPromise>&& promise)
                 updateExpiration(std::numeric_limits<double>::quiet_NaN());
 
                 // 4.5.3. If any of the preceding steps failed, reject promise with a new DOMException whose name is the appropriate error name.
-                if (succeeded == CDMInstance::SuccessValue::Failed) {
+                if (succeeded == CDMInstanceSession::SuccessValue::Failed) {
                     promise->reject(NotSupportedError);
                     return;
                 }
@@ -599,7 +599,7 @@ void MediaKeySession::enqueueMessage(MediaKeyMessageType messageType, const Shar
     m_eventQueue.enqueueEvent(WTFMove(messageEvent));
 }
 
-void MediaKeySession::updateKeyStatuses(CDMInstanceClient::KeyStatusVector&& inputStatuses)
+void MediaKeySession::updateKeyStatuses(CDMInstanceSession::KeyStatusVector&& inputStatuses)
 {
     // https://w3c.github.io/encrypted-media/#update-key-statuses
     // W3C Editor's Draft 09 November 2016
@@ -613,21 +613,21 @@ void MediaKeySession::updateKeyStatuses(CDMInstanceClient::KeyStatusVector&& inp
     //     4.2.1. Let pair be the pair.
     //     4.2.2. Insert an entry for pair's key ID into statuses with the value of pair's MediaKeyStatus value.
 
-    static auto toMediaKeyStatus = [] (CDMInstance::KeyStatus status) -> MediaKeyStatus {
+    static auto toMediaKeyStatus = [] (CDMInstanceSession::KeyStatus status) -> MediaKeyStatus {
         switch (status) {
-        case CDMInstance::KeyStatus::Usable:
+        case CDMInstanceSession::KeyStatus::Usable:
             return MediaKeyStatus::Usable;
-        case CDMInstance::KeyStatus::Expired:
+        case CDMInstanceSession::KeyStatus::Expired:
             return MediaKeyStatus::Expired;
-        case CDMInstance::KeyStatus::Released:
+        case CDMInstanceSession::KeyStatus::Released:
             return MediaKeyStatus::Released;
-        case CDMInstance::KeyStatus::OutputRestricted:
+        case CDMInstanceSession::KeyStatus::OutputRestricted:
             return MediaKeyStatus::OutputRestricted;
-        case CDMInstance::KeyStatus::OutputDownscaled:
+        case CDMInstanceSession::KeyStatus::OutputDownscaled:
             return MediaKeyStatus::OutputDownscaled;
-        case CDMInstance::KeyStatus::StatusPending:
+        case CDMInstanceSession::KeyStatus::StatusPending:
             return MediaKeyStatus::StatusPending;
-        case CDMInstance::KeyStatus::InternalError:
+        case CDMInstanceSession::KeyStatus::InternalError:
             return MediaKeyStatus::InternalError;
         };
 
@@ -666,7 +666,7 @@ void MediaKeySession::sessionClosed()
     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);
+        m_instanceSession->storeRecordOfKeyUsage(m_sessionId);
     }
 
     // 3. Run the Update Key Statuses algorithm on the session, providing an empty sequence.
index 0d1900e..80eb96a 100644 (file)
@@ -31,7 +31,7 @@
 #if ENABLE(ENCRYPTED_MEDIA)
 
 #include "ActiveDOMObject.h"
-#include "CDMInstance.h"
+#include "CDMInstanceSession.h"
 #include "DOMPromiseProxy.h"
 #include "EventTarget.h"
 #include "GenericEventQueue.h"
@@ -52,9 +52,9 @@ class MediaKeyStatusMap;
 class MediaKeys;
 class SharedBuffer;
 
-class MediaKeySession final : public RefCounted<MediaKeySession>, public EventTargetWithInlineData, public ActiveDOMObject, public CanMakeWeakPtr<MediaKeySession>, public CDMInstanceClient {
+class MediaKeySession final : public RefCounted<MediaKeySession>, public EventTargetWithInlineData, public ActiveDOMObject, public CanMakeWeakPtr<MediaKeySession>, public CDMInstanceSessionClient {
 public:
-    static Ref<MediaKeySession> create(ScriptExecutionContext&, WeakPtr<MediaKeys>&&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstance>&&);
+    static Ref<MediaKeySession> create(ScriptExecutionContext&, WeakPtr<MediaKeys>&&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstanceSession>&&);
     virtual ~MediaKeySession();
 
     using RefCounted<MediaKeySession>::ref;
@@ -78,14 +78,14 @@ public:
     const Vector<std::pair<Ref<SharedBuffer>, MediaKeyStatus>>& statuses() const { return m_statuses; }
 
 private:
-    MediaKeySession(ScriptExecutionContext&, WeakPtr<MediaKeys>&&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstance>&&);
+    MediaKeySession(ScriptExecutionContext&, WeakPtr<MediaKeys>&&, MediaKeySessionType, bool useDistinctiveIdentifier, Ref<CDM>&&, Ref<CDMInstanceSession>&&);
     void enqueueMessage(MediaKeyMessageType, const SharedBuffer&);
     void updateExpiration(double);
     void sessionClosed();
     String mediaKeysStorageDirectory() const;
 
-    // CDMInstanceClient
-    void updateKeyStatuses(CDMInstanceClient::KeyStatusVector&&) override;
+    // CDMInstanceSessionClient
+    void updateKeyStatuses(CDMInstanceSessionClient::KeyStatusVector&&) override;
 
     // EventTarget
     EventTargetInterface eventTargetInterface() const override { return MediaKeySessionEventTargetInterfaceType; }
@@ -110,13 +110,14 @@ private:
     bool m_useDistinctiveIdentifier;
     MediaKeySessionType m_sessionType;
     Ref<CDM> m_implementation;
-    Ref<CDMInstance> m_instance;
+    Ref<CDMInstanceSession> m_instanceSession;
     GenericEventQueue m_eventQueue;
     GenericTaskQueue<Timer> m_taskQueue;
     Vector<Ref<SharedBuffer>> m_recordOfKeyUsage;
     double m_firstDecryptTime { 0 };
     double m_latestDecryptTime { 0 };
     Vector<std::pair<Ref<SharedBuffer>, MediaKeyStatus>> m_statuses;
+    WeakPtrFactory<CDMInstanceSessionClient> m_cdmInstanceClientWeakPtrFactory;
 };
 
 } // namespace WebCore
index 39fbb80..cec3b86 100644 (file)
@@ -64,10 +64,14 @@ ExceptionOr<Ref<MediaKeySession>> MediaKeys::createSession(ScriptExecutionContex
     if (!m_implementation->supportsSessions())
         return Exception(InvalidStateError);
 
+    auto instanceSession = m_instance->createSession();
+    if (!instanceSession)
+        return Exception(InvalidStateError);
+
     // 3. Let session be a new MediaKeySession object, and initialize it as follows:
     // NOTE: Continued in MediaKeySession.
     // 4. Return session.
-    auto session = MediaKeySession::create(context, makeWeakPtr(*this), sessionType, m_useDistinctiveIdentifier, m_implementation.copyRef(), m_instance.copyRef());
+    auto session = MediaKeySession::create(context, makeWeakPtr(*this), sessionType, m_useDistinctiveIdentifier, m_implementation.copyRef(), instanceSession.releaseNonNull());
     m_sessions.append(session.copyRef());
     return WTFMove(session);
 }
index 1563d22..1abc88f 100644 (file)
                CD94A5D61F71CB6D00F525C5 /* CDMMessageType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDMMessageType.h; sourceTree = "<group>"; };
                CD94A5DA1F71CBB000F525C5 /* CDMClearKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDMClearKey.h; sourceTree = "<group>"; };
                CD94A5DB1F71CBB000F525C5 /* CDMClearKey.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CDMClearKey.cpp; sourceTree = "<group>"; };
+               CD9D375A215163E40049657B /* CDMInstanceSession.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CDMInstanceSession.h; sourceTree = "<group>"; };
                CD9D82731C7AE535006FF066 /* TextureCacheCV.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TextureCacheCV.mm; sourceTree = "<group>"; };
                CD9D82741C7AE535006FF066 /* TextureCacheCV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextureCacheCV.h; sourceTree = "<group>"; };
                CD9D82771C7B8EE1006FF066 /* VideoTextureCopierCV.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = VideoTextureCopierCV.cpp; sourceTree = "<group>"; };
                                CD94A5D11F71CB6B00F525C5 /* CDMFactory.cpp */,
                                CD94A5D21F71CB6B00F525C5 /* CDMFactory.h */,
                                CD94A5CE1F71CB6A00F525C5 /* CDMInstance.h */,
+                               CD9D375A215163E40049657B /* CDMInstanceSession.h */,
                                CD94A5D41F71CB6C00F525C5 /* CDMKeyStatus.h */,
                                CD94A5CD1F71CB6900F525C5 /* CDMKeySystemConfiguration.h */,
                                CD94A5D31F71CB6C00F525C5 /* CDMMediaCapability.h */,
index e665ccc..04e8b35 100644 (file)
@@ -41,17 +41,9 @@ namespace WebCore {
 
 class SharedBuffer;
 
+class CDMInstanceSession;
 struct CDMKeySystemConfiguration;
 
-class CDMInstanceClient {
-public:
-    virtual ~CDMInstanceClient() = default;
-
-    using KeyStatus = CDMKeyStatus;
-    using KeyStatusVector = Vector<std::pair<Ref<SharedBuffer>, KeyStatus>>;
-    virtual void updateKeyStatuses(KeyStatusVector&&) = 0;
-};
-
 class CDMInstance : public RefCounted<CDMInstance> {
 public:
     virtual ~CDMInstance() = default;
@@ -61,7 +53,6 @@ public:
         ClearKey,
         FairPlayStreaming,
     };
-
     virtual ImplementationType implementationType() const = 0;
 
     enum SuccessValue {
@@ -69,15 +60,13 @@ public:
         Succeeded,
     };
 
-    using KeyStatus = CDMKeyStatus;
-    using LicenseType = CDMSessionType;
-    using MessageType = CDMMessageType;
-
     virtual SuccessValue initializeWithConfiguration(const CDMKeySystemConfiguration&) = 0;
     virtual SuccessValue setDistinctiveIdentifiersAllowed(bool) = 0;
     virtual SuccessValue setPersistentStateAllowed(bool) = 0;
     virtual SuccessValue setServerCertificate(Ref<SharedBuffer>&&) = 0;
     virtual SuccessValue setStorageDirectory(const String&) = 0;
+    virtual const String& keySystem() const = 0;
+    virtual RefPtr<CDMInstanceSession> createSession() = 0;
 
     enum class HDCPStatus {
         Unknown,
@@ -86,38 +75,6 @@ public:
         OutputDownscaled,
     };
     virtual SuccessValue setHDCPStatus(HDCPStatus) { return Failed; }
-
-    virtual void setClient(CDMInstanceClient&) { }
-    virtual void clearClient() { }
-
-    using LicenseCallback = Function<void(Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, SuccessValue succeeded)>;
-    virtual void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) = 0;
-
-    using KeyStatusVector = CDMInstanceClient::KeyStatusVector;
-    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(const String& sessionId, LicenseType, const SharedBuffer& response, LicenseUpdateCallback) = 0;
-
-    enum class SessionLoadFailure {
-        None,
-        NoSessionData,
-        MismatchedSessionType,
-        QuotaExceeded,
-        Other,
-    };
-
-    using LoadSessionCallback = Function<void(std::optional<KeyStatusVector>&&, std::optional<double>&&, std::optional<Message>&&, SuccessValue, SessionLoadFailure)>;
-    virtual void loadSession(LicenseType, const String& sessionId, const String& origin, LoadSessionCallback) = 0;
-
-    using CloseSessionCallback = Function<void()>;
-    virtual void closeSession(const String& sessionId, CloseSessionCallback) = 0;
-
-    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;
-
-    virtual const String& keySystem() const = 0;
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h b/Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h
new file mode 100644 (file)
index 0000000..cf3b2d4
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#if ENABLE(ENCRYPTED_MEDIA)
+
+#include "CDMKeyStatus.h"
+#include "CDMMessageType.h"
+#include "CDMSessionType.h"
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class SharedBuffer;
+
+class CDMInstanceSessionClient {
+public:
+    virtual ~CDMInstanceSessionClient() = default;
+
+    using KeyStatus = CDMKeyStatus;
+    using KeyStatusVector = Vector<std::pair<Ref<SharedBuffer>, KeyStatus>>;
+    virtual void updateKeyStatuses(KeyStatusVector&&) = 0;
+};
+
+class CDMInstanceSession : public RefCounted<CDMInstanceSession> {
+public:
+    virtual ~CDMInstanceSession() = default;
+
+    using KeyStatus = CDMKeyStatus;
+    using LicenseType = CDMSessionType;
+    using MessageType = CDMMessageType;
+
+    virtual void setClient(WeakPtr<CDMInstanceSessionClient>&&) { }
+    virtual void clearClient() { }
+
+    enum SuccessValue {
+        Failed,
+        Succeeded,
+    };
+
+    using LicenseCallback = Function<void(Ref<SharedBuffer>&& message, const String& sessionId, bool needsIndividualization, SuccessValue succeeded)>;
+    virtual void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&&) = 0;
+
+    using KeyStatusVector = CDMInstanceSessionClient::KeyStatusVector;
+    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(const String& sessionId, LicenseType, const SharedBuffer& response, LicenseUpdateCallback&&) = 0;
+
+    enum class SessionLoadFailure {
+        None,
+        NoSessionData,
+        MismatchedSessionType,
+        QuotaExceeded,
+        Other,
+    };
+
+    using LoadSessionCallback = Function<void(std::optional<KeyStatusVector>&&, std::optional<double>&&, std::optional<Message>&&, SuccessValue, SessionLoadFailure)>;
+    virtual void loadSession(LicenseType, const String& sessionId, const String& origin, LoadSessionCallback&&) = 0;
+
+    using CloseSessionCallback = Function<void()>;
+    virtual void closeSession(const String& sessionId, CloseSessionCallback&&) = 0;
+
+    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;
+};
+
+} // namespace WebCore
+
+#define SPECIALIZE_TYPE_TRAITS_CDM_INSTANCE(ToValueTypeName, ImplementationTypeName) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(ToValueTypeName) \
+static bool isType(const WebCore::CDMInstance& instance) { return instance.implementationType() == ImplementationTypeName; } \
+SPECIALIZE_TYPE_TRAITS_END()
+
+#endif
index efad6c1..5a7ff86 100644 (file)
@@ -40,7 +40,6 @@
 #include <wtf/NeverDestroyed.h>
 #include <wtf/text/Base64.h>
 
-
 namespace WebCore {
 
 // ClearKey CENC SystemID.
@@ -120,7 +119,7 @@ static std::optional<Vector<CDMInstanceClearKey::Key>> parseLicenseFormat(const
             if (!WTF::base64URLDecode(keyID, { keyIDData }) || !WTF::base64URLDecode(keyValue, { keyValueData }))
                 return false;
 
-            decodedKeys.append({ CDMInstanceClearKey::KeyStatus::Usable, SharedBuffer::create(WTFMove(keyIDData)), SharedBuffer::create(WTFMove(keyValueData)) });
+            decodedKeys.append({ CDMInstanceSession::KeyStatus::Usable, SharedBuffer::create(WTFMove(keyIDData)), SharedBuffer::create(WTFMove(keyValueData)) });
             return true;
         });
     if (!validFormat)
@@ -493,7 +492,34 @@ CDMInstance::SuccessValue CDMInstanceClearKey::setStorageDirectory(const String&
     return storageDirectory.isEmpty() ? Succeeded : Failed;
 }
 
-void CDMInstanceClearKey::requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+const String& CDMInstanceClearKey::keySystem() const
+{
+    static const NeverDestroyed<String> s_keySystem { MAKE_STATIC_STRING_IMPL("org.w3.clearkey") };
+
+    return s_keySystem;
+}
+
+RefPtr<CDMInstanceSession> CDMInstanceClearKey::createSession()
+{
+    return adoptRef(new CDMInstanceSessionClearKey());
+}
+
+const Vector<CDMInstanceClearKey::Key> CDMInstanceClearKey::keys() const
+{
+    // Return the keys of all sessions.
+    Vector<CDMInstanceClearKey::Key> allKeys { };
+    size_t initialCapacity = 0;
+    for (auto& key : ClearKeyState::singleton().keys().values())
+        initialCapacity += key.size();
+    allKeys.reserveInitialCapacity(initialCapacity);
+
+    for (auto& key : ClearKeyState::singleton().keys().values())
+        allKeys.appendVector(key);
+
+    return allKeys;
+}
+
+void CDMInstanceSessionClearKey::requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&& callback)
 {
     static uint32_t s_sessionIdValue = 0;
     ++s_sessionIdValue;
@@ -513,17 +539,7 @@ void CDMInstanceClearKey::requestLicense(LicenseType, const AtomicString& initDa
         });
 }
 
-const Vector<CDMInstanceClearKey::Key> CDMInstanceClearKey::keys() const
-{
-    // Return the keys of all sessions.
-    Vector<CDMInstanceClearKey::Key> allKeys { };
-    for (auto& key : ClearKeyState::singleton().keys().values())
-        allKeys.appendVector(key);
-
-    return allKeys;
-}
-
-void CDMInstanceClearKey::updateLicense(const String& sessionId, LicenseType, const SharedBuffer& response, LicenseUpdateCallback callback)
+void CDMInstanceSessionClearKey::updateLicense(const String& sessionId, LicenseType, const SharedBuffer& response, LicenseUpdateCallback&& callback)
 {
     // Use a helper functor that schedules the callback dispatch, avoiding
     // duplicated callOnMainThread() calls.
@@ -548,7 +564,7 @@ void CDMInstanceClearKey::updateLicense(const String& sessionId, LicenseType, co
     // Parse the response using 'license' formatting, if possible.
     if (auto decodedKeys = parseLicenseFormat(*root)) {
         // Retrieve the target Vector of Key objects for this session.
-        auto& keyVector = ClearKeyState::singleton().keys().ensure(sessionId, [] { return Vector<Key> { }; }).iterator->value;
+        auto& keyVector = ClearKeyState::singleton().keys().ensure(sessionId, [] { return Vector<CDMInstanceClearKey::Key> { }; }).iterator->value;
 
         // For each decoded key, find an existing item for the decoded key's ID. If none exist,
         // the key is decoded. Otherwise, the key is updated in case there's a mismatch between
@@ -556,7 +572,7 @@ void CDMInstanceClearKey::updateLicense(const String& sessionId, LicenseType, co
         bool keysChanged = false;
         for (auto& key : *decodedKeys) {
             auto it = std::find_if(keyVector.begin(), keyVector.end(),
-                [&key] (const Key& containedKey) {
+                [&key] (const CDMInstanceClearKey::Key& containedKey) {
                     return containedKey.keyIDData->size() == key.keyIDData->size()
                         && !std::memcmp(containedKey.keyIDData->data(), key.keyIDData->data(), containedKey.keyIDData->size());
                 });
@@ -624,7 +640,7 @@ void CDMInstanceClearKey::updateLicense(const String& sessionId, LicenseType, co
     dispatchCallback(false, std::nullopt, SuccessValue::Failed);
 }
 
-void CDMInstanceClearKey::loadSession(LicenseType, const String& sessionId, const String&, LoadSessionCallback callback)
+void CDMInstanceSessionClearKey::loadSession(LicenseType, const String& sessionId, const String&, LoadSessionCallback&& callback)
 {
     // Use a helper functor that schedules the callback dispatch, avoiding duplicated callOnMainThread() calls.
     auto dispatchCallback =
@@ -657,7 +673,7 @@ void CDMInstanceClearKey::loadSession(LicenseType, const String& sessionId, cons
     dispatchCallback(WTFMove(keyStatusVector), Succeeded, SessionLoadFailure::None);
 }
 
-void CDMInstanceClearKey::closeSession(const String&, CloseSessionCallback callback)
+void CDMInstanceSessionClearKey::closeSession(const String&, CloseSessionCallback&& callback)
 {
     callOnMainThread(
         [weakThis = makeWeakPtr(*this), callback = WTFMove(callback)] {
@@ -668,7 +684,7 @@ void CDMInstanceClearKey::closeSession(const String&, CloseSessionCallback callb
         });
 }
 
-void CDMInstanceClearKey::removeSessionData(const String& sessionId, LicenseType, RemoveSessionDataCallback callback)
+void CDMInstanceSessionClearKey::removeSessionData(const String& sessionId, LicenseType, RemoveSessionDataCallback&& callback)
 {
     // Use a helper functor that schedules the callback dispatch, avoiding duplicated callOnMainThread() calls.
     auto dispatchCallback =
@@ -726,17 +742,10 @@ void CDMInstanceClearKey::removeSessionData(const String& sessionId, LicenseType
     dispatchCallback(WTFMove(keyStatusVector), Ref<SharedBuffer>(*message), SuccessValue::Succeeded);
 }
 
-void CDMInstanceClearKey::storeRecordOfKeyUsage(const String&)
+void CDMInstanceSessionClearKey::storeRecordOfKeyUsage(const String&)
 {
 }
 
-const String& CDMInstanceClearKey::keySystem() const
-{
-    static const NeverDestroyed<String> s_keySystem = MAKE_STATIC_STRING_IMPL("org.w3.clearkey");
-
-    return s_keySystem;
-}
-
 } // namespace WebCore
 
 #endif // ENABLE(ENCRYPTED_MEDIA)
index cd4c880..f11ccdc 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "CDMFactory.h"
 #include "CDMInstance.h"
+#include "CDMInstanceSession.h"
 #include "CDMPrivate.h"
 #include "SharedBuffer.h"
 #include <wtf/WeakPtr.h>
@@ -44,8 +45,8 @@ public:
 
     virtual ~CDMFactoryClearKey();
 
-    std::unique_ptr<CDMPrivate> createCDM(const String&) override;
-    bool supportsKeySystem(const String&) override;
+    std::unique_ptr<CDMPrivate> createCDM(const String&) final;
+    bool supportsKeySystem(const String&) final;
 
 private:
     friend class NeverDestroyed<CDMFactoryClearKey>;
@@ -57,21 +58,21 @@ public:
     CDMPrivateClearKey();
     virtual ~CDMPrivateClearKey();
 
-    bool supportsInitDataType(const AtomicString&) const override;
-    bool supportsConfiguration(const CDMKeySystemConfiguration&) const override;
-    bool supportsConfigurationWithRestrictions(const CDMKeySystemConfiguration&, const CDMRestrictions&) const override;
-    bool supportsSessionTypeWithConfiguration(CDMSessionType&, const CDMKeySystemConfiguration&) const override;
-    bool supportsRobustness(const String&) const override;
-    CDMRequirement distinctiveIdentifiersRequirement(const CDMKeySystemConfiguration&, const CDMRestrictions&) const override;
-    CDMRequirement persistentStateRequirement(const CDMKeySystemConfiguration&, const CDMRestrictions&) const override;
-    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const CDMKeySystemConfiguration&) const override;
-    RefPtr<CDMInstance> createInstance() override;
-    void loadAndInitialize() override;
-    bool supportsServerCertificates() const override;
-    bool supportsSessions() const override;
-    bool supportsInitData(const AtomicString&, const SharedBuffer&) const override;
-    RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const override;
-    std::optional<String> sanitizeSessionId(const String&) const override;
+    bool supportsInitDataType(const AtomicString&) const final;
+    bool supportsConfiguration(const CDMKeySystemConfiguration&) const final;
+    bool supportsConfigurationWithRestrictions(const CDMKeySystemConfiguration&, const CDMRestrictions&) const final;
+    bool supportsSessionTypeWithConfiguration(CDMSessionType&, const CDMKeySystemConfiguration&) const final;
+    bool supportsRobustness(const String&) const final;
+    CDMRequirement distinctiveIdentifiersRequirement(const CDMKeySystemConfiguration&, const CDMRestrictions&) const final;
+    CDMRequirement persistentStateRequirement(const CDMKeySystemConfiguration&, const CDMRestrictions&) const final;
+    bool distinctiveIdentifiersAreUniquePerOriginAndClearable(const CDMKeySystemConfiguration&) const final;
+    RefPtr<CDMInstance> createInstance() final;
+    void loadAndInitialize() final;
+    bool supportsServerCertificates() const final;
+    bool supportsSessions() const final;
+    bool supportsInitData(const AtomicString&, const SharedBuffer&) const final;
+    RefPtr<SharedBuffer> sanitizeResponse(const SharedBuffer&) const final;
+    std::optional<String> sanitizeSessionId(const String&) const final;
 };
 
 class CDMInstanceClearKey final : public CDMInstance, public CanMakeWeakPtr<CDMInstanceClearKey> {
@@ -81,23 +82,16 @@ public:
 
     ImplementationType implementationType() const final { return ImplementationType::ClearKey; }
 
-    SuccessValue initializeWithConfiguration(const CDMKeySystemConfiguration&) override;
-    SuccessValue setDistinctiveIdentifiersAllowed(bool) override;
-    SuccessValue setPersistentStateAllowed(bool) override;
-    SuccessValue setServerCertificate(Ref<SharedBuffer>&&) override;
-    SuccessValue setStorageDirectory(const String&) override;
-
-    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) override;
-    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback) override;
-    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback) override;
-    void closeSession(const String&, CloseSessionCallback) override;
-    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) override;
-    void storeRecordOfKeyUsage(const String&) override;
-
+    SuccessValue initializeWithConfiguration(const CDMKeySystemConfiguration&) final;
+    SuccessValue setDistinctiveIdentifiersAllowed(bool) final;
+    SuccessValue setPersistentStateAllowed(bool) final;
+    SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
+    SuccessValue setStorageDirectory(const String&) final;
     const String& keySystem() const final;
+    RefPtr<CDMInstanceSession> createSession() final;
 
     struct Key {
-        KeyStatus status;
+        CDMInstanceSession::KeyStatus status;
         RefPtr<SharedBuffer> keyIDData;
         RefPtr<SharedBuffer> keyValueData;
     };
@@ -105,6 +99,16 @@ public:
     const Vector<Key> keys() const;
 };
 
+class CDMInstanceSessionClearKey final : public CDMInstanceSession, public CanMakeWeakPtr<CDMInstanceSessionClearKey> {
+public:
+    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&&) final;
+    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback&&) final;
+    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback&&) final;
+    void closeSession(const String&, CloseSessionCallback&&) final;
+    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback&&) final;
+    void storeRecordOfKeyUsage(const String&) final;
+};
+
 } // namespace WebCore
 
 SPECIALIZE_TYPE_TRAITS_CDM_INSTANCE(WebCore::CDMInstanceClearKey, WebCore::CDMInstance::ImplementationType::ClearKey);
index 83b9d50..377b430 100644 (file)
 #if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
 
 #include "CDMInstance.h"
+#include "CDMInstanceSession.h"
 #include <wtf/Function.h>
+#include <wtf/HashMap.h>
 #include <wtf/RetainPtr.h>
-#include <wtf/WeakPtr.h>
 #include <wtf/text/WTFString.h>
 
 OBJC_CLASS AVContentKeyRequest;
@@ -42,6 +43,8 @@ OBJC_CLASS WebCoreFPSContentKeySessionDelegate;
 
 namespace WebCore {
 
+class CDMInstanceSessionFairPlayStreamingAVFObjC;
+
 class CDMInstanceFairPlayStreamingAVFObjC final : public CDMInstance, public CanMakeWeakPtr<CDMInstanceFairPlayStreamingAVFObjC> {
 public:
     CDMInstanceFairPlayStreamingAVFObjC();
@@ -58,15 +61,9 @@ public:
     SuccessValue setPersistentStateAllowed(bool) final;
     SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
     SuccessValue setStorageDirectory(const String&) final;
+    RefPtr<CDMInstanceSession> createSession() final;
 
-    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final;
-    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback) final;
-    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback) final;
-    void closeSession(const String&, CloseSessionCallback) final;
-    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) final;
-    void storeRecordOfKeyUsage(const String&) final;
-    void setClient(CDMInstanceClient&) final;
-    void clearClient() final;
+    void processContentKeyRequestForSession(CDMInstanceSessionFairPlayStreamingAVFObjC&, RetainPtr<NSString>&& identifier, RetainPtr<NSData>&& initData);
 
     const String& keySystem() const final;
 
@@ -79,21 +76,62 @@ public:
     void sessionIdentifierChanged(NSData *);
     void outputObscuredDueToInsufficientExternalProtectionChanged(bool);
 
+    NSURL *storageDirectory() const { return m_storageDirectory.get(); }
     AVContentKeySession *contentKeySession() { return m_session.get(); }
+    bool persistentStateAllowed() const { return m_persistentStateAllowed; }
+    SharedBuffer* serverCertificate() const { return m_serverCertificate.get(); }
 
 private:
-    bool isLicenseTypeSupported(LicenseType) const;
+    void processNextContentKeyRequest();
 
-    Vector<Ref<SharedBuffer>> keyIDs();
+    struct ContentKeyRequest {
+        WeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC> sessionInstance;
+        RetainPtr<NSString> identifier;
+        RetainPtr<NSData> initData;
+    };
+    Vector<ContentKeyRequest> m_currentRequests;
+
+    HashMap<RetainPtr<AVContentKeyRequest>, WeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC>> m_requestMap;
 
     RefPtr<SharedBuffer> m_serverCertificate;
     bool m_persistentStateAllowed { true };
     RetainPtr<NSURL> m_storageDirectory;
     RetainPtr<AVContentKeySession> m_session;
-    RetainPtr<AVContentKeyRequest> m_request;
     RetainPtr<WebCoreFPSContentKeySessionDelegate> m_delegate;
+};
+
+class CDMInstanceSessionFairPlayStreamingAVFObjC final : public CDMInstanceSession, public CanMakeWeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC> {
+public:
+    CDMInstanceSessionFairPlayStreamingAVFObjC(Ref<CDMInstanceFairPlayStreamingAVFObjC>&&);
+
+    // CDMInstanceSession
+    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&&) final;
+    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback&&) final;
+    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback&&) final;
+    void closeSession(const String&, CloseSessionCallback&&) final;
+    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback&&) final;
+    void storeRecordOfKeyUsage(const String&) final;
+    void setClient(WeakPtr<CDMInstanceSessionClient>&&) final;
+    void clearClient() final;
+
+    void didProvideRequest(AVContentKeyRequest*);
+    void didProvideRenewingRequest(AVContentKeyRequest*);
+    void didProvidePersistableRequest(AVContentKeyRequest*);
+    void didFailToProvideRequest(AVContentKeyRequest*, NSError*);
+    void requestDidSucceed(AVContentKeyRequest*);
+    bool shouldRetryRequestForReason(AVContentKeyRequest*, NSString*);
+    void sessionIdentifierChanged(NSData*);
+    void outputObscuredDueToInsufficientExternalProtectionChanged(bool);
+
+    Vector<Ref<SharedBuffer>> keyIDs();
+
+private:
+    bool isLicenseTypeSupported(LicenseType) const;
+
+    Ref<CDMInstanceFairPlayStreamingAVFObjC> m_instance;
+    RetainPtr<AVContentKeyRequest> m_request;
     Vector<RetainPtr<NSData>> m_expiredSessions;
-    CDMInstanceClient* m_client;
+    WeakPtr<CDMInstanceSessionClient> m_client;
     String m_sessionId;
 
     LicenseCallback m_requestLicenseCallback;
@@ -101,6 +139,7 @@ private:
     CloseSessionCallback m_closeSessionCallback;
     RemoveSessionDataCallback m_removeSessionDataCallback;
 };
+
 }
 
 SPECIALIZE_TYPE_TRAITS_CDM_INSTANCE(WebCore::CDMInstanceFairPlayStreamingAVFObjC, WebCore::CDMInstance::ImplementationType::FairPlayStreaming)
index df3bc09..67f2f49 100644 (file)
@@ -221,19 +221,122 @@ CDMInstance::SuccessValue CDMInstanceFairPlayStreamingAVFObjC::setStorageDirecto
     return Succeeded;
 }
 
-bool CDMInstanceFairPlayStreamingAVFObjC::isLicenseTypeSupported(LicenseType licenseType) const
+RefPtr<CDMInstanceSession> CDMInstanceFairPlayStreamingAVFObjC::createSession()
 {
-    switch (licenseType) {
-    case CDMSessionType::PersistentLicense:
-        return m_persistentStateAllowed && supportsPersistentKeys();
-    case CDMSessionType::PersistentUsageRecord:
-        return m_persistentStateAllowed && supportsPersistableState();
-    case CDMSessionType::Temporary:
-        return true;
+    return adoptRef(new CDMInstanceSessionFairPlayStreamingAVFObjC(*this));
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::processContentKeyRequestForSession(CDMInstanceSessionFairPlayStreamingAVFObjC& session, RetainPtr<NSString>&& identifier, RetainPtr<NSData>&& initData)
+{
+    m_currentRequests.append({ makeWeakPtr(session), WTFMove(identifier), WTFMove(initData) });
+    if (m_currentRequests.size() == 1)
+        processNextContentKeyRequest();
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::processNextContentKeyRequest()
+{
+    if (m_currentRequests.isEmpty())
+        return;
+
+    auto& nextRequest = m_currentRequests.first();
+    [m_session processContentKeyRequestWithIdentifier:nextRequest.identifier.get() initializationData:nextRequest.initData.get() options:nil];
+}
+
+const String& CDMInstanceFairPlayStreamingAVFObjC::keySystem() const
+{
+    static NeverDestroyed<String> keySystem { "com.apple.fps"_s };
+    return keySystem;
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest *request)
+{
+    if (m_currentRequests.isEmpty())
+        return;
+
+    auto currentRequest = WTFMove(m_currentRequests.first());
+    m_currentRequests.remove(0);
+
+    if (!currentRequest.sessionInstance)
+        return;
+
+    m_requestMap.set(request, currentRequest.sessionInstance);
+    currentRequest.sessionInstance->didProvideRequest(request);
+    processNextContentKeyRequest();
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::didProvideRenewingRequest(AVContentKeyRequest *request)
+{
+    if (m_currentRequests.isEmpty())
+        return;
+
+    auto currentRequest = WTFMove(m_currentRequests.first());
+    m_currentRequests.remove(0);
+
+    if (!currentRequest.sessionInstance)
+        return;
+
+    m_requestMap.set(request, currentRequest.sessionInstance);
+    currentRequest.sessionInstance->didProvideRenewingRequest(request);
+    processNextContentKeyRequest();
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::didProvidePersistableRequest(AVContentKeyRequest *request)
+{
+    if (m_currentRequests.isEmpty())
+        return;
+
+    auto currentRequest = WTFMove(m_currentRequests.first());
+    m_currentRequests.remove(0);
+
+    if (!currentRequest.sessionInstance)
+        return;
+
+    m_requestMap.set(request, currentRequest.sessionInstance);
+    currentRequest.sessionInstance->didProvidePersistableRequest(request);
+    processNextContentKeyRequest();
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::didFailToProvideRequest(AVContentKeyRequest *request, NSError *error)
+{
+    if (auto sessionInterface = m_requestMap.get(request))
+        sessionInterface->didFailToProvideRequest(request, error);
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
+{
+    if (auto sessionInterface = m_requestMap.get(request))
+        sessionInterface->requestDidSucceed(request);
+}
+
+bool CDMInstanceFairPlayStreamingAVFObjC::shouldRetryRequestForReason(AVContentKeyRequest *request, NSString *reason)
+{
+    if (auto sessionInterface = m_requestMap.get(request))
+        return sessionInterface->shouldRetryRequestForReason(request, reason);
+    return false;
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::sessionIdentifierChanged(NSData *sessionIdentifier)
+{
+    for (auto sessionInterface : m_requestMap.values()) {
+        if (sessionInterface)
+            sessionInterface->sessionIdentifierChanged(sessionIdentifier);
     }
 }
 
-Vector<Ref<SharedBuffer>> CDMInstanceFairPlayStreamingAVFObjC::keyIDs()
+void CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
+{
+    for (auto sessionInterface : m_requestMap.values()) {
+        if (sessionInterface)
+            sessionInterface->outputObscuredDueToInsufficientExternalProtectionChanged(obscured);
+    }
+}
+
+CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC(Ref<CDMInstanceFairPlayStreamingAVFObjC>&& instance)
+    : m_instance(WTFMove(instance))
+{
+}
+
+Vector<Ref<SharedBuffer>> CDMInstanceSessionFairPlayStreamingAVFObjC::keyIDs()
 {
     // FIXME(rdar://problem/35597141): use the future AVContentKeyRequest keyID property, rather than parsing it out of the init
     // data, to get the keyID.
@@ -250,14 +353,14 @@ Vector<Ref<SharedBuffer>> CDMInstanceFairPlayStreamingAVFObjC::keyIDs()
     return { };
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&& callback)
 {
     if (!isLicenseTypeSupported(licenseType)) {
         callback(SharedBuffer::create(), emptyString(), false, Failed);
         return;
     }
 
-    if (!m_serverCertificate) {
+    if (!m_instance->serverCertificate()) {
         callback(SharedBuffer::create(), emptyString(), false, Failed);
         return;
     }
@@ -275,7 +378,7 @@ void CDMInstanceFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType
     }
 
     m_requestLicenseCallback = WTFMove(callback);
-    [m_session processContentKeyRequestWithIdentifier:identifier.get() initializationData:initializationData.get() options:nil];
+    m_instance->processContentKeyRequestForSession(*this, WTFMove(identifier), WTFMove(initializationData));
 }
 
 static bool isEqual(const SharedBuffer& data, const String& value)
@@ -296,14 +399,23 @@ static bool isEqual(const SharedBuffer& data, const String& value)
     return stringOrException.returnValue() == value;
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::updateLicense(const String&, LicenseType, const SharedBuffer& responseData, LicenseUpdateCallback callback)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::updateLicense(const String&, LicenseType, const SharedBuffer& responseData, LicenseUpdateCallback&& callback)
 {
     if (!m_expiredSessions.isEmpty() && isEqual(responseData, "acknowledged"_s)) {
         auto expiredSessions = adoptNS([[NSMutableArray alloc] init]);
         for (auto& session : m_expiredSessions)
-            [expiredSessions addObject:session.get()]; 
-        RetainPtr<NSData> appIdentifier = m_serverCertificate->createNSData();
-        [getAVContentKeySessionClass() removePendingExpiredSessionReports:expiredSessions.get() withAppIdentifier:appIdentifier.get() storageDirectoryAtURL:m_storageDirectory.get()];
+            [expiredSessions addObject:session.get()];
+
+        auto* certificate = m_instance->serverCertificate();
+        auto* storageDirectory = m_instance->storageDirectory();
+
+        if (!certificate || !storageDirectory) {
+            callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
+            return;
+        }
+
+        RetainPtr<NSData> appIdentifier = certificate->createNSData();
+        [getAVContentKeySessionClass() removePendingExpiredSessionReports:expiredSessions.get() withAppIdentifier:appIdentifier.get() storageDirectoryAtURL:storageDirectory];
         callback(false, { }, std::nullopt, std::nullopt, Succeeded);
         return;
     }
@@ -333,22 +445,24 @@ void CDMInstanceFairPlayStreamingAVFObjC::updateLicense(const String&, LicenseTy
     m_updateLicenseCallback = WTFMove(callback);
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::loadSession(LicenseType licenseType, const String& sessionId, const String& origin, LoadSessionCallback callback)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::loadSession(LicenseType licenseType, const String& sessionId, const String& origin, LoadSessionCallback&& callback)
 {
     UNUSED_PARAM(origin);
     if (licenseType == LicenseType::PersistentUsageRecord) {
-        if (!m_persistentStateAllowed || !m_storageDirectory) {
+        auto* storageDirectory = m_instance->storageDirectory();
+        if (!m_instance->persistentStateAllowed() || storageDirectory) {
             callback(std::nullopt, std::nullopt, std::nullopt, Failed, SessionLoadFailure::MismatchedSessionType);
             return;
         }
-        if (!m_serverCertificate) {
-            callback(std::nullopt, std::nullopt, std::nullopt, Failed, SessionLoadFailure::Other);
+        auto* certificate = m_instance->serverCertificate();
+        if (!certificate) {
+            callback(std::nullopt, std::nullopt, std::nullopt, Failed, SessionLoadFailure::NoSessionData);
             return;
         }
 
-        RetainPtr<NSData> appIdentifier = m_serverCertificate->createNSData();
+        RetainPtr<NSData> appIdentifier = certificate->createNSData();
         KeyStatusVector changedKeys;
-        for (NSData* expiredSessionData in [getAVContentKeySessionClass() pendingExpiredSessionReportsWithAppIdentifier:appIdentifier.get() storageDirectoryAtURL:m_storageDirectory.get()]) {
+        for (NSData* expiredSessionData in [getAVContentKeySessionClass() pendingExpiredSessionReportsWithAppIdentifier:appIdentifier.get() storageDirectoryAtURL:storageDirectory]) {
             NSDictionary *expiredSession = [NSPropertyListSerialization propertyListWithData:expiredSessionData options:kCFPropertyListImmutable format:nullptr error:nullptr];
             NSString *playbackSessionIdValue = (NSString *)[expiredSession objectForKey:PlaybackSessionIdKey];
             if (![playbackSessionIdValue isKindOfClass:[NSString class]])
@@ -370,7 +484,7 @@ void CDMInstanceFairPlayStreamingAVFObjC::loadSession(LicenseType licenseType, c
     }
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::closeSession(const String&, CloseSessionCallback callback)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::closeSession(const String&, CloseSessionCallback&& callback)
 {
     if (m_requestLicenseCallback) {
         m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
@@ -384,25 +498,28 @@ void CDMInstanceFairPlayStreamingAVFObjC::closeSession(const String&, CloseSessi
         m_removeSessionDataCallback({ }, std::nullopt, Failed);
         m_removeSessionDataCallback = nullptr;
     }
-    m_session = nullptr;
     m_request = nullptr;
     callback();
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::removeSessionData(const String& sessionId, LicenseType licenseType, RemoveSessionDataCallback callback)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::removeSessionData(const String& sessionId, LicenseType licenseType, RemoveSessionDataCallback&& callback)
 {
-    [m_session expire];
+    // FIXME: We should be able to expire individual AVContentKeyRequests rather than the entire AVContentKeySession.
+    [m_instance->contentKeySession() expire];
 
     if (licenseType == LicenseType::PersistentUsageRecord) {
-        if (!m_persistentStateAllowed || !m_storageDirectory || !m_serverCertificate) {
+        auto* storageDirectory = m_instance->storageDirectory();
+        auto* certificate = m_instance->serverCertificate();
+
+        if (!m_instance->persistentStateAllowed() || !storageDirectory || !certificate) {
             callback({ }, std::nullopt, Failed);
             return;
         }
 
-        RetainPtr<NSData> appIdentifier = m_serverCertificate->createNSData();
+        RetainPtr<NSData> appIdentifier = certificate->createNSData();
         RetainPtr<NSMutableArray> expiredSessionsArray = adoptNS([[NSMutableArray alloc] init]);
         KeyStatusVector changedKeys;
-        for (NSData* expiredSessionData in [getAVContentKeySessionClass() pendingExpiredSessionReportsWithAppIdentifier:appIdentifier.get() storageDirectoryAtURL:m_storageDirectory.get()]) {
+        for (NSData* expiredSessionData in [getAVContentKeySessionClass() pendingExpiredSessionReportsWithAppIdentifier:appIdentifier.get() storageDirectoryAtURL:storageDirectory]) {
             NSDictionary *expiredSession = [NSPropertyListSerialization propertyListWithData:expiredSessionData options:kCFPropertyListImmutable format:nullptr error:nullptr];
             NSString *playbackSessionIdValue = (NSString *)[expiredSession objectForKey:PlaybackSessionIdKey];
             if (![playbackSessionIdValue isKindOfClass:[NSString class]])
@@ -422,34 +539,30 @@ void CDMInstanceFairPlayStreamingAVFObjC::removeSessionData(const String& sessio
     }
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::storeRecordOfKeyUsage(const String&)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::storeRecordOfKeyUsage(const String&)
 {
     // no-op; key usage data is stored automatically.
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::setClient(CDMInstanceClient& client)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::setClient(WeakPtr<CDMInstanceSessionClient>&& client)
 {
-    m_client = &client;
+    m_client = WTFMove(client);
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::clearClient()
+void CDMInstanceSessionFairPlayStreamingAVFObjC::clearClient()
 {
     m_client = nullptr;
 }
 
-const String& CDMInstanceFairPlayStreamingAVFObjC::keySystem() const
-{
-    static NeverDestroyed<String> s_keySystem { "com.apple.fps"_s };
-    return s_keySystem;
-}
-
-void CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest *request)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest *request)
 {
     m_request = request;
     if (!m_requestLicenseCallback)
         return;
 
-    RetainPtr<NSData> appIdentifier = m_serverCertificate ? m_serverCertificate->createNSData() : nullptr;
+    RetainPtr<NSData> appIdentifier;
+    if (auto* certificate = m_instance->serverCertificate())
+        appIdentifier = certificate->createNSData();
     Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
 
     if (keyIDs.isEmpty()) {
@@ -473,17 +586,17 @@ void CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest
     }];
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::didProvideRenewingRequest(AVContentKeyRequest *request)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRenewingRequest(AVContentKeyRequest *request)
 {
     UNUSED_PARAM(request);
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::didProvidePersistableRequest(AVContentKeyRequest *request)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvidePersistableRequest(AVContentKeyRequest *request)
 {
     UNUSED_PARAM(request);
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::didFailToProvideRequest(AVContentKeyRequest *request, NSError *error)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::didFailToProvideRequest(AVContentKeyRequest *request, NSError *error)
 {
     UNUSED_PARAM(request);
     UNUSED_PARAM(error);
@@ -491,7 +604,7 @@ void CDMInstanceFairPlayStreamingAVFObjC::didFailToProvideRequest(AVContentKeyRe
         m_updateLicenseCallback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
 {
     UNUSED_PARAM(request);
     if (!m_updateLicenseCallback)
@@ -504,7 +617,7 @@ void CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest
     m_updateLicenseCallback(false, std::make_optional(WTFMove(keyStatuses)), std::nullopt, std::nullopt, Succeeded);
 }
 
-bool CDMInstanceFairPlayStreamingAVFObjC::shouldRetryRequestForReason(AVContentKeyRequest *request, NSString *reason)
+bool CDMInstanceSessionFairPlayStreamingAVFObjC::shouldRetryRequestForReason(AVContentKeyRequest *request, NSString *reason)
 {
     UNUSED_PARAM(request);
     UNUSED_PARAM(reason);
@@ -512,7 +625,7 @@ bool CDMInstanceFairPlayStreamingAVFObjC::shouldRetryRequestForReason(AVContentK
     return false;
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::sessionIdentifierChanged(NSData *sessionIdentifier)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::sessionIdentifierChanged(NSData *sessionIdentifier)
 {
     if (!sessionIdentifier) {
         m_sessionId = emptyString();
@@ -523,7 +636,7 @@ void CDMInstanceFairPlayStreamingAVFObjC::sessionIdentifierChanged(NSData *sessi
     m_sessionId = sessionIdentifierString.get();
 }
 
-void CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
+void CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
 {
     if (!m_client || !m_request)
         return;
@@ -556,6 +669,18 @@ void CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExterna
     m_client->updateKeyStatuses(WTFMove(keyStatuses));
 }
 
+bool CDMInstanceSessionFairPlayStreamingAVFObjC::isLicenseTypeSupported(LicenseType licenseType) const
+{
+    switch (licenseType) {
+    case CDMSessionType::PersistentLicense:
+        return m_instance->persistentStateAllowed() && m_instance->supportsPersistentKeys();
+    case CDMSessionType::PersistentUsageRecord:
+        return m_instance->persistentStateAllowed() && m_instance->supportsPersistableState();
+    case CDMSessionType::Temporary:
+        return true;
+    }
+}
+
 }
 
 #endif // ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
index 12bc7f6..d043771 100644 (file)
@@ -269,9 +269,26 @@ CDMInstance::SuccessValue MockCDMInstance::setStorageDirectory(const String&)
     return Succeeded;
 }
 
-void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback callback)
+const String& MockCDMInstance::keySystem() const
 {
-    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    static const NeverDestroyed<String> s_keySystem = MAKE_STATIC_STRING_IMPL("org.webkit.mock");
+
+    return s_keySystem;
+}
+
+RefPtr<CDMInstanceSession> MockCDMInstance::createSession()
+{
+    return adoptRef(new MockCDMInstanceSession(makeWeakPtr(*this)));
+}
+
+MockCDMInstanceSession::MockCDMInstanceSession(WeakPtr<MockCDMInstance>&& instance)
+    : m_instance(WTFMove(instance))
+{
+}
+
+void MockCDMInstanceSession::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&& callback)
+{
+    MockCDMFactory* factory = m_instance ? m_instance->factory() : nullptr;
     if (!factory) {
         callback(SharedBuffer::create(), emptyAtom(), false, SuccessValue::Failed);
         return;
@@ -295,9 +312,9 @@ void MockCDMInstance::requestLicense(LicenseType licenseType, const AtomicString
     callback(SharedBuffer::create(license.data(), license.length()), sessionID, false, SuccessValue::Succeeded);
 }
 
-void MockCDMInstance::updateLicense(const String& sessionID, LicenseType, const SharedBuffer& response, LicenseUpdateCallback callback)
+void MockCDMInstanceSession::updateLicense(const String& sessionID, LicenseType, const SharedBuffer& response, LicenseUpdateCallback&& callback)
 {
-    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    MockCDMFactory* factory = m_instance ? m_instance->factory() : nullptr;
     if (!factory) {
         callback(false, std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed);
         return;
@@ -329,9 +346,9 @@ void MockCDMInstance::updateLicense(const String& sessionID, LicenseType, const
     callback(false, WTFMove(changedKeys), std::nullopt, std::nullopt, SuccessValue::Succeeded);
 }
 
-void MockCDMInstance::loadSession(LicenseType, const String&, const String&, LoadSessionCallback callback)
+void MockCDMInstanceSession::loadSession(LicenseType, const String&, const String&, LoadSessionCallback&& callback)
 {
-    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    MockCDMFactory* factory = m_instance ? m_instance->factory() : nullptr;
     if (!factory) {
         callback(std::nullopt, std::nullopt, std::nullopt, SuccessValue::Failed, SessionLoadFailure::Other);
         return;
@@ -345,9 +362,9 @@ void MockCDMInstance::loadSession(LicenseType, const String&, const String&, Loa
     callback(std::nullopt, std::nullopt, WTFMove(message), SuccessValue::Succeeded, SessionLoadFailure::None);
 }
 
-void MockCDMInstance::closeSession(const String& sessionID, CloseSessionCallback callback)
+void MockCDMInstanceSession::closeSession(const String& sessionID, CloseSessionCallback&& callback)
 {
-    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    MockCDMFactory* factory = m_instance ? m_instance->factory() : nullptr;
     if (!factory) {
         callback();
         return;
@@ -357,9 +374,9 @@ void MockCDMInstance::closeSession(const String& sessionID, CloseSessionCallback
     callback();
 }
 
-void MockCDMInstance::removeSessionData(const String& id, LicenseType, RemoveSessionDataCallback callback)
+void MockCDMInstanceSession::removeSessionData(const String& id, LicenseType, RemoveSessionDataCallback&& callback)
 {
-    MockCDMFactory* factory = m_cdm ? m_cdm->factory() : nullptr;
+    MockCDMFactory* factory = m_instance ? m_instance->factory() : nullptr;
     if (!factory) {
         callback({ }, std::nullopt, SuccessValue::Failed);
         return;
@@ -375,18 +392,11 @@ void MockCDMInstance::removeSessionData(const String& id, LicenseType, RemoveSes
     callback(WTFMove(keyStatusVector), SharedBuffer::create(message.data(), message.length()), SuccessValue::Succeeded);
 }
 
-void MockCDMInstance::storeRecordOfKeyUsage(const String&)
+void MockCDMInstanceSession::storeRecordOfKeyUsage(const String&)
 {
     // FIXME: This should be implemented along with the support for persistent-usage-record sessions.
 }
 
-const String& MockCDMInstance::keySystem() const
-{
-    static const NeverDestroyed<String> s_keySystem = MAKE_STATIC_STRING_IMPL("org.webkit.mock");
-
-    return s_keySystem;
-}
-
 }
 
 #endif
index 216d29a..a822731 100644 (file)
@@ -30,6 +30,7 @@
 #include "CDM.h"
 #include "CDMFactory.h"
 #include "CDMInstance.h"
+#include "CDMInstanceSession.h"
 #include "CDMPrivate.h"
 #include "MediaKeysRequirement.h"
 #include <wtf/HashMap.h>
@@ -121,10 +122,14 @@ private:
     WeakPtr<MockCDMFactory> m_factory;
 };
 
-class MockCDMInstance : public CDMInstance {
+class MockCDMInstance : public CDMInstance, public CanMakeWeakPtr<MockCDMInstance> {
 public:
     MockCDMInstance(WeakPtr<MockCDM>);
 
+    MockCDMFactory* factory() const { return m_cdm ? m_cdm->factory() : nullptr; }
+    bool distinctiveIdentifiersAllowed() const { return m_distinctiveIdentifiersAllowed; }
+    bool persistentStateAllowed() const { return m_persistentStateAllowed; }
+
 private:
     ImplementationType implementationType() const final { return ImplementationType::Mock; }
     SuccessValue initializeWithConfiguration(const MediaKeySystemConfiguration&) final;
@@ -132,20 +137,29 @@ private:
     SuccessValue setPersistentStateAllowed(bool) final;
     SuccessValue setServerCertificate(Ref<SharedBuffer>&&) final;
     SuccessValue setStorageDirectory(const String&) final;
-    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback) final;
-    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback) final;
-    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback) final;
-    void closeSession(const String&, CloseSessionCallback) final;
-    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback) final;
-    void storeRecordOfKeyUsage(const String&) final;
-
     const String& keySystem() const final;
+    RefPtr<CDMInstanceSession> createSession() final;
 
     WeakPtr<MockCDM> m_cdm;
     bool m_distinctiveIdentifiersAllowed { true };
     bool m_persistentStateAllowed { true };
 };
 
+class MockCDMInstanceSession : public CDMInstanceSession {
+public:
+    MockCDMInstanceSession(WeakPtr<MockCDMInstance>&&);
+
+private:
+    void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&&) final;
+    void updateLicense(const String&, LicenseType, const SharedBuffer&, LicenseUpdateCallback&&) final;
+    void loadSession(LicenseType, const String&, const String&, LoadSessionCallback&&) final;
+    void closeSession(const String&, CloseSessionCallback&&) final;
+    void removeSessionData(const String&, LicenseType, RemoveSessionDataCallback&&) final;
+    void storeRecordOfKeyUsage(const String&) final;
+
+    WeakPtr<MockCDMInstance> m_instance;
+};
+
 }
 
 #endif