mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
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
This commit is contained in:
parent
14e784f9fc
commit
c7e65777e1
1 changed files with 59 additions and 29 deletions
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue