/* update the corked state of a stream, must be called with the mainloop * lock */ static gboolean gst_pulsesrc_set_corked (GstPulseSrc * psrc, gboolean corked, gboolean wait) { pa_operation *o = NULL; gboolean res = FALSE; GST_DEBUG_OBJECT (psrc, "setting corked state to %d", corked); if (!psrc->stream_connected) return TRUE; if (psrc->corked != corked) { if (!(o = pa_stream_cork (psrc->stream, corked, gst_pulsesrc_success_cb, psrc))) goto cork_failed; while (wait && pa_operation_get_state (o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait (psrc->mainloop); if (gst_pulsesrc_is_dead (psrc, TRUE)) goto server_dead; } psrc->corked = corked; } else { GST_DEBUG_OBJECT (psrc, "skipping, already in requested state"); } res = TRUE; cleanup: if (o) pa_operation_unref (o); return res; /* ERRORS */ server_dead: { GST_DEBUG_OBJECT (psrc, "the server is dead"); goto cleanup; } cork_failed: { GST_ELEMENT_ERROR (psrc, RESOURCE, FAILED, ("pa_stream_cork() failed: %s", pa_strerror (pa_context_errno (psrc->context))), (NULL)); goto cleanup; } }
static gchar * gst_pulsesrc_device_description (GstPulseSrc * pulsesrc) { pa_operation *o = NULL; gchar *t; if (!pulsesrc->mainloop) goto no_mainloop; pa_threaded_mainloop_lock (pulsesrc->mainloop); if (!(o = pa_context_get_source_info_by_name (pulsesrc->context, pulsesrc->device, 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, FALSE)) 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; no_mainloop: { GST_DEBUG_OBJECT (pulsesrc, "have no mainloop"); return NULL; } }
/* return the delay in samples */ static guint gst_pulsesrc_delay (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_usec_t t; int negative, res; guint result; pa_threaded_mainloop_lock (pulsesrc->mainloop); if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto server_dead; /* get the latency, this can fail when we don't have a latency update yet. * We don't want to wait for latency updates here but we just return 0. */ res = pa_stream_get_latency (pulsesrc->stream, &t, &negative); pa_threaded_mainloop_unlock (pulsesrc->mainloop); if (res > 0) { GST_DEBUG_OBJECT (pulsesrc, "could not get latency"); result = 0; } else { if (negative) result = 0; else result = (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL); } return result; /* ERRORS */ server_dead: { GST_DEBUG_OBJECT (pulsesrc, "the server is dead"); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return 0; } }
static GstClockTime gst_pulsesrc_get_time (GstClock * clock, GstPulseSrc * src) { pa_usec_t time = 0; pa_threaded_mainloop_lock (src->mainloop); if (gst_pulsesrc_is_dead (src, TRUE)) { goto unlock_and_out; } if (pa_stream_get_time (src->stream, &time) < 0) { GST_DEBUG_OBJECT (src, "could not get time"); time = GST_CLOCK_TIME_NONE; } else { time *= 1000; } unlock_and_out: pa_threaded_mainloop_unlock (src->mainloop); return time; }
static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); size_t sum = 0; pa_threaded_mainloop_lock (pulsesrc->mainloop); pulsesrc->in_read = TRUE; if (pulsesrc->paused) goto was_paused; while (length > 0) { size_t l; GST_LOG_OBJECT (pulsesrc, "reading %u bytes", length); /*check if we have a leftover buffer */ if (!pulsesrc->read_buffer) { for (;;) { if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock_and_fail; /* read all available data, we keep a pointer to the data and the length * and take from it what we need. */ if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer, &pulsesrc->read_buffer_length) < 0) goto peek_failed; GST_LOG_OBJECT (pulsesrc, "have data of %" G_GSIZE_FORMAT " bytes", pulsesrc->read_buffer_length); /* if we have data, process if */ if (pulsesrc->read_buffer && pulsesrc->read_buffer_length) break; /* now wait for more data to become available */ GST_LOG_OBJECT (pulsesrc, "waiting for data"); pa_threaded_mainloop_wait (pulsesrc->mainloop); if (pulsesrc->paused) goto was_paused; } } l = pulsesrc->read_buffer_length > length ? length : pulsesrc->read_buffer_length; memcpy (data, pulsesrc->read_buffer, l); pulsesrc->read_buffer = (const guint8 *) pulsesrc->read_buffer + l; pulsesrc->read_buffer_length -= l; data = (guint8 *) data + l; length -= l; sum += l; if (pulsesrc->read_buffer_length <= 0) { /* we copied all of the data, drop it now */ if (pa_stream_drop (pulsesrc->stream) < 0) goto drop_failed; /* reset pointer to data */ pulsesrc->read_buffer = NULL; pulsesrc->read_buffer_length = 0; } } pulsesrc->in_read = FALSE; pa_threaded_mainloop_unlock (pulsesrc->mainloop); return sum; /* ERRORS */ was_paused: { GST_LOG_OBJECT (pulsesrc, "we are paused"); goto unlock_and_fail; } peek_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_stream_peek() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } drop_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_stream_drop() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { pulsesrc->in_read = FALSE; pa_threaded_mainloop_unlock (pulsesrc->mainloop); return (guint) - 1; } }
static gdouble gst_pulsesrc_get_stream_volume (GstPulseSrc * pulsesrc) { pa_operation *o = NULL; gdouble v; if (!pulsesrc->mainloop) goto no_mainloop; if (pulsesrc->source_output_idx == PA_INVALID_INDEX) goto no_index; pa_threaded_mainloop_lock (pulsesrc->mainloop); if (!(o = pa_context_get_source_output_info (pulsesrc->context, pulsesrc->source_output_idx, gst_pulsesrc_source_output_info_cb, pulsesrc))) goto info_failed; while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait (pulsesrc->mainloop); if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) goto unlock; } unlock: v = pulsesrc->volume; if (o) pa_operation_unref (o); pa_threaded_mainloop_unlock (pulsesrc->mainloop); if (v > MAX_VOLUME) { GST_WARNING_OBJECT (pulsesrc, "Clipped volume from %f to %f", v, MAX_VOLUME); v = MAX_VOLUME; } return v; /* ERRORS */ no_mainloop: { v = pulsesrc->volume; GST_DEBUG_OBJECT (pulsesrc, "we have no mainloop"); return v; } no_index: { v = pulsesrc->volume; GST_DEBUG_OBJECT (pulsesrc, "we don't have a stream index"); return v; } info_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_context_get_source_output_info() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock; } }