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