static void gst_pulsesrc_stream_latency_update_cb (pa_stream * s, void *userdata) { const pa_timing_info *info; pa_usec_t source_usec; info = pa_stream_get_timing_info (s); if (!info) { GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata), "latency update (information unknown)"); return; } #ifdef HAVE_PULSE_0_9_11 source_usec = info->configured_source_usec; #else source_usec = 0; #endif GST_LOG_OBJECT (GST_PULSESRC_CAST (userdata), "latency_update, %" G_GUINT64_FORMAT ", %d:%" G_GINT64_FORMAT ", %d:%" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT ", %" G_GUINT64_FORMAT, GST_TIMEVAL_TO_TIME (info->timestamp), info->write_index_corrupt, info->write_index, info->read_index_corrupt, info->read_index, info->source_usec, source_usec); }
static void gst_pulsesrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object); switch (prop_id) { case PROP_SERVER: g_free (pulsesrc->server); pulsesrc->server = g_value_dup_string (value); if (pulsesrc->probe) gst_pulseprobe_set_server (pulsesrc->probe, pulsesrc->server); break; case PROP_DEVICE: g_free (pulsesrc->device); pulsesrc->device = g_value_dup_string (value); break; case PROP_STREAM_PROPERTIES: if (pulsesrc->properties) gst_structure_free (pulsesrc->properties); pulsesrc->properties = gst_structure_copy (gst_value_get_structure (value)); if (pulsesrc->proplist) pa_proplist_free (pulsesrc->proplist); pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_pulsesrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object); switch (prop_id) { case PROP_SERVER: g_value_set_string (value, pulsesrc->server); break; case PROP_DEVICE: g_value_set_string (value, pulsesrc->device); break; case PROP_DEVICE_NAME: g_value_take_string (value, gst_pulsesrc_device_description (pulsesrc)); break; case PROP_STREAM_PROPERTIES: gst_value_set_structure (value, pulsesrc->properties); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_pulsesrc_finalize (GObject * object) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object); g_free (pulsesrc->server); g_free (pulsesrc->device); if (pulsesrc->properties) gst_structure_free (pulsesrc->properties); if (pulsesrc->proplist) pa_proplist_free (pulsesrc->proplist); if (pulsesrc->mixer) { gst_pulsemixer_ctrl_free (pulsesrc->mixer); pulsesrc->mixer = NULL; } if (pulsesrc->probe) { gst_pulseprobe_free (pulsesrc->probe); pulsesrc->probe = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); }
static void gst_pulsesrc_success_cb (pa_stream * s, int success, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata); pulsesrc->operation_success = !!success; pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); }
static gboolean gst_pulsesrc_close (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_threaded_mainloop_lock (pulsesrc->mainloop); gst_pulsesrc_destroy_context (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; }
static void gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata); GST_LOG_OBJECT (pulsesrc, "got request for length %" G_GSIZE_FORMAT, length); if (pulsesrc->in_read) { /* only signal when reading */ pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); } }
static void gst_pulsesrc_reset (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_operation *o = NULL; pa_threaded_mainloop_lock (pulsesrc->mainloop); GST_DEBUG_OBJECT (pulsesrc, "reset"); if (gst_pulsesrc_is_dead (pulsesrc, TRUE)) 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; } pulsesrc->paused = TRUE; /* Inform anyone waiting in _write() call that it shall wakeup */ if (pulsesrc->in_read) { 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, TRUE)) 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 gboolean gst_pulsesrc_interface_supported (GstImplementsInterface * iface, GType interface_type) { GstPulseSrc *this = GST_PULSESRC_CAST (iface); if (interface_type == GST_TYPE_MIXER && this->mixer) return TRUE; if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe) return TRUE; return FALSE; }
static void gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata); if (!i) goto done; g_free (pulsesrc->device_description); pulsesrc->device_description = g_strdup (i->description); done: pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); }
static gboolean gst_pulsesrc_unprepare (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_threaded_mainloop_lock (pulsesrc->mainloop); gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); pulsesrc->read_buffer = NULL; pulsesrc->read_buffer_length = 0; return TRUE; }
static void gst_pulsesrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object); switch (prop_id) { case PROP_SERVER: g_free (pulsesrc->server); pulsesrc->server = g_value_dup_string (value); if (pulsesrc->probe) gst_pulseprobe_set_server (pulsesrc->probe, pulsesrc->server); break; case PROP_DEVICE: g_free (pulsesrc->device); pulsesrc->device = g_value_dup_string (value); break; case PROP_CLIENT_NAME: g_free (pulsesrc->client_name); if (!g_value_get_string (value)) { GST_WARNING_OBJECT (pulsesrc, "Empty PulseAudio client name not allowed. Resetting to default value"); pulsesrc->client_name = gst_pulse_client_name (); } else pulsesrc->client_name = g_value_dup_string (value); break; case PROP_STREAM_PROPERTIES: if (pulsesrc->properties) gst_structure_free (pulsesrc->properties); pulsesrc->properties = gst_structure_copy (gst_value_get_structure (value)); if (pulsesrc->proplist) pa_proplist_free (pulsesrc->proplist); pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties); break; case PROP_VOLUME: gst_pulsesrc_set_stream_volume (pulsesrc, g_value_get_double (value)); break; case PROP_MUTE: gst_pulsesrc_set_stream_mute (pulsesrc, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_pulsesrc_source_info_cb (pa_context * c, const pa_source_info * i, int eol, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (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 void gst_pulsesrc_stream_state_cb (pa_stream * s, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata); switch (pa_stream_get_state (s)) { case PA_STREAM_READY: case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); break; case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: break; } }
static void gst_pulsesrc_context_state_cb (pa_context * c, void *userdata) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (userdata); switch (pa_context_get_state (c)) { case PA_CONTEXT_READY: case PA_CONTEXT_TERMINATED: case PA_CONTEXT_FAILED: pa_threaded_mainloop_signal (pulsesrc->mainloop, 0); break; case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; } }
static void gst_pulsesrc_source_output_info_cb (pa_context * c, const pa_source_output_info * i, int eol, void *userdata) { GstPulseSrc *psrc; psrc = GST_PULSESRC_CAST (userdata); if (!i) goto done; /* If the index doesn't match our current stream, * it implies we just recreated the stream (caps change) */ if (i->index == psrc->source_output_idx) { psrc->volume = pa_sw_volume_to_linear (pa_cvolume_max (&i->volume)); psrc->mute = i->mute; } done: pa_threaded_mainloop_signal (psrc->mainloop, 0); }
static void gst_pulsesrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (object); switch (prop_id) { case PROP_SERVER: g_value_set_string (value, pulsesrc->server); break; case PROP_DEVICE: g_value_set_string (value, pulsesrc->device); break; case PROP_DEVICE_NAME: g_value_take_string (value, gst_pulsesrc_device_description (pulsesrc)); break; case PROP_CLIENT_NAME: g_value_set_string (value, pulsesrc->client_name); break; case PROP_STREAM_PROPERTIES: gst_value_set_structure (value, pulsesrc->properties); break; case PROP_SOURCE_OUTPUT_INDEX: g_value_set_uint (value, pulsesrc->source_output_idx); break; case PROP_VOLUME: g_value_set_double (value, gst_pulsesrc_get_stream_volume (pulsesrc)); break; case PROP_MUTE: g_value_set_boolean (value, gst_pulsesrc_get_stream_mute (pulsesrc)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* 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 GstStateChangeReturn gst_pulsesrc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstPulseSrc *this = GST_PULSESRC_CAST (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!(this->mainloop = pa_threaded_mainloop_new ())) goto mainloop_failed; if (pa_threaded_mainloop_start (this->mainloop) < 0) { pa_threaded_mainloop_free (this->mainloop); this->mainloop = NULL; goto mainloop_start_failed; } break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), GST_AUDIO_BASE_SRC (this)->clock, TRUE)); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: /* uncork and start recording */ gst_pulsesrc_play (this); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* stop recording ASAP by corking */ pa_threaded_mainloop_lock (this->mainloop); GST_DEBUG_OBJECT (this, "corking"); gst_pulsesrc_set_corked (this, TRUE, FALSE); pa_threaded_mainloop_unlock (this->mainloop); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* now make sure we get out of the _read method */ gst_pulsesrc_pause (this); break; case GST_STATE_CHANGE_READY_TO_NULL: if (this->mainloop) pa_threaded_mainloop_stop (this->mainloop); gst_pulsesrc_destroy_context (this); if (this->mainloop) { pa_threaded_mainloop_free (this->mainloop); this->mainloop = NULL; } break; case GST_STATE_CHANGE_PAUSED_TO_READY: /* format_lost is reset in release() in baseaudiosink */ gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), GST_AUDIO_BASE_SRC (this)->clock)); break; default: break; } return ret; /* ERRORS */ mainloop_failed: { GST_ELEMENT_ERROR (this, RESOURCE, FAILED, ("pa_threaded_mainloop_new() failed"), (NULL)); return GST_STATE_CHANGE_FAILURE; } mainloop_start_failed: { GST_ELEMENT_ERROR (this, RESOURCE, FAILED, ("pa_threaded_mainloop_start() failed"), (NULL)); return GST_STATE_CHANGE_FAILURE; } }
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 GstStateChangeReturn gst_pulsesrc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstPulseSrc *this = GST_PULSESRC_CAST (element); int e; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: this->mainloop = pa_threaded_mainloop_new (); g_assert (this->mainloop); e = pa_threaded_mainloop_start (this->mainloop); g_assert (e == 0); if (!this->mixer) this->mixer = gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server, this->device, GST_PULSEMIXER_SOURCE); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: /* uncork and start recording */ gst_pulsesrc_play (this); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* stop recording ASAP by corking */ pa_threaded_mainloop_lock (this->mainloop); GST_DEBUG_OBJECT (this, "corking"); gst_pulsesrc_set_corked (this, TRUE, FALSE); pa_threaded_mainloop_unlock (this->mainloop); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* now make sure we get out of the _read method */ gst_pulsesrc_pause (this); break; case GST_STATE_CHANGE_READY_TO_NULL: if (this->mixer) { gst_pulsemixer_ctrl_free (this->mixer); this->mixer = NULL; } if (this->mainloop) pa_threaded_mainloop_stop (this->mainloop); gst_pulsesrc_destroy_context (this); if (this->mainloop) { pa_threaded_mainloop_free (this->mainloop); this->mainloop = NULL; } break; default: break; } return ret; }
/* This is essentially gst_base_src_negotiate_default() but the caps * are guaranteed to have a channel layout for > 2 channels */ static gboolean gst_pulsesrc_negotiate (GstBaseSrc * basesrc) { GstCaps *thiscaps; GstCaps *caps = NULL; GstCaps *peercaps = NULL; gboolean result = FALSE; /* first see what is possible on our source pad */ thiscaps = gst_pad_get_caps_reffed (GST_BASE_SRC_PAD (basesrc)); GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps); /* nothing or anything is allowed, we're done */ if (thiscaps == NULL || gst_caps_is_any (thiscaps)) goto no_nego_needed; /* get the peer caps */ peercaps = gst_pad_peer_get_caps_reffed (GST_BASE_SRC_PAD (basesrc)); GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps); if (peercaps) { /* get intersection */ caps = gst_caps_intersect (thiscaps, peercaps); GST_DEBUG_OBJECT (basesrc, "intersect: %" GST_PTR_FORMAT, caps); gst_caps_unref (thiscaps); gst_caps_unref (peercaps); } else { /* no peer, work with our own caps then */ caps = thiscaps; } if (caps) { /* take first (and best, since they are sorted) possibility */ caps = gst_caps_make_writable (caps); gst_caps_truncate (caps); /* now fixate */ if (!gst_caps_is_empty (caps)) { gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps); GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps); if (gst_caps_is_any (caps)) { /* hmm, still anything, so element can do anything and * nego is not needed */ result = TRUE; } else if (gst_caps_is_fixed (caps)) { /* yay, fixed caps, use those then */ result = gst_pulsesrc_create_stream (GST_PULSESRC_CAST (basesrc), caps); if (result) result = gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps); } } gst_caps_unref (caps); } return result; no_nego_needed: { GST_DEBUG_OBJECT (basesrc, "no negotiation needed"); if (thiscaps) gst_caps_unref (thiscaps); return TRUE; } }
static gboolean gst_pulsesrc_open (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); gchar *name = gst_pulse_client_name (); pa_threaded_mainloop_lock (pulsesrc->mainloop); g_assert (!pulsesrc->context); g_assert (!pulsesrc->stream); GST_DEBUG_OBJECT (pulsesrc, "opening device"); if (!(pulsesrc->context = pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop), name))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"), (NULL)); goto unlock_and_fail; } pa_context_set_state_callback (pulsesrc->context, gst_pulsesrc_context_state_cb, pulsesrc); GST_DEBUG_OBJECT (pulsesrc, "connect to server %s", GST_STR_NULL (pulsesrc->server)); if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } for (;;) { pa_context_state_t state; 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); } GST_DEBUG_OBJECT (pulsesrc, "connected"); pa_threaded_mainloop_unlock (pulsesrc->mainloop); g_free (name); return TRUE; /* ERRORS */ unlock_and_fail: { gst_pulsesrc_destroy_context (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); g_free (name); return FALSE; } }
static void gst_pulsesrc_stream_overflow_cb (pa_stream * s, void *userdata) { GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got overflow"); }
static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) { pa_buffer_attr wanted; const pa_buffer_attr *actual; GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_threaded_mainloop_lock (pulsesrc->mainloop); wanted.maxlength = -1; wanted.tlength = -1; wanted.prebuf = 0; wanted.minreq = -1; wanted.fragsize = spec->segsize; GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize); if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted, PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONOUS | #ifdef 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; } pulsesrc->corked = TRUE; for (;;) { pa_stream_state_t state; 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); } /* get the actual buffering properties now */ actual = pa_stream_get_buffer_attr (pulsesrc->stream); GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)", actual->tlength, wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq, wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)", actual->fragsize, wanted.fragsize); if (actual->fragsize >= wanted.fragsize) { spec->segsize = actual->fragsize; } else { spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize); } spec->segtotal = actual->maxlength / spec->segsize; pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }
static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { pa_buffer_attr wanted; const pa_buffer_attr *actual; GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_stream_flags_t flags; pa_operation *o; GstAudioClock *clock; pa_threaded_mainloop_lock (pulsesrc->mainloop); { GstAudioRingBufferSpec s = *spec; const pa_channel_map *m; m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &s); gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (pulsesrc)->ringbuffer, s.info.position); } /* enable event notifications */ GST_LOG_OBJECT (pulsesrc, "subscribing to context events"); if (!(o = pa_context_subscribe (pulsesrc->context, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_context_subscribe() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pa_operation_unref (o); wanted.maxlength = -1; wanted.tlength = -1; wanted.prebuf = 0; wanted.minreq = -1; wanted.fragsize = spec->segsize; GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize); flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED; if (pulsesrc->mute_set && pulsesrc->mute) flags |= PA_STREAM_START_MUTED; if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted, flags) < 0) { goto connect_failed; } /* our clock will now start from 0 again */ clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock); gst_audio_clock_reset (clock, 0); pulsesrc->corked = TRUE; for (;;) { pa_stream_state_t state; state = pa_stream_get_state (pulsesrc->stream); if (!PA_STREAM_IS_GOOD (state)) goto stream_is_bad; if (state == PA_STREAM_READY) break; /* Wait until the stream is ready */ pa_threaded_mainloop_wait (pulsesrc->mainloop); } pulsesrc->stream_connected = TRUE; /* store the source output index so it can be accessed via a property */ pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream); g_object_notify (G_OBJECT (pulsesrc), "source-output-index"); if (pulsesrc->volume_set) { gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume); pulsesrc->volume_set = FALSE; } /* get the actual buffering properties now */ actual = pa_stream_get_buffer_attr (pulsesrc->stream); GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)", actual->tlength, wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq, wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)", actual->fragsize, wanted.fragsize); if (actual->fragsize >= wanted.fragsize) { spec->segsize = actual->fragsize; } else { spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize); } spec->segtotal = actual->maxlength / spec->segsize; if (!pulsesrc->paused) { GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing"); gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ connect_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } stream_is_bad: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }