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);