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
29 #include <gst/base/gstbasesink.h>
30 #include <gst/gsttaglist.h>
32 #include "pulsesink.h"
33 #include "pulseutil.h"
35 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
36 #define GST_CAT_DEFAULT pulse_debug
44 static GstAudioSinkClass *parent_class = NULL;
46 static void gst_pulsesink_destroy_stream (GstPulseSink * pulsesink);
48 static void gst_pulsesink_destroy_context (GstPulseSink * pulsesink);
50 static void gst_pulsesink_set_property (GObject * object, guint prop_id,
51 const GValue * value, GParamSpec * pspec);
52 static void gst_pulsesink_get_property (GObject * object, guint prop_id,
53 GValue * value, GParamSpec * pspec);
54 static void gst_pulsesink_finalize (GObject * object);
56 static void gst_pulsesink_dispose (GObject * object);
58 static gboolean gst_pulsesink_open (GstAudioSink * asink);
60 static gboolean gst_pulsesink_close (GstAudioSink * asink);
62 static gboolean gst_pulsesink_prepare (GstAudioSink * asink,
63 GstRingBufferSpec * spec);
64 static gboolean gst_pulsesink_unprepare (GstAudioSink * asink);
66 static guint gst_pulsesink_write (GstAudioSink * asink, gpointer data,
68 static guint gst_pulsesink_delay (GstAudioSink * asink);
70 static void gst_pulsesink_reset (GstAudioSink * asink);
72 static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event);
74 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
75 # define ENDIANNESS "LITTLE_ENDIAN, BIG_ENDIAN"
77 # define ENDIANNESS "BIG_ENDIAN, LITTLE_ENDIAN"
81 gst_pulsesink_base_init (gpointer g_class)
84 static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
87 GST_STATIC_CAPS ("audio/x-raw-int, "
88 "endianness = (int) { " ENDIANNESS " }, "
89 "signed = (boolean) TRUE, "
92 "rate = (int) [ 1, MAX ], "
93 "channels = (int) [ 1, 16 ];"
95 "endianness = (int) { " ENDIANNESS " }, "
97 "rate = (int) [ 1, MAX ], "
98 "channels = (int) [ 1, 16 ];"
100 "endianness = (int) { " ENDIANNESS " }, "
101 "signed = (boolean) TRUE, "
104 "rate = (int) [ 1, MAX ], "
105 "channels = (int) [ 1, 16 ];"
107 "signed = (boolean) FALSE, "
110 "rate = (int) [ 1, MAX ], "
111 "channels = (int) [ 1, 16 ];"
113 "rate = (int) [ 1, MAX], "
114 "channels = (int) [ 1, 16 ];"
116 "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 16 ]")
119 static const GstElementDetails details =
120 GST_ELEMENT_DETAILS ("PulseAudio Audio Sink",
122 "Plays audio to a PulseAudio server",
123 "Lennart Poettering");
125 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
127 gst_element_class_set_details (element_class, &details);
128 gst_element_class_add_pad_template (element_class,
129 gst_static_pad_template_get (&pad_template));
133 gst_pulsesink_class_init (gpointer g_class, gpointer class_data)
136 GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
138 GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (g_class);
140 GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (g_class);
142 parent_class = g_type_class_peek_parent (g_class);
144 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pulsesink_dispose);
145 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pulsesink_finalize);
146 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pulsesink_set_property);
147 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_pulsesink_get_property);
149 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_pulsesink_event);
151 gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_pulsesink_open);
152 gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_pulsesink_close);
153 gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesink_prepare);
154 gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesink_unprepare);
155 gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_pulsesink_write);
156 gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesink_delay);
157 gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesink_reset);
159 /* Overwrite GObject fields */
160 g_object_class_install_property (gobject_class,
162 g_param_spec_string ("server", "Server",
163 "The PulseAudio server to connect to", NULL, G_PARAM_READWRITE));
164 g_object_class_install_property (gobject_class, PROP_DEVICE,
165 g_param_spec_string ("device", "Sink",
166 "The PulseAudio sink device to connect to", NULL, G_PARAM_READWRITE));
170 gst_pulsesink_init (GTypeInstance * instance, gpointer g_class)
173 GstPulseSink *pulsesink = GST_PULSESINK (instance);
177 pulsesink->server = pulsesink->device = pulsesink->stream_name = NULL;
179 pulsesink->context = NULL;
180 pulsesink->stream = NULL;
182 pulsesink->mainloop = pa_threaded_mainloop_new ();
183 g_assert (pulsesink->mainloop);
185 e = pa_threaded_mainloop_start (pulsesink->mainloop);
190 gst_pulsesink_destroy_stream (GstPulseSink * pulsesink)
192 if (pulsesink->stream) {
193 pa_stream_disconnect (pulsesink->stream);
194 pa_stream_unref (pulsesink->stream);
195 pulsesink->stream = NULL;
198 g_free (pulsesink->stream_name);
199 pulsesink->stream_name = NULL;
203 gst_pulsesink_destroy_context (GstPulseSink * pulsesink)
206 gst_pulsesink_destroy_stream (pulsesink);
208 if (pulsesink->context) {
209 pa_context_disconnect (pulsesink->context);
210 pa_context_unref (pulsesink->context);
211 pulsesink->context = NULL;
216 gst_pulsesink_finalize (GObject * object)
218 GstPulseSink *pulsesink = GST_PULSESINK (object);
220 pa_threaded_mainloop_stop (pulsesink->mainloop);
222 gst_pulsesink_destroy_context (pulsesink);
224 g_free (pulsesink->server);
225 g_free (pulsesink->device);
226 g_free (pulsesink->stream_name);
228 pa_threaded_mainloop_free (pulsesink->mainloop);
230 G_OBJECT_CLASS (parent_class)->finalize (object);
234 gst_pulsesink_dispose (GObject * object)
236 G_OBJECT_CLASS (parent_class)->dispose (object);
240 gst_pulsesink_set_property (GObject * object,
241 guint prop_id, const GValue * value, GParamSpec * pspec)
243 GstPulseSink *pulsesink = GST_PULSESINK (object);
247 g_free (pulsesink->server);
248 pulsesink->server = g_value_dup_string (value);
252 g_free (pulsesink->device);
253 pulsesink->device = g_value_dup_string (value);
257 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
263 gst_pulsesink_get_property (GObject * object,
264 guint prop_id, GValue * value, GParamSpec * pspec)
267 GstPulseSink *pulsesink = GST_PULSESINK (object);
271 g_value_set_string (value, pulsesink->server);
275 g_value_set_string (value, pulsesink->device);
279 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
285 gst_pulsesink_context_state_cb (pa_context * c, void *userdata)
287 GstPulseSink *pulsesink = GST_PULSESINK (userdata);
289 switch (pa_context_get_state (c)) {
290 case PA_CONTEXT_READY:
291 case PA_CONTEXT_TERMINATED:
292 case PA_CONTEXT_FAILED:
293 pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
296 case PA_CONTEXT_UNCONNECTED:
297 case PA_CONTEXT_CONNECTING:
298 case PA_CONTEXT_AUTHORIZING:
299 case PA_CONTEXT_SETTING_NAME:
305 gst_pulsesink_stream_state_cb (pa_stream * s, void *userdata)
307 GstPulseSink *pulsesink = GST_PULSESINK (userdata);
309 switch (pa_stream_get_state (s)) {
311 case PA_STREAM_READY:
312 case PA_STREAM_FAILED:
313 case PA_STREAM_TERMINATED:
314 pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
317 case PA_STREAM_UNCONNECTED:
318 case PA_STREAM_CREATING:
324 gst_pulsesink_stream_request_cb (pa_stream * s, size_t length, void *userdata)
326 GstPulseSink *pulsesink = GST_PULSESINK (userdata);
328 pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
332 gst_pulsesink_stream_latency_update_cb (pa_stream * s, void *userdata)
334 GstPulseSink *pulsesink = GST_PULSESINK (userdata);
336 pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
340 gst_pulsesink_open (GstAudioSink * asink)
342 GstPulseSink *pulsesink = GST_PULSESINK (asink);
344 gchar *name = gst_pulse_client_name ();
346 pa_threaded_mainloop_lock (pulsesink->mainloop);
348 if (!(pulsesink->context =
349 pa_context_new (pa_threaded_mainloop_get_api (pulsesink->mainloop),
351 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
352 ("Failed to create context"), (NULL));
353 goto unlock_and_fail;
356 pa_context_set_state_callback (pulsesink->context,
357 gst_pulsesink_context_state_cb, pulsesink);
359 if (pa_context_connect (pulsesink->context, pulsesink->server, 0, NULL) < 0) {
360 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Failed to connect: %s",
361 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
362 goto unlock_and_fail;
365 /* Wait until the context is ready */
366 pa_threaded_mainloop_wait (pulsesink->mainloop);
368 if (pa_context_get_state (pulsesink->context) != PA_CONTEXT_READY) {
369 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Failed to connect: %s",
370 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
371 goto unlock_and_fail;
374 pa_threaded_mainloop_unlock (pulsesink->mainloop);
380 pa_threaded_mainloop_unlock (pulsesink->mainloop);
386 gst_pulsesink_close (GstAudioSink * asink)
388 GstPulseSink *pulsesink = GST_PULSESINK (asink);
390 pa_threaded_mainloop_lock (pulsesink->mainloop);
391 gst_pulsesink_destroy_context (pulsesink);
392 pa_threaded_mainloop_unlock (pulsesink->mainloop);
398 gst_pulsesink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
400 pa_buffer_attr buf_attr;
402 pa_channel_map channel_map;
404 GstPulseSink *pulsesink = GST_PULSESINK (asink);
406 if (!gst_pulse_fill_sample_spec (spec, &pulsesink->sample_spec)) {
407 GST_ELEMENT_ERROR (pulsesink, RESOURCE, SETTINGS,
408 ("Invalid sample specification."), (NULL));
409 goto unlock_and_fail;
412 pa_threaded_mainloop_lock (pulsesink->mainloop);
414 if (!pulsesink->context
415 || pa_context_get_state (pulsesink->context) != PA_CONTEXT_READY) {
416 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Bad context state: %s",
417 pulsesink->context ? pa_strerror (pa_context_errno (pulsesink->
418 context)) : NULL), (NULL));
419 goto unlock_and_fail;
422 if (!(pulsesink->stream = pa_stream_new (pulsesink->context,
423 pulsesink->stream_name ? pulsesink->
424 stream_name : "Playback Stream", &pulsesink->sample_spec,
425 gst_pulse_gst_to_channel_map (&channel_map, spec)))) {
426 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
427 ("Failed to create stream: %s",
428 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
429 goto unlock_and_fail;
432 pa_stream_set_state_callback (pulsesink->stream,
433 gst_pulsesink_stream_state_cb, pulsesink);
434 pa_stream_set_write_callback (pulsesink->stream,
435 gst_pulsesink_stream_request_cb, pulsesink);
436 pa_stream_set_latency_update_callback (pulsesink->stream,
437 gst_pulsesink_stream_latency_update_cb, pulsesink);
439 memset (&buf_attr, 0, sizeof (buf_attr));
440 buf_attr.tlength = spec->segtotal * spec->segsize;
441 buf_attr.maxlength = buf_attr.tlength * 2;
442 buf_attr.prebuf = buf_attr.tlength - spec->segsize;
443 buf_attr.minreq = spec->segsize;
445 if (pa_stream_connect_playback (pulsesink->stream, pulsesink->device,
447 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
448 PA_STREAM_NOT_MONOTONOUS, NULL, NULL) < 0) {
449 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
450 ("Failed to connect stream: %s",
451 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
452 goto unlock_and_fail;
455 /* Wait until the stream is ready */
456 pa_threaded_mainloop_wait (pulsesink->mainloop);
458 if (pa_stream_get_state (pulsesink->stream) != PA_STREAM_READY) {
459 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
460 ("Failed to connect stream: %s",
461 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
462 goto unlock_and_fail;
465 pa_threaded_mainloop_unlock (pulsesink->mainloop);
467 spec->bytes_per_sample = pa_frame_size (&pulsesink->sample_spec);
468 memset (spec->silence_sample, 0, spec->bytes_per_sample);
474 pa_threaded_mainloop_unlock (pulsesink->mainloop);
479 gst_pulsesink_unprepare (GstAudioSink * asink)
481 GstPulseSink *pulsesink = GST_PULSESINK (asink);
483 pa_threaded_mainloop_lock (pulsesink->mainloop);
484 gst_pulsesink_destroy_stream (pulsesink);
485 pa_threaded_mainloop_unlock (pulsesink->mainloop);
490 #define CHECK_DEAD_GOTO(pulsesink, label) \
491 if (!(pulsesink)->context || pa_context_get_state((pulsesink)->context) != PA_CONTEXT_READY || \
492 !(pulsesink)->stream || pa_stream_get_state((pulsesink)->stream) != PA_STREAM_READY) { \
493 GST_ELEMENT_ERROR((pulsesink), RESOURCE, FAILED, ("Disconnected: %s", (pulsesink)->context ? pa_strerror(pa_context_errno((pulsesink)->context)) : NULL), (NULL)); \
498 gst_pulsesink_write (GstAudioSink * asink, gpointer data, guint length)
500 GstPulseSink *pulsesink = GST_PULSESINK (asink);
504 pa_threaded_mainloop_lock (pulsesink->mainloop);
510 CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
512 if ((l = pa_stream_writable_size (pulsesink->stream)) == (size_t) - 1) {
513 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
514 ("pa_stream_writable_size() failed: %s",
515 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
516 goto unlock_and_fail;
522 pa_threaded_mainloop_wait (pulsesink->mainloop);
528 if (pa_stream_write (pulsesink->stream, data, l, NULL, 0,
529 PA_SEEK_RELATIVE) < 0) {
530 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
531 ("pa_stream_write() failed: %s",
532 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
533 goto unlock_and_fail;
536 data = (guint8 *) data + l;
542 pa_threaded_mainloop_unlock (pulsesink->mainloop);
548 pa_threaded_mainloop_unlock (pulsesink->mainloop);
553 gst_pulsesink_delay (GstAudioSink * asink)
555 GstPulseSink *pulsesink = GST_PULSESINK (asink);
559 pa_threaded_mainloop_lock (pulsesink->mainloop);
562 CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
564 if (pa_stream_get_latency (pulsesink->stream, &t, NULL) >= 0)
567 if (pa_context_errno (pulsesink->context) != PA_ERR_NODATA) {
568 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
569 ("pa_stream_get_latency() failed: %s",
570 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
571 goto unlock_and_fail;
574 pa_threaded_mainloop_wait (pulsesink->mainloop);
577 pa_threaded_mainloop_unlock (pulsesink->mainloop);
579 return gst_util_uint64_scale_int (t, pulsesink->sample_spec.rate, 1000000LL);
583 pa_threaded_mainloop_unlock (pulsesink->mainloop);
588 gst_pulsesink_success_cb (pa_stream * s, int success, void *userdata)
590 GstPulseSink *pulsesink = GST_PULSESINK (userdata);
592 pulsesink->operation_success = success;
593 pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
597 gst_pulsesink_reset (GstAudioSink * asink)
599 GstPulseSink *pulsesink = GST_PULSESINK (asink);
601 pa_operation *o = NULL;
603 pa_threaded_mainloop_lock (pulsesink->mainloop);
605 CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
608 pa_stream_flush (pulsesink->stream, gst_pulsesink_success_cb,
610 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
611 ("pa_stream_flush() failed: %s",
612 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
613 goto unlock_and_fail;
616 pulsesink->operation_success = 0;
617 while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
618 CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
620 pa_threaded_mainloop_wait (pulsesink->mainloop);
623 if (!pulsesink->operation_success) {
624 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Flush failed: %s",
625 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
626 goto unlock_and_fail;
632 pa_operation_cancel (o);
633 pa_operation_unref (o);
636 pa_threaded_mainloop_unlock (pulsesink->mainloop);
640 gst_pulsesink_change_title (GstPulseSink * pulsesink, const gchar * t)
642 pa_operation *o = NULL;
644 pa_threaded_mainloop_lock (pulsesink->mainloop);
646 g_free (pulsesink->stream_name);
647 pulsesink->stream_name = g_strdup (t);
649 if (!(pulsesink)->context
650 || pa_context_get_state ((pulsesink)->context) != PA_CONTEXT_READY
651 || !(pulsesink)->stream
652 || pa_stream_get_state ((pulsesink)->stream) != PA_STREAM_READY) {
653 goto unlock_and_fail;
657 pa_stream_set_name (pulsesink->stream, pulsesink->stream_name, NULL,
659 GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
660 ("pa_stream_set_name() failed: %s",
661 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
662 goto unlock_and_fail;
665 /* We're not interested if this operation failed or not */
670 pa_operation_unref (o);
672 pa_threaded_mainloop_unlock (pulsesink->mainloop);
676 gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
678 GstPulseSink *pulsesink = GST_PULSESINK (sink);
680 switch (GST_EVENT_TYPE (event)) {
682 gchar *title = NULL, *artist = NULL, *location = NULL, *description =
683 NULL, *t = NULL, *buf = NULL;
686 gst_event_parse_tag (event, &l);
688 gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
689 gst_tag_list_get_string (l, GST_TAG_ARTIST, &artist);
690 gst_tag_list_get_string (l, GST_TAG_LOCATION, &location);
691 gst_tag_list_get_string (l, GST_TAG_DESCRIPTION, &description);
695 g_strdup_printf ("'%s' by '%s'", g_strstrip (title),
696 g_strstrip (artist));
698 t = g_strstrip (title);
699 else if (description)
700 t = g_strstrip (description);
702 t = g_strstrip (location);
705 gst_pulsesink_change_title (pulsesink, t);
710 g_free (description);
719 return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
723 gst_pulsesink_get_type (void)
725 static GType pulsesink_type = 0;
727 if (!pulsesink_type) {
729 static const GTypeInfo pulsesink_info = {
730 sizeof (GstPulseSinkClass),
731 gst_pulsesink_base_init,
733 gst_pulsesink_class_init,
736 sizeof (GstPulseSink),
741 pulsesink_type = g_type_register_static (GST_TYPE_AUDIO_SINK,
742 "GstPulseSink", &pulsesink_info, 0);
745 return pulsesink_type;