summaryrefslogtreecommitdiffstats
path: root/ext/pulse/pulsesrc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pulse/pulsesrc.c')
-rw-r--r--ext/pulse/pulsesrc.c377
1 files changed, 305 insertions, 72 deletions
diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
index 08fec595..bd05ffa1 100644
--- a/ext/pulse/pulsesrc.c
+++ b/ext/pulse/pulsesrc.c
@@ -68,8 +68,6 @@ static void gst_pulsesrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_pulsesrc_finalize (GObject * object);
-static void gst_pulsesrc_dispose (GObject * object);
-
static gboolean gst_pulsesrc_open (GstAudioSrc * asrc);
static gboolean gst_pulsesrc_close (GstAudioSrc * asrc);
@@ -83,6 +81,8 @@ static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data,
guint length);
static guint gst_pulsesrc_delay (GstAudioSrc * asrc);
+static void gst_pulsesrc_reset (GstAudioSrc * src);
+
static gboolean gst_pulsesrc_negotiate (GstBaseSrc * basesrc);
static GstStateChangeReturn gst_pulsesrc_change_state (GstElement *
@@ -161,30 +161,30 @@ gst_pulsesrc_base_init (gpointer g_class)
"width = (int) 16, "
"depth = (int) 16, "
"rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
- "audio/x-raw-int, "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-raw-float, "
"endianness = (int) { " ENDIANNESS " }, "
- "signed = (boolean) TRUE, "
"width = (int) 32, "
- "depth = (int) 32, "
"rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
- "audio/x-raw-float, "
+ "channels = (int) [ 1, 32 ];"
+ "audio/x-raw-int, "
"endianness = (int) { " ENDIANNESS " }, "
+ "signed = (boolean) TRUE, "
"width = (int) 32, "
+ "depth = (int) 32, "
"rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
+ "channels = (int) [ 1, 32 ];"
"audio/x-raw-int, "
"signed = (boolean) FALSE, "
"width = (int) 8, "
"depth = (int) 8, "
"rate = (int) [ 1, MAX ], "
- "channels = (int) [ 1, 16 ];"
+ "channels = (int) [ 1, 32 ];"
"audio/x-alaw, "
"rate = (int) [ 1, MAX], "
- "channels = (int) [ 1, 16 ];"
+ "channels = (int) [ 1, 32 ];"
"audio/x-mulaw, "
- "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 16 ]")
+ "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 32 ]")
);
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
@@ -205,14 +205,13 @@ gst_pulsesrc_class_init (GstPulseSrcClass * klass)
GstBaseSrcClass *gstbasesrc_class = GST_BASE_SRC_CLASS (klass);
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
-
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pulsesrc_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pulsesrc_finalize);
gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pulsesrc_set_property);
gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_pulsesrc_get_property);
+ gstelement_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
+
gstbasesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_pulsesrc_negotiate);
gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_pulsesrc_open);
@@ -221,6 +220,7 @@ gst_pulsesrc_class_init (GstPulseSrcClass * klass)
gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_unprepare);
gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_pulsesrc_read);
gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesrc_delay);
+ gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesrc_reset);
/* Overwrite GObject fields */
g_object_class_install_property (gobject_class,
@@ -245,7 +245,7 @@ gst_pulsesrc_init (GstPulseSrc * pulsesrc, GstPulseSrcClass * klass)
{
int e;
- pulsesrc->server = pulsesrc->device = NULL;
+ pulsesrc->server = pulsesrc->device = pulsesrc->device_description = NULL;
pulsesrc->context = NULL;
pulsesrc->stream = NULL;
@@ -253,6 +253,18 @@ gst_pulsesrc_init (GstPulseSrc * pulsesrc, GstPulseSrcClass * klass)
pulsesrc->read_buffer = NULL;
pulsesrc->read_buffer_length = 0;
+#if HAVE_PULSE_0_9_13
+ pa_sample_spec_init (&pulsesrc->sample_spec);
+#else
+ pulsesrc->sample_spec.format = PA_SAMPLE_INVALID;
+ pulsesrc->sample_spec.rate = 0;
+ pulsesrc->sample_spec.channels = 0;
+#endif
+
+ pulsesrc->operation_success = FALSE;
+ pulsesrc->did_reset = FALSE;
+ pulsesrc->in_read = FALSE;
+
pulsesrc->mainloop = pa_threaded_mainloop_new ();
g_assert (pulsesrc->mainloop);
@@ -272,6 +284,9 @@ gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc)
pa_stream_unref (pulsesrc->stream);
pulsesrc->stream = NULL;
}
+
+ g_free (pulsesrc->device_description);
+ pulsesrc->device_description = NULL;
}
static void
@@ -301,8 +316,10 @@ gst_pulsesrc_finalize (GObject * object)
pa_threaded_mainloop_free (pulsesrc->mainloop);
- if (pulsesrc->mixer)
+ if (pulsesrc->mixer) {
gst_pulsemixer_ctrl_free (pulsesrc->mixer);
+ pulsesrc->mixer = NULL;
+ }
if (pulsesrc->probe) {
gst_pulseprobe_free (pulsesrc->probe);
@@ -312,12 +329,26 @@ gst_pulsesrc_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object);
}
-static void
-gst_pulsesrc_dispose (GObject * object)
+static gboolean
+gst_pulsesrc_is_dead (GstPulseSrc * pulsesrc)
{
- G_OBJECT_CLASS (parent_class)->dispose (object);
+
+ if (!pulsesrc->context
+ || !PA_CONTEXT_IS_GOOD (pa_context_get_state (pulsesrc->context))
+ || !pulsesrc->stream
+ || !PA_STREAM_IS_GOOD (pa_stream_get_state (pulsesrc->stream))) {
+ const gchar *err_str = pulsesrc->context ?
+ pa_strerror (pa_context_errno (pulsesrc->context)) : NULL;
+
+ GST_ELEMENT_ERROR ((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s",
+ err_str), (NULL));
+ return TRUE;
+ }
+
+ return FALSE;
}
+
static void
gst_pulsesrc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
@@ -347,6 +378,65 @@ gst_pulsesrc_set_property (GObject * object,
}
static void
+gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol,
+ void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
+
+ if (!i)
+ return;
+
+ if (!pulsesrc->stream)
+ return;
+
+ g_assert (i->index == pa_stream_get_device_index (pulsesrc->stream));
+
+ g_free (pulsesrc->device_description);
+ pulsesrc->device_description = g_strdup (i->description);
+}
+
+static gchar *
+gst_pulsesrc_device_description (GstPulseSrc * pulsesrc)
+{
+ pa_operation *o = NULL;
+ gchar *t;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (!pulsesrc->stream)
+ goto unlock;
+
+ if (!(o = pa_context_get_source_info_by_index (pulsesrc->context,
+ pa_stream_get_device_index (pulsesrc->stream),
+ gst_pulsesrc_source_info_cb, pulsesrc))) {
+
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_get_source_info() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock;
+
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ t = g_strdup (pulsesrc->device_description);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+
+ return t;
+}
+
+static void
gst_pulsesrc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
@@ -362,14 +452,12 @@ gst_pulsesrc_get_property (GObject * object,
g_value_set_string (value, pulsesrc->device);
break;
- case PROP_DEVICE_NAME:
-
- if (pulsesrc->mixer)
- g_value_set_string (value, pulsesrc->mixer->description);
- else
- g_value_set_string (value, NULL);
-
+ case PROP_DEVICE_NAME:{
+ char *t = gst_pulsesrc_device_description (pulsesrc);
+ g_value_set_string (value, t);
+ g_free (t);
break;
+ }
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -424,15 +512,25 @@ gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata)
pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
}
+static void
+gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
+
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
static gboolean
gst_pulsesrc_open (GstAudioSrc * asrc)
{
GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
-
gchar *name = gst_pulse_client_name ();
pa_threaded_mainloop_lock (pulsesrc->mainloop);
+ g_assert (!pulsesrc->context);
+ g_assert (!pulsesrc->stream);
+
if (!(pulsesrc->context =
pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop),
name))) {
@@ -450,13 +548,22 @@ gst_pulsesrc_open (GstAudioSrc * asrc)
goto unlock_and_fail;
}
- /* Wait until the context is ready */
- pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ for (;;) {
+ pa_context_state_t state;
- if (pa_context_get_state (pulsesrc->context) != PA_CONTEXT_READY) {
- GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
- pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
- goto unlock_and_fail;
+ state = pa_context_get_state (pulsesrc->context);
+
+ if (!PA_CONTEXT_IS_GOOD (state)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (state == PA_CONTEXT_READY)
+ break;
+
+ /* Wait until the context is ready */
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
}
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
@@ -466,6 +573,8 @@ gst_pulsesrc_open (GstAudioSrc * asrc)
unlock_and_fail:
+ gst_pulsesrc_destroy_context (pulsesrc);
+
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
g_free (name);
@@ -500,23 +609,15 @@ gst_pulsesrc_unprepare (GstAudioSrc * asrc)
return TRUE;
}
-#define CHECK_DEAD_GOTO(pulsesrc, label) \
-if (!(pulsesrc)->context || pa_context_get_state((pulsesrc)->context) != PA_CONTEXT_READY || \
- !(pulsesrc)->stream || pa_stream_get_state((pulsesrc)->stream) != PA_STREAM_READY) { \
- GST_ELEMENT_ERROR((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s", (pulsesrc)->context ? pa_strerror(pa_context_errno((pulsesrc)->context)) : NULL), (NULL)); \
- goto label; \
-}
-
static guint
gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
{
GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
-
size_t sum = 0;
pa_threaded_mainloop_lock (pulsesrc->mainloop);
- CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
+ pulsesrc->in_read = TRUE;
while (length > 0) {
size_t l;
@@ -524,6 +625,9 @@ gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
if (!pulsesrc->read_buffer) {
for (;;) {
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock_and_fail;
+
if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer,
&pulsesrc->read_buffer_length) < 0) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
@@ -535,9 +639,10 @@ gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
if (pulsesrc->read_buffer)
break;
- pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ if (pulsesrc->did_reset)
+ goto unlock_and_fail;
- CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
}
}
@@ -570,16 +675,19 @@ gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
}
}
- pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+ pulsesrc->did_reset = FALSE;
+ pulsesrc->in_read = FALSE;
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
return sum;
- /* ERRORS */
unlock_and_fail:
- {
- pa_threaded_mainloop_unlock (pulsesrc->mainloop);
- return -1;
- }
+
+ pulsesrc->did_reset = FALSE;
+ pulsesrc->in_read = FALSE;
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+ return (guint) - 1;
}
static guint
@@ -593,9 +701,12 @@ gst_pulsesrc_delay (GstAudioSrc * asrc)
pa_threaded_mainloop_lock (pulsesrc->mainloop);
- CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
+ for (;;) {
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock_and_fail;
- if (pa_stream_get_latency (pulsesrc->stream, &t, &negative) < 0) {
+ if (pa_stream_get_latency (pulsesrc->stream, &t, &negative) >= 0)
+ break;
if (pa_context_errno (pulsesrc->context) != PA_ERR_NODATA) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
@@ -604,9 +715,10 @@ gst_pulsesrc_delay (GstAudioSrc * asrc)
goto unlock_and_fail;
}
- GST_WARNING_OBJECT (pulsesrc, "Not data while querying latency");
- t = 0;
- } else if (negative)
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+ if (negative)
t = 0;
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
@@ -645,12 +757,8 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
pa_threaded_mainloop_lock (pulsesrc->mainloop);
- if (!pulsesrc->context
- || pa_context_get_state (pulsesrc->context) != PA_CONTEXT_READY) {
- GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context state: %s",
- pulsesrc->
- context ? pa_strerror (pa_context_errno (pulsesrc->context)) :
- NULL), (NULL));
+ if (!pulsesrc->context) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context"), (NULL));
goto unlock_and_fail;
}
@@ -688,10 +796,16 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
pulsesrc);
pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
pulsesrc);
+ pa_stream_set_latency_update_callback (pulsesrc->stream,
+ gst_pulsesrc_stream_latency_update_cb, pulsesrc);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
return TRUE;
unlock_and_fail:
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
fail:
@@ -776,27 +890,42 @@ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
pa_buffer_attr buf_attr;
GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
memset (&buf_attr, 0, sizeof (buf_attr));
buf_attr.maxlength = spec->segtotal * spec->segsize * 2;
buf_attr.fragsize = spec->segsize;
if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &buf_attr,
- PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
- PA_STREAM_NOT_MONOTONOUS) < 0) {
+ PA_STREAM_INTERPOLATE_TIMING |
+ PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONOUS |
+#if HAVE_PULSE_0_9_11
+ PA_STREAM_ADJUST_LATENCY |
+#endif
+ PA_STREAM_START_CORKED) < 0) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
("Failed to connect stream: %s",
pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
goto unlock_and_fail;
}
- /* Wait until the stream is ready */
- pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ for (;;) {
+ pa_stream_state_t state;
- if (pa_stream_get_state (pulsesrc->stream) != PA_STREAM_READY) {
- GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
- ("Failed to connect stream: %s",
- pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
- goto unlock_and_fail;
+ state = pa_stream_get_state (pulsesrc->stream);
+
+ if (!PA_STREAM_IS_GOOD (state)) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("Failed to connect stream: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ if (state == PA_STREAM_READY)
+ break;
+
+ /* Wait until the stream is ready */
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
}
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
@@ -804,16 +933,120 @@ gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
return TRUE;
unlock_and_fail:
+
+ gst_pulsesrc_destroy_stream (pulsesrc);
+
pa_threaded_mainloop_unlock (pulsesrc->mainloop);
return FALSE;
}
+static void
+gst_pulsesrc_success_cb (pa_stream * s, int success, void *userdata)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
+
+ pulsesrc->operation_success = !!success;
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+}
+
+static void
+gst_pulsesrc_reset (GstAudioSrc * asrc)
+{
+ GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
+ pa_operation *o = NULL;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock_and_fail;
+
+ if (!(o =
+ pa_stream_flush (pulsesrc->stream, gst_pulsesrc_success_cb,
+ pulsesrc))) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_flush() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+ /* Inform anyone waiting in _write() call that it shall wakeup */
+ if (pulsesrc->in_read) {
+ pulsesrc->did_reset = TRUE;
+ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
+ }
+
+ pulsesrc->operation_success = FALSE;
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock_and_fail;
+
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+ if (!pulsesrc->operation_success) {
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Flush failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock_and_fail;
+ }
+
+unlock_and_fail:
+
+ if (o) {
+ pa_operation_cancel (o);
+ pa_operation_unref (o);
+ }
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+}
+
+static void
+gst_pulsesrc_pause (GstPulseSrc * pulsesrc, gboolean b)
+{
+ pa_operation *o = NULL;
+
+ pa_threaded_mainloop_lock (pulsesrc->mainloop);
+
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock;
+
+ if (!(o = pa_stream_cork (pulsesrc->stream, b, NULL, NULL))) {
+
+ GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
+ ("pa_stream_cork() failed: %s",
+ pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
+ goto unlock;
+ }
+
+ while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) {
+
+ if (gst_pulsesrc_is_dead (pulsesrc))
+ goto unlock;
+
+ pa_threaded_mainloop_wait (pulsesrc->mainloop);
+ }
+
+unlock:
+
+ if (o)
+ pa_operation_unref (o);
+
+ pa_threaded_mainloop_unlock (pulsesrc->mainloop);
+}
+
static GstStateChangeReturn
gst_pulsesrc_change_state (GstElement * element, GstStateChange transition)
{
GstPulseSrc *this = GST_PULSESRC (element);
switch (transition) {
+
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ gst_pulsesrc_pause (this,
+ GST_STATE_TRANSITION_NEXT (transition) == GST_STATE_PAUSED);
+ break;
+
case GST_STATE_CHANGE_NULL_TO_READY:
if (!this->mixer)