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.Bus;
26 
27 private import glib.ConstructionException;
28 private import glib.Source;
29 private import gobject.ObjectG;
30 private import gobject.Signals;
31 private import gstreamer.Message;
32 private import gstreamer.ObjectGst;
33 private import gstreamerc.gstreamer;
34 public  import gstreamerc.gstreamertypes;
35 public  import gtkc.gdktypes;
36 private import std.algorithm;
37 
38 
39 /**
40  * The #GstBus is an object responsible for delivering #GstMessage packets in
41  * a first-in first-out way from the streaming threads (see #GstTask) to the
42  * application.
43  * 
44  * Since the application typically only wants to deal with delivery of these
45  * messages from one thread, the GstBus will marshall the messages between
46  * different threads. This is important since the actual streaming of media
47  * is done in another thread than the application.
48  * 
49  * The GstBus provides support for #GSource based notifications. This makes it
50  * possible to handle the delivery in the glib mainloop.
51  * 
52  * The #GSource callback function gst_bus_async_signal_func() can be used to
53  * convert all bus messages into signal emissions.
54  * 
55  * A message is posted on the bus with the gst_bus_post() method. With the
56  * gst_bus_peek() and gst_bus_pop() methods one can look at or retrieve a
57  * previously posted message.
58  * 
59  * The bus can be polled with the gst_bus_poll() method. This methods blocks
60  * up to the specified timeout value until one of the specified messages types
61  * is posted on the bus. The application can then gst_bus_pop() the messages
62  * from the bus to handle them.
63  * Alternatively the application can register an asynchronous bus function
64  * using gst_bus_add_watch_full() or gst_bus_add_watch(). This function will
65  * install a #GSource in the default glib main loop and will deliver messages
66  * a short while after they have been posted. Note that the main loop should
67  * be running for the asynchronous callbacks.
68  * 
69  * It is also possible to get messages from the bus without any thread
70  * marshalling with the gst_bus_set_sync_handler() method. This makes it
71  * possible to react to a message in the same thread that posted the
72  * message on the bus. This should only be used if the application is able
73  * to deal with messages from different threads.
74  * 
75  * Every #GstPipeline has one bus.
76  * 
77  * Note that a #GstPipeline will set its bus into flushing state when changing
78  * from READY to NULL state.
79  */
80 public class Bus : ObjectGst
81 {
82 	/** the main Gtk struct */
83 	protected GstBus* gstBus;
84 
85 	/** Get the main Gtk struct */
86 	public GstBus* getBusStruct()
87 	{
88 		return gstBus;
89 	}
90 
91 	/** the main Gtk struct as a void* */
92 	protected override void* getStruct()
93 	{
94 		return cast(void*)gstBus;
95 	}
96 
97 	protected override void setStruct(GObject* obj)
98 	{
99 		gstBus = cast(GstBus*)obj;
100 		super.setStruct(obj);
101 	}
102 
103 	/**
104 	 * Sets our main struct and passes it to the parent class.
105 	 */
106 	public this (GstBus* gstBus, bool ownedRef = false)
107 	{
108 		this.gstBus = gstBus;
109 		super(cast(GstObject*)gstBus, ownedRef);
110 	}
111 
112 	/**
113 	 * Adds a bus watch to the default main context with the default priority.
114 	 * This function is used to receive asynchronous messages in the main loop.
115 	 * The watch can be removed using g_source_remove() or by returning FALSE
116 	 * from func.
117 	 * MT safe.
118 	 * Params:
119 	 *  dlg = A function to call when a message is received.
120 	 * Returns:
121 	 *  The event source id.
122 	 */
123 	public uint addWatch( bool delegate(Message) dlg )
124 	{
125 		onWatchListener = dlg;
126 		return gst_bus_add_watch(gstBus, cast(GstBusFunc)&watchCallBack, cast(void*)this);
127 	}
128 	
129 	bool delegate(Message) onWatchListener;
130 	
131 	extern(C) static int watchCallBack(GstBus* bus, GstMessage* msg, Bus bus_d )//gpointer data)
132 	{
133 		Message msg_d = new Message( msg );
134 		
135 		return bus_d.onWatchListener( msg_d );
136 	}
137 	
138 	/**
139 	 * Use this for making an XOverlay.
140 	 * Sets the synchronous handler on the bus. The function will be called
141 	 * every time a new message is posted on the bus. Note that the function
142 	 * will be called in the same thread context as the posting object. This
143 	 * function is usually only called by the creator of the bus. Applications
144 	 * should handle messages asynchronously using the gst_bus watch and poll
145 	 * functions.
146 	 * You cannot replace an existing sync_handler. You can pass NULL to this
147 	 * function, which will clear the existing handler.
148 	 * Params:
149 	 *  dlg = The handler function to install
150 	 */
151 	public void setSyncHandler( GstBusSyncReply delegate(Message) dlg )
152 	{
153 		onSyncHandlerListener = dlg;
154 		gst_bus_set_sync_handler(gstBus, cast(GstBusSyncHandler)&syncHandlerCallBack, cast(void*)this, null);
155 	}
156 	
157 	GstBusSyncReply delegate(Message) onSyncHandlerListener;
158 	
159 	extern(C) static GstBusSyncReply syncHandlerCallBack(GstBus* bus, GstMessage* msg, Bus bus_d)
160 	{
161 		Message msg_d = new Message( msg );
162 		
163 		return bus_d.onSyncHandlerListener( msg_d );
164 	}
165 
166 	/**
167 	 */
168 
169 	/** */
170 	public static GType getType()
171 	{
172 		return gst_bus_get_type();
173 	}
174 
175 	/**
176 	 * Creates a new #GstBus instance.
177 	 *
178 	 * Return: a new #GstBus instance
179 	 *
180 	 * Throws: ConstructionException GTK+ fails to create the object.
181 	 */
182 	public this()
183 	{
184 		auto p = gst_bus_new();
185 		
186 		if(p is null)
187 		{
188 			throw new ConstructionException("null returned by new");
189 		}
190 		
191 		this(cast(GstBus*) p, true);
192 	}
193 
194 	/**
195 	 * Adds a bus signal watch to the default main context with the default priority
196 	 * (%G_PRIORITY_DEFAULT). It is also possible to use a non-default
197 	 * main context set up using g_main_context_push_thread_default() (before
198 	 * one had to create a bus watch source and attach it to the desired main
199 	 * context 'manually').
200 	 *
201 	 * After calling this statement, the bus will emit the "message" signal for each
202 	 * message posted on the bus.
203 	 *
204 	 * This function may be called multiple times. To clean up, the caller is
205 	 * responsible for calling gst_bus_remove_signal_watch() as many times as this
206 	 * function is called.
207 	 *
208 	 * MT safe.
209 	 */
210 	public void addSignalWatch()
211 	{
212 		gst_bus_add_signal_watch(gstBus);
213 	}
214 
215 	/**
216 	 * Adds a bus signal watch to the default main context with the given @priority
217 	 * (e.g. %G_PRIORITY_DEFAULT). It is also possible to use a non-default main
218 	 * context set up using g_main_context_push_thread_default()
219 	 * (before one had to create a bus watch source and attach it to the desired
220 	 * main context 'manually').
221 	 *
222 	 * After calling this statement, the bus will emit the "message" signal for each
223 	 * message posted on the bus when the main loop is running.
224 	 *
225 	 * This function may be called multiple times. To clean up, the caller is
226 	 * responsible for calling gst_bus_remove_signal_watch() as many times as this
227 	 * function is called.
228 	 *
229 	 * There can only be a single bus watch per bus, you must remove any signal
230 	 * watch before you can set another type of watch.
231 	 *
232 	 * MT safe.
233 	 *
234 	 * Params:
235 	 *     priority = The priority of the watch.
236 	 */
237 	public void addSignalWatchFull(int priority)
238 	{
239 		gst_bus_add_signal_watch_full(gstBus, priority);
240 	}
241 
242 	/**
243 	 * Adds a bus watch to the default main context with the given @priority (e.g.
244 	 * %G_PRIORITY_DEFAULT). It is also possible to use a non-default  main
245 	 * context set up using g_main_context_push_thread_default() (before
246 	 * one had to create a bus watch source and attach it to the desired main
247 	 * context 'manually').
248 	 *
249 	 * This function is used to receive asynchronous messages in the main loop.
250 	 * There can only be a single bus watch per bus, you must remove it before you
251 	 * can set a new one.
252 	 *
253 	 * The bus watch will only work if a GLib main loop is being run.
254 	 *
255 	 * When @func is called, the message belongs to the caller; if you want to
256 	 * keep a copy of it, call gst_message_ref() before leaving @func.
257 	 *
258 	 * The watch can be removed using gst_bus_remove_watch() or by returning %FALSE
259 	 * from @func. If the watch was added to the default main context it is also
260 	 * possible to remove the watch using g_source_remove().
261 	 *
262 	 * MT safe.
263 	 *
264 	 * Params:
265 	 *     priority = The priority of the watch.
266 	 *     func = A function to call when a message is received.
267 	 *     userData = user data passed to @func.
268 	 *     notify = the function to call when the source is removed.
269 	 *
270 	 * Return: The event source id or 0 if @bus already got an event source.
271 	 */
272 	public uint addWatchFull(int priority, GstBusFunc func, void* userData, GDestroyNotify notify)
273 	{
274 		return gst_bus_add_watch_full(gstBus, priority, func, userData, notify);
275 	}
276 
277 	/**
278 	 * A helper #GstBusFunc that can be used to convert all asynchronous messages
279 	 * into signals.
280 	 *
281 	 * Params:
282 	 *     message = the #GstMessage received
283 	 *     data = user data
284 	 *
285 	 * Return: %TRUE
286 	 */
287 	public bool asyncSignalFunc(Message message, void* data)
288 	{
289 		return gst_bus_async_signal_func(gstBus, (message is null) ? null : message.getMessageStruct(), data) != 0;
290 	}
291 
292 	/**
293 	 * Create watch for this bus. The GSource will be dispatched whenever
294 	 * a message is on the bus. After the GSource is dispatched, the
295 	 * message is popped off the bus and unreffed.
296 	 *
297 	 * Return: a #GSource that can be added to a mainloop.
298 	 */
299 	public Source createWatch()
300 	{
301 		auto p = gst_bus_create_watch(gstBus);
302 		
303 		if(p is null)
304 		{
305 			return null;
306 		}
307 		
308 		return new Source(cast(GSource*) p, true);
309 	}
310 
311 	/**
312 	 * Instructs GStreamer to stop emitting the "sync-message" signal for this bus.
313 	 * See gst_bus_enable_sync_message_emission() for more information.
314 	 *
315 	 * In the event that multiple pieces of code have called
316 	 * gst_bus_enable_sync_message_emission(), the sync-message emissions will only
317 	 * be stopped after all calls to gst_bus_enable_sync_message_emission() were
318 	 * "cancelled" by calling this function. In this way the semantics are exactly
319 	 * the same as gst_object_ref() that which calls enable should also call
320 	 * disable.
321 	 *
322 	 * MT safe.
323 	 */
324 	public void disableSyncMessageEmission()
325 	{
326 		gst_bus_disable_sync_message_emission(gstBus);
327 	}
328 
329 	/**
330 	 * Instructs GStreamer to emit the "sync-message" signal after running the bus's
331 	 * sync handler. This function is here so that code can ensure that they can
332 	 * synchronously receive messages without having to affect what the bin's sync
333 	 * handler is.
334 	 *
335 	 * This function may be called multiple times. To clean up, the caller is
336 	 * responsible for calling gst_bus_disable_sync_message_emission() as many times
337 	 * as this function is called.
338 	 *
339 	 * While this function looks similar to gst_bus_add_signal_watch(), it is not
340 	 * exactly the same -- this function enables <emphasis>synchronous</emphasis> emission of
341 	 * signals when messages arrive; gst_bus_add_signal_watch() adds an idle callback
342 	 * to pop messages off the bus <emphasis>asynchronously</emphasis>. The sync-message signal
343 	 * comes from the thread of whatever object posted the message; the "message"
344 	 * signal is marshalled to the main thread via the main loop.
345 	 *
346 	 * MT safe.
347 	 */
348 	public void enableSyncMessageEmission()
349 	{
350 		gst_bus_enable_sync_message_emission(gstBus);
351 	}
352 
353 	/**
354 	 * Check if there are pending messages on the bus that
355 	 * should be handled.
356 	 *
357 	 * Return: %TRUE if there are messages on the bus to be handled, %FALSE
358 	 *     otherwise.
359 	 *
360 	 *     MT safe.
361 	 */
362 	public bool havePending()
363 	{
364 		return gst_bus_have_pending(gstBus) != 0;
365 	}
366 
367 	/**
368 	 * Peek the message on the top of the bus' queue. The message will remain
369 	 * on the bus' message queue. A reference is returned, and needs to be unreffed
370 	 * by the caller.
371 	 *
372 	 * Return: the #GstMessage that is on the
373 	 *     bus, or %NULL if the bus is empty.
374 	 *
375 	 *     MT safe.
376 	 */
377 	public Message peek()
378 	{
379 		auto p = gst_bus_peek(gstBus);
380 		
381 		if(p is null)
382 		{
383 			return null;
384 		}
385 		
386 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
387 	}
388 
389 	/**
390 	 * Poll the bus for messages. Will block while waiting for messages to come.
391 	 * You can specify a maximum time to poll with the @timeout parameter. If
392 	 * @timeout is negative, this function will block indefinitely.
393 	 *
394 	 * All messages not in @events will be popped off the bus and will be ignored.
395 	 * It is not possible to use message enums beyond #GST_MESSAGE_EXTENDED in the
396 	 * @events mask
397 	 *
398 	 * Because poll is implemented using the "message" signal enabled by
399 	 * gst_bus_add_signal_watch(), calling gst_bus_poll() will cause the "message"
400 	 * signal to be emitted for every message that poll sees. Thus a "message"
401 	 * signal handler will see the same messages that this function sees -- neither
402 	 * will steal messages from the other.
403 	 *
404 	 * This function will run a main loop from the default main context when
405 	 * polling.
406 	 *
407 	 * You should never use this function, since it is pure evil. This is
408 	 * especially true for GUI applications based on Gtk+ or Qt, but also for any
409 	 * other non-trivial application that uses the GLib main loop. As this function
410 	 * runs a GLib main loop, any callback attached to the default GLib main
411 	 * context may be invoked. This could be timeouts, GUI events, I/O events etc.;
412 	 * even if gst_bus_poll() is called with a 0 timeout. Any of these callbacks
413 	 * may do things you do not expect, e.g. destroy the main application window or
414 	 * some other resource; change other application state; display a dialog and
415 	 * run another main loop until the user clicks it away. In short, using this
416 	 * function may add a lot of complexity to your code through unexpected
417 	 * re-entrancy and unexpected changes to your application's state.
418 	 *
419 	 * For 0 timeouts use gst_bus_pop_filtered() instead of this function; for
420 	 * other short timeouts use gst_bus_timed_pop_filtered(); everything else is
421 	 * better handled by setting up an asynchronous bus watch and doing things
422 	 * from there.
423 	 *
424 	 * Params:
425 	 *     events = a mask of #GstMessageType, representing the set of message types to
426 	 *         poll for (note special handling of extended message types below)
427 	 *     timeout = the poll timeout, as a #GstClockTime, or #GST_CLOCK_TIME_NONE to poll
428 	 *         indefinitely.
429 	 *
430 	 * Return: the message that was received,
431 	 *     or %NULL if the poll timed out. The message is taken from the
432 	 *     bus and needs to be unreffed with gst_message_unref() after
433 	 *     usage.
434 	 */
435 	public Message poll(GstMessageType events, GstClockTime timeout)
436 	{
437 		auto p = gst_bus_poll(gstBus, events, timeout);
438 		
439 		if(p is null)
440 		{
441 			return null;
442 		}
443 		
444 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
445 	}
446 
447 	/**
448 	 * Get a message from the bus.
449 	 *
450 	 * Return: the #GstMessage that is on the
451 	 *     bus, or %NULL if the bus is empty. The message is taken from
452 	 *     the bus and needs to be unreffed with gst_message_unref() after
453 	 *     usage.
454 	 *
455 	 *     MT safe.
456 	 */
457 	public Message pop()
458 	{
459 		auto p = gst_bus_pop(gstBus);
460 		
461 		if(p is null)
462 		{
463 			return null;
464 		}
465 		
466 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
467 	}
468 
469 	/**
470 	 * Get a message matching @type from the bus.  Will discard all messages on
471 	 * the bus that do not match @type and that have been posted before the first
472 	 * message that does match @type.  If there is no message matching @type on
473 	 * the bus, all messages will be discarded. It is not possible to use message
474 	 * enums beyond #GST_MESSAGE_EXTENDED in the @events mask.
475 	 *
476 	 * Params:
477 	 *     types = message types to take into account
478 	 *
479 	 * Return: the next #GstMessage matching
480 	 *     @type that is on the bus, or %NULL if the bus is empty or there
481 	 *     is no message matching @type. The message is taken from the bus
482 	 *     and needs to be unreffed with gst_message_unref() after usage.
483 	 *
484 	 *     MT safe.
485 	 */
486 	public Message popFiltered(GstMessageType types)
487 	{
488 		auto p = gst_bus_pop_filtered(gstBus, types);
489 		
490 		if(p is null)
491 		{
492 			return null;
493 		}
494 		
495 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
496 	}
497 
498 	/**
499 	 * Post a message on the given bus. Ownership of the message
500 	 * is taken by the bus.
501 	 *
502 	 * Params:
503 	 *     message = the #GstMessage to post
504 	 *
505 	 * Return: %TRUE if the message could be posted, %FALSE if the bus is flushing.
506 	 *
507 	 *     MT safe.
508 	 */
509 	public bool post(Message message)
510 	{
511 		return gst_bus_post(gstBus, (message is null) ? null : message.getMessageStruct()) != 0;
512 	}
513 
514 	/**
515 	 * Removes a signal watch previously added with gst_bus_add_signal_watch().
516 	 *
517 	 * MT safe.
518 	 */
519 	public void removeSignalWatch()
520 	{
521 		gst_bus_remove_signal_watch(gstBus);
522 	}
523 
524 	/**
525 	 * Removes an installed bus watch from @bus.
526 	 *
527 	 * Return: %TRUE on success or %FALSE if @bus has no event source.
528 	 *
529 	 * Since: 1.6
530 	 */
531 	public bool removeWatch()
532 	{
533 		return gst_bus_remove_watch(gstBus) != 0;
534 	}
535 
536 	/**
537 	 * If @flushing, flush out and unref any messages queued in the bus. Releases
538 	 * references to the message origin objects. Will flush future messages until
539 	 * gst_bus_set_flushing() sets @flushing to %FALSE.
540 	 *
541 	 * MT safe.
542 	 *
543 	 * Params:
544 	 *     flushing = whether or not to flush the bus
545 	 */
546 	public void setFlushing(bool flushing)
547 	{
548 		gst_bus_set_flushing(gstBus, flushing);
549 	}
550 
551 	/**
552 	 * A helper GstBusSyncHandler that can be used to convert all synchronous
553 	 * messages into signals.
554 	 *
555 	 * Params:
556 	 *     message = the #GstMessage received
557 	 *     data = user data
558 	 *
559 	 * Return: GST_BUS_PASS
560 	 */
561 	public GstBusSyncReply syncSignalHandler(Message message, void* data)
562 	{
563 		return gst_bus_sync_signal_handler(gstBus, (message is null) ? null : message.getMessageStruct(), data);
564 	}
565 
566 	/**
567 	 * Get a message from the bus, waiting up to the specified timeout.
568 	 *
569 	 * If @timeout is 0, this function behaves like gst_bus_pop(). If @timeout is
570 	 * #GST_CLOCK_TIME_NONE, this function will block forever until a message was
571 	 * posted on the bus.
572 	 *
573 	 * Params:
574 	 *     timeout = a timeout
575 	 *
576 	 * Return: the #GstMessage that is on the
577 	 *     bus after the specified timeout or %NULL if the bus is empty
578 	 *     after the timeout expired.  The message is taken from the bus
579 	 *     and needs to be unreffed with gst_message_unref() after usage.
580 	 *
581 	 *     MT safe.
582 	 */
583 	public Message timedPop(GstClockTime timeout)
584 	{
585 		auto p = gst_bus_timed_pop(gstBus, timeout);
586 		
587 		if(p is null)
588 		{
589 			return null;
590 		}
591 		
592 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
593 	}
594 
595 	/**
596 	 * Get a message from the bus whose type matches the message type mask @types,
597 	 * waiting up to the specified timeout (and discarding any messages that do not
598 	 * match the mask provided).
599 	 *
600 	 * If @timeout is 0, this function behaves like gst_bus_pop_filtered(). If
601 	 * @timeout is #GST_CLOCK_TIME_NONE, this function will block forever until a
602 	 * matching message was posted on the bus.
603 	 *
604 	 * Params:
605 	 *     timeout = a timeout in nanoseconds, or GST_CLOCK_TIME_NONE to wait forever
606 	 *     types = message types to take into account, GST_MESSAGE_ANY for any type
607 	 *
608 	 * Return: a #GstMessage matching the
609 	 *     filter in @types, or %NULL if no matching message was found on
610 	 *     the bus until the timeout expired. The message is taken from
611 	 *     the bus and needs to be unreffed with gst_message_unref() after
612 	 *     usage.
613 	 *
614 	 *     MT safe.
615 	 */
616 	public Message timedPopFiltered(GstClockTime timeout, GstMessageType types)
617 	{
618 		auto p = gst_bus_timed_pop_filtered(gstBus, timeout, types);
619 		
620 		if(p is null)
621 		{
622 			return null;
623 		}
624 		
625 		return ObjectG.getDObject!(Message)(cast(GstMessage*) p, true);
626 	}
627 
628 	protected class OnMessageDelegateWrapper
629 	{
630 		void delegate(Message, Bus) dlg;
631 		gulong handlerId;
632 		ConnectFlags flags;
633 		this(void delegate(Message, Bus) dlg, gulong handlerId, ConnectFlags flags)
634 		{
635 			this.dlg = dlg;
636 			this.handlerId = handlerId;
637 			this.flags = flags;
638 		}
639 	}
640 	protected OnMessageDelegateWrapper[] onMessageListeners;
641 
642 	/**
643 	 * A message has been posted on the bus. This signal is emitted from a
644 	 * GSource added to the mainloop. this signal will only be emitted when
645 	 * there is a mainloop running.
646 	 *
647 	 * Params:
648 	 *     message = the message that has been posted asynchronously
649 	 */
650 	gulong addOnMessage(void delegate(Message, Bus) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
651 	{
652 		onMessageListeners ~= new OnMessageDelegateWrapper(dlg, 0, connectFlags);
653 		onMessageListeners[onMessageListeners.length - 1].handlerId = Signals.connectData(
654 			this,
655 			"message",
656 			cast(GCallback)&callBackMessage,
657 			cast(void*)onMessageListeners[onMessageListeners.length - 1],
658 			cast(GClosureNotify)&callBackMessageDestroy,
659 			connectFlags);
660 		return onMessageListeners[onMessageListeners.length - 1].handlerId;
661 	}
662 	
663 	extern(C) static void callBackMessage(GstBus* busStruct, GstMessage* message,OnMessageDelegateWrapper wrapper)
664 	{
665 		wrapper.dlg(ObjectG.getDObject!(Message)(message), wrapper.outer);
666 	}
667 	
668 	extern(C) static void callBackMessageDestroy(OnMessageDelegateWrapper wrapper, GClosure* closure)
669 	{
670 		wrapper.outer.internalRemoveOnMessage(wrapper);
671 	}
672 
673 	protected void internalRemoveOnMessage(OnMessageDelegateWrapper source)
674 	{
675 		foreach(index, wrapper; onMessageListeners)
676 		{
677 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
678 			{
679 				onMessageListeners[index] = null;
680 				onMessageListeners = std.algorithm.remove(onMessageListeners, index);
681 				break;
682 			}
683 		}
684 	}
685 	
686 
687 	protected class OnSyncMessageDelegateWrapper
688 	{
689 		void delegate(Message, Bus) dlg;
690 		gulong handlerId;
691 		ConnectFlags flags;
692 		this(void delegate(Message, Bus) dlg, gulong handlerId, ConnectFlags flags)
693 		{
694 			this.dlg = dlg;
695 			this.handlerId = handlerId;
696 			this.flags = flags;
697 		}
698 	}
699 	protected OnSyncMessageDelegateWrapper[] onSyncMessageListeners;
700 
701 	/**
702 	 * A message has been posted on the bus. This signal is emitted from the
703 	 * thread that posted the message so one has to be careful with locking.
704 	 *
705 	 * This signal will not be emitted by default, you have to call
706 	 * gst_bus_enable_sync_message_emission() before.
707 	 *
708 	 * Params:
709 	 *     message = the message that has been posted synchronously
710 	 */
711 	gulong addOnSyncMessage(void delegate(Message, Bus) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)
712 	{
713 		onSyncMessageListeners ~= new OnSyncMessageDelegateWrapper(dlg, 0, connectFlags);
714 		onSyncMessageListeners[onSyncMessageListeners.length - 1].handlerId = Signals.connectData(
715 			this,
716 			"sync-message",
717 			cast(GCallback)&callBackSyncMessage,
718 			cast(void*)onSyncMessageListeners[onSyncMessageListeners.length - 1],
719 			cast(GClosureNotify)&callBackSyncMessageDestroy,
720 			connectFlags);
721 		return onSyncMessageListeners[onSyncMessageListeners.length - 1].handlerId;
722 	}
723 	
724 	extern(C) static void callBackSyncMessage(GstBus* busStruct, GstMessage* message,OnSyncMessageDelegateWrapper wrapper)
725 	{
726 		wrapper.dlg(ObjectG.getDObject!(Message)(message), wrapper.outer);
727 	}
728 	
729 	extern(C) static void callBackSyncMessageDestroy(OnSyncMessageDelegateWrapper wrapper, GClosure* closure)
730 	{
731 		wrapper.outer.internalRemoveOnSyncMessage(wrapper);
732 	}
733 
734 	protected void internalRemoveOnSyncMessage(OnSyncMessageDelegateWrapper source)
735 	{
736 		foreach(index, wrapper; onSyncMessageListeners)
737 		{
738 			if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)
739 			{
740 				onSyncMessageListeners[index] = null;
741 				onSyncMessageListeners = std.algorithm.remove(onSyncMessageListeners, index);
742 				break;
743 			}
744 		}
745 	}
746 	
747 }