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