From c7e65777e104c3f8aaacee9eb46a1080f05deb83 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 26 May 2013 08:18:04 +0530 Subject: [PATCH] pulsesink: Cache the getcaps/acceptcaps probe stream getcaps is called frequently during stream setup, and creating a new stream each time is very inefficient. There's some more room for optimisation by caching the queried sink formats as well, but this needs some more changes to listen for format changes on the sink (for when supported formats change between probe stream creation and sink querying). https://bugzilla.gnome.org/show_bug.cgi?id=686459 --- ext/pulse/pulsesink.c | 88 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c index 0023d2c..cd257d6 100644 --- a/ext/pulse/pulsesink.c +++ b/ext/pulse/pulsesink.c @@ -139,6 +139,7 @@ struct _GstPulseRingBuffer pa_context *context; pa_stream *stream; + pa_stream *probe_stream; pa_format_info *format; guint channels; @@ -225,6 +226,7 @@ gst_pulseringbuffer_init (GstPulseRingBuffer * pbuf) pbuf->stream_name = NULL; pbuf->context = NULL; pbuf->stream = NULL; + pbuf->probe_stream = NULL; pbuf->format = NULL; pbuf->channels = 0; @@ -241,9 +243,32 @@ gst_pulseringbuffer_init (GstPulseRingBuffer * pbuf) pbuf->paused = FALSE; } +/* Call with mainloop lock held if wait == TRUE) */ +static void +gst_pulse_destroy_stream (pa_stream * stream, gboolean wait) +{ + /* Make sure we don't get any further callbacks */ + pa_stream_set_write_callback (stream, NULL, NULL); + pa_stream_set_underflow_callback (stream, NULL, NULL); + pa_stream_set_overflow_callback (stream, NULL, NULL); + + pa_stream_disconnect (stream); + + if (wait) + pa_threaded_mainloop_wait (mainloop); + + pa_stream_set_state_callback (stream, NULL, NULL); + pa_stream_unref (stream); +} + static void gst_pulsering_destroy_stream (GstPulseRingBuffer * pbuf) { + if (pbuf->probe_stream) { + gst_pulse_destroy_stream (pbuf->probe_stream, FALSE); + pbuf->probe_stream = NULL; + } + if (pbuf->stream) { if (pbuf->m_data) { @@ -857,6 +882,13 @@ gst_pulseringbuffer_acquire (GstAudioRingBuffer * buf, g_assert (pbuf->context); g_assert (!pbuf->stream); + /* if we have a probe, disconnect it first so that if we're creating a + * compressed stream, it doesn't get blocked by a PCM stream */ + if (pbuf->probe_stream) { + gst_pulse_destroy_stream (pbuf->probe_stream, TRUE); + pbuf->probe_stream = NULL; + } + /* enable event notifications */ GST_LOG_OBJECT (psink, "subscribing to context events"); if (!(o = pa_context_subscribe (pbuf->context, @@ -2139,7 +2171,6 @@ gst_pulsesink_query_getcaps (GstPulseSink * psink, GstCaps * filter) GList *i; pa_operation *o = NULL; pa_stream *stream; - const char *device_name; GST_OBJECT_LOCK (psink); pbuf = GST_PULSERING_BUFFER_CAST (GST_AUDIO_BASE_SINK (psink)->ringbuffer); @@ -2160,9 +2191,17 @@ gst_pulsesink_query_getcaps (GstPulseSink * psink, GstCaps * filter) goto unlock; } - if (!pbuf->stream) { - /* We're not yet in PAUSED - create a dummy stream to query the correct - * sink. + if (pbuf->stream) { + /* We're in PAUSED or higher */ + stream = pbuf->stream; + + } else if (pbuf->probe_stream) { + /* We're not paused, but have a cached probe stream */ + stream = pbuf->probe_stream; + + } else { + /* We're not yet in PAUSED and still need to create a probe stream. + * * FIXME: PA doesn't accept "any" format. We fix something reasonable since * this is merely a probe. This should eventually be fixed in PA and * hard-coding the format should be dropped. */ @@ -2172,27 +2211,23 @@ gst_pulsesink_query_getcaps (GstPulseSink * psink, GstCaps * filter) pa_format_info_set_rate (format, GST_AUDIO_DEF_RATE); pa_format_info_set_channels (format, GST_AUDIO_DEF_CHANNELS); - stream = gst_pulsesink_create_probe_stream (psink, pbuf, format); - if (!stream) { + pbuf->probe_stream = gst_pulsesink_create_probe_stream (psink, pbuf, + format); + if (!pbuf->probe_stream) { GST_WARNING_OBJECT (psink, "Could not create probe stream"); goto unlock; } - device_name = pa_stream_get_device_name (stream); - - pa_stream_set_state_callback (stream, NULL, NULL); - pa_stream_disconnect (stream); - pa_stream_unref (stream); - pa_format_info_free (format); - } else { - device_name = pa_stream_get_device_name (pbuf->stream); + + stream = pbuf->probe_stream; } ret = gst_caps_new_empty (); - if (!(o = pa_context_get_sink_info_by_name (pbuf->context, device_name, - gst_pulsesink_sink_info_cb, &device_info))) + if (!(o = pa_context_get_sink_info_by_name (pbuf->context, + pa_stream_get_device_name (stream), gst_pulsesink_sink_info_cb, + &device_info))) goto info_failed; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { @@ -2250,7 +2285,6 @@ gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps) gboolean ret = FALSE; GstAudioRingBufferSpec spec = { 0 }; - pa_stream *stream = NULL; pa_operation *o = NULL; pa_channel_map channel_map; pa_format_info *format = NULL; @@ -2312,18 +2346,20 @@ gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps) gst_pulse_gst_to_channel_map (&channel_map, &spec)) pa_format_info_set_channel_map (format, &channel_map); - if (pbuf->stream) { + if (pbuf->stream || pbuf->probe_stream) { /* We're already in PAUSED or above, so just reuse this stream to query * sink formats and use those. */ GList *i; + const char *device_name = pa_stream_get_device_name (pbuf->stream ? + pbuf->stream : pbuf->probe_stream); - if (!(o = pa_context_get_sink_info_by_name (pbuf->context, psink->device, + if (!(o = pa_context_get_sink_info_by_name (pbuf->context, device_name, gst_pulsesink_sink_info_cb, &device_info))) goto info_failed; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait (mainloop); - if (gst_pulsering_is_dead (psink, pbuf, TRUE)) + if (gst_pulsering_is_dead (psink, pbuf, FALSE)) goto out; } @@ -2336,8 +2372,9 @@ gst_pulsesink_query_acceptcaps (GstPulseSink * psink, GstCaps * caps) } else { /* We're in READY, let's connect a stream to see if the format is * accepted by whatever sink we're routed to */ - stream = gst_pulsesink_create_probe_stream (psink, pbuf, format); - if (stream) + pbuf->probe_stream = gst_pulsesink_create_probe_stream (psink, pbuf, + format); + if (pbuf->probe_stream) ret = TRUE; } @@ -2348,13 +2385,6 @@ out: if (o) pa_operation_unref (o); - if (stream) { - free_device_info (&device_info); - pa_stream_set_state_callback (stream, NULL, NULL); - pa_stream_disconnect (stream); - pa_stream_unref (stream); - } - pa_threaded_mainloop_unlock (mainloop); GST_OBJECT_UNLOCK (pbuf); -- 2.7.4