tizen 2.0 init
[framework/multimedia/gst-plugins-good0.10.git] / ext / pulse / pulseaudiosink.c
1 /*-*- Mode: C; c-basic-offset: 2 -*-*/
2
3 /*  GStreamer pulseaudio plugin
4  *
5  *  Copyright (c) 2011 Intel Corporation
6  *                2011 Collabora
7  *                2011 Arun Raghavan <arun.raghavan@collabora.co.uk>
8  *                2011 Sebastian Dröge <sebastian.droege@collabora.co.uk>
9  *
10  *  gst-pulse is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as
12  *  published by the Free Software Foundation; either version 2.1 of the
13  *  License, or (at your option) any later version.
14  *
15  *  gst-pulse is distributed in the hope that it will be useful, but
16  *  WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  *  Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with gst-pulse; if not, write to the Free Software
22  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23  *  USA.
24  */
25
26 /**
27  * SECTION:element-pulseaudiosink
28  * @see_also: pulsesink, pulsesrc, pulsemixer
29  *
30  * This element outputs audio to a
31  * <ulink href="http://www.pulseaudio.org">PulseAudio sound server</ulink> via
32  * the @pulsesink element. It transparently takes care of passing compressed
33  * format as-is if the sink supports it, decoding if necessary, and changes
34  * to supported formats at runtime.
35  *
36  * <refsect2>
37  * <title>Example pipelines</title>
38  * |[
39  * gst-launch -v filesrc location=sine.ogg ! oggdemux ! vorbisdec ! pulseaudiosink
40  * ]| Decode and play an Ogg/Vorbis file.
41  * |[
42  * gst-launch -v filesrc location=test.mp3 ! mp3parse ! pulseaudiosink stream-properties="props,media.title=test"
43  * ]| Play an MP3 file on a sink that supports decoding directly, plug in a
44  * decoder if/when required.
45  * </refsect2>
46  */
47
48 #ifdef HAVE_CONFIG_H
49 #include "config.h"
50 #endif
51
52 #ifdef HAVE_PULSE_1_0
53
54 #include <gst/pbutils/pbutils.h>
55 #include <gst/gst-i18n-plugin.h>
56 #include <gst/glib-compat-private.h>
57
58 #include <gst/audio/gstaudioiec61937.h>
59 #include "pulsesink.h"
60
61 GST_DEBUG_CATEGORY (pulseaudiosink_debug);
62 #define GST_CAT_DEFAULT (pulseaudiosink_debug)
63
64 #define GST_PULSE_AUDIO_SINK_LOCK(obj) G_STMT_START {                    \
65     GST_LOG_OBJECT (obj,                                              \
66                     "locking from thread %p",                         \
67                     g_thread_self ());                                \
68     g_mutex_lock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock);                 \
69     GST_LOG_OBJECT (obj,                                              \
70                     "locked from thread %p",                          \
71                     g_thread_self ());                                \
72 } G_STMT_END
73
74 #define GST_PULSE_AUDIO_SINK_UNLOCK(obj) G_STMT_START {                  \
75     GST_LOG_OBJECT (obj,                                              \
76                     "unlocking from thread %p",                       \
77                     g_thread_self ());                                \
78     g_mutex_unlock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock);               \
79 } G_STMT_END
80
81 typedef struct
82 {
83   GstBin parent;
84   GMutex *lock;
85
86   GstPad *sinkpad;
87   GstPad *sink_proxypad;
88   GstPadEventFunction sinkpad_old_eventfunc;
89   GstPadEventFunction proxypad_old_eventfunc;
90
91   GstPulseSink *psink;
92   GstElement *dbin2;
93
94   GstSegment segment;
95
96   guint event_probe_id;
97   gulong pad_added_id;
98
99   gboolean format_lost;
100 } GstPulseAudioSink;
101
102 typedef struct
103 {
104   GstBinClass parent_class;
105   guint n_prop_own;
106   guint n_prop_total;
107 } GstPulseAudioSinkClass;
108
109 static void gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
110     GValue * value, GParamSpec * pspec);
111 static void gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
112     const GValue * value, GParamSpec * pspec);
113 static void gst_pulse_audio_sink_dispose (GObject * object);
114 static gboolean gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event);
115 static gboolean gst_pulse_audio_sink_sink_event (GstPad * pad,
116     GstEvent * event);
117 static gboolean gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad,
118     GstCaps * caps);
119 static gboolean gst_pulse_audio_sink_sink_setcaps (GstPad * pad,
120     GstCaps * caps);
121 static GstStateChangeReturn
122 gst_pulse_audio_sink_change_state (GstElement * element,
123     GstStateChange transition);
124
125 static void
126 gst_pulse_audio_sink_do_init (GType type)
127 {
128   GST_DEBUG_CATEGORY_INIT (pulseaudiosink_debug, "pulseaudiosink", 0,
129       "Bin that wraps pulsesink for handling compressed formats");
130 }
131
132 GST_BOILERPLATE_FULL (GstPulseAudioSink, gst_pulse_audio_sink, GstBin,
133     GST_TYPE_BIN, gst_pulse_audio_sink_do_init);
134
135 static GstStaticPadTemplate sink_template =
136 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
137     GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
138
139 static void
140 gst_pulse_audio_sink_base_init (gpointer klass)
141 {
142   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
143
144   gst_element_class_add_static_pad_template (element_class, &sink_template);
145
146   gst_element_class_set_details_simple (element_class,
147       "Bin wrapping pulsesink", "Sink/Audio/Bin",
148       "Correctly handles sink changes when streaming compressed formats to "
149       "pulsesink", "Arun Raghavan <arun.raghavan@collabora.co.uk>");
150 }
151
152 static GParamSpec *
153 param_spec_copy (GParamSpec * spec)
154 {
155   const char *name, *nick, *blurb;
156   GParamFlags flags;
157
158   name = g_param_spec_get_name (spec);
159   nick = g_param_spec_get_nick (spec);
160   blurb = g_param_spec_get_blurb (spec);
161   flags = spec->flags;
162
163   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOOLEAN) {
164     return g_param_spec_boolean (name, nick, blurb,
165         G_PARAM_SPEC_BOOLEAN (spec)->default_value, flags);
166   }
167
168   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_BOXED) {
169     return g_param_spec_boxed (name, nick, blurb, spec->value_type, flags);
170   }
171
172   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_CHAR) {
173     GParamSpecChar *cspec = G_PARAM_SPEC_CHAR (spec);
174     return g_param_spec_char (name, nick, blurb, cspec->minimum,
175         cspec->maximum, cspec->default_value, flags);
176   }
177
178   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_DOUBLE) {
179     GParamSpecDouble *dspec = G_PARAM_SPEC_DOUBLE (spec);
180     return g_param_spec_double (name, nick, blurb, dspec->minimum,
181         dspec->maximum, dspec->default_value, flags);
182   }
183
184   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ENUM) {
185     return g_param_spec_enum (name, nick, blurb, spec->value_type,
186         G_PARAM_SPEC_ENUM (spec)->default_value, flags);
187   }
188
189   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLAGS) {
190     return g_param_spec_flags (name, nick, blurb, spec->value_type,
191         G_PARAM_SPEC_ENUM (spec)->default_value, flags);
192   }
193
194   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_FLOAT) {
195     GParamSpecFloat *fspec = G_PARAM_SPEC_FLOAT (spec);
196     return g_param_spec_double (name, nick, blurb, fspec->minimum,
197         fspec->maximum, fspec->default_value, flags);
198   }
199
200   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_GTYPE) {
201     return g_param_spec_gtype (name, nick, blurb,
202         G_PARAM_SPEC_GTYPE (spec)->is_a_type, flags);
203   }
204
205   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT) {
206     GParamSpecInt *ispec = G_PARAM_SPEC_INT (spec);
207     return g_param_spec_int (name, nick, blurb, ispec->minimum,
208         ispec->maximum, ispec->default_value, flags);
209   }
210
211   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_INT64) {
212     GParamSpecInt64 *ispec = G_PARAM_SPEC_INT64 (spec);
213     return g_param_spec_int64 (name, nick, blurb, ispec->minimum,
214         ispec->maximum, ispec->default_value, flags);
215   }
216
217   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_LONG) {
218     GParamSpecLong *lspec = G_PARAM_SPEC_LONG (spec);
219     return g_param_spec_long (name, nick, blurb, lspec->minimum,
220         lspec->maximum, lspec->default_value, flags);
221   }
222
223   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_OBJECT) {
224     return g_param_spec_object (name, nick, blurb, spec->value_type, flags);
225   }
226
227   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_PARAM) {
228     return g_param_spec_param (name, nick, blurb, spec->value_type, flags);
229   }
230
231   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_POINTER) {
232     return g_param_spec_pointer (name, nick, blurb, flags);
233   }
234
235   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_STRING) {
236     return g_param_spec_string (name, nick, blurb,
237         G_PARAM_SPEC_STRING (spec)->default_value, flags);
238   }
239
240   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UCHAR) {
241     GParamSpecUChar *cspec = G_PARAM_SPEC_UCHAR (spec);
242     return g_param_spec_uchar (name, nick, blurb, cspec->minimum,
243         cspec->maximum, cspec->default_value, flags);
244   }
245
246   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT) {
247     GParamSpecUInt *ispec = G_PARAM_SPEC_UINT (spec);
248     return g_param_spec_uint (name, nick, blurb, ispec->minimum,
249         ispec->maximum, ispec->default_value, flags);
250   }
251
252   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UINT64) {
253     GParamSpecUInt64 *ispec = G_PARAM_SPEC_UINT64 (spec);
254     return g_param_spec_uint64 (name, nick, blurb, ispec->minimum,
255         ispec->maximum, ispec->default_value, flags);
256   }
257
258   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_ULONG) {
259     GParamSpecULong *lspec = G_PARAM_SPEC_ULONG (spec);
260     return g_param_spec_ulong (name, nick, blurb, lspec->minimum,
261         lspec->maximum, lspec->default_value, flags);
262   }
263
264   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_UNICHAR) {
265     return g_param_spec_unichar (name, nick, blurb,
266         G_PARAM_SPEC_UNICHAR (spec)->default_value, flags);
267   }
268
269   if (G_PARAM_SPEC_TYPE (spec) == G_TYPE_PARAM_VARIANT) {
270     GParamSpecVariant *vspec = G_PARAM_SPEC_VARIANT (spec);
271     return g_param_spec_variant (name, nick, blurb, vspec->type,
272         vspec->default_value, flags);
273   }
274
275   if (G_PARAM_SPEC_TYPE (spec) == GST_TYPE_PARAM_MINI_OBJECT) {
276     return gst_param_spec_mini_object (name, nick, blurb, spec->value_type,
277         flags);
278   }
279
280   g_warning ("Unknown param type %ld for '%s'",
281       (long) G_PARAM_SPEC_TYPE (spec), name);
282   g_assert_not_reached ();
283 }
284
285 static void
286 gst_pulse_audio_sink_class_init (GstPulseAudioSinkClass * klass)
287 {
288   GObjectClass *gobject_class = (GObjectClass *) klass;
289   GstElementClass *element_class = (GstElementClass *) klass;
290   GstPulseSinkClass *psink_class =
291       GST_PULSESINK_CLASS (g_type_class_ref (GST_TYPE_PULSESINK));
292   GParamSpec **specs;
293   guint n, i, j;
294
295   gobject_class->get_property = gst_pulse_audio_sink_get_property;
296   gobject_class->set_property = gst_pulse_audio_sink_set_property;
297   gobject_class->dispose = gst_pulse_audio_sink_dispose;
298   element_class->change_state =
299       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_change_state);
300
301   /* Find out how many properties we already have */
302   specs = g_object_class_list_properties (gobject_class, &klass->n_prop_own);
303   g_free (specs);
304
305   /* Proxy pulsesink's properties */
306   specs = g_object_class_list_properties (G_OBJECT_CLASS (psink_class), &n);
307   for (i = 0, j = klass->n_prop_own; i < n; i++) {
308     if (g_object_class_find_property (gobject_class,
309             g_param_spec_get_name (specs[i]))) {
310       /* We already inherited this property from a parent, skip */
311       j--;
312     } else {
313       g_object_class_install_property (gobject_class, i + j + 1,
314           param_spec_copy (specs[i]));
315     }
316   }
317
318   klass->n_prop_total = i + j;
319
320   g_free (specs);
321   g_type_class_unref (psink_class);
322 }
323
324 static GstPad *
325 get_proxypad (GstPad * sinkpad)
326 {
327   GstIterator *iter = NULL;
328   GstPad *proxypad = NULL;
329
330   iter = gst_pad_iterate_internal_links (sinkpad);
331   if (iter) {
332     if (gst_iterator_next (iter, (gpointer) & proxypad) != GST_ITERATOR_OK)
333       proxypad = NULL;
334     gst_iterator_free (iter);
335   }
336
337   return proxypad;
338 }
339
340 static void
341 post_missing_element_message (GstPulseAudioSink * pbin, const gchar * name)
342 {
343   GstMessage *msg;
344
345   msg = gst_missing_element_message_new (GST_ELEMENT_CAST (pbin), name);
346   gst_element_post_message (GST_ELEMENT_CAST (pbin), msg);
347 }
348
349 static void
350 notify_cb (GObject * selector, GParamSpec * pspec, GstPulseAudioSink * pbin)
351 {
352   g_object_notify (G_OBJECT (pbin), g_param_spec_get_name (pspec));
353 }
354
355 static void
356 gst_pulse_audio_sink_init (GstPulseAudioSink * pbin,
357     GstPulseAudioSinkClass * klass)
358 {
359   GstPadTemplate *template;
360   GstPad *pad = NULL;
361   GParamSpec **specs;
362   GString *prop;
363   guint i;
364
365   pbin->lock = g_mutex_new ();
366
367   gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
368
369   pbin->psink = GST_PULSESINK (gst_element_factory_make ("pulsesink",
370           "pulseaudiosink-sink"));
371   g_assert (pbin->psink != NULL);
372
373   if (!gst_bin_add (GST_BIN (pbin), GST_ELEMENT (pbin->psink))) {
374     GST_ERROR_OBJECT (pbin, "Failed to add pulsesink to bin");
375     goto error;
376   }
377
378   pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
379   template = gst_static_pad_template_get (&sink_template);
380   pbin->sinkpad = gst_ghost_pad_new_from_template ("sink", pad, template);
381   gst_object_unref (template);
382
383   pbin->sinkpad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sinkpad);
384   gst_pad_set_event_function (pbin->sinkpad,
385       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_event));
386   gst_pad_set_setcaps_function (pbin->sinkpad,
387       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_setcaps));
388   gst_pad_set_acceptcaps_function (pbin->sinkpad,
389       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_acceptcaps));
390
391   gst_element_add_pad (GST_ELEMENT (pbin), pbin->sinkpad);
392
393   if (!(pbin->sink_proxypad = get_proxypad (pbin->sinkpad)))
394     GST_ERROR_OBJECT (pbin, "Failed to get proxypad of srcpad");
395   else {
396     pbin->proxypad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sink_proxypad);
397     gst_pad_set_event_function (pbin->sink_proxypad,
398         GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_src_event));
399   }
400
401   /* Now proxy all the notify::* signals */
402   specs = g_object_class_list_properties (G_OBJECT_CLASS (klass), &i);
403   prop = g_string_sized_new (30);
404
405   for (i--; i >= klass->n_prop_own; i--) {
406     g_string_printf (prop, "notify::%s", g_param_spec_get_name (specs[i]));
407     g_signal_connect (pbin->psink, prop->str, G_CALLBACK (notify_cb), pbin);
408   }
409
410   g_string_free (prop, TRUE);
411   g_free (specs);
412
413   pbin->format_lost = FALSE;
414
415 out:
416   if (pad)
417     gst_object_unref (pad);
418
419   return;
420
421 error:
422   if (pbin->psink)
423     gst_object_unref (pbin->psink);
424   goto out;
425 }
426
427 static void
428 gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
429     const GValue * value, GParamSpec * pspec)
430 {
431   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
432   GstPulseAudioSinkClass *klass =
433       GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
434
435   g_return_if_fail (prop_id <= klass->n_prop_total);
436
437   g_object_set_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
438       value);
439 }
440
441 static void
442 gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
443     GValue * value, GParamSpec * pspec)
444 {
445   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
446   GstPulseAudioSinkClass *klass =
447       GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
448
449   g_return_if_fail (prop_id <= klass->n_prop_total);
450
451   g_object_get_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
452       value);
453 }
454
455 static void
456 gst_pulse_audio_sink_free_dbin2 (GstPulseAudioSink * pbin)
457 {
458   g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
459   gst_element_set_state (pbin->dbin2, GST_STATE_NULL);
460
461   gst_bin_remove (GST_BIN (pbin), pbin->dbin2);
462
463   pbin->dbin2 = NULL;
464 }
465
466 static void
467 gst_pulse_audio_sink_dispose (GObject * object)
468 {
469   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
470
471   if (pbin->lock) {
472     g_mutex_free (pbin->lock);
473     pbin->lock = NULL;
474   }
475
476   if (pbin->sink_proxypad) {
477     gst_object_unref (pbin->sink_proxypad);
478     pbin->sink_proxypad = NULL;
479   }
480
481   if (pbin->dbin2) {
482     g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
483     pbin->dbin2 = NULL;
484   }
485
486   pbin->sinkpad = NULL;
487   pbin->psink = NULL;
488
489   G_OBJECT_CLASS (parent_class)->dispose (object);
490 }
491
492 static gboolean
493 gst_pulse_audio_sink_update_sinkpad (GstPulseAudioSink * pbin, GstPad * sinkpad)
494 {
495   gboolean ret;
496
497   ret = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (pbin->sinkpad), sinkpad);
498
499   if (!ret)
500     GST_WARNING_OBJECT (pbin, "Could not update ghostpad target");
501
502   return ret;
503 }
504
505 static void
506 distribute_running_time (GstElement * element, const GstSegment * segment)
507 {
508   GstEvent *event;
509   GstPad *pad;
510
511   pad = gst_element_get_static_pad (element, "sink");
512
513   /* FIXME: Some decoders collect newsegments and send them out at once, making
514    * them lose accumulator events (and thus making dbin2_event_probe() hard to
515    * do right if we're sending these as well. We can get away with not sending
516    * these at the moment, but this should be fixed! */
517 #if 0
518   if (segment->accum) {
519     event = gst_event_new_new_segment_full (FALSE, segment->rate,
520         segment->applied_rate, segment->format, 0, segment->accum, 0);
521     gst_pad_send_event (pad, event);
522   }
523 #endif
524
525   event = gst_event_new_new_segment_full (FALSE, segment->rate,
526       segment->applied_rate, segment->format,
527       segment->start, segment->stop, segment->time);
528   gst_pad_send_event (pad, event);
529
530   gst_object_unref (pad);
531 }
532
533 static gboolean
534 dbin2_event_probe (GstPad * pad, GstMiniObject * obj, gpointer data)
535 {
536   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
537   GstEvent *event = GST_EVENT (obj);
538
539   if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
540     GST_DEBUG_OBJECT (pbin, "Got newsegment - dropping");
541     gst_pad_remove_event_probe (pad, pbin->event_probe_id);
542     return FALSE;
543   }
544
545   return TRUE;
546 }
547
548 static void
549 pad_added_cb (GstElement * dbin2, GstPad * pad, gpointer * data)
550 {
551   GstPulseAudioSink *pbin;
552   GstPad *sinkpad = NULL;
553
554   pbin = GST_PULSE_AUDIO_SINK (data);
555   sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
556
557   GST_PULSE_AUDIO_SINK_LOCK (pbin);
558   if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
559     GST_ERROR_OBJECT (pbin, "Failed to link decodebin2 to pulsesink");
560   else
561     GST_DEBUG_OBJECT (pbin, "Linked new pad to pulsesink");
562   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
563
564   gst_object_unref (sinkpad);
565 }
566
567 /* Called with pbin lock held */
568 static void
569 gst_pulse_audio_sink_add_dbin2 (GstPulseAudioSink * pbin)
570 {
571   GstPad *sinkpad = NULL;
572
573   g_assert (pbin->dbin2 == NULL);
574
575   pbin->dbin2 = gst_element_factory_make ("decodebin2", "pulseaudiosink-dbin2");
576
577   if (!pbin->dbin2) {
578     post_missing_element_message (pbin, "decodebin2");
579     GST_ELEMENT_WARNING (pbin, CORE, MISSING_PLUGIN,
580         (_("Missing element '%s' - check your GStreamer installation."),
581             "decodebin2"), ("audio playback might fail"));
582     goto out;
583   }
584
585   if (!gst_bin_add (GST_BIN (pbin), pbin->dbin2)) {
586     GST_ERROR_OBJECT (pbin, "Failed to add decodebin2 to bin");
587     goto out;
588   }
589
590   pbin->pad_added_id = g_signal_connect (pbin->dbin2, "pad-added",
591       G_CALLBACK (pad_added_cb), pbin);
592
593   if (!gst_element_sync_state_with_parent (pbin->dbin2)) {
594     GST_ERROR_OBJECT (pbin, "Failed to set decodebin2 to parent state");
595     goto out;
596   }
597
598   /* Trap the newsegment events that we feed the decodebin and discard them */
599   sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
600   pbin->event_probe_id = gst_pad_add_event_probe_full (sinkpad,
601       G_CALLBACK (dbin2_event_probe), gst_object_ref (pbin),
602       (GDestroyNotify) gst_object_unref);
603   gst_object_unref (sinkpad);
604   sinkpad = NULL;
605
606   GST_DEBUG_OBJECT (pbin, "Distributing running time to decodebin");
607   distribute_running_time (pbin->dbin2, &pbin->segment);
608
609   sinkpad = gst_element_get_static_pad (pbin->dbin2, "sink");
610
611   gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
612
613 out:
614   if (sinkpad)
615     gst_object_unref (sinkpad);
616 }
617
618 static void
619 update_eac3_alignment (GstPulseAudioSink * pbin)
620 {
621   GstCaps *caps = gst_pad_peer_get_caps_reffed (pbin->sinkpad);
622   GstStructure *st;
623
624   if (!caps)
625     return;
626
627   st = gst_caps_get_structure (caps, 0);
628
629   if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
630     GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
631         "alignment", G_TYPE_STRING, pbin->dbin2 ? "frame" : "iec61937", NULL);
632
633     if (!gst_pad_push_event (pbin->sinkpad,
634             gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
635       GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
636   }
637
638   gst_caps_unref (caps);
639 }
640
641 static void
642 proxypad_blocked_cb (GstPad * pad, gboolean blocked, gpointer data)
643 {
644   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
645   GstCaps *caps;
646   GstPad *sinkpad = NULL;
647
648   if (!blocked) {
649     /* Unblocked, don't need to do anything */
650     GST_DEBUG_OBJECT (pbin, "unblocked");
651     return;
652   }
653
654   GST_DEBUG_OBJECT (pbin, "blocked");
655
656   GST_PULSE_AUDIO_SINK_LOCK (pbin);
657
658   if (!pbin->format_lost) {
659     sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
660
661     if (GST_PAD_CAPS (pbin->sinkpad)) {
662       /* See if we already got caps on our sinkpad */
663       caps = gst_caps_ref (GST_PAD_CAPS (pbin->sinkpad));
664     } else {
665       /* We haven't, so get caps from upstream */
666       caps = gst_pad_get_caps_reffed (pad);
667     }
668
669     if (gst_pad_accept_caps (sinkpad, caps)) {
670       if (pbin->dbin2) {
671         GST_DEBUG_OBJECT (pbin, "Removing decodebin");
672         gst_pulse_audio_sink_free_dbin2 (pbin);
673         gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
674       } else
675         GST_DEBUG_OBJECT (pbin, "Doing nothing");
676
677       gst_caps_unref (caps);
678       gst_object_unref (sinkpad);
679       goto done;
680     }
681     /* pulsesink doesn't accept the incoming caps, so add a decodebin
682      * (potentially after removing the existing once, since decodebin2 can't
683      * renegotiate). */
684   } else {
685     /* Format lost, proceed to try plugging a decodebin */
686     pbin->format_lost = FALSE;
687   }
688
689   if (pbin->dbin2 != NULL) {
690     /* decodebin2 doesn't support reconfiguration, so throw this one away and
691      * create a new one. */
692     gst_pulse_audio_sink_free_dbin2 (pbin);
693   }
694
695   GST_DEBUG_OBJECT (pbin, "Adding decodebin");
696   gst_pulse_audio_sink_add_dbin2 (pbin);
697
698 done:
699   update_eac3_alignment (pbin);
700
701   gst_pad_set_blocked_async_full (pad, FALSE, proxypad_blocked_cb,
702       gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
703
704   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
705 }
706
707 static gboolean
708 gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event)
709 {
710   GstPulseAudioSink *pbin = NULL;
711   GstPad *ghostpad = NULL;
712   gboolean ret = FALSE;
713
714   ghostpad = GST_PAD_CAST (gst_pad_get_parent (pad));
715   if (G_UNLIKELY (!ghostpad)) {
716     GST_WARNING_OBJECT (pad, "Could not get ghostpad");
717     goto out;
718   }
719
720   pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (ghostpad));
721   if (G_UNLIKELY (!pbin)) {
722     GST_WARNING_OBJECT (pad, "Could not get pulseaudiosink");
723     goto out;
724   }
725
726   if (G_UNLIKELY (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) &&
727       (gst_event_has_name (event, "pulse-format-lost") ||
728           gst_event_has_name (event, "pulse-sink-changed"))) {
729     g_return_val_if_fail (pad->mode != GST_ACTIVATE_PULL, FALSE);
730
731     GST_PULSE_AUDIO_SINK_LOCK (pbin);
732     if (gst_event_has_name (event, "pulse-format-lost"))
733       pbin->format_lost = TRUE;
734
735     if (!gst_pad_is_blocked (pad))
736       gst_pad_set_blocked_async_full (pad, TRUE, proxypad_blocked_cb,
737           gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
738     GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
739
740     ret = TRUE;
741   } else if (pbin->proxypad_old_eventfunc) {
742     ret = pbin->proxypad_old_eventfunc (pad, event);
743     event = NULL;
744   }
745
746 out:
747   if (ghostpad)
748     gst_object_unref (ghostpad);
749   if (pbin)
750     gst_object_unref (pbin);
751   if (event)
752     gst_event_unref (event);
753
754   return ret;
755 }
756
757 static gboolean
758 gst_pulse_audio_sink_sink_event (GstPad * pad, GstEvent * event)
759 {
760   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
761   gboolean ret;
762
763   ret = pbin->sinkpad_old_eventfunc (pad, gst_event_ref (event));
764
765   switch (GST_EVENT_TYPE (event)) {
766     case GST_EVENT_NEWSEGMENT:
767     {
768       GstFormat format;
769       gdouble rate, arate;
770       gint64 start, stop, time;
771       gboolean update;
772
773       GST_PULSE_AUDIO_SINK_LOCK (pbin);
774       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
775           &start, &stop, &time);
776
777       GST_DEBUG_OBJECT (pbin,
778           "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
779           ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
780           update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
781           GST_TIME_ARGS (time));
782
783       if (format == GST_FORMAT_TIME) {
784         /* Store the values for feeding to sub-elements */
785         gst_segment_set_newsegment_full (&pbin->segment, update,
786             rate, arate, format, start, stop, time);
787       } else {
788         GST_WARNING_OBJECT (pbin, "Got a non-TIME format segment");
789         gst_segment_init (&pbin->segment, GST_FORMAT_TIME);
790       }
791       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
792
793       break;
794     }
795
796     case GST_EVENT_FLUSH_STOP:
797       GST_PULSE_AUDIO_SINK_LOCK (pbin);
798       gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
799       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
800       break;
801
802     default:
803       break;
804   }
805
806   gst_object_unref (pbin);
807   gst_event_unref (event);
808
809   return ret;
810 }
811
812 /* The bin's acceptcaps should be exactly equivalent to a pulsesink that is
813  * connected to a sink that supports all the formats in template caps. This
814  * means that upstream will have to have everything possibly upto a parser
815  * plugged and we plugin a decoder whenever required. */
816 static gboolean
817 gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad, GstCaps * caps)
818 {
819   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
820   GstRingBufferSpec spec = { 0 };
821   const GstStructure *st;
822   GstCaps *pad_caps = NULL;
823   gboolean ret = FALSE;
824
825   pad_caps = gst_pad_get_caps_reffed (pad);
826   if (!pad_caps || !gst_caps_can_intersect (pad_caps, caps))
827     goto out;
828
829   /* If we've not got fixed caps, creating a stream might fail, so let's just
830    * return from here with default acceptcaps behaviour */
831   if (!gst_caps_is_fixed (caps))
832     goto out;
833
834   spec.latency_time = GST_BASE_AUDIO_SINK (pbin->psink)->latency_time;
835   if (!gst_ring_buffer_parse_caps (&spec, caps))
836     goto out;
837
838   /* Make sure non-raw input is framed (one frame per buffer) and can be
839    * payloaded */
840   st = gst_caps_get_structure (caps, 0);
841
842   if (!g_str_has_prefix (gst_structure_get_name (st), "audio/x-raw")) {
843     gboolean framed = FALSE, parsed = FALSE;
844
845     gst_structure_get_boolean (st, "framed", &framed);
846     gst_structure_get_boolean (st, "parsed", &parsed);
847     if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
848       goto out;
849   }
850
851   ret = TRUE;
852
853 out:
854   if (pad_caps)
855     gst_caps_unref (pad_caps);
856
857   gst_object_unref (pbin);
858
859   return ret;
860 }
861
862 static gboolean
863 gst_pulse_audio_sink_sink_setcaps (GstPad * pad, GstCaps * caps)
864 {
865   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
866   gboolean ret = TRUE;
867
868   GST_PULSE_AUDIO_SINK_LOCK (pbin);
869
870   if (!gst_pad_is_blocked (pbin->sinkpad))
871     gst_pad_set_blocked_async_full (pbin->sink_proxypad, TRUE,
872         proxypad_blocked_cb, gst_object_ref (pbin),
873         (GDestroyNotify) gst_object_unref);
874
875   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
876
877   gst_object_unref (pbin);
878
879   return ret;
880 }
881
882 static GstStateChangeReturn
883 gst_pulse_audio_sink_change_state (GstElement * element,
884     GstStateChange transition)
885 {
886   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (element);
887   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
888
889   /* Nothing to do for upward transitions */
890   switch (transition) {
891     case GST_STATE_CHANGE_PAUSED_TO_READY:
892       GST_PULSE_AUDIO_SINK_LOCK (pbin);
893       if (gst_pad_is_blocked (pbin->sinkpad)) {
894         gst_pad_set_blocked_async_full (pbin->sink_proxypad, FALSE,
895             proxypad_blocked_cb, gst_object_ref (pbin),
896             (GDestroyNotify) gst_object_unref);
897       }
898       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
899       break;
900
901     default:
902       break;
903   }
904
905   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
906   if (ret != GST_STATE_CHANGE_SUCCESS) {
907     GST_DEBUG_OBJECT (pbin, "Base class returned %d on state change", ret);
908     goto out;
909   }
910
911   switch (transition) {
912     case GST_STATE_CHANGE_PAUSED_TO_READY:
913       GST_PULSE_AUDIO_SINK_LOCK (pbin);
914       gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
915
916       if (pbin->dbin2) {
917         GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink),
918             "sink");
919
920         gst_pulse_audio_sink_free_dbin2 (pbin);
921         gst_pulse_audio_sink_update_sinkpad (pbin, pad);
922
923         gst_object_unref (pad);
924
925       }
926       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
927
928       break;
929
930     default:
931       break;
932   }
933
934 out:
935   return ret;
936 }
937
938 #endif /* HAVE_PULSE_1_0 */