Title: [174460] trunk/Source/WebCore
Revision
174460
Author
jer.no...@apple.com
Date
2014-10-08 10:32:41 -0700 (Wed, 08 Oct 2014)

Log Message

[EME][Mac] Update CDMSessionMediaSourceAVFObjC to match new API provided by AVStreamSession
https://bugs.webkit.org/show_bug.cgi?id=137469

Reviewed by Brent Fulgham.

Update our forward declaration to match the API provided by AVStreamSession.
AVStreamSession now takes an error: parameter in its initialiazer. It also provides the
sessionIdentifier used by the CDM, which CDMSessionMediaSourceAVFObjC will use as the
value of sessionId. Having this identifier allows us to fire a
secure-proof-of-key-release message after the client calls MediaKeySession.close().
Because this call will now generate messages, which have to be responded to in order
to remove those proofs from storage, do not clear the CDMSession from MediaKeySession
after calling close().

* Modules/encryptedmedia/MediaKeySession.cpp:
(WebCore::MediaKeySession::~MediaKeySession):
(WebCore::MediaKeySession::close):
(WebCore::MediaKeySession::setError): Deleted.
(WebCore::MediaKeySession::sessionId): Deleted.
* platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h:
(WebCore::CDMSessionMediaSourceAVFObjC::setSessionId):
* platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm:
(-[CDMSessionMediaSourceAVFObjCListener initWithParent:]):
(-[CDMSessionMediaSourceAVFObjCObserver dealloc]):
(-[CDMSessionMediaSourceAVFObjCObserver beginObserving:]):
(-[CDMSessionMediaSourceAVFObjCObserver stopObserving:]):
(-[CDMSessionMediaSourceAVFObjCObserver invalidate]):
(-[CDMSessionMediaSourceAVFObjCListener observeValueForKeyPath:ofObject:change:context:]):
(WebCore::CDMSessionMediaSourceAVFObjC::CDMSessionMediaSourceAVFObjC):
(WebCore::CDMSessionMediaSourceAVFObjC::~CDMSessionMediaSourceAVFObjC):
(WebCore::CDMSessionMediaSourceAVFObjC::releaseKeys):
(WebCore::CDMSessionMediaSourceAVFObjC::update):
(WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer):
(WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (174459 => 174460)


--- trunk/Source/WebCore/ChangeLog	2014-10-08 17:20:32 UTC (rev 174459)
+++ trunk/Source/WebCore/ChangeLog	2014-10-08 17:32:41 UTC (rev 174460)
@@ -1,3 +1,40 @@
+2014-10-07  Jer Noble  <jer.no...@apple.com>
+
+        [EME][Mac] Update CDMSessionMediaSourceAVFObjC to match new API provided by AVStreamSession
+        https://bugs.webkit.org/show_bug.cgi?id=137469
+
+        Reviewed by Brent Fulgham.
+
+        Update our forward declaration to match the API provided by AVStreamSession.
+        AVStreamSession now takes an error: parameter in its initialiazer. It also provides the
+        sessionIdentifier used by the CDM, which CDMSessionMediaSourceAVFObjC will use as the
+        value of sessionId. Having this identifier allows us to fire a
+        secure-proof-of-key-release message after the client calls MediaKeySession.close().
+        Because this call will now generate messages, which have to be responded to in order
+        to remove those proofs from storage, do not clear the CDMSession from MediaKeySession
+        after calling close().
+
+        * Modules/encryptedmedia/MediaKeySession.cpp:
+        (WebCore::MediaKeySession::~MediaKeySession):
+        (WebCore::MediaKeySession::close):
+        (WebCore::MediaKeySession::setError): Deleted.
+        (WebCore::MediaKeySession::sessionId): Deleted.
+        * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h:
+        (WebCore::CDMSessionMediaSourceAVFObjC::setSessionId):
+        * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm:
+        (-[CDMSessionMediaSourceAVFObjCListener initWithParent:]):
+        (-[CDMSessionMediaSourceAVFObjCObserver dealloc]):
+        (-[CDMSessionMediaSourceAVFObjCObserver beginObserving:]):
+        (-[CDMSessionMediaSourceAVFObjCObserver stopObserving:]):
+        (-[CDMSessionMediaSourceAVFObjCObserver invalidate]):
+        (-[CDMSessionMediaSourceAVFObjCListener observeValueForKeyPath:ofObject:change:context:]):
+        (WebCore::CDMSessionMediaSourceAVFObjC::CDMSessionMediaSourceAVFObjC):
+        (WebCore::CDMSessionMediaSourceAVFObjC::~CDMSessionMediaSourceAVFObjC):
+        (WebCore::CDMSessionMediaSourceAVFObjC::releaseKeys):
+        (WebCore::CDMSessionMediaSourceAVFObjC::update):
+        (WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer):
+        (WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer):
+
 2014-10-08  Chris Dumez  <cdu...@apple.com>
 
         Unreviewed build fix after r174456.

Modified: trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp (174459 => 174460)


--- trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2014-10-08 17:20:32 UTC (rev 174459)
+++ trunk/Source/WebCore/Modules/encryptedmedia/MediaKeySession.cpp	2014-10-08 17:32:41 UTC (rev 174460)
@@ -59,7 +59,12 @@
 
 MediaKeySession::~MediaKeySession()
 {
-    close();
+    if (m_session) {
+        m_session->setClient(nullptr);
+        m_session = nullptr;
+    }
+
+    m_asyncEventQueue.cancelAllEvents();
 }
 
 void MediaKeySession::setError(MediaKeyError* error)
@@ -69,12 +74,8 @@
 
 void MediaKeySession::close()
 {
-    if (m_session) {
+    if (m_session)
         m_session->releaseKeys();
-        m_session->setClient(nullptr);
-    }
-    m_session = nullptr;
-    m_asyncEventQueue.cancelAllEvents();
 }
 
 const String& MediaKeySession::sessionId() const

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h (174459 => 174460)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h	2014-10-08 17:20:32 UTC (rev 174459)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h	2014-10-08 17:32:41 UTC (rev 174460)
@@ -34,6 +34,7 @@
 #if ENABLE(ENCRYPTED_MEDIA_V2) && ENABLE(MEDIA_SOURCE)
 
 OBJC_CLASS AVStreamSession;
+OBJC_CLASS CDMSessionMediaSourceAVFObjCObserver;
 
 namespace WebCore {
 
@@ -55,6 +56,8 @@
     void addSourceBuffer(SourceBufferPrivateAVFObjC*);
     void removeSourceBuffer(SourceBufferPrivateAVFObjC*);
 
+    void setSessionId(const String& sessionId) { m_sessionId = sessionId; }
+
 protected:
     PassRefPtr<Uint8Array> generateKeyReleaseMessage(unsigned short& errorCode, unsigned long& systemCode);
 
@@ -64,6 +67,7 @@
     RefPtr<Uint8Array> m_initData;
     RefPtr<Uint8Array> m_certificate;
     RetainPtr<NSData> m_expiredSession;
+    RetainPtr<CDMSessionMediaSourceAVFObjCObserver> m_dataParserObserver;
     String m_sessionId;
     enum { Normal, KeyRelease } m_mode;
 };

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm (174459 => 174460)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm	2014-10-08 17:20:32 UTC (rev 174459)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm	2014-10-08 17:32:41 UTC (rev 174460)
@@ -51,10 +51,11 @@
 - (void)processContentKeyResponseError:(NSError *)error forTrackID:(CMPersistentTrackID)trackID;
 - (void)renewExpiringContentKeyResponseDataForTrackID:(CMPersistentTrackID)trackID;
 - (NSData *)streamingContentKeyRequestDataForApp:(NSData *)appIdentifier contentIdentifier:(NSData *)contentIdentifier trackID:(CMPersistentTrackID)trackID options:(NSDictionary *)options error:(NSError **)outError;
+- (NSData *)sessionIdentifier;
 @end
 
 @interface AVStreamSession : NSObject
-- (instancetype)initWithAppIdentifier:(NSData *)appIdentifier storageDirectoryAtURL:(NSURL *)storageURL;
+- (instancetype)initWithAppIdentifier:(NSData *)appIdentifier storageDirectoryAtURL:(NSURL *)storageURL error:(NSError **)outError;
 - (void)addStreamDataParser:(AVStreamDataParser *)streamDataParser;
 - (void)removeStreamDataParser:(AVStreamDataParser *)streamDataParser;
 - (void)expire;
@@ -62,22 +63,89 @@
 + (void)removePendingExpiredSessionReports:(NSArray *)expiredSessionReports withAppIdentifier:(NSData *)appIdentifier;
 @end
 
+@interface CDMSessionMediaSourceAVFObjCObserver : NSObject {
+    WebCore::CDMSessionMediaSourceAVFObjC *m_parent;
+    HashSet<RetainPtr<AVStreamDataParser>> m_parsers;
+}
+@end
+
+@implementation CDMSessionMediaSourceAVFObjCObserver
+- (id)initWithParent:(WebCore::CDMSessionMediaSourceAVFObjC *)parent
+{
+    if ((self = [super init]))
+        m_parent = parent;
+    return self;
+}
+
+- (void)dealloc
+{
+    [self invalidate];
+    [super dealloc];
+}
+
+- (void)beginObserving:(AVStreamDataParser *)parser
+{
+    ASSERT(!m_parsers.contains(parser));
+    m_parsers.add(parser);
+    [parser addObserver:self forKeyPath:@"sessionIdentifier" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial) context:nullptr];
+}
+
+- (void)stopObserving:(AVStreamDataParser *)parser
+{
+    ASSERT(m_parsers.contains(parser));
+    m_parsers.remove(parser);
+    [parser removeObserver:self forKeyPath:@"sessionIdentifier" context:nullptr];
+}
+
+- (void)invalidate
+{
+    m_parent = nullptr;
+    for (auto& parser : m_parsers)
+        [parser removeObserver:self forKeyPath:@"sessionIdentifier" context:nullptr];
+    m_parsers.clear();
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context
+{
+    UNUSED_PARAM(object);
+    UNUSED_PARAM(change);
+    UNUSED_PARAM(context);
+
+    if ([keyPath isEqual:@"sessionIdentifier"]) {
+        NSData* identifier = [change valueForKey:NSKeyValueChangeNewKey];
+        if ([identifier isKindOfClass:[NSNull class]])
+            return;
+
+        RetainPtr<NSString> sessionIdentifierString = adoptNS([[NSString alloc] initWithData:identifier encoding:(NSUTF8StringEncoding)]);
+        if (m_parent)
+            m_parent->setSessionId(sessionIdentifierString.get());
+        return;
+    }
+
+    ASSERT_NOT_REACHED();
+}
+@end
+
 namespace WebCore {
 
 CDMSessionMediaSourceAVFObjC::CDMSessionMediaSourceAVFObjC()
     : m_client(nullptr)
-    , m_sessionId(createCanonicalUUIDString())
+    , m_dataParserObserver(adoptNS([[CDMSessionMediaSourceAVFObjCObserver alloc] initWithParent:this]))
     , m_mode(Normal)
 {
 }
 
 CDMSessionMediaSourceAVFObjC::~CDMSessionMediaSourceAVFObjC()
 {
-    if (m_streamSession) {
-        for (auto& sourceBuffer : m_sourceBuffers)
+    for (auto& sourceBuffer : m_sourceBuffers) {
+        if (m_streamSession)
             [m_streamSession removeStreamDataParser:sourceBuffer->parser()];
-        m_streamSession = nil;
+
+        [sourceBuffer->parser() removeObserver:m_dataParserObserver.get() forKeyPath:@"sessionIdentifier" context:nullptr];
     }
+
+    m_streamSession = nil;
+    [m_dataParserObserver invalidate];
 }
 
 PassRefPtr<Uint8Array> CDMSessionMediaSourceAVFObjC::generateKeyRequest(const String& mimeType, Uint8Array* initData, String& destinationURL, unsigned short& errorCode, unsigned long& systemCode)
@@ -107,15 +175,20 @@
 
 void CDMSessionMediaSourceAVFObjC::releaseKeys()
 {
-    if (m_mode == KeyRelease) {
-        RetainPtr<NSData> certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate->data() length:m_certificate->length()]);
-        [getAVStreamSessionClass() removePendingExpiredSessionReports:@[m_expiredSession.get()] withAppIdentifier:certificateData.get()];
-        return;
-    }
-
     if (m_streamSession) {
         LOG(Media, "CDMSessionMediaSourceAVFObjC::releaseKeys(%p) - expiring stream session", this);
         [m_streamSession expire];
+
+        RetainPtr<NSData> certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate->data() length:m_certificate->length()]);
+        NSArray* expiredSessions = [getAVStreamSessionClass() pendingExpiredSessionReportsWithAppIdentifier:certificateData.get()];
+        for (NSData* expiredSessionData in expiredSessions) {
+            NSDictionary *expiredSession = [NSPropertyListSerialization propertyListWithData:expiredSessionData options:kCFPropertyListImmutable format:nullptr error:nullptr];
+            if ([expiredSession objectForKey:m_sessionId]) {
+                m_expiredSession = expiredSessionData;
+                m_client->sendMessage(Uint8Array::create(static_cast<const uint8_t*>([m_expiredSession bytes]), [m_expiredSession length]).get(), emptyString());
+                break;
+            }
+        }
     }
 }
 
@@ -163,6 +236,17 @@
         m_certificate = key;
     }
 
+    if (isEqual(key, "acknowledged")) {
+        if (!m_expiredSession) {
+            errorCode = MediaPlayer::InvalidPlayerState;
+            return false;
+        }
+
+        RetainPtr<NSData> certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate->data() length:m_certificate->length()]);
+        [getAVStreamSessionClass() removePendingExpiredSessionReports:@[m_expiredSession.get()] withAppIdentifier:certificateData.get()];
+        m_expiredSession = nullptr;
+    }
+
     RefPtr<SourceBufferPrivateAVFObjC> protectedSourceBuffer;
     for (auto& sourceBuffer : m_sourceBuffers) {
         if (sourceBuffer->protectedTrackID() != -1) {
@@ -173,8 +257,8 @@
 
     if (shouldGenerateKeyRequest) {
         RetainPtr<NSData> certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate->data() length:m_certificate->length()]);
-        if (getAVStreamSessionClass()) {
-            m_streamSession = adoptNS([[getAVStreamSessionClass() alloc] initWithAppIdentifier:certificateData.get() storageDirectoryAtURL:[NSURL fileURLWithPath:sessionStorageDirectory()]]);
+        if (getAVStreamSessionClass() && [getAVStreamSessionClass() instancesRespondToSelector:@selector(initWithAppIdentifier:storageDirectoryAtURL:error:)]) {
+            m_streamSession = adoptNS([[getAVStreamSessionClass() alloc] initWithAppIdentifier:certificateData.get() storageDirectoryAtURL:[NSURL fileURLWithPath:sessionStorageDirectory()] error:nil]);
             for (auto& sourceBuffer : m_sourceBuffers)
                 [m_streamSession addStreamDataParser:sourceBuffer->parser()];
             LOG(Media, "CDMSessionMediaSourceAVFObjC::update(%p) - created stream session %p", this, m_streamSession.get());
@@ -191,6 +275,9 @@
         NSError* error = nil;
         RetainPtr<NSData> request = [protectedSourceBuffer->parser() streamingContentKeyRequestDataForApp:certificateData.get() contentIdentifier:initData.get() trackID:protectedSourceBuffer->protectedTrackID() options:nil error:&error];
 
+        if (![protectedSourceBuffer->parser() respondsToSelector:@selector(sessionIdentifier)])
+            m_sessionId = createCanonicalUUIDString();
+
         if (error) {
             LOG(Media, "CDMSessionMediaSourceAVFObjC::update(%p) - error:%@", this, [error description]);
             errorCode = MediaPlayer::InvalidPlayerState;
@@ -209,6 +296,7 @@
     systemCode = 0;
     RetainPtr<NSData> keyData = adoptNS([[NSData alloc] initWithBytes:key->data() length:key->length()]);
     [protectedSourceBuffer->parser() processContentKeyResponseData:keyData.get() forTrackID:protectedSourceBuffer->protectedTrackID()];
+
     return true;
 }
 
@@ -238,6 +326,8 @@
 
     if (m_streamSession)
         [m_streamSession addStreamDataParser:sourceBuffer->parser()];
+
+    [m_dataParserObserver beginObserving:sourceBuffer->parser()];
 }
 
 void CDMSessionMediaSourceAVFObjC::removeSourceBuffer(SourceBufferPrivateAVFObjC* sourceBuffer)
@@ -250,6 +340,8 @@
 
     sourceBuffer->unregisterForErrorNotifications(this);
     m_sourceBuffers.remove(m_sourceBuffers.find(sourceBuffer));
+
+    [m_dataParserObserver stopObserving:sourceBuffer->parser()];
 }
 
 PassRefPtr<Uint8Array> CDMSessionMediaSourceAVFObjC::generateKeyReleaseMessage(unsigned short& errorCode, unsigned long& systemCode)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to