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