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)