pa_context *context;
pa_stream *stream;
-#ifdef HAVE_PULSE_1_0
pa_format_info *format;
guint channels;
gboolean is_pcm;
-#else
- pa_sample_spec sample_spec;
-#endif
void *m_data;
size_t m_towrite;
pbuf->context = NULL;
pbuf->stream = NULL;
-#ifdef HAVE_PULSE_1_0
pbuf->format = NULL;
pbuf->channels = 0;
pbuf->is_pcm = FALSE;
-#else
- pa_sample_spec_init (&pbuf->sample_spec);
-#endif
pbuf->m_data = NULL;
pbuf->m_towrite = 0;
pbuf->m_offset = 0;
pbuf->m_lastoffset = 0;
}
-#ifdef HAVE_PULSE_1_0
if (pbuf->format) {
pa_format_info_free (pbuf->format);
pbuf->format = NULL;
pbuf->channels = 0;
pbuf->is_pcm = FALSE;
}
-#endif
pa_stream_disconnect (pbuf->stream);
if (idx != pa_stream_get_index (pbuf->stream))
continue;
-#ifdef HAVE_PULSE_1_0
if (psink->device && pbuf->is_pcm &&
!g_str_equal (psink->device,
pa_stream_get_device_name (pbuf->stream))) {
if (!gst_pad_push_event (GST_BASE_SINK (psink)->sinkpad, renego))
GST_DEBUG_OBJECT (psink, "Emitted sink-changed - nobody was listening");
}
-#endif
/* Actually this event is also triggered when other properties of
* the stream change that are unrelated to the volume. However it is
gst_element_post_message (GST_ELEMENT_CAST (psink),
gst_message_new_request_state (GST_OBJECT_CAST (psink),
GST_STATE_PLAYING));
-#ifdef HAVE_PULSE_1_0
} else if (!strcmp (name, PA_STREAM_EVENT_FORMAT_LOST)) {
GstEvent *renego;
GST_ELEMENT_ERROR (psink, STREAM, FORMAT, ("Sink format changed"),
("Sink format changed"));
}
-#endif
} else {
GST_DEBUG_OBJECT (psink, "got unknown event %s", name);
}
const pa_buffer_attr *actual;
pa_channel_map channel_map;
pa_operation *o = NULL;
-#ifdef HAVE_PULSE_0_9_20
pa_cvolume v;
-#endif
pa_cvolume *pv = NULL;
pa_stream_flags_t flags;
const gchar *name;
GstAudioClock *clock;
-#ifdef HAVE_PULSE_1_0
pa_format_info *formats[1];
#ifndef GST_DISABLE_GST_DEBUG
gchar print_buf[PA_FORMAT_INFO_SNPRINT_MAX];
#endif
-#endif
psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (buf));
pbuf = GST_PULSERING_BUFFER_CAST (buf);
GST_LOG_OBJECT (psink, "creating sample spec");
/* convert the gstreamer sample spec to the pulseaudio format */
-#ifdef HAVE_PULSE_1_0
if (!gst_pulse_fill_format_info (spec, &pbuf->format, &pbuf->channels))
goto invalid_spec;
pbuf->is_pcm = pa_format_info_is_pcm (pbuf->format);
-#else
- if (!gst_pulse_fill_sample_spec (spec, &pbuf->sample_spec))
- goto invalid_spec;
-#endif
pa_threaded_mainloop_lock (mainloop);
pa_operation_unref (o);
/* initialize the channel map */
-#ifdef HAVE_PULSE_1_0
if (pbuf->is_pcm && gst_pulse_gst_to_channel_map (&channel_map, spec))
pa_format_info_set_channel_map (pbuf->format, &channel_map);
-#else
- gst_pulse_gst_to_channel_map (&channel_map, spec);
-#endif
/* find a good name for the stream */
if (psink->stream_name)
name = "Playback Stream";
/* create a stream */
-#ifdef HAVE_PULSE_1_0
formats[0] = pbuf->format;
if (!(pbuf->stream = pa_stream_new_extended (pbuf->context, name, formats, 1,
psink->proplist)))
goto stream_failed;
-#else
- GST_LOG_OBJECT (psink, "creating stream with name %s", name);
- if (!(pbuf->stream = pa_stream_new_with_proplist (pbuf->context, name,
- &pbuf->sample_spec, &channel_map, psink->proplist)))
- goto stream_failed;
-#endif
/* install essential callbacks */
pa_stream_set_state_callback (pbuf->stream,
GST_INFO_OBJECT (psink, "prebuf: %d", wanted.prebuf);
GST_INFO_OBJECT (psink, "minreq: %d", wanted.minreq);
-#ifdef HAVE_PULSE_0_9_20
/* configure volume when we changed it, else we leave the default */
if (psink->volume_set) {
GST_LOG_OBJECT (psink, "have volume of %f", psink->volume);
pv = &v;
-#ifdef HAVE_PULSE_1_0
if (pbuf->is_pcm)
gst_pulse_cvolume_from_linear (pv, pbuf->channels, psink->volume);
else {
GST_DEBUG_OBJECT (psink, "passthrough stream, not setting volume");
pv = NULL;
}
-#else
- gst_pulse_cvolume_from_linear (pv, pbuf->sample_spec.channels,
- psink->volume);
-#endif
} else {
pv = NULL;
}
-#endif
/* construct the flags */
flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
if (!gst_pulsering_wait_for_stream_ready (psink, pbuf->stream))
goto connect_failed;
-#ifdef HAVE_PULSE_1_0
g_free (psink->device);
psink->device = g_strdup (pa_stream_get_device_name (pbuf->stream));
pa_stream_get_format_info (pbuf->stream));
GST_INFO_OBJECT (psink, "negotiated to: %s", print_buf);
#endif
-#endif
/* After we passed the volume off of to PA we never want to set it
again, since it is PA's job to save/restore volumes. */
gst_pulsering_destroy_stream (pbuf);
pa_threaded_mainloop_unlock (mainloop);
-#ifdef HAVE_PULSE_1_0
{
GstPulseSink *psink;
g_atomic_int_set (&psink->format_lost, FALSE);
psink->format_lost_time = GST_CLOCK_TIME_NONE;
}
-#endif
return TRUE;
}
psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_get (&psink->format_lost)) {
/* Sink format changed, stream's gone so fake being paused */
return TRUE;
}
-#endif
GST_DEBUG_OBJECT (psink, "setting corked state to %d", corked);
if (pbuf->corked != corked) {
GST_DEBUG_OBJECT (psink, "signal commit thread");
pa_threaded_mainloop_signal (mainloop, 0);
}
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_get (&psink->format_lost)) {
/* Don't try to flush, the stream's probably gone by now */
res = TRUE;
goto cleanup;
}
-#endif
/* then try to flush, it's not fatal when this fails */
GST_DEBUG_OBJECT (psink, "flushing");
* needed to properly handle reverse playback: it points to the last sample. */
data_end = data + (bpf * inr);
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_get (&psink->format_lost)) {
/* Sink format changed, drop the data and hope upstream renegotiates */
goto fake_done;
}
-#endif
if (pbuf->paused)
goto was_paused;
for (;;) {
pbuf->m_writable = pa_stream_writable_size (pbuf->stream);
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_get (&psink->format_lost)) {
/* Sink format changed, give up and hope upstream renegotiates */
goto fake_done;
}
-#endif
if (pbuf->m_writable == (size_t) - 1)
goto writable_size_failed;
GST_LOG_OBJECT (psink, "writing %u samples at offset %" G_GUINT64_FORMAT,
(guint) avail, offset);
-#ifdef HAVE_PULSE_1_0
/* No trick modes for passthrough streams */
if (G_UNLIKELY (!pbuf->is_pcm && (inr != outr || reverse))) {
GST_WARNING_OBJECT (psink, "Passthrough stream can't run in trick mode");
goto unlock_and_fail;
}
-#endif
if (G_LIKELY (inr == outr && !reverse)) {
/* no rate conversion, simply write out the samples */
}
}
-#ifdef HAVE_PULSE_1_0
fake_done:
-#endif
/* we consumed all samples here */
data = data_end + bpf;
pbuf = GST_PULSERING_BUFFER_CAST (sink->ringbuffer);
psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_get (&psink->format_lost)) {
/* Stream was lost in a format change, it'll get set up again once
* upstream renegotiates */
return psink->format_lost_time;
}
-#endif
pa_threaded_mainloop_lock (mainloop);
if (gst_pulsering_is_dead (psink, pbuf, TRUE))
{
GstPulseRingBuffer *pbuf;
GstPulseSink *psink;
-#ifdef HAVE_PULSE_1_0
GList *l;
guint8 j;
-#endif
pbuf = GST_PULSERING_BUFFER_CAST (userdata);
psink = GST_PULSESINK_CAST (GST_OBJECT_PARENT (pbuf));
g_free (psink->device_description);
psink->device_description = g_strdup (i->description);
-#ifdef HAVE_PULSE_1_0
g_mutex_lock (psink->sink_formats_lock);
for (l = g_list_first (psink->sink_formats); l; l = g_list_next (l))
pa_format_info_copy (i->formats[j]));
g_mutex_unlock (psink->sink_formats_lock);
-#endif
done:
pa_threaded_mainloop_signal (mainloop, 0);
}
-#ifdef HAVE_PULSE_1_0
/* NOTE: If you're making changes here, see if pulseaudiosink acceptcaps also
* needs to be changed accordingly. */
static gboolean
goto out;
}
}
-#endif
static void
gst_pulsesink_init (GstPulseSink * pulsesink)
pulsesink->device_description = NULL;
pulsesink->client_name = gst_pulse_client_name ();
-#ifdef HAVE_PULSE_1_0
pulsesink->sink_formats_lock = g_mutex_new ();
pulsesink->sink_formats = NULL;
-#endif
pulsesink->volume = DEFAULT_VOLUME;
pulsesink->volume_set = FALSE;
pulsesink->notify = 0;
-#ifdef HAVE_PULSE_1_0
g_atomic_int_set (&pulsesink->format_lost, FALSE);
pulsesink->format_lost_time = GST_CLOCK_TIME_NONE;
-#endif
pulsesink->properties = NULL;
pulsesink->proplist = NULL;
gst_pulsesink_finalize (GObject * object)
{
GstPulseSink *pulsesink = GST_PULSESINK_CAST (object);
-#ifdef HAVE_PULSE_1_0
GList *i;
-#endif
g_free (pulsesink->server);
g_free (pulsesink->device);
g_free (pulsesink->device_description);
g_free (pulsesink->client_name);
-#ifdef HAVE_PULSE_1_0
for (i = g_list_first (pulsesink->sink_formats); i; i = g_list_next (i))
pa_format_info_free ((pa_format_info *) i->data);
g_list_free (pulsesink->sink_formats);
g_mutex_free (pulsesink->sink_formats_lock);
-#endif
if (pulsesink->properties)
gst_structure_free (pulsesink->properties);
if ((idx = pa_stream_get_index (pbuf->stream)) == PA_INVALID_INDEX)
goto no_index;
-#ifdef HAVE_PULSE_1_0
if (pbuf->is_pcm)
gst_pulse_cvolume_from_linear (&v, pbuf->channels, volume);
else
/* FIXME: this will eventually be superceded by checks to see if the volume
* is readable/writable */
goto unlock;
-#else
- gst_pulse_cvolume_from_linear (&v, pbuf->sample_spec.channels, volume);
-#endif
if (!(o = pa_context_set_sink_input_volume (pbuf->context, idx,
&v, NULL, NULL)))
static gboolean
gst_pulsesink_query (GstBaseSink * sink, GstQuery * query)
{
-#ifdef HAVE_PULSE_1_0
GstPulseSink *pulsesink = GST_PULSESINK_CAST (sink);
gboolean ret;
break;
}
return ret;
-#else
- return GST_BASE_SINK_CLASS (parent_class)->query (sink, query);
-#endif
}
static void
#include <gst/base/gstbasesrc.h>
#include <gst/gsttaglist.h>
-#ifdef HAVE_PULSE_1_0
#include <gst/interfaces/streamvolume.h>
-#endif
#include "pulsesrc.h"
#include "pulseutil.h"
#define DEFAULT_DEVICE NULL
#define DEFAULT_DEVICE_NAME NULL
-#ifdef HAVE_PULSE_1_0
#define DEFAULT_VOLUME 1.0
#define DEFAULT_MUTE FALSE
#define MAX_VOLUME 10.0
-#endif
enum
{
PROP_CLIENT,
PROP_STREAM_PROPERTIES,
PROP_SOURCE_OUTPUT_INDEX,
-#ifdef HAVE_PULSE_1_0
PROP_VOLUME,
PROP_MUTE,
-#endif
PROP_LAST
};
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&pad_template));
-#ifdef HAVE_PULSE_1_0
/**
* GstPulseSrc:volume
*
- * The volume of the record stream. Only works when using PulseAudio 1.0 or
- * later.
- *
- * Since: 0.10.36
+ * The volume of the record stream.
*/
g_object_class_install_property (gobject_class,
PROP_VOLUME, g_param_spec_double ("volume", "Volume",
/**
* GstPulseSrc:mute
*
- * Whether the stream is muted or not. Only works when using PulseAudio 1.0
- * or later.
- *
- * Since: 0.10.36
+ * Whether the stream is muted or not.
*/
g_object_class_install_property (gobject_class,
PROP_MUTE, g_param_spec_boolean ("mute", "Mute",
"Mute state of this stream",
DEFAULT_MUTE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-#endif
}
static void
pulsesrc->paused = TRUE;
pulsesrc->in_read = FALSE;
-#ifdef HAVE_PULSE_1_0
pulsesrc->volume = DEFAULT_VOLUME;
pulsesrc->volume_set = FALSE;
pulsesrc->mute_set = FALSE;
pulsesrc->notify = 0;
-#endif
pulsesrc->mixer = NULL;
/* Make sure we don't get any further callbacks */
pa_context_set_state_callback (pulsesrc->context, NULL, NULL);
-#ifdef HAVE_PULSE_1_0
pa_context_set_subscribe_callback (pulsesrc->context, NULL, NULL);
-#endif
pa_context_unref (pulsesrc->context);
}
}
-#ifdef HAVE_PULSE_1_0
static void
gst_pulsesrc_source_output_info_cb (pa_context * c,
const pa_source_output_info * i, int eol, void *userdata)
goto unlock;
}
}
-#endif
static void
gst_pulsesrc_set_property (GObject * object,
pa_proplist_free (pulsesrc->proplist);
pulsesrc->proplist = gst_pulse_make_proplist (pulsesrc->properties);
break;
-#ifdef HAVE_PULSE_1_0
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;
-#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_SOURCE_OUTPUT_INDEX:
g_value_set_uint (value, pulsesrc->source_output_idx);
break;
-#ifdef HAVE_PULSE_1_0
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;
-#endif
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GST_WARNING_OBJECT (GST_PULSESRC_CAST (userdata), "Got overflow");
}
-#ifdef HAVE_PULSE_1_0
static void
gst_pulsesrc_context_subscribe_cb (pa_context * c,
pa_subscription_event_type_t t, uint32_t idx, void *userdata)
/* inform streaming thread to notify */
g_atomic_int_compare_and_exchange (&psrc->notify, 0, 1);
}
-#endif
static gboolean
gst_pulsesrc_open (GstAudioSrc * asrc)
pa_context_set_state_callback (pulsesrc->context,
gst_pulsesrc_context_state_cb, pulsesrc);
-#ifdef HAVE_PULSE_1_0
pa_context_set_subscribe_callback (pulsesrc->context,
gst_pulsesrc_context_subscribe_cb, pulsesrc);
-#endif
GST_DEBUG_OBJECT (pulsesrc, "connect to server %s",
GST_STR_NULL (pulsesrc->server));
pa_threaded_mainloop_lock (pulsesrc->mainloop);
pulsesrc->in_read = TRUE;
-#ifdef HAVE_PULSE_1_0
if (g_atomic_int_compare_and_exchange (&pulsesrc->notify, 1, 0)) {
g_object_notify (G_OBJECT (pulsesrc), "volume");
g_object_notify (G_OBJECT (pulsesrc), "mute");
}
-#endif
if (pulsesrc->paused)
goto was_paused;
const pa_buffer_attr *actual;
GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc);
pa_stream_flags_t flags;
-#ifdef HAVE_PULSE_1_0
pa_operation *o;
-#endif
pa_threaded_mainloop_lock (pulsesrc->mainloop);
-#ifdef HAVE_PULSE_1_0
/* enable event notifications */
GST_LOG_OBJECT (pulsesrc, "subscribing to context events");
if (!(o = pa_context_subscribe (pulsesrc->context,
}
pa_operation_unref (o);
-#endif
wanted.maxlength = -1;
wanted.tlength = -1;
PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY |
PA_STREAM_START_CORKED;
-#ifdef HAVE_PULSE_1_0
if (pulsesrc->mute_set && pulsesrc->mute)
flags |= PA_STREAM_START_MUTED;
-#endif
if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted,
flags) < 0) {
pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream);
g_object_notify (G_OBJECT (pulsesrc), "source-output-index");
-#ifdef HAVE_PULSE_1_0
if (pulsesrc->volume_set) {
gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume);
pulsesrc->volume_set = FALSE;
}
-#endif
/* get the actual buffering properties now */
actual = pa_stream_get_buffer_attr (pulsesrc->stream);