Diff
Modified: trunk/Source/WebCore/ChangeLog (237648 => 237649)
--- trunk/Source/WebCore/ChangeLog 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/ChangeLog 2018-10-31 20:23:38 UTC (rev 237649)
@@ -1,3 +1,85 @@
+2018-10-26 Jer Noble <jer.no...@apple.com>
+
+ [EME][Cocoa] Cannot play unmuxed video and audio fMP4 streams encrypted with different keys via MSE
+ https://bugs.webkit.org/show_bug.cgi?id=190946
+
+ Reviewed by Eric Carlson.
+
+ Use separate AVContentKeySessions per CDMInstanceSession (rather than one AVContentKeySession per
+ CDMInstance).
+
+ - Add a mechanism for sending a message out from platform/CDMInstance to MediaKeySession without
+ requiring MediaKeySession to send a callback first.
+
+ - Move all the AVContentKeySession delegate methods from CDMInstanceFairPlayStreamingAVFObjC to
+ CDMInstanceSessionFairPlayStreamingAVFObjC.
+
+ - Add a mechanism for requesting the correct CDMInstanceSession for a given KeyID.
+
+ - Support key renewal through a "renew" message.
+
+ - Remember the keyID in SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID()
+ and ask for the correct CDMInstanceSession for that keyID in attemptToDecrypt().
+
+ - Pass the CDMInstance down from MediaPlayerPrivateMediaSourceAVFObjC -> SourceBufferPrivateAVFObjC.
+
+ * Modules/encryptedmedia/MediaKeySession.cpp:
+ (WebCore::MediaKeySession::sendMessage):
+ * Modules/encryptedmedia/MediaKeySession.h:
+ * platform/encryptedmedia/CDMInstanceSession.h:
+ * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
+ * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
+ (-[WebCoreFPSContentKeySessionDelegate initWithParent:]):
+ (WebCore::CDMInstanceFairPlayStreamingAVFObjC::initializeWithConfiguration):
+ (WebCore::CDMInstanceFairPlayStreamingAVFObjC::createSession):
+ (WebCore::CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+ (WebCore::CDMInstanceFairPlayStreamingAVFObjC::sessionForKeyIDs const):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::~CDMInstanceSessionFairPlayStreamingAVFObjC):
+ (WebCore::keyIDsForRequest):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyIDs):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestLicense):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateLicense):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::closeSession):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::removeSessionData):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRequest):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRenewingRequest):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::didFailToProvideRequest):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::nextRequest):
+ (WebCore::requestStatusToCDMStatus):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyStatuses const):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+ (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::ensureSession):
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::shouldWaitForLoadingOfResource):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceAttached):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::cdmInstanceDetached):
+ (WebCore::MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance):
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::cdmInstanceAttached):
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::cdmInstanceDetached):
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::attemptToDecryptWithInstance):
+ (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::waitingForKey const):
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
+ * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
+ (WebCore::MediaSourcePrivateAVFObjC::addSourceBuffer):
+ (WebCore::MediaSourcePrivateAVFObjC::cdmInstanceAttached):
+ (WebCore::MediaSourcePrivateAVFObjC::cdmInstanceDetached):
+ (WebCore::MediaSourcePrivateAVFObjC::attemptToDecryptWithInstance):
+ (WebCore::MediaSourcePrivateAVFObjC::waitingForKey const):
+ (WebCore::MediaSourcePrivateAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+ * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+ * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+ (WebCore::SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID):
+ (WebCore::SourceBufferPrivateAVFObjC::destroyParser):
+ (WebCore::SourceBufferPrivateAVFObjC::setCDMInstance):
+ (WebCore::SourceBufferPrivateAVFObjC::attemptToDecrypt):
+ (WebCore::SourceBufferPrivateAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+
2018-10-31 Zach Li <zacharyli...@gmail.com>
Add credit card autofill button
Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp (237648 => 237649)
--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp 2018-10-31 20:23:38 UTC (rev 237649)
@@ -666,6 +666,11 @@
});
}
+void MediaKeySession::sendMessage(CDMMessageType messageType, Ref<SharedBuffer>&& message)
+{
+ enqueueMessage(messageType, message);
+}
+
void MediaKeySession::updateExpiration(double)
{
notImplemented();
Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h (237648 => 237649)
--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -86,6 +86,7 @@
// CDMInstanceSessionClient
void updateKeyStatuses(CDMInstanceSessionClient::KeyStatusVector&&) override;
+ void sendMessage(CDMMessageType, Ref<SharedBuffer>&& message) final;
// EventTarget
EventTargetInterface eventTargetInterface() const override { return MediaKeySessionEventTargetInterfaceType; }
Modified: trunk/Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h (237648 => 237649)
--- trunk/Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/encryptedmedia/CDMInstanceSession.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -45,6 +45,7 @@
using KeyStatus = CDMKeyStatus;
using KeyStatusVector = Vector<std::pair<Ref<SharedBuffer>, KeyStatus>>;
virtual void updateKeyStatuses(KeyStatusVector&&) = 0;
+ virtual void sendMessage(CDMMessageType, Ref<SharedBuffer>&& message) = 0;
};
class CDMInstanceSession : public RefCounted<CDMInstanceSession> {
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -48,8 +48,7 @@
class CDMInstanceFairPlayStreamingAVFObjC final : public CDMInstance, public CanMakeWeakPtr<CDMInstanceFairPlayStreamingAVFObjC> {
public:
- CDMInstanceFairPlayStreamingAVFObjC();
- virtual ~CDMInstanceFairPlayStreamingAVFObjC();
+ virtual ~CDMInstanceFairPlayStreamingAVFObjC() = default;
static bool supportsPersistableState();
static bool supportsPersistentKeys();
@@ -65,46 +64,26 @@
SuccessValue setStorageDirectory(const String&) final;
RefPtr<CDMInstanceSession> createSession() final;
- void processContentKeyRequestForSession(CDMInstanceSessionFairPlayStreamingAVFObjC&, RetainPtr<NSString>&& identifier, RetainPtr<NSData>&& initData);
-
const String& keySystem() const 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);
-
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(); }
+ void outputObscuredDueToInsufficientExternalProtectionChanged(bool);
+ CDMInstanceSessionFairPlayStreamingAVFObjC* sessionForKeyIDs(const Vector<Ref<SharedBuffer>>&) const;
+
private:
- void processNextContentKeyRequest();
-
- 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<WebCoreFPSContentKeySessionDelegate> m_delegate;
+ Vector<WeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC>> m_sessions;
};
class CDMInstanceSessionFairPlayStreamingAVFObjC final : public CDMInstanceSession, public CanMakeWeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC> {
public:
CDMInstanceSessionFairPlayStreamingAVFObjC(Ref<CDMInstanceFairPlayStreamingAVFObjC>&&);
+ virtual ~CDMInstanceSessionFairPlayStreamingAVFObjC();
// CDMInstanceSession
void requestLicense(LicenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&&) final;
@@ -126,16 +105,27 @@
void outputObscuredDueToInsufficientExternalProtectionChanged(bool);
Vector<Ref<SharedBuffer>> keyIDs();
+ AVContentKeySession* contentKeySession() { return m_session.get(); }
private:
+ AVContentKeySession* ensureSession();
bool isLicenseTypeSupported(LicenseType) const;
+ KeyStatusVector keyStatuses() const;
+ void nextRequest();
+
Ref<CDMInstanceFairPlayStreamingAVFObjC> m_instance;
- RetainPtr<AVContentKeyRequest> m_request;
+ RetainPtr<AVContentKeySession> m_session;
+ RetainPtr<AVContentKeyRequest> m_currentRequest;
+ RetainPtr<WebCoreFPSContentKeySessionDelegate> m_delegate;
Vector<RetainPtr<NSData>> m_expiredSessions;
WeakPtr<CDMInstanceSessionClient> m_client;
String m_sessionId;
+ bool m_outputObscured { false };
+ Vector<RetainPtr<AVContentKeyRequest>> m_pendingRequests;
+ Vector<RetainPtr<AVContentKeyRequest>> m_requests;
+
LicenseCallback m_requestLicenseCallback;
LicenseUpdateCallback m_updateLicenseCallback;
CloseSessionCallback m_closeSessionCallback;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm 2018-10-31 20:23:38 UTC (rev 237649)
@@ -37,6 +37,7 @@
#import <AVFoundation/AVContentKeySession.h>
#import <objc/runtime.h>
#import <pal/spi/mac/AVFoundationSPI.h>
+#import <wtf/Algorithms.h>
#import <wtf/SoftLinking.h>
#import <wtf/text/StringHash.h>
@@ -53,12 +54,12 @@
static const NSString *PlaybackSessionIdKey = @"PlaybackSessionID";
@interface WebCoreFPSContentKeySessionDelegate : NSObject<AVContentKeySessionDelegate> {
- WebCore::CDMInstanceFairPlayStreamingAVFObjC* _parent;
+ WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC* _parent;
}
@end
@implementation WebCoreFPSContentKeySessionDelegate
-- (id)initWithParent:(WebCore::CDMInstanceFairPlayStreamingAVFObjC *)parent
+- (id)initWithParent:(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC *)parent
{
if (!(self = [super init]))
return nil;
@@ -134,17 +135,6 @@
namespace WebCore {
-CDMInstanceFairPlayStreamingAVFObjC::CDMInstanceFairPlayStreamingAVFObjC()
- : CDMInstance()
- , m_delegate([[WebCoreFPSContentKeySessionDelegate alloc] initWithParent:this])
-{
-}
-
-CDMInstanceFairPlayStreamingAVFObjC::~CDMInstanceFairPlayStreamingAVFObjC()
-{
- [m_delegate invalidate];
-}
-
bool CDMInstanceFairPlayStreamingAVFObjC::supportsPersistableState()
{
return [getAVContentKeySessionClass() respondsToSelector:@selector(pendingExpiredSessionReportsWithAppIdentifier:storageDirectoryAtURL:)];
@@ -189,16 +179,6 @@
if (!canLoadAVContentKeySystemFairPlayStreaming())
return Failed;
- if (configuration.persistentState == CDMRequirement::NotAllowed || !m_storageDirectory)
- m_session = [getAVContentKeySessionClass() contentKeySessionWithKeySystem:getAVContentKeySystemFairPlayStreaming()];
- else
- m_session = [getAVContentKeySessionClass() contentKeySessionWithKeySystem:getAVContentKeySystemFairPlayStreaming() storageDirectoryAtURL:m_storageDirectory.get()];
-
- if (!m_session)
- return Failed;
-
- [m_session setDelegate:m_delegate.get() queue:dispatch_get_main_queue()];
-
return Succeeded;
}
@@ -231,25 +211,11 @@
RefPtr<CDMInstanceSession> CDMInstanceFairPlayStreamingAVFObjC::createSession()
{
- return adoptRef(new CDMInstanceSessionFairPlayStreamingAVFObjC(*this));
+ auto session = adoptRef(*new CDMInstanceSessionFairPlayStreamingAVFObjC(*this));
+ m_sessions.append(makeWeakPtr(session.get()));
+ return session;
}
-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 };
@@ -256,109 +222,64 @@
return keySystem;
}
-void CDMInstanceFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest *request)
+void CDMInstanceFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
{
- 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();
+ for (auto& sessionInterface : m_sessions) {
+ if (sessionInterface)
+ sessionInterface->outputObscuredDueToInsufficientExternalProtectionChanged(obscured);
+ }
}
-void CDMInstanceFairPlayStreamingAVFObjC::didProvideRenewingRequest(AVContentKeyRequest *request)
+CDMInstanceSessionFairPlayStreamingAVFObjC* CDMInstanceFairPlayStreamingAVFObjC::sessionForKeyIDs(const Vector<Ref<SharedBuffer>>& keyIDs) const
{
- if (m_currentRequests.isEmpty())
- return;
+ for (auto& sessionInterface : m_sessions) {
+ if (!sessionInterface)
+ continue;
- 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();
+ auto sessionKeys = sessionInterface->keyIDs();
+ if (anyOf(sessionKeys, [&](auto& sessionKey) {
+ return keyIDs.contains(sessionKey);
+ }))
+ return sessionInterface.get();
+ }
+ return nullptr;
}
-void CDMInstanceFairPlayStreamingAVFObjC::didProvidePersistableRequest(AVContentKeyRequest *request)
+CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC(Ref<CDMInstanceFairPlayStreamingAVFObjC>&& instance)
+ : m_instance(WTFMove(instance))
+ , m_delegate([[WebCoreFPSContentKeySessionDelegate alloc] initWithParent:this])
{
- 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)
+CDMInstanceSessionFairPlayStreamingAVFObjC::~CDMInstanceSessionFairPlayStreamingAVFObjC()
{
- if (auto sessionInterface = m_requestMap.get(request))
- sessionInterface->didFailToProvideRequest(request, error);
+ [m_delegate invalidate];
}
-void CDMInstanceFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
+static Vector<Ref<SharedBuffer>> keyIDsForRequest(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);
+ if ([request.identifier isKindOfClass:[NSString class]])
+ return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create([(NSString *)request.identifier dataUsingEncoding:NSUTF8StringEncoding]));
+ if ([request.identifier isKindOfClass:[NSData class]])
+ return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create((NSData *)request.identifier));
+ if (request.initializationData) {
+ if (auto sinfKeyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(request.initializationData)))
+ return WTFMove(sinfKeyIDs.value());
}
+ return { };
}
-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.
- if ([m_request.get().identifier isKindOfClass:[NSString class]])
- return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create([(NSString *)m_request.get().identifier dataUsingEncoding:NSUTF8StringEncoding]));
- if ([m_request.get().identifier isKindOfClass:[NSData class]])
- return Vector<Ref<SharedBuffer>>::from(SharedBuffer::create((NSData *)m_request.get().identifier));
- if (m_request.get().initializationData) {
- auto sinfKeyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(SharedBuffer::create(m_request.get().initializationData));
- if (!sinfKeyIDs)
- return { };
- return WTFMove(sinfKeyIDs.value());
+ Vector<Ref<SharedBuffer>> keyIDs;
+ for (auto& request : m_requests) {
+ for (auto& key : keyIDsForRequest(request.get()))
+ keyIDs.append(WTFMove(key));
}
- return { };
+
+ return keyIDs;
}
void CDMInstanceSessionFairPlayStreamingAVFObjC::requestLicense(LicenseType licenseType, const AtomicString& initDataType, Ref<SharedBuffer>&& initData, LicenseCallback&& callback)
@@ -373,6 +294,11 @@
return;
}
+ if (!ensureSession()) {
+ callback(SharedBuffer::create(), emptyString(), false, Failed);
+ return;
+ }
+
RetainPtr<NSString> identifier;
RetainPtr<NSData> initializationData;
@@ -386,7 +312,7 @@
}
m_requestLicenseCallback = WTFMove(callback);
- m_instance->processContentKeyRequestForSession(*this, WTFMove(identifier), WTFMove(initializationData));
+ [m_session processContentKeyRequestWithIdentifier:identifier.get() initializationData:initializationData.get() options:nil];
}
static bool isEqual(const SharedBuffer& data, const String& value)
@@ -428,17 +354,23 @@
return;
}
- if (!m_request) {
+ if (!m_requests.isEmpty() && isEqual(responseData, "renew"_s)) {
+ [m_session renewExpiringResponseDataForContentKeyRequest:m_requests.last().get()];
+ m_updateLicenseCallback = WTFMove(callback);
+ return;
+ }
+
+ if (!m_currentRequest) {
callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
return;
}
- Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
+ Vector<Ref<SharedBuffer>> keyIDs = keyIDsForRequest(m_currentRequest.get());
if (keyIDs.isEmpty()) {
callback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
return;
}
- [m_request processContentKeyResponse:[getAVContentKeyResponseClass() contentKeyResponseWithFairPlayStreamingKeyResponseData:responseData.createNSData().get()]];
+ [m_currentRequest processContentKeyResponse:[getAVContentKeyResponseClass() contentKeyResponseWithFairPlayStreamingKeyResponseData:responseData.createNSData().get()]];
// FIXME(rdar://problem/35592277): stash the callback and call it once AVContentKeyResponse supports a success callback.
struct objc_method_description method = protocol_getMethodDescription(@protocol(AVContentKeySessionDelegate), @selector(contentKeySession:contentKeyRequestDidSucceed:), NO, YES);
@@ -506,7 +438,9 @@
m_removeSessionDataCallback({ }, std::nullopt, Failed);
m_removeSessionDataCallback = nullptr;
}
- m_request = nullptr;
+ m_currentRequest = nullptr;
+ m_pendingRequests.clear();
+ m_requests.clear();
callback();
}
@@ -513,7 +447,7 @@
void CDMInstanceSessionFairPlayStreamingAVFObjC::removeSessionData(const String& sessionId, LicenseType licenseType, RemoveSessionDataCallback&& callback)
{
// FIXME: We should be able to expire individual AVContentKeyRequests rather than the entire AVContentKeySession.
- [m_instance->contentKeySession() expire];
+ [m_session expire];
if (licenseType == LicenseType::PersistentUsageRecord) {
auto* storageDirectory = m_instance->storageDirectory();
@@ -564,31 +498,41 @@
void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRequest(AVContentKeyRequest *request)
{
- m_request = request;
- if (!m_requestLicenseCallback)
+ if (m_currentRequest) {
+ m_pendingRequests.append(request);
return;
+ }
+ m_currentRequest = request;
+
+ ASSERT(!m_requests.contains(m_currentRequest));
+ m_requests.append(m_currentRequest);
+
RetainPtr<NSData> appIdentifier;
if (auto* certificate = m_instance->serverCertificate())
appIdentifier = certificate->createNSData();
- Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
+ auto keyIDs = keyIDsForRequest(request);
if (keyIDs.isEmpty()) {
- m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
- m_requestLicenseCallback = nullptr;
+ if (m_requestLicenseCallback) {
+ m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
+ m_requestLicenseCallback = nullptr;
+ }
return;
}
RetainPtr<NSData> contentIdentifier = keyIDs.first()->createNSData();
- [m_request makeStreamingContentKeyRequestDataForApp:appIdentifier.get() contentIdentifier:contentIdentifier.get() options:nil completionHandler:[this, weakThis = makeWeakPtr(*this)] (NSData *contentKeyRequestData, NSError *error) mutable {
+ [m_currentRequest makeStreamingContentKeyRequestDataForApp:appIdentifier.get() contentIdentifier:contentIdentifier.get() options:nil completionHandler:[this, weakThis = makeWeakPtr(*this)] (NSData *contentKeyRequestData, NSError *error) mutable {
callOnMainThread([this, weakThis = WTFMove(weakThis), error = retainPtr(error), contentKeyRequestData = retainPtr(contentKeyRequestData)] {
- if (!weakThis || !m_requestLicenseCallback)
+ if (!weakThis)
return;
- if (error)
+ if (error && m_requestLicenseCallback)
m_requestLicenseCallback(SharedBuffer::create(), m_sessionId, false, Failed);
- else
+ else if (m_requestLicenseCallback)
m_requestLicenseCallback(SharedBuffer::create(contentKeyRequestData.get()), m_sessionId, false, Succeeded);
+ else if (m_client)
+ m_client->sendMessage(CDMMessageType::LicenseRequest, SharedBuffer::create(contentKeyRequestData.get()));
m_requestLicenseCallback = nullptr;
});
}];
@@ -596,7 +540,38 @@
void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvideRenewingRequest(AVContentKeyRequest *request)
{
- UNUSED_PARAM(request);
+ ASSERT(!m_requestLicenseCallback);
+ if (m_currentRequest) {
+ m_pendingRequests.append(request);
+ return;
+ }
+
+ m_currentRequest = request;
+
+ // The assumption here is that AVContentKeyRequest will only ever notify us of a renewing request as a result of calling
+ // -renewExpiringResponseDataForContentKeyRequest: with an existing request.
+ ASSERT(m_requests.contains(m_currentRequest));
+
+ RetainPtr<NSData> appIdentifier;
+ if (auto* certificate = m_instance->serverCertificate())
+ appIdentifier = certificate->createNSData();
+ auto keyIDs = keyIDsForRequest(m_currentRequest.get());
+
+ RetainPtr<NSData> contentIdentifier = keyIDs.first()->createNSData();
+ [m_currentRequest makeStreamingContentKeyRequestDataForApp:appIdentifier.get() contentIdentifier:contentIdentifier.get() options:nil completionHandler:[this, weakThis = makeWeakPtr(*this)] (NSData *contentKeyRequestData, NSError *error) mutable {
+ callOnMainThread([this, weakThis = WTFMove(weakThis), error = retainPtr(error), contentKeyRequestData = retainPtr(contentKeyRequestData)] {
+ if (!weakThis || !m_client || error)
+ return;
+
+ if (error && m_updateLicenseCallback)
+ m_updateLicenseCallback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
+ else if (m_updateLicenseCallback)
+ m_updateLicenseCallback(false, std::nullopt, std::nullopt, Message(MessageType::LicenseRenewal, SharedBuffer::create(contentKeyRequestData.get())), Succeeded);
+ else if (m_client)
+ m_client->sendMessage(CDMMessageType::LicenseRenewal, SharedBuffer::create(contentKeyRequestData.get()));
+ m_updateLicenseCallback = nullptr;
+ });
+ }];
}
void CDMInstanceSessionFairPlayStreamingAVFObjC::didProvidePersistableRequest(AVContentKeyRequest *request)
@@ -610,19 +585,35 @@
UNUSED_PARAM(error);
if (m_updateLicenseCallback)
m_updateLicenseCallback(false, std::nullopt, std::nullopt, std::nullopt, Failed);
+
+ m_currentRequest = nullptr;
+
+ nextRequest();
}
void CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
{
UNUSED_PARAM(request);
- if (!m_updateLicenseCallback)
+ if (m_updateLicenseCallback)
+ m_updateLicenseCallback(false, std::make_optional(keyStatuses()), std::nullopt, std::nullopt, Succeeded);
+
+ m_currentRequest = nullptr;
+
+ nextRequest();
+}
+
+void CDMInstanceSessionFairPlayStreamingAVFObjC::nextRequest()
+{
+ if (m_pendingRequests.isEmpty())
return;
- Vector<Ref<SharedBuffer>> keyIDs = this->keyIDs();
- KeyStatusVector keyStatuses;
- keyStatuses.reserveInitialCapacity(1);
- keyStatuses.uncheckedAppend(std::make_pair(WTFMove(keyIDs.first()), KeyStatus::Usable));
- m_updateLicenseCallback(false, std::make_optional(WTFMove(keyStatuses)), std::nullopt, std::nullopt, Succeeded);
+ RetainPtr<AVContentKeyRequest> nextRequest = m_pendingRequests.first();
+ m_pendingRequests.remove(0);
+
+ if (nextRequest.get().renewsExpiringResponseData)
+ didProvideRenewingRequest(nextRequest.get());
+ else
+ didProvideRequest(nextRequest.get());
}
bool CDMInstanceSessionFairPlayStreamingAVFObjC::shouldRetryRequestForReason(AVContentKeyRequest *request, NSString *reason)
@@ -644,39 +635,68 @@
m_sessionId = sessionIdentifierString.get();
}
-void CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
+static auto requestStatusToCDMStatus(AVContentKeyRequestStatus status)
{
- if (!m_client || !m_request)
- return;
-
- CDMKeyStatus status;
- if (obscured)
- status = CDMKeyStatus::OutputRestricted;
- else {
- switch (m_request.get().status) {
+ switch (status) {
case AVContentKeyRequestStatusRequestingResponse:
case AVContentKeyRequestStatusRetried:
- status = CDMKeyStatus::StatusPending;
- break;
+ return CDMKeyStatus::StatusPending;
case AVContentKeyRequestStatusReceivedResponse:
case AVContentKeyRequestStatusRenewed:
- status = CDMKeyStatus::Usable;
- break;
+ return CDMKeyStatus::Usable;
case AVContentKeyRequestStatusCancelled:
- status = CDMKeyStatus::Released;
- break;
+ return CDMKeyStatus::Released;
case AVContentKeyRequestStatusFailed:
- status = CDMKeyStatus::InternalError;
- break;
- }
+ return CDMKeyStatus::InternalError;
}
+}
- auto keyStatuses = keyIDs().map([status] (const Ref<SharedBuffer>& keyID) -> KeyStatusVector::ValueType {
- return { keyID.copyRef(), status };
- });
- m_client->updateKeyStatuses(WTFMove(keyStatuses));
+CDMInstanceSession::KeyStatusVector CDMInstanceSessionFairPlayStreamingAVFObjC::keyStatuses() const
+{
+ KeyStatusVector keyStatuses;
+
+ for (auto& request : m_requests) {
+ auto keyIDs = keyIDsForRequest(request.get());
+ auto status = requestStatusToCDMStatus(request.get().status);
+ if (m_outputObscured)
+ status = CDMKeyStatus::OutputRestricted;
+
+ for (auto& keyID : keyIDs)
+ keyStatuses.append({ WTFMove(keyID), status });
+ }
+
+ return keyStatuses;
}
+void CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
+{
+ if (obscured == m_outputObscured)
+ return;
+
+ m_outputObscured = obscured;
+
+ if (m_client)
+ m_client->updateKeyStatuses(keyStatuses());
+}
+
+AVContentKeySession* CDMInstanceSessionFairPlayStreamingAVFObjC::ensureSession()
+{
+ if (m_session)
+ return m_session.get();
+
+ auto* storageDirectory = m_instance->storageDirectory();
+ if (!m_instance->persistentStateAllowed() || !storageDirectory)
+ m_session = [getAVContentKeySessionClass() contentKeySessionWithKeySystem:getAVContentKeySystemFairPlayStreaming()];
+ else
+ m_session = [getAVContentKeySessionClass() contentKeySessionWithKeySystem:getAVContentKeySystemFairPlayStreaming() storageDirectoryAtURL:storageDirectory];
+
+ if (!m_session)
+ return nullptr;
+
+ [m_session setDelegate:m_delegate.get() queue:dispatch_get_main_queue()];
+ return m_session.get();
+}
+
bool CDMInstanceSessionFairPlayStreamingAVFObjC::isLicenseTypeSupported(LicenseType licenseType) const
{
switch (licenseType) {
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -61,6 +61,7 @@
class InbandMetadataTextTrackPrivateAVF;
class MediaSelectionGroupAVFObjC;
class PixelBufferConformerCV;
+class SharedBuffer;
class VideoFullscreenLayerManagerObjC;
class VideoTextureCopierCV;
class VideoTrackPrivateAVFObjC;
@@ -411,6 +412,7 @@
RetainPtr<NSArray> m_currentMetaData;
FloatSize m_cachedPresentationSize;
MediaTime m_cachedDuration;
+ RefPtr<SharedBuffer> m_keyID;
double m_cachedRate;
mutable long long m_cachedTotalBytes;
unsigned m_pendingStatusChanges;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm 2018-10-31 20:23:38 UTC (rev 237649)
@@ -1780,8 +1780,8 @@
return false;
RetainPtr<NSData> keyURIData = [keyURI dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
- auto keyURIBuffer = SharedBuffer::create(keyURIData.get());
- player()->initializationDataEncountered("skd"_s, keyURIBuffer->tryCreateArrayBuffer());
+ m_keyID = SharedBuffer::create(keyURIData.get());
+ player()->initializationDataEncountered("skd"_s, m_keyID->tryCreateArrayBuffer());
setWaitingForKey(true);
#endif
return true;
@@ -2470,7 +2470,6 @@
cdmInstanceDetached(*m_cdmInstance);
m_cdmInstance = &fpsInstance;
- [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_avAsset.get()];
#else
UNUSED_PARAM(instance);
#endif
@@ -2480,7 +2479,6 @@
{
#if HAVE(AVCONTENTKEYSESSION)
ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
- [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_avAsset.get()];
m_cdmInstance = nullptr;
#else
UNUSED_PARAM(instance);
@@ -2489,6 +2487,15 @@
void MediaPlayerPrivateAVFoundationObjC::attemptToDecryptWithInstance(CDMInstance&)
{
+ if (!m_keyID || !m_cdmInstance)
+ return;
+
+ auto instanceSession = m_cdmInstance->sessionForKeyIDs(Vector<Ref<SharedBuffer>>::from(*m_keyID));
+ if (!instanceSession)
+ return;
+
+ [instanceSession->contentKeySession() addContentKeyRecipient:m_avAsset.get()];
+
auto keyURIToRequestMap = WTFMove(m_keyURIToRequestMap);
for (auto& request : keyURIToRequestMap.values()) {
if (auto *infoRequest = request.get().contentInformationRequest)
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -123,7 +123,6 @@
bool waitingForKey() const final;
void waitingForKeyChanged();
- CDMInstance* cdmInstance() const { return m_cdmInstance.get(); }
#endif
#if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
@@ -309,9 +308,6 @@
bool m_shouldPlayToTarget { false };
#endif
std::unique_ptr<VideoFullscreenLayerManagerObjC> m_videoFullscreenLayerManager;
-#if ENABLE(ENCRYPTED_MEDIA)
- RefPtr<CDMInstance> m_cdmInstance;
-#endif
};
}
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm 2018-10-31 20:23:38 UTC (rev 237649)
@@ -30,9 +30,7 @@
#import "AVAssetTrackUtilities.h"
#import "AVFoundationMIMETypeCache.h"
-#import "CDMInstance.h"
#import "CDMSessionAVStreamSession.h"
-#import "CDMSessionMediaSourceAVFObjC.h"
#import "FileSystem.h"
#import "GraphicsContextCG.h"
#import "Logging.h"
@@ -50,7 +48,6 @@
#import <objc_runtime.h>
#import <pal/avfoundation/MediaTimeAVFoundation.h>
#import <pal/spi/mac/AVFoundationSPI.h>
-#import <wtf/Algorithms.h>
#import <wtf/Deque.h>
#import <wtf/MainThread.h>
#import <wtf/NeverDestroyed.h>
@@ -933,8 +930,8 @@
void MediaPlayerPrivateMediaSourceAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
{
#if ENABLE(ENCRYPTED_MEDIA)
- if (m_cdmInstance)
- m_cdmInstance->setHDCPStatus(obscured ? CDMInstance::HDCPStatus::OutputRestricted : CDMInstance::HDCPStatus::Valid);
+ if (m_mediaSourcePrivate)
+ m_mediaSourcePrivate->outputObscuredDueToInsufficientExternalProtectionChanged(obscured);
#else
UNUSED_PARAM(obscured);
#endif
@@ -944,30 +941,25 @@
#if ENABLE(ENCRYPTED_MEDIA)
void MediaPlayerPrivateMediaSourceAVFObjC::cdmInstanceAttached(CDMInstance& instance)
{
- ASSERT(!m_cdmInstance);
- m_cdmInstance = &instance;
- for (auto& sourceBuffer : m_mediaSourcePrivate->sourceBuffers())
- sourceBuffer->setCDMInstance(&instance);
+ if (m_mediaSourcePrivate)
+ m_mediaSourcePrivate->cdmInstanceAttached(instance);
}
void MediaPlayerPrivateMediaSourceAVFObjC::cdmInstanceDetached(CDMInstance& instance)
{
- ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
- for (auto& sourceBuffer : m_mediaSourcePrivate->sourceBuffers())
- sourceBuffer->setCDMInstance(nullptr);
-
- m_cdmInstance = nullptr;
+ if (m_mediaSourcePrivate)
+ m_mediaSourcePrivate->cdmInstanceDetached(instance);
}
-void MediaPlayerPrivateMediaSourceAVFObjC::attemptToDecryptWithInstance(CDMInstance&)
+void MediaPlayerPrivateMediaSourceAVFObjC::attemptToDecryptWithInstance(CDMInstance& instance)
{
+ if (m_mediaSourcePrivate)
+ m_mediaSourcePrivate->attemptToDecryptWithInstance(instance);
}
bool MediaPlayerPrivateMediaSourceAVFObjC::waitingForKey() const
{
- return anyOf(m_mediaSourcePrivate->sourceBuffers(), [] (auto& sourceBuffer) {
- return sourceBuffer->waitingForKey();
- });
+ return m_mediaSourcePrivate ? m_mediaSourcePrivate->waitingForKey() : false;
}
void MediaPlayerPrivateMediaSourceAVFObjC::waitingForKeyChanged()
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -43,6 +43,7 @@
namespace WebCore {
+class CDMInstance;
class LegacyCDMSession;
class MediaPlayerPrivateMediaSourceAVFObjC;
class MediaSourcePrivateClient;
@@ -84,6 +85,16 @@
void setVideoLayer(AVSampleBufferDisplayLayer*);
void setDecompressionSession(WebCoreDecompressionSession*);
+#if ENABLE(ENCRYPTED_MEDIA)
+ void cdmInstanceAttached(CDMInstance&);
+ void cdmInstanceDetached(CDMInstance&);
+ void attemptToDecryptWithInstance(CDMInstance&);
+ bool waitingForKey() const;
+
+ CDMInstance* cdmInstance() const { return m_cdmInstance.get(); }
+ void outputObscuredDueToInsufficientExternalProtectionChanged(bool);
+#endif
+
private:
MediaSourcePrivateAVFObjC(MediaPlayerPrivateMediaSourceAVFObjC*, MediaSourcePrivateClient*);
@@ -106,6 +117,9 @@
Deque<SourceBufferPrivateAVFObjC*> m_sourceBuffersNeedingSessions;
SourceBufferPrivateAVFObjC* m_sourceBufferWithSelectedVideo { nullptr };
bool m_isEnded;
+#if ENABLE(ENCRYPTED_MEDIA)
+ RefPtr<CDMInstance> m_cdmInstance;
+#endif
};
}
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm 2018-10-31 20:23:38 UTC (rev 237649)
@@ -28,6 +28,7 @@
#if ENABLE(MEDIA_SOURCE) && USE(AVFOUNDATION)
+#import "CDMInstance.h"
#import "CDMSessionMediaSourceAVFObjC.h"
#import "ContentType.h"
#import "MediaPlayerPrivateMediaSourceAVFObjC.h"
@@ -34,6 +35,7 @@
#import "MediaSourcePrivateClient.h"
#import "SourceBufferPrivateAVFObjC.h"
#import <objc/runtime.h>
+#import <wtf/Algorithms.h>
#import <wtf/SoftLinking.h>
#import <wtf/text/AtomicString.h>
@@ -70,8 +72,12 @@
if (MediaPlayerPrivateMediaSourceAVFObjC::supportsType(parameters) == MediaPlayer::IsNotSupported)
return NotSupported;
- m_sourceBuffers.append(SourceBufferPrivateAVFObjC::create(this));
- outPrivate = m_sourceBuffers.last();
+ auto newSourceBuffer = SourceBufferPrivateAVFObjC::create(this);
+#if ENABLE(ENCRYPTED_MEDIA)
+ newSourceBuffer->setCDMInstance(m_cdmInstance.get());
+#endif
+ outPrivate = newSourceBuffer;
+ m_sourceBuffers.append(WTFMove(newSourceBuffer));
return Ok;
}
@@ -245,6 +251,45 @@
m_sourceBufferWithSelectedVideo->setDecompressionSession(decompressionSession);
}
+#if ENABLE(ENCRYPTED_MEDIA)
+void MediaSourcePrivateAVFObjC::cdmInstanceAttached(CDMInstance& instance)
+{
+ ASSERT(!m_cdmInstance);
+ m_cdmInstance = &instance;
+ for (auto& sourceBuffer : m_sourceBuffers)
+ sourceBuffer->setCDMInstance(&instance);
+}
+
+void MediaSourcePrivateAVFObjC::cdmInstanceDetached(CDMInstance& instance)
+{
+ ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
+ for (auto& sourceBuffer : m_sourceBuffers)
+ sourceBuffer->setCDMInstance(nullptr);
+
+ m_cdmInstance = nullptr;
+}
+
+void MediaSourcePrivateAVFObjC::attemptToDecryptWithInstance(CDMInstance& instance)
+{
+ ASSERT_UNUSED(instance, m_cdmInstance && m_cdmInstance == &instance);
+ for (auto& sourceBuffer : m_sourceBuffers)
+ sourceBuffer->attemptToDecrypt();
+}
+
+bool MediaSourcePrivateAVFObjC::waitingForKey() const
+{
+ return anyOf(m_sourceBuffers, [] (auto& sourceBuffer) {
+ return sourceBuffer->waitingForKey();
+ });
+}
+
+void MediaSourcePrivateAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
+{
+ if (m_cdmInstance)
+ m_cdmInstance->setHDCPStatus(obscured ? CDMInstance::HDCPStatus::OutputRestricted : CDMInstance::HDCPStatus::Valid);
+}
+#endif
+
void MediaSourcePrivateAVFObjC::setSourceBufferWithSelectedVideo(SourceBufferPrivateAVFObjC* sourceBuffer)
{
if (m_sourceBufferWithSelectedVideo) {
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h 2018-10-31 20:23:38 UTC (rev 237649)
@@ -66,6 +66,7 @@
class AudioTrackPrivateMediaSourceAVFObjC;
class VideoTrackPrivateMediaSourceAVFObjC;
class WebCoreDecompressionSession;
+class SharedBuffer;
class SourceBufferPrivateAVFObjCErrorClient {
public:
@@ -184,6 +185,7 @@
#endif
#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
RefPtr<CDMInstanceFairPlayStreamingAVFObjC> m_cdmInstance;
+ Vector<Ref<SharedBuffer>> m_keyIDs;
#endif
std::optional<FloatSize> m_cachedSize;
Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (237648 => 237649)
--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2018-10-31 20:16:49 UTC (rev 237648)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm 2018-10-31 20:23:38 UTC (rev 237649)
@@ -30,6 +30,7 @@
#import "AVAssetTrackUtilities.h"
#import "AudioTrackPrivateMediaSourceAVFObjC.h"
+#import "CDMFairPlayStreaming.h"
#import "CDMInstanceFairPlayStreamingAVFObjC.h"
#import "CDMSessionAVContentKeySession.h"
#import "CDMSessionMediaSourceAVFObjC.h"
@@ -665,11 +666,27 @@
#endif
#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
- if (m_mediaSource) {
- auto initDataBuffer = SharedBuffer::create(initData);
- m_mediaSource->player()->initializationDataEncountered("sinf", initDataBuffer->tryCreateArrayBuffer());
+ //
+ auto initDataBuffer = SharedBuffer::create(initData);
+ auto keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(initDataBuffer);
+ if (!keyIDs)
+ return;
+
+ if (m_cdmInstance) {
+ if (auto instanceSession = m_cdmInstance->sessionForKeyIDs(keyIDs.value())) {
+ [instanceSession->contentKeySession() addContentKeyRecipient:m_parser.get()];
+ if (m_hasSessionSemaphore) {
+ m_hasSessionSemaphore->signal();
+ m_hasSessionSemaphore = nullptr;
+ }
+ m_waitingForKey = false;
+ return;
+ }
}
+ m_keyIDs = WTFMove(keyIDs.value());
+ m_mediaSource->player()->initializationDataEncountered("sinf", initDataBuffer->tryCreateArrayBuffer());
+
m_waitingForKey = true;
m_mediaSource->player()->waitingForKeyChanged();
#endif
@@ -758,8 +775,10 @@
[m_mediaSource->player()->streamSession() removeStreamDataParser:m_parser.get()];
#endif
#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
- if (m_cdmInstance)
- [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_parser.get()];
+ if (m_cdmInstance) {
+ if (auto instanceSession = m_cdmInstance->sessionForKeyIDs(m_keyIDs))
+ [instanceSession->contentKeySession() removeContentKeyRecipient:m_parser.get()];
+ }
#endif
[m_delegate invalidate];
@@ -918,25 +937,32 @@
{
#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
auto* fpsInstance = downcast<CDMInstanceFairPlayStreamingAVFObjC>(instance);
- if (!fpsInstance || fpsInstance == m_cdmInstance)
+ if (fpsInstance == m_cdmInstance)
return;
- if (m_cdmInstance)
- [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_parser.get()];
-
m_cdmInstance = fpsInstance;
+ attemptToDecrypt();
+#else
+ UNUSED_PARAM(instance);
+#endif
+}
- if (m_cdmInstance) {
- [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_parser.get()];
- if (m_hasSessionSemaphore) {
- m_hasSessionSemaphore->signal();
- m_hasSessionSemaphore = nullptr;
- }
+void SourceBufferPrivateAVFObjC::attemptToDecrypt()
+{
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+ if (!m_cdmInstance || m_keyIDs.isEmpty() || !m_waitingForKey)
+ return;
+
+ auto instanceSession = m_cdmInstance->sessionForKeyIDs(m_keyIDs);
+ if (!instanceSession)
+ return;
+
+ [instanceSession->contentKeySession() addContentKeyRecipient:m_parser.get()];
+ if (m_hasSessionSemaphore) {
+ m_hasSessionSemaphore->signal();
+ m_hasSessionSemaphore = nullptr;
}
m_waitingForKey = false;
- m_mediaSource->player()->waitingForKeyChanged();
-#else
- UNUSED_PARAM(instance);
#endif
}
@@ -983,9 +1009,8 @@
void SourceBufferPrivateAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
{
#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
- auto player = m_mediaSource ? m_mediaSource->player() : nullptr;
- if (player && player->cdmInstance()) {
- player->outputObscuredDueToInsufficientExternalProtectionChanged(obscured);
+ if (m_mediaSource->cdmInstance()) {
+ m_mediaSource->outputObscuredDueToInsufficientExternalProtectionChanged(obscured);
return;
}
#else