0b2e4b84927435f6d6caaba7dcbacf220ffd23df
[platform/upstream/gstreamer.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
57 #include <gst/audio/gstaudioiec61937.h>
58 #include "pulsesink.h"
59
60 GST_DEBUG_CATEGORY (pulseaudiosink_debug);
61 #define GST_CAT_DEFAULT (pulseaudiosink_debug)
62
63 #define GST_PULSE_AUDIO_SINK_LOCK(obj) G_STMT_START {                    \
64     GST_LOG_OBJECT (obj,                                              \
65                     "locking from thread %p",                         \
66                     g_thread_self ());                                \
67     g_mutex_lock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock);                 \
68     GST_LOG_OBJECT (obj,                                              \
69                     "locked from thread %p",                          \
70                     g_thread_self ());                                \
71 } G_STMT_END
72
73 #define GST_PULSE_AUDIO_SINK_UNLOCK(obj) G_STMT_START {                  \
74     GST_LOG_OBJECT (obj,                                              \
75                     "unlocking from thread %p",                       \
76                     g_thread_self ());                                \
77     g_mutex_unlock (GST_PULSE_AUDIO_SINK_CAST(obj)->lock);               \
78 } G_STMT_END
79
80 typedef struct
81 {
82   GstBin parent;
83   GMutex *lock;
84
85   GstPad *sinkpad;
86   GstPad *sink_proxypad;
87   GstPadEventFunction sinkpad_old_eventfunc;
88   GstPadEventFunction proxypad_old_eventfunc;
89
90   GstPulseSink *psink;
91   GstElement *dbin2;
92
93   GstSegment segment;
94
95   guint event_probe_id;
96   gulong pad_added_id;
97
98   gboolean format_lost;
99 } GstPulseAudioSink;
100
101 typedef struct
102 {
103   GstBinClass parent_class;
104   guint n_prop_own;
105   guint n_prop_total;
106 } GstPulseAudioSinkClass;
107
108 static void gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
109     GValue * value, GParamSpec * pspec);
110 static void gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
111     const GValue * value, GParamSpec * pspec);
112 static void gst_pulse_audio_sink_dispose (GObject * object);
113 static gboolean gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event);
114 static gboolean gst_pulse_audio_sink_sink_event (GstPad * pad,
115     GstEvent * event);
116 static gboolean gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad,
117     GstCaps * caps);
118 static gboolean gst_pulse_audio_sink_sink_setcaps (GstPad * pad,
119     GstCaps * caps);
120 static GstStateChangeReturn
121 gst_pulse_audio_sink_change_state (GstElement * element,
122     GstStateChange transition);
123
124 static void
125 gst_pulse_audio_sink_do_init (GType type)
126 {
127   GST_DEBUG_CATEGORY_INIT (pulseaudiosink_debug, "pulseaudiosink", 0,
128       "Bin that wraps pulsesink for handling compressed formats");
129 }
130
131 GST_BOILERPLATE_FULL (GstPulseAudioSink, gst_pulse_audio_sink, GstBin,
132     GST_TYPE_BIN, gst_pulse_audio_sink_do_init);
133
134 static GstStaticPadTemplate sink_template =
135 GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
136     GST_STATIC_CAPS (PULSE_SINK_TEMPLATE_CAPS));
137
138 static void
139 gst_pulse_audio_sink_base_init (gpointer klass)
140 {
141   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
142
143   gst_element_class_add_pad_template (element_class,
144       gst_static_pad_template_get (&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   GstPad *pad = NULL;
360   GParamSpec **specs;
361   GString *prop;
362   guint i;
363
364   pbin->lock = g_mutex_new ();
365
366   gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
367
368   pbin->psink = GST_PULSESINK (gst_element_factory_make ("pulsesink",
369           "pulseaudiosink-sink"));
370   g_assert (pbin->psink != NULL);
371
372   if (!gst_bin_add (GST_BIN (pbin), GST_ELEMENT (pbin->psink))) {
373     GST_ERROR_OBJECT (pbin, "Failed to add pulsesink to bin");
374     goto error;
375   }
376
377   pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
378   pbin->sinkpad = gst_ghost_pad_new_from_template ("sink", pad,
379       gst_static_pad_template_get (&sink_template));
380
381   pbin->sinkpad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sinkpad);
382   gst_pad_set_event_function (pbin->sinkpad,
383       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_event));
384   gst_pad_set_setcaps_function (pbin->sinkpad,
385       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_setcaps));
386   gst_pad_set_acceptcaps_function (pbin->sinkpad,
387       GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_sink_acceptcaps));
388
389   gst_element_add_pad (GST_ELEMENT (pbin), pbin->sinkpad);
390
391   if (!(pbin->sink_proxypad = get_proxypad (pbin->sinkpad)))
392     GST_ERROR_OBJECT (pbin, "Failed to get proxypad of srcpad");
393   else {
394     pbin->proxypad_old_eventfunc = GST_PAD_EVENTFUNC (pbin->sink_proxypad);
395     gst_pad_set_event_function (pbin->sink_proxypad,
396         GST_DEBUG_FUNCPTR (gst_pulse_audio_sink_src_event));
397   }
398
399   /* Now proxy all the notify::* signals */
400   specs = g_object_class_list_properties (G_OBJECT_CLASS (klass), &i);
401   prop = g_string_sized_new (30);
402
403   for (i--; i >= klass->n_prop_own; i--) {
404     g_string_printf (prop, "notify::%s", g_param_spec_get_name (specs[i]));
405     g_signal_connect (pbin->psink, prop->str, G_CALLBACK (notify_cb), pbin);
406   }
407
408   g_string_free (prop, TRUE);
409   g_free (specs);
410
411   pbin->format_lost = FALSE;
412
413 out:
414   if (pad)
415     gst_object_unref (pad);
416
417   return;
418
419 error:
420   if (pbin->psink)
421     gst_object_unref (pbin->psink);
422   goto out;
423 }
424
425 static void
426 gst_pulse_audio_sink_set_property (GObject * object, guint prop_id,
427     const GValue * value, GParamSpec * pspec)
428 {
429   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
430   GstPulseAudioSinkClass *klass =
431       GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
432
433   g_return_if_fail (prop_id <= klass->n_prop_total);
434
435   g_object_set_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
436       value);
437 }
438
439 static void
440 gst_pulse_audio_sink_get_property (GObject * object, guint prop_id,
441     GValue * value, GParamSpec * pspec)
442 {
443   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
444   GstPulseAudioSinkClass *klass =
445       GST_PULSE_AUDIO_SINK_CLASS (G_OBJECT_GET_CLASS (object));
446
447   g_return_if_fail (prop_id <= klass->n_prop_total);
448
449   g_object_get_property (G_OBJECT (pbin->psink), g_param_spec_get_name (pspec),
450       value);
451 }
452
453 static void
454 gst_pulse_audio_sink_free_dbin2 (GstPulseAudioSink * pbin)
455 {
456   g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
457   gst_element_set_state (pbin->dbin2, GST_STATE_NULL);
458
459   gst_bin_remove (GST_BIN (pbin), pbin->dbin2);
460
461   pbin->dbin2 = NULL;
462 }
463
464 static void
465 gst_pulse_audio_sink_dispose (GObject * object)
466 {
467   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (object);
468
469   if (pbin->lock) {
470     g_mutex_free (pbin->lock);
471     pbin->lock = NULL;
472   }
473
474   if (pbin->sink_proxypad) {
475     gst_object_unref (pbin->sink_proxypad);
476     pbin->sink_proxypad = NULL;
477   }
478
479   if (pbin->dbin2) {
480     g_signal_handler_disconnect (pbin->dbin2, pbin->pad_added_id);
481     pbin->dbin2 = NULL;
482   }
483
484   pbin->sinkpad = NULL;
485   pbin->psink = NULL;
486
487   G_OBJECT_CLASS (parent_class)->dispose (object);
488 }
489
490 static gboolean
491 gst_pulse_audio_sink_update_sinkpad (GstPulseAudioSink * pbin, GstPad * sinkpad)
492 {
493   gboolean ret;
494
495   ret = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (pbin->sinkpad), sinkpad);
496
497   if (!ret)
498     GST_WARNING_OBJECT (pbin, "Could not update ghostpad target");
499
500   return ret;
501 }
502
503 static void
504 distribute_running_time (GstElement * element, const GstSegment * segment)
505 {
506   GstEvent *event;
507   GstPad *pad;
508
509   pad = gst_element_get_static_pad (element, "sink");
510
511   /* FIXME: Some decoders collect newsegments and send them out at once, making
512    * them lose accumulator events (and thus making dbin2_event_probe() hard to
513    * do right if we're sending these as well. We can get away with not sending
514    * these at the moment, but this should be fixed! */
515 #if 0
516   if (segment->accum) {
517     event = gst_event_new_new_segment_full (FALSE, segment->rate,
518         segment->applied_rate, segment->format, 0, segment->accum, 0);
519     gst_pad_send_event (pad, event);
520   }
521 #endif
522
523   event = gst_event_new_new_segment_full (FALSE, segment->rate,
524       segment->applied_rate, segment->format,
525       segment->start, segment->stop, segment->time);
526   gst_pad_send_event (pad, event);
527
528   gst_object_unref (pad);
529 }
530
531 static gboolean
532 dbin2_event_probe (GstPad * pad, GstMiniObject * obj, gpointer data)
533 {
534   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
535   GstEvent *event = GST_EVENT (obj);
536
537   if (GST_EVENT_TYPE (event) == GST_EVENT_NEWSEGMENT) {
538     GST_DEBUG_OBJECT (pbin, "Got newsegment - dropping");
539     gst_pad_remove_event_probe (pad, pbin->event_probe_id);
540     return FALSE;
541   }
542
543   return TRUE;
544 }
545
546 static void
547 pad_added_cb (GstElement * dbin2, GstPad * pad, gpointer * data)
548 {
549   GstPulseAudioSink *pbin;
550   GstPad *sinkpad = NULL;
551
552   pbin = GST_PULSE_AUDIO_SINK (data);
553   sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
554
555   GST_PULSE_AUDIO_SINK_LOCK (pbin);
556   if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
557     GST_ERROR_OBJECT (pbin, "Failed to link decodebin2 to pulsesink");
558   else
559     GST_DEBUG_OBJECT (pbin, "Linked new pad to pulsesink");
560   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
561
562   gst_object_unref (sinkpad);
563 }
564
565 /* Called with pbin lock held */
566 static void
567 gst_pulse_audio_sink_add_dbin2 (GstPulseAudioSink * pbin)
568 {
569   GstPad *sinkpad = NULL;
570
571   g_assert (pbin->dbin2 == NULL);
572
573   pbin->dbin2 = gst_element_factory_make ("decodebin2", "pulseaudiosink-dbin2");
574
575   if (!pbin->dbin2) {
576     post_missing_element_message (pbin, "decodebin2");
577     GST_ELEMENT_WARNING (pbin, CORE, MISSING_PLUGIN,
578         (_("Missing element '%s' - check your GStreamer installation."),
579             "decodebin2"), ("audio playback might fail"));
580     goto out;
581   }
582
583   if (!gst_bin_add (GST_BIN (pbin), pbin->dbin2)) {
584     GST_ERROR_OBJECT (pbin, "Failed to add decodebin2 to bin");
585     goto out;
586   }
587
588   pbin->pad_added_id = g_signal_connect (pbin->dbin2, "pad-added",
589       G_CALLBACK (pad_added_cb), pbin);
590
591   if (!gst_element_sync_state_with_parent (pbin->dbin2)) {
592     GST_ERROR_OBJECT (pbin, "Failed to set decodebin2 to parent state");
593     goto out;
594   }
595
596   /* Trap the newsegment events that we feed the decodebin and discard them */
597   sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
598   pbin->event_probe_id = gst_pad_add_event_probe_full (sinkpad,
599       G_CALLBACK (dbin2_event_probe), gst_object_ref (pbin),
600       (GDestroyNotify) gst_object_unref);
601   gst_object_unref (sinkpad);
602   sinkpad = NULL;
603
604   GST_DEBUG_OBJECT (pbin, "Distributing running time to decodebin");
605   distribute_running_time (pbin->dbin2, &pbin->segment);
606
607   sinkpad = gst_element_get_static_pad (pbin->dbin2, "sink");
608
609   gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
610
611 out:
612   if (sinkpad)
613     gst_object_unref (sinkpad);
614 }
615
616 static void
617 update_eac3_alignment (GstPulseAudioSink * pbin)
618 {
619   GstCaps *caps = gst_pad_peer_get_caps_reffed (pbin->sinkpad);
620   GstStructure *st;
621
622   if (!caps)
623     return;
624
625   st = gst_caps_get_structure (caps, 0);
626
627   if (g_str_equal (gst_structure_get_name (st), "audio/x-eac3")) {
628     GstStructure *event_st = gst_structure_new ("ac3parse-set-alignment",
629         "alignment", G_TYPE_STRING, pbin->dbin2 ? "frame" : "iec61937", NULL);
630
631     if (!gst_pad_push_event (pbin->sinkpad,
632             gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, event_st)))
633       GST_WARNING_OBJECT (pbin->sinkpad, "Could not update alignment");
634   }
635
636   gst_caps_unref (caps);
637 }
638
639 static void
640 proxypad_blocked_cb (GstPad * pad, gboolean blocked, gpointer data)
641 {
642   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (data);
643   GstCaps *caps;
644   GstPad *sinkpad = NULL;
645
646   if (!blocked) {
647     /* Unblocked, don't need to do anything */
648     GST_DEBUG_OBJECT (pbin, "unblocked");
649     return;
650   }
651
652   GST_DEBUG_OBJECT (pbin, "blocked");
653
654   GST_PULSE_AUDIO_SINK_LOCK (pbin);
655
656   if (!pbin->format_lost) {
657     sinkpad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink), "sink");
658
659     if (GST_PAD_CAPS (pbin->sinkpad)) {
660       /* See if we already got caps on our sinkpad */
661       caps = gst_caps_ref (GST_PAD_CAPS (pbin->sinkpad));
662     } else {
663       /* We haven't, so get caps from upstream */
664       caps = gst_pad_get_caps_reffed (pad);
665     }
666
667     if (gst_pad_accept_caps (sinkpad, caps)) {
668       if (pbin->dbin2) {
669         GST_DEBUG_OBJECT (pbin, "Removing decodebin");
670         gst_pulse_audio_sink_free_dbin2 (pbin);
671         gst_pulse_audio_sink_update_sinkpad (pbin, sinkpad);
672       } else
673         GST_DEBUG_OBJECT (pbin, "Doing nothing");
674
675       gst_caps_unref (caps);
676       gst_object_unref (sinkpad);
677       goto done;
678     }
679     /* pulsesink doesn't accept the incoming caps, so add a decodebin
680      * (potentially after removing the existing once, since decodebin2 can't
681      * renegotiate). */
682   } else {
683     /* Format lost, proceed to try plugging a decodebin */
684     pbin->format_lost = FALSE;
685   }
686
687   if (pbin->dbin2 != NULL) {
688     /* decodebin2 doesn't support reconfiguration, so throw this one away and
689      * create a new one. */
690     gst_pulse_audio_sink_free_dbin2 (pbin);
691   }
692
693   GST_DEBUG_OBJECT (pbin, "Adding decodebin");
694   gst_pulse_audio_sink_add_dbin2 (pbin);
695
696 done:
697   update_eac3_alignment (pbin);
698
699   gst_pad_set_blocked_async_full (pad, FALSE, proxypad_blocked_cb,
700       gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
701
702   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
703 }
704
705 static gboolean
706 gst_pulse_audio_sink_src_event (GstPad * pad, GstEvent * event)
707 {
708   GstPulseAudioSink *pbin = NULL;
709   GstPad *ghostpad = NULL;
710   gboolean ret = FALSE;
711
712   ghostpad = GST_PAD_CAST (gst_pad_get_parent (pad));
713   if (G_UNLIKELY (!ghostpad)) {
714     GST_WARNING_OBJECT (pad, "Could not get ghostpad");
715     goto out;
716   }
717
718   pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (ghostpad));
719   if (G_UNLIKELY (!pbin)) {
720     GST_WARNING_OBJECT (pad, "Could not get pulseaudiosink");
721     goto out;
722   }
723
724   if (G_UNLIKELY (GST_EVENT_TYPE (event) == GST_EVENT_CUSTOM_UPSTREAM) &&
725       (gst_event_has_name (event, "pulse-format-lost") ||
726           gst_event_has_name (event, "pulse-sink-changed"))) {
727     g_return_val_if_fail (pad->mode != GST_ACTIVATE_PULL, FALSE);
728
729     GST_PULSE_AUDIO_SINK_LOCK (pbin);
730     if (gst_event_has_name (event, "pulse-format-lost"))
731       pbin->format_lost = TRUE;
732
733     if (!gst_pad_is_blocked (pad))
734       gst_pad_set_blocked_async_full (pad, TRUE, proxypad_blocked_cb,
735           gst_object_ref (pbin), (GDestroyNotify) gst_object_unref);
736     GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
737
738     ret = TRUE;
739   } else if (pbin->proxypad_old_eventfunc) {
740     ret = pbin->proxypad_old_eventfunc (pad, event);
741     event = NULL;
742   }
743
744 out:
745   if (ghostpad)
746     gst_object_unref (ghostpad);
747   if (pbin)
748     gst_object_unref (pbin);
749   if (event)
750     gst_event_unref (event);
751
752   return ret;
753 }
754
755 static gboolean
756 gst_pulse_audio_sink_sink_event (GstPad * pad, GstEvent * event)
757 {
758   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
759   gboolean ret;
760
761   ret = pbin->sinkpad_old_eventfunc (pad, gst_event_ref (event));
762
763   switch (GST_EVENT_TYPE (event)) {
764     case GST_EVENT_NEWSEGMENT:
765     {
766       GstFormat format;
767       gdouble rate, arate;
768       gint64 start, stop, time;
769       gboolean update;
770
771       GST_PULSE_AUDIO_SINK_LOCK (pbin);
772       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
773           &start, &stop, &time);
774
775       GST_DEBUG_OBJECT (pbin,
776           "newsegment: update %d, rate %g, arate %g, start %" GST_TIME_FORMAT
777           ", stop %" GST_TIME_FORMAT ", time %" GST_TIME_FORMAT,
778           update, rate, arate, GST_TIME_ARGS (start), GST_TIME_ARGS (stop),
779           GST_TIME_ARGS (time));
780
781       if (format == GST_FORMAT_TIME) {
782         /* Store the values for feeding to sub-elements */
783         gst_segment_set_newsegment_full (&pbin->segment, update,
784             rate, arate, format, start, stop, time);
785       } else {
786         GST_WARNING_OBJECT (pbin, "Got a non-TIME format segment");
787         gst_segment_init (&pbin->segment, GST_FORMAT_TIME);
788       }
789       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
790
791       break;
792     }
793
794     case GST_EVENT_FLUSH_STOP:
795       GST_PULSE_AUDIO_SINK_LOCK (pbin);
796       gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
797       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
798       break;
799
800     default:
801       break;
802   }
803
804   gst_object_unref (pbin);
805   gst_event_unref (event);
806
807   return ret;
808 }
809
810 /* The bin's acceptcaps should be exactly equivalent to a pulsesink that is
811  * connected to a sink that supports all the formats in template caps. This
812  * means that upstream will have to have everything possibly upto a parser
813  * plugged and we plugin a decoder whenever required. */
814 static gboolean
815 gst_pulse_audio_sink_sink_acceptcaps (GstPad * pad, GstCaps * caps)
816 {
817   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
818   GstRingBufferSpec spec = { 0 };
819   const GstStructure *st;
820   GstCaps *pad_caps = NULL;
821   gboolean ret = FALSE;
822
823   pad_caps = gst_pad_get_caps_reffed (pad);
824   if (!pad_caps || !gst_caps_can_intersect (pad_caps, caps))
825     goto out;
826
827   /* If we've not got fixed caps, creating a stream might fail, so let's just
828    * return from here with default acceptcaps behaviour */
829   if (!gst_caps_is_fixed (caps))
830     goto out;
831
832   spec.latency_time = GST_BASE_AUDIO_SINK (pbin->psink)->latency_time;
833   if (!gst_ring_buffer_parse_caps (&spec, caps))
834     goto out;
835
836   /* Make sure non-raw input is framed (one frame per buffer) and can be
837    * payloaded */
838   st = gst_caps_get_structure (caps, 0);
839
840   if (!g_str_has_prefix (gst_structure_get_name (st), "audio/x-raw")) {
841     gboolean framed = FALSE, parsed = FALSE;
842
843     gst_structure_get_boolean (st, "framed", &framed);
844     gst_structure_get_boolean (st, "parsed", &parsed);
845     if ((!framed && !parsed) || gst_audio_iec61937_frame_size (&spec) <= 0)
846       goto out;
847   }
848
849   ret = TRUE;
850
851 out:
852   if (pad_caps)
853     gst_caps_unref (pad_caps);
854
855   gst_object_unref (pbin);
856
857   return ret;
858 }
859
860 static gboolean
861 gst_pulse_audio_sink_sink_setcaps (GstPad * pad, GstCaps * caps)
862 {
863   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (gst_pad_get_parent (pad));
864   gboolean ret = TRUE;
865
866   GST_PULSE_AUDIO_SINK_LOCK (pbin);
867
868   if (!gst_pad_is_blocked (pbin->sinkpad))
869     gst_pad_set_blocked_async_full (pbin->sink_proxypad, TRUE,
870         proxypad_blocked_cb, gst_object_ref (pbin),
871         (GDestroyNotify) gst_object_unref);
872
873   GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
874
875   gst_caps_unref (caps);
876   gst_object_unref (pbin);
877
878   return ret;
879 }
880
881 static GstStateChangeReturn
882 gst_pulse_audio_sink_change_state (GstElement * element,
883     GstStateChange transition)
884 {
885   GstPulseAudioSink *pbin = GST_PULSE_AUDIO_SINK (element);
886   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
887
888   /* Nothing to do for upward transitions */
889   switch (transition) {
890     case GST_STATE_CHANGE_PAUSED_TO_READY:
891       GST_PULSE_AUDIO_SINK_LOCK (pbin);
892       if (gst_pad_is_blocked (pbin->sinkpad)) {
893         gst_pad_set_blocked_async_full (pbin->sink_proxypad, FALSE,
894             proxypad_blocked_cb, gst_object_ref (pbin),
895             (GDestroyNotify) gst_object_unref);
896       }
897       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
898       break;
899
900     default:
901       break;
902   }
903
904   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
905   if (ret != GST_STATE_CHANGE_SUCCESS) {
906     GST_DEBUG_OBJECT (pbin, "Base class returned %d on state change", ret);
907     goto out;
908   }
909
910   switch (transition) {
911     case GST_STATE_CHANGE_PAUSED_TO_READY:
912       GST_PULSE_AUDIO_SINK_LOCK (pbin);
913       gst_segment_init (&pbin->segment, GST_FORMAT_UNDEFINED);
914
915       if (pbin->dbin2) {
916         GstPad *pad = gst_element_get_static_pad (GST_ELEMENT (pbin->psink),
917             "sink");
918
919         gst_pulse_audio_sink_free_dbin2 (pbin);
920         gst_pulse_audio_sink_update_sinkpad (pbin, pad);
921
922         gst_object_unref (pad);
923
924       }
925       GST_PULSE_AUDIO_SINK_UNLOCK (pbin);
926
927       break;
928
929     default:
930       break;
931   }
932
933 out:
934   return ret;
935 }
936
937 #endif /* HAVE_PULSE_1_0 */