<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[175000] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/175000">175000</a></dd>
<dt>Author</dt> <dd>jer.noble@apple.com</dd>
<dt>Date</dt> <dd>2014-10-21 16:06:59 -0700 (Tue, 21 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>[EME][Mac] Update to match new AVStreamSession API and requirements.
https://bugs.webkit.org/show_bug.cgi?id=137923

Reviewed by Eric Carlson.

The session identifier has moved from AVStreamDataParser to -[AVStreamSession contentProtectionSessionIdentifier]
and the property is no longer KVObservable. A new notification key has been added in place of KVO.

Additionally, the requirements for using AVStreamDataParser with AVStreamSession have changed. It is now
required that AVStreamDataParsers be added to an AVStreamSession before the
-streamSession:didProvideContentKeyRequestInitializationData:forTrackID delegate method is called. A
-streamParserWillProvideContentKeyRequestInitializationData:forTrackID delegate has been added, and
an AVStreamSession must be created and the AVStreamDataParser added to it during the scope of that delegate
method.

To facilitate this, the MediaPlayerPrivateMediaSourceAVFObjC object will lazily create and own a AVStreamSession
object when requested. The SourceBufferPrivateAVFObjC object will listen for the -willProvide delegate call
and will add its AVStreamDataParser to that AVStreamSession when called.

The CDMSessionMediaSourceAVFObjC object is no longer responsible for creating the AVStreamSession, and because
the session identifier has moved from many AVStreamDataParsers to a single AVStreamSession, the
CDMSessionMediaSourceAVFObjCObserver class can become much simpler, as it only has to observe a single object.

* platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h:
* platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm:
(-[CDMSessionMediaSourceAVFObjCObserver dealloc]): Deleted.
(-[CDMSessionMediaSourceAVFObjCObserver beginObserving:]): Deleted.
(-[CDMSessionMediaSourceAVFObjCObserver stopObserving:]): Deleted.
(-[CDMSessionMediaSourceAVFObjCObserver invalidate]): Deleted.
(-[CDMSessionMediaSourceAVFObjCObserver observeValueForKeyPath:ofObject:change:context:]): Deleted.
(-[CDMSessionMediaSourceAVFObjCObserver contentProtectionSessionIdentifierChanged:]): Added.
(WebCore::CDMSessionMediaSourceAVFObjC::~CDMSessionMediaSourceAVFObjC): Call setStreamSession(nullptr).
(WebCore::CDMSessionMediaSourceAVFObjC::releaseKeys): The sessionId is now a value in the dictionary, not the key.
(WebCore::CDMSessionMediaSourceAVFObjC::update): No longer create an AVStreamSession.
(WebCore::CDMSessionMediaSourceAVFObjC::setStreamSession): Add and remove observers as appropriate.
(WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer): No longer add or remove parsers from AVStreamSessions.
(WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer): Ditto.
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::hasStreamSession): Simple getter.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::streamSession): Lazy initializing getter.
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::setCDMSession): Call setStreamSession().
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(-[WebAVStreamDataParserListener streamParserWillProvideContentKeyRequestInitializationData:forTrackID:]): Synchronously pass to SourceBufferPrivateAVFObjC.
(WebCore::SourceBufferPrivateAVFObjC::willProvideContentKeyRequestInitializationDataForTrackID): Add the parser to an AVStreamSession.
(WebCore::SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID): Check the trackId.
* platform/mac/SoftLinking.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcCDMSessionMediaSourceAVFObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcCDMSessionMediaSourceAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh">trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h</a></li>
<li><a href="#trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm">trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm</a></li>
<li><a href="#trunkSourceWebCoreplatformmacSoftLinkingh">trunk/Source/WebCore/platform/mac/SoftLinking.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/ChangeLog        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -1,3 +1,54 @@
</span><ins>+2014-10-21  Jer Noble  &lt;jer.noble@apple.com&gt;
+
+        [EME][Mac] Update to match new AVStreamSession API and requirements.
+        https://bugs.webkit.org/show_bug.cgi?id=137923
+
+        Reviewed by Eric Carlson.
+
+        The session identifier has moved from AVStreamDataParser to -[AVStreamSession contentProtectionSessionIdentifier]
+        and the property is no longer KVObservable. A new notification key has been added in place of KVO.
+
+        Additionally, the requirements for using AVStreamDataParser with AVStreamSession have changed. It is now
+        required that AVStreamDataParsers be added to an AVStreamSession before the 
+        -streamSession:didProvideContentKeyRequestInitializationData:forTrackID delegate method is called. A
+        -streamParserWillProvideContentKeyRequestInitializationData:forTrackID delegate has been added, and
+        an AVStreamSession must be created and the AVStreamDataParser added to it during the scope of that delegate
+        method.
+
+        To facilitate this, the MediaPlayerPrivateMediaSourceAVFObjC object will lazily create and own a AVStreamSession
+        object when requested. The SourceBufferPrivateAVFObjC object will listen for the -willProvide delegate call
+        and will add its AVStreamDataParser to that AVStreamSession when called.
+
+        The CDMSessionMediaSourceAVFObjC object is no longer responsible for creating the AVStreamSession, and because
+        the session identifier has moved from many AVStreamDataParsers to a single AVStreamSession, the
+        CDMSessionMediaSourceAVFObjCObserver class can become much simpler, as it only has to observe a single object.
+
+        * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h:
+        * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm:
+        (-[CDMSessionMediaSourceAVFObjCObserver dealloc]): Deleted.
+        (-[CDMSessionMediaSourceAVFObjCObserver beginObserving:]): Deleted.
+        (-[CDMSessionMediaSourceAVFObjCObserver stopObserving:]): Deleted.
+        (-[CDMSessionMediaSourceAVFObjCObserver invalidate]): Deleted.
+        (-[CDMSessionMediaSourceAVFObjCObserver observeValueForKeyPath:ofObject:change:context:]): Deleted.
+        (-[CDMSessionMediaSourceAVFObjCObserver contentProtectionSessionIdentifierChanged:]): Added.
+        (WebCore::CDMSessionMediaSourceAVFObjC::~CDMSessionMediaSourceAVFObjC): Call setStreamSession(nullptr).
+        (WebCore::CDMSessionMediaSourceAVFObjC::releaseKeys): The sessionId is now a value in the dictionary, not the key.
+        (WebCore::CDMSessionMediaSourceAVFObjC::update): No longer create an AVStreamSession.
+        (WebCore::CDMSessionMediaSourceAVFObjC::setStreamSession): Add and remove observers as appropriate.
+        (WebCore::CDMSessionMediaSourceAVFObjC::addSourceBuffer): No longer add or remove parsers from AVStreamSessions.
+        (WebCore::CDMSessionMediaSourceAVFObjC::removeSourceBuffer): Ditto.
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::hasStreamSession): Simple getter.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::streamSession): Lazy initializing getter.
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::setCDMSession): Call setStreamSession().
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (-[WebAVStreamDataParserListener streamParserWillProvideContentKeyRequestInitializationData:forTrackID:]): Synchronously pass to SourceBufferPrivateAVFObjC.
+        (WebCore::SourceBufferPrivateAVFObjC::willProvideContentKeyRequestInitializationDataForTrackID): Add the parser to an AVStreamSession.
+        (WebCore::SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID): Check the trackId.
+        * platform/mac/SoftLinking.h:
+
</ins><span class="cx"> 2014-10-21  Jaehun Lim  &lt;ljaehun.lim@samsung.com&gt;
</span><span class="cx"> 
</span><span class="cx">         'true' isn't a valid value for justify-self
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcCDMSessionMediaSourceAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -53,6 +53,8 @@
</span><span class="cx">     virtual void layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *);
</span><span class="cx">     virtual void rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *);
</span><span class="cx"> 
</span><ins>+    void setStreamSession(AVStreamSession *);
+
</ins><span class="cx">     void addSourceBuffer(SourceBufferPrivateAVFObjC*);
</span><span class="cx">     void removeSourceBuffer(SourceBufferPrivateAVFObjC*);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcCDMSessionMediaSourceAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -45,27 +45,27 @@
</span><span class="cx"> SOFT_LINK_FRAMEWORK_OPTIONAL(AVFoundation)
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVStreamDataParser);
</span><span class="cx"> SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVStreamSession);
</span><ins>+SOFT_LINK_CONSTANT_MAY_FAIL(AVFoundation, AVStreamSessionContentProtectionSessionIdentifierChangedNotification, NSString *);
</ins><span class="cx"> 
</span><span class="cx"> @interface AVStreamDataParser : NSObject
</span><span class="cx"> - (void)processContentKeyResponseData:(NSData *)contentKeyResponseData forTrackID:(CMPersistentTrackID)trackID;
</span><span class="cx"> - (void)processContentKeyResponseError:(NSError *)error forTrackID:(CMPersistentTrackID)trackID;
</span><span class="cx"> - (void)renewExpiringContentKeyResponseDataForTrackID:(CMPersistentTrackID)trackID;
</span><span class="cx"> - (NSData *)streamingContentKeyRequestDataForApp:(NSData *)appIdentifier contentIdentifier:(NSData *)contentIdentifier trackID:(CMPersistentTrackID)trackID options:(NSDictionary *)options error:(NSError **)outError;
</span><del>-- (NSData *)sessionIdentifier;
</del><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @interface AVStreamSession : NSObject
</span><del>-- (instancetype)initWithAppIdentifier:(NSData *)appIdentifier storageDirectoryAtURL:(NSURL *)storageURL error:(NSError **)outError;
</del><ins>+- (BOOL)setStorageDirectoryAtURL:(NSURL *)storageURL appIdentifier:(NSData *)appIdentifier error:(NSError **)outError;
</ins><span class="cx"> - (void)addStreamDataParser:(AVStreamDataParser *)streamDataParser;
</span><span class="cx"> - (void)removeStreamDataParser:(AVStreamDataParser *)streamDataParser;
</span><span class="cx"> - (void)expire;
</span><ins>+- (NSData *)contentProtectionSessionIdentifier;
</ins><span class="cx"> + (NSArray *)pendingExpiredSessionReportsWithAppIdentifier:(NSData *)appIdentifier;
</span><span class="cx"> + (void)removePendingExpiredSessionReports:(NSArray *)expiredSessionReports withAppIdentifier:(NSData *)appIdentifier;
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @interface CDMSessionMediaSourceAVFObjCObserver : NSObject {
</span><span class="cx">     WebCore::CDMSessionMediaSourceAVFObjC *m_parent;
</span><del>-    HashSet&lt;RetainPtr&lt;AVStreamDataParser&gt;&gt; m_parsers;
</del><span class="cx"> }
</span><span class="cx"> @end
</span><span class="cx"> 
</span><span class="lines">@@ -77,59 +77,20 @@
</span><span class="cx">     return self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (void)dealloc
</del><ins>+- (void)contentProtectionSessionIdentifierChanged:(NSNotification *)notification
</ins><span class="cx"> {
</span><del>-    [self invalidate];
-    [super dealloc];
-}
</del><ins>+    AVStreamSession* streamSession = (AVStreamSession*)[notification object];
</ins><span class="cx"> 
</span><del>-- (void)beginObserving:(AVStreamDataParser *)parser
-{
-    ASSERT(!m_parsers.contains(parser));
-    m_parsers.add(parser);
-    if ([parser respondsToSelector:@selector(sessionIdentifier)])
-        [parser addObserver:self forKeyPath:@&quot;sessionIdentifier&quot; options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionInitial) context:nullptr];
-}
</del><ins>+    NSData* identifier = [streamSession contentProtectionSessionIdentifier];
+    RetainPtr&lt;NSString&gt; sessionIdentifierString = identifier ? adoptNS([[NSString alloc] initWithData:identifier encoding:NSUTF8StringEncoding]) : nil;
</ins><span class="cx"> 
</span><del>-- (void)stopObserving:(AVStreamDataParser *)parser
-{
-    ASSERT(m_parsers.contains(parser));
-    m_parsers.remove(parser);
-    if ([parser respondsToSelector:@selector(sessionIdentifier)])
-        [parser removeObserver:self forKeyPath:@&quot;sessionIdentifier&quot; context:nullptr];
</del><ins>+    if (m_parent)
+        m_parent-&gt;setSessionId(sessionIdentifierString.get());
</ins><span class="cx"> }
</span><del>-
-- (void)invalidate
-{
-    m_parent = nullptr;
-    for (auto&amp; parser : m_parsers) {
-        if ([parser respondsToSelector:@selector(sessionIdentifier)])
-            [parser removeObserver:self forKeyPath:@&quot;sessionIdentifier&quot; 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:@&quot;sessionIdentifier&quot;]) {
-        NSData* identifier = [change valueForKey:NSKeyValueChangeNewKey];
-        if ([identifier isKindOfClass:[NSNull class]])
-            return;
-
-        RetainPtr&lt;NSString&gt; sessionIdentifierString = adoptNS([[NSString alloc] initWithData:identifier encoding:(NSUTF8StringEncoding)]);
-        if (m_parent)
-            m_parent-&gt;setSessionId(sessionIdentifierString.get());
-        return;
-    }
-
-    ASSERT_NOT_REACHED();
-}
</del><span class="cx"> @end
</span><span class="cx"> 
</span><ins>+static const NSString *PlaybackSessionIdKey = @&quot;PlaybackSessionID&quot;;
+
</ins><span class="cx"> namespace WebCore {
</span><span class="cx"> 
</span><span class="cx"> CDMSessionMediaSourceAVFObjC::CDMSessionMediaSourceAVFObjC()
</span><span class="lines">@@ -144,12 +105,9 @@
</span><span class="cx">     for (auto&amp; sourceBuffer : m_sourceBuffers) {
</span><span class="cx">         if (m_streamSession)
</span><span class="cx">             [m_streamSession removeStreamDataParser:sourceBuffer-&gt;parser()];
</span><del>-
-        [sourceBuffer-&gt;parser() removeObserver:m_dataParserObserver.get() forKeyPath:@&quot;sessionIdentifier&quot; context:nullptr];
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    m_streamSession = nil;
-    [m_dataParserObserver invalidate];
</del><ins>+    setStreamSession(nullptr);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;Uint8Array&gt; CDMSessionMediaSourceAVFObjC::generateKeyRequest(const String&amp; mimeType, Uint8Array* initData, String&amp; destinationURL, unsigned short&amp; errorCode, unsigned long&amp; systemCode)
</span><span class="lines">@@ -187,7 +145,12 @@
</span><span class="cx">         NSArray* expiredSessions = [getAVStreamSessionClass() pendingExpiredSessionReportsWithAppIdentifier:certificateData.get()];
</span><span class="cx">         for (NSData* expiredSessionData in expiredSessions) {
</span><span class="cx">             NSDictionary *expiredSession = [NSPropertyListSerialization propertyListWithData:expiredSessionData options:kCFPropertyListImmutable format:nullptr error:nullptr];
</span><del>-            if ([expiredSession objectForKey:m_sessionId]) {
</del><ins>+            NSString *playbackSessionIdValue = (NSString *)[expiredSession objectForKey:PlaybackSessionIdKey];
+            if (![playbackSessionIdValue isKindOfClass:[NSString class]])
+                continue;
+
+            if (m_sessionId == String(playbackSessionIdValue)) {
+                LOG(Media, &quot;CDMSessionMediaSourceAVFObjC::releaseKeys(%p) - found session, sending expiration message&quot;);
</ins><span class="cx">                 m_expiredSession = expiredSessionData;
</span><span class="cx">                 m_client-&gt;sendMessage(Uint8Array::create(static_cast&lt;const uint8_t*&gt;([m_expiredSession bytes]), [m_expiredSession length]).get(), emptyString());
</span><span class="cx">                 break;
</span><span class="lines">@@ -241,6 +204,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (isEqual(key, &quot;acknowledged&quot;)) {
</span><ins>+        LOG(Media, &quot;CDMSessionMediaSourceAVFObjC::update(%p) - acknowleding secure stop message&quot;, this);
+
</ins><span class="cx">         if (!m_expiredSession) {
</span><span class="cx">             errorCode = MediaPlayer::InvalidPlayerState;
</span><span class="cx">             return false;
</span><span class="lines">@@ -249,6 +214,7 @@
</span><span class="cx">         RetainPtr&lt;NSData&gt; certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate-&gt;data() length:m_certificate-&gt;length()]);
</span><span class="cx">         [getAVStreamSessionClass() removePendingExpiredSessionReports:@[m_expiredSession.get()] withAppIdentifier:certificateData.get()];
</span><span class="cx">         m_expiredSession = nullptr;
</span><ins>+        return true;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RefPtr&lt;SourceBufferPrivateAVFObjC&gt; protectedSourceBuffer;
</span><span class="lines">@@ -261,8 +227,8 @@
</span><span class="cx"> 
</span><span class="cx">     if (shouldGenerateKeyRequest) {
</span><span class="cx">         RetainPtr&lt;NSData&gt; certificateData = adoptNS([[NSData alloc] initWithBytes:m_certificate-&gt;data() length:m_certificate-&gt;length()]);
</span><del>-        if (getAVStreamSessionClass() &amp;&amp; [getAVStreamSessionClass() instancesRespondToSelector:@selector(initWithAppIdentifier:storageDirectoryAtURL:error:)]) {
-            m_streamSession = adoptNS([[getAVStreamSessionClass() alloc] initWithAppIdentifier:certificateData.get() storageDirectoryAtURL:[NSURL fileURLWithPath:sessionStorageDirectory()] error:nil]);
</del><ins>+        if (m_streamSession &amp;&amp; [m_streamSession respondsToSelector:@selector(setStorageDirectoryAtURL:storageURL:appIdentifier:error:)]) {
+            [m_streamSession setStorageDirectoryAtURL:[NSURL fileURLWithPath:sessionStorageDirectory()] appIdentifier:certificateData.get() error:nil];
</ins><span class="cx">             for (auto&amp; sourceBuffer : m_sourceBuffers)
</span><span class="cx">                 [m_streamSession addStreamDataParser:sourceBuffer-&gt;parser()];
</span><span class="cx">             LOG(Media, &quot;CDMSessionMediaSourceAVFObjC::update(%p) - created stream session %p&quot;, this, m_streamSession.get());
</span><span class="lines">@@ -279,7 +245,7 @@
</span><span class="cx">         NSError* error = nil;
</span><span class="cx">         RetainPtr&lt;NSData&gt; request = [protectedSourceBuffer-&gt;parser() streamingContentKeyRequestDataForApp:certificateData.get() contentIdentifier:initData.get() trackID:protectedSourceBuffer-&gt;protectedTrackID() options:nil error:&amp;error];
</span><span class="cx"> 
</span><del>-        if (![protectedSourceBuffer-&gt;parser() respondsToSelector:@selector(sessionIdentifier)])
</del><ins>+        if (![protectedSourceBuffer-&gt;parser() respondsToSelector:@selector(contentProtectionSessionIdentifier)])
</ins><span class="cx">             m_sessionId = createCanonicalUUIDString();
</span><span class="cx"> 
</span><span class="cx">         if (error) {
</span><span class="lines">@@ -320,6 +286,24 @@
</span><span class="cx">     m_client-&gt;sendError(CDMSessionClient::MediaKeyErrorDomain, std::abs([error code]));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void CDMSessionMediaSourceAVFObjC::setStreamSession(AVStreamSession *streamSession)
+{
+    if (m_streamSession &amp;&amp; canLoadAVStreamSessionContentProtectionSessionIdentifierChangedNotification())
+        [[NSNotificationCenter defaultCenter] removeObserver:m_dataParserObserver.get() name:getAVStreamSessionContentProtectionSessionIdentifierChangedNotification() object:m_streamSession.get()];
+
+    m_streamSession = streamSession;
+
+    if (!m_streamSession)
+        return;
+
+    if (canLoadAVStreamSessionContentProtectionSessionIdentifierChangedNotification())
+        [[NSNotificationCenter defaultCenter] addObserver:m_dataParserObserver.get() selector:@selector(contentProtectionSessionIdentifierChanged:) name:getAVStreamSessionContentProtectionSessionIdentifierChangedNotification() object:m_streamSession.get()];
+
+    NSData* identifier = [streamSession contentProtectionSessionIdentifier];
+    RetainPtr&lt;NSString&gt; sessionIdentifierString = identifier ? adoptNS([[NSString alloc] initWithData:identifier encoding:(NSUTF8StringEncoding)]) : nil;
+    setSessionId(sessionIdentifierString.get());
+}
+
</ins><span class="cx"> void CDMSessionMediaSourceAVFObjC::addSourceBuffer(SourceBufferPrivateAVFObjC* sourceBuffer)
</span><span class="cx"> {
</span><span class="cx">     ASSERT(!m_sourceBuffers.contains(sourceBuffer));
</span><span class="lines">@@ -327,11 +311,6 @@
</span><span class="cx"> 
</span><span class="cx">     m_sourceBuffers.append(sourceBuffer);
</span><span class="cx">     sourceBuffer-&gt;registerForErrorNotifications(this);
</span><del>-
-    if (m_streamSession)
-        [m_streamSession addStreamDataParser:sourceBuffer-&gt;parser()];
-
-    [m_dataParserObserver beginObserving:sourceBuffer-&gt;parser()];
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void CDMSessionMediaSourceAVFObjC::removeSourceBuffer(SourceBufferPrivateAVFObjC* sourceBuffer)
</span><span class="lines">@@ -344,8 +323,6 @@
</span><span class="cx"> 
</span><span class="cx">     sourceBuffer-&gt;unregisterForErrorNotifications(this);
</span><span class="cx">     m_sourceBuffers.remove(m_sourceBuffers.find(sourceBuffer));
</span><del>-
-    [m_dataParserObserver stopObserving:sourceBuffer-&gt;parser()];
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> PassRefPtr&lt;Uint8Array&gt; CDMSessionMediaSourceAVFObjC::generateKeyReleaseMessage(unsigned short&amp; errorCode, unsigned long&amp; systemCode)
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -38,6 +38,7 @@
</span><span class="cx"> OBJC_CLASS AVSampleBufferAudioRenderer;
</span><span class="cx"> OBJC_CLASS AVSampleBufferDisplayLayer;
</span><span class="cx"> OBJC_CLASS AVSampleBufferRenderSynchronizer;
</span><ins>+OBJC_CLASS AVStreamSession;
</ins><span class="cx"> 
</span><span class="cx"> typedef struct OpaqueCMTimebase* CMTimebaseRef;
</span><span class="cx"> 
</span><span class="lines">@@ -83,6 +84,8 @@
</span><span class="cx">     void characteristicsChanged();
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ENCRYPTED_MEDIA_V2)
</span><ins>+    bool hasStreamSession() { return m_streamSession; }
+    AVStreamSession *streamSession();
</ins><span class="cx">     virtual void setCDMSession(CDMSession*) override;
</span><span class="cx">     void keyNeeded(Uint8Array*);
</span><span class="cx"> #endif
</span><span class="lines">@@ -191,6 +194,7 @@
</span><span class="cx">     RetainPtr&lt;AVSampleBufferRenderSynchronizer&gt; m_synchronizer;
</span><span class="cx">     RetainPtr&lt;id&gt; m_timeJumpedObserver;
</span><span class="cx">     RetainPtr&lt;id&gt; m_durationObserver;
</span><ins>+    RetainPtr&lt;AVStreamSession&gt; m_streamSession;
</ins><span class="cx">     Timer&lt;MediaPlayerPrivateMediaSourceAVFObjC&gt; m_seekTimer;
</span><span class="cx">     CDMSessionMediaSourceAVFObjC* m_session;
</span><span class="cx">     MediaPlayer::NetworkState m_networkState;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcMediaPlayerPrivateMediaSourceAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -57,6 +57,7 @@
</span><span class="cx"> SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVSampleBufferDisplayLayer)
</span><span class="cx"> SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVSampleBufferRenderSynchronizer)
</span><span class="cx"> SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVStreamDataParser)
</span><ins>+SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVStreamSession);
</ins><span class="cx"> SOFT_LINK_CLASS_OPTIONAL(AVFoundation, AVVideoPerformanceMetrics)
</span><span class="cx"> 
</span><span class="cx"> typedef struct opaqueCMNotificationCenter *CMNotificationCenterRef;
</span><span class="lines">@@ -666,6 +667,13 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(ENCRYPTED_MEDIA_V2)
</span><ins>+AVStreamSession* MediaPlayerPrivateMediaSourceAVFObjC::streamSession()
+{
+    if (!m_streamSession)
+        m_streamSession = adoptNS([[getAVStreamSessionClass() alloc] init]);
+    return m_streamSession.get();
+}
+
</ins><span class="cx"> void MediaPlayerPrivateMediaSourceAVFObjC::setCDMSession(CDMSession* session)
</span><span class="cx"> {
</span><span class="cx">     if (m_session) {
</span><span class="lines">@@ -677,6 +685,7 @@
</span><span class="cx">     m_session = toCDMSessionMediaSourceAVFObjC(session);
</span><span class="cx"> 
</span><span class="cx">     if (m_session) {
</span><ins>+        m_session-&gt;setStreamSession(m_streamSession.get());
</ins><span class="cx">         for (auto&amp; sourceBuffer : m_mediaSourcePrivate-&gt;sourceBuffers())
</span><span class="cx">             m_session-&gt;addSourceBuffer(sourceBuffer.get());
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -80,6 +80,7 @@
</span><span class="cx">     void didFailToParseStreamDataWithError(NSError*);
</span><span class="cx">     void didProvideMediaDataForTrackID(int trackID, CMSampleBufferRef, const String&amp; mediaType, unsigned flags);
</span><span class="cx">     void didReachEndOfTrackWithTrackID(int trackID, const String&amp; mediaType);
</span><ins>+    void willProvideContentKeyRequestInitializationDataForTrackID(int trackID);
</ins><span class="cx">     void didProvideContentKeyRequestInitializationDataForTrackID(NSData*, int trackID);
</span><span class="cx"> 
</span><span class="cx">     bool processCodedFrame(int trackID, CMSampleBufferRef, const String&amp; mediaType);
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformgraphicsavfoundationobjcSourceBufferPrivateAVFObjCmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> 
</span><span class="cx"> #if ENABLE(MEDIA_SOURCE) &amp;&amp; USE(AVFOUNDATION)
</span><span class="cx"> 
</span><ins>+#import &quot;BlockExceptions.h&quot;
</ins><span class="cx"> #import &quot;ExceptionCodePlaceholder.h&quot;
</span><span class="cx"> #import &quot;Logging.h&quot;
</span><span class="cx"> #import &quot;MediaDescription.h&quot;
</span><span class="lines">@@ -62,6 +63,7 @@
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVStreamDataParser)
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVSampleBufferAudioRenderer)
</span><span class="cx"> SOFT_LINK_CLASS(AVFoundation, AVSampleBufferDisplayLayer)
</span><ins>+SOFT_LINK_CLASS(AVFoundation, AVStreamSession)
</ins><span class="cx"> 
</span><span class="cx"> SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaTypeVideo, NSString *)
</span><span class="cx"> SOFT_LINK_POINTER_OPTIONAL(AVFoundation, AVMediaTypeAudio, NSString *)
</span><span class="lines">@@ -115,6 +117,14 @@
</span><span class="cx"> #define AVMediaCharacteristicLegible getAVMediaCharacteristicLegible()
</span><span class="cx"> 
</span><span class="cx"> #pragma mark -
</span><ins>+#pragma mark AVStreamSession
+
+@interface AVStreamSession : NSObject
+- (void)addStreamDataParser:(AVStreamDataParser *)streamDataParser;
+- (void)removeStreamDataParser:(AVStreamDataParser *)streamDataParser;
+@end
+
+#pragma mark -
</ins><span class="cx"> #pragma mark AVStreamDataParser
</span><span class="cx"> 
</span><span class="cx"> @interface AVStreamDataParser : NSObject
</span><span class="lines">@@ -268,6 +278,27 @@
</span><span class="cx">     });
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (void)streamParserWillProvideContentKeyRequestInitializationData:(AVStreamDataParser *)streamDataParser forTrackID:(CMPersistentTrackID)trackID
+{
+#if ASSERT_DISABLED
+    UNUSED_PARAM(streamDataParser);
+#endif
+    ASSERT(streamDataParser == _parser);
+
+    if (isMainThread()) {
+        _parent-&gt;willProvideContentKeyRequestInitializationDataForTrackID(trackID);
+        return;
+    }
+
+    // We must call synchronously to the main thread, as the AVStreamSession must be associated
+    // with the streamDataParser before the delegate method returns.
+    RetainPtr&lt;WebAVStreamDataParserListener&gt; strongSelf = self;
+    dispatch_sync(dispatch_get_main_queue(), [strongSelf, trackID]() {
+        if (strongSelf-&gt;_parent)
+            strongSelf-&gt;_parent-&gt;willProvideContentKeyRequestInitializationDataForTrackID(trackID);
+    });
+}
+
</ins><span class="cx"> - (void)streamDataParser:(AVStreamDataParser *)streamDataParser didProvideContentKeyRequestInitializationData:(NSData *)initData forTrackID:(CMPersistentTrackID)trackID
</span><span class="cx"> {
</span><span class="cx"> #if ASSERT_DISABLED
</span><span class="lines">@@ -658,6 +689,25 @@
</span><span class="cx">     notImplemented();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+void SourceBufferPrivateAVFObjC::willProvideContentKeyRequestInitializationDataForTrackID(int trackID)
+{
+    if (!m_mediaSource)
+        return;
+
+    ASSERT(m_parser);
+
+#if ENABLE(ENCRYPTED_MEDIA_V2)
+    LOG(MediaSource, &quot;SourceBufferPrivateAVFObjC::willProvideContentKeyRequestInitializationDataForTrackID(%p) - track:%d&quot;, this, trackID);
+    m_protectedTrackID = trackID;
+
+    BEGIN_BLOCK_OBJC_EXCEPTIONS;
+    [m_mediaSource-&gt;player()-&gt;streamSession() addStreamDataParser:m_parser.get()];
+    END_BLOCK_OBJC_EXCEPTIONS;
+#else
+    UNUSED_PARAM(trackID);
+#endif
+}
+
</ins><span class="cx"> void SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID(NSData* initData, int trackID)
</span><span class="cx"> {
</span><span class="cx">     if (!m_mediaSource)
</span><span class="lines">@@ -733,6 +783,9 @@
</span><span class="cx"> 
</span><span class="cx"> void SourceBufferPrivateAVFObjC::destroyParser()
</span><span class="cx"> {
</span><ins>+    if (m_mediaSource-&gt;player()-&gt;hasStreamSession())
+        [m_mediaSource-&gt;player()-&gt;streamSession() removeStreamDataParser:m_parser.get()];
+
</ins><span class="cx">     [m_delegate invalidate];
</span><span class="cx">     m_delegate = nullptr;
</span><span class="cx">     m_parser = nullptr;
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformmacSoftLinkingh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/mac/SoftLinking.h (174999 => 175000)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/SoftLinking.h        2014-10-21 21:37:05 UTC (rev 174999)
+++ trunk/Source/WebCore/platform/mac/SoftLinking.h        2014-10-21 23:06:59 UTC (rev 175000)
</span><span class="lines">@@ -236,7 +236,6 @@
</span><span class="cx">         return constant##name; \
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-#if PLATFORM(IOS)
</del><span class="cx"> #define SOFT_LINK_CONSTANT_MAY_FAIL(framework, name, type) \
</span><span class="cx">     static bool init##name(); \
</span><span class="cx">     static type (*get##name)() = 0; \
</span><span class="lines">@@ -263,4 +262,3 @@
</span><span class="cx">         get##name = name##Function; \
</span><span class="cx">         return true; \
</span><span class="cx">     }
</span><del>-#endif
</del></span></pre>
</div>
</div>

</body>
</html>