From 5332287e2d8f9dc7b32da0f6618a0730bd98513a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 6 May 2010 13:51:59 +0200 Subject: [PATCH] pulsesink: Create and free the PA mainloop in NULL->READY/READY->NULL This fixes a race condition, when stopping the mainloop during finalization is done from a mainloop callback. Fixes bugs #614765 and #590662. --- ext/pulse/pulsesink.c | 54 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 11 deletions(-) diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 0460748..4b45a2f 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -1405,6 +1405,9 @@ static void gst_pulsesink_finalize (GObject * object); static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event); +static GstStateChangeReturn gst_pulsesink_change_state (GstElement * element, + GstStateChange transition); + static void gst_pulsesink_init_interfaces (GType type); #if (G_BYTE_ORDER == G_LITTLE_ENDIAN) @@ -1544,6 +1547,7 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass) GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass); GstBaseSinkClass *bc; GstBaseAudioSinkClass *gstaudiosink_class = GST_BASE_AUDIO_SINK_CLASS (klass); + GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pulsesink_finalize); gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pulsesink_set_property); @@ -1555,6 +1559,9 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass) bc = g_type_class_peek (GST_TYPE_BASE_SINK); gstbasesink_class->activate_pull = GST_DEBUG_FUNCPTR (bc->activate_pull); + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_pulsesink_change_state); + gstaudiosink_class->create_ringbuffer = GST_DEBUG_FUNCPTR (gst_pulsesink_create_ringbuffer); @@ -1635,8 +1642,6 @@ server_dead: static void gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass) { - guint res; - pulsesink->server = NULL; pulsesink->device = NULL; pulsesink->device_description = NULL; @@ -1655,11 +1660,6 @@ gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass) GST_DEBUG_OBJECT (pulsesink, "using pulseaudio version %s", pulsesink->pa_version); - pulsesink->mainloop = pa_threaded_mainloop_new (); - g_assert (pulsesink->mainloop != NULL); - res = pa_threaded_mainloop_start (pulsesink->mainloop); - g_assert (res == 0); - /* TRUE for sinks, FALSE for sources */ pulsesink->probe = gst_pulseprobe_new (G_OBJECT (pulsesink), G_OBJECT_GET_CLASS (pulsesink), PROP_DEVICE, pulsesink->device, @@ -1678,14 +1678,10 @@ gst_pulsesink_finalize (GObject * object) { GstPulseSink *pulsesink = GST_PULSESINK_CAST (object); - pa_threaded_mainloop_stop (pulsesink->mainloop); - g_free (pulsesink->server); g_free (pulsesink->device); g_free (pulsesink->device_description); - pa_threaded_mainloop_free (pulsesink->mainloop); - if (pulsesink->probe) { gst_pulseprobe_free (pulsesink->probe); pulsesink->probe = NULL; @@ -2264,3 +2260,39 @@ gst_pulsesink_event (GstBaseSink * sink, GstEvent * event) return GST_BASE_SINK_CLASS (parent_class)->event (sink, event); } + +static GstStateChangeReturn +gst_pulsesink_change_state (GstElement * element, GstStateChange transition) +{ + GstPulseSink *pulsesink = GST_PULSESINK (element); + GstStateChangeReturn ret; + guint res; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + g_assert (pulsesink->mainloop == NULL); + pulsesink->mainloop = pa_threaded_mainloop_new (); + g_assert (pulsesink->mainloop != NULL); + res = pa_threaded_mainloop_start (pulsesink->mainloop); + g_assert (res == 0); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + + switch (transition) { + case GST_STATE_CHANGE_READY_TO_NULL: + if (pulsesink->mainloop) { + pa_threaded_mainloop_stop (pulsesink->mainloop); + pa_threaded_mainloop_free (pulsesink->mainloop); + pulsesink->mainloop = NULL; + } + break; + default: + break; + } + + return ret; +} -- 2.7.4