Changeset 181033 in webkit


Ignore:
Timestamp:
Mar 4, 2015, 2:29:25 PM (10 years ago)
Author:
Lucas Forschler
Message:

Merged r181005. rdar://problem/20044540

Location:
branches/safari-600.5-branch/Source/WebCore
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • branches/safari-600.5-branch/Source/WebCore/ChangeLog

    r181032 r181033  
     12015-03-04  Lucas Forschler  <lforschler@apple.com>
     2
     3        Merge r181005
     4
     5    2015-03-04  Jer Noble  <jer.noble@apple.com>
     6
     7            [MSE][EME][Mac] Calling close on a MediaKeysSession will cause many decoding errors to be emitted
     8            https://bugs.webkit.org/show_bug.cgi?id=142285
     9
     10            Reviewed by Eric Carlson.
     11
     12            When a MediaKeySession (backed by CDMSessionMediaSourceAVFObjC) is closed and the
     13            underlying AVStreamSession is invalidated, the decryption context for in-flight
     14            CMSampleBuffers is also invalidated, and the AVSampleBufferDisplayLayer will issue
     15            one error for each enqueued and un-displayed sample in its image-queue. -flush-ing
     16            the AVSampleBufferDisplayLayer is not enough, as the flush only takes effect
     17            asynchronously the next time the layer needs new samples.
     18
     19            Add a workaround until framework-level support lands to fully flush enqueued and
     20            encrypted frames.
     21
     22            When the CDMSessionMediaSOurceAVFObjC object recieves an error from the layer,
     23            check to see if the session has been stopped. If so, and if the error in question is
     24            one that indicates that the samples decryption context has been invalidated, suppress
     25            the error and instruct the sender to suppress the error as well. This workaround will
     26            be removed once real support for synchronous flushing lands in <rdar://problem/20027434.>
     27
     28            Still, we'll make our best effort to flush undisplayed frames when our CDM session is
     29            invalidated. Move away from std::map and instead use HashMap to store the set of
     30            AVSampleBufferAudioRenderers. This allows us to use C++11 style loops against just
     31            the HashMap's set of values.
     32
     33            * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h:
     34            * platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm:
     35            (WebCore::CDMSessionMediaSourceAVFObjC::releaseKeys): Flush and set m_stopped.
     36            (WebCore::CDMSessionMediaSourceAVFObjC::layerDidReceiveError): Check m_stopped and the
     37                error code and bail before issuing the error.
     38            (WebCore::CDMSessionMediaSourceAVFObjC::rendererDidReceiveError): Ditto.
     39            * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
     40            * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
     41            (-[WebAVSampleBufferErrorListener layerFailedToDecode:]): Drive-by fix. Check whether
     42                the layer is in the set of listened-to layers only back in the main thread; the
     43                listnener may have been unregistered by the time the main thread was called.
     44            (WebCore::SourceBufferPrivateAVFObjC::destroyRenderers): std::map -> HashMap.
     45            (WebCore::SourceBufferPrivateAVFObjC::trackDidChangeEnabled): Ditto.
     46            (WebCore::SourceBufferPrivateAVFObjC::flushAndEnqueueNonDisplayingSamples): Ditto.
     47            (WebCore::SourceBufferPrivateAVFObjC::enqueueSample): Ditto.
     48            (WebCore::SourceBufferPrivateAVFObjC::isReadyForMoreSamples): Ditto.
     49            (WebCore::SourceBufferPrivateAVFObjC::didBecomeReadyForMoreSamples): Ditto.
     50            (WebCore::SourceBufferPrivateAVFObjC::notifyClientWhenReadyForMoreSamples): Ditto.
     51            (WebCore::SourceBufferPrivateAVFObjC::flush): Added; call -flush on all the display
     52                layers and audio renderers.
     53            (WebCore::SourceBufferPrivateAVFObjC::layerDidReceiveError): Check if any clients
     54                asked to ignore the error, and if so, bail.
     55            (WebCore::SourceBufferPrivateAVFObjC::rendererDidReceiveError): Ditto.
     56
    1572015-03-04  Lucas Forschler  <lforschler@apple.com>
    258
  • branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.h

    r178977 r181033  
    5151    virtual bool update(Uint8Array*, RefPtr<Uint8Array>& nextMessage, unsigned short& errorCode, unsigned long& systemCode) override;
    5252
    53     virtual void layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *);
    54     virtual void rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *);
     53    virtual void layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *, bool& shouldIgnore);
     54    virtual void rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *, bool& shouldIgnore);
    5555
    5656    void setStreamSession(AVStreamSession *);
     
    7575    String m_sessionId;
    7676    enum { Normal, KeyRelease } m_mode;
     77    bool m_stopped = { false };
    7778};
    7879
  • branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionMediaSourceAVFObjC.mm

    r179948 r181033  
    141141{
    142142    if (m_streamSession) {
     143        m_stopped = true;
     144        for (auto& sourceBuffer : m_sourceBuffers)
     145            sourceBuffer->flush();
     146
    143147        LOG(Media, "CDMSessionMediaSourceAVFObjC::releaseKeys(%p) - expiring stream session", this);
    144148        [m_streamSession expire];
     
    282286}
    283287
    284 void CDMSessionMediaSourceAVFObjC::layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *error)
     288void CDMSessionMediaSourceAVFObjC::layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *error, bool& shouldIgnore)
    285289{
    286290    if (!m_client)
    287291        return;
    288292
    289     m_client->sendError(CDMSessionClient::MediaKeyErrorDomain, abs(systemCodeForError(error)));
    290 }
    291 
    292 void CDMSessionMediaSourceAVFObjC::rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *error)
     293    unsigned long code = abs(systemCodeForError(error));
     294
     295    // FIXME(142246): Remove the following once <rdar://problem/20027434> is resolved.
     296    shouldIgnore = m_stopped && code == 12785;
     297    if (!shouldIgnore)
     298        m_client->sendError(CDMSessionClient::MediaKeyErrorDomain, code);
     299}
     300
     301void CDMSessionMediaSourceAVFObjC::rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *error, bool& shouldIgnore)
    293302{
    294303    if (!m_client)
    295304        return;
    296305
    297     m_client->sendError(CDMSessionClient::MediaKeyErrorDomain, abs(systemCodeForError(error)));
     306    unsigned long code = abs(systemCodeForError(error));
     307
     308    // FIXME(142246): Remove the following once <rdar://problem/20027434> is resolved.
     309    shouldIgnore = m_stopped && code == 12785;
     310    if (!shouldIgnore)
     311        m_client->sendError(CDMSessionClient::MediaKeyErrorDomain, code);
    298312}
    299313
  • branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h

    r181022 r181033  
    3030
    3131#include "SourceBufferPrivate.h"
    32 #include <map>
    3332#include <wtf/Deque.h>
    3433#include <wtf/HashMap.h>
     
    6564public:
    6665    virtual ~SourceBufferPrivateAVFObjCErrorClient() { }
    67     virtual void layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *) = 0;
    68     virtual void rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *) = 0;
     66    virtual void layerDidReceiveError(AVSampleBufferDisplayLayer *, NSError *, bool& shouldIgnore) = 0;
     67    virtual void rendererDidReceiveError(AVSampleBufferAudioRenderer *, NSError *, bool& shouldIgnore) = 0;
    6968};
    7069
     
    9897    int protectedTrackID() const { return m_protectedTrackID; }
    9998    AVStreamDataParser* parser() const { return m_parser.get(); }
     99
     100    void flush();
    100101
    101102    void registerForErrorNotifications(SourceBufferPrivateAVFObjCErrorClient*);
     
    139140    RetainPtr<AVAsset> m_asset;
    140141    RetainPtr<AVSampleBufferDisplayLayer> m_displayLayer;
    141     std::map<int, RetainPtr<AVSampleBufferAudioRenderer>> m_audioRenderers;
     142    HashMap<int, RetainPtr<AVSampleBufferAudioRenderer>> m_audioRenderers;
    142143    RetainPtr<WebAVStreamDataParserListener> m_delegate;
    143144    RetainPtr<WebAVSampleBufferErrorListener> m_errorListener;
  • branches/safari-600.5-branch/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm

    r181032 r181033  
    3030
    3131#import "BlockExceptions.h"
     32#import "CDMSessionMediaSourceAVFObjC.h"
    3233#import "ExceptionCodePlaceholder.h"
    3334#import "Logging.h"
     
    148149- (void)enqueueSampleBuffer:(CMSampleBufferRef)sampleBuffer;
    149150- (void)flush;
     151- (void)flushAndRemoveImage;
    150152- (BOOL)isReadyForMoreMediaData;
    151153- (void)requestMediaDataWhenReadyOnQueue:(dispatch_queue_t)queue usingBlock:(void (^)(void))block;
     
    451453{
    452454    RetainPtr<AVSampleBufferDisplayLayer> layer = (AVSampleBufferDisplayLayer *)[note object];
    453     ASSERT(_layers.contains(layer.get()));
    454 
    455455    RetainPtr<NSError> error = [[note userInfo] valueForKey:AVSampleBufferDisplayLayerFailedToDecodeNotificationErrorKey];
    456456
    457457    RetainPtr<WebAVSampleBufferErrorListener> strongSelf = self;
    458458    callOnMainThread([strongSelf, layer, error] {
     459        if (!strongSelf->_parent || !strongSelf->_layers.contains(layer.get()))
     460            return;
    459461        strongSelf->_parent->layerDidReceiveError(layer.get(), error.get());
    460462    });
     
    804806    }
    805807
    806     for (auto it = m_audioRenderers.begin(), end = m_audioRenderers.end(); it != end; ++it) {
    807         AVSampleBufferAudioRenderer* renderer = it->second.get();
     808    for (auto& renderer : m_audioRenderers.values()) {
    808809        if (m_mediaSource)
    809             m_mediaSource->player()->removeAudioRenderer(renderer);
     810            m_mediaSource->player()->removeAudioRenderer(renderer.get());
    810811        [renderer flush];
    811812        [renderer stopRequestingMediaData];
    812         [m_errorListener stopObservingRenderer:renderer];
     813        [m_errorListener stopObservingRenderer:renderer.get()];
    813814    }
    814815
     
    883884
    884885    if (!track->enabled()) {
    885         AVSampleBufferAudioRenderer* renderer = m_audioRenderers[trackID].get();
     886        RetainPtr<AVSampleBufferAudioRenderer> renderer = m_audioRenderers.get(trackID);
    886887        [m_parser setShouldProvideMediaData:NO forTrackID:trackID];
    887888        if (m_mediaSource)
    888             m_mediaSource->player()->removeAudioRenderer(renderer);
     889            m_mediaSource->player()->removeAudioRenderer(renderer.get());
    889890    } else {
    890891        [m_parser setShouldProvideMediaData:YES forTrackID:trackID];
    891892        RetainPtr<AVSampleBufferAudioRenderer> renderer;
    892         if (!m_audioRenderers.count(trackID)) {
     893        if (!m_audioRenderers.contains(trackID)) {
    893894            renderer = adoptNS([[getAVSampleBufferAudioRendererClass() alloc] init]);
    894895            [renderer requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^{
    895896                didBecomeReadyForMoreSamples(trackID);
    896897            }];
    897             m_audioRenderers[trackID] = renderer;
     898            m_audioRenderers.set(trackID, renderer);
    898899            [m_errorListener beginObservingRenderer:renderer.get()];
    899900        } else
    900             renderer = m_audioRenderers[trackID].get();
     901            renderer = m_audioRenderers.get(trackID);
    901902
    902903        if (m_mediaSource)
     
    905906}
    906907
     908void SourceBufferPrivateAVFObjC::flush()
     909{
     910    if (m_displayLayer)
     911        [m_displayLayer flushAndRemoveImage];
     912
     913    for (auto& renderer : m_audioRenderers.values())
     914        [renderer flush];
     915}
     916
    907917void SourceBufferPrivateAVFObjC::registerForErrorNotifications(SourceBufferPrivateAVFObjCErrorClient* client)
    908918{
     
    920930{
    921931    LOG(MediaSource, "SourceBufferPrivateAVFObjC::layerDidReceiveError(%p): layer(%p), error(%@)", this, layer, [error description]);
    922     for (auto& client : m_errorClients)
    923         client->layerDidReceiveError(layer, error);
     932
     933    // FIXME(142246): Remove the following once <rdar://problem/20027434> is resolved.
     934    bool anyIgnored = false;
     935    for (auto& client : m_errorClients) {
     936        bool shouldIgnore = false;
     937        client->layerDidReceiveError(layer, error, shouldIgnore);
     938        anyIgnored |= shouldIgnore;
     939    }
     940    if (anyIgnored)
     941        return;
    924942
    925943    int errorCode = [[[error userInfo] valueForKey:@"OSStatus"] intValue];
     
    932950{
    933951    LOG(MediaSource, "SourceBufferPrivateAVFObjC::rendererDidReceiveError(%p): renderer(%p), error(%@)", this, renderer, [error description]);
    934     for (auto& client : m_errorClients)
    935         client->rendererDidReceiveError(renderer, error);
     952
     953    // FIXME(142246): Remove the following once <rdar://problem/20027434> is resolved.
     954    bool anyIgnored = false;
     955    for (auto& client : m_errorClients) {
     956        bool shouldIgnore = false;
     957        client->rendererDidReceiveError(renderer, error, shouldIgnore);
     958        anyIgnored |= shouldIgnore;
     959    }
     960    if (anyIgnored)
     961        return;
    936962}
    937963
     
    959985    if (trackID == m_enabledVideoTrackID)
    960986        flushAndEnqueueNonDisplayingSamples(mediaSamples, m_displayLayer.get());
    961     else if (m_audioRenderers.count(trackID))
    962         flushAndEnqueueNonDisplayingSamples(mediaSamples, m_audioRenderers[trackID].get());
     987    else if (m_audioRenderers.contains(trackID))
     988        flushAndEnqueueNonDisplayingSamples(mediaSamples, m_audioRenderers.get(trackID).get());
    963989}
    964990
     
    10031029{
    10041030    int trackID = trackIDString.toInt();
    1005     if (trackID != m_enabledVideoTrackID && !m_audioRenderers.count(trackID))
     1031    if (trackID != m_enabledVideoTrackID && !m_audioRenderers.contains(trackID))
    10061032        return;
    10071033
     
    10191045            m_mediaSource->player()->setHasAvailableVideoFrame(true);
    10201046    } else
    1021         [m_audioRenderers[trackID] enqueueSampleBuffer:platformSample.sample.cmSampleBuffer];
     1047        [m_audioRenderers.get(trackID) enqueueSampleBuffer:platformSample.sample.cmSampleBuffer];
    10221048}
    10231049
     
    10271053    if (trackID == m_enabledVideoTrackID)
    10281054        return [m_displayLayer isReadyForMoreMediaData];
    1029     else if (m_audioRenderers.count(trackID))
    1030         return [m_audioRenderers[trackID] isReadyForMoreMediaData];
     1055    else if (m_audioRenderers.contains(trackID))
     1056        return [m_audioRenderers.get(trackID) isReadyForMoreMediaData];
    10311057    else
    10321058        ASSERT_NOT_REACHED();
     
    10631089    if (trackID == m_enabledVideoTrackID)
    10641090        [m_displayLayer stopRequestingMediaData];
    1065     else if (m_audioRenderers.count(trackID))
    1066         [m_audioRenderers[trackID] stopRequestingMediaData];
     1091    else if (m_audioRenderers.contains(trackID))
     1092        [m_audioRenderers.get(trackID) stopRequestingMediaData];
    10671093    else {
    10681094        ASSERT_NOT_REACHED();
     
    10811107            didBecomeReadyForMoreSamples(trackID);
    10821108        }];
    1083     } else if (m_audioRenderers.count(trackID)) {
    1084         [m_audioRenderers[trackID] requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^{
     1109    } else if (m_audioRenderers.contains(trackID)) {
     1110        [m_audioRenderers.get(trackID) requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^{
    10851111            didBecomeReadyForMoreSamples(trackID);
    10861112        }];
Note: See TracChangeset for help on using the changeset viewer.