1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 // generated automatically - do not change
21 // find conversion definition on APILookup.txt
22 // implement new conversion functionalities on the wrap.utils pakage
23 
24 
25 module gstreamer.Bin;
26 
27 private import glib.ConstructionException;
28 private import glib.Str;
29 private import gobject.ObjectG;
30 private import gobject.Signals;
31 private import gstreamer.ChildProxyIF;
32 private import gstreamer.ChildProxyT;
33 private import gstreamer.Element;
34 private import gstreamer.Iterator;
35 private import gstreamer.Pad;
36 private import gstreamerc.gstreamer;
37 public  import gstreamerc.gstreamertypes;
38 public  import gtkc.gdktypes;
39 private import std.algorithm;
40 
41 
42 /**
43  * #GstBin is an element that can contain other #GstElement, allowing them to be
44  * managed as a group.
45  * Pads from the child elements can be ghosted to the bin, see #GstGhostPad.
46  * This makes the bin look like any other elements and enables creation of
47  * higher-level abstraction elements.
48  * 
49  * A new #GstBin is created with gst_bin_new(). Use a #GstPipeline instead if you
50  * want to create a toplevel bin because a normal bin doesn't have a bus or
51  * handle clock distribution of its own.
52  * 
53  * After the bin has been created you will typically add elements to it with
54  * gst_bin_add(). You can remove elements with gst_bin_remove().
55  * 
56  * An element can be retrieved from a bin with gst_bin_get_by_name(), using the
57  * elements name. gst_bin_get_by_name_recurse_up() is mainly used for internal
58  * purposes and will query the parent bins when the element is not found in the
59  * current bin.
60  * 
61  * An iterator of elements in a bin can be retrieved with
62  * gst_bin_iterate_elements(). Various other iterators exist to retrieve the
63  * elements in a bin.
64  * 
65  * gst_object_unref() is used to drop your reference to the bin.
66  * 
67  * The #GstBin::element-added signal is fired whenever a new element is added to
68  * the bin. Likewise the #GstBin::element-removed signal is fired whenever an
69  * element is removed from the bin.
70  * 
71  * <refsect2><title>Notes</title>
72  * <para>
73  * A #GstBin internally intercepts every #GstMessage posted by its children and
74  * implements the following default behaviour for each of them:
75  * <variablelist>
76  * <varlistentry>
77  * <term>GST_MESSAGE_EOS</term>
78  * <listitem><para>This message is only posted by sinks in the PLAYING
79  * state. If all sinks posted the EOS message, this bin will post and EOS
80  * message upwards.</para></listitem>
81  * </varlistentry>
82  * <varlistentry>
83  * <term>GST_MESSAGE_SEGMENT_START</term>
84  * <listitem><para>just collected and never forwarded upwards.
85  * The messages are used to decide when all elements have completed playback
86  * of their segment.</para></listitem>
87  * </varlistentry>
88  * <varlistentry>
89  * <term>GST_MESSAGE_SEGMENT_DONE</term>
90  * <listitem><para> Is posted by #GstBin when all elements that posted
91  * a SEGMENT_START have posted a SEGMENT_DONE.</para></listitem>
92  * </varlistentry>
93  * <varlistentry>
94  * <term>GST_MESSAGE_DURATION_CHANGED</term>
95  * <listitem><para> Is posted by an element that detected a change
96  * in the stream duration. The default bin behaviour is to clear any
97  * cached duration values so that the next duration query will perform
98  * a full duration recalculation. The duration change is posted to the
99  * application so that it can refetch the new duration with a duration
100  * query. Note that these messages can be posted before the bin is
101  * prerolled, in which case the duration query might fail.
102  * </para></listitem>
103  * </varlistentry>
104  * <varlistentry>
105  * <term>GST_MESSAGE_CLOCK_LOST</term>
106  * <listitem><para> This message is posted by an element when it
107  * can no longer provide a clock. The default bin behaviour is to
108  * check if the lost clock was the one provided by the bin. If so and
109  * the bin is currently in the PLAYING state, the message is forwarded to
110  * the bin parent.
111  * This message is also generated when a clock provider is removed from
112  * the bin. If this message is received by the application, it should
113  * PAUSE the pipeline and set it back to PLAYING to force a new clock
114  * distribution.
115  * </para></listitem>
116  * </varlistentry>
117  * <varlistentry>
118  * <term>GST_MESSAGE_CLOCK_PROVIDE</term>
119  * <listitem><para> This message is generated when an element
120  * can provide a clock. This mostly happens when a new clock
121  * provider is added to the bin. The default behaviour of the bin is to
122  * mark the currently selected clock as dirty, which will perform a clock
123  * recalculation the next time the bin is asked to provide a clock.
124  * This message is never sent tot the application but is forwarded to
125  * the parent of the bin.
126  * </para></listitem>
127  * </varlistentry>
128  * <varlistentry>
129  * <term>OTHERS</term>
130  * <listitem><para> posted upwards.</para></listitem>
131  * </varlistentry>
132  * </variablelist>
133  * 
134  * 
135  * A #GstBin implements the following default behaviour for answering to a
136  * #GstQuery:
137  * <variablelist>
138  * <varlistentry>
139  * <term>GST_QUERY_DURATION</term>
140  * <listitem><para>If the query has been asked before with the same format
141  * and the bin is a toplevel bin (ie. has no parent),
142  * use the cached previous value. If no previous value was cached, the
143  * query is sent to all sink elements in the bin and the MAXIMUM of all
144  * values is returned. If the bin is a toplevel bin the value is cached.
145  * If no sinks are available in the bin, the query fails.
146  * </para></listitem>
147  * </varlistentry>
148  * <varlistentry>
149  * <term>GST_QUERY_POSITION</term>
150  * <listitem><para>The query is sent to all sink elements in the bin and the
151  * MAXIMUM of all values is returned. If no sinks are available in the bin,
152  * the query fails.
153  * </para></listitem>
154  * </varlistentry>
155  * <varlistentry>
156  * <term>OTHERS</term>
157  * <listitem><para>the query is forwarded to all sink elements, the result
158  * of the first sink that answers the query successfully is returned. If no
159  * sink is in the bin, the query fails.</para></listitem>
160  * </varlistentry>
161  * </variablelist>
162  * 
163  * A #GstBin will by default forward any event sent to it to all sink elements.
164  * If all the sinks return %TRUE, the bin will also return %TRUE, else %FALSE is
165  * returned. If no sinks are in the bin, the event handler will return %TRUE.
166  * 
167  * </para>
168  * </refsect2>
169  */
170 public class Bin : Element, ChildProxyIF
171 {
172 	/** the main Gtk struct */
173 	protected GstBin* gstBin;
174 
175 	/** Get the main Gtk struct */
176 	public GstBin* getBinStruct()
177 	{
178 		return gstBin;
179 	}
180 
181 	/** the main Gtk struct as a void* */
182 	protected override void* getStruct()
183 	{
184 		return cast(void*)gstBin;
185 	}
186 
187 	protected override void setStruct(GObject* obj)
188 	{
189 		gstBin = cast(GstBin*)obj;
190 		super.setStruct(obj);
191 	}
192 
193 	/**
194 	 * Sets our main struct and passes it to the parent class.
195 	 */
196 	public this (GstBin* gstBin, bool ownedRef = false)
197 	{
198 		this.gstBin = gstBin;
199 		super(cast(GstElement*)gstBin, ownedRef);
200 	}
201 
202 	// add the ChildProxy capabilities
203 	mixin ChildProxyT!(GstBin);
204 
205 	/** */
206 	public this(Element elem)
207 	{
208 		super( elem.getElementStruct(), true );
209 		this.gstBin = cast(GstBin*)elem.getElementStruct();
210 	}
211 	
212 	/**
213 	 * Adds a list of elements to a bin.
214 	 * This function is equivalent to calling add() for each member of the list.
215 	 * The return value of each add() is ignored.
216 	 */
217 	public void addMany( Element[] elems... )
218 	{
219 		foreach( e; elems ) add( e );
220 	}
221 	
222 	/**
223 	 * Remove a list of elements from a bin.
224 	 * This function is equivalent to calling remove() with each member of the list.
225 	 */
226 	public void removeMany( Element[] elems... )
227 	{
228 		foreach( e; elems ) remove( e );
229 	}
230 
231 	/**
232 	 */
233 
234 	/** */
235 	public static GType getType()
236 	{
237 		return gst_bin_get_type();
238 	}
239 
240 	/**
241 	 * Creates a new bin with the given name.
242 	 *
243 	 * Params:
244 	 *     name = the name of the new bin
245 	 *
246 	 * Return: a new #GstBin
247 	 *
248 	 * Throws: ConstructionException GTK+ fails to create the object.
249 	 */
250 	public this(string name)
251 	{
252 		auto p = gst_bin_new(Str.toStringz(name));
253 		
254 		if(p is null)
255 		{
256 			throw new ConstructionException("null returned by new");
257 		}
258 		
259 		this(cast(GstBin*) p);
260 	}
261 
262 	/**
263 	 * Adds the given element to the bin.  Sets the element's parent, and thus
264 	 * takes ownership of the element. An element can only be added to one bin.
265 	 *
266 	 * If the element's pads are linked to other pads, the pads will be unlinked
267 	 * before the element is added to the bin.
268 	 *
269 	 * <note>
270 	 * When you add an element to an already-running pipeline, you will have to
271 	 * take care to set the state of the newly-added element to the desired
272 	 * state (usually PLAYING or PAUSED, same you set the pipeline to originally)
273 	 * with gst_element_set_state(), or use gst_element_sync_state_with_parent().
274 	 * The bin or pipeline will not take care of this for you.
275 	 * </note>
276 	 *
277 	 * MT safe.
278 	 *
279 	 * Params:
280 	 *     element = the #GstElement to add
281 	 *
282 	 * Return: %TRUE if the element could be added, %FALSE if
283 	 *     the bin does not want to accept the element.
284 	 */
285 	public bool add(Element element)
286 	{
287 		return gst_bin_add(gstBin, (element is null) ? null : element.getElementStruct()) != 0;
288 	}
289 
290 	/**
291 	 * Recursively looks for elements with an unlinked pad of the given
292 	 * direction within the specified bin and returns an unlinked pad
293 	 * if one is found, or %NULL otherwise. If a pad is found, the caller
294 	 * owns a reference to it and should use gst_object_unref() on the
295 	 * pad when it is not needed any longer.
296 	 *
297 	 * Params:
298 	 *     direction = whether to look for an unlinked source or sink pad
299 	 *
300 	 * Return: unlinked pad of the given
301 	 *     direction, %NULL.
302 	 */
303 	public Pad findUnlinkedPad(GstPadDirection direction)
304 	{
305 		auto p = gst_bin_find_unlinked_pad(gstBin, direction);
306 		
307 		if(p is null)
308 		{
309 			return null;
310 		}
311 		
312 		return ObjectG.getDObject!(Pad)(cast(GstPad*) p, true);
313 	}
314 
315 	/**
316 	 * Looks for an element inside the bin that implements the given
317 	 * interface. If such an element is found, it returns the element.
318 	 * You can cast this element to the given interface afterwards.  If you want
319 	 * all elements that implement the interface, use
320 	 * gst_bin_iterate_all_by_interface(). This function recurses into child bins.
321 	 *
322 	 * MT safe.  Caller owns returned reference.
323 	 *
324 	 * Params:
325 	 *     iface = the #GType of an interface
326 	 *
327 	 * Return: A #GstElement inside the bin implementing the interface
328 	 */
329 	public Element getByInterface(GType iface)
330 	{
331 		auto p = gst_bin_get_by_interface(gstBin, iface);
332 		
333 		if(p is null)
334 		{
335 			return null;
336 		}
337 		
338 		return ObjectG.getDObject!(Element)(cast(GstElement*) p, true);
339 	}
340 
341 	/**
342 	 * Gets the element with the given name from a bin. This
343 	 * function recurses into child bins.
344 	 *
345 	 * Returns %NULL if no element with the given name is found in the bin.
346 	 *
347 	 * MT safe.  Caller owns returned reference.
348 	 *
349 	 * Params:
350 	 *     name = the element name to search for
351 	 *
352 	 * Return: the #GstElement with the given
353 	 *     name, or %NULL
354 	 */
355 	public Element getByName(string name)
356 	{
357 		auto p = gst_bin_get_by_name(gstBin, Str.toStringz(name));
358 		
359 		if(p is null)
360 		{
361 			return null;
362 		}
363 		
364 		return ObjectG.getDObject!(Element)(cast(GstElement*) p, true);
365 	}
366 
367 	/**
368 	 * Gets the element with the given name from this bin. If the
369 	 * element is not found, a recursion is performed on the parent bin.
370 	 *
371 	 * Returns %NULL if:
372 	 * - no element with the given name is found in the bin
373 	 *
374 	 * MT safe.  Caller owns returned reference.
375 	 *
376 	 * Params:
377 	 *     name = the element name to search for
378 	 *
379 	 * Return: the #GstElement with the given
380 	 *     name, or %NULL
381 	 */
382 	public Element getByNameRecurseUp(string name)
383 	{
384 		auto p = gst_bin_get_by_name_recurse_up(gstBin, Str.toStringz(name));
385 		
386 		if(p is null)
387 		{
388 			return null;
389 		}
390 		
391 		return ObjectG.getDObject!(Element)(cast(GstElement*) p, true);
392 	}
393 
394 	/**
395 	 * Return the suppressed flags of the bin.
396 	 *
397 	 * MT safe.
398 	 *
399 	 * Return: the bin's suppressed #GstElementFlags.
400 	 *
401 	 * Since: 1.10
402 	 */
403 	public GstElementFlags getSuppressedFlags()
404 	{
405 		return gst_bin_get_suppressed_flags(gstBin);
406 	}
407 
408 	/**
409 	 * Looks for all elements inside the bin that implements the given
410 	 * interface. You can safely cast all returned elements to the given interface.
411 	 * The function recurses inside child bins. The iterator will yield a series
412 	 * of #GstElement that should be unreffed after use.
413 	 *
414 	 * MT safe.  Caller owns returned value.
415 	 *
416 	 * Params:
417 	 *     iface = the #GType of an interface
418 	 *
419 	 * Return: a #GstIterator of #GstElement
420 	 *     for all elements in the bin implementing the given interface,
421 	 *     or %NULL
422 	 */
423 	public Iterator iterateAllByInterface(GType iface)
424 	{
425 		auto p = gst_bin_iterate_all_by_interface(gstBin, iface);
426 		
427 		if(p is null)
428 		{
429 			return null;
430 		}
431 		
432 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
433 	}
434 
435 	/**
436 	 * Gets an iterator for the elements in this bin.
437 	 *
438 	 * MT safe.  Caller owns returned value.
439 	 *
440 	 * Return: a #GstIterator of #GstElement,
441 	 *     or %NULL
442 	 */
443 	public Iterator iterateElements()
444 	{
445 		auto p = gst_bin_iterate_elements(gstBin);
446 		
447 		if(p is null)
448 		{
449 			return null;
450 		}
451 		
452 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
453 	}
454 
455 	/**
456 	 * Gets an iterator for the elements in this bin.
457 	 * This iterator recurses into GstBin children.
458 	 *
459 	 * MT safe.  Caller owns returned value.
460 	 *
461 	 * Return: a #GstIterator of #GstElement,
462 	 *     or %NULL
463 	 */
464 	public Iterator iterateRecurse()
465 	{
466 		auto p = gst_bin_iterate_recurse(gstBin);
467 		
468 		if(p is null)
469 		{
470 			return null;
471 		}
472 		
473 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
474 	}
475 
476 	/**
477 	 * Gets an iterator for all elements in the bin that have the
478 	 * #GST_ELEMENT_FLAG_SINK flag set.
479 	 *
480 	 * MT safe.  Caller owns returned value.
481 	 *
482 	 * Return: a #GstIterator of #GstElement,
483 	 *     or %NULL
484 	 */
485 	public Iterator iterateSinks()
486 	{
487 		auto p = gst_bin_iterate_sinks(gstBin);
488 		
489 		if(p is null)
490 		{
491 			return null;
492 		}
493 		
494 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
495 	}
496 
497 	/**
498 	 * Gets an iterator for the elements in this bin in topologically
499 	 * sorted order. This means that the elements are returned from
500 	 * the most downstream elements (sinks) to the sources.
501 	 *
502 	 * This function is used internally to perform the state changes
503 	 * of the bin elements and for clock selection.
504 	 *
505 	 * MT safe.  Caller owns returned value.
506 	 *
507 	 * Return: a #GstIterator of #GstElement,
508 	 *     or %NULL
509 	 */
510 	public Iterator iterateSorted()
511 	{
512 		auto p = gst_bin_iterate_sorted(gstBin);
513 		
514 		if(p is null)
515 		{
516 			return null;
517 		}
518 		
519 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
520 	}
521 
522 	/**
523 	 * Gets an iterator for all elements in the bin that have the
524 	 * #GST_ELEMENT_FLAG_SOURCE flag set.
525 	 *
526 	 * MT safe.  Caller owns returned value.
527 	 *
528 	 * Return: a #GstIterator of #GstElement,
529 	 *     or %NULL
530 	 */
531 	public Iterator iterateSources()
532 	{
533 		auto p = gst_bin_iterate_sources(gstBin);
534 		
535 		if(p is null)
536 		{
537 			return null;
538 		}
539 		
540 		return ObjectG.getDObject!(Iterator)(cast(GstIterator*) p, true);
541 	}
542 
543 	/**
544 	 * Query @bin for the current latency using and reconfigures this latency to all the
545 	 * elements with a LATENCY event.
546 	 *
547 	 * This method is typically called on the pipeline when a #GST_MESSAGE_LATENCY
548 	 * is posted on the bus.
549 	 *
550 	 * This function simply emits the 'do-latency' signal so any custom latency
551 	 * calculations will be performed.
552 	 *
553 	 * Return: %TRUE if the latency could be queried and reconfigured.
554 	 */
555 	public bool recalculateLatency()
556 	{
557 		return gst_bin_recalculate_latency(gstBin) != 0;
558 	}
559 
560 	/**
561 	 * Removes the element from the bin, unparenting it as well.
562 	 * Unparenting the element means that the element will be dereferenced,
563 	 * so if the bin holds the only reference to the element, the element
564 	 * will be freed in the process of removing it from the bin.  If you
565 	 * want the element to still exist after removing, you need to call
566 	 * gst_object_ref() before removing it from the bin.
567 	 *
568 	 * If the element's pads are linked to other pads, the pads will be unlinked
569 	 * before the element is removed from the bin.
570 	 *
571 	 * MT safe.
572 	 *
573 	 * Params:
574 	 *     element = the #GstElement to remove
575 	 *
576 	 * Return: %TRUE if the element could be removed, %FALSE if
577 	 *     the bin does not want to remove the element.
578 	 */
579 	public bool remove(Element element)
580 	{
581 		return gst_bin_remove(gstBin, (element is null) ? null : element.getElementStruct()) != 0;
582 	}
583 
584 	/**
585 	 * Suppress the given flags on the bin. #GstElementFlags of a
586 	 * child element are propagated when it is added to the bin.
587 	 * When suppressed flags are set, those specified flags will
588 	 * not be propagated to the bin.
589 	 *
590 	 * MT safe.
591 	 *
592 	 * Params:
593 	 *     flags = the #GstElementFlags to suppress
594 	 *
595 	 * Since: 1.10
596 	 */
597 	public void setSuppressedFlags(GstElementFlags flags)
598 	{
599 		gst_bin_set_suppressed_flags(gstBin, flags);
600 	}
601 
602 	/**
603 	 * Synchronizes the state of every child of @bin with the state
604 	 * of @bin. See also gst_element_sync_state_with_parent().
605 	 *
606 	 * Return: %TRUE if syncing the state was successful for all children,
607 	 *     otherwise %FALSE.
608 	 *
609 	 * Since: 1.6
610 	 */
611 	public bool syncChildrenStates()
612 	{
613 		return gst_bin_sync_children_states(gstBin) != 0;
614 	}
615 
616 	protected class OnDeepElementAddedDelegateWrapper
617 	{
618 		void delegate(Bin, Element, Bin) dlg;
619 		gulong handlerId;
620 		ConnectFlags flags;
621 		this(void delegate(Bin, Element, Bin) dlg, gulong handlerId, ConnectFlags flags)
622 		{
623 			this.dlg = dlg;
624 			this.handlerId = handlerId;
625 			this.flags = flags;
626 		}
627 	}
628 	protected OnDeepElementAddedDelegateWrapper[] onDeepElementAddedListeners;
629 
630 	/**
631 	 * Will be emitted after the element was added to sub_bin.
632 	 *
633 	 * Params:
634 	 *     subBin = the #GstBin the element was added to
635 	 *     element = the #GstElement that was added to @sub_bin
636 	 *
637 	 * Since: 1.10
638 	 */
639 	gulong addOnDeepElementAdded(void delegate(Bin, Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
640 	{
641 		onDeepElementAddedListeners ~= new OnDeepElementAddedDelegateWrapper(dlg, 0, connectFlags);
642 		onDeepElementAddedListeners[onDeepElementAddedListeners.length - 1].handlerId = Signals.connectData(
643 			this,
644 			"deep-element-added",
645 			cast(GCallback)&callBackDeepElementAdded,
646 			cast(void*)onDeepElementAddedListeners[onDeepElementAddedListeners.length - 1],
647 			cast(GClosureNotify)&callBackDeepElementAddedDestroy,
648 			connectFlags);
649 		return onDeepElementAddedListeners[onDeepElementAddedListeners.length - 1].handlerId;
650 	}
651 	
652 	extern(C) static void callBackDeepElementAdded(GstBin* binStruct, GstBin* subBin, GstElement* element,OnDeepElementAddedDelegateWrapper wrapper)
653 	{
654 		wrapper.dlg(ObjectG.getDObject!(Bin)(subBin), ObjectG.getDObject!(Element)(element), wrapper.outer);
655 	}
656 	
657 	extern(C) static void callBackDeepElementAddedDestroy(OnDeepElementAddedDelegateWrapper wrapper, GClosure* closure)
658 	{
659 		wrapper.outer.internalRemoveOnDeepElementAdded(wrapper);
660 	}
661 
662 	protected void internalRemoveOnDeepElementAdded(OnDeepElementAddedDelegateWrapper source)
663 	{
664 		foreach(index, wrapper; onDeepElementAddedListeners)
665 		{
666 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
667 			{
668 				onDeepElementAddedListeners[index] = null;
669 				onDeepElementAddedListeners = std.algorithm.remove(onDeepElementAddedListeners, index);
670 				break;
671 			}
672 		}
673 	}
674 	
675 
676 	protected class OnDeepElementRemovedDelegateWrapper
677 	{
678 		void delegate(Bin, Element, Bin) dlg;
679 		gulong handlerId;
680 		ConnectFlags flags;
681 		this(void delegate(Bin, Element, Bin) dlg, gulong handlerId, ConnectFlags flags)
682 		{
683 			this.dlg = dlg;
684 			this.handlerId = handlerId;
685 			this.flags = flags;
686 		}
687 	}
688 	protected OnDeepElementRemovedDelegateWrapper[] onDeepElementRemovedListeners;
689 
690 	/**
691 	 * Will be emitted after the element was removed from sub_bin.
692 	 *
693 	 * Params:
694 	 *     subBin = the #GstBin the element was removed from
695 	 *     element = the #GstElement that was removed from @sub_bin
696 	 *
697 	 * Since: 1.10
698 	 */
699 	gulong addOnDeepElementRemoved(void delegate(Bin, Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
700 	{
701 		onDeepElementRemovedListeners ~= new OnDeepElementRemovedDelegateWrapper(dlg, 0, connectFlags);
702 		onDeepElementRemovedListeners[onDeepElementRemovedListeners.length - 1].handlerId = Signals.connectData(
703 			this,
704 			"deep-element-removed",
705 			cast(GCallback)&callBackDeepElementRemoved,
706 			cast(void*)onDeepElementRemovedListeners[onDeepElementRemovedListeners.length - 1],
707 			cast(GClosureNotify)&callBackDeepElementRemovedDestroy,
708 			connectFlags);
709 		return onDeepElementRemovedListeners[onDeepElementRemovedListeners.length - 1].handlerId;
710 	}
711 	
712 	extern(C) static void callBackDeepElementRemoved(GstBin* binStruct, GstBin* subBin, GstElement* element,OnDeepElementRemovedDelegateWrapper wrapper)
713 	{
714 		wrapper.dlg(ObjectG.getDObject!(Bin)(subBin), ObjectG.getDObject!(Element)(element), wrapper.outer);
715 	}
716 	
717 	extern(C) static void callBackDeepElementRemovedDestroy(OnDeepElementRemovedDelegateWrapper wrapper, GClosure* closure)
718 	{
719 		wrapper.outer.internalRemoveOnDeepElementRemoved(wrapper);
720 	}
721 
722 	protected void internalRemoveOnDeepElementRemoved(OnDeepElementRemovedDelegateWrapper source)
723 	{
724 		foreach(index, wrapper; onDeepElementRemovedListeners)
725 		{
726 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
727 			{
728 				onDeepElementRemovedListeners[index] = null;
729 				onDeepElementRemovedListeners = std.algorithm.remove(onDeepElementRemovedListeners, index);
730 				break;
731 			}
732 		}
733 	}
734 	
735 
736 	protected class OnDoLatencyDelegateWrapper
737 	{
738 		bool delegate(Bin) dlg;
739 		gulong handlerId;
740 		ConnectFlags flags;
741 		this(bool delegate(Bin) dlg, gulong handlerId, ConnectFlags flags)
742 		{
743 			this.dlg = dlg;
744 			this.handlerId = handlerId;
745 			this.flags = flags;
746 		}
747 	}
748 	protected OnDoLatencyDelegateWrapper[] onDoLatencyListeners;
749 
750 	/**
751 	 * Will be emitted when the bin needs to perform latency calculations. This
752 	 * signal is only emitted for toplevel bins or when async-handling is
753 	 * enabled.
754 	 *
755 	 * Only one signal handler is invoked. If no signals are connected, the
756 	 * default handler is invoked, which will query and distribute the lowest
757 	 * possible latency to all sinks.
758 	 *
759 	 * Connect to this signal if the default latency calculations are not
760 	 * sufficient, like when you need different latencies for different sinks in
761 	 * the same pipeline.
762 	 */
763 	gulong addOnDoLatency(bool delegate(Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
764 	{
765 		onDoLatencyListeners ~= new OnDoLatencyDelegateWrapper(dlg, 0, connectFlags);
766 		onDoLatencyListeners[onDoLatencyListeners.length - 1].handlerId = Signals.connectData(
767 			this,
768 			"do-latency",
769 			cast(GCallback)&callBackDoLatency,
770 			cast(void*)onDoLatencyListeners[onDoLatencyListeners.length - 1],
771 			cast(GClosureNotify)&callBackDoLatencyDestroy,
772 			connectFlags);
773 		return onDoLatencyListeners[onDoLatencyListeners.length - 1].handlerId;
774 	}
775 	
776 	extern(C) static int callBackDoLatency(GstBin* binStruct,OnDoLatencyDelegateWrapper wrapper)
777 	{
778 		return wrapper.dlg(wrapper.outer);
779 	}
780 	
781 	extern(C) static void callBackDoLatencyDestroy(OnDoLatencyDelegateWrapper wrapper, GClosure* closure)
782 	{
783 		wrapper.outer.internalRemoveOnDoLatency(wrapper);
784 	}
785 
786 	protected void internalRemoveOnDoLatency(OnDoLatencyDelegateWrapper source)
787 	{
788 		foreach(index, wrapper; onDoLatencyListeners)
789 		{
790 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
791 			{
792 				onDoLatencyListeners[index] = null;
793 				onDoLatencyListeners = std.algorithm.remove(onDoLatencyListeners, index);
794 				break;
795 			}
796 		}
797 	}
798 	
799 
800 	protected class OnElementAddedDelegateWrapper
801 	{
802 		void delegate(Element, Bin) dlg;
803 		gulong handlerId;
804 		ConnectFlags flags;
805 		this(void delegate(Element, Bin) dlg, gulong handlerId, ConnectFlags flags)
806 		{
807 			this.dlg = dlg;
808 			this.handlerId = handlerId;
809 			this.flags = flags;
810 		}
811 	}
812 	protected OnElementAddedDelegateWrapper[] onElementAddedListeners;
813 
814 	/**
815 	 * Will be emitted after the element was added to the bin.
816 	 *
817 	 * Params:
818 	 *     element = the #GstElement that was added to the bin
819 	 */
820 	gulong addOnElementAdded(void delegate(Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
821 	{
822 		onElementAddedListeners ~= new OnElementAddedDelegateWrapper(dlg, 0, connectFlags);
823 		onElementAddedListeners[onElementAddedListeners.length - 1].handlerId = Signals.connectData(
824 			this,
825 			"element-added",
826 			cast(GCallback)&callBackElementAdded,
827 			cast(void*)onElementAddedListeners[onElementAddedListeners.length - 1],
828 			cast(GClosureNotify)&callBackElementAddedDestroy,
829 			connectFlags);
830 		return onElementAddedListeners[onElementAddedListeners.length - 1].handlerId;
831 	}
832 	
833 	extern(C) static void callBackElementAdded(GstBin* binStruct, GstElement* element,OnElementAddedDelegateWrapper wrapper)
834 	{
835 		wrapper.dlg(ObjectG.getDObject!(Element)(element), wrapper.outer);
836 	}
837 	
838 	extern(C) static void callBackElementAddedDestroy(OnElementAddedDelegateWrapper wrapper, GClosure* closure)
839 	{
840 		wrapper.outer.internalRemoveOnElementAdded(wrapper);
841 	}
842 
843 	protected void internalRemoveOnElementAdded(OnElementAddedDelegateWrapper source)
844 	{
845 		foreach(index, wrapper; onElementAddedListeners)
846 		{
847 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
848 			{
849 				onElementAddedListeners[index] = null;
850 				onElementAddedListeners = std.algorithm.remove(onElementAddedListeners, index);
851 				break;
852 			}
853 		}
854 	}
855 	
856 
857 	protected class OnElementRemovedDelegateWrapper
858 	{
859 		void delegate(Element, Bin) dlg;
860 		gulong handlerId;
861 		ConnectFlags flags;
862 		this(void delegate(Element, Bin) dlg, gulong handlerId, ConnectFlags flags)
863 		{
864 			this.dlg = dlg;
865 			this.handlerId = handlerId;
866 			this.flags = flags;
867 		}
868 	}
869 	protected OnElementRemovedDelegateWrapper[] onElementRemovedListeners;
870 
871 	/**
872 	 * Will be emitted after the element was removed from the bin.
873 	 *
874 	 * Params:
875 	 *     element = the #GstElement that was removed from the bin
876 	 */
877 	gulong addOnElementRemoved(void delegate(Element, Bin) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
878 	{
879 		onElementRemovedListeners ~= new OnElementRemovedDelegateWrapper(dlg, 0, connectFlags);
880 		onElementRemovedListeners[onElementRemovedListeners.length - 1].handlerId = Signals.connectData(
881 			this,
882 			"element-removed",
883 			cast(GCallback)&callBackElementRemoved,
884 			cast(void*)onElementRemovedListeners[onElementRemovedListeners.length - 1],
885 			cast(GClosureNotify)&callBackElementRemovedDestroy,
886 			connectFlags);
887 		return onElementRemovedListeners[onElementRemovedListeners.length - 1].handlerId;
888 	}
889 	
890 	extern(C) static void callBackElementRemoved(GstBin* binStruct, GstElement* element,OnElementRemovedDelegateWrapper wrapper)
891 	{
892 		wrapper.dlg(ObjectG.getDObject!(Element)(element), wrapper.outer);
893 	}
894 	
895 	extern(C) static void callBackElementRemovedDestroy(OnElementRemovedDelegateWrapper wrapper, GClosure* closure)
896 	{
897 		wrapper.outer.internalRemoveOnElementRemoved(wrapper);
898 	}
899 
900 	protected void internalRemoveOnElementRemoved(OnElementRemovedDelegateWrapper source)
901 	{
902 		foreach(index, wrapper; onElementRemovedListeners)
903 		{
904 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
905 			{
906 				onElementRemovedListeners[index] = null;
907 				onElementRemovedListeners = std.algorithm.remove(onElementRemovedListeners, index);
908 				break;
909 			}
910 		}
911 	}
912 	
913 }