Add documentation to the pulseaudio plugin and run make update in docs/plugins.
[platform/upstream/gstreamer.git] / ext / pulse / pulsesink.c
1 /*
2  *  GStreamer pulseaudio plugin
3  *
4  *  Copyright (c) 2004-2008 Lennart Poettering
5  *
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.
10  *
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.
15  *
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
19  *  USA.
20  */
21
22 /**
23  * SECTION:element-pulsesink
24  * @short_description: Output audio to a PulseAudio sound server
25  * @see_also: pulsesrc, pulsemixer
26  *
27  * <refsect2>
28  * <para>
29  * This element outputs audio to a PulseAudio sound server.
30  * </para>
31  * <title>Example pipelines</title>
32  * <para>
33  * <programlisting>
34  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! audioconvert ! audioresample ! pulsesink
35  * </programlisting>
36  * Play an Ogg/Vorbis file.
37  * </para>
38  * <para>
39  * <programlisting>
40  * gst-launch -v audiotestsrc ! audioconvert ! volume volume=0.4 ! pulsesink
41  * </programlisting>
42  * Play a 440Hz sine wave.
43  * </para>
44  * </refsect2>
45  *
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #include <string.h>
53 #include <stdio.h>
54
55 #include <gst/base/gstbasesink.h>
56 #include <gst/gsttaglist.h>
57
58 #include "pulsesink.h"
59 #include "pulseutil.h"
60
61 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
62 #define GST_CAT_DEFAULT pulse_debug
63
64 enum
65 {
66   PROP_SERVER = 1,
67   PROP_DEVICE,
68 };
69
70 static GstAudioSinkClass *parent_class = NULL;
71
72 static void gst_pulsesink_destroy_stream (GstPulseSink * pulsesink);
73
74 static void gst_pulsesink_destroy_context (GstPulseSink * pulsesink);
75
76 static void gst_pulsesink_set_property (GObject * object, guint prop_id,
77     const GValue * value, GParamSpec * pspec);
78 static void gst_pulsesink_get_property (GObject * object, guint prop_id,
79     GValue * value, GParamSpec * pspec);
80 static void gst_pulsesink_finalize (GObject * object);
81
82 static void gst_pulsesink_dispose (GObject * object);
83
84 static gboolean gst_pulsesink_open (GstAudioSink * asink);
85
86 static gboolean gst_pulsesink_close (GstAudioSink * asink);
87
88 static gboolean gst_pulsesink_prepare (GstAudioSink * asink,
89     GstRingBufferSpec * spec);
90 static gboolean gst_pulsesink_unprepare (GstAudioSink * asink);
91
92 static guint gst_pulsesink_write (GstAudioSink * asink, gpointer data,
93     guint length);
94 static guint gst_pulsesink_delay (GstAudioSink * asink);
95
96 static void gst_pulsesink_reset (GstAudioSink * asink);
97
98 static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event);
99
100 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
101 # define ENDIANNESS   "LITTLE_ENDIAN, BIG_ENDIAN"
102 #else
103 # define ENDIANNESS   "BIG_ENDIAN, LITTLE_ENDIAN"
104 #endif
105
106 static void
107 gst_pulsesink_base_init (gpointer g_class)
108 {
109
110   static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
111       GST_PAD_SINK,
112       GST_PAD_ALWAYS,
113       GST_STATIC_CAPS ("audio/x-raw-int, "
114           "endianness = (int) { " ENDIANNESS " }, "
115           "signed = (boolean) TRUE, "
116           "width = (int) 16, "
117           "depth = (int) 16, "
118           "rate = (int) [ 1, MAX ], "
119           "channels = (int) [ 1, 16 ];"
120           "audio/x-raw-float, "
121           "endianness = (int) { " ENDIANNESS " }, "
122           "width = (int) 32, "
123           "rate = (int) [ 1, MAX ], "
124           "channels = (int) [ 1, 16 ];"
125           "audio/x-raw-int, "
126           "endianness = (int) { " ENDIANNESS " }, "
127           "signed = (boolean) TRUE, "
128           "width = (int) 32, "
129           "depth = (int) 32, "
130           "rate = (int) [ 1, MAX ], "
131           "channels = (int) [ 1, 16 ];"
132           "audio/x-raw-int, "
133           "signed = (boolean) FALSE, "
134           "width = (int) 8, "
135           "depth = (int) 8, "
136           "rate = (int) [ 1, MAX ], "
137           "channels = (int) [ 1, 16 ];"
138           "audio/x-alaw, "
139           "rate = (int) [ 1, MAX], "
140           "channels = (int) [ 1, 16 ];"
141           "audio/x-mulaw, "
142           "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 16 ]")
143       );
144
145   static const GstElementDetails details =
146       GST_ELEMENT_DETAILS ("PulseAudio Audio Sink",
147       "Sink/Audio",
148       "Plays audio to a PulseAudio server",
149       "Lennart Poettering");
150
151   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
152
153   gst_element_class_set_details (element_class, &details);
154   gst_element_class_add_pad_template (element_class,
155       gst_static_pad_template_get (&pad_template));
156 }
157
158 static void
159 gst_pulsesink_class_init (gpointer g_class, gpointer class_data)
160 {
161
162   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
163
164   GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (g_class);
165
166   GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (g_class);
167
168   parent_class = g_type_class_peek_parent (g_class);
169
170   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_pulsesink_dispose);
171   gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pulsesink_finalize);
172   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_pulsesink_set_property);
173   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_pulsesink_get_property);
174
175   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_pulsesink_event);
176
177   gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_pulsesink_open);
178   gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_pulsesink_close);
179   gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_pulsesink_prepare);
180   gstaudiosink_class->unprepare = GST_DEBUG_FUNCPTR (gst_pulsesink_unprepare);
181   gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_pulsesink_write);
182   gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_pulsesink_delay);
183   gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_pulsesink_reset);
184
185   /* Overwrite GObject fields */
186   g_object_class_install_property (gobject_class,
187       PROP_SERVER,
188       g_param_spec_string ("server", "Server",
189           "The PulseAudio server to connect to", NULL, G_PARAM_READWRITE));
190   g_object_class_install_property (gobject_class, PROP_DEVICE,
191       g_param_spec_string ("device", "Sink",
192           "The PulseAudio sink device to connect to", NULL, G_PARAM_READWRITE));
193 }
194
195 static void
196 gst_pulsesink_init (GTypeInstance * instance, gpointer g_class)
197 {
198
199   GstPulseSink *pulsesink = GST_PULSESINK (instance);
200
201   int e;
202
203   pulsesink->server = pulsesink->device = pulsesink->stream_name = NULL;
204
205   pulsesink->context = NULL;
206   pulsesink->stream = NULL;
207
208   pulsesink->mainloop = pa_threaded_mainloop_new ();
209   g_assert (pulsesink->mainloop);
210
211   e = pa_threaded_mainloop_start (pulsesink->mainloop);
212   g_assert (e == 0);
213 }
214
215 static void
216 gst_pulsesink_destroy_stream (GstPulseSink * pulsesink)
217 {
218   if (pulsesink->stream) {
219     pa_stream_disconnect (pulsesink->stream);
220     pa_stream_unref (pulsesink->stream);
221     pulsesink->stream = NULL;
222   }
223
224   g_free (pulsesink->stream_name);
225   pulsesink->stream_name = NULL;
226 }
227
228 static void
229 gst_pulsesink_destroy_context (GstPulseSink * pulsesink)
230 {
231
232   gst_pulsesink_destroy_stream (pulsesink);
233
234   if (pulsesink->context) {
235     pa_context_disconnect (pulsesink->context);
236     pa_context_unref (pulsesink->context);
237     pulsesink->context = NULL;
238   }
239 }
240
241 static void
242 gst_pulsesink_finalize (GObject * object)
243 {
244   GstPulseSink *pulsesink = GST_PULSESINK (object);
245
246   pa_threaded_mainloop_stop (pulsesink->mainloop);
247
248   gst_pulsesink_destroy_context (pulsesink);
249
250   g_free (pulsesink->server);
251   g_free (pulsesink->device);
252   g_free (pulsesink->stream_name);
253
254   pa_threaded_mainloop_free (pulsesink->mainloop);
255
256   G_OBJECT_CLASS (parent_class)->finalize (object);
257 }
258
259 static void
260 gst_pulsesink_dispose (GObject * object)
261 {
262   G_OBJECT_CLASS (parent_class)->dispose (object);
263 }
264
265 static void
266 gst_pulsesink_set_property (GObject * object,
267     guint prop_id, const GValue * value, GParamSpec * pspec)
268 {
269   GstPulseSink *pulsesink = GST_PULSESINK (object);
270
271   switch (prop_id) {
272     case PROP_SERVER:
273       g_free (pulsesink->server);
274       pulsesink->server = g_value_dup_string (value);
275       break;
276
277     case PROP_DEVICE:
278       g_free (pulsesink->device);
279       pulsesink->device = g_value_dup_string (value);
280       break;
281
282     default:
283       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
284       break;
285   }
286 }
287
288 static void
289 gst_pulsesink_get_property (GObject * object,
290     guint prop_id, GValue * value, GParamSpec * pspec)
291 {
292
293   GstPulseSink *pulsesink = GST_PULSESINK (object);
294
295   switch (prop_id) {
296     case PROP_SERVER:
297       g_value_set_string (value, pulsesink->server);
298       break;
299
300     case PROP_DEVICE:
301       g_value_set_string (value, pulsesink->device);
302       break;
303
304     default:
305       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
306       break;
307   }
308 }
309
310 static void
311 gst_pulsesink_context_state_cb (pa_context * c, void *userdata)
312 {
313   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
314
315   switch (pa_context_get_state (c)) {
316     case PA_CONTEXT_READY:
317     case PA_CONTEXT_TERMINATED:
318     case PA_CONTEXT_FAILED:
319       pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
320       break;
321
322     case PA_CONTEXT_UNCONNECTED:
323     case PA_CONTEXT_CONNECTING:
324     case PA_CONTEXT_AUTHORIZING:
325     case PA_CONTEXT_SETTING_NAME:
326       break;
327   }
328 }
329
330 static void
331 gst_pulsesink_stream_state_cb (pa_stream * s, void *userdata)
332 {
333   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
334
335   switch (pa_stream_get_state (s)) {
336
337     case PA_STREAM_READY:
338     case PA_STREAM_FAILED:
339     case PA_STREAM_TERMINATED:
340       pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
341       break;
342
343     case PA_STREAM_UNCONNECTED:
344     case PA_STREAM_CREATING:
345       break;
346   }
347 }
348
349 static void
350 gst_pulsesink_stream_request_cb (pa_stream * s, size_t length, void *userdata)
351 {
352   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
353
354   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
355 }
356
357 static void
358 gst_pulsesink_stream_latency_update_cb (pa_stream * s, void *userdata)
359 {
360   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
361
362   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
363 }
364
365 static gboolean
366 gst_pulsesink_open (GstAudioSink * asink)
367 {
368   GstPulseSink *pulsesink = GST_PULSESINK (asink);
369
370   gchar *name = gst_pulse_client_name ();
371
372   pa_threaded_mainloop_lock (pulsesink->mainloop);
373
374   if (!(pulsesink->context =
375           pa_context_new (pa_threaded_mainloop_get_api (pulsesink->mainloop),
376               name))) {
377     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
378         ("Failed to create context"), (NULL));
379     goto unlock_and_fail;
380   }
381
382   pa_context_set_state_callback (pulsesink->context,
383       gst_pulsesink_context_state_cb, pulsesink);
384
385   if (pa_context_connect (pulsesink->context, pulsesink->server, 0, NULL) < 0) {
386     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Failed to connect: %s",
387             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
388     goto unlock_and_fail;
389   }
390
391   /* Wait until the context is ready */
392   pa_threaded_mainloop_wait (pulsesink->mainloop);
393
394   if (pa_context_get_state (pulsesink->context) != PA_CONTEXT_READY) {
395     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Failed to connect: %s",
396             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
397     goto unlock_and_fail;
398   }
399
400   pa_threaded_mainloop_unlock (pulsesink->mainloop);
401   g_free (name);
402   return TRUE;
403
404 unlock_and_fail:
405
406   pa_threaded_mainloop_unlock (pulsesink->mainloop);
407   g_free (name);
408   return FALSE;
409 }
410
411 static gboolean
412 gst_pulsesink_close (GstAudioSink * asink)
413 {
414   GstPulseSink *pulsesink = GST_PULSESINK (asink);
415
416   pa_threaded_mainloop_lock (pulsesink->mainloop);
417   gst_pulsesink_destroy_context (pulsesink);
418   pa_threaded_mainloop_unlock (pulsesink->mainloop);
419
420   return TRUE;
421 }
422
423 static gboolean
424 gst_pulsesink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
425 {
426   pa_buffer_attr buf_attr;
427
428   pa_channel_map channel_map;
429
430   GstPulseSink *pulsesink = GST_PULSESINK (asink);
431
432   if (!gst_pulse_fill_sample_spec (spec, &pulsesink->sample_spec)) {
433     GST_ELEMENT_ERROR (pulsesink, RESOURCE, SETTINGS,
434         ("Invalid sample specification."), (NULL));
435     goto unlock_and_fail;
436   }
437
438   pa_threaded_mainloop_lock (pulsesink->mainloop);
439
440   if (!pulsesink->context
441       || pa_context_get_state (pulsesink->context) != PA_CONTEXT_READY) {
442     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Bad context state: %s",
443             pulsesink->
444             context ? pa_strerror (pa_context_errno (pulsesink->context)) :
445             NULL), (NULL));
446     goto unlock_and_fail;
447   }
448
449   if (!(pulsesink->stream = pa_stream_new (pulsesink->context,
450               pulsesink->
451               stream_name ? pulsesink->stream_name : "Playback Stream",
452               &pulsesink->sample_spec,
453               gst_pulse_gst_to_channel_map (&channel_map, spec)))) {
454     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
455         ("Failed to create stream: %s",
456             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
457     goto unlock_and_fail;
458   }
459
460   pa_stream_set_state_callback (pulsesink->stream,
461       gst_pulsesink_stream_state_cb, pulsesink);
462   pa_stream_set_write_callback (pulsesink->stream,
463       gst_pulsesink_stream_request_cb, pulsesink);
464   pa_stream_set_latency_update_callback (pulsesink->stream,
465       gst_pulsesink_stream_latency_update_cb, pulsesink);
466
467   memset (&buf_attr, 0, sizeof (buf_attr));
468   buf_attr.tlength = spec->segtotal * spec->segsize;
469   buf_attr.maxlength = buf_attr.tlength * 2;
470   buf_attr.prebuf = buf_attr.tlength - spec->segsize;
471   buf_attr.minreq = spec->segsize;
472
473   if (pa_stream_connect_playback (pulsesink->stream, pulsesink->device,
474           &buf_attr,
475           PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE |
476           PA_STREAM_NOT_MONOTONOUS, NULL, NULL) < 0) {
477     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
478         ("Failed to connect stream: %s",
479             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
480     goto unlock_and_fail;
481   }
482
483   /* Wait until the stream is ready */
484   pa_threaded_mainloop_wait (pulsesink->mainloop);
485
486   if (pa_stream_get_state (pulsesink->stream) != PA_STREAM_READY) {
487     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
488         ("Failed to connect stream: %s",
489             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
490     goto unlock_and_fail;
491   }
492
493   pa_threaded_mainloop_unlock (pulsesink->mainloop);
494
495   spec->bytes_per_sample = pa_frame_size (&pulsesink->sample_spec);
496   memset (spec->silence_sample, 0, spec->bytes_per_sample);
497
498   return TRUE;
499
500 unlock_and_fail:
501
502   pa_threaded_mainloop_unlock (pulsesink->mainloop);
503   return FALSE;
504 }
505
506 static gboolean
507 gst_pulsesink_unprepare (GstAudioSink * asink)
508 {
509   GstPulseSink *pulsesink = GST_PULSESINK (asink);
510
511   pa_threaded_mainloop_lock (pulsesink->mainloop);
512   gst_pulsesink_destroy_stream (pulsesink);
513   pa_threaded_mainloop_unlock (pulsesink->mainloop);
514
515   return TRUE;
516 }
517
518 #define CHECK_DEAD_GOTO(pulsesink, label) \
519 if (!(pulsesink)->context || pa_context_get_state((pulsesink)->context) != PA_CONTEXT_READY || \
520     !(pulsesink)->stream || pa_stream_get_state((pulsesink)->stream) != PA_STREAM_READY) { \
521     GST_ELEMENT_ERROR((pulsesink), RESOURCE, FAILED, ("Disconnected: %s", (pulsesink)->context ? pa_strerror(pa_context_errno((pulsesink)->context)) : NULL), (NULL)); \
522     goto label; \
523 }
524
525 static guint
526 gst_pulsesink_write (GstAudioSink * asink, gpointer data, guint length)
527 {
528   GstPulseSink *pulsesink = GST_PULSESINK (asink);
529
530   size_t sum = 0;
531
532   pa_threaded_mainloop_lock (pulsesink->mainloop);
533
534   while (length > 0) {
535     size_t l;
536
537     for (;;) {
538       CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
539
540       if ((l = pa_stream_writable_size (pulsesink->stream)) == (size_t) - 1) {
541         GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
542             ("pa_stream_writable_size() failed: %s",
543                 pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
544         goto unlock_and_fail;
545       }
546
547       if (l > 0)
548         break;
549
550       pa_threaded_mainloop_wait (pulsesink->mainloop);
551     }
552
553     if (l > length)
554       l = length;
555
556     if (pa_stream_write (pulsesink->stream, data, l, NULL, 0,
557             PA_SEEK_RELATIVE) < 0) {
558       GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
559           ("pa_stream_write() failed: %s",
560               pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
561       goto unlock_and_fail;
562     }
563
564     data = (guint8 *) data + l;
565     length -= l;
566
567     sum += l;
568   }
569
570   pa_threaded_mainloop_unlock (pulsesink->mainloop);
571
572   return sum;
573
574 unlock_and_fail:
575
576   pa_threaded_mainloop_unlock (pulsesink->mainloop);
577   return 0;
578 }
579
580 static guint
581 gst_pulsesink_delay (GstAudioSink * asink)
582 {
583   GstPulseSink *pulsesink = GST_PULSESINK (asink);
584
585   pa_usec_t t;
586
587   pa_threaded_mainloop_lock (pulsesink->mainloop);
588
589   for (;;) {
590     CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
591
592     if (pa_stream_get_latency (pulsesink->stream, &t, NULL) >= 0)
593       break;
594
595     if (pa_context_errno (pulsesink->context) != PA_ERR_NODATA) {
596       GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
597           ("pa_stream_get_latency() failed: %s",
598               pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
599       goto unlock_and_fail;
600     }
601
602     pa_threaded_mainloop_wait (pulsesink->mainloop);
603   }
604
605   pa_threaded_mainloop_unlock (pulsesink->mainloop);
606
607   return gst_util_uint64_scale_int (t, pulsesink->sample_spec.rate, 1000000LL);
608
609 unlock_and_fail:
610
611   pa_threaded_mainloop_unlock (pulsesink->mainloop);
612   return 0;
613 }
614
615 static void
616 gst_pulsesink_success_cb (pa_stream * s, int success, void *userdata)
617 {
618   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
619
620   pulsesink->operation_success = success;
621   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
622 }
623
624 static void
625 gst_pulsesink_reset (GstAudioSink * asink)
626 {
627   GstPulseSink *pulsesink = GST_PULSESINK (asink);
628
629   pa_operation *o = NULL;
630
631   pa_threaded_mainloop_lock (pulsesink->mainloop);
632
633   CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
634
635   if (!(o =
636           pa_stream_flush (pulsesink->stream, gst_pulsesink_success_cb,
637               pulsesink))) {
638     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
639         ("pa_stream_flush() failed: %s",
640             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
641     goto unlock_and_fail;
642   }
643
644   pulsesink->operation_success = 0;
645   while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
646     CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
647
648     pa_threaded_mainloop_wait (pulsesink->mainloop);
649   }
650
651   if (!pulsesink->operation_success) {
652     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED, ("Flush failed: %s",
653             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
654     goto unlock_and_fail;
655   }
656
657 unlock_and_fail:
658
659   if (o) {
660     pa_operation_cancel (o);
661     pa_operation_unref (o);
662   }
663
664   pa_threaded_mainloop_unlock (pulsesink->mainloop);
665 }
666
667 static void
668 gst_pulsesink_change_title (GstPulseSink * pulsesink, const gchar * t)
669 {
670   pa_operation *o = NULL;
671
672   pa_threaded_mainloop_lock (pulsesink->mainloop);
673
674   g_free (pulsesink->stream_name);
675   pulsesink->stream_name = g_strdup (t);
676
677   if (!(pulsesink)->context
678       || pa_context_get_state ((pulsesink)->context) != PA_CONTEXT_READY
679       || !(pulsesink)->stream
680       || pa_stream_get_state ((pulsesink)->stream) != PA_STREAM_READY) {
681     goto unlock_and_fail;
682   }
683
684   if (!(o =
685           pa_stream_set_name (pulsesink->stream, pulsesink->stream_name, NULL,
686               pulsesink))) {
687     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
688         ("pa_stream_set_name() failed: %s",
689             pa_strerror (pa_context_errno (pulsesink->context))), (NULL));
690     goto unlock_and_fail;
691   }
692
693   /* We're not interested if this operation failed or not */
694
695 unlock_and_fail:
696
697   if (o)
698     pa_operation_unref (o);
699
700   pa_threaded_mainloop_unlock (pulsesink->mainloop);
701 }
702
703 static gboolean
704 gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
705 {
706   GstPulseSink *pulsesink = GST_PULSESINK (sink);
707
708   switch (GST_EVENT_TYPE (event)) {
709     case GST_EVENT_TAG:{
710       gchar *title = NULL, *artist = NULL, *location = NULL, *description =
711           NULL, *t = NULL, *buf = NULL;
712       GstTagList *l;
713
714       gst_event_parse_tag (event, &l);
715
716       gst_tag_list_get_string (l, GST_TAG_TITLE, &title);
717       gst_tag_list_get_string (l, GST_TAG_ARTIST, &artist);
718       gst_tag_list_get_string (l, GST_TAG_LOCATION, &location);
719       gst_tag_list_get_string (l, GST_TAG_DESCRIPTION, &description);
720
721       if (title && artist)
722         t = buf =
723             g_strdup_printf ("'%s' by '%s'", g_strstrip (title),
724             g_strstrip (artist));
725       else if (title)
726         t = g_strstrip (title);
727       else if (description)
728         t = g_strstrip (description);
729       else if (location)
730         t = g_strstrip (location);
731
732       if (t)
733         gst_pulsesink_change_title (pulsesink, t);
734
735       g_free (title);
736       g_free (artist);
737       g_free (location);
738       g_free (description);
739       g_free (buf);
740
741       break;
742     }
743     default:
744       ;
745   }
746
747   return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
748 }
749
750 GType
751 gst_pulsesink_get_type (void)
752 {
753   static GType pulsesink_type = 0;
754
755   if (!pulsesink_type) {
756
757     static const GTypeInfo pulsesink_info = {
758       sizeof (GstPulseSinkClass),
759       gst_pulsesink_base_init,
760       NULL,
761       gst_pulsesink_class_init,
762       NULL,
763       NULL,
764       sizeof (GstPulseSink),
765       0,
766       gst_pulsesink_init,
767     };
768
769     pulsesink_type = g_type_register_static (GST_TYPE_AUDIO_SINK,
770         "GstPulseSink", &pulsesink_info, 0);
771   }
772
773   return pulsesink_type;
774 }