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