2 * GStreamer pulseaudio plugin
4 * Copyright (c) 2004-2008 Lennart Poettering
6 * gst-pulse is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as
8 * published by the Free Software Foundation; either version 2.1 of the
9 * License, or (at your option) any later version.
11 * gst-pulse is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with gst-pulse; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * SECTION:element-pulsesrc
24 * @short_description: Capture audio from a PulseAudio sound server
25 * @see_also: pulsesink, pulsemixer
29 * This element captures audio from a PulseAudio sound server.
31 * <title>Example pipelines</title>
34 * gst-launch -v pulsesrc ! audioconvert ! vorbisenc ! oggmux ! filesink location=alsasrc.ogg
36 * Record from a sound card using ALSA and encode to Ogg/Vorbis.
48 #include <gst/base/gstbasesrc.h>
49 #include <gst/gsttaglist.h>
52 #include "pulseutil.h"
53 #include "pulsemixerctrl.h"
55 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
56 #define GST_CAT_DEFAULT pulse_debug
65 static GstAudioSrcClass *parent_class = NULL;
67 GST_IMPLEMENT_PULSEMIXER_CTRL_METHODS (GstPulseSrc, gst_pulsesrc);
69 static void gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc);
71 static void gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc);
73 static void gst_pulsesrc_set_property (GObject * object, guint prop_id,
74 const GValue * value, GParamSpec * pspec);
75 static void gst_pulsesrc_get_property (GObject * object, guint prop_id,
76 GValue * value, GParamSpec * pspec);
77 static void gst_pulsesrc_finalize (GObject * object);
79 static void gst_pulsesrc_dispose (GObject * object);
81 static gboolean gst_pulsesrc_open (GstAudioSrc * asrc);
83 static gboolean gst_pulsesrc_close (GstAudioSrc * asrc);
85 static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc,
86 GstRingBufferSpec * spec);
87 static gboolean gst_pulsesrc_unprepare (GstAudioSrc * asrc);
89 static guint gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data,
91 static guint gst_pulsesrc_delay (GstAudioSrc * asrc);
93 static GstStateChangeReturn gst_pulsesrc_change_state (GstElement *
94 element, GstStateChange transition);
96 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
97 # define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
99 # define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
102 GST_IMPLEMENT_PULSEPROBE_METHODS (GstPulseSrc, gst_pulsesrc);
105 gst_pulsesrc_interface_supported (GstImplementsInterface *
106 iface, GType interface_type)
108 GstPulseSrc *this = GST_PULSESRC (iface);
110 if (interface_type == GST_TYPE_MIXER && this->mixer)
113 if (interface_type == GST_TYPE_PROPERTY_PROBE && this->probe)
120 gst_pulsesrc_implements_interface_init (GstImplementsInterfaceClass * klass)
122 klass->supported = gst_pulsesrc_interface_supported;
126 gst_pulsesrc_init_interfaces (GType type)
128 static const GInterfaceInfo implements_iface_info = {
129 (GInterfaceInitFunc) gst_pulsesrc_implements_interface_init,
133 static const GInterfaceInfo mixer_iface_info = {
134 (GInterfaceInitFunc) gst_pulsesrc_mixer_interface_init,
138 static const GInterfaceInfo probe_iface_info = {
139 (GInterfaceInitFunc) gst_pulsesrc_property_probe_interface_init,
144 g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE,
145 &implements_iface_info);
146 g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_iface_info);
147 g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
152 gst_pulsesrc_base_init (gpointer g_class)
155 static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("src",
158 GST_STATIC_CAPS ("audio/x-raw-int, "
159 "endianness = (int) { " ENDIANNESS " }, "
160 "signed = (boolean) TRUE, "
163 "rate = (int) [ 1, MAX ], "
164 "channels = (int) [ 1, 16 ];"
166 "endianness = (int) { " ENDIANNESS " }, "
167 "signed = (boolean) TRUE, "
170 "rate = (int) [ 1, MAX ], "
171 "channels = (int) [ 1, 16 ];"
172 "audio/x-raw-float, "
173 "endianness = (int) { " ENDIANNESS " }, "
175 "rate = (int) [ 1, MAX ], "
176 "channels = (int) [ 1, 16 ];"
178 "signed = (boolean) FALSE, "
181 "rate = (int) [ 1, MAX ], "
182 "channels = (int) [ 1, 16 ];"
184 "rate = (int) [ 1, MAX], "
185 "channels = (int) [ 1, 16 ];"
187 "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 16 ]")
190 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
192 gst_element_class_set_details_simple (element_class,
193 "PulseAudio Audio Source",
195 "Captures audio from a PulseAudio server", "Lennart Poettering");
196 gst_element_class_add_pad_template (element_class,
197 gst_static_pad_template_get (&pad_template));
201 gst_pulsesrc_class_init (gpointer g_class, gpointer class_data)
204 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
206 GstAudioSrcClass *gstaudiosrc_class = GST_AUDIO_SRC_CLASS (g_class);
208 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
210 parent_class = g_type_class_peek_parent (g_class);
212 gstelement_class->change_state =
213 GST_DEBUG_FUNCPTR (gst_pulsesrc_change_state);
215 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pulsesrc_dispose);
216 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pulsesrc_finalize);
217 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pulsesrc_set_property);
218 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_pulsesrc_get_property);
220 gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_pulsesrc_open);
221 gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_pulsesrc_close);
222 gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_prepare);
223 gstaudiosrc_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesrc_unprepare);
224 gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_pulsesrc_read);
225 gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesrc_delay);
227 /* Overwrite GObject fields */
228 g_object_class_install_property (gobject_class,
230 g_param_spec_string ("server", "Server",
231 "The PulseAudio server to connect to", NULL,
232 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
233 g_object_class_install_property (gobject_class, PROP_DEVICE,
234 g_param_spec_string ("device", "Source",
235 "The PulseAudio source device to connect to", NULL,
236 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
238 g_object_class_install_property (gobject_class,
240 g_param_spec_string ("device-name", "Device name",
241 "Human-readable name of the sound device", NULL,
242 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
246 gst_pulsesrc_init (GTypeInstance * instance, gpointer g_class)
249 GstPulseSrc *pulsesrc = GST_PULSESRC (instance);
253 pulsesrc->server = pulsesrc->device = NULL;
255 pulsesrc->context = NULL;
256 pulsesrc->stream = NULL;
258 pulsesrc->read_buffer = NULL;
259 pulsesrc->read_buffer_length = 0;
261 pulsesrc->mainloop = pa_threaded_mainloop_new ();
262 g_assert (pulsesrc->mainloop);
264 e = pa_threaded_mainloop_start (pulsesrc->mainloop);
267 pulsesrc->mixer = NULL;
269 pulsesrc->probe = gst_pulseprobe_new (G_OBJECT (pulsesrc), G_OBJECT_GET_CLASS (pulsesrc), PROP_DEVICE, pulsesrc->device, FALSE, TRUE); /* FALSE for sinks, TRUE for sources */
273 gst_pulsesrc_destroy_stream (GstPulseSrc * pulsesrc)
275 if (pulsesrc->stream) {
276 pa_stream_disconnect (pulsesrc->stream);
277 pa_stream_unref (pulsesrc->stream);
278 pulsesrc->stream = NULL;
283 gst_pulsesrc_destroy_context (GstPulseSrc * pulsesrc)
286 gst_pulsesrc_destroy_stream (pulsesrc);
288 if (pulsesrc->context) {
289 pa_context_disconnect (pulsesrc->context);
290 pa_context_unref (pulsesrc->context);
291 pulsesrc->context = NULL;
296 gst_pulsesrc_finalize (GObject * object)
298 GstPulseSrc *pulsesrc = GST_PULSESRC (object);
300 pa_threaded_mainloop_stop (pulsesrc->mainloop);
302 gst_pulsesrc_destroy_context (pulsesrc);
304 g_free (pulsesrc->server);
305 g_free (pulsesrc->device);
307 pa_threaded_mainloop_free (pulsesrc->mainloop);
310 gst_pulsemixer_ctrl_free (pulsesrc->mixer);
312 if (pulsesrc->probe) {
313 gst_pulseprobe_free (pulsesrc->probe);
314 pulsesrc->probe = NULL;
317 G_OBJECT_CLASS (parent_class)->finalize (object);
321 gst_pulsesrc_dispose (GObject * object)
323 G_OBJECT_CLASS (parent_class)->dispose (object);
327 gst_pulsesrc_set_property (GObject * object,
328 guint prop_id, const GValue * value, GParamSpec * pspec)
331 GstPulseSrc *pulsesrc = GST_PULSESRC (object);
335 g_free (pulsesrc->server);
336 pulsesrc->server = g_value_dup_string (value);
339 gst_pulseprobe_set_server (pulsesrc->probe, pulsesrc->server);
344 g_free (pulsesrc->device);
345 pulsesrc->device = g_value_dup_string (value);
349 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
355 gst_pulsesrc_get_property (GObject * object,
356 guint prop_id, GValue * value, GParamSpec * pspec)
359 GstPulseSrc *pulsesrc = GST_PULSESRC (object);
363 g_value_set_string (value, pulsesrc->server);
367 g_value_set_string (value, pulsesrc->device);
370 case PROP_DEVICE_NAME:
373 g_value_set_string (value, pulsesrc->mixer->description);
375 g_value_set_string (value, NULL);
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
386 gst_pulsesrc_context_state_cb (pa_context * c, void *userdata)
388 GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
390 switch (pa_context_get_state (c)) {
391 case PA_CONTEXT_READY:
392 case PA_CONTEXT_TERMINATED:
393 case PA_CONTEXT_FAILED:
394 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
397 case PA_CONTEXT_UNCONNECTED:
398 case PA_CONTEXT_CONNECTING:
399 case PA_CONTEXT_AUTHORIZING:
400 case PA_CONTEXT_SETTING_NAME:
406 gst_pulsesrc_stream_state_cb (pa_stream * s, void *userdata)
408 GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
410 switch (pa_stream_get_state (s)) {
412 case PA_STREAM_READY:
413 case PA_STREAM_FAILED:
414 case PA_STREAM_TERMINATED:
415 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
418 case PA_STREAM_UNCONNECTED:
419 case PA_STREAM_CREATING:
425 gst_pulsesrc_stream_request_cb (pa_stream * s, size_t length, void *userdata)
427 GstPulseSrc *pulsesrc = GST_PULSESRC (userdata);
429 pa_threaded_mainloop_signal (pulsesrc->mainloop, 0);
433 gst_pulsesrc_open (GstAudioSrc * asrc)
435 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
437 gchar *name = gst_pulse_client_name ();
439 pa_threaded_mainloop_lock (pulsesrc->mainloop);
441 if (!(pulsesrc->context =
442 pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop),
444 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"),
446 goto unlock_and_fail;
449 pa_context_set_state_callback (pulsesrc->context,
450 gst_pulsesrc_context_state_cb, pulsesrc);
452 if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) {
453 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
454 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
455 goto unlock_and_fail;
458 /* Wait until the context is ready */
459 pa_threaded_mainloop_wait (pulsesrc->mainloop);
461 if (pa_context_get_state (pulsesrc->context) != PA_CONTEXT_READY) {
462 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s",
463 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
464 goto unlock_and_fail;
467 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
474 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
481 gst_pulsesrc_close (GstAudioSrc * asrc)
483 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
485 pa_threaded_mainloop_lock (pulsesrc->mainloop);
486 gst_pulsesrc_destroy_context (pulsesrc);
487 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
493 gst_pulsesrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec)
495 pa_buffer_attr buf_attr;
497 pa_channel_map channel_map;
499 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
501 if (!gst_pulse_fill_sample_spec (spec, &pulsesrc->sample_spec)) {
502 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, SETTINGS,
503 ("Invalid sample specification."), (NULL));
504 goto unlock_and_fail;
507 pa_threaded_mainloop_lock (pulsesrc->mainloop);
509 if (!pulsesrc->context
510 || pa_context_get_state (pulsesrc->context) != PA_CONTEXT_READY) {
511 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Bad context state: %s",
513 context ? pa_strerror (pa_context_errno (pulsesrc->context)) :
515 goto unlock_and_fail;
518 if (!(pulsesrc->stream = pa_stream_new (pulsesrc->context,
520 &pulsesrc->sample_spec,
521 gst_pulse_gst_to_channel_map (&channel_map, spec)))) {
522 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
523 ("Failed to create stream: %s",
524 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
525 goto unlock_and_fail;
528 pa_stream_set_state_callback (pulsesrc->stream, gst_pulsesrc_stream_state_cb,
530 pa_stream_set_read_callback (pulsesrc->stream, gst_pulsesrc_stream_request_cb,
533 memset (&buf_attr, 0, sizeof (buf_attr));
534 buf_attr.maxlength = spec->segtotal * spec->segsize * 2;
535 buf_attr.fragsize = spec->segsize;
537 if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &buf_attr,
538 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
539 PA_STREAM_NOT_MONOTONOUS) < 0) {
540 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
541 ("Failed to connect stream: %s",
542 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
543 goto unlock_and_fail;
546 /* Wait until the stream is ready */
547 pa_threaded_mainloop_wait (pulsesrc->mainloop);
549 if (pa_stream_get_state (pulsesrc->stream) != PA_STREAM_READY) {
550 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
551 ("Failed to connect stream: %s",
552 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
553 goto unlock_and_fail;
556 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
562 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
567 gst_pulsesrc_unprepare (GstAudioSrc * asrc)
569 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
571 pa_threaded_mainloop_lock (pulsesrc->mainloop);
572 gst_pulsesrc_destroy_stream (pulsesrc);
574 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
576 pulsesrc->read_buffer = NULL;
577 pulsesrc->read_buffer_length = 0;
582 #define CHECK_DEAD_GOTO(pulsesrc, label) \
583 if (!(pulsesrc)->context || pa_context_get_state((pulsesrc)->context) != PA_CONTEXT_READY || \
584 !(pulsesrc)->stream || pa_stream_get_state((pulsesrc)->stream) != PA_STREAM_READY) { \
585 GST_ELEMENT_ERROR((pulsesrc), RESOURCE, FAILED, ("Disconnected: %s", (pulsesrc)->context ? pa_strerror(pa_context_errno((pulsesrc)->context)) : NULL), (NULL)); \
590 gst_pulsesrc_read (GstAudioSrc * asrc, gpointer data, guint length)
592 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
596 pa_threaded_mainloop_lock (pulsesrc->mainloop);
598 CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
603 if (!pulsesrc->read_buffer) {
606 if (pa_stream_peek (pulsesrc->stream, &pulsesrc->read_buffer,
607 &pulsesrc->read_buffer_length) < 0) {
608 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
609 ("pa_stream_peek() failed: %s",
610 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
611 goto unlock_and_fail;
614 if (pulsesrc->read_buffer)
617 pa_threaded_mainloop_wait (pulsesrc->mainloop);
619 CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
623 g_assert (pulsesrc->read_buffer && pulsesrc->read_buffer_length);
625 l = pulsesrc->read_buffer_length >
626 length ? length : pulsesrc->read_buffer_length;
628 memcpy (data, pulsesrc->read_buffer, l);
630 pulsesrc->read_buffer = (const guint8 *) pulsesrc->read_buffer + l;
631 pulsesrc->read_buffer_length -= l;
633 data = (guint8 *) data + l;
638 if (pulsesrc->read_buffer_length <= 0) {
640 if (pa_stream_drop (pulsesrc->stream) < 0) {
641 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
642 ("pa_stream_drop() failed: %s",
643 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
644 goto unlock_and_fail;
647 pulsesrc->read_buffer = NULL;
648 pulsesrc->read_buffer_length = 0;
652 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
657 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
662 gst_pulsesrc_delay (GstAudioSrc * asrc)
664 GstPulseSrc *pulsesrc = GST_PULSESRC (asrc);
670 pa_threaded_mainloop_lock (pulsesrc->mainloop);
672 CHECK_DEAD_GOTO (pulsesrc, unlock_and_fail);
674 if (pa_stream_get_latency (pulsesrc->stream, &t, &negative) < 0) {
676 if (pa_context_errno (pulsesrc->context) != PA_ERR_NODATA) {
677 GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED,
678 ("pa_stream_get_latency() failed: %s",
679 pa_strerror (pa_context_errno (pulsesrc->context))), (NULL));
680 goto unlock_and_fail;
683 GST_WARNING_OBJECT (pulsesrc, "Not data while querying latency");
688 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
690 return (guint) ((t * pulsesrc->sample_spec.rate) / 1000000LL);
694 pa_threaded_mainloop_unlock (pulsesrc->mainloop);
698 static GstStateChangeReturn
699 gst_pulsesrc_change_state (GstElement * element, GstStateChange transition)
701 GstPulseSrc *this = GST_PULSESRC (element);
703 switch (transition) {
704 case GST_STATE_CHANGE_NULL_TO_READY:
708 gst_pulsemixer_ctrl_new (G_OBJECT (this), this->server,
709 this->device, GST_PULSEMIXER_SOURCE);
713 case GST_STATE_CHANGE_READY_TO_NULL:
716 gst_pulsemixer_ctrl_free (this->mixer);
726 if (GST_ELEMENT_CLASS (parent_class)->change_state)
727 return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
729 return GST_STATE_CHANGE_SUCCESS;
733 gst_pulsesrc_get_type (void)
735 static GType pulsesrc_type = 0;
737 if (!pulsesrc_type) {
739 static const GTypeInfo pulsesrc_info = {
740 sizeof (GstPulseSrcClass),
741 gst_pulsesrc_base_init,
743 gst_pulsesrc_class_init,
746 sizeof (GstPulseSrc),
751 pulsesrc_type = g_type_register_static (GST_TYPE_AUDIO_SRC,
752 "GstPulseSrc", &pulsesrc_info, 0);
754 gst_pulsesrc_init_interfaces (pulsesrc_type);
757 return pulsesrc_type;