PROP_VOLUME,
PROP_MUTE,
PROP_CLIENT,
+ PROP_STREAM_PROPERTIES,
PROP_LAST
};
/* 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;
/**
* GstPulseSink:client
*
- * The PulseAudio client name to use
+ * The PulseAudio client name to use.
*
* Since: 0.10.25
*/
"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 */
/* 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);
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;
} 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;
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;
const gchar *pa_version;
+ GstStructure *properties;
+ pa_proplist *proplist;
};
struct _GstPulseSinkClass
PROP_SERVER,
PROP_DEVICE,
PROP_DEVICE_NAME,
+ PROP_STREAM_PROPERTIES,
PROP_LAST
};
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
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 */
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;
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;
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;
GstStructure *s;
gboolean need_channel_layout = FALSE;
GstRingBufferSpec spec;
+ const gchar *name;
memset (&spec, 0, sizeof (GstRingBufferSpec));
spec.latency_time = GST_SECOND;
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",
gboolean operation_success:1;
gboolean paused:1;
gboolean in_read:1;
+
+ GstStructure *properties;
+ pa_proplist *proplist;
};
struct _GstPulseSrcClass
{
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;
+}
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) {