gst/gstbin.c: Make default message forwarding from child->bus to bin->bus threadsafe...
[platform/upstream/gstreamer.git] / gst / gstbin.c
1 /* GStreamer
2  *
3  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
4  *                    2004 Wim Taymans <wim@fluendo.com>
5  *
6  * gstbin.c: GstBin container object and support code
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  * MT safe.
24  */
25
26 #include "gst_private.h"
27
28 #include "gstevent.h"
29 #include "gstbin.h"
30 #include "gstmarshal.h"
31 #include "gstxml.h"
32 #include "gstinfo.h"
33 #include "gsterror.h"
34
35 #include "gstindex.h"
36 #include "gstutils.h"
37
38 GST_DEBUG_CATEGORY_STATIC (bin_debug);
39 #define GST_CAT_DEFAULT bin_debug
40 #define GST_LOG_BIN_CONTENTS(bin, text) GST_LOG_OBJECT ((bin), \
41         text ": %d elements: %u PLAYING, %u PAUSED, %u READY, %u NULL, own state: %s", \
42         (bin)->numchildren, (guint) (bin)->child_states[3], \
43         (guint) (bin)->child_states[2], (bin)->child_states[1], \
44         (bin)->child_states[0], gst_element_state_get_name (GST_STATE (bin)))
45
46
47 static GstElementDetails gst_bin_details = GST_ELEMENT_DETAILS ("Generic bin",
48     "Generic/Bin",
49     "Simple container object",
50     "Erik Walthinsen <omega@cse.ogi.edu>," "Wim Taymans <wim@fluendo.com>");
51
52 GType _gst_bin_type = 0;
53
54 static void gst_bin_dispose (GObject * object);
55
56 static GstElementStateReturn gst_bin_change_state (GstElement * element);
57 static GstElementStateReturn gst_bin_get_state (GstElement * element,
58     GstElementState * state, GstElementState * pending, GTimeVal * timeout);
59
60 static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
61 static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
62
63 #ifndef GST_DISABLE_INDEX
64 static void gst_bin_set_index_func (GstElement * element, GstIndex * index);
65 #endif
66 static GstClock *gst_bin_get_clock_func (GstElement * element);
67 static void gst_bin_set_clock_func (GstElement * element, GstClock * clock);
68
69 static gboolean gst_bin_send_event (GstElement * element, GstEvent * event);
70 static GstBusSyncReply bin_bus_handler (GstBus * bus,
71     GstMessage * message, GstBin * bin);
72 static gboolean gst_bin_query (GstElement * element, GstQuery * query);
73
74 #ifndef GST_DISABLE_LOADSAVE
75 static xmlNodePtr gst_bin_save_thyself (GstObject * object, xmlNodePtr parent);
76 static void gst_bin_restore_thyself (GstObject * object, xmlNodePtr self);
77 #endif
78
79 static gint bin_element_is_sink (GstElement * child, GstBin * bin);
80
81 /* Bin signals and args */
82 enum
83 {
84   ELEMENT_ADDED,
85   ELEMENT_REMOVED,
86   LAST_SIGNAL
87 };
88
89 enum
90 {
91   ARG_0
92       /* FILL ME */
93 };
94
95 static void gst_bin_base_init (gpointer g_class);
96 static void gst_bin_class_init (GstBinClass * klass);
97 static void gst_bin_init (GstBin * bin);
98
99 static GstElementClass *parent_class = NULL;
100 static guint gst_bin_signals[LAST_SIGNAL] = { 0 };
101
102 /**
103  * gst_bin_get_type:
104  *
105  * Returns: the type of #GstBin
106  */
107 GType
108 gst_bin_get_type (void)
109 {
110   if (!_gst_bin_type) {
111     static const GTypeInfo bin_info = {
112       sizeof (GstBinClass),
113       gst_bin_base_init,
114       NULL,
115       (GClassInitFunc) gst_bin_class_init,
116       NULL,
117       NULL,
118       sizeof (GstBin),
119       0,
120       (GInstanceInitFunc) gst_bin_init,
121       NULL
122     };
123
124     _gst_bin_type =
125         g_type_register_static (GST_TYPE_ELEMENT, "GstBin", &bin_info, 0);
126
127     GST_DEBUG_CATEGORY_INIT (bin_debug, "bin", GST_DEBUG_BOLD,
128         "debugging info for the 'bin' container element");
129   }
130   return _gst_bin_type;
131 }
132
133 static void
134 gst_bin_base_init (gpointer g_class)
135 {
136   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
137
138   gst_element_class_set_details (gstelement_class, &gst_bin_details);
139 }
140
141 static void
142 gst_bin_class_init (GstBinClass * klass)
143 {
144   GObjectClass *gobject_class;
145   GstObjectClass *gstobject_class;
146   GstElementClass *gstelement_class;
147
148   gobject_class = (GObjectClass *) klass;
149   gstobject_class = (GstObjectClass *) klass;
150   gstelement_class = (GstElementClass *) klass;
151
152   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
153
154   gst_bin_signals[ELEMENT_ADDED] =
155       g_signal_new ("element-added", G_TYPE_FROM_CLASS (klass),
156       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_added), NULL,
157       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
158   gst_bin_signals[ELEMENT_REMOVED] =
159       g_signal_new ("element-removed", G_TYPE_FROM_CLASS (klass),
160       G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GstBinClass, element_removed), NULL,
161       NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
162
163   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_bin_dispose);
164
165 #ifndef GST_DISABLE_LOADSAVE
166   gstobject_class->save_thyself = GST_DEBUG_FUNCPTR (gst_bin_save_thyself);
167   gstobject_class->restore_thyself =
168       GST_DEBUG_FUNCPTR (gst_bin_restore_thyself);
169 #endif
170
171   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_bin_change_state);
172   gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state);
173 #ifndef GST_DISABLE_INDEX
174   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
175 #endif
176   gstelement_class->get_clock = GST_DEBUG_FUNCPTR (gst_bin_get_clock_func);
177   gstelement_class->set_clock = GST_DEBUG_FUNCPTR (gst_bin_set_clock_func);
178
179   gstelement_class->send_event = GST_DEBUG_FUNCPTR (gst_bin_send_event);
180   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_bin_query);
181
182   klass->add_element = GST_DEBUG_FUNCPTR (gst_bin_add_func);
183   klass->remove_element = GST_DEBUG_FUNCPTR (gst_bin_remove_func);
184 }
185
186 static void
187 gst_bin_init (GstBin * bin)
188 {
189   GstBus *bus;
190
191   bin->numchildren = 0;
192   bin->children = NULL;
193   bin->children_cookie = 0;
194   bin->eosed = NULL;
195
196   /* Set up a bus for listening to child elements,
197    * and one for sending messages up the hierarchy */
198   bus = g_object_new (gst_bus_get_type (), NULL);
199   bin->child_bus = bus;
200   gst_bus_set_sync_handler (bus, (GstBusSyncHandler) bin_bus_handler, bin);
201
202   bus = g_object_new (gst_bus_get_type (), NULL);
203   gst_element_set_bus (GST_ELEMENT (bin), bus);
204   /* set_bus refs the bus via gst_object_replace, we drop our ref */
205   gst_object_unref (bus);
206 }
207
208 /**
209  * gst_bin_new:
210  * @name: name of new bin
211  *
212  * Create a new bin with given name.
213  *
214  * Returns: new bin
215  */
216 GstElement *
217 gst_bin_new (const gchar * name)
218 {
219   return gst_element_factory_make ("bin", name);
220 }
221
222 /* set the index on all elements in this bin
223  *
224  * MT safe
225  */
226 #ifndef GST_DISABLE_INDEX
227 static void
228 gst_bin_set_index_func (GstElement * element, GstIndex * index)
229 {
230   GstBin *bin;
231   GList *children;
232
233   bin = GST_BIN (element);
234
235   GST_LOCK (bin);
236   for (children = bin->children; children; children = g_list_next (children)) {
237     GstElement *child = GST_ELEMENT (children->data);
238
239     gst_element_set_index (child, index);
240   }
241   GST_UNLOCK (bin);
242 }
243 #endif
244
245 /* set the clock on all elements in this bin
246  *
247  * MT safe
248  */
249 static void
250 gst_bin_set_clock_func (GstElement * element, GstClock * clock)
251 {
252   GList *children;
253   GstBin *bin;
254
255   bin = GST_BIN (element);
256
257   GST_LOCK (bin);
258   for (children = bin->children; children; children = g_list_next (children)) {
259     GstElement *child = GST_ELEMENT (children->data);
260
261     gst_element_set_clock (child, clock);
262   }
263   GST_UNLOCK (bin);
264 }
265
266 /* get the clock for this bin by asking all of the children in this bin
267  *
268  * MT safe
269  */
270 static GstClock *
271 gst_bin_get_clock_func (GstElement * element)
272 {
273   GstClock *result = NULL;
274   GstBin *bin;
275   GList *children;
276
277   bin = GST_BIN (element);
278
279   GST_LOCK (bin);
280   for (children = bin->children; children; children = g_list_next (children)) {
281     GstElement *child = GST_ELEMENT (children->data);
282
283     result = gst_element_get_clock (child);
284     if (result)
285       break;
286   }
287   GST_UNLOCK (bin);
288
289   return result;
290 }
291
292 static gboolean
293 is_eos (GstBin * bin)
294 {
295   GstIterator *sinks;
296   gboolean result = TRUE;
297   gboolean done = FALSE;
298
299   sinks = gst_bin_iterate_sinks (bin);
300   while (!done) {
301     gpointer data;
302
303     switch (gst_iterator_next (sinks, &data)) {
304       case GST_ITERATOR_OK:
305       {
306         GstElement *element = GST_ELEMENT (data);
307         GList *eosed;
308         gchar *name;
309
310         name = gst_element_get_name (element);
311         eosed = g_list_find (bin->eosed, element);
312         if (!eosed) {
313           GST_DEBUG ("element %s did not post EOS yet", name);
314           result = FALSE;
315           done = TRUE;
316         } else {
317           GST_DEBUG ("element %s posted EOS", name);
318         }
319         g_free (name);
320         gst_object_unref (element);
321         break;
322       }
323       case GST_ITERATOR_RESYNC:
324         result = TRUE;
325         gst_iterator_resync (sinks);
326         break;
327       case GST_ITERATOR_DONE:
328         done = TRUE;
329         break;
330       default:
331         g_assert_not_reached ();
332         break;
333     }
334   }
335   gst_iterator_free (sinks);
336   return result;
337 }
338
339 static void
340 unlink_pads (GstPad * pad)
341 {
342   GstPad *peer;
343
344   if ((peer = gst_pad_get_peer (pad))) {
345     if (gst_pad_get_direction (pad) == GST_PAD_SRC)
346       gst_pad_unlink (pad, peer);
347     else
348       gst_pad_unlink (peer, pad);
349     gst_object_unref (peer);
350   }
351   gst_object_unref (pad);
352 }
353
354 /* add an element to this bin
355  *
356  * MT safe
357  */
358 static gboolean
359 gst_bin_add_func (GstBin * bin, GstElement * element)
360 {
361   gchar *elem_name;
362   GstIterator *it;
363
364   /* we obviously can't add ourself to ourself */
365   if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin)))
366     goto adding_itself;
367
368   /* get the element name to make sure it is unique in this bin. */
369   GST_LOCK (element);
370   elem_name = g_strdup (GST_ELEMENT_NAME (element));
371   GST_UNLOCK (element);
372
373   GST_LOCK (bin);
374
375   /* then check to see if the element's name is already taken in the bin,
376    * we can safely take the lock here. This check is probably bogus because
377    * you can safely change the element name after this check and before setting
378    * the object parent. The window is very small though... */
379   if (G_UNLIKELY (!gst_object_check_uniqueness (bin->children, elem_name)))
380     goto duplicate_name;
381
382   /* set the element's parent and add the element to the bin's list of children */
383   if (G_UNLIKELY (!gst_object_set_parent (GST_OBJECT_CAST (element),
384               GST_OBJECT_CAST (bin))))
385     goto had_parent;
386
387   /* if we add a sink we become a sink */
388   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK))
389     GST_FLAG_SET (bin, GST_ELEMENT_IS_SINK);
390
391   bin->children = g_list_prepend (bin->children, element);
392   bin->numchildren++;
393   bin->children_cookie++;
394
395   /* distribute the bus */
396   gst_element_set_bus (element, bin->child_bus);
397
398   /* propagate the current base time and clock */
399   gst_element_set_base_time (element, GST_ELEMENT (bin)->base_time);
400   gst_element_set_clock (element, GST_ELEMENT_CLOCK (bin));
401
402   GST_UNLOCK (bin);
403
404   /* unlink all linked pads */
405   it = gst_element_iterate_pads (element);
406   gst_iterator_foreach (it, (GFunc) unlink_pads, element);
407   gst_iterator_free (it);
408
409   GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, "added element \"%s\"",
410       elem_name);
411   g_free (elem_name);
412
413   g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_ADDED], 0, element);
414
415   return TRUE;
416
417   /* ERROR handling here */
418 adding_itself:
419   {
420     GST_LOCK (bin);
421     g_warning ("Cannot add bin %s to itself", GST_ELEMENT_NAME (bin));
422     GST_UNLOCK (bin);
423     return FALSE;
424   }
425 duplicate_name:
426   {
427     g_warning ("Name %s is not unique in bin %s, not adding",
428         elem_name, GST_ELEMENT_NAME (bin));
429     GST_UNLOCK (bin);
430     g_free (elem_name);
431     return FALSE;
432   }
433 had_parent:
434   {
435     g_warning ("Element %s already has parent", elem_name);
436     GST_UNLOCK (bin);
437     g_free (elem_name);
438     return FALSE;
439   }
440 }
441
442
443 /**
444  * gst_bin_add:
445  * @bin: #GstBin to add element to
446  * @element: #GstElement to add to bin
447  *
448  * Adds the given element to the bin.  Sets the element's parent, and thus
449  * takes ownership of the element. An element can only be added to one bin.
450  *
451  * If the element's pads are linked to other pads, the pads will be unlinked
452  * before the element is added to the bin.
453  *
454  * MT safe.
455  *
456  * Returns: TRUE if the element could be added, FALSE on wrong parameters or
457  * the bin does not want to accept the element.
458  */
459 gboolean
460 gst_bin_add (GstBin * bin, GstElement * element)
461 {
462   GstBinClass *bclass;
463   gboolean result;
464
465   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
466   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
467
468   bclass = GST_BIN_GET_CLASS (bin);
469
470   if (G_UNLIKELY (bclass->add_element == NULL))
471     goto no_function;
472
473   GST_CAT_DEBUG (GST_CAT_PARENTAGE, "adding element %s to bin %s",
474       GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
475
476   result = bclass->add_element (bin, element);
477
478   return result;
479
480   /* ERROR handling */
481 no_function:
482   {
483     g_warning ("adding elements to bin %s is not supported",
484         GST_ELEMENT_NAME (bin));
485     return FALSE;
486   }
487 }
488
489 /* remove an element from the bin
490  *
491  * MT safe
492  */
493 static gboolean
494 gst_bin_remove_func (GstBin * bin, GstElement * element)
495 {
496   gchar *elem_name;
497   GstIterator *it;
498
499   /* grab element name so we can print it */
500   GST_LOCK (element);
501   elem_name = g_strdup (GST_ELEMENT_NAME (element));
502   GST_UNLOCK (element);
503
504   GST_LOCK (bin);
505   /* the element must be in the bin's list of children */
506   if (G_UNLIKELY (g_list_find (bin->children, element) == NULL))
507     goto not_in_bin;
508
509   /* now remove the element from the list of elements */
510   bin->children = g_list_remove (bin->children, element);
511   bin->numchildren--;
512   bin->children_cookie++;
513
514   /* check if we removed a sink */
515   if (GST_FLAG_IS_SET (element, GST_ELEMENT_IS_SINK)) {
516     GList *other_sink;
517
518     /* check if we removed the last sink */
519     other_sink = g_list_find_custom (bin->children,
520         bin, (GCompareFunc) bin_element_is_sink);
521     if (!other_sink) {
522       /* yups, we're not a sink anymore */
523       GST_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK);
524     }
525   }
526   GST_UNLOCK (bin);
527
528   GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"",
529       elem_name);
530   g_free (elem_name);
531
532   /* unlink all linked pads */
533   it = gst_element_iterate_pads (element);
534   gst_iterator_foreach (it, (GFunc) unlink_pads, element);
535   gst_iterator_free (it);
536
537   gst_element_set_bus (element, NULL);
538
539   /* unlock any waiters for the state change. It is possible that
540    * we are waiting for an ASYNC state change on this element. The
541    * element cannot be added to another bin yet as it is not yet
542    * unparented. */
543   GST_STATE_LOCK (element);
544   GST_STATE_BROADCAST (element);
545   GST_STATE_UNLOCK (element);
546
547   /* we ref here because after the _unparent() the element can be disposed
548    * and we still need it to fire a signal. */
549   gst_object_ref (element);
550   gst_object_unparent (GST_OBJECT_CAST (element));
551
552   g_signal_emit (G_OBJECT (bin), gst_bin_signals[ELEMENT_REMOVED], 0, element);
553   /* element is really out of our control now */
554   gst_object_unref (element);
555
556   return TRUE;
557
558   /* ERROR handling */
559 not_in_bin:
560   {
561     g_warning ("Element %s is not in bin %s", elem_name,
562         GST_ELEMENT_NAME (bin));
563     GST_UNLOCK (bin);
564     g_free (elem_name);
565     return FALSE;
566   }
567 }
568
569 /**
570  * gst_bin_remove:
571  * @bin: #GstBin to remove element from
572  * @element: #GstElement to remove
573  *
574  * Remove the element from its associated bin, unparenting it as well.
575  * Unparenting the element means that the element will be dereferenced,
576  * so if the bin holds the only reference to the element, the element
577  * will be freed in the process of removing it from the bin.  If you
578  * want the element to still exist after removing, you need to call
579  * #gst_object_ref before removing it from the bin.
580  *
581  * If the element's pads are linked to other pads, the pads will be unlinked
582  * before the element is removed from the bin.
583  *
584  * MT safe.
585  *
586  * Returns: TRUE if the element could be removed, FALSE on wrong parameters or
587  * the bin does not want to remove the element.
588  */
589 gboolean
590 gst_bin_remove (GstBin * bin, GstElement * element)
591 {
592   GstBinClass *bclass;
593   gboolean result;
594
595   g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
596   g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
597
598   bclass = GST_BIN_GET_CLASS (bin);
599
600   if (G_UNLIKELY (bclass->remove_element == NULL))
601     goto no_function;
602
603   GST_CAT_DEBUG (GST_CAT_PARENTAGE, "removing element %s from bin %s",
604       GST_ELEMENT_NAME (element), GST_ELEMENT_NAME (bin));
605
606   result = bclass->remove_element (bin, element);
607
608   return result;
609
610   /* ERROR handling */
611 no_function:
612   {
613     g_warning ("removing elements from bin %s is not supported",
614         GST_ELEMENT_NAME (bin));
615     return FALSE;
616   }
617 }
618
619 static GstIteratorItem
620 iterate_child (GstIterator * it, GstElement * child)
621 {
622   gst_object_ref (child);
623   return GST_ITERATOR_ITEM_PASS;
624 }
625
626 /**
627  * gst_bin_iterate_elements:
628  * @bin: #Gstbin to iterate the elements of
629  *
630  * Get an iterator for the elements in this bin.
631  * Each element will have its refcount increased, so unref
632  * after use.
633  *
634  * MT safe.
635  *
636  * Returns: a #GstIterator of #GstElements. gst_iterator_free after
637  * use. returns NULL when passing bad parameters.
638  */
639 GstIterator *
640 gst_bin_iterate_elements (GstBin * bin)
641 {
642   GstIterator *result;
643
644   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
645
646   GST_LOCK (bin);
647   /* add ref because the iterator refs the bin. When the iterator
648    * is freed it will unref the bin again using the provided dispose
649    * function. */
650   gst_object_ref (bin);
651   result = gst_iterator_new_list (GST_GET_LOCK (bin),
652       &bin->children_cookie,
653       &bin->children,
654       bin,
655       (GstIteratorItemFunction) iterate_child,
656       (GstIteratorDisposeFunction) gst_object_unref);
657   GST_UNLOCK (bin);
658
659   return result;
660 }
661
662 static GstIteratorItem
663 iterate_child_recurse (GstIterator * it, GstElement * child)
664 {
665   gst_object_ref (child);
666   if (GST_IS_BIN (child)) {
667     GstIterator *other = gst_bin_iterate_recurse (GST_BIN (child));
668
669     gst_iterator_push (it, other);
670   }
671   return GST_ITERATOR_ITEM_PASS;
672 }
673
674 /**
675  * gst_bin_iterate_recurse:
676  * @bin: #Gstbin to iterate the elements of
677  *
678  * Get an iterator for the elements in this bin.
679  * Each element will have its refcount increased, so unref
680  * after use. This iterator recurses into GstBin children.
681  *
682  * MT safe.
683  *
684  * Returns: a #GstIterator of #GstElements. gst_iterator_free after
685  * use. returns NULL when passing bad parameters.
686  */
687 GstIterator *
688 gst_bin_iterate_recurse (GstBin * bin)
689 {
690   GstIterator *result;
691
692   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
693
694   GST_LOCK (bin);
695   /* add ref because the iterator refs the bin. When the iterator
696    * is freed it will unref the bin again using the provided dispose
697    * function. */
698   gst_object_ref (bin);
699   result = gst_iterator_new_list (GST_GET_LOCK (bin),
700       &bin->children_cookie,
701       &bin->children,
702       bin,
703       (GstIteratorItemFunction) iterate_child_recurse,
704       (GstIteratorDisposeFunction) gst_object_unref);
705   GST_UNLOCK (bin);
706
707   return result;
708 }
709
710 /* returns 0 when TRUE because this is a GCompareFunc */
711 /* MT safe */
712 static gint
713 bin_element_is_sink (GstElement * child, GstBin * bin)
714 {
715   gboolean is_sink;
716
717   /* we lock the child here for the remainder of the function to
718    * get its name safely. */
719   GST_LOCK (child);
720   is_sink = GST_FLAG_IS_SET (child, GST_ELEMENT_IS_SINK);
721
722   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
723       "child %s %s sink", GST_OBJECT_NAME (child), is_sink ? "is" : "is not");
724
725   GST_UNLOCK (child);
726   return is_sink ? 0 : 1;
727 }
728
729 /* check if object has the given ancestor somewhere up in
730  * the hierarchy
731  */
732 static gboolean
733 has_ancestor (GstObject * object, GstObject * ancestor)
734 {
735   GstObject *parent;
736   gboolean result = FALSE;
737
738   if (object == NULL)
739     return FALSE;
740
741   if (object == ancestor)
742     return TRUE;
743
744   parent = gst_object_get_parent (object);
745   result = has_ancestor (parent, ancestor);
746   if (parent)
747     gst_object_unref (parent);
748
749   return result;
750 }
751
752 /* returns 0 when TRUE because this is a GCompareFunc.
753  * This function returns elements that have no connected srcpads and
754  * are therefore not reachable from a real sink. */
755 /* MT safe */
756 static gint
757 bin_element_is_semi_sink (GstElement * child, GstBin * bin)
758 {
759   int ret = 1;
760
761   /* we lock the child here for the remainder of the function to
762    * get its pads and name safely. */
763   GST_LOCK (child);
764
765   /* check if this is a sink element, these are the elements
766    * without (linked) source pads. */
767   if (child->numsrcpads == 0) {
768     /* shortcut */
769     GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
770         "adding child %s as sink", GST_OBJECT_NAME (child));
771     ret = 0;
772   } else {
773     /* loop over all pads, try to figure out if this element
774      * is a semi sink because it has no linked source pads */
775     GList *pads;
776     gboolean connected_src = FALSE;
777
778     for (pads = child->srcpads; pads; pads = g_list_next (pads)) {
779       GstPad *peer;
780
781       if ((peer = gst_pad_get_peer (GST_PAD_CAST (pads->data)))) {
782         connected_src =
783             has_ancestor (GST_OBJECT_CAST (peer), GST_OBJECT_CAST (bin));
784         gst_object_unref (peer);
785         if (connected_src) {
786           break;
787         }
788       }
789     }
790     if (connected_src) {
791       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
792           "not adding child %s as sink: linked source pads",
793           GST_OBJECT_NAME (child));
794     } else {
795       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, bin,
796           "adding child %s as sink since it has unlinked source pads in this bin",
797           GST_OBJECT_NAME (child));
798       ret = 0;
799     }
800   }
801   GST_UNLOCK (child);
802
803   return ret;
804 }
805
806 static gint
807 sink_iterator_filter (GstElement * child, GstBin * bin)
808 {
809   if (bin_element_is_sink (child, bin) == 0) {
810     /* returns 0 because this is a GCompareFunc */
811     return 0;
812   } else {
813     /* child carries a ref from gst_bin_iterate_elements -- drop if not passing
814        through */
815     gst_object_unref ((GstObject *) child);
816     return 1;
817   }
818 }
819
820 /**
821  * gst_bin_iterate_sinks:
822  * @bin: #Gstbin to iterate on
823  *
824  * Get an iterator for the sink elements in this bin.
825  * Each element will have its refcount increased, so unref
826  * after use.
827  *
828  * The sink elements are those without any linked srcpads.
829  *
830  * MT safe.
831  *
832  * Returns: a #GstIterator of #GstElements. gst_iterator_free after use.
833  */
834 GstIterator *
835 gst_bin_iterate_sinks (GstBin * bin)
836 {
837   GstIterator *children;
838   GstIterator *result;
839
840   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
841
842   children = gst_bin_iterate_elements (bin);
843   result = gst_iterator_filter (children,
844       (GCompareFunc) sink_iterator_filter, bin);
845
846   return result;
847 }
848
849 /* 2 phases:
850  *  1) check state of all children with 0 timeout to find ERROR and
851  *     NO_PREROLL elements. return if found.
852  *  2) perform full blocking wait with requested timeout.
853  *
854  * 2) cannot be performed when 1) returns results as the sinks might
855  *    not be able to complete the state change making 2) block forever.
856  *
857  * MT safe
858  */
859 static GstElementStateReturn
860 gst_bin_get_state (GstElement * element, GstElementState * state,
861     GstElementState * pending, GTimeVal * timeout)
862 {
863   GstBin *bin = GST_BIN (element);
864   GstElementStateReturn ret = GST_STATE_SUCCESS;
865   GList *children;
866   guint32 children_cookie;
867   gboolean have_no_preroll;
868
869   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "getting state");
870
871   /* lock bin, no element can be added or removed between going into
872    * the quick scan and the blocking wait. */
873   GST_LOCK (bin);
874
875 restart:
876   have_no_preroll = FALSE;
877
878   /* first we need to poll with a non zero timeout to make sure we don't block
879    * on the sinks when we have NO_PREROLL elements. This is why we do
880    * a quick check if there are still NO_PREROLL elements. We also
881    * catch the error elements this way. */
882   {
883     GTimeVal tv;
884     gboolean have_async = FALSE;
885
886     GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "checking for NO_PREROLL");
887     /* use 0 timeout so we don't block on the sinks */
888     GST_TIME_TO_TIMEVAL (0, tv);
889     children = bin->children;
890     children_cookie = bin->children_cookie;
891     while (children) {
892       GstElement *child = GST_ELEMENT_CAST (children->data);
893
894       gst_object_ref (child);
895       /* now we release the lock to enter a non blocking wait. We 
896        * release the lock anyway since we can. */
897       GST_UNLOCK (bin);
898
899       ret = gst_element_get_state (child, NULL, NULL, &tv);
900
901       gst_object_unref (child);
902
903       /* now grab the lock to iterate to the next child */
904       GST_LOCK (bin);
905       if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
906         /* child added/removed during state change, restart. We need
907          * to restart with the quick check as a no-preroll element could
908          * have been added here and we don't want to block on sinks then.*/
909         goto restart;
910       }
911
912       switch (ret) {
913           /* report FAILURE  immediatly */
914         case GST_STATE_FAILURE:
915           goto done;
916         case GST_STATE_NO_PREROLL:
917           /* we have to continue scanning as there might be
918            * ERRORS too */
919           have_no_preroll = TRUE;
920           break;
921         case GST_STATE_ASYNC:
922           have_async = TRUE;
923           break;
924         default:
925           break;
926       }
927       children = g_list_next (children);
928     }
929     /* if we get here, we have no FAILURES, check for any NO_PREROLL
930      * elements then. */
931     if (have_no_preroll) {
932       ret = GST_STATE_NO_PREROLL;
933       goto done;
934     }
935
936     /* if we get here, no NO_PREROLL elements are in the pipeline */
937     GST_CAT_INFO_OBJECT (GST_CAT_STATES, element, "no NO_PREROLL elements");
938
939     /* if no ASYNC elements exist we don't even have to poll with a
940      * timeout again */
941     if (!have_async) {
942       ret = GST_STATE_SUCCESS;
943       goto done;
944     }
945   }
946
947   /* next we poll all children for their state to see if one of them
948    * is still busy with its state change. We did not release the bin lock
949    * yet so the elements are the same as the ones from the quick scan. */
950   children = bin->children;
951   children_cookie = bin->children_cookie;
952   while (children) {
953     GstElement *child = GST_ELEMENT_CAST (children->data);
954
955     gst_object_ref (child);
956     /* now we release the lock to enter the potentialy blocking wait */
957     GST_UNLOCK (bin);
958
959     /* ret is ASYNC if some child is still performing the state change
960      * ater the timeout. */
961     ret = gst_element_get_state (child, NULL, NULL, timeout);
962
963     gst_object_unref (child);
964
965     /* now grab the lock to iterate to the next child */
966     GST_LOCK (bin);
967     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
968       /* child added/removed during state change, restart. We need
969        * to restart with the quick check as a no-preroll element could
970        * have been added here and we don't want to block on sinks then.*/
971       goto restart;
972     }
973
974     switch (ret) {
975       case GST_STATE_SUCCESS:
976         break;
977       case GST_STATE_FAILURE:
978       case GST_STATE_NO_PREROLL:
979         /* report FAILURE and NO_PREROLL immediatly */
980         goto done;
981       case GST_STATE_ASYNC:
982         goto done;
983       default:
984         g_assert_not_reached ();
985     }
986     children = g_list_next (children);
987   }
988   /* if we got here, all elements can do preroll */
989   have_no_preroll = FALSE;
990
991 done:
992   GST_UNLOCK (bin);
993
994   /* now we can take the state lock, it is possible that new elements
995    * are added now and we still report the old state. No problem though as
996    * the return is still consistent, the effect is as if the element was
997    * added after this function completed. */
998   GST_STATE_LOCK (bin);
999   switch (ret) {
1000     case GST_STATE_SUCCESS:
1001       /* we can commit the state */
1002       gst_element_commit_state (element);
1003       break;
1004     case GST_STATE_FAILURE:
1005       /* some element failed, abort the state change */
1006       gst_element_abort_state (element);
1007       break;
1008     default:
1009       /* other cases are just passed along */
1010       break;
1011   }
1012
1013   /* and report the state if needed */
1014   if (state)
1015     *state = GST_STATE (element);
1016   if (pending)
1017     *pending = GST_STATE_PENDING (element);
1018
1019   GST_STATE_NO_PREROLL (element) = have_no_preroll;
1020
1021   GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1022       "state current: %s, pending: %s, error: %d, no_preroll: %d, result: %d",
1023       gst_element_state_get_name (GST_STATE (element)),
1024       gst_element_state_get_name (GST_STATE_PENDING (element)),
1025       GST_STATE_ERROR (element), GST_STATE_NO_PREROLL (element), ret);
1026
1027   GST_STATE_UNLOCK (bin);
1028
1029   return ret;
1030 }
1031
1032 static void
1033 append_child (gpointer child, GQueue * queue)
1034 {
1035   g_queue_push_tail (queue, child);
1036 }
1037
1038 /**
1039  * gst_bin_iterate_state_order:
1040  * @bin: #Gstbin to iterate on
1041  *
1042  * Get an iterator for the elements in this bin in the order
1043  * in which a state change should be performed on them. This 
1044  * means that first the sinks and then the other elements will
1045  * be returned.
1046  * Each element will have its refcount increased, so unref
1047  * after use.
1048  *
1049  * Not implemented yet.
1050  *
1051  * MT safe.
1052  *
1053  * Returns: a #GstIterator of #GstElements. gst_iterator_free after use.
1054  */
1055 GstIterator *
1056 gst_bin_iterate_state_order (GstBin * bin)
1057 {
1058   GstIterator *result;
1059
1060   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1061
1062   result = NULL;
1063
1064   return result;
1065 }
1066
1067 static void
1068 clear_queue (GQueue * queue, gboolean unref)
1069 {
1070   gpointer p;
1071
1072   while ((p = g_queue_pop_head (queue)))
1073     if (unref)
1074       gst_object_unref (p);
1075 }
1076 static void
1077 remove_all_from_queue (GQueue * queue, gpointer elem, gboolean unref)
1078 {
1079   gpointer p;
1080
1081   while ((p = g_queue_find (queue, elem))) {
1082     if (unref)
1083       gst_object_unref (elem);
1084     g_queue_delete_link (queue, p);
1085   }
1086 }
1087
1088 /* this function is called with the STATE_LOCK held. It works
1089  * as follows:
1090  *
1091  * 1) put all sink elements on the queue.
1092  * 2) put all semisink elements on the queue.
1093  * 3) change state of elements in queue, put linked elements to queue.
1094  * 4) while queue not empty goto 3)
1095  *
1096  * This will effectively change the state of all elements in the bin
1097  * from the sinks to the sources. We have to change the states this
1098  * way so that when a source element pushes data, the downstream element
1099  * is in the right state to receive the data.
1100  *
1101  * MT safe.
1102  */
1103 /* FIXME,  make me more elegant, want to use a topological sort algorithm
1104  * based on indegrees (or outdegrees in our case) */
1105 static GstElementStateReturn
1106 gst_bin_change_state (GstElement * element)
1107 {
1108   GstBin *bin;
1109   GstElementStateReturn ret;
1110   GstElementState old_state, pending;
1111   gboolean have_async = FALSE;
1112   gboolean have_no_preroll = FALSE;
1113   GList *children;
1114   guint32 children_cookie;
1115   GQueue *elem_queue;           /* list of elements waiting for a state change */
1116   GQueue *semi_queue;           /* list of elements with no connected srcpads */
1117   GQueue *temp;                 /* queue of leftovers */
1118   GstClockTime base_time;
1119
1120   bin = GST_BIN (element);
1121
1122   /* we don't need to take the STATE_LOCK, it is already taken */
1123   old_state = GST_STATE (element);
1124   pending = GST_STATE_PENDING (element);
1125
1126   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1127       "changing state of children from %s to %s",
1128       gst_element_state_get_name (old_state),
1129       gst_element_state_get_name (pending));
1130
1131   if (pending == GST_STATE_VOID_PENDING)
1132     return GST_STATE_SUCCESS;
1133
1134   /* Clear eosed element list on READY-> PAUSED */
1135   if (GST_STATE_TRANSITION (element) == GST_STATE_READY_TO_PAUSED) {
1136     g_list_free (bin->eosed);
1137     bin->eosed = NULL;
1138   }
1139
1140   /* all elements added to these queues should have their refcount
1141    * incremented */
1142   elem_queue = g_queue_new ();
1143   semi_queue = g_queue_new ();
1144   temp = g_queue_new ();
1145
1146   /* first step, find all sink elements, these are the elements
1147    * without (linked) source pads. */
1148   GST_LOCK (bin);
1149
1150 restart:
1151   /* take base time */
1152   base_time = element->base_time;
1153
1154   /* make sure queues are empty, they could be filled when 
1155    * restarting. */
1156   clear_queue (elem_queue, TRUE);
1157   clear_queue (semi_queue, TRUE);
1158   clear_queue (temp, TRUE);
1159
1160   children = bin->children;
1161   children_cookie = bin->children_cookie;
1162   while (children) {
1163     GstElement *child = GST_ELEMENT_CAST (children->data);
1164
1165     gst_object_ref (child);
1166     GST_UNLOCK (bin);
1167
1168     if (bin_element_is_sink (child, bin) == 0) {
1169       g_queue_push_tail (elem_queue, child);
1170     } else if (bin_element_is_semi_sink (child, bin) == 0) {
1171       g_queue_push_tail (semi_queue, child);
1172     } else {
1173       g_queue_push_tail (temp, child);
1174     }
1175
1176     GST_LOCK (bin);
1177     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
1178       /* FIXME: we reffed some children already, are we leaking refcounts
1179        * in that case ? */
1180       GST_INFO_OBJECT (bin, "bin->children_cookie changed, restarting");
1181       goto restart;
1182     }
1183     children = g_list_next (children);
1184   }
1185   GST_UNLOCK (bin);
1186   /* after this point new elements can be added/removed from the
1187    * bin. We operate on the snapshot taken above. Applications
1188    * should serialize their add/remove and set_state. */
1189
1190   /* now change state for semi sink elements first so add them in
1191    * front of the other elements */
1192   g_queue_foreach (temp, (GFunc) append_child, semi_queue);
1193   clear_queue (temp, FALSE);
1194
1195   /* if we don't have real sinks, we continue with the other elements */
1196   if (g_queue_is_empty (elem_queue) && !g_queue_is_empty (semi_queue)) {
1197     GQueue *q = elem_queue;
1198
1199     /* we swap the queues as oposed to copy them over */
1200     elem_queue = semi_queue;
1201     semi_queue = q;
1202   }
1203
1204   /* second step, change state of elements in the queue */
1205   while (!g_queue_is_empty (elem_queue)) {
1206     GstElement *qelement;
1207     GList *pads;
1208     gboolean locked;
1209
1210     /* take element */
1211     qelement = g_queue_pop_head (elem_queue);
1212     /* we don't need any duplicates in the other queue anymore */
1213     remove_all_from_queue (semi_queue, qelement, TRUE);
1214
1215     /* queue all elements connected to the sinkpads of this element */
1216     GST_LOCK (qelement);
1217     pads = qelement->sinkpads;
1218     while (pads) {
1219       GstPad *pad = GST_PAD_CAST (pads->data);
1220       GstPad *peer;
1221
1222       GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1223           "found sinkpad %s:%s", GST_DEBUG_PAD_NAME (pad));
1224
1225       peer = gst_pad_get_peer (pad);
1226       if (peer) {
1227         GstObject *peer_parent;
1228
1229         /*  get parent */
1230         peer_parent = gst_object_get_parent (GST_OBJECT (peer));
1231
1232         /* if we have an element parent, follow it */
1233         if (peer_parent && GST_IS_ELEMENT (peer_parent)) {
1234           GstObject *parent;
1235
1236           /* see if this element is in the bin we are currently handling */
1237           parent = gst_object_get_parent (peer_parent);
1238           if (parent) {
1239             if (parent == GST_OBJECT_CAST (bin)) {
1240               GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1241                   "adding element %s to queue", GST_ELEMENT_NAME (peer_parent));
1242
1243               /* make sure we don't have duplicates */
1244               remove_all_from_queue (semi_queue, peer_parent, TRUE);
1245               remove_all_from_queue (elem_queue, peer_parent, TRUE);
1246
1247               /* was reffed before pushing on the queue by the
1248                * gst_object_get_parent() call we used to get the element. */
1249               g_queue_push_tail (elem_queue, peer_parent);
1250               /* so that we don't unref it */
1251               peer_parent = NULL;
1252             } else {
1253               GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1254                   "not adding element %s to queue, it is in another bin",
1255                   GST_ELEMENT_NAME (peer_parent));
1256             }
1257             gst_object_unref (parent);
1258           }
1259         }
1260         if (peer_parent)
1261           gst_object_unref (peer_parent);
1262
1263         gst_object_unref (peer);
1264       } else {
1265         GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1266             "pad %s:%s does not have a peer", GST_DEBUG_PAD_NAME (pad));
1267       }
1268       pads = g_list_next (pads);
1269     }
1270     /* peel off the locked flag and release the element lock */
1271     locked = GST_FLAG_IS_SET (qelement, GST_ELEMENT_LOCKED_STATE);
1272     GST_UNLOCK (qelement);
1273
1274     /* skip locked elements */
1275     if (G_UNLIKELY (locked))
1276       goto next_element;
1277
1278     /* set base time on element */
1279     gst_element_set_base_time (qelement, base_time);
1280
1281     /* then change state */
1282     ret = gst_element_set_state (qelement, pending);
1283
1284     /* the set state could have cause elements to be added/removed,
1285      * we support that. */
1286     GST_LOCK (bin);
1287     if (G_UNLIKELY (children_cookie != bin->children_cookie)) {
1288       gst_object_unref (qelement);
1289       goto restart;
1290     }
1291     GST_UNLOCK (bin);
1292
1293     switch (ret) {
1294       case GST_STATE_SUCCESS:
1295         GST_CAT_DEBUG (GST_CAT_STATES,
1296             "child '%s' changed state to %d(%s) successfully",
1297             GST_ELEMENT_NAME (qelement), pending,
1298             gst_element_state_get_name (pending));
1299         break;
1300       case GST_STATE_ASYNC:
1301         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1302             "child '%s' is changing state asynchronously",
1303             GST_ELEMENT_NAME (qelement));
1304         have_async = TRUE;
1305         break;
1306       case GST_STATE_FAILURE:
1307         GST_CAT_INFO_OBJECT (GST_CAT_STATES, element,
1308             "child '%s' failed to go to state %d(%s)",
1309             GST_ELEMENT_NAME (qelement),
1310             pending, gst_element_state_get_name (pending));
1311         ret = GST_STATE_FAILURE;
1312         /* release refcount of element we popped off the queue */
1313         gst_object_unref (qelement);
1314         goto exit;
1315       case GST_STATE_NO_PREROLL:
1316         GST_CAT_DEBUG (GST_CAT_STATES,
1317             "child '%s' changed state to %d(%s) successfully without preroll",
1318             GST_ELEMENT_NAME (qelement), pending,
1319             gst_element_state_get_name (pending));
1320         have_no_preroll = TRUE;
1321         break;
1322       default:
1323         g_assert_not_reached ();
1324         break;
1325     }
1326   next_element:
1327     gst_object_unref (qelement);
1328
1329     /* if queue is empty now, continue with a non-sink */
1330     if (g_queue_is_empty (elem_queue)) {
1331       GstElement *non_sink;
1332
1333       GST_DEBUG ("sinks and upstream elements exhausted");
1334       non_sink = g_queue_pop_head (semi_queue);
1335       if (non_sink) {
1336         GST_DEBUG ("found lefover non-sink %s", GST_OBJECT_NAME (non_sink));
1337         g_queue_push_tail (elem_queue, non_sink);
1338       }
1339     }
1340   }
1341
1342   if (have_no_preroll) {
1343     ret = GST_STATE_NO_PREROLL;
1344   } else if (have_async) {
1345     ret = GST_STATE_ASYNC;
1346   } else {
1347     ret = parent_class->change_state (element);
1348   }
1349
1350   GST_CAT_DEBUG_OBJECT (GST_CAT_STATES, element,
1351       "done changing bin's state from %s to %s, now in %s, ret %d",
1352       gst_element_state_get_name (old_state),
1353       gst_element_state_get_name (pending),
1354       gst_element_state_get_name (GST_STATE (element)), ret);
1355
1356 exit:
1357   /* release refcounts in queue, should normally be empty unless we
1358    * had an error. */
1359   clear_queue (elem_queue, TRUE);
1360   clear_queue (semi_queue, TRUE);
1361   g_queue_free (elem_queue);
1362   g_queue_free (semi_queue);
1363   g_queue_free (temp);
1364
1365   return ret;
1366 }
1367
1368 static void
1369 gst_bin_dispose (GObject * object)
1370 {
1371   GstBin *bin = GST_BIN (object);
1372
1373   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose");
1374
1375   /* ref to not hit 0 again */
1376   gst_object_ref (object);
1377
1378   g_list_free (bin->eosed);
1379   bin->eosed = NULL;
1380   gst_object_unref (bin->child_bus);
1381   bin->child_bus = NULL;
1382   gst_element_set_bus (GST_ELEMENT (bin), NULL);
1383
1384   while (bin->children) {
1385     gst_bin_remove (bin, GST_ELEMENT (bin->children->data));
1386   }
1387   GST_CAT_DEBUG_OBJECT (GST_CAT_REFCOUNTING, object, "dispose no children");
1388   g_assert (bin->children == NULL);
1389   g_assert (bin->numchildren == 0);
1390
1391   G_OBJECT_CLASS (parent_class)->dispose (object);
1392 }
1393
1394 /*
1395  * This function is a utility event handler for seek events.
1396  * It will send the event to all sinks.
1397  * Applications are free to override this behaviour and
1398  * implement their own seek handler, but this will work for
1399  * pretty much all cases in practice.
1400  */
1401 static gboolean
1402 gst_bin_send_event (GstElement * element, GstEvent * event)
1403 {
1404   GstBin *bin = GST_BIN (element);
1405   GstIterator *iter;
1406   gboolean res = TRUE;
1407   gboolean done = FALSE;
1408
1409   iter = gst_bin_iterate_sinks (bin);
1410   GST_DEBUG_OBJECT (bin, "Sending event to sink children");
1411
1412   while (!done) {
1413     gpointer data;
1414
1415     switch (gst_iterator_next (iter, &data)) {
1416       case GST_ITERATOR_OK:
1417       {
1418         GstElement *sink;
1419
1420         gst_event_ref (event);
1421         sink = GST_ELEMENT_CAST (data);
1422         res &= gst_element_send_event (sink, event);
1423         gst_object_unref (sink);
1424         break;
1425       }
1426       case GST_ITERATOR_RESYNC:
1427         gst_iterator_resync (iter);
1428         res = TRUE;
1429         break;
1430       default:
1431       case GST_ITERATOR_DONE:
1432         done = TRUE;
1433         break;
1434     }
1435   }
1436   gst_iterator_free (iter);
1437   gst_event_unref (event);
1438
1439   return res;
1440 }
1441
1442 /* FIXME, make me threadsafe */
1443 static GstBusSyncReply
1444 bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin)
1445 {
1446   GST_DEBUG_OBJECT (bin, "[msg %p] handling child message of type %d",
1447       message, GST_MESSAGE_TYPE (message));
1448   /* we don't want messages from the streaming thread while we're doing the
1449    * state change. We do want them from the state change functions. */
1450   switch (GST_MESSAGE_TYPE (message)) {
1451     case GST_MESSAGE_EOS:{
1452       gchar *name = gst_object_get_name (GST_MESSAGE_SRC (message));
1453
1454       GST_DEBUG_OBJECT (bin, "got EOS message from %s", name);
1455       g_free (name);
1456
1457       GST_LOCK (bin->child_bus);
1458       bin->eosed = g_list_prepend (bin->eosed, GST_MESSAGE_SRC (message));
1459       GST_UNLOCK (bin->child_bus);
1460
1461       if (is_eos (bin)) {
1462         GST_DEBUG_OBJECT (bin, "all sinks posted EOS");
1463         gst_bus_post (GST_ELEMENT (bin)->bus,
1464             gst_message_new_eos (GST_OBJECT (bin)));
1465       }
1466
1467       /* we drop all EOS messages */
1468       gst_message_unref (message);
1469       break;
1470     }
1471     default:{
1472       GstBus *bus;
1473
1474       /* Send all other messages upward */
1475       GST_LOCK (bin);
1476       if (!(bus = GST_ELEMENT (bin)->bus)) {
1477         GST_DEBUG_OBJECT (bin, "dropping message because no parent bus");
1478         GST_UNLOCK (bin);
1479       } else {
1480         gst_object_ref (bus);
1481         GST_UNLOCK (bin);
1482
1483         GST_DEBUG_OBJECT (bin, "posting message upward");
1484         gst_bus_post (GST_ELEMENT (bin)->bus, message);
1485         gst_object_unref (bus);
1486       }
1487       break;
1488     }
1489   }
1490
1491   return GST_BUS_DROP;
1492 }
1493
1494 static gboolean
1495 gst_bin_query (GstElement * element, GstQuery * query)
1496 {
1497   GstBin *bin = GST_BIN (element);
1498   GstIterator *iter;
1499   gboolean res = FALSE, done = FALSE;
1500
1501   iter = gst_bin_iterate_sinks (bin);
1502   GST_DEBUG_OBJECT (bin, "Sending event to sink children");
1503
1504   while (!(res || done)) {
1505     gpointer data;
1506
1507     switch (gst_iterator_next (iter, &data)) {
1508       case GST_ITERATOR_OK:
1509       {
1510         GstElement *sink;
1511
1512         sink = GST_ELEMENT_CAST (data);
1513         res = gst_element_query (sink, query);
1514         gst_object_unref (sink);
1515         break;
1516       }
1517       case GST_ITERATOR_RESYNC:
1518         gst_iterator_resync (iter);
1519         break;
1520       default:
1521       case GST_ITERATOR_DONE:
1522         done = TRUE;
1523         break;
1524     }
1525   }
1526   gst_iterator_free (iter);
1527
1528   return res;
1529 }
1530
1531 static gint
1532 compare_name (GstElement * element, const gchar * name)
1533 {
1534   gint eq;
1535
1536   GST_LOCK (element);
1537   eq = strcmp (GST_ELEMENT_NAME (element), name);
1538   GST_UNLOCK (element);
1539
1540   if (eq != 0) {
1541     gst_object_unref (element);
1542   }
1543   return eq;
1544 }
1545
1546 /**
1547  * gst_bin_get_by_name:
1548  * @bin: #Gstbin to search
1549  * @name: the element name to search for
1550  *
1551  * Get the element with the given name from this bin. This
1552  * function recurses into subbins.
1553  *
1554  * MT safe.
1555  *
1556  * Returns: the element with the given name. Returns NULL if the
1557  * element is not found or when bad parameters were given. Unref after
1558  * use.
1559  */
1560 GstElement *
1561 gst_bin_get_by_name (GstBin * bin, const gchar * name)
1562 {
1563   GstIterator *children;
1564   GstIterator *result;
1565
1566   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1567
1568   GST_CAT_INFO (GST_CAT_PARENTAGE, "[%s]: looking up child element %s",
1569       GST_ELEMENT_NAME (bin), name);
1570
1571   children = gst_bin_iterate_recurse (bin);
1572   result = gst_iterator_find_custom (children,
1573       (GCompareFunc) compare_name, (gpointer) name);
1574   gst_iterator_free (children);
1575
1576   return GST_ELEMENT_CAST (result);
1577 }
1578
1579 /**
1580  * gst_bin_get_by_name_recurse_up:
1581  * @bin: #Gstbin to search
1582  * @name: the element name to search for
1583  *
1584  * MT safe.
1585  *
1586  * Get the element with the given name from this bin. If the
1587  * element is not found, a recursion is performed on the parent bin.
1588  *
1589  * Returns: the element with the given name or NULL when the element
1590  * was not found or bad parameters were given. Unref after use.
1591  */
1592 GstElement *
1593 gst_bin_get_by_name_recurse_up (GstBin * bin, const gchar * name)
1594 {
1595   GstElement *result;
1596
1597   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1598   g_return_val_if_fail (name != NULL, NULL);
1599
1600   result = gst_bin_get_by_name (bin, name);
1601
1602   if (!result) {
1603     GstObject *parent;
1604
1605     parent = gst_object_get_parent (GST_OBJECT_CAST (bin));
1606     if (parent) {
1607       if (GST_IS_BIN (parent)) {
1608         result = gst_bin_get_by_name_recurse_up (GST_BIN_CAST (parent), name);
1609       }
1610       gst_object_unref (parent);
1611     }
1612   }
1613
1614   return result;
1615 }
1616
1617 static gint
1618 compare_interface (GstElement * element, gpointer interface)
1619 {
1620   gint ret;
1621
1622   if (G_TYPE_CHECK_INSTANCE_TYPE (element, GPOINTER_TO_INT (interface))) {
1623     ret = 0;
1624   } else {
1625     /* we did not find the element, need to release the ref
1626      * added by the iterator */
1627     gst_object_unref (element);
1628     ret = 1;
1629   }
1630   return ret;
1631 }
1632
1633 /**
1634  * gst_bin_get_by_interface:
1635  * @bin: bin to find element in
1636  * @interface: interface to be implemented by interface
1637  *
1638  * Looks for the first element inside the bin that implements the given
1639  * interface. If such an element is found, it returns the element. You can
1640  * cast this element to the given interface afterwards.
1641  * If you want all elements that implement the interface, use
1642  * gst_bin_iterate_all_by_interface(). The function recurses inside bins.
1643  *
1644  * MT safe.
1645  *
1646  * Returns: An #GstElement inside the bin implementing the interface.
1647  *          Unref after use.
1648  */
1649 GstElement *
1650 gst_bin_get_by_interface (GstBin * bin, GType interface)
1651 {
1652   GstIterator *children;
1653   GstIterator *result;
1654
1655   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1656
1657   children = gst_bin_iterate_recurse (bin);
1658   result = gst_iterator_find_custom (children, (GCompareFunc) compare_interface,
1659       GINT_TO_POINTER (interface));
1660   gst_iterator_free (children);
1661
1662   return GST_ELEMENT_CAST (result);
1663 }
1664
1665 /**
1666  * gst_bin_get_all_by_interface:
1667  * @bin: bin to find elements in
1668  * @interface: interface to be implemented by interface
1669  *
1670  * Looks for all elements inside the bin that implements the given
1671  * interface. You can safely cast all returned elements to the given interface.
1672  * The function recurses bins inside bins. The iterator will return a series
1673  * of #GstElement that should be unreffed after use.
1674  *
1675  * MT safe.
1676  *
1677  * Returns: A #GstIterator for the elements inside the bin implementing the
1678  *          given interface.
1679  */
1680 GstIterator *
1681 gst_bin_iterate_all_by_interface (GstBin * bin, GType interface)
1682 {
1683   GstIterator *children;
1684   GstIterator *result;
1685
1686   g_return_val_if_fail (GST_IS_BIN (bin), NULL);
1687
1688   children = gst_bin_iterate_recurse (bin);
1689   result = gst_iterator_filter (children, (GCompareFunc) compare_interface,
1690       GINT_TO_POINTER (interface));
1691
1692   return result;
1693 }
1694
1695 #ifndef GST_DISABLE_LOADSAVE
1696 static xmlNodePtr
1697 gst_bin_save_thyself (GstObject * object, xmlNodePtr parent)
1698 {
1699   GstBin *bin = GST_BIN (object);
1700   xmlNodePtr childlist, elementnode;
1701   GList *children;
1702   GstElement *child;
1703
1704   if (GST_OBJECT_CLASS (parent_class)->save_thyself)
1705     GST_OBJECT_CLASS (parent_class)->save_thyself (GST_OBJECT (bin), parent);
1706
1707   childlist = xmlNewChild (parent, NULL, (xmlChar *) "children", NULL);
1708
1709   GST_CAT_INFO (GST_CAT_XML, "[%s]: saving %d children",
1710       GST_ELEMENT_NAME (bin), bin->numchildren);
1711
1712   children = bin->children;
1713   while (children) {
1714     child = GST_ELEMENT (children->data);
1715     elementnode = xmlNewChild (childlist, NULL, (xmlChar *) "element", NULL);
1716     gst_object_save_thyself (GST_OBJECT (child), elementnode);
1717     children = g_list_next (children);
1718   }
1719   return childlist;
1720 }
1721
1722 static void
1723 gst_bin_restore_thyself (GstObject * object, xmlNodePtr self)
1724 {
1725   GstBin *bin = GST_BIN (object);
1726   xmlNodePtr field = self->xmlChildrenNode;
1727   xmlNodePtr childlist;
1728
1729   while (field) {
1730     if (!strcmp ((char *) field->name, "children")) {
1731       GST_CAT_INFO (GST_CAT_XML, "[%s]: loading children",
1732           GST_ELEMENT_NAME (object));
1733       childlist = field->xmlChildrenNode;
1734       while (childlist) {
1735         if (!strcmp ((char *) childlist->name, "element")) {
1736           GstElement *element =
1737               gst_xml_make_element (childlist, GST_OBJECT (bin));
1738
1739           /* it had to be parented to find the pads, now we ref and unparent so
1740            * we can add it to the bin */
1741           gst_object_ref (element);
1742           gst_object_unparent (GST_OBJECT (element));
1743
1744           gst_bin_add (bin, element);
1745         }
1746         childlist = childlist->next;
1747       }
1748     }
1749
1750     field = field->next;
1751   }
1752   if (GST_OBJECT_CLASS (parent_class)->restore_thyself)
1753     (GST_OBJECT_CLASS (parent_class)->restore_thyself) (object, self);
1754 }
1755 #endif /* GST_DISABLE_LOADSAVE */