Title: [289946] trunk
Revision
289946
Author
[email protected]
Date
2022-02-16 12:49:59 -0800 (Wed, 16 Feb 2022)

Log Message

[Cocoa] Adopt -streamDataParser:didProvideContentKeySpecifier:forTrackID: delegate callback
https://bugs.webkit.org/show_bug.cgi?id=236109

Reviewed by Eric Carlson.

Source/WebCore:

The current set of delegate callback methods have a significant shortcoming: clients must
attach an AVContentKeySession to the AVStreamDataParser before returning from the
-streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID: callback. This
is because the parser itself attaches the object required to decrypt each encrypted sample
to the sample itself at the parsing stage. If a client does not attach an
AVContentKeySession by the time that method returns, AVStreamDataParser will attach one of
its own.

The web-facing behavior this causes is that MSE appends will not complete (by firing
an "updateend" event) if an encrypted segment is parsed until the client creates and
attaches a MediaKeys object with a valid session.

A new delegate callback method, -streamDataParser:didProvideContentKeySpecifier:forTrackID:
allows us to work around this problem. When this delegate is present, AVStreamDataParser
will skip attaching a decryption object entirely, moving that responsibility to the
client. However, this comes with the requirement that the client (WebKit) won't enqueue
an encrypted sample before a decryption object is available via AVContentKeySession.

In order to meet this new requirement, WebKit will associate the key IDs necessary to
decrypt each sample in the MediaSample object that wraps the encrypted sample. Because not
every type of MediaSample will carry key IDs, this property was added to the
MediaSampleAVFObjC subclass, and therefore we need to be able to safely downcast from
MediaSample to MediaSampleAVFObjC. MediaSample subclasses can be distinguished by the
PlatformMediaSample type available through their platformSample() property, however this
call is not const, and may not be free, as it returns a non-POD type. So
PlatformMedia::Type was made an explicit enum type, and a new virtual method
platformSampleType() was added to MediaSample (and implemented by all subclasses), and a
type specialization macro was added to MediaSampleAVFObjC.

In order to check whether a given sample is capable of being enqueued, the CDMInstance
must be queried to determine if the sample's required keys are usable. For
CDMInstanceFairPlayStreamingAVFObjC, it has an existing keyStatus(), method, but that
method is also non-const, and may be expensive. So a KeyStatusMap instance variable
has been added to cache the key status for ease of querying. To notify an arbitrary number
of clients when the key statuses change, an Observer has been added.

When an encrypted sample is enqueued, if this new delegate method is available, the
source buffer will check if a CDM instance is available, and if so, whether the sample's
keys are usable. If any of these checks fail, the sample will be stored in a local queue
and new enqueues will be blocked. When the CDM's keyStatus observer is triggered, the
local queue will be processed, and all samples with usable key IDs will be enqueued.

Drive-by fix: Use SharedBuffer rather than Uint8Array, as the former is lighter weight
and can be more easily converted to and from a NSData.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::mediaPlayerKeyNeeded):
* html/HTMLMediaElement.h:
* platform/MediaSample.h:
* platform/audio/cocoa/AudioFileReaderCocoa.cpp:
(WebCore::AudioFileReader::demuxWebMData const):
* platform/graphics/MediaPlayer.cpp:
(WebCore::MediaPlayer::keyNeeded):
* platform/graphics/MediaPlayer.h:
(WebCore::MediaPlayerClient::mediaPlayerKeyNeeded):
* platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
* platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::isAnyKeyUsable const):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::addKeyStatusesChangedObserver):
(WebCore::CDMInstanceFairPlayStreamingAVFObjC::sessionKeyStatusesChanged):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateKeyStatuses):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::copyKeyStatuses const):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateProtectionStatusForDisplayID):
(WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyStatuses const): Deleted.
* platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.h:
* platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm:
(WebCore::CDMSessionAVContentKeySession::generateKeyRequest):
(WebCore::CDMSessionAVContentKeySession::update):
* platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
(WebCore::MediaPlayerPrivateAVFoundationObjC::shouldWaitForLoadingOfResource):
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
(WebCore::MediaPlayerPrivateMediaSourceAVFObjC::keyNeeded):
* platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h:
(WebCore::MediaSampleAVFObjC::setKeyIDs):
(WebCore::MediaSampleAVFObjC::keyIDs const):
(WebCore::MediaSampleAVFObjC::keyIDs):
(WTF::LogArgument<WebCore::MediaSampleAVFObjC>::toString):
(isType):
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
(WebCore::MediaSourcePrivateAVFObjC::sourceBufferKeyNeeded):
* platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm:
(-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeySpecifier:forTrackID:]):
(WebCore::SourceBufferParserAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID):
(WebCore::SourceBufferParserAVFObjC::didProvideContentKeyRequestSpecifierForTrackID):
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
* platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
(WebCore::sampleBufferRenderersSupportKeySession):
(WebCore::copyKeyIDs):
(WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
(WebCore::SourceBufferPrivateAVFObjC::didParseInitializationData):
(WebCore::SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackId):
(WebCore::SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID):
(WebCore::SourceBufferPrivateAVFObjC::append):
(WebCore::SourceBufferPrivateAVFObjC::destroyRenderers):
(WebCore::SourceBufferPrivateAVFObjC::trackDidChangeEnabled):
(WebCore::SourceBufferPrivateAVFObjC::setCDMInstance):
(WebCore::SourceBufferPrivateAVFObjC::attemptToDecrypt):
(WebCore::SourceBufferPrivateAVFObjC::trackIsBlocked const):
(WebCore::SourceBufferPrivateAVFObjC::keyStatusesChanged):
(WebCore::SourceBufferPrivateAVFObjC::canEnqueueSample):
(WebCore::SourceBufferPrivateAVFObjC::enqueueSample):
(WebCore::SourceBufferPrivateAVFObjC::didBecomeReadyForMoreSamples):
(WebCore::SourceBufferPrivateAVFObjC::setVideoLayer):
* platform/graphics/cocoa/SourceBufferParser.h:
* platform/graphics/cocoa/SourceBufferParserWebM.cpp:
(WebCore::SourceBufferParserWebM::OnTrackEntry):
* platform/graphics/cocoa/SourceBufferParserWebM.h:
* platform/graphics/gstreamer/MediaSampleGStreamer.h:
* platform/mock/mediasource/MockSourceBufferPrivate.cpp:

Source/WebKit:

Add the newly requried virtual method changes to MediaSample subclasses, and use
SharedBuffer rather than Uint8Array.

* GPUProcess/media/RemoteMediaPlayerProxy.cpp:
(WebKit::RemoteMediaPlayerProxy::mediaPlayerKeyNeeded):
* GPUProcess/media/RemoteMediaPlayerProxy.h:
* Shared/mac/MediaFormatReader/MediaFormatReader.cpp:
(WebKit::MediaFormatReader::parseByteSource):
(WebKit::MediaFormatReader::didProvideMediaData):
* Shared/mac/MediaFormatReader/MediaFormatReader.h:
* Shared/mac/MediaFormatReader/MediaSampleByteRange.h:
* WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:
(WebKit::MediaPlayerPrivateRemote::mediaPlayerKeyNeeded):

Source/WTF:

* wtf/PlatformHave.h:

Tools:

* TestWebKitAPI/Tests/WebCore/SampleMap.cpp:

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (289945 => 289946)


--- trunk/Source/WTF/ChangeLog	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WTF/ChangeLog	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1,3 +1,12 @@
+2022-02-16  Jer Noble  <[email protected]>
+
+        [Cocoa] Adopt -streamDataParser:didProvideContentKeySpecifier:forTrackID: delegate callback
+        https://bugs.webkit.org/show_bug.cgi?id=236109
+
+        Reviewed by Eric Carlson.
+
+        * wtf/PlatformHave.h:
+
 2022-02-16  Eliot Hsu  <[email protected]>
 
         Move Safe Browsing knowledge into SafariSafeBrowsing framework

Modified: trunk/Source/WTF/wtf/PlatformHave.h (289945 => 289946)


--- trunk/Source/WTF/wtf/PlatformHave.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WTF/wtf/PlatformHave.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -388,6 +388,13 @@
 #define HAVE_AVCONTENTKEYSESSION 1
 #endif
 
+#if (PLATFORM(MAC) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 110300) \
+    || (((PLATFORM(IOS) && !PLATFORM(IOS_FAMILY_SIMULATOR)) || PLATFORM(MACCATALYST)) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 140500) \
+    || (PLATFORM(WATCHOS) && !PLATFORM(IOS_FAMILY_SIMULATOR) && __WATCH_OS_VERSION_MAX_ALLOWED >= 70400) \
+    || (PLATFORM(APPLETV) && !PLATFORM(IOS_FAMILY_SIMULATOR) && __TV_OS_VERSION_MAX_ALLOWED >= 140500)
+#define HAVE_AVCONTENTKEYSPECIFIER 1
+#endif
+
 #if PLATFORM(MAC) || PLATFORM(IOS) || PLATFORM(MACCATALYST)
 #define HAVE_SEC_KEY_PROXY 1
 #endif

Modified: trunk/Source/WebCore/ChangeLog (289945 => 289946)


--- trunk/Source/WebCore/ChangeLog	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/ChangeLog	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1,3 +1,125 @@
+2022-02-16  Jer Noble  <[email protected]>
+
+        [Cocoa] Adopt -streamDataParser:didProvideContentKeySpecifier:forTrackID: delegate callback
+        https://bugs.webkit.org/show_bug.cgi?id=236109
+
+        Reviewed by Eric Carlson.
+
+        The current set of delegate callback methods have a significant shortcoming: clients must
+        attach an AVContentKeySession to the AVStreamDataParser before returning from the
+        -streamDataParser:didProvideContentKeyRequestInitializationData:forTrackID: callback. This
+        is because the parser itself attaches the object required to decrypt each encrypted sample
+        to the sample itself at the parsing stage. If a client does not attach an
+        AVContentKeySession by the time that method returns, AVStreamDataParser will attach one of
+        its own.
+
+        The web-facing behavior this causes is that MSE appends will not complete (by firing
+        an "updateend" event) if an encrypted segment is parsed until the client creates and
+        attaches a MediaKeys object with a valid session.
+
+        A new delegate callback method, -streamDataParser:didProvideContentKeySpecifier:forTrackID:
+        allows us to work around this problem. When this delegate is present, AVStreamDataParser
+        will skip attaching a decryption object entirely, moving that responsibility to the
+        client. However, this comes with the requirement that the client (WebKit) won't enqueue
+        an encrypted sample before a decryption object is available via AVContentKeySession.
+
+        In order to meet this new requirement, WebKit will associate the key IDs necessary to
+        decrypt each sample in the MediaSample object that wraps the encrypted sample. Because not
+        every type of MediaSample will carry key IDs, this property was added to the
+        MediaSampleAVFObjC subclass, and therefore we need to be able to safely downcast from
+        MediaSample to MediaSampleAVFObjC. MediaSample subclasses can be distinguished by the
+        PlatformMediaSample type available through their platformSample() property, however this
+        call is not const, and may not be free, as it returns a non-POD type. So
+        PlatformMedia::Type was made an explicit enum type, and a new virtual method
+        platformSampleType() was added to MediaSample (and implemented by all subclasses), and a
+        type specialization macro was added to MediaSampleAVFObjC.
+
+        In order to check whether a given sample is capable of being enqueued, the CDMInstance
+        must be queried to determine if the sample's required keys are usable. For
+        CDMInstanceFairPlayStreamingAVFObjC, it has an existing keyStatus(), method, but that
+        method is also non-const, and may be expensive. So a KeyStatusMap instance variable
+        has been added to cache the key status for ease of querying. To notify an arbitrary number
+        of clients when the key statuses change, an Observer has been added.
+
+        When an encrypted sample is enqueued, if this new delegate method is available, the
+        source buffer will check if a CDM instance is available, and if so, whether the sample's
+        keys are usable. If any of these checks fail, the sample will be stored in a local queue
+        and new enqueues will be blocked. When the CDM's keyStatus observer is triggered, the
+        local queue will be processed, and all samples with usable key IDs will be enqueued.
+
+        Drive-by fix: Use SharedBuffer rather than Uint8Array, as the former is lighter weight
+        and can be more easily converted to and from a NSData.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::mediaPlayerKeyNeeded):
+        * html/HTMLMediaElement.h:
+        * platform/MediaSample.h:
+        * platform/audio/cocoa/AudioFileReaderCocoa.cpp:
+        (WebCore::AudioFileReader::demuxWebMData const):
+        * platform/graphics/MediaPlayer.cpp:
+        (WebCore::MediaPlayer::keyNeeded):
+        * platform/graphics/MediaPlayer.h:
+        (WebCore::MediaPlayerClient::mediaPlayerKeyNeeded):
+        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h:
+        * platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm:
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::isAnyKeyUsable const):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::addKeyStatusesChangedObserver):
+        (WebCore::CDMInstanceFairPlayStreamingAVFObjC::sessionKeyStatusesChanged):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateKeyStatuses):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::copyKeyStatuses const):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::updateProtectionStatusForDisplayID):
+        (WebCore::CDMInstanceSessionFairPlayStreamingAVFObjC::keyStatuses const): Deleted.
+        * platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.h:
+        * platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm:
+        (WebCore::CDMSessionAVContentKeySession::generateKeyRequest):
+        (WebCore::CDMSessionAVContentKeySession::update):
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm:
+        (WebCore::MediaPlayerPrivateAVFoundationObjC::shouldWaitForLoadingOfResource):
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm:
+        (WebCore::MediaPlayerPrivateMediaSourceAVFObjC::keyNeeded):
+        * platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h:
+        (WebCore::MediaSampleAVFObjC::setKeyIDs):
+        (WebCore::MediaSampleAVFObjC::keyIDs const):
+        (WebCore::MediaSampleAVFObjC::keyIDs):
+        (WTF::LogArgument<WebCore::MediaSampleAVFObjC>::toString):
+        (isType):
+        * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h:
+        * platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm:
+        (WebCore::MediaSourcePrivateAVFObjC::sourceBufferKeyNeeded):
+        * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h:
+        * platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm:
+        (-[WebAVStreamDataParserListener streamDataParser:didProvideContentKeySpecifier:forTrackID:]):
+        (WebCore::SourceBufferParserAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID):
+        (WebCore::SourceBufferParserAVFObjC::didProvideContentKeyRequestSpecifierForTrackID):
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h:
+        * platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm:
+        (WebCore::sampleBufferRenderersSupportKeySession):
+        (WebCore::copyKeyIDs):
+        (WebCore::SourceBufferPrivateAVFObjC::SourceBufferPrivateAVFObjC):
+        (WebCore::SourceBufferPrivateAVFObjC::didParseInitializationData):
+        (WebCore::SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackId):
+        (WebCore::SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID):
+        (WebCore::SourceBufferPrivateAVFObjC::append):
+        (WebCore::SourceBufferPrivateAVFObjC::destroyRenderers):
+        (WebCore::SourceBufferPrivateAVFObjC::trackDidChangeEnabled):
+        (WebCore::SourceBufferPrivateAVFObjC::setCDMInstance):
+        (WebCore::SourceBufferPrivateAVFObjC::attemptToDecrypt):
+        (WebCore::SourceBufferPrivateAVFObjC::trackIsBlocked const):
+        (WebCore::SourceBufferPrivateAVFObjC::keyStatusesChanged):
+        (WebCore::SourceBufferPrivateAVFObjC::canEnqueueSample):
+        (WebCore::SourceBufferPrivateAVFObjC::enqueueSample):
+        (WebCore::SourceBufferPrivateAVFObjC::didBecomeReadyForMoreSamples):
+        (WebCore::SourceBufferPrivateAVFObjC::setVideoLayer):
+        * platform/graphics/cocoa/SourceBufferParser.h:
+        * platform/graphics/cocoa/SourceBufferParserWebM.cpp:
+        (WebCore::SourceBufferParserWebM::OnTrackEntry):
+        * platform/graphics/cocoa/SourceBufferParserWebM.h:
+        * platform/graphics/gstreamer/MediaSampleGStreamer.h:
+        * platform/mock/mediasource/MockSourceBufferPrivate.cpp:
+
 2022-02-16  Eric Carlson  <[email protected]>
 
         [Cocoa] Update audio session category before setting NowPlaying status

Modified: trunk/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeys.idl (289945 => 289946)


--- trunk/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeys.idl	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/Modules/encryptedmedia/legacy/WebKitMediaKeys.idl	2022-02-16 20:49:59 UTC (rev 289946)
@@ -30,7 +30,7 @@
 ] interface WebKitMediaKeys {
     constructor(DOMString keySystem);
 
-    [CallWith=CurrentScriptExecutionContext] WebKitMediaKeySession createSession(DOMString type, Uint8Array initData);
+    [CallWith=CurrentDocument] WebKitMediaKeySession createSession(DOMString type, Uint8Array initData);
     static boolean isTypeSupported(DOMString keySystem, optional DOMString type);
     readonly attribute DOMString keySystem;
 };

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (289945 => 289946)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -2644,7 +2644,7 @@
     return m_webKitMediaKeys ? m_webKitMediaKeys->cachedKeyForKeyId(keyId) : nullptr;
 }
 
-void HTMLMediaElement::mediaPlayerKeyNeeded(Uint8Array* initData)
+void HTMLMediaElement::mediaPlayerKeyNeeded(const SharedBuffer& initData)
 {
     if (!document().settings().legacyEncryptedMediaAPIEnabled())
         return;
@@ -2661,7 +2661,14 @@
         return;
     }
 
-    auto event = WebKitMediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, initData);
+    WebKitMediaKeyNeededEvent::Init init;
+
+    if (auto initDataBuffer = initData.tryCreateArrayBuffer()) {
+        auto byteLength = initDataBuffer->byteLength();
+        init.initData = Uint8Array::tryCreate(initDataBuffer.releaseNonNull(), 0, byteLength);
+    }
+
+    auto event = WebKitMediaKeyNeededEvent::create(eventNames().webkitneedkeyEvent, init);
     scheduleEvent(WTFMove(event));
 }
 

Modified: trunk/Source/WebCore/html/HTMLMediaElement.h (289945 => 289946)


--- trunk/Source/WebCore/html/HTMLMediaElement.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/html/HTMLMediaElement.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -706,7 +706,7 @@
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     RefPtr<ArrayBuffer> mediaPlayerCachedKeyForKeyId(const String& keyId) const final;
-    void mediaPlayerKeyNeeded(Uint8Array*) final;
+    void mediaPlayerKeyNeeded(const SharedBuffer&) final;
     String mediaPlayerMediaKeysStorageDirectory() const final;
 #endif
 

Modified: trunk/Source/WebCore/platform/MediaSample.h (289945 => 289946)


--- trunk/Source/WebCore/platform/MediaSample.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/MediaSample.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -44,7 +44,7 @@
 class MockSampleBox;
 
 struct PlatformSample {
-    enum {
+    enum Type {
         None,
         MockSampleBoxType,
         CMSampleBufferType,
@@ -92,6 +92,7 @@
     };
     virtual SampleFlags flags() const = 0;
     virtual PlatformSample platformSample() const = 0;
+    virtual PlatformSample::Type platformSampleType() const = 0;
 
     struct ByteRange {
         size_t byteOffset { 0 };

Modified: trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp (289945 => 289946)


--- trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/audio/cocoa/AudioFileReaderCocoa.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -202,10 +202,10 @@
             }
         }
     });
-    parser->setDidProvideMediaDataCallback([&](Ref<MediaSample>&& sample, uint64_t trackID, const String&) {
+    parser->setDidProvideMediaDataCallback([&](Ref<MediaSampleAVFObjC>&& sample, uint64_t trackID, const String&) {
         if (!audioTrackId || trackID != *audioTrackId)
             return;
-        samples.append(static_reference_cast<MediaSampleAVFObjC>(WTFMove(sample)));
+        samples.append(WTFMove(sample));
     });
     parser->setCallOnClientThreadCallback([](auto&& function) {
         function();

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1425,7 +1425,7 @@
     return client().mediaPlayerCachedKeyForKeyId(keyId);
 }
 
-void MediaPlayer::keyNeeded(Uint8Array* initData)
+void MediaPlayer::keyNeeded(const SharedBuffer& initData)
 {
     client().mediaPlayerKeyNeeded(initData);
 }

Modified: trunk/Source/WebCore/platform/graphics/MediaPlayer.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/MediaPlayer.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -86,6 +86,7 @@
 class NativeImage;
 class PlatformMediaResourceLoader;
 class PlatformTimeRanges;
+class SharedBuffer;
 class TextTrackRepresentation;
 class VideoTrackPrivate;
 
@@ -200,7 +201,7 @@
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     virtual RefPtr<ArrayBuffer> mediaPlayerCachedKeyForKeyId(const String&) const = 0;
-    virtual void mediaPlayerKeyNeeded(Uint8Array*) { }
+    virtual void mediaPlayerKeyNeeded(const SharedBuffer&) { }
     virtual String mediaPlayerMediaKeysStorageDirectory() const { return emptyString(); }
 #endif
 
@@ -558,7 +559,7 @@
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     RefPtr<ArrayBuffer> cachedKeyForKeyId(const String& keyId) const;
-    void keyNeeded(Uint8Array* initData);
+    void keyNeeded(const SharedBuffer& initData);
     String mediaKeysStorageDirectory() const;
 #endif
 

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/cf/MediaPlayerPrivateAVFoundationCF.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1921,15 +1921,15 @@
         // [4 bytes: keyURI size], [keyURI size bytes: keyURI]
         unsigned keyURISize = keyURI.length() * sizeof(UChar);
         auto initDataBuffer = ArrayBuffer::create(4 + keyURISize, 1);
-        auto initDataView = JSC::DataView::create(initDataBuffer.copyRef(), 0, initDataBuffer->byteLength());
+        unsigned byteLength = initDataBuffer->byteLength();
+        auto initDataView = JSC::DataView::create(initDataBuffer.copyRef(), 0, byteLength);
         initDataView->set<uint32_t>(0, keyURISize, true);
 
         auto keyURIArray = Uint16Array::create(initDataBuffer.copyRef(), 4, keyURI.length());
         keyURIArray->setRange(reinterpret_cast<const uint16_t*>(StringView(keyURI).upconvertedCharacters().get()), keyURI.length() / sizeof(unsigned char), 0);
 
-        unsigned byteLength = initDataBuffer->byteLength();
-        auto initData = Uint8Array::create(WTFMove(initDataBuffer), 0, byteLength);
-        m_owner->player()->keyNeeded(initData.ptr());
+        auto initData = SharedBuffer::create(Vector<uint8_t> { static_cast<uint8_t*>(initDataBuffer->data()), byteLength });
+        m_owner->player()->keyNeeded(initData);
         setRequestForKey(keyURI, avRequest);
         return true;
     }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -30,7 +30,9 @@
 #include "CDMInstance.h"
 #include "CDMInstanceSession.h"
 #include <wtf/Function.h>
+#include <wtf/Observer.h>
 #include <wtf/RetainPtr.h>
+#include <wtf/WeakHashSet.h>
 
 OBJC_CLASS AVContentKeyReportGroup;
 OBJC_CLASS AVContentKeyRequest;
@@ -117,6 +119,13 @@
     CDMInstanceSessionFairPlayStreamingAVFObjC* sessionForGroup(AVContentKeyReportGroup*) const;
     CDMInstanceSessionFairPlayStreamingAVFObjC* sessionForRequest(AVContentKeyRequest*) const;
 
+    bool isAnyKeyUsable(const Keys&) const;
+
+    using KeyStatusesChangedObserver = Observer<void()>;
+    void addKeyStatusesChangedObserver(const KeyStatusesChangedObserver&);
+
+    void sessionKeyStatusesChanged(const CDMInstanceSessionFairPlayStreamingAVFObjC&);
+
 private:
     void handleUnexpectedRequests(Vector<RetainPtr<AVContentKeyRequest>>&&);
 
@@ -134,6 +143,7 @@
     RetainPtr<NSURL> m_storageURL;
     Vector<WeakPtr<CDMInstanceSessionFairPlayStreamingAVFObjC>> m_sessions;
     HashSet<RetainPtr<AVContentKeyRequest>> m_unexpectedKeyRequests;
+    WeakHashSet<KeyStatusesChangedObserver> m_keyStatusChangedObservers;
 #if !RELEASE_LOG_DISABLED
     RefPtr<Logger> m_logger;
     const void* m_logIdentifier { nullptr };
@@ -186,11 +196,14 @@
 
     bool hasRequest(AVContentKeyRequest*) const;
 
+    const KeyStatusVector& keyStatuses() const { return m_keyStatuses; }
+    KeyStatusVector copyKeyStatuses() const;
+
 private:
     bool ensureSessionOrGroup();
     bool isLicenseTypeSupported(LicenseType) const;
 
-    KeyStatusVector keyStatuses(std::optional<PlatformDisplayID> = std::nullopt) const;
+    void updateKeyStatuses(std::optional<PlatformDisplayID> = std::nullopt);
     void nextRequest();
     AVContentKeyRequest* lastKeyRequest() const;
 
@@ -216,6 +229,7 @@
 
     class UpdateResponseCollector;
     std::unique_ptr<UpdateResponseCollector> m_updateResponseCollector;
+    KeyStatusVector m_keyStatuses;
 
     Vector<Request> m_pendingRequests;
     Vector<Request> m_requests;

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMInstanceFairPlayStreamingAVFObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -617,6 +617,37 @@
     return nullptr;
 }
 
+bool CDMInstanceFairPlayStreamingAVFObjC::isAnyKeyUsable(const Keys& keys) const
+{
+    for (auto& sessionInterface : m_sessions) {
+        if (!sessionInterface)
+            continue;
+
+        for (auto& keyStatusPair : sessionInterface->keyStatuses()) {
+            if (keyStatusPair.second != CDMInstanceSession::KeyStatus::Usable)
+                continue;
+
+            if (keys.findIf([&] (auto& key) {
+                return key.get() == keyStatusPair.first.get();
+            }) != notFound)
+                return true;
+        }
+    }
+    return false;
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::addKeyStatusesChangedObserver(const KeyStatusesChangedObserver& observer)
+{
+    m_keyStatusChangedObservers.add(observer);
+}
+
+void CDMInstanceFairPlayStreamingAVFObjC::sessionKeyStatusesChanged(const CDMInstanceSessionFairPlayStreamingAVFObjC&)
+{
+    m_keyStatusChangedObservers.forEach([] (auto& observer) {
+        observer();
+    });
+}
+
 CDMInstanceSessionFairPlayStreamingAVFObjC::CDMInstanceSessionFairPlayStreamingAVFObjC(Ref<CDMInstanceFairPlayStreamingAVFObjC>&& instance)
     : m_instance(WTFMove(instance))
     , m_delegate(adoptNS([[WebCoreFPSContentKeySessionDelegate alloc] initWithParent:this]))
@@ -1306,6 +1337,8 @@
 
 void CDMInstanceSessionFairPlayStreamingAVFObjC::requestDidSucceed(AVContentKeyRequest *request)
 {
+    updateKeyStatuses();
+
     if (m_updateResponseCollector) {
         m_updateResponseCollector->addSuccessfulResponse(request, nullptr);
         return;
@@ -1312,7 +1345,7 @@
     }
 
     if (m_updateLicenseCallback) {
-        m_updateLicenseCallback(false, std::make_optional(keyStatuses()), std::nullopt, std::nullopt, Succeeded);
+        m_updateLicenseCallback(false, std::make_optional(copyKeyStatuses()), std::nullopt, std::nullopt, Succeeded);
         ASSERT(!m_updateLicenseCallback);
     }
 
@@ -1405,7 +1438,7 @@
     }
 }
 
-CDMInstanceSession::KeyStatusVector CDMInstanceSessionFairPlayStreamingAVFObjC::keyStatuses(std::optional<PlatformDisplayID> displayID) const
+void CDMInstanceSessionFairPlayStreamingAVFObjC::updateKeyStatuses(std::optional<PlatformDisplayID> displayID)
 {
     KeyStatusVector keyStatuses;
 
@@ -1427,9 +1460,21 @@
         }
     }
 
-    return keyStatuses;
+    m_keyStatuses.swap(keyStatuses);
+
+    m_instance->sessionKeyStatusesChanged(*this);
 }
 
+auto CDMInstanceSessionFairPlayStreamingAVFObjC::copyKeyStatuses() const -> KeyStatusVector
+{
+    KeyStatusVector copiedKeyStatuses;
+    copiedKeyStatuses.reserveInitialCapacity(m_keyStatuses.size());
+    for (auto& status : m_keyStatuses)
+        copiedKeyStatuses.uncheckedAppend({ status.first.copyRef(), status.second });
+    return copiedKeyStatuses;
+
+}
+
 void CDMInstanceSessionFairPlayStreamingAVFObjC::outputObscuredDueToInsufficientExternalProtectionChanged(bool obscured)
 {
     if (obscured == m_outputObscured)
@@ -1438,8 +1483,10 @@
     ALWAYS_LOG_IF_POSSIBLE(LOGIDENTIFIER, obscured);
     m_outputObscured = obscured;
 
+    updateKeyStatuses();
+
     if (m_client)
-        m_client->updateKeyStatuses(keyStatuses());
+        m_client->updateKeyStatuses(copyKeyStatuses());
 }
 
 void CDMInstanceSessionFairPlayStreamingAVFObjC::externalProtectionStatusDidChangeForContentKeyRequest(AVContentKeyRequest*)
@@ -1492,9 +1539,13 @@
 
 void CDMInstanceSessionFairPlayStreamingAVFObjC::updateProtectionStatusForDisplayID(PlatformDisplayID displayID)
 {
-    if (m_requests.isEmpty() || !m_client)
+    if (m_requests.isEmpty())
         return;
-    m_client->updateKeyStatuses(keyStatuses(displayID));
+
+    updateKeyStatuses(displayID);
+
+    if (m_client)
+        m_client->updateKeyStatuses(copyKeyStatuses());
 }
 
 bool CDMInstanceSessionFairPlayStreamingAVFObjC::ensureSessionOrGroup()

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -70,7 +70,7 @@
     RetainPtr<WebCDMSessionAVContentKeySessionDelegate> m_contentKeySessionDelegate;
     RetainPtr<AVContentKeyRequest> m_keyRequest;
     RefPtr<Uint8Array> m_identifier;
-    RefPtr<Uint8Array> m_initData;
+    RefPtr<SharedBuffer> m_initData;
     RetainPtr<NSData> m_expiredSession;
     Vector<int> m_protocolVersions;
     int m_cdmVersion;

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/CDMSessionAVContentKeySession.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -32,6 +32,7 @@
 #import "LegacyCDM.h"
 #import "Logging.h"
 #import "MediaPlayer.h"
+#import "SharedBuffer.h"
 #import "SourceBufferPrivateAVFObjC.h"
 #import "WebCoreNSErrorExtras.h"
 #import <AVFoundation/AVError.h>
@@ -146,7 +147,7 @@
     if (m_cdmVersion == 2)
         m_identifier = initData;
     else
-        m_initData = initData;
+        m_initData = SharedBuffer::create(initData->data(), initData->length());
 
     ASSERT(!m_certificate);
     String certificateString("certificate"_s);
@@ -268,12 +269,12 @@
     }
 
     if (!m_keyRequest) {
-        NSData* nsInitData = m_initData ? [NSData dataWithBytes:m_initData->data() length:m_initData->length()] : nil;
+        RetainPtr<NSData> nsInitData = m_initData ? m_initData->createNSData() : nil;
         NSData* nsIdentifier = m_identifier ? [NSData dataWithBytes:m_identifier->data() length:m_identifier->length()] : nil;
         if ([contentKeySession() respondsToSelector:@selector(processContentKeyRequestWithIdentifier:initializationData:options:)])
-            [contentKeySession() processContentKeyRequestWithIdentifier:nsIdentifier initializationData:nsInitData options:nil];
+            [contentKeySession() processContentKeyRequestWithIdentifier:nsIdentifier initializationData:nsInitData.get() options:nil];
         else
-            [contentKeySession() processContentKeyRequestInitializationData:nsInitData options:nil];
+            [contentKeySession() processContentKeyRequestInitializationData:nsInitData.get() options:nil];
     }
 
     if (shouldGenerateKeyRequest) {

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateAVFoundationObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -2114,8 +2114,8 @@
         auto keyURIArray = Uint16Array::create(initDataBuffer.copyRef(), 4, keyURI.length());
         keyURIArray->setRange(reinterpret_cast<const UniChar*>(StringView(keyURI).upconvertedCharacters().get()), keyURI.length() / sizeof(unsigned char), 0);
 
-        auto initData = Uint8Array::create(WTFMove(initDataBuffer), 0, byteLength);
-        player()->keyNeeded(initData.ptr());
+        auto initData = SharedBuffer::create(Vector<uint8_t> { static_cast<uint8_t*>(initDataBuffer->data()), byteLength });
+        player()->keyNeeded(initData);
 #if ENABLE(ENCRYPTED_MEDIA)
         if (!player()->shouldContinueAfterKeyNeeded())
             return true;
@@ -2143,10 +2143,8 @@
     if (scheme == "clearkey") {
         String keyID = [[[avRequest request] URL] resourceSpecifier];
         auto encodedKeyId = PAL::UTF8Encoding().encode(keyID, PAL::UnencodableHandling::URLEncodedEntities);
+        auto initData = SharedBuffer::create(WTFMove(encodedKeyId));
 
-        auto initData = Uint8Array::create(encodedKeyId.size());
-        initData->setRange(encodedKeyId.data(), encodedKeyId.size(), 0);
-
         auto keyData = player()->cachedKeyForKeyId(keyID);
         if (keyData) {
             fulfillRequestWithKeyData(avRequest, keyData.get());
@@ -2153,7 +2151,7 @@
             return false;
         }
 
-        player()->keyNeeded(initData.ptr());
+        player()->keyNeeded(initData);
 
         if (!player()->shouldContinueAfterKeyNeeded())
             return false;

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -137,7 +137,7 @@
     void endSimulatedHDCPError() override { outputObscuredDueToInsufficientExternalProtectionChanged(false); }
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
-    void keyNeeded(Uint8Array*);
+    void keyNeeded(const SharedBuffer&);
 #endif
 
 #if ENABLE(ENCRYPTED_MEDIA)

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaPlayerPrivateMediaSourceAVFObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1143,7 +1143,7 @@
 #endif // ENABLE(LEGACY_ENCRYPTED_MEDIA)
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA) || ENABLE(ENCRYPTED_MEDIA)
-void MediaPlayerPrivateMediaSourceAVFObjC::keyNeeded(Uint8Array* initData)
+void MediaPlayerPrivateMediaSourceAVFObjC::keyNeeded(const SharedBuffer& initData)
 {
     m_player->keyNeeded(initData);
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSampleAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -29,11 +29,13 @@
 #include <_javascript_Core/Forward.h>
 #include <pal/avfoundation/MediaTimeAVFoundation.h>
 #include <wtf/Forward.h>
+#include <wtf/TypeCasts.h>
 
 using CVPixelBufferRef = struct __CVBuffer*;
 
 namespace WebCore {
 
+class FragmentedSharedBuffer;
 class PixelBuffer;
 
 class MediaSampleAVFObjC : public MediaSample {
@@ -60,6 +62,7 @@
 
     SampleFlags flags() const override;
     PlatformSample platformSample() const override;
+    PlatformSample::Type platformSampleType() const override { return PlatformSample::CMSampleBufferType; }
     std::optional<ByteRange> byteRange() const override;
     WEBCORE_EXPORT void dump(PrintStream&) const override;
     void offsetTimestampsBy(const MediaTime&) override;
@@ -80,6 +83,13 @@
 
     void setByteRangeOffset(size_t);
 
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    using KeyIDs = Vector<Ref<FragmentedSharedBuffer>>;
+    void setKeyIDs(KeyIDs&& keyIDs) { m_keyIDs = WTFMove(keyIDs); }
+    const KeyIDs& keyIDs() const { return m_keyIDs; }
+    KeyIDs& keyIDs() { return m_keyIDs; }
+#endif
+
 protected:
     WEBCORE_EXPORT MediaSampleAVFObjC(RetainPtr<CMSampleBufferRef>&&);
     WEBCORE_EXPORT MediaSampleAVFObjC(CMSampleBufferRef);
@@ -94,10 +104,27 @@
     AtomString m_id;
     VideoRotation m_rotation { VideoRotation::None };
     bool m_mirrored { false };
+
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    Vector<Ref<FragmentedSharedBuffer>> m_keyIDs;
+#endif
 };
 
 } // namespace WebCore
 
+namespace WTF {
+
+template<typename Type> struct LogArgument;
+template <>
+struct LogArgument<WebCore::MediaSampleAVFObjC> {
+    static String toString(const WebCore::MediaSampleAVFObjC& sample)
+    {
+        return sample.toJSONString();
+    }
+};
+
+} // namespace WTF
+
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::MediaSampleAVFObjC)
-    static bool isType(const WebCore::MediaSample& mediaSample) { return mediaSample.platformSample().type == WebCore::PlatformSample::CMSampleBufferType; }
+static bool isType(const WebCore::MediaSample& sample) { return sample.platformSampleType() == WebCore::PlatformSample::CMSampleBufferType; }
 SPECIALIZE_TYPE_TRAITS_END()

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -125,7 +125,7 @@
     void sourceBufferPrivateDidChangeActiveState(SourceBufferPrivateAVFObjC*, bool active);
     void sourceBufferPrivateDidReceiveInitializationSegment(SourceBufferPrivateAVFObjC*);
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-    void sourceBufferKeyNeeded(SourceBufferPrivateAVFObjC*, Uint8Array*);
+    void sourceBufferKeyNeeded(SourceBufferPrivateAVFObjC*, const SharedBuffer&);
 #endif
     void removeSourceBuffer(SourceBufferPrivate*);
 

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/MediaSourcePrivateAVFObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -195,9 +195,10 @@
 }
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-void MediaSourcePrivateAVFObjC::sourceBufferKeyNeeded(SourceBufferPrivateAVFObjC* buffer, Uint8Array* initData)
+void MediaSourcePrivateAVFObjC::sourceBufferKeyNeeded(SourceBufferPrivateAVFObjC* buffer, const SharedBuffer& initData)
 {
     m_sourceBuffersNeedingSessions.append(buffer);
+
     if (m_player)
         m_player->keyNeeded(initData);
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -68,6 +68,7 @@
     void didProvideMediaDataForTrackID(uint64_t trackID, CMSampleBufferRef, const String& mediaType, unsigned flags);
     void willProvideContentKeyRequestInitializationDataForTrackID(uint64_t trackID);
     void didProvideContentKeyRequestInitializationDataForTrackID(NSData*, uint64_t trackID);
+    void didProvideContentKeyRequestSpecifierForTrackID(NSData*, uint64_t trackID);
 
 private:
 #if !RELEASE_LOG_DISABLED

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferParserAVFObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -57,6 +57,12 @@
 #pragma mark -
 #pragma mark WebAVStreamDataParserListener
 
+#if HAVE(AVCONTENTKEYSPECIFIER)
+@interface AVContentKeySpecifier (WebCorePrivate)
+@property (readonly) NSData *initializationData;
+@end
+#endif
+
 @interface WebAVStreamDataParserListener : NSObject<AVStreamDataParserOutputHandling> {
     WebCore::SourceBufferParserAVFObjC* _parent;
     AVStreamDataParser* _parser;
@@ -133,6 +139,16 @@
     ASSERT_UNUSED(streamDataParser, streamDataParser == _parser);
     _parent->didProvideContentKeyRequestInitializationDataForTrackID(initData, trackID);
 }
+
+#if HAVE(AVCONTENTKEYSPECIFIER)
+- (void)streamDataParser:(AVStreamDataParser *)streamDataParser didProvideContentKeySpecifier:(AVContentKeySpecifier *)keySpecifier forTrackID:(CMPersistentTrackID)trackID
+{
+    ASSERT_UNUSED(streamDataParser, streamDataParser == _parser);
+    if ([keySpecifier respondsToSelector:@selector(initializationData)])
+        _parent->didProvideContentKeyRequestSpecifierForTrackID(keySpecifier.initializationData, trackID);
+}
+#endif
+
 @end
 
 namespace WebCore {
@@ -334,10 +350,14 @@
 
 void SourceBufferParserAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID(NSData* nsInitData, uint64_t trackID)
 {
-    auto initData = Uint8Array::create(nsInitData.length);
-    [nsInitData getBytes:initData->data() length:initData->length()];
+    m_didProvideContentKeyRequestInitializationDataForTrackIDCallback(SharedBuffer::create(nsInitData), trackID);
+}
 
-    m_didProvideContentKeyRequestInitializationDataForTrackIDCallback(WTFMove(initData), trackID);
+void SourceBufferParserAVFObjC::didProvideContentKeyRequestSpecifierForTrackID(NSData* nsInitData, uint64_t trackID)
+{
+    m_callOnClientThreadCallback([this, strongThis = Ref { *this }, nsInitData = retainPtr(nsInitData), trackID] {
+        m_didProvideContentKeyRequestIdentifierForTrackIDCallback(SharedBuffer::create(nsInitData.get()), trackID);
+    });
 }
 
 }

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -37,6 +37,7 @@
 #include <wtf/LoggerHelper.h>
 #include <wtf/MediaTime.h>
 #include <wtf/OSObjectPtr.h>
+#include <wtf/Observer.h>
 #include <wtf/RefPtr.h>
 #include <wtf/RetainPtr.h>
 #include <wtf/Vector.h>
@@ -95,8 +96,10 @@
     void clearMediaSource() { m_mediaSource = nullptr; }
 
     void willProvideContentKeyRequestInitializationDataForTrackID(uint64_t trackID);
-    void didProvideContentKeyRequestInitializationDataForTrackID(Ref<Uint8Array>&&, uint64_t trackID, Box<BinarySemaphore>);
+    void didProvideContentKeyRequestInitializationDataForTrackID(Ref<SharedBuffer>&&, uint64_t trackID, Box<BinarySemaphore>);
 
+    void didProvideContentKeyRequestIdentifierForTrackID(Ref<SharedBuffer>&&, uint64_t trackID);
+
     bool hasSelectedVideo() const;
 
     void trackDidChangeSelected(VideoTrackPrivate&, bool selected);
@@ -132,7 +135,7 @@
     void bufferWasConsumed();
     
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-    Uint8Array* initData() { return m_initData.get(); }
+    SharedBuffer* initData() { return m_initData.get(); }
 #endif
 
 #if !RELEASE_LOG_DISABLED
@@ -150,7 +153,7 @@
     using InitializationSegment = SourceBufferPrivateClient::InitializationSegment;
     void didParseInitializationData(InitializationSegment&&);
     void didEncounterErrorDuringParsing(int32_t);
-    void didProvideMediaDataForTrackId(Ref<MediaSample>&&, uint64_t trackId, const String& mediaType);
+    void didProvideMediaDataForTrackId(Ref<MediaSampleAVFObjC>&&, uint64_t trackId, const String& mediaType);
 
     // SourceBufferPrivate overrides
     void append(Ref<SharedBuffer>&&) final;
@@ -174,6 +177,7 @@
     MediaTime currentMediaTime() const final;
     MediaTime duration() const final;
 
+    void enqueueSample(Ref<MediaSampleAVFObjC>&&, uint64_t trackID);
     void didBecomeReadyForMoreSamples(uint64_t trackID);
     void appendCompleted();
     void destroyStreamDataParser();
@@ -186,7 +190,13 @@
     ALLOW_NEW_API_WITHOUT_GUARDS_END
 
     MediaPlayerPrivateMediaSourceAVFObjC* player() const;
+    bool canEnqueueSample(uint64_t trackID, const MediaSampleAVFObjC&);
+    bool trackIsBlocked(uint64_t track) const;
 
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    void keyStatusesChanged();
+#endif
+
     Vector<RefPtr<VideoTrackPrivate>> m_videoTracks;
     Vector<RefPtr<AudioTrackPrivate>> m_audioTracks;
     Vector<SourceBufferPrivateAVFObjCErrorClient*> m_errorClients;
@@ -197,7 +207,8 @@
     bool m_processingInitializationSegment { false };
     bool m_hasPendingAppendCompletedCallback { false };
     Vector<Function<void()>> m_pendingTrackChangeCallbacks;
-    Vector<std::pair<uint64_t, Ref<MediaSample>>> m_mediaSamples;
+    Vector<std::pair<uint64_t, Ref<MediaSampleAVFObjC>>> m_mediaSamples;
+    Deque<std::pair<uint64_t, Ref<MediaSampleAVFObjC>>> m_blockedSamples;
 
     RetainPtr<AVSampleBufferDisplayLayer> m_displayLayer;
     ALLOW_NEW_API_WITHOUT_GUARDS_BEGIN
@@ -215,13 +226,27 @@
 
     MediaSourcePrivateAVFObjC* m_mediaSource;
     bool m_isActive { false };
+
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
-    RefPtr<Uint8Array> m_initData;
+    RefPtr<SharedBuffer> m_initData;
     WeakPtr<CDMSessionMediaSourceAVFObjC> m_session { nullptr };
 #endif
 #if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    using KeyIDs = Vector<Ref<FragmentedSharedBuffer>>;
+    struct TrackInitData {
+        RefPtr<SharedBuffer> initData;
+        KeyIDs keyIDs;
+    };
+    using TrackInitDataMap = HashMap<uint64_t, TrackInitData>;
+    TrackInitDataMap m_pendingProtectedTrackInitDataMap;
+    TrackInitDataMap m_protectedTrackInitDataMap;
+
+    using TrackKeyIDsMap = HashMap<uint64_t, KeyIDs>;
+    TrackKeyIDsMap m_currentTrackIDs;
+
     RefPtr<CDMInstanceFairPlayStreamingAVFObjC> m_cdmInstance;
-    Vector<Ref<FragmentedSharedBuffer>> m_keyIDs;
+    UniqueRef<Observer<void()>> m_keyStatusesChangedObserver;
+    KeyIDs m_keyIDs;
 #endif
 
     std::optional<FloatSize> m_cachedSize;

Modified: trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/avfoundation/objc/SourceBufferPrivateAVFObjC.mm	2022-02-16 20:49:59 UTC (rev 289946)
@@ -76,6 +76,12 @@
 - (void)resetUpcomingSampleBufferPresentationTimeExpectations;
 @end
 
+@interface AVSampleBufferDisplayLayer (WebCoreSampleBufferKeySession) <AVContentKeyRecipient>
+@end
+
+@interface AVSampleBufferAudioRenderer (WebCoreSampleBufferKeySession) <AVContentKeyRecipient>
+@end
+
 #pragma mark -
 #pragma mark AVStreamSession
 
@@ -275,6 +281,24 @@
     return ++mapID;
 }
 
+static bool sampleBufferRenderersSupportKeySession()
+{
+    static bool supports = false;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, [&] {
+        supports = [PAL::getAVSampleBufferAudioRendererClass() conformsToProtocol:@protocol(AVContentKeyRecipient)]
+            && [PAL::getAVSampleBufferDisplayLayerClass() conformsToProtocol:@protocol(AVContentKeyRecipient)];
+    });
+    return supports;
+}
+
+static Vector<Ref<FragmentedSharedBuffer>> copyKeyIDs(const Vector<Ref<FragmentedSharedBuffer>> keyIDs)
+{
+    return keyIDs.map([] (auto& keyID) {
+        return keyID.copyRef();
+    });
+}
+
 static void bufferWasConsumedCallback(CMNotificationCenterRef, const void* listener, CFStringRef notificationName, const void*, CFTypeRef)
 {
     if (!CFEqual(PAL::kCMSampleBufferConsumerNotification_BufferConsumed, notificationName))
@@ -307,6 +331,9 @@
     , m_errorListener(adoptNS([[WebAVSampleBufferErrorListener alloc] initWithParent:*this]))
     , m_appendQueue(WorkQueue::create("SourceBufferPrivateAVFObjC data parser queue"))
     , m_mediaSource(parent)
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    , m_keyStatusesChangedObserver(makeUniqueRef<Observer<void()>>([this] { keyStatusesChanged(); }))
+#endif
     , m_mapID(nextMapID())
 #if !RELEASE_LOG_DISABLED
     , m_logger(parent->logger())
@@ -364,6 +391,9 @@
 
     clearTracks();
 
+    m_protectedTrackInitDataMap.swap(m_pendingProtectedTrackInitDataMap);
+    m_pendingProtectedTrackInitDataMap.clear();
+
     for (auto videoTrackInfo : segment.videoTracks) {
         videoTrackInfo.track->setSelectedChangedCallback([weakThis = WeakPtr { *this }, this] (VideoTrackPrivate& track, bool selected) {
             if (!weakThis)
@@ -458,10 +488,16 @@
     m_parsingSucceeded = false;
 }
 
-void SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackId(Ref<MediaSample>&& mediaSample, uint64_t trackId, const String& mediaType)
+void SourceBufferPrivateAVFObjC::didProvideMediaDataForTrackId(Ref<MediaSampleAVFObjC>&& mediaSample, uint64_t trackId, const String& mediaType)
 {
     UNUSED_PARAM(mediaType);
 
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    auto findResult = m_protectedTrackInitDataMap.find(trackId);
+    if (findResult != m_protectedTrackInitDataMap.end())
+        mediaSample->setKeyIDs(copyKeyIDs(findResult->value.keyIDs));
+#endif
+
     if (m_processingInitializationSegment) {
         DEBUG_LOG(LOGIDENTIFIER, mediaSample.get());
         m_mediaSamples.append(std::make_pair(trackId, WTFMove(mediaSample)));
@@ -508,7 +544,7 @@
 #endif
 }
 
-void SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID(Ref<Uint8Array>&& initData, uint64_t trackID, Box<BinarySemaphore> hasSessionSemaphore)
+void SourceBufferPrivateAVFObjC::didProvideContentKeyRequestInitializationDataForTrackID(Ref<SharedBuffer>&& initData, uint64_t trackID, Box<BinarySemaphore> hasSessionSemaphore)
 {
     auto player = this->player();
     if (!player)
@@ -519,11 +555,15 @@
 
     m_protectedTrackID = trackID;
     m_initData = WTFMove(initData);
-    m_mediaSource->sourceBufferKeyNeeded(this, m_initData.get());
+    m_mediaSource->sourceBufferKeyNeeded(this, *m_initData);
+
     if (auto session = player->cdmSession()) {
-        if (auto parser = this->streamDataParser())
+        if (sampleBufferRenderersSupportKeySession()) {
+            // no-op.
+        } else if (auto parser = this->streamDataParser())
             session->addParser(parser);
-        hasSessionSemaphore->signal();
+        if (hasSessionSemaphore)
+            hasSessionSemaphore->signal();
         return;
     }
 #endif
@@ -533,14 +573,17 @@
     m_hasSessionSemaphore = hasSessionSemaphore;
     
 #if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
-    auto initDataBuffer = SharedBuffer::create(m_initData->data(), m_initData->byteLength());
-    auto keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(initDataBuffer);
+    auto keyIDs = CDMPrivateFairPlayStreaming::extractKeyIDsSinf(*m_initData);
     if (!keyIDs)
         return;
 
+    m_pendingProtectedTrackInitDataMap.set(trackID, TrackInitData { m_initData.copyRef(), *keyIDs });
+
     if (m_cdmInstance) {
         if (auto instanceSession = m_cdmInstance->sessionForKeyIDs(keyIDs.value())) {
-            if (auto parser = this->streamDataParser())
+            if (sampleBufferRenderersSupportKeySession()) {
+                // no-op.
+            } else if (auto parser = this->streamDataParser())
                 [instanceSession->contentKeySession() addContentKeyRecipient:parser];
             if (m_hasSessionSemaphore) {
                 m_hasSessionSemaphore->signal();
@@ -552,7 +595,7 @@
     }
 
     m_keyIDs = WTFMove(keyIDs.value());
-    player->initializationDataEncountered("sinf", initDataBuffer->tryCreateArrayBuffer());
+    player->initializationDataEncountered("sinf", m_initData->tryCreateArrayBuffer());
 
     m_waitingForKey = true;
     player->waitingForKeyChanged();
@@ -587,7 +630,7 @@
         weakThis->didEncounterErrorDuringParsing(errorCode);
     });
 
-    m_parser->setDidProvideMediaDataCallback([weakThis = WeakPtr { *this }, abortCalled = m_abortCalled] (Ref<MediaSample>&& sample, uint64_t trackId, const String& mediaType) {
+    m_parser->setDidProvideMediaDataCallback([weakThis = WeakPtr { *this }, abortCalled = m_abortCalled] (Ref<MediaSampleAVFObjC>&& sample, uint64_t trackId, const String& mediaType) {
         ASSERT(isMainThread());
         if (!weakThis || abortCalled != weakThis->m_abortCalled)
             return;
@@ -616,7 +659,7 @@
         }
     });
 
-    m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = WeakPtr { *this }, abortSemaphore = m_abortSemaphore, abortCalled = m_abortCalled](Ref<Uint8Array>&& initData, uint64_t trackID) mutable {
+    m_parser->setDidProvideContentKeyRequestInitializationDataForTrackIDCallback([weakThis = WeakPtr { *this }, abortSemaphore = m_abortSemaphore, abortCalled = m_abortCalled](Ref<SharedBuffer>&& initData, uint64_t trackID) mutable {
         // Called on the data parser queue.
         Box<BinarySemaphore> hasSessionSemaphore = Box<BinarySemaphore>::create();
         callOnMainThread([weakThis = WTFMove(weakThis), abortCalled, initData = WTFMove(initData), trackID, hasSessionSemaphore] () mutable {
@@ -636,6 +679,13 @@
         }
     });
 
+    m_parser->setDidProvideContentKeyRequestIdentifierForTrackIDCallback([weakThis = WeakPtr { *this }, abortCalled = m_abortCalled] (Ref<SharedBuffer>&& initData, uint64_t trackID) {
+        ASSERT(isMainThread());
+        if (!weakThis || abortCalled != weakThis->m_abortCalled)
+            return;
+        weakThis->didProvideContentKeyRequestInitializationDataForTrackID(WTFMove(initData), trackID, nullptr);
+    });
+
     m_parsingSucceeded = true;
 
     m_appendQueue->dispatch([data = "" weakThis = m_appendWeakFactory.createWeakPtr(*this), parser = m_parser, abortCalled = m_abortCalled]() mutable {
@@ -736,6 +786,11 @@
         [renderer flush];
         [renderer stopRequestingMediaData];
         [m_errorListener stopObservingRenderer:renderer.get()];
+
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+        if (m_cdmInstance && sampleBufferRenderersSupportKeySession())
+            [m_cdmInstance->contentKeySession() removeContentKeyRecipient:renderer.get()];
+#endif
     }
 
     [m_errorListener invalidate];
@@ -843,6 +898,11 @@
                 return;
             }
 
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+        if (m_cdmInstance && sampleBufferRenderersSupportKeySession())
+            [m_cdmInstance->contentKeySession() addContentKeyRecipient:renderer.get()];
+#endif
+
             WeakPtr weakThis { *this };
             [renderer requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^{
                 if (weakThis)
@@ -909,7 +969,24 @@
 
     ALWAYS_LOG(LOGIDENTIFIER);
 
+    if (sampleBufferRenderersSupportKeySession() && m_cdmInstance) {
+        if (m_displayLayer)
+            [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_displayLayer.get()];
+
+        for (auto& audioRenderer : m_audioRenderers.values())
+            [m_cdmInstance->contentKeySession() removeContentKeyRecipient:audioRenderer.get()];
+    }
+
     m_cdmInstance = fpsInstance;
+
+    if (sampleBufferRenderersSupportKeySession() && m_cdmInstance) {
+        if (m_displayLayer)
+            [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_displayLayer.get()];
+
+        for (auto& audioRenderer : m_audioRenderers.values())
+            [m_cdmInstance->contentKeySession() addContentKeyRecipient:audioRenderer.get()];
+    }
+
     attemptToDecrypt();
 #else
     UNUSED_PARAM(instance);
@@ -926,8 +1003,10 @@
     if (!instanceSession)
         return;
 
-    if (auto parser = this->streamDataParser())
-        [instanceSession->contentKeySession() addContentKeyRecipient:parser];
+    if (!sampleBufferRenderersSupportKeySession()) {
+        if (auto parser = this->streamDataParser())
+            [instanceSession->contentKeySession() addContentKeyRecipient:parser];
+    }
     if (m_hasSessionSemaphore) {
         m_hasSessionSemaphore->signal();
         m_hasSessionSemaphore = nullptr;
@@ -1105,6 +1184,63 @@
         player->setHasAvailableAudioSample(renderer, false);
 }
 
+bool SourceBufferPrivateAVFObjC::trackIsBlocked(uint64_t trackID) const
+{
+    for (auto& samplePair : m_blockedSamples) {
+        if (samplePair.first == trackID)
+            return true;
+    }
+    return false;
+}
+
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+void SourceBufferPrivateAVFObjC::keyStatusesChanged()
+{
+    while (!m_blockedSamples.isEmpty()) {
+        auto& firstPair = m_blockedSamples.first();
+
+        // If we still can't enqueue the sample, bail.
+        if (!canEnqueueSample(firstPair.first, firstPair.second))
+            return;
+
+        auto firstPairTaken = m_blockedSamples.takeFirst();
+        enqueueSample(WTFMove(firstPairTaken.second), firstPairTaken.first);
+    }
+}
+#endif
+
+bool SourceBufferPrivateAVFObjC::canEnqueueSample(uint64_t trackID, const MediaSampleAVFObjC& sample)
+{
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+    // If sample buffers don't support AVContentKeySession: enqueue sample
+    if (!sampleBufferRenderersSupportKeySession())
+        return true;
+
+    // if sample is unencrytped: enqueue sample
+    if (sample.keyIDs().isEmpty())
+        return true;
+
+    // if sample is encrypted, but we are not attached to a CDM: do not enqueue sample.
+    if (!m_cdmInstance)
+        return false;
+
+    // if sample is encrypted, and keyIDs match the current set of keyIDs: enqueue sample.
+    auto findResult = m_currentTrackIDs.find(trackID);
+    if (findResult != m_currentTrackIDs.end() && findResult->value == sample.keyIDs())
+        return true;
+
+    // if sample's set of keyIDs does not match the current set of keyIDs, consult with the CDM
+    // to determine if the keyIDs are usable; if so, update the current set of keyIDs and enqueue sample.
+    if (m_cdmInstance->isAnyKeyUsable(sample.keyIDs())) {
+        m_currentTrackIDs.set(trackID, sample.keyIDs());
+        return true;
+    }
+    return false;
+#else
+    return true;
+#endif
+}
+
 void SourceBufferPrivateAVFObjC::enqueueSample(Ref<MediaSample>&& sample, const AtomString& trackIDString)
 {
     auto trackID = parseIntegerAllowingTrailingJunk<uint64_t>(trackIDString).value_or(0);
@@ -1111,13 +1247,26 @@
     if (trackID != m_enabledVideoTrackID && !m_audioRenderers.contains(trackID))
         return;
 
-    PlatformSample platformSample = sample->platformSample();
-    if (platformSample.type != PlatformSample::CMSampleBufferType)
+    ASSERT(is<MediaSampleAVFObjC>(sample));
+    if (!is<MediaSampleAVFObjC>(sample))
         return;
 
+    Ref<MediaSampleAVFObjC> sampleAVFObjC = static_reference_cast<MediaSampleAVFObjC>(WTFMove(sample));
+    if (!sampleAVFObjC->keyIDs().isEmpty() && !canEnqueueSample(trackID, sampleAVFObjC)) {
+        m_blockedSamples.append({ trackID, WTFMove(sampleAVFObjC) });
+        return;
+    }
+
+    enqueueSample(WTFMove(sampleAVFObjC), trackID);
+}
+
+void SourceBufferPrivateAVFObjC::enqueueSample(Ref<MediaSampleAVFObjC>&& sample, uint64_t trackID)
+{
     auto logSiteIdentifier = LOGIDENTIFIER;
     DEBUG_LOG(logSiteIdentifier, "track ID = ", trackID, ", sample = ", sample.get());
 
+    PlatformSample platformSample = sample->platformSample();
+
     CMFormatDescriptionRef formatDescription = PAL::CMSampleBufferGetFormatDescription(platformSample.sample.cmSampleBuffer);
     ASSERT(formatDescription);
     if (!formatDescription) {
@@ -1284,6 +1433,9 @@
     else
         return;
 
+    if (trackIsBlocked(trackID))
+        return;
+
     provideMediaData(AtomString::number(trackID));
 }
 
@@ -1375,11 +1527,21 @@
         [m_displayLayer flush];
         [m_displayLayer stopRequestingMediaData];
         [m_errorListener stopObservingLayer:m_displayLayer.get()];
+
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+        if (m_cdmInstance && sampleBufferRenderersSupportKeySession())
+            [m_cdmInstance->contentKeySession() removeContentKeyRecipient:m_displayLayer.get()];
+#endif
     }
 
     m_displayLayer = layer;
 
     if (m_displayLayer) {
+#if ENABLE(ENCRYPTED_MEDIA) && HAVE(AVCONTENTKEYSESSION)
+        if (m_cdmInstance && sampleBufferRenderersSupportKeySession())
+            [m_cdmInstance->contentKeySession() addContentKeyRecipient:m_displayLayer.get()];
+#endif
+
         WeakPtr weakThis { *this };
         [m_displayLayer requestMediaDataWhenReadyOnQueue:dispatch_get_main_queue() usingBlock:^ {
             if (weakThis)

Modified: trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParser.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -44,7 +44,7 @@
 namespace WebCore {
 
 class ContentType;
-class MediaSample;
+class MediaSampleAVFObjC;
 class SharedBuffer;
 
 class WEBCORE_EXPORT SourceBufferParser : public ThreadSafeRefCounted<SourceBufferParser> {
@@ -123,7 +123,7 @@
     }
 
     // Will be called on the main thread.
-    using DidProvideMediaDataCallback = Function<void(Ref<MediaSample>&&, uint64_t trackID, const String& mediaType)>;
+    using DidProvideMediaDataCallback = Function<void(Ref<MediaSampleAVFObjC>&&, uint64_t trackID, const String& mediaType)>;
     void setDidProvideMediaDataCallback(DidProvideMediaDataCallback&& callback)
     {
         m_didProvideMediaDataCallback = WTFMove(callback);
@@ -137,12 +137,19 @@
     }
 
     // Will be called synchronously on the parser thead.
-    using DidProvideContentKeyRequestInitializationDataForTrackIDCallback = Function<void(Ref<Uint8Array>&&, uint64_t trackID)>;
+    using DidProvideContentKeyRequestInitializationDataForTrackIDCallback = Function<void(Ref<SharedBuffer>&&, uint64_t trackID)>;
     void setDidProvideContentKeyRequestInitializationDataForTrackIDCallback(DidProvideContentKeyRequestInitializationDataForTrackIDCallback&& callback)
     {
         m_didProvideContentKeyRequestInitializationDataForTrackIDCallback = WTFMove(callback);
     }
 
+    // Will be called on the main thread.
+    using DidProvideContentKeyRequestIdentifierForTrackIDCallback = Function<void(Ref<SharedBuffer>&&, uint64_t trackID)>;
+    void setDidProvideContentKeyRequestIdentifierForTrackIDCallback(DidProvideContentKeyRequestIdentifierForTrackIDCallback&& callback)
+    {
+        m_didProvideContentKeyRequestIdentifierForTrackIDCallback = WTFMove(callback);
+    }
+
 protected:
     SourceBufferParser();
 
@@ -152,6 +159,7 @@
     DidProvideMediaDataCallback m_didProvideMediaDataCallback;
     WillProvideContentKeyRequestInitializationDataForTrackIDCallback m_willProvideContentKeyRequestInitializationDataForTrackIDCallback;
     DidProvideContentKeyRequestInitializationDataForTrackIDCallback m_didProvideContentKeyRequestInitializationDataForTrackIDCallback;
+    DidProvideContentKeyRequestIdentifierForTrackIDCallback m_didProvideContentKeyRequestIdentifierForTrackIDCallback;
 };
 
 }

Modified: trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1032,7 +1032,7 @@
                 continue;
 
             auto& keyId = keyIdElement.value();
-            m_keyIds.append(std::make_pair(trackEntry.track_uid.value(), Uint8Array::create(keyId.data(), keyId.size())));
+            m_keyIds.append(std::make_pair(trackEntry.track_uid.value(), SharedBuffer::create(keyId.data(), keyId.size())));
         }
     }
 

Modified: trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/cocoa/SourceBufferParserWebM.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -269,7 +269,7 @@
     webm::Status OnFrame(const webm::FrameMetadata&, webm::Reader*, uint64_t* bytesRemaining) final;
 
     std::unique_ptr<InitializationSegment> m_initializationSegment;
-    Vector<std::pair<uint64_t, Ref<Uint8Array>>> m_keyIds;
+    Vector<std::pair<uint64_t, Ref<SharedBuffer>>> m_keyIds;
     webm::Status m_status;
     std::unique_ptr<webm::WebmParser> m_parser;
     bool m_initializationSegmentEncountered { false };

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h (289945 => 289946)


--- trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/MediaSampleGStreamer.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -62,6 +62,7 @@
     Ref<MediaSample> createNonDisplayingCopy() const override;
     SampleFlags flags() const override { return m_flags; }
     PlatformSample platformSample() const override;
+    PlatformSample::Type platformSampleType() const override { return PlatformSample::GStreamerSampleType; }
     std::optional<ByteRange> byteRange() const override { return std::nullopt; }
     void dump(PrintStream&) const override;
     RefPtr<JSC::Uint8ClampedArray> getRGBAImageData() const final;

Modified: trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp (289945 => 289946)


--- trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebCore/platform/mock/mediasource/MockSourceBufferPrivate.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -61,6 +61,7 @@
     size_t sizeInBytes() const override { return sizeof(m_box); }
     SampleFlags flags() const override;
     PlatformSample platformSample() const override;
+    PlatformSample::Type platformSampleType() const override { return PlatformSample::MockSampleBoxType; }
     std::optional<ByteRange> byteRange() const override { return std::nullopt; }
     FloatSize presentationSize() const override { return FloatSize(); }
     void dump(PrintStream&) const override;

Modified: trunk/Source/WebKit/ChangeLog (289945 => 289946)


--- trunk/Source/WebKit/ChangeLog	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/ChangeLog	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1,3 +1,24 @@
+2022-02-16  Jer Noble  <[email protected]>
+
+        [Cocoa] Adopt -streamDataParser:didProvideContentKeySpecifier:forTrackID: delegate callback
+        https://bugs.webkit.org/show_bug.cgi?id=236109
+
+        Reviewed by Eric Carlson.
+
+        Add the newly requried virtual method changes to MediaSample subclasses, and use
+        SharedBuffer rather than Uint8Array.
+
+        * GPUProcess/media/RemoteMediaPlayerProxy.cpp:
+        (WebKit::RemoteMediaPlayerProxy::mediaPlayerKeyNeeded):
+        * GPUProcess/media/RemoteMediaPlayerProxy.h:
+        * Shared/mac/MediaFormatReader/MediaFormatReader.cpp:
+        (WebKit::MediaFormatReader::parseByteSource):
+        (WebKit::MediaFormatReader::didProvideMediaData):
+        * Shared/mac/MediaFormatReader/MediaFormatReader.h:
+        * Shared/mac/MediaFormatReader/MediaSampleByteRange.h:
+        * WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:
+        (WebKit::MediaPlayerPrivateRemote::mediaPlayerKeyNeeded):
+
 2022-02-16  Stephan Szabo  <[email protected]>
 
         [PlayStation] Build fix after r289872

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp (289945 => 289946)


--- trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -698,11 +698,10 @@
     return nullptr;
 }
 
-void RemoteMediaPlayerProxy::mediaPlayerKeyNeeded(Uint8Array* message)
+void RemoteMediaPlayerProxy::mediaPlayerKeyNeeded(const SharedBuffer& message)
 {
     IPC::DataReference messageReference;
-    if (message)
-        messageReference = { message->data(), message->byteLength() };
+    messageReference = { message.data(), message.size() };
     m_webProcessConnection->send(Messages::MediaPlayerPrivateRemote::MediaPlayerKeyNeeded(WTFMove(messageReference)), m_id);
 }
 #endif

Modified: trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.h (289945 => 289946)


--- trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/GPUProcess/media/RemoteMediaPlayerProxy.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -249,7 +249,7 @@
 
 #if ENABLE(LEGACY_ENCRYPTED_MEDIA)
     RefPtr<ArrayBuffer> mediaPlayerCachedKeyForKeyId(const String&) const final;
-    void mediaPlayerKeyNeeded(Uint8Array*) final;
+    void mediaPlayerKeyNeeded(const WebCore::SharedBuffer&) final;
     String mediaPlayerMediaKeysStorageDirectory() const final;
 #endif
 

Modified: trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp (289945 => 289946)


--- trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -162,7 +162,7 @@
         didParseTracks({ }, errorCode);
     });
 
-    parser->setDidProvideMediaDataCallback([this, protectedThis = Ref { *this }](Ref<MediaSample>&& mediaSample, uint64_t trackID, const String& mediaType) {
+    parser->setDidProvideMediaDataCallback([this, protectedThis = Ref { *this }](Ref<MediaSampleAVFObjC>&& mediaSample, uint64_t trackID, const String& mediaType) {
         didProvideMediaData(WTFMove(mediaSample), trackID, mediaType);
     });
 
@@ -224,7 +224,7 @@
     m_init = true;
 }
 
-void MediaFormatReader::didProvideMediaData(Ref<MediaSample>&& mediaSample, uint64_t trackID, const String&)
+void MediaFormatReader::didProvideMediaData(Ref<MediaSampleAVFObjC>&& mediaSample, uint64_t trackID, const String&)
 {
     ASSERT(!isMainRunLoop());
 

Modified: trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.h (289945 => 289946)


--- trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaFormatReader.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -36,6 +36,7 @@
 DECLARE_CORE_MEDIA_TRAITS(FormatReader);
 
 namespace WebCore {
+class MediaSampleAVFObjC;
 class SourceBufferParser;
 }
 
@@ -67,7 +68,7 @@
     void didParseTracks(WebCore::SourceBufferPrivateClient::InitializationSegment&&, uint64_t errorCode);
     void didSelectVideoTrack(WebCore::VideoTrackPrivate&, bool) { }
     void didEnableAudioTrack(WebCore::AudioTrackPrivate&, bool) { }
-    void didProvideMediaData(Ref<WebCore::MediaSample>&&, uint64_t, const String&);
+    void didProvideMediaData(Ref<WebCore::MediaSampleAVFObjC>&&, uint64_t, const String&);
     void finishParsing(Ref<WebCore::SourceBufferParser>&&);
 
     // CMBaseClass

Modified: trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaSampleByteRange.h (289945 => 289946)


--- trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaSampleByteRange.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/Shared/mac/MediaFormatReader/MediaSampleByteRange.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -51,6 +51,7 @@
 
     AtomString trackID() const final;
     WebCore::PlatformSample platformSample() const final;
+    WebCore::PlatformSample::Type platformSampleType() const final { return WebCore::PlatformSample::ByteRangeSampleType; }
     void offsetTimestampsBy(const MediaTime&) final;
     void setTimestamps(const MediaTime&, const MediaTime&) final;
 

Modified: trunk/Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp (289945 => 289946)


--- trunk/Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1191,7 +1191,7 @@
 void MediaPlayerPrivateRemote::mediaPlayerKeyNeeded(IPC::DataReference&& message)
 {
     if (RefPtr player = m_player.get())
-        player->keyNeeded(Uint8Array::create(message.data(), message.size()).ptr());
+        player->keyNeeded(SharedBuffer::create(message));
 }
 #endif
 

Modified: trunk/Source/WebKit/WebProcess/GPU/media/RemoteVideoFrameProxy.h (289945 => 289946)


--- trunk/Source/WebKit/WebProcess/GPU/media/RemoteVideoFrameProxy.h	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Source/WebKit/WebProcess/GPU/media/RemoteVideoFrameProxy.h	2022-02-16 20:49:59 UTC (rev 289946)
@@ -102,6 +102,7 @@
     uint32_t videoPixelFormat() const final;
     // FIXME: When VideoFrame is not MediaSample, these will not be needed.
     WebCore::PlatformSample platformSample() const final;
+    WebCore::PlatformSample::Type platformSampleType() const final { return WebCore::PlatformSample::RemoteVideoFrameProxyType; }
 
 #if PLATFORM(COCOA)
     void getPixelBuffer();
@@ -143,9 +144,9 @@
 }
 
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebKit::RemoteVideoFrameProxy)
-    static bool isType(const WebCore::MediaSample& mediaSample) { return mediaSample.platformSample().type == WebCore::PlatformSample::RemoteVideoFrameProxyType; }
+    static bool isType(const WebCore::MediaSample& mediaSample) { return mediaSample.platformSampleType() == WebCore::PlatformSample::RemoteVideoFrameProxyType; }
 SPECIALIZE_TYPE_TRAITS_END()
 SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::VideoFrame)
-    static bool isType(const WebCore::MediaSample& mediaSample) { return mediaSample.platformSample().type == WebCore::PlatformSample::RemoteVideoFrameProxyType; }
+    static bool isType(const WebCore::MediaSample& mediaSample) { return mediaSample.platformSampleType() == WebCore::PlatformSample::RemoteVideoFrameProxyType; }
 SPECIALIZE_TYPE_TRAITS_END()
 #endif

Modified: trunk/Tools/ChangeLog (289945 => 289946)


--- trunk/Tools/ChangeLog	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Tools/ChangeLog	2022-02-16 20:49:59 UTC (rev 289946)
@@ -1,3 +1,12 @@
+2022-02-16  Jer Noble  <[email protected]>
+
+        [Cocoa] Adopt -streamDataParser:didProvideContentKeySpecifier:forTrackID: delegate callback
+        https://bugs.webkit.org/show_bug.cgi?id=236109
+
+        Reviewed by Eric Carlson.
+
+        * TestWebKitAPI/Tests/WebCore/SampleMap.cpp:
+
 2022-02-16  David Kilzer  <[email protected]>
 
         Workaround ASAN false positive stack-buffer-underflow bmalloc_allocate_impl_casual_case

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp (289945 => 289946)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp	2022-02-16 20:26:05 UTC (rev 289945)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/SampleMap.cpp	2022-02-16 20:49:59 UTC (rev 289946)
@@ -71,6 +71,7 @@
     }
     SampleFlags flags() const final { return m_flags; }
     PlatformSample platformSample() const final { return { PlatformSample::None, { nullptr } }; }
+    PlatformSample::Type platformSampleType() const final { return PlatformSample::None; }
     std::optional<ByteRange> byteRange() const final { return std::nullopt; }
 
     void dump(PrintStream&) const final { }
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to