Title: [276755] releases/WebKitGTK/webkit-2.32/Source/WebCore
Revision
276755
Author
[email protected]
Date
2021-04-29 01:09:13 -0700 (Thu, 29 Apr 2021)

Log Message

Merge r273644 - [GStreamer][Playbin3] Stream collection handling fixes
https://bugs.webkit.org/show_bug.cgi?id=222322

Patch by Philippe Normand <[email protected]> on 2021-03-01
Reviewed by Xabier Rodriguez-Calvar.

The track orphaning trying to avoid un-necessary track addition/removals was making the
whole thing inconsistent with the final stream collection. Also stream-collection messages
don't need to be handled from a synchronous GstBus handler, this should be needed for
need-context messages only, so the corresponding code has been refactored.

This patch also includes changes and cleanups for the mediastreamsrc element, needed after
the stream collection handling fixes. Most notably the element now keeps an internal list of
tracks, in addition to observing the MediaStreamPrivate for topology changes. Also it emits
a new stream collection whenever a new source pad has been added.

No new tests, but this patch fixes flakyness of http/tests/media/hls/hls-audio-tracks.html
when the pipeline is driven by playbin3.

* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
(WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
(WebCore::MediaPlayerPrivateGStreamer::updateTracks):
(WebCore::MediaPlayerPrivateGStreamer::setPipeline):
(WebCore::MediaPlayerPrivateGStreamer::handleStreamCollectionMessage):
(WebCore::MediaPlayerPrivateGStreamer::handleNeedContextMessage):
(WebCore::MediaPlayerPrivateGStreamer::handleMessage):
(WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
* platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
* platform/graphics/gstreamer/mse/AppendPipeline.cpp:
(WebCore::AppendPipeline::handleNeedContextSyncMessage):
* platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:
(stopObservingTracks):
(webkitMediaStreamSrcDispose):
(webkitMediaStreamSrcAddPad):
(ProbeData::ProbeData):
(webkitMediaStreamSrcPadProbeCb):
(webkitMediaStreamSrcSetupSrc):
(webkitMediaStreamSrcPostStreamCollection):
(webkitMediaStreamSrcAddTrack):
(webkitMediaStreamSrcSetStream):
(webkitMediaStreamSrcTrackEnded):

Modified Paths

Diff

Modified: releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog (276754 => 276755)


--- releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog	2021-04-29 08:09:04 UTC (rev 276754)
+++ releases/WebKitGTK/webkit-2.32/Source/WebCore/ChangeLog	2021-04-29 08:09:13 UTC (rev 276755)
@@ -1,3 +1,46 @@
+2021-03-01  Philippe Normand  <[email protected]>
+
+        [GStreamer][Playbin3] Stream collection handling fixes
+        https://bugs.webkit.org/show_bug.cgi?id=222322
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        The track orphaning trying to avoid un-necessary track addition/removals was making the
+        whole thing inconsistent with the final stream collection. Also stream-collection messages
+        don't need to be handled from a synchronous GstBus handler, this should be needed for
+        need-context messages only, so the corresponding code has been refactored.
+
+        This patch also includes changes and cleanups for the mediastreamsrc element, needed after
+        the stream collection handling fixes. Most notably the element now keeps an internal list of
+        tracks, in addition to observing the MediaStreamPrivate for topology changes. Also it emits
+        a new stream collection whenever a new source pad has been added.
+
+        No new tests, but this patch fixes flakyness of http/tests/media/hls/hls-audio-tracks.html
+        when the pipeline is driven by playbin3.
+
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp:
+        (WebCore::MediaPlayerPrivateGStreamer::~MediaPlayerPrivateGStreamer):
+        (WebCore::MediaPlayerPrivateGStreamer::updateTracks):
+        (WebCore::MediaPlayerPrivateGStreamer::setPipeline):
+        (WebCore::MediaPlayerPrivateGStreamer::handleStreamCollectionMessage):
+        (WebCore::MediaPlayerPrivateGStreamer::handleNeedContextMessage):
+        (WebCore::MediaPlayerPrivateGStreamer::handleMessage):
+        (WebCore::MediaPlayerPrivateGStreamer::createGSTPlayBin):
+        * platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h:
+        * platform/graphics/gstreamer/mse/AppendPipeline.cpp:
+        (WebCore::AppendPipeline::handleNeedContextSyncMessage):
+        * platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp:
+        (stopObservingTracks):
+        (webkitMediaStreamSrcDispose):
+        (webkitMediaStreamSrcAddPad):
+        (ProbeData::ProbeData):
+        (webkitMediaStreamSrcPadProbeCb):
+        (webkitMediaStreamSrcSetupSrc):
+        (webkitMediaStreamSrcPostStreamCollection):
+        (webkitMediaStreamSrcAddTrack):
+        (webkitMediaStreamSrcSetStream):
+        (webkitMediaStreamSrcTrackEnded):
+
 2021-04-06  Philippe Normand  <[email protected]>
 
         [GTK][GStreamer] Web Audio - Media element source - Audio is cracking.

Modified: releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp (276754 => 276755)


--- releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2021-04-29 08:09:04 UTC (rev 276754)
+++ releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.cpp	2021-04-29 08:09:13 UTC (rev 276755)
@@ -101,20 +101,6 @@
 #undef GST_USE_UNSTABLE_API
 #endif // ENABLE(VIDEO) && USE(GSTREAMER_MPEGTS)
 
-#define CREATE_TRACK(type, Type) G_STMT_START {                         \
-        m_has##Type = true;                                             \
-        if (!useMediaSource) {                                          \
-            RefPtr<Type##TrackPrivateGStreamer> track = Type##TrackPrivateGStreamer::create(makeWeakPtr(*this), type##TrackIndex++, stream); \
-            if (!track->trackIndex()) {                                 \
-                track->setActive(true);                                 \
-                m_wanted##Type##StreamId = track->id();                 \
-                m_requested##Type##StreamId = track->id();              \
-            }                                                           \
-            m_##type##Tracks.add(track->id(), track);                   \
-            m_player->add##Type##Track(*track);                         \
-        }                                                               \
-    } G_STMT_END
-
 #if USE(GSTREAMER_GL)
 #include "GLVideoSinkGStreamer.h"
 #include "VideoTextureCopierGStreamer.h"
@@ -148,11 +134,6 @@
 static const FloatSize s_holePunchDefaultFrameSize(1280, 720);
 #endif
 
-static void busMessageCallback(GstBus*, GstMessage* message, MediaPlayerPrivateGStreamer* player)
-{
-    player->handleMessage(message);
-}
-
 static void initializeDebugCategory()
 {
     static std::once_flag onceFlag;
@@ -244,11 +225,10 @@
     }
 
     if (m_pipeline) {
-        GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
+        auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
         ASSERT(bus);
-        g_signal_handlers_disconnect_by_func(bus.get(), gpointer(busMessageCallback), this);
+        g_signal_handlers_disconnect_matched(bus.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
         gst_bus_remove_signal_watch(bus.get());
-        gst_bus_set_sync_handler(bus.get(), nullptr, nullptr, nullptr);
         g_signal_handlers_disconnect_matched(m_pipeline.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this);
     }
 
@@ -1484,17 +1464,8 @@
     g_list_free_full(streams, reinterpret_cast<GDestroyNotify>(g_free));
 }
 
-template<typename K, typename V>
-HashSet<K> hashSetFromHashMapKeys(const HashMap<K, V>& hashMap)
+void MediaPlayerPrivateGStreamer::updateTracks(const GRefPtr<GstStreamCollection>& streamCollection)
 {
-    HashSet<K> keys;
-    for (auto& key : hashMap.keys())
-        keys.add(key);
-    return keys;
-}
-
-void MediaPlayerPrivateGStreamer::updateTracks(GRefPtr<GstStreamCollection>&& streamCollection)
-{
     ASSERT(!m_isLegacyPlaybin);
 
     bool useMediaSource = isMediaSource();
@@ -1504,29 +1475,46 @@
     bool oldHasAudio = m_hasAudio;
     bool oldHasVideo = m_hasVideo;
 
-    // New stream collections override previous ones.
+    // New stream collections override previous ones so in order to keep our internal tracks
+    // consistent with the collection contents, we can't reuse our old tracks.
+#define REMOVE_OLD_TRACKS(type, Type) G_STMT_START {             \
+        for (const auto& trackId : m_##type##Tracks.keys()) {    \
+            auto track = m_##type##Tracks.get(trackId);          \
+            m_player->remove##Type##Track(*track);               \
+        }                                                        \
+        m_##type##Tracks.clear();                                \
+    } G_STMT_END
+
+    REMOVE_OLD_TRACKS(audio, Audio);
+    REMOVE_OLD_TRACKS(video, Video);
+    REMOVE_OLD_TRACKS(text, Text);
+
     unsigned audioTrackIndex = 0;
     unsigned videoTrackIndex = 0;
     unsigned textTrackIndex = 0;
-    HashSet<AtomString> orphanedAudioTrackIds = hashSetFromHashMapKeys(m_audioTracks);
-    HashSet<AtomString> orphanedVideoTrackIds = hashSetFromHashMapKeys(m_videoTracks);
-    HashSet<AtomString> orphanedTextTrackIds = hashSetFromHashMapKeys(m_textTracks);
+
+#define CREATE_TRACK(type, Type) G_STMT_START {                         \
+        m_has##Type = true;                                             \
+        if (!useMediaSource) {                                          \
+            RefPtr<Type##TrackPrivateGStreamer> track = Type##TrackPrivateGStreamer::create(makeWeakPtr(*this), type##TrackIndex, stream); \
+            auto trackId = track->id();                                 \
+            if (!type##TrackIndex) {                                    \
+                m_wanted##Type##StreamId = trackId;                     \
+                m_requested##Type##StreamId = trackId;                  \
+                track->setActive(true);                                 \
+            }                                                           \
+            type##TrackIndex++;                                         \
+            m_##type##Tracks.add(trackId, track);                       \
+            m_player->add##Type##Track(*track);                         \
+        }                                                               \
+    } G_STMT_END
+
     for (unsigned i = 0; i < length; i++) {
-        GRefPtr<GstStream> stream = gst_stream_collection_get_stream(streamCollection.get(), i);
-        String streamId(gst_stream_get_stream_id(stream.get()));
-        GstStreamType type = gst_stream_get_stream_type(stream.get());
+        auto* stream = gst_stream_collection_get_stream(streamCollection.get(), i);
+        String streamId(gst_stream_get_stream_id(stream));
+        auto type = gst_stream_get_stream_type(stream);
 
-        orphanedAudioTrackIds.remove(streamId);
-        orphanedVideoTrackIds.remove(streamId);
-        orphanedTextTrackIds.remove(streamId);
-
         GST_DEBUG_OBJECT(pipeline(), "Inspecting %s track with ID %s", gst_stream_type_get_name(type), streamId.utf8().data());
-        if ((type & GST_STREAM_TYPE_AUDIO && m_audioTracks.contains(streamId)) || (type & GST_STREAM_TYPE_VIDEO && m_videoTracks.contains(streamId))
-            || (type & GST_STREAM_TYPE_TEXT && m_textTracks.contains(streamId)))
-        {
-            GST_DEBUG_OBJECT(pipeline(), "%s track with ID %s already exists, skipping", gst_stream_type_get_name(type), streamId.utf8().data());
-            continue;
-        }
 
         if (type & GST_STREAM_TYPE_AUDIO)
             CREATE_TRACK(audio, Audio);
@@ -1540,17 +1528,6 @@
             GST_WARNING("Unknown track type found for stream %s", streamId.utf8().data());
     }
 
-#define REMOVE_ORPHANED_TRACKS(type, Type)            \
-    for (auto& trackId : orphaned##Type##TrackIds) {  \
-        auto iter = m_##type##Tracks.find(trackId);   \
-        m_player->remove##Type##Track(*iter->value);  \
-        m_##type##Tracks.remove(iter->key);           \
-    }
-
-    REMOVE_ORPHANED_TRACKS(audio, Audio);
-    REMOVE_ORPHANED_TRACKS(video, Video);
-    REMOVE_ORPHANED_TRACKS(text, Text);
-
     if (oldHasVideo != m_hasVideo || oldHasAudio != m_hasAudio)
         m_player->characteristicChanged();
 
@@ -1576,53 +1553,38 @@
     }
 
     m_pipeline = pipeline;
-
-    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
-    gst_bus_set_sync_handler(bus.get(), [](GstBus*, GstMessage* message, gpointer userData) {
-        auto& player = *static_cast<MediaPlayerPrivateGStreamer*>(userData);
-
-        if (player.handleSyncMessage(message)) {
-            gst_message_unref(message);
-            return GST_BUS_DROP;
-        }
-
-        return GST_BUS_PASS;
-    }, this, nullptr);
 }
 
-bool MediaPlayerPrivateGStreamer::handleSyncMessage(GstMessage* message)
+void MediaPlayerPrivateGStreamer::handleStreamCollectionMessage(GstMessage* message)
 {
-    if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STREAM_COLLECTION && !m_isLegacyPlaybin) {
-        GRefPtr<GstStreamCollection> collection;
-        gst_message_parse_stream_collection(message, &collection.outPtr());
-#ifndef GST_DISABLE_DEBUG
-        GST_DEBUG_OBJECT(pipeline(), "Received STREAM_COLLECTION message with upstream id \"%s\" defining the following streams:", gst_stream_collection_get_upstream_id(collection.get()));
-        unsigned numStreams = gst_stream_collection_get_size(collection.get());
-        for (unsigned i = 0; i < numStreams; i++) {
-            GstStream* stream = gst_stream_collection_get_stream(collection.get(), i);
-            GST_DEBUG_OBJECT(pipeline(), "#%u %s %s", i, gst_stream_type_get_name(gst_stream_get_stream_type(stream)), gst_stream_get_stream_id(stream));
-        }
-#endif
+    if (m_isLegacyPlaybin)
+        return;
 
-        if (collection) {
-            m_notifier->notify(MainThreadNotification::StreamCollectionChanged, [this, collection = WTFMove(collection)]() mutable {
-                this->updateTracks(WTFMove(collection));
-            });
-        }
+    ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_STREAM_COLLECTION);
+    GRefPtr<GstStreamCollection> collection;
+    gst_message_parse_stream_collection(message, &collection.outPtr());
 #ifndef GST_DISABLE_DEBUG
-    } else if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_STREAMS_SELECTED && !m_isLegacyPlaybin) {
-        GST_DEBUG_OBJECT(pipeline(), "Received STREAMS_SELECTED message selecting the following streams:");
-        unsigned numStreams = gst_message_streams_selected_get_size(message);
-        for (unsigned i = 0; i < numStreams; i++) {
-            GstStream* stream = gst_message_streams_selected_get_stream(message, i);
-            GST_DEBUG_OBJECT(pipeline(), "#%u %s %s", i, gst_stream_type_get_name(gst_stream_get_stream_type(stream)), gst_stream_get_stream_id(stream));
-        }
+    GST_DEBUG_OBJECT(pipeline(), "Received STREAM_COLLECTION message with upstream id \"%s\" defining the following streams:", gst_stream_collection_get_upstream_id(collection.get()));
+    unsigned numStreams = gst_stream_collection_get_size(collection.get());
+    for (unsigned i = 0; i < numStreams; i++) {
+        GstStream* stream = gst_stream_collection_get_stream(collection.get(), i);
+        GST_DEBUG_OBJECT(pipeline(), "#%u %s %s", i, gst_stream_type_get_name(gst_stream_get_stream_type(stream)), gst_stream_get_stream_id(stream));
+    }
 #endif
-    }
 
-    if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_NEED_CONTEXT)
-        return false;
+    if (!collection)
+        return;
 
+    callOnMainThreadAndWait([player = makeWeakPtr(*this), collection = WTFMove(collection)] {
+        if (player)
+            player->updateTracks(collection);
+    });
+}
+
+bool MediaPlayerPrivateGStreamer::handleNeedContextMessage(GstMessage* message)
+{
+    ASSERT(GST_MESSAGE_TYPE(message) == GST_MESSAGE_NEED_CONTEXT);
+
     const gchar* contextType;
     if (!gst_message_parse_context_type(message, &contextType))
         return false;
@@ -1848,7 +1810,6 @@
     case GST_MESSAGE_STATE_CHANGED: {
         if (!messageSourceIsPlaybin || m_isDelayingLoad)
             break;
-        updateStates();
 
         // Construct a filename for the graphviz dot file output.
         GstState newState;
@@ -1859,6 +1820,7 @@
 
         if (!m_isLegacyPlaybin && currentState == GST_STATE_PAUSED && newState == GST_STATE_PLAYING)
             playbin3SendSelectStreamsIfAppropriate();
+        updateStates();
 
         break;
     }
@@ -1991,7 +1953,15 @@
         if (m_isLegacyPlaybin)
             break;
 
-        GST_DEBUG_OBJECT(m_pipeline.get(), "Received STREAMS_SELECTED, setting m_waitingForStreamsSelectedEvent to false.");
+#ifndef GST_DISABLE_DEBUG
+        GST_DEBUG_OBJECT(m_pipeline.get(), "Received STREAMS_SELECTED message selecting the following streams:");
+        unsigned numStreams = gst_message_streams_selected_get_size(message);
+        for (unsigned i = 0; i < numStreams; i++) {
+            GstStream* stream = gst_message_streams_selected_get_stream(message, i);
+            GST_DEBUG_OBJECT(pipeline(), "#%u %s %s", i, gst_stream_type_get_name(gst_stream_get_stream_type(stream)), gst_stream_get_stream_id(stream));
+        }
+#endif
+        GST_DEBUG_OBJECT(m_pipeline.get(), "Setting m_waitingForStreamsSelectedEvent to false.");
         m_waitingForStreamsSelectedEvent = false;
 
         // Unfortunately, STREAMS_SELECTED messages from playbin3 are highly unreliable, often only including the audio
@@ -2006,6 +1976,9 @@
         playbin3SendSelectStreamsIfAppropriate();
         break;
     }
+    case GST_MESSAGE_STREAM_COLLECTION:
+        handleStreamCollectionMessage(message);
+        break;
     default:
         GST_DEBUG_OBJECT(pipeline(), "Unhandled GStreamer message type: %s", GST_MESSAGE_TYPE_NAME(message));
         break;
@@ -2741,9 +2714,15 @@
     setPlaybackFlags(pipeline());
 
     // Let also other listeners subscribe to (application) messages in this bus.
-    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
+    auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(m_pipeline.get())));
+    gst_bus_enable_sync_message_emission(bus.get());
     gst_bus_add_signal_watch_full(bus.get(), RunLoopSourcePriority::RunLoopDispatcher);
-    g_signal_connect(bus.get(), "message", G_CALLBACK(busMessageCallback), this);
+    g_signal_connect_swapped(bus.get(), "message", G_CALLBACK(+[](MediaPlayerPrivateGStreamer* player, GstMessage* message) {
+        player->handleMessage(message);
+    }), this);
+    g_signal_connect_swapped(bus.get(), "sync-message::need-context", G_CALLBACK(+[](MediaPlayerPrivateGStreamer* player, GstMessage* message) {
+        player->handleNeedContextMessage(message);
+    }), this);
 
     g_object_set(m_pipeline.get(), "mute", m_player->muted(), nullptr);
 

Modified: releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h (276754 => 276755)


--- releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h	2021-04-29 08:09:04 UTC (rev 276754)
+++ releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/MediaPlayerPrivateGStreamer.h	2021-04-29 08:09:13 UTC (rev 276755)
@@ -214,8 +214,10 @@
     void playbin3SendSelectStreamsIfAppropriate();
 
     // Append pipeline interface
-    // FIXME: Use the client interface pattern, AppendPipeline does not need the full interface to this class just for these two functions.
-    bool handleSyncMessage(GstMessage*);
+    // FIXME: Use the client interface pattern, AppendPipeline does not need the full interface to this class just for this function.
+    bool handleNeedContextMessage(GstMessage*);
+
+    void handleStreamCollectionMessage(GstMessage*);
     void handleMessage(GstMessage*);
 
     void triggerRepaint(GstSample*);
@@ -443,7 +445,7 @@
     void setPlaybinURL(const URL& urlString);
     void loadFull(const String& url, const String& pipelineName);
 
-    void updateTracks(GRefPtr<GstStreamCollection>&&);
+    void updateTracks(const GRefPtr<GstStreamCollection>&);
     void videoSinkCapsChanged(GstPad*);
     void updateVideoSizeAndOrientationFromCaps(const GstCaps*);
 

Modified: releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp (276754 => 276755)


--- releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2021-04-29 08:09:04 UTC (rev 276754)
+++ releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/graphics/gstreamer/mse/AppendPipeline.cpp	2021-04-29 08:09:13 UTC (rev 276755)
@@ -329,12 +329,8 @@
 
 void AppendPipeline::handleNeedContextSyncMessage(GstMessage* message)
 {
-    const gchar* contextType = nullptr;
-    gst_message_parse_context_type(message, &contextType);
-    GST_TRACE("context type: %s", contextType);
-
     // MediaPlayerPrivateGStreamerBase will take care of setting up encryption.
-    m_playerPrivate->handleSyncMessage(message);
+    m_playerPrivate->handleNeedContextMessage(message);
 }
 
 void AppendPipeline::handleStateChangeMessage(GstMessage* message)

Modified: releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp (276754 => 276755)


--- releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp	2021-04-29 08:09:04 UTC (rev 276754)
+++ releases/WebKitGTK/webkit-2.32/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp	2021-04-29 08:09:13 UTC (rev 276755)
@@ -35,6 +35,7 @@
 #include "VideoTrackPrivate.h"
 
 #include <gst/app/gstappsrc.h>
+#include <wtf/UUID.h>
 #include <wtf/glib/WTFGType.h>
 
 using namespace WebCore;
@@ -44,6 +45,7 @@
 static void webkitMediaStreamSrcTrackEnded(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&);
 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc*, RealtimeMediaSource::Type);
 static void webkitMediaStreamSrcRemoveTrackObserver(WebKitMediaStreamSrc*, MediaStreamTrackPrivate&);
+static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc*);
 
 static GstStaticPadTemplate videoSrcTemplate = GST_STATIC_PAD_TEMPLATE("video_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
     GST_STATIC_CAPS("video/x-raw;video/x-h264;video/x-vp8"));
@@ -142,7 +144,7 @@
     }
 
 private:
-    GstElement* m_src;
+    GstElement* m_src { nullptr };
     bool m_enabled { true };
 };
 
@@ -263,7 +265,7 @@
     std::unique_ptr<WebKitMediaStreamTrackObserver> mediaStreamTrackObserver;
     std::unique_ptr<WebKitMediaStreamObserver> mediaStreamObserver;
     RefPtr<MediaStreamPrivate> stream;
-    RefPtr<MediaStreamTrackPrivate> track;
+    Vector<RefPtr<MediaStreamTrackPrivate>> tracks;
     GUniquePtr<GstFlowCombiner> flowCombiner;
     GRefPtr<GstStreamCollection> streamCollection;
 };
@@ -373,11 +375,8 @@
 {
     GST_OBJECT_LOCK(self);
     auto* priv = self->priv;
-    if (priv->stream) {
-        for (auto& track : priv->stream->tracks())
-            webkitMediaStreamSrcRemoveTrackObserver(self, *track);
-    } else if (priv->track)
-        webkitMediaStreamSrcRemoveTrackObserver(self, *priv->track);
+    for (auto& track : priv->tracks)
+        webkitMediaStreamSrcRemoveTrackObserver(self, *track);
     GST_OBJECT_UNLOCK(self);
 }
 
@@ -393,7 +392,6 @@
         priv->stream->removeObserver(*priv->mediaStreamObserver);
         priv->stream = nullptr;
     }
-    priv->track = nullptr;
     GST_OBJECT_UNLOCK(self);
 
     GST_CALL_PARENT(G_OBJECT_CLASS, dispose, (object));
@@ -445,13 +443,12 @@
     return result;
 }
 
-static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags)
+static void webkitMediaStreamSrcAddPad(WebKitMediaStreamSrc* self, GstPad* target, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, RealtimeMediaSource::Type sourceType)
 {
     GST_DEBUG_OBJECT(self, "%s Ghosting %" GST_PTR_FORMAT, gst_object_get_path_string(GST_OBJECT_CAST(self)), target);
 
-    static Atomic<uint32_t> nextPadId;
-    auto padName = makeString("src_", nextPadId.exchangeAdd(1));
-    auto* ghostPad = webkitGstGhostPadFromStaticTemplate(padTemplate, padName.utf8().data(), target);
+    const char* padName = sourceType == RealtimeMediaSource::Type::Audio ? "audio_src" : "video_src";
+    auto* ghostPad = webkitGstGhostPadFromStaticTemplate(padTemplate, padName, target);
     gst_pad_set_active(ghostPad, TRUE);
     gst_element_add_pad(GST_ELEMENT_CAST(self), ghostPad);
 
@@ -463,12 +460,13 @@
 }
 
 struct ProbeData {
-    ProbeData(GstElement* element, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, const char* trackId)
+    ProbeData(GstElement* element, GstStaticPadTemplate* padTemplate, GRefPtr<GstTagList>&& tags, const char* trackId, RealtimeMediaSource::Type sourceType)
         : element(element)
         , padTemplate(padTemplate)
         , tags(WTFMove(tags))
+        , trackId(g_strdup(trackId))
+        , sourceType(sourceType)
     {
-        this->trackId.reset(g_strdup(trackId));
     }
 
     GRefPtr<GstElement> element;
@@ -475,6 +473,7 @@
     GstStaticPadTemplate* padTemplate;
     GRefPtr<GstTagList> tags;
     GUniquePtr<char> trackId;
+    RealtimeMediaSource::Type sourceType;
 };
 
 static GstPadProbeReturn webkitMediaStreamSrcPadProbeCb(GstPad* pad, GstPadProbeInfo* info, ProbeData* data)
@@ -496,7 +495,10 @@
         gst_event_set_group_id(streamStart, 1);
         gst_pad_push_event(pad, streamStart);
 
-        webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags));
+        webkitMediaStreamSrcAddPad(self, pad, data->padTemplate, WTFMove(data->tags), data->sourceType);
+        callOnMainThreadAndWait([element = data->element] {
+            webkitMediaStreamSrcPostStreamCollection(WEBKIT_MEDIA_STREAM_SRC(element.get()));
+        });
         return GST_PAD_PROBE_REMOVE;
     }
     default:
@@ -508,19 +510,31 @@
 
 static void webkitMediaStreamSrcSetupSrc(WebKitMediaStreamSrc* self, MediaStreamTrackPrivate* track, GstElement* element, GstStaticPadTemplate* padTemplate, bool onlyTrack)
 {
-    GST_DEBUG_OBJECT(self, "Setup source %" GST_PTR_FORMAT ", only track: %s", element, boolForPrinting(onlyTrack));
+    const char* sourceType = "unknown";
+    switch (track->source().type()) {
+    case RealtimeMediaSource::Type::Audio:
+        sourceType = "audio";
+        break;
+    case RealtimeMediaSource::Type::Video:
+        sourceType = "video";
+        break;
+    case RealtimeMediaSource::Type::None:
+        ASSERT_NOT_REACHED();
+    }
+
+    GST_DEBUG_OBJECT(self, "Setup %s source for track %s, only track: %s", sourceType, track->id().utf8().data(), boolForPrinting(onlyTrack));
     gst_bin_add(GST_BIN_CAST(self), element);
 
     auto pad = adoptGRef(gst_element_get_static_pad(element, "src"));
     auto tags = mediaStreamTrackPrivateGetTags(track);
     if (!onlyTrack) {
-        auto* data = "" ProbeData(GST_ELEMENT_CAST(self), padTemplate, WTFMove(tags), track->id().utf8().data());
+        auto* data = "" ProbeData(GST_ELEMENT_CAST(self), padTemplate, WTFMove(tags), track->id().utf8().data(), track->source().type());
         gst_pad_add_probe(pad.get(), GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, reinterpret_cast<GstPadProbeCallback>(webkitMediaStreamSrcPadProbeCb), data, [](gpointer data) {
             delete reinterpret_cast<ProbeData*>(data);
         });
     } else {
         gst_pad_set_active(pad.get(), TRUE);
-        webkitMediaStreamSrcAddPad(self, pad.get(), padTemplate, WTFMove(tags));
+        webkitMediaStreamSrcAddPad(self, pad.get(), padTemplate, WTFMove(tags), track->source().type());
     }
 
     auto* priv = self->priv;
@@ -542,14 +556,18 @@
 static void webkitMediaStreamSrcPostStreamCollection(WebKitMediaStreamSrc* self)
 {
     auto* priv = self->priv;
-    ASSERT(priv->stream);
+
     GST_OBJECT_LOCK(self);
-    priv->streamCollection = adoptGRef(gst_stream_collection_new(priv->stream->id().utf8().data()));
-    for (auto& track : priv->stream->tracks())
+    String upstreamId;
+    if (priv->stream)
+        upstreamId = priv->stream->id();
+    else
+        upstreamId = createCanonicalUUIDString();
+
+    priv->streamCollection = adoptGRef(gst_stream_collection_new(upstreamId.ascii().data()));
+    for (auto& track : priv->tracks)
         gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(track.get()));
 
-    if (priv->track)
-        gst_stream_collection_add_stream(priv->streamCollection.get(), webkitMediaStreamNew(priv->track.get()));
     GST_OBJECT_UNLOCK(self);
 
     GST_DEBUG_OBJECT(self, "Posting stream collection");
@@ -568,8 +586,7 @@
     } else
         GST_INFO_OBJECT(self, "Unsupported track type: %d", static_cast<int>(track->type()));
 
-    if ((priv->videoSrc || priv->audioSrc) && onlyTrack)
-        self->priv->track = track;
+    self->priv->tracks.append(track);
 }
 
 static void webkitMediaStreamSrcRemoveTrackByType(WebKitMediaStreamSrc* self, RealtimeMediaSource::Type trackType)
@@ -587,7 +604,6 @@
     ASSERT(WEBKIT_IS_MEDIA_STREAM_SRC(self));
     ASSERT(!self->priv->stream);
     self->priv->stream = stream;
-    webkitMediaStreamSrcPostStreamCollection(self);
 
     self->priv->stream->addObserver(*self->priv->mediaStreamObserver.get());
     auto tracks = stream->tracks();
@@ -594,6 +610,9 @@
     bool _onlyTrack_ = tracks.size() == 1;
     for (auto& track : tracks)
         webkitMediaStreamSrcAddTrack(self, track.get(), onlyTrack);
+
+    webkitMediaStreamSrcPostStreamCollection(self);
+    gst_element_no_more_pads(GST_ELEMENT_CAST(self));
 }
 
 static void webkitMediaStreamSrcPushVideoSample(WebKitMediaStreamSrc* self, GstSample* sample)
@@ -614,17 +633,22 @@
 
     GST_DEBUG_OBJECT(self, "Track %s ended", track.label().utf8().data());
     GST_OBJECT_LOCK(self);
-    for (auto* item = GST_ELEMENT_CAST(self)->srcpads; item; item = item->next) {
-        auto* currentPad = GST_PAD_CAST(item->data);
-        auto streamStart = adoptGRef(gst_pad_get_sticky_event(currentPad, GST_EVENT_STREAM_START, 0));
-        if (!streamStart)
-            continue;
+    GstElement* element = GST_ELEMENT_CAST(self);
+    if (element->numpads == 1)
+        pad = GST_PAD_CAST(element->srcpads->data);
+    else {
+        for (auto* item = element->srcpads; item; item = item->next) {
+            auto* currentPad = GST_PAD_CAST(item->data);
+            auto streamStart = adoptGRef(gst_pad_get_sticky_event(currentPad, GST_EVENT_STREAM_START, 0));
+            if (!streamStart)
+                continue;
 
-        const char* streamId;
-        gst_event_parse_stream_start(streamStart.get(), &streamId);
-        if (!g_strcmp0(streamId, track.id().utf8().data())) {
-            pad = currentPad;
-            break;
+            const char* streamId;
+            gst_event_parse_stream_start(streamStart.get(), &streamId);
+            if (track.id() == streamId) {
+                pad = currentPad;
+                break;
+            }
         }
     }
     GST_OBJECT_UNLOCK(self);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to