0d24d39a0e1d8d1df8bdaf51a91c9eb9384cc2ce
[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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27 #include <stdio.h>
28
29 #include <gst/base/gstbasesink.h>
30 #include <gst/gsttaglist.h>
31
32 #include "pulsesink.h"
33 #include "pulseutil.h"
34
35 GST_DEBUG_CATEGORY_EXTERN (pulse_debug);
36 #define GST_CAT_DEFAULT pulse_debug
37
38 enum
39 {
40   PROP_SERVER = 1,
41   PROP_DEVICE,
42 };
43
44 static GstAudioSinkClass *parent_class = NULL;
45
46 static void gst_pulsesink_destroy_stream (GstPulseSink * pulsesink);
47
48 static void gst_pulsesink_destroy_context (GstPulseSink * pulsesink);
49
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);
55
56 static void gst_pulsesink_dispose (GObject * object);
57
58 static gboolean gst_pulsesink_open (GstAudioSink * asink);
59
60 static gboolean gst_pulsesink_close (GstAudioSink * asink);
61
62 static gboolean gst_pulsesink_prepare (GstAudioSink * asink,
63     GstRingBufferSpec * spec);
64 static gboolean gst_pulsesink_unprepare (GstAudioSink * asink);
65
66 static guint gst_pulsesink_write (GstAudioSink * asink, gpointer data,
67     guint length);
68 static guint gst_pulsesink_delay (GstAudioSink * asink);
69
70 static void gst_pulsesink_reset (GstAudioSink * asink);
71
72 static gboolean gst_pulsesink_event (GstBaseSink * sink, GstEvent * event);
73
74 #if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
75 # define ENDIANNESS   "LITTLE_ENDIAN, BIG_ENDIAN"
76 #else
77 # define ENDIANNESS   "BIG_ENDIAN, LITTLE_ENDIAN"
78 #endif
79
80 static void
81 gst_pulsesink_base_init (gpointer g_class)
82 {
83
84   static GstStaticPadTemplate pad_template = GST_STATIC_PAD_TEMPLATE ("sink",
85       GST_PAD_SINK,
86       GST_PAD_ALWAYS,
87       GST_STATIC_CAPS ("audio/x-raw-int, "
88           "endianness = (int) { " ENDIANNESS " }, "
89           "signed = (boolean) TRUE, "
90           "width = (int) 16, "
91           "depth = (int) 16, "
92           "rate = (int) [ 1, MAX ], "
93           "channels = (int) [ 1, 16 ];"
94           "audio/x-raw-float, "
95           "endianness = (int) { " ENDIANNESS " }, "
96           "width = (int) 32, "
97           "rate = (int) [ 1, MAX ], "
98           "channels = (int) [ 1, 16 ];"
99           "audio/x-raw-int, "
100           "endianness = (int) { " ENDIANNESS " }, "
101           "signed = (boolean) TRUE, "
102           "width = (int) 32, "
103           "depth = (int) 32, "
104           "rate = (int) [ 1, MAX ], "
105           "channels = (int) [ 1, 16 ];"
106           "audio/x-raw-int, "
107           "signed = (boolean) FALSE, "
108           "width = (int) 8, "
109           "depth = (int) 8, "
110           "rate = (int) [ 1, MAX ], "
111           "channels = (int) [ 1, 16 ];"
112           "audio/x-alaw, "
113           "rate = (int) [ 1, MAX], "
114           "channels = (int) [ 1, 16 ];"
115           "audio/x-mulaw, "
116           "rate = (int) [ 1, MAX], " "channels = (int) [ 1, 16 ]")
117       );
118
119   static const GstElementDetails details =
120       GST_ELEMENT_DETAILS ("PulseAudio Audio Sink",
121       "Sink/Audio",
122       "Plays audio to a PulseAudio server",
123       "Lennart Poettering");
124
125   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
126
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));
130 }
131
132 static void
133 gst_pulsesink_class_init (gpointer g_class, gpointer class_data)
134 {
135
136   GObjectClass *gobject_class = G_OBJECT_CLASS (g_class);
137
138   GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (g_class);
139
140   GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (g_class);
141
142   parent_class = g_type_class_peek_parent (g_class);
143
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);
148
149   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_pulsesink_event);
150
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);
158
159   /* Overwrite GObject fields */
160   g_object_class_install_property (gobject_class,
161       PROP_SERVER,
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));
167 }
168
169 static void
170 gst_pulsesink_init (GTypeInstance * instance, gpointer g_class)
171 {
172
173   GstPulseSink *pulsesink = GST_PULSESINK (instance);
174
175   int e;
176
177   pulsesink->server = pulsesink->device = pulsesink->stream_name = NULL;
178
179   pulsesink->context = NULL;
180   pulsesink->stream = NULL;
181
182   pulsesink->mainloop = pa_threaded_mainloop_new ();
183   g_assert (pulsesink->mainloop);
184
185   e = pa_threaded_mainloop_start (pulsesink->mainloop);
186   g_assert (e == 0);
187 }
188
189 static void
190 gst_pulsesink_destroy_stream (GstPulseSink * pulsesink)
191 {
192   if (pulsesink->stream) {
193     pa_stream_disconnect (pulsesink->stream);
194     pa_stream_unref (pulsesink->stream);
195     pulsesink->stream = NULL;
196   }
197
198   g_free (pulsesink->stream_name);
199   pulsesink->stream_name = NULL;
200 }
201
202 static void
203 gst_pulsesink_destroy_context (GstPulseSink * pulsesink)
204 {
205
206   gst_pulsesink_destroy_stream (pulsesink);
207
208   if (pulsesink->context) {
209     pa_context_disconnect (pulsesink->context);
210     pa_context_unref (pulsesink->context);
211     pulsesink->context = NULL;
212   }
213 }
214
215 static void
216 gst_pulsesink_finalize (GObject * object)
217 {
218   GstPulseSink *pulsesink = GST_PULSESINK (object);
219
220   pa_threaded_mainloop_stop (pulsesink->mainloop);
221
222   gst_pulsesink_destroy_context (pulsesink);
223
224   g_free (pulsesink->server);
225   g_free (pulsesink->device);
226   g_free (pulsesink->stream_name);
227
228   pa_threaded_mainloop_free (pulsesink->mainloop);
229
230   G_OBJECT_CLASS (parent_class)->finalize (object);
231 }
232
233 static void
234 gst_pulsesink_dispose (GObject * object)
235 {
236   G_OBJECT_CLASS (parent_class)->dispose (object);
237 }
238
239 static void
240 gst_pulsesink_set_property (GObject * object,
241     guint prop_id, const GValue * value, GParamSpec * pspec)
242 {
243   GstPulseSink *pulsesink = GST_PULSESINK (object);
244
245   switch (prop_id) {
246     case PROP_SERVER:
247       g_free (pulsesink->server);
248       pulsesink->server = g_value_dup_string (value);
249       break;
250
251     case PROP_DEVICE:
252       g_free (pulsesink->device);
253       pulsesink->device = g_value_dup_string (value);
254       break;
255
256     default:
257       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
258       break;
259   }
260 }
261
262 static void
263 gst_pulsesink_get_property (GObject * object,
264     guint prop_id, GValue * value, GParamSpec * pspec)
265 {
266
267   GstPulseSink *pulsesink = GST_PULSESINK (object);
268
269   switch (prop_id) {
270     case PROP_SERVER:
271       g_value_set_string (value, pulsesink->server);
272       break;
273
274     case PROP_DEVICE:
275       g_value_set_string (value, pulsesink->device);
276       break;
277
278     default:
279       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
280       break;
281   }
282 }
283
284 static void
285 gst_pulsesink_context_state_cb (pa_context * c, void *userdata)
286 {
287   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
288
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);
294       break;
295
296     case PA_CONTEXT_UNCONNECTED:
297     case PA_CONTEXT_CONNECTING:
298     case PA_CONTEXT_AUTHORIZING:
299     case PA_CONTEXT_SETTING_NAME:
300       break;
301   }
302 }
303
304 static void
305 gst_pulsesink_stream_state_cb (pa_stream * s, void *userdata)
306 {
307   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
308
309   switch (pa_stream_get_state (s)) {
310
311     case PA_STREAM_READY:
312     case PA_STREAM_FAILED:
313     case PA_STREAM_TERMINATED:
314       pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
315       break;
316
317     case PA_STREAM_UNCONNECTED:
318     case PA_STREAM_CREATING:
319       break;
320   }
321 }
322
323 static void
324 gst_pulsesink_stream_request_cb (pa_stream * s, size_t length, void *userdata)
325 {
326   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
327
328   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
329 }
330
331 static void
332 gst_pulsesink_stream_latency_update_cb (pa_stream * s, void *userdata)
333 {
334   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
335
336   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
337 }
338
339 static gboolean
340 gst_pulsesink_open (GstAudioSink * asink)
341 {
342   GstPulseSink *pulsesink = GST_PULSESINK (asink);
343
344   gchar *name = gst_pulse_client_name ();
345
346   pa_threaded_mainloop_lock (pulsesink->mainloop);
347
348   if (!(pulsesink->context =
349           pa_context_new (pa_threaded_mainloop_get_api (pulsesink->mainloop),
350               name))) {
351     GST_ELEMENT_ERROR (pulsesink, RESOURCE, FAILED,
352         ("Failed to create context"), (NULL));
353     goto unlock_and_fail;
354   }
355
356   pa_context_set_state_callback (pulsesink->context,
357       gst_pulsesink_context_state_cb, pulsesink);
358
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;
363   }
364
365   /* Wait until the context is ready */
366   pa_threaded_mainloop_wait (pulsesink->mainloop);
367
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;
372   }
373
374   pa_threaded_mainloop_unlock (pulsesink->mainloop);
375   g_free (name);
376   return TRUE;
377
378 unlock_and_fail:
379
380   pa_threaded_mainloop_unlock (pulsesink->mainloop);
381   g_free (name);
382   return FALSE;
383 }
384
385 static gboolean
386 gst_pulsesink_close (GstAudioSink * asink)
387 {
388   GstPulseSink *pulsesink = GST_PULSESINK (asink);
389
390   pa_threaded_mainloop_lock (pulsesink->mainloop);
391   gst_pulsesink_destroy_context (pulsesink);
392   pa_threaded_mainloop_unlock (pulsesink->mainloop);
393
394   return TRUE;
395 }
396
397 static gboolean
398 gst_pulsesink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
399 {
400   pa_buffer_attr buf_attr;
401
402   pa_channel_map channel_map;
403
404   GstPulseSink *pulsesink = GST_PULSESINK (asink);
405
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;
410   }
411
412   pa_threaded_mainloop_lock (pulsesink->mainloop);
413
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;
420   }
421
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;
430   }
431
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);
438
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;
444
445   if (pa_stream_connect_playback (pulsesink->stream, pulsesink->device,
446           &buf_attr,
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;
453   }
454
455   /* Wait until the stream is ready */
456   pa_threaded_mainloop_wait (pulsesink->mainloop);
457
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;
463   }
464
465   pa_threaded_mainloop_unlock (pulsesink->mainloop);
466
467   spec->bytes_per_sample = pa_frame_size (&pulsesink->sample_spec);
468   memset (spec->silence_sample, 0, spec->bytes_per_sample);
469
470   return TRUE;
471
472 unlock_and_fail:
473
474   pa_threaded_mainloop_unlock (pulsesink->mainloop);
475   return FALSE;
476 }
477
478 static gboolean
479 gst_pulsesink_unprepare (GstAudioSink * asink)
480 {
481   GstPulseSink *pulsesink = GST_PULSESINK (asink);
482
483   pa_threaded_mainloop_lock (pulsesink->mainloop);
484   gst_pulsesink_destroy_stream (pulsesink);
485   pa_threaded_mainloop_unlock (pulsesink->mainloop);
486
487   return TRUE;
488 }
489
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)); \
494     goto label; \
495 }
496
497 static guint
498 gst_pulsesink_write (GstAudioSink * asink, gpointer data, guint length)
499 {
500   GstPulseSink *pulsesink = GST_PULSESINK (asink);
501
502   size_t sum = 0;
503
504   pa_threaded_mainloop_lock (pulsesink->mainloop);
505
506   while (length > 0) {
507     size_t l;
508
509     for (;;) {
510       CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
511
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;
517       }
518
519       if (l > 0)
520         break;
521
522       pa_threaded_mainloop_wait (pulsesink->mainloop);
523     }
524
525     if (l > length)
526       l = length;
527
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;
534     }
535
536     data = (guint8 *) data + l;
537     length -= l;
538
539     sum += l;
540   }
541
542   pa_threaded_mainloop_unlock (pulsesink->mainloop);
543
544   return sum;
545
546 unlock_and_fail:
547
548   pa_threaded_mainloop_unlock (pulsesink->mainloop);
549   return 0;
550 }
551
552 static guint
553 gst_pulsesink_delay (GstAudioSink * asink)
554 {
555   GstPulseSink *pulsesink = GST_PULSESINK (asink);
556
557   pa_usec_t t;
558
559   pa_threaded_mainloop_lock (pulsesink->mainloop);
560
561   for (;;) {
562     CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
563
564     if (pa_stream_get_latency (pulsesink->stream, &t, NULL) >= 0)
565       break;
566
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;
572     }
573
574     pa_threaded_mainloop_wait (pulsesink->mainloop);
575   }
576
577   pa_threaded_mainloop_unlock (pulsesink->mainloop);
578
579   return gst_util_uint64_scale_int (t, pulsesink->sample_spec.rate, 1000000LL);
580
581 unlock_and_fail:
582
583   pa_threaded_mainloop_unlock (pulsesink->mainloop);
584   return 0;
585 }
586
587 static void
588 gst_pulsesink_success_cb (pa_stream * s, int success, void *userdata)
589 {
590   GstPulseSink *pulsesink = GST_PULSESINK (userdata);
591
592   pulsesink->operation_success = success;
593   pa_threaded_mainloop_signal (pulsesink->mainloop, 0);
594 }
595
596 static void
597 gst_pulsesink_reset (GstAudioSink * asink)
598 {
599   GstPulseSink *pulsesink = GST_PULSESINK (asink);
600
601   pa_operation *o = NULL;
602
603   pa_threaded_mainloop_lock (pulsesink->mainloop);
604
605   CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
606
607   if (!(o =
608           pa_stream_flush (pulsesink->stream, gst_pulsesink_success_cb,
609               pulsesink))) {
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;
614   }
615
616   pulsesink->operation_success = 0;
617   while (pa_operation_get_state (o) != PA_OPERATION_DONE) {
618     CHECK_DEAD_GOTO (pulsesink, unlock_and_fail);
619
620     pa_threaded_mainloop_wait (pulsesink->mainloop);
621   }
622
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;
627   }
628
629 unlock_and_fail:
630
631   if (o) {
632     pa_operation_cancel (o);
633     pa_operation_unref (o);
634   }
635
636   pa_threaded_mainloop_unlock (pulsesink->mainloop);
637 }
638
639 static void
640 gst_pulsesink_change_title (GstPulseSink * pulsesink, const gchar * t)
641 {
642   pa_operation *o = NULL;
643
644   pa_threaded_mainloop_lock (pulsesink->mainloop);
645
646   g_free (pulsesink->stream_name);
647   pulsesink->stream_name = g_strdup (t);
648
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;
654   }
655
656   if (!(o =
657           pa_stream_set_name (pulsesink->stream, pulsesink->stream_name, NULL,
658               pulsesink))) {
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;
663   }
664
665   /* We're not interested if this operation failed or not */
666
667 unlock_and_fail:
668
669   if (o)
670     pa_operation_unref (o);
671
672   pa_threaded_mainloop_unlock (pulsesink->mainloop);
673 }
674
675 static gboolean
676 gst_pulsesink_event (GstBaseSink * sink, GstEvent * event)
677 {
678   GstPulseSink *pulsesink = GST_PULSESINK (sink);
679
680   switch (GST_EVENT_TYPE (event)) {
681     case GST_EVENT_TAG:{
682       gchar *title = NULL, *artist = NULL, *location = NULL, *description =
683           NULL, *t = NULL, *buf = NULL;
684       GstTagList *l;
685
686       gst_event_parse_tag (event, &l);
687
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);
692
693       if (title && artist)
694         t = buf =
695             g_strdup_printf ("'%s' by '%s'", g_strstrip (title),
696             g_strstrip (artist));
697       else if (title)
698         t = g_strstrip (title);
699       else if (description)
700         t = g_strstrip (description);
701       else if (location)
702         t = g_strstrip (location);
703
704       if (t)
705         gst_pulsesink_change_title (pulsesink, t);
706
707       g_free (title);
708       g_free (artist);
709       g_free (location);
710       g_free (description);
711       g_free (buf);
712
713       break;
714     }
715     default:
716       ;
717   }
718
719   return GST_BASE_SINK_CLASS (parent_class)->event (sink, event);
720 }
721
722 GType
723 gst_pulsesink_get_type (void)
724 {
725   static GType pulsesink_type = 0;
726
727   if (!pulsesink_type) {
728
729     static const GTypeInfo pulsesink_info = {
730       sizeof (GstPulseSinkClass),
731       gst_pulsesink_base_init,
732       NULL,
733       gst_pulsesink_class_init,
734       NULL,
735       NULL,
736       sizeof (GstPulseSink),
737       0,
738       gst_pulsesink_init,
739     };
740
741     pulsesink_type = g_type_register_static (GST_TYPE_AUDIO_SINK,
742         "GstPulseSink", &pulsesink_info, 0);
743   }
744
745   return pulsesink_type;
746 }