Title: [271290] trunk
Revision
271290
Author
[email protected]
Date
2021-01-08 05:16:25 -0800 (Fri, 08 Jan 2021)

Log Message

[GStreamer] WebAudio provider should clean-up its bin when the client disappears
https://bugs.webkit.org/show_bug.cgi?id=219245

Reviewed by Xabier Rodriguez-Calvar.

Source/WebCore:

Clean-up elements downstream of the deinterleave element when the provider client changes or
is removed.

* platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp:
(WebCore::copyGStreamerBuffersToAudioChannel):
(WebCore::AudioSourceProviderGStreamer::provideInput):
(WebCore::AudioSourceProviderGStreamer::handleSample):
(WebCore::AudioSourceProviderGStreamer::setClient):
(WebCore::AudioSourceProviderGStreamer::handleRemovedDeinterleavePad):
(WebCore::AudioSourceProviderGStreamer::deinterleavePadsConfigured):
* platform/graphics/gstreamer/GStreamerCommon.cpp:
(WebCore::disconnectSimpleBusMessageCallback): Drive-by, remove bus signal handler.
(WebCore::connectSimpleBusMessageCallback):
* platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp: Drive-by, define
GST_CAT_DEFAULT earlier so that all GST_DEBUG call sites actually log something.

LayoutTests:

Unflag tests no longer crashing.

* platform/glib/TestExpectations:
* platform/gtk-wayland/TestExpectations:
* platform/gtk/TestExpectations:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (271289 => 271290)


--- trunk/LayoutTests/ChangeLog	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/LayoutTests/ChangeLog	2021-01-08 13:16:25 UTC (rev 271290)
@@ -1,3 +1,16 @@
+2021-01-08  Philippe Normand  <[email protected]>
+
+        [GStreamer] WebAudio provider should clean-up its bin when the client disappears
+        https://bugs.webkit.org/show_bug.cgi?id=219245
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Unflag tests no longer crashing.
+
+        * platform/glib/TestExpectations:
+        * platform/gtk-wayland/TestExpectations:
+        * platform/gtk/TestExpectations:
+
 2021-01-07  Zalan Bujtas  <[email protected]>
 
         paypal.com: text at the bottom of the page is not aligned properly

Modified: trunk/LayoutTests/platform/glib/TestExpectations (271289 => 271290)


--- trunk/LayoutTests/platform/glib/TestExpectations	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/LayoutTests/platform/glib/TestExpectations	2021-01-08 13:16:25 UTC (rev 271290)
@@ -452,13 +452,6 @@
 
 webkit.org/b/218580 fast/mediastream/captureStream/canvas2d.html [ Failure Timeout ]
 
-webkit.org/b/219245 webrtc/audio-replace-track.html [ Crash ]
-webkit.org/b/219245 webrtc/peer-connection-audio-mute.html [ Crash ]
-webkit.org/b/219245 webrtc/peer-connection-audio-mute2.html [ Crash ]
-webkit.org/b/219245 webrtc/peer-connection-audio-unmute.html [ Crash ]
-webkit.org/b/219245 webrtc/peer-connection-remote-audio-mute.html [ Crash ]
-webkit.org/b/219245 webrtc/peer-connection-remote-audio-mute2.html [ Crash ]
-
 #////////////////////////////////////////////////////////////////////////////////////////
 # End of GStreamer-related bugs
 #////////////////////////////////////////////////////////////////////////////////////////

Modified: trunk/LayoutTests/platform/gtk/TestExpectations (271289 => 271290)


--- trunk/LayoutTests/platform/gtk/TestExpectations	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/LayoutTests/platform/gtk/TestExpectations	2021-01-08 13:16:25 UTC (rev 271290)
@@ -1404,7 +1404,7 @@
 
 webkit.org/b/193311 fast/images/decode-render-animated-image.html [ ImageOnlyFailure Pass ]
 
-webkit.org/b/193318 webkit.org/b/219245 webrtc/audio-replace-track.html [ Timeout Pass Crash ]
+webkit.org/b/193318 webrtc/audio-replace-track.html [ Timeout Pass ]
 
 webkit.org/b/193490 [ Debug ] animations/play-state-suspend.html [ Pass Failure ]
 

Modified: trunk/LayoutTests/platform/gtk-wayland/TestExpectations (271289 => 271290)


--- trunk/LayoutTests/platform/gtk-wayland/TestExpectations	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/LayoutTests/platform/gtk-wayland/TestExpectations	2021-01-08 13:16:25 UTC (rev 271290)
@@ -32,7 +32,7 @@
 webkit.org/b/217363 imported/w3c/web-platform-tests/xhr/sync-no-timeout.any.html [ Failure Crash ]
 
 # WebRTC
-webkit.org/b/219245 webkit.org/b/212892 webrtc/peer-connection-audio-mute2.html [ Failure Timeout Pass Crash ]
+webkit.org/b/212892 webrtc/peer-connection-audio-mute2.html [ Failure Timeout Pass Crash ]
 
 # Workers
 ## Crashing in X11, but also timing out in Wayland

Modified: trunk/Source/WebCore/ChangeLog (271289 => 271290)


--- trunk/Source/WebCore/ChangeLog	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/Source/WebCore/ChangeLog	2021-01-08 13:16:25 UTC (rev 271290)
@@ -1,3 +1,26 @@
+2021-01-08  Philippe Normand  <[email protected]>
+
+        [GStreamer] WebAudio provider should clean-up its bin when the client disappears
+        https://bugs.webkit.org/show_bug.cgi?id=219245
+
+        Reviewed by Xabier Rodriguez-Calvar.
+
+        Clean-up elements downstream of the deinterleave element when the provider client changes or
+        is removed.
+
+        * platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp:
+        (WebCore::copyGStreamerBuffersToAudioChannel):
+        (WebCore::AudioSourceProviderGStreamer::provideInput):
+        (WebCore::AudioSourceProviderGStreamer::handleSample):
+        (WebCore::AudioSourceProviderGStreamer::setClient):
+        (WebCore::AudioSourceProviderGStreamer::handleRemovedDeinterleavePad):
+        (WebCore::AudioSourceProviderGStreamer::deinterleavePadsConfigured):
+        * platform/graphics/gstreamer/GStreamerCommon.cpp:
+        (WebCore::disconnectSimpleBusMessageCallback): Drive-by, remove bus signal handler.
+        (WebCore::connectSimpleBusMessageCallback):
+        * platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp: Drive-by, define
+        GST_CAT_DEFAULT earlier so that all GST_DEBUG call sites actually log something.
+
 2021-01-08  Xabier Rodriguez Calvar  <[email protected]>
 
         [GStreamer][EME][Thunder] Accept no protection system specific caps for CENC

Modified: trunk/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp (271289 => 271290)


--- trunk/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/Source/WebCore/platform/audio/gstreamer/AudioSourceProviderGStreamer.cpp	2021-01-08 13:16:25 UTC (rev 271290)
@@ -67,10 +67,12 @@
 {
     auto available = gst_adapter_available(adapter);
     if (!available) {
+        GST_TRACE("Adapter empty, silencing bus");
         bus->zero();
         return;
     }
 
+    GST_TRACE("%zu samples available for channel %d (%zu frames requested)", available, channelNumber, framesToProcess);
     size_t bytes = framesToProcess * sizeof(float);
     if (available >= bytes) {
         gst_adapter_copy(adapter, bus->channel(channelNumber)->mutableData(), 0, bytes);
@@ -150,6 +152,7 @@
 
 void AudioSourceProviderGStreamer::provideInput(AudioBus* bus, size_t framesToProcess)
 {
+    GST_TRACE("Fetching buffers from adapters");
     auto locker = holdLock(m_adapterMutex);
     for (auto& it : m_adapters)
         copyGStreamerBuffersToAudioChannel(it.value.get(), bus, it.key - 1, framesToProcess);
@@ -157,6 +160,7 @@
 
 GstFlowReturn AudioSourceProviderGStreamer::handleSample(GstAppSink* sink, bool isPreroll)
 {
+    GST_TRACE("Pulling audio sample from the sink");
     auto sample = adoptGRef(isPreroll ? gst_app_sink_try_pull_preroll(sink, 0) : gst_app_sink_try_pull_sample(sink, 0));
     if (!sample)
         return gst_app_sink_is_eos(sink) ? GST_FLOW_EOS : GST_FLOW_ERROR;
@@ -168,10 +172,13 @@
     if (!buffer)
         return GST_FLOW_ERROR;
 
+    GST_TRACE("Storing audio sample %" GST_PTR_FORMAT, sample.get());
     {
         auto locker = holdLock(m_adapterMutex);
         GQuark quark = g_quark_from_static_string("channel-id");
         int channelId = GPOINTER_TO_INT(g_object_get_qdata(G_OBJECT(sink), quark));
+        GST_DEBUG("Channel ID: %d", channelId);
+
         auto result = m_adapters.ensure(channelId, [&] {
             return gst_adapter_new();
         });
@@ -189,18 +196,10 @@
     if (m_client == client)
         return;
 
+    GST_DEBUG("Setting up client %p (previous: %p)", client, m_client);
+    bool previousClientWasValid = m_client;
     m_client = client;
 
-#if ENABLE(MEDIA_STREAM)
-    if (m_pipeline)
-        gst_element_set_state(m_pipeline.get(), m_client ? GST_STATE_PLAYING : GST_STATE_NULL);
-#endif
-
-    // FIXME: This early return should ideally be replaced by a removal of the m_audioSinkBin from
-    // its parent pipeline. https://bugs.webkit.org/show_bug.cgi?id=219245
-    if (!m_client)
-        return;
-
     // The volume element is used to mute audio playback towards the
     // autoaudiosink. This is needed to avoid double playback of audio
     // from our audio sink and from the WebAudio AudioDestination node
@@ -207,46 +206,80 @@
     // supposedly configured already by application side.
     auto volumeElement = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "volume"));
 
-    if (volumeElement)
-        g_object_set(volumeElement.get(), "mute", TRUE, nullptr);
+    if (volumeElement) {
+        bool shouldMute = m_client;
+        g_object_set(volumeElement.get(), "mute", shouldMute, nullptr);
+    }
 
-    // The audioconvert and audioresample elements are needed to
-    // ensure deinterleave and the sinks downstream receive buffers in
-    // the format specified by the capsfilter.
-    GstElement* audioQueue = gst_element_factory_make("queue", nullptr);
-    GstElement* audioConvert  = gst_element_factory_make("audioconvert", nullptr);
-    GstElement* audioResample = gst_element_factory_make("audioresample", nullptr);
-    GstElement* capsFilter = gst_element_factory_make("capsfilter", nullptr);
-    GstElement* deInterleave = gst_element_factory_make("deinterleave", "deinterleave");
+    auto audioTee = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "audioTee"));
+    if (!m_client || previousClientWasValid) {
+        auto audioQueue = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "queue"));
+        auto audioConvert = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "audioconvert"));
+        auto audioResample = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "audioresample"));
+        auto capsFilter = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "capsfilter"));
+        auto deInterleave = adoptGRef(gst_bin_get_by_name(GST_BIN_CAST(m_audioSinkBin.get()), "deinterleave"));
+        auto queueSinkPad = adoptGRef(gst_element_get_static_pad(audioQueue.get(), "sink"));
+        auto teeSrcPad = adoptGRef(gst_pad_get_peer(queueSinkPad.get()));
 
-    g_object_set(deInterleave, "keep-positions", TRUE, nullptr);
-    m_deinterleavePadAddedHandlerId = g_signal_connect(deInterleave, "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this);
-    m_deinterleaveNoMorePadsHandlerId = g_signal_connect(deInterleave, "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this);
-    m_deinterleavePadRemovedHandlerId = g_signal_connect(deInterleave, "pad-removed", G_CALLBACK(onGStreamerDeinterleavePadRemovedCallback), this);
+        GST_DEBUG("Cleaning up audio deinterleave chain");
+        gst_element_set_locked_state(m_audioSinkBin.get(), true);
 
-    auto caps = adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, static_cast<int>(gSampleBitRate),
-        "format", G_TYPE_STRING, GST_AUDIO_NE(F32), "layout", G_TYPE_STRING, "interleaved", nullptr));
-    g_object_set(capsFilter, "caps", caps.get(), nullptr);
+        gst_element_set_state(audioQueue.get(), GST_STATE_NULL);
+        gst_element_set_state(audioConvert.get(), GST_STATE_NULL);
+        gst_element_set_state(audioResample.get(), GST_STATE_NULL);
+        gst_element_set_state(capsFilter.get(), GST_STATE_NULL);
+        gst_element_set_state(deInterleave.get(), GST_STATE_NULL);
+        gst_element_unlink_many(audioTee.get(), audioQueue.get(), audioConvert.get(), audioResample.get(), capsFilter.get(), deInterleave.get(), nullptr);
+        gst_element_set_locked_state(m_audioSinkBin.get(), false);
+        gst_bin_remove_many(GST_BIN_CAST(m_audioSinkBin.get()), audioQueue.get(), audioConvert.get(), audioResample.get(), capsFilter.get(), deInterleave.get(), nullptr);
+        gst_element_release_request_pad(audioTee.get(), teeSrcPad.get());
+    }
 
-    gst_bin_add_many(GST_BIN_CAST(m_audioSinkBin.get()), audioQueue, audioConvert, audioResample, capsFilter, deInterleave, nullptr);
+    if (m_client) {
+        // The audioconvert and audioresample elements are needed to
+        // ensure deinterleave and the sinks downstream receive buffers in
+        // the format specified by the capsfilter.
+        auto* audioQueue = gst_element_factory_make("queue", "queue");
+        auto* audioConvert = gst_element_factory_make("audioconvert", "audioconvert");
+        auto* audioResample = gst_element_factory_make("audioresample", "audioresample");
+        auto* capsFilter = gst_element_factory_make("capsfilter", "capsfilter");
+        auto* deInterleave = gst_element_factory_make("deinterleave", "deinterleave");
 
-    auto audioTee = adoptGRef(gst_bin_get_by_name(GST_BIN(m_audioSinkBin.get()), "audioTee"));
+        GST_DEBUG("Setting up audio deinterleave chain");
+        g_object_set(deInterleave, "keep-positions", TRUE, nullptr);
+        m_deinterleavePadAddedHandlerId = g_signal_connect(deInterleave, "pad-added", G_CALLBACK(onGStreamerDeinterleavePadAddedCallback), this);
+        m_deinterleaveNoMorePadsHandlerId = g_signal_connect(deInterleave, "no-more-pads", G_CALLBACK(onGStreamerDeinterleaveReadyCallback), this);
+        m_deinterleavePadRemovedHandlerId = g_signal_connect(deInterleave, "pad-removed", G_CALLBACK(onGStreamerDeinterleavePadRemovedCallback), this);
 
-    // Link a new src pad from tee to queue ! audioconvert !
-    // audioresample ! capsfilter ! deinterleave. Later
-    // on each deinterleaved planar audio channel will be routed to an
-    // appsink for data extraction and processing.
-    gst_element_link_pads_full(audioTee.get(), "src_%u", audioQueue, "sink", GST_PAD_LINK_CHECK_NOTHING);
-    gst_element_link_pads_full(audioQueue, "src", audioConvert, "sink", GST_PAD_LINK_CHECK_NOTHING);
-    gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
-    gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING);
-    gst_element_link_pads_full(capsFilter, "src", deInterleave, "sink", GST_PAD_LINK_CHECK_NOTHING);
+        auto caps = adoptGRef(gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, static_cast<int>(gSampleBitRate),
+            "format", G_TYPE_STRING, GST_AUDIO_NE(F32), "layout", G_TYPE_STRING, "interleaved", nullptr));
+        g_object_set(capsFilter, "caps", caps.get(), nullptr);
 
-    gst_element_sync_state_with_parent(audioQueue);
-    gst_element_sync_state_with_parent(audioConvert);
-    gst_element_sync_state_with_parent(audioResample);
-    gst_element_sync_state_with_parent(capsFilter);
-    gst_element_sync_state_with_parent(deInterleave);
+        gst_bin_add_many(GST_BIN_CAST(m_audioSinkBin.get()), audioQueue, audioConvert, audioResample, capsFilter, deInterleave, nullptr);
+
+        // Link a new src pad from tee to queue ! audioconvert !
+        // audioresample ! capsfilter ! deinterleave. Later
+        // on each deinterleaved planar audio channel will be routed to an
+        // appsink for data extraction and processing.
+        gst_element_link_pads_full(audioTee.get(), "src_%u", audioQueue, "sink", GST_PAD_LINK_CHECK_NOTHING);
+        gst_element_link_pads_full(audioQueue, "src", audioConvert, "sink", GST_PAD_LINK_CHECK_NOTHING);
+        gst_element_link_pads_full(audioConvert, "src", audioResample, "sink", GST_PAD_LINK_CHECK_NOTHING);
+        gst_element_link_pads_full(audioResample, "src", capsFilter, "sink", GST_PAD_LINK_CHECK_NOTHING);
+        gst_element_link_pads_full(capsFilter, "src", deInterleave, "sink", GST_PAD_LINK_CHECK_NOTHING);
+
+        gst_element_sync_state_with_parent(audioQueue);
+        gst_element_sync_state_with_parent(audioConvert);
+        gst_element_sync_state_with_parent(audioResample);
+        gst_element_sync_state_with_parent(capsFilter);
+        gst_element_sync_state_with_parent(deInterleave);
+    }
+
+    m_deinterleaveSourcePads = 0;
+    clearAdapters();
+#if ENABLE(MEDIA_STREAM)
+    if (m_pipeline)
+        gst_element_set_state(m_pipeline.get(), m_client ? GST_STATE_PLAYING : GST_STATE_NULL);
+#endif
 }
 
 void AudioSourceProviderGStreamer::handleNewDeinterleavePad(GstPad* pad)
@@ -305,6 +338,9 @@
 
 void AudioSourceProviderGStreamer::handleRemovedDeinterleavePad(GstPad* pad)
 {
+    if (GST_PAD_DIRECTION(pad) != GST_PAD_SRC)
+        return;
+
     GST_DEBUG("Pad %" GST_PTR_FORMAT " gone", pad);
     m_deinterleaveSourcePads--;
 
@@ -320,7 +356,7 @@
 
 void AudioSourceProviderGStreamer::deinterleavePadsConfigured()
 {
-    GST_DEBUG("Deinterleave configured, notifying client");
+    GST_DEBUG("Deinterleave configured with %d channels, notifying client", m_deinterleaveSourcePads);
     m_notifier->notify(MainThreadNotification::DeinterleavePadsConfigured, [numberOfChannels = m_deinterleaveSourcePads, sampleRate = gSampleBitRate, client = m_client] {
         if (client)
             client->setFormat(numberOfChannels, sampleRate);

Modified: trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp (271289 => 271290)


--- trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/Source/WebCore/platform/graphics/gstreamer/GStreamerCommon.cpp	2021-01-08 13:16:25 UTC (rev 271290)
@@ -404,13 +404,14 @@
 
 void disconnectSimpleBusMessageCallback(GstElement* pipeline)
 {
-    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline)));
+    auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline)));
     g_signal_handlers_disconnect_by_func(bus.get(), reinterpret_cast<gpointer>(simpleBusMessageCallback), pipeline);
+    gst_bus_remove_signal_watch(bus.get());
 }
 
 void connectSimpleBusMessageCallback(GstElement* pipeline)
 {
-    GRefPtr<GstBus> bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline)));
+    auto bus = adoptGRef(gst_pipeline_get_bus(GST_PIPELINE(pipeline)));
     gst_bus_add_signal_watch_full(bus.get(), RunLoopSourcePriority::RunLoopDispatcher);
     g_signal_connect(bus.get(), "message", G_CALLBACK(simpleBusMessageCallback), pipeline);
 }

Modified: trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp (271289 => 271290)


--- trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp	2021-01-08 10:28:50 UTC (rev 271289)
+++ trunk/Source/WebCore/platform/mediastream/gstreamer/GStreamerMediaStreamSource.cpp	2021-01-08 13:16:25 UTC (rev 271290)
@@ -51,6 +51,9 @@
 static GstStaticPadTemplate audioSrcTemplate = GST_STATIC_PAD_TEMPLATE("audio_src", GST_PAD_SRC, GST_PAD_SOMETIMES,
     GST_STATIC_CAPS("audio/x-raw(ANY);"));
 
+GST_DEBUG_CATEGORY_STATIC(webkitMediaStreamSrcDebug);
+#define GST_CAT_DEFAULT webkitMediaStreamSrcDebug
+
 GRefPtr<GstTagList> mediaStreamTrackPrivateGetTags(MediaStreamTrackPrivate* track)
 {
     auto tagList = adoptGRef(gst_tag_list_new_empty());
@@ -304,9 +307,6 @@
     iface->set_uri = webkitMediaStreamSrcUriSetUri;
 }
 
-GST_DEBUG_CATEGORY_STATIC(webkitMediaStreamSrcDebug);
-#define GST_CAT_DEFAULT webkitMediaStreamSrcDebug
-
 #define doInit \
     G_IMPLEMENT_INTERFACE(GST_TYPE_URI_HANDLER, webkitMediaStreamSrcUriHandlerInit); \
     GST_DEBUG_CATEGORY_INIT(webkitMediaStreamSrcDebug, "webkitmediastreamsrc", 0, "mediastreamsrc element"); \
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to