pulsesink: Re-enable emission of stream status messages

This was disabled almost 10 years ago because we were missing libpulse API to
avoid a deadlock. That was fixed quite a long time ago, so let's enable this
again. The defer counter becomes an atomic, as we no longer have a threaded
mainloop lock protecting it.

Fixes: https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/3444
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/6500>
This commit is contained in:
Arun Raghavan 2024-04-01 12:01:58 -04:00 committed by GStreamer Marge Bot
parent 8d3e7689e1
commit 82b10e57b0
2 changed files with 24 additions and 38 deletions

View file

@ -1187,10 +1187,9 @@ gst_pulseringbuffer_clear (GstAudioRingBuffer * buf)
pa_threaded_mainloop_unlock (mainloop); pa_threaded_mainloop_unlock (mainloop);
} }
#if 0 /* called from pulse thread WITHOUT the mainloop lock */
/* called from pulse thread with the mainloop lock */
static void static void
mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata) mainloop_enter_defer_cb (pa_threaded_mainloop * loop, void *userdata)
{ {
GstPulseSink *pulsesink = GST_PULSESINK (userdata); GstPulseSink *pulsesink = GST_PULSESINK (userdata);
GstMessage *message; GstMessage *message;
@ -1206,11 +1205,10 @@ mainloop_enter_defer_cb (pa_mainloop_api * api, void *userdata)
gst_element_post_message (GST_ELEMENT (pulsesink), message); gst_element_post_message (GST_ELEMENT (pulsesink), message);
g_return_if_fail (pulsesink->defer_pending); g_return_if_fail (g_atomic_int_get (&pulsesink->defer_pending));
pulsesink->defer_pending--; g_atomic_int_dec_and_test (&pulsesink->defer_pending);
pa_threaded_mainloop_signal (mainloop, 0); pa_threaded_mainloop_signal (mainloop, 0);
} }
#endif
/* start/resume playback ASAP, we don't uncork here but in the commit method */ /* start/resume playback ASAP, we don't uncork here but in the commit method */
static gboolean static gboolean
@ -1232,19 +1230,14 @@ gst_pulseringbuffer_start (GstAudioRingBuffer * buf)
g_atomic_int_get (&GST_AUDIO_BASE_SINK (psink)->eos_rendering)) g_atomic_int_get (&GST_AUDIO_BASE_SINK (psink)->eos_rendering))
gst_pulsering_set_corked (pbuf, FALSE, FALSE); gst_pulsering_set_corked (pbuf, FALSE, FALSE);
#if 0 #if PA_CHECK_VERSION(13, 0, 0)
GST_DEBUG_OBJECT (psink, "scheduling stream status"); GST_DEBUG_OBJECT (psink, "scheduling stream status");
psink->defer_pending++; g_atomic_int_inc (&psink->defer_pending);
pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop), /* We'll emit this in the mainloop thread so applications have a callback in
mainloop_enter_defer_cb, psink); * that context. We emit this without the mainloop locked -- if we did not,
* then the mainloop lock would be implicitly taken before the object lock
/* Wait for the stream status message to be posted. This needs to be done * (during message emission), causing a deadlock */
* synchronously because the callback will take the mainloop lock pa_threaded_mainloop_once_unlocked (mainloop, mainloop_enter_defer_cb, psink);
* (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
* the locks in the reverse order, so not doing this synchronously could
* cause a deadlock. */
GST_DEBUG_OBJECT (psink, "waiting for stream status (ENTER) to be posted");
pa_threaded_mainloop_wait (mainloop);
#endif #endif
pa_threaded_mainloop_unlock (mainloop); pa_threaded_mainloop_unlock (mainloop);
@ -1278,10 +1271,9 @@ gst_pulseringbuffer_pause (GstAudioRingBuffer * buf)
return res; return res;
} }
#if 0 /* called from pulse thread WITHOUT the mainloop lock */
/* called from pulse thread with the mainloop lock */
static void static void
mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata) mainloop_leave_defer_cb (pa_threaded_mainloop * loop, void *userdata)
{ {
GstPulseSink *pulsesink = GST_PULSESINK (userdata); GstPulseSink *pulsesink = GST_PULSESINK (userdata);
GstMessage *message; GstMessage *message;
@ -1297,11 +1289,10 @@ mainloop_leave_defer_cb (pa_mainloop_api * api, void *userdata)
gst_element_post_message (GST_ELEMENT (pulsesink), message); gst_element_post_message (GST_ELEMENT (pulsesink), message);
g_return_if_fail (pulsesink->defer_pending); g_return_if_fail (g_atomic_int_get (&pulsesink->defer_pending));
pulsesink->defer_pending--; g_atomic_int_dec_and_test (&pulsesink->defer_pending);
pa_threaded_mainloop_signal (mainloop, 0); pa_threaded_mainloop_signal (mainloop, 0);
} }
#endif
/* stop playback, we flush everything. */ /* stop playback, we flush everything. */
static gboolean static gboolean
@ -1349,19 +1340,14 @@ cleanup:
pa_operation_cancel (o); pa_operation_cancel (o);
pa_operation_unref (o); pa_operation_unref (o);
} }
#if 0 #if PA_CHECK_VERSION(13, 0, 0)
GST_DEBUG_OBJECT (psink, "scheduling stream status"); GST_DEBUG_OBJECT (psink, "scheduling stream status");
psink->defer_pending++; g_atomic_int_inc (&psink->defer_pending);
pa_mainloop_api_once (pa_threaded_mainloop_get_api (mainloop), /* We'll emit this in the mainloop thread so applications have a callback in
mainloop_leave_defer_cb, psink); * that context. We emit this without the mainloop locked -- if we did not,
* then the mainloop lock would be implicitly taken before the object lock
/* Wait for the stream status message to be posted. This needs to be done * (during message emission), causing a deadlock */
* synchronously because the callback will take the mainloop lock pa_threaded_mainloop_once_unlocked (mainloop, mainloop_leave_defer_cb, psink);
* (implicitly) and then take the GST_OBJECT_LOCK. Everywhere else, we take
* the locks in the reverse order, so not doing this synchronously could
* cause a deadlock. */
GST_DEBUG_OBJECT (psink, "waiting for stream status (LEAVE) to be posted");
pa_threaded_mainloop_wait (mainloop);
#endif #endif
pa_threaded_mainloop_unlock (mainloop); pa_threaded_mainloop_unlock (mainloop);
@ -3214,7 +3200,7 @@ gst_pulsesink_release_mainloop (GstPulseSink * psink)
return; return;
pa_threaded_mainloop_lock (mainloop); pa_threaded_mainloop_lock (mainloop);
while (psink->defer_pending) { while (g_atomic_int_get (&psink->defer_pending)) {
GST_DEBUG_OBJECT (psink, "waiting for stream status message emission"); GST_DEBUG_OBJECT (psink, "waiting for stream status message emission");
pa_threaded_mainloop_wait (mainloop); pa_threaded_mainloop_wait (mainloop);
} }

View file

@ -63,7 +63,7 @@ struct _GstPulseSink
guint32 current_sink_idx; guint32 current_sink_idx;
gchar *current_sink_name; gchar *current_sink_name;
guint defer_pending; volatile guint defer_pending;
gint notify; /* atomic */ gint notify; /* atomic */