pulse: allow setting stream properties

Add a "properties" property to the elements to allow setting extra stream
properties.

Fixes #537544
This commit is contained in:
Stefan Kost 2010-08-16 15:35:51 +03:00
parent 956074a3cf
commit f604e20499
6 changed files with 149 additions and 6 deletions

View file

@ -80,6 +80,7 @@ enum
PROP_VOLUME,
PROP_MUTE,
PROP_CLIENT,
PROP_STREAM_PROPERTIES,
PROP_LAST
};
@ -770,7 +771,11 @@ gst_pulseringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
/* create a stream */
GST_LOG_OBJECT (psink, "creating stream with name %s", name);
if (!(pbuf->stream = pa_stream_new (pctx->context,
if (psink->proplist) {
if (!(pbuf->stream = pa_stream_new_with_proplist (pctx->context,
name, &pbuf->sample_spec, &channel_map, psink->proplist)))
goto stream_failed;
} else if (!(pbuf->stream = pa_stream_new (pctx->context,
name, &pbuf->sample_spec, &channel_map)))
goto stream_failed;
@ -1853,7 +1858,7 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass)
/**
* GstPulseSink:client
*
* The PulseAudio client name to use
* The PulseAudio client name to use.
*
* Since: 0.10.25
*/
@ -1863,6 +1868,29 @@ gst_pulsesink_class_init (GstPulseSinkClass * klass)
"The PulseAudio client name to use", gst_pulse_client_name (),
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_READY));
/**
* GstPulseSink:stream-properties
*
* List of pulseaudio stream properties. A list of defined properties can be
* found in the <ulink href="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
*
* Below is an example for registering as a music application to pulseaudio.
* |[
* GstStructure *props;
*
* props = gst_structure_from_string ("props,media.role=music", NULL);
* g_object_set (pulse, "stream-properties", props, NULL);
* gst_structure_free
* ]|
*
* Since: 0.10.26
*/
g_object_class_install_property (gobject_class,
PROP_STREAM_PROPERTIES,
g_param_spec_boxed ("stream-properties", "stream properties",
"list of pulseaudio stream properties",
GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
/* returns the current time of the sink ringbuffer */
@ -1926,6 +1954,9 @@ gst_pulsesink_init (GstPulseSink * pulsesink, GstPulseSinkClass * klass)
/* needed for conditional execution */
pulsesink->pa_version = pa_get_library_version ();
pulsesink->properties = NULL;
pulsesink->proplist = NULL;
GST_DEBUG_OBJECT (pulsesink, "using pulseaudio version %s",
pulsesink->pa_version);
@ -1945,6 +1976,11 @@ gst_pulsesink_finalize (GObject * object)
g_free (pulsesink->device_description);
g_free (pulsesink->client_name);
if (pulsesink->properties)
gst_structure_free (pulsesink->properties);
if (pulsesink->proplist)
pa_proplist_free (pulsesink->proplist);
if (pulsesink->probe) {
gst_pulseprobe_free (pulsesink->probe);
pulsesink->probe = NULL;
@ -2385,6 +2421,15 @@ gst_pulsesink_set_property (GObject * object,
} else
pulsesink->client_name = g_value_dup_string (value);
break;
case PROP_STREAM_PROPERTIES:
if (pulsesink->properties)
gst_structure_free (pulsesink->properties);
pulsesink->properties =
gst_structure_copy (gst_value_get_structure (value));
if (pulsesink->proplist)
pa_proplist_free (pulsesink->proplist);
pulsesink->proplist = gst_pulse_make_proplist (pulsesink->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@ -2419,6 +2464,9 @@ gst_pulsesink_get_property (GObject * object,
case PROP_CLIENT:
g_value_set_string (value, pulsesink->client_name);
break;
case PROP_STREAM_PROPERTIES:
gst_value_set_structure (value, pulsesink->properties);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;

View file

@ -72,6 +72,8 @@ struct _GstPulseSink
const gchar *pa_version;
GstStructure *properties;
pa_proplist *proplist;
};
struct _GstPulseSinkClass

View file

@ -61,6 +61,7 @@ enum
PROP_SERVER,
PROP_DEVICE,
PROP_DEVICE_NAME,
PROP_STREAM_PROPERTIES,
PROP_LAST
};
@ -244,6 +245,29 @@ gst_pulsesrc_class_init (GstPulseSrcClass * klass)
g_param_spec_string ("device-name", "Device name",
"Human-readable name of the sound device", DEFAULT_DEVICE_NAME,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
/**
* GstPulseSrc:stream-properties
*
* List of pulseaudio stream properties. A list of defined properties can be
* found in the <ulink href="http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html">pulseaudio api docs</ulink>.
*
* Below is an example for registering as a music application to pulseaudio.
* |[
* GstStructure *props;
*
* props = gst_structure_from_string ("props,media.role=music", NULL);
* g_object_set (pulse, "stream-properties", props, NULL);
* gst_structure_free (props);
* ]|
*
* Since: 0.10.26
*/
g_object_class_install_property (gobject_class,
PROP_STREAM_PROPERTIES,
g_param_spec_boxed ("stream-properties", "stream properties",
"list of pulseaudio stream properties",
GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
@ -273,6 +297,9 @@ gst_pulsesrc_init (GstPulseSrc * pulsesrc, GstPulseSrcClass * klass)
pulsesrc->mixer = NULL;
pulsesrc->properties = NULL;
pulsesrc->proplist = NULL;
pulsesrc->probe = gst_pulseprobe_new (G_OBJECT (pulsesrc), G_OBJECT_GET_CLASS (pulsesrc), PROP_DEVICE, pulsesrc->server, FALSE, TRUE); /* FALSE for sinks, TRUE for sources */
/* this should be the default but it isn't yet */
@ -314,6 +341,11 @@ gst_pulsesrc_finalize (GObject * 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;
@ -432,6 +464,15 @@ gst_pulsesrc_set_property (GObject * object,
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;
@ -455,6 +496,9 @@ gst_pulsesrc_get_property (GObject * object,
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;
@ -797,6 +841,7 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
GstStructure *s;
gboolean need_channel_layout = FALSE;
GstRingBufferSpec spec;
const gchar *name;
memset (&spec, 0, sizeof (GstRingBufferSpec));
spec.latency_time = GST_SECOND;
@ -832,9 +877,19 @@ gst_pulsesrc_create_stream (GstPulseSrc * pulsesrc, GstCaps * caps)
need_channel_layout = TRUE;
}
if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
"Record Stream",
&pulsesrc->sample_spec,
name = "Record Stream";
if (pulsesrc->proplist) {
if (!(pulsesrc->stream = pa_stream_new_with_proplist (pulsesrc->context,
name, &pulsesrc->sample_spec,
(need_channel_layout) ? NULL : &channel_map,
pulsesrc->proplist))) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
("Failed to create stream: %s",
pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
goto unlock_and_fail;
}
} else if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
name, &pulsesrc->sample_spec,
(need_channel_layout) ? NULL : &channel_map))) {
GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
("Failed to create stream: %s",

View file

@ -76,6 +76,9 @@ struct _GstPulseSrc
gboolean operation_success:1;
gboolean paused:1;
gboolean in_read:1;
GstStructure *properties;
pa_proplist *proplist;
};
struct _GstPulseSrcClass

View file

@ -216,3 +216,36 @@ gst_pulse_cvolume_from_linear (pa_cvolume * v, unsigned channels,
{
pa_cvolume_set (v, channels, pa_sw_volume_from_linear (volume));
}
static gboolean
make_proplist_item (GQuark field_id, const GValue * value, gpointer user_data)
{
pa_proplist *p = (pa_proplist *) user_data;
gchar *prop_id = (gchar *) g_quark_to_string (field_id);
/* http://0pointer.de/lennart/projects/pulseaudio/doxygen/proplist_8h.html */
/* match prop id */
/* check type */
switch (G_VALUE_TYPE (value)) {
case G_TYPE_STRING:
pa_proplist_sets (p, prop_id, g_value_get_string (value));
break;
default:
GST_WARNING ("unmapped property type %s", G_VALUE_TYPE_NAME (value));
break;
}
return TRUE;
}
pa_proplist *
gst_pulse_make_proplist (const GstStructure * properties)
{
pa_proplist *proplist = pa_proplist_new ();
/* iterate the structure and fill the proplist */
gst_structure_foreach (properties, make_proplist_item, proplist);
return proplist;
}

View file

@ -37,7 +37,9 @@ pa_channel_map *gst_pulse_gst_to_channel_map (pa_channel_map * map,
GstRingBufferSpec *gst_pulse_channel_map_to_gst (const pa_channel_map * map,
GstRingBufferSpec * spec);
void gst_pulse_cvolume_from_linear(pa_cvolume *v, unsigned channels, gdouble volume);
void gst_pulse_cvolume_from_linear (pa_cvolume *v, unsigned channels, gdouble volume);
pa_proplist *gst_pulse_make_proplist (const GstStructure *properties);
#if !HAVE_PULSE_0_9_11
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {