diff --git a/ext/pulse/pulsesink.c b/ext/pulse/pulsesink.c
index 97ffd4bc00..a6f9f881bf 100644
--- a/ext/pulse/pulsesink.c
+++ b/ext/pulse/pulsesink.c
@@ -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 pulseaudio api docs.
+ *
+ * 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;
diff --git a/ext/pulse/pulsesink.h b/ext/pulse/pulsesink.h
index 9658c1ea27..83a0bed2af 100644
--- a/ext/pulse/pulsesink.h
+++ b/ext/pulse/pulsesink.h
@@ -72,6 +72,8 @@ struct _GstPulseSink
const gchar *pa_version;
+ GstStructure *properties;
+ pa_proplist *proplist;
};
struct _GstPulseSinkClass
diff --git a/ext/pulse/pulsesrc.c b/ext/pulse/pulsesrc.c
index c0a38841d5..0baad9f163 100644
--- a/ext/pulse/pulsesrc.c
+++ b/ext/pulse/pulsesrc.c
@@ -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 pulseaudio api docs.
+ *
+ * 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",
diff --git a/ext/pulse/pulsesrc.h b/ext/pulse/pulsesrc.h
index be8943475b..fb5006d6f6 100644
--- a/ext/pulse/pulsesrc.h
+++ b/ext/pulse/pulsesrc.h
@@ -76,6 +76,9 @@ struct _GstPulseSrc
gboolean operation_success:1;
gboolean paused:1;
gboolean in_read:1;
+
+ GstStructure *properties;
+ pa_proplist *proplist;
};
struct _GstPulseSrcClass
diff --git a/ext/pulse/pulseutil.c b/ext/pulse/pulseutil.c
index 2541459904..c779e1aff9 100644
--- a/ext/pulse/pulseutil.c
+++ b/ext/pulse/pulseutil.c
@@ -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;
+}
diff --git a/ext/pulse/pulseutil.h b/ext/pulse/pulseutil.h
index 4cafba51b2..75b31120a9 100644
--- a/ext/pulse/pulseutil.h
+++ b/ext/pulse/pulseutil.h
@@ -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) {