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