1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git)
// DO NOT EDIT

use crate::{ffi, ClockTime, Message, Object};
use glib::{
    prelude::*,
    signal::{connect_raw, SignalHandlerId},
    translate::*,
};
use std::boxed::Box as Box_;

glib::wrapper! {
    /// The [`Bus`][crate::Bus] is an object responsible for delivering [`Message`][crate::Message] packets in
    /// a first-in first-out way from the streaming threads (see [`Task`][crate::Task]) to the
    /// application.
    ///
    /// Since the application typically only wants to deal with delivery of these
    /// messages from one thread, the GstBus will marshall the messages between
    /// different threads. This is important since the actual streaming of media
    /// is done in another thread than the application.
    ///
    /// The GstBus provides support for [`glib::Source`][crate::glib::Source] based notifications. This makes it
    /// possible to handle the delivery in the glib `GMainLoop`.
    ///
    /// The [`glib::Source`][crate::glib::Source] callback function `gst_bus_async_signal_func()` can be used to
    /// convert all bus messages into signal emissions.
    ///
    /// A message is posted on the bus with the [`post()`][Self::post()] method. With the
    /// [`peek()`][Self::peek()] and [`pop()`][Self::pop()] methods one can look at or retrieve a
    /// previously posted message.
    ///
    /// The bus can be polled with the [`poll()`][Self::poll()] method. This methods blocks
    /// up to the specified timeout value until one of the specified messages types
    /// is posted on the bus. The application can then [`pop()`][Self::pop()] the messages
    /// from the bus to handle them.
    /// Alternatively the application can register an asynchronous bus function
    /// using [`add_watch_full()`][Self::add_watch_full()] or [`add_watch()`][Self::add_watch()]. This function will
    /// install a [`glib::Source`][crate::glib::Source] in the default glib main loop and will deliver messages
    /// a short while after they have been posted. Note that the main loop should
    /// be running for the asynchronous callbacks.
    ///
    /// It is also possible to get messages from the bus without any thread
    /// marshalling with the [`set_sync_handler()`][Self::set_sync_handler()] method. This makes it
    /// possible to react to a message in the same thread that posted the
    /// message on the bus. This should only be used if the application is able
    /// to deal with messages from different threads.
    ///
    /// Every [`Pipeline`][crate::Pipeline] has one bus.
    ///
    /// Note that a [`Pipeline`][crate::Pipeline] will set its bus into flushing state when changing
    /// from READY to NULL state.
    ///
    /// ## Properties
    ///
    ///
    /// #### `enable-async`
    ///  Enables async message delivery support for bus watches,
    /// [`Bus::pop()`][crate::Bus::pop()] and similar API. Without this only the
    /// synchronous message handlers are called.
    ///
    /// This property is used to create the child element buses
    /// in [`Bin`][crate::Bin].
    ///
    /// Writeable | Construct Only
    /// <details><summary><h4>Object</h4></summary>
    ///
    ///
    /// #### `name`
    ///  Readable | Writeable | Construct
    ///
    ///
    /// #### `parent`
    ///  The parent of the object. Please note, that when changing the 'parent'
    /// property, we don't emit [`notify`][struct@crate::glib::Object#notify] and [`deep-notify`][struct@crate::Object#deep-notify]
    /// signals due to locking issues. In some cases one can use
    /// [`element-added`][struct@crate::Bin#element-added] or [`element-removed`][struct@crate::Bin#element-removed] signals on the parent to
    /// achieve a similar effect.
    ///
    /// Readable | Writeable
    /// </details>
    ///
    /// ## Signals
    ///
    ///
    /// #### `message`
    ///  A message has been posted on the bus. This signal is emitted from a
    /// [`glib::Source`][crate::glib::Source] added to the mainloop. this signal will only be emitted when
    /// there is a `GMainLoop` running.
    ///
    /// Detailed
    ///
    ///
    /// #### `sync-message`
    ///  A message has been posted on the bus. This signal is emitted from the
    /// thread that posted the message so one has to be careful with locking.
    ///
    /// This signal will not be emitted by default, you have to call
    /// [`Bus::enable_sync_message_emission()`][crate::Bus::enable_sync_message_emission()] before.
    ///
    /// Detailed
    /// <details><summary><h4>Object</h4></summary>
    ///
    ///
    /// #### `deep-notify`
    ///  The deep notify signal is used to be notified of property changes. It is
    /// typically attached to the toplevel bin to receive notifications from all
    /// the elements contained in that bin.
    ///
    /// Detailed
    /// </details>
    ///
    /// # Implements
    ///
    /// [`GstObjectExt`][trait@crate::prelude::GstObjectExt], [`trait@glib::ObjectExt`]
    #[doc(alias = "GstBus")]
    pub struct Bus(Object<ffi::GstBus, ffi::GstBusClass>) @extends Object;

    match fn {
        type_ => || ffi::gst_bus_get_type(),
    }
}

impl Bus {
    /// Creates a new [`Bus`][crate::Bus] instance.
    ///
    /// # Returns
    ///
    /// a new [`Bus`][crate::Bus] instance
    #[doc(alias = "gst_bus_new")]
    pub fn new() -> Bus {
        assert_initialized_main_thread!();
        unsafe { from_glib_full(ffi::gst_bus_new()) }
    }

    /// Adds a bus signal watch to the default main context with the default priority
    /// ( `G_PRIORITY_DEFAULT` ). It is also possible to use a non-default
    /// main context set up using [`glib::MainContext::push_thread_default()`][crate::glib::MainContext::push_thread_default()] (before
    /// one had to create a bus watch source and attach it to the desired main
    /// context 'manually').
    ///
    /// After calling this statement, the bus will emit the "message" signal for each
    /// message posted on the bus.
    ///
    /// This function may be called multiple times. To clean up, the caller is
    /// responsible for calling [`remove_signal_watch()`][Self::remove_signal_watch()] as many times as this
    /// function is called.
    #[doc(alias = "gst_bus_add_signal_watch")]
    pub fn add_signal_watch(&self) {
        unsafe {
            ffi::gst_bus_add_signal_watch(self.to_glib_none().0);
        }
    }

    //#[doc(alias = "gst_bus_async_signal_func")]
    //pub fn async_signal_func(&self, message: &Message, data: /*Unimplemented*/Option<Basic: Pointer>) -> bool {
    //    unsafe { TODO: call ffi:gst_bus_async_signal_func() }
    //}

    /// Instructs GStreamer to stop emitting the "sync-message" signal for this bus.
    /// See [`enable_sync_message_emission()`][Self::enable_sync_message_emission()] for more information.
    ///
    /// In the event that multiple pieces of code have called
    /// [`enable_sync_message_emission()`][Self::enable_sync_message_emission()], the sync-message emissions will only
    /// be stopped after all calls to [`enable_sync_message_emission()`][Self::enable_sync_message_emission()] were
    /// "cancelled" by calling this function. In this way the semantics are exactly
    /// the same as `gst_object_ref()` that which calls enable should also call
    /// disable.
    #[doc(alias = "gst_bus_disable_sync_message_emission")]
    pub fn disable_sync_message_emission(&self) {
        unsafe {
            ffi::gst_bus_disable_sync_message_emission(self.to_glib_none().0);
        }
    }

    /// Instructs GStreamer to emit the "sync-message" signal after running the bus's
    /// sync handler. This function is here so that code can ensure that they can
    /// synchronously receive messages without having to affect what the bin's sync
    /// handler is.
    ///
    /// This function may be called multiple times. To clean up, the caller is
    /// responsible for calling [`disable_sync_message_emission()`][Self::disable_sync_message_emission()] as many times
    /// as this function is called.
    ///
    /// While this function looks similar to [`add_signal_watch()`][Self::add_signal_watch()], it is not
    /// exactly the same -- this function enables *synchronous* emission of
    /// signals when messages arrive; [`add_signal_watch()`][Self::add_signal_watch()] adds an idle callback
    /// to pop messages off the bus *asynchronously*. The sync-message signal
    /// comes from the thread of whatever object posted the message; the "message"
    /// signal is marshalled to the main thread via the `GMainLoop`.
    #[doc(alias = "gst_bus_enable_sync_message_emission")]
    pub fn enable_sync_message_emission(&self) {
        unsafe {
            ffi::gst_bus_enable_sync_message_emission(self.to_glib_none().0);
        }
    }

    //#[doc(alias = "gst_bus_get_pollfd")]
    //#[doc(alias = "get_pollfd")]
    //pub fn pollfd(&self, fd: /*Ignored*/glib::PollFD) {
    //    unsafe { TODO: call ffi:gst_bus_get_pollfd() }
    //}

    /// Checks if there are pending messages on the bus that
    /// should be handled.
    ///
    /// # Returns
    ///
    /// [`true`] if there are messages on the bus to be handled, [`false`]
    /// otherwise.
    #[doc(alias = "gst_bus_have_pending")]
    pub fn have_pending(&self) -> bool {
        unsafe { from_glib(ffi::gst_bus_have_pending(self.to_glib_none().0)) }
    }

    /// Peeks the message on the top of the bus' queue. The message will remain
    /// on the bus' message queue.
    ///
    /// # Returns
    ///
    /// the [`Message`][crate::Message] that is on the
    ///  bus, or [`None`] if the bus is empty.
    #[doc(alias = "gst_bus_peek")]
    pub fn peek(&self) -> Option<Message> {
        unsafe { from_glib_full(ffi::gst_bus_peek(self.to_glib_none().0)) }
    }

    /// Gets a message from the bus.
    ///
    /// # Returns
    ///
    /// the [`Message`][crate::Message] that is on the
    ///  bus, or [`None`] if the bus is empty.
    #[doc(alias = "gst_bus_pop")]
    pub fn pop(&self) -> Option<Message> {
        unsafe { from_glib_full(ffi::gst_bus_pop(self.to_glib_none().0)) }
    }

    /// Posts a message on the given bus. Ownership of the message
    /// is taken by the bus.
    /// ## `message`
    /// the [`Message`][crate::Message] to post
    ///
    /// # Returns
    ///
    /// [`true`] if the message could be posted, [`false`] if the bus is flushing.
    #[doc(alias = "gst_bus_post")]
    pub fn post(&self, message: Message) -> Result<(), glib::error::BoolError> {
        unsafe {
            glib::result_from_gboolean!(
                ffi::gst_bus_post(self.to_glib_none().0, message.into_glib_ptr()),
                "Failed to post message"
            )
        }
    }

    /// Removes a signal watch previously added with [`add_signal_watch()`][Self::add_signal_watch()].
    #[doc(alias = "gst_bus_remove_signal_watch")]
    pub fn remove_signal_watch(&self) {
        unsafe {
            ffi::gst_bus_remove_signal_watch(self.to_glib_none().0);
        }
    }

    /// Removes an installed bus watch from `self`.
    ///
    /// # Returns
    ///
    /// [`true`] on success or [`false`] if `self` has no event source.
    #[doc(alias = "gst_bus_remove_watch")]
    #[allow(dead_code)]
    pub(crate) fn remove_watch(&self) -> Result<(), glib::error::BoolError> {
        unsafe {
            glib::result_from_gboolean!(
                ffi::gst_bus_remove_watch(self.to_glib_none().0),
                "Bus has no event source"
            )
        }
    }

    /// If `flushing`, flushes out and unrefs any messages queued in the bus. Releases
    /// references to the message origin objects. Will flush future messages until
    /// [`set_flushing()`][Self::set_flushing()] sets `flushing` to [`false`].
    /// ## `flushing`
    /// whether or not to flush the bus
    #[doc(alias = "gst_bus_set_flushing")]
    pub fn set_flushing(&self, flushing: bool) {
        unsafe {
            ffi::gst_bus_set_flushing(self.to_glib_none().0, flushing.into_glib());
        }
    }

    //#[doc(alias = "gst_bus_sync_signal_handler")]
    //pub fn sync_signal_handler(&self, message: &Message, data: /*Unimplemented*/Option<Basic: Pointer>) -> BusSyncReply {
    //    unsafe { TODO: call ffi:gst_bus_sync_signal_handler() }
    //}

    /// Gets a message from the bus, waiting up to the specified timeout.
    ///
    /// If `timeout` is 0, this function behaves like [`pop()`][Self::pop()]. If `timeout` is
    /// `GST_CLOCK_TIME_NONE`, this function will block forever until a message was
    /// posted on the bus.
    /// ## `timeout`
    /// a timeout
    ///
    /// # Returns
    ///
    /// the [`Message`][crate::Message] that is on the
    ///  bus after the specified timeout or [`None`] if the bus is empty
    ///  after the timeout expired.
    #[doc(alias = "gst_bus_timed_pop")]
    pub fn timed_pop(&self, timeout: impl Into<Option<ClockTime>>) -> Option<Message> {
        unsafe {
            from_glib_full(ffi::gst_bus_timed_pop(
                self.to_glib_none().0,
                timeout.into().into_glib(),
            ))
        }
    }

    /// A message has been posted on the bus. This signal is emitted from a
    /// [`glib::Source`][crate::glib::Source] added to the mainloop. this signal will only be emitted when
    /// there is a `GMainLoop` running.
    /// ## `message`
    /// the message that has been posted asynchronously
    #[doc(alias = "message")]
    pub fn connect_message<F: Fn(&Self, &Message) + Send + 'static>(
        &self,
        detail: Option<&str>,
        f: F,
    ) -> SignalHandlerId {
        unsafe extern "C" fn message_trampoline<F: Fn(&Bus, &Message) + Send + 'static>(
            this: *mut ffi::GstBus,
            message: *mut ffi::GstMessage,
            f: glib::ffi::gpointer,
        ) {
            let f: &F = &*(f as *const F);
            f(&from_glib_borrow(this), &from_glib_borrow(message))
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            let detailed_signal_name = detail.map(|name| format!("message::{name}\0"));
            let signal_name: &[u8] = detailed_signal_name
                .as_ref()
                .map_or(&b"message\0"[..], |n| n.as_bytes());
            connect_raw(
                self.as_ptr() as *mut _,
                signal_name.as_ptr() as *const _,
                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
                    message_trampoline::<F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }

    /// A message has been posted on the bus. This signal is emitted from the
    /// thread that posted the message so one has to be careful with locking.
    ///
    /// This signal will not be emitted by default, you have to call
    /// [`enable_sync_message_emission()`][Self::enable_sync_message_emission()] before.
    /// ## `message`
    /// the message that has been posted synchronously
    #[doc(alias = "sync-message")]
    pub fn connect_sync_message<F: Fn(&Self, &Message) + Send + Sync + 'static>(
        &self,
        detail: Option<&str>,
        f: F,
    ) -> SignalHandlerId {
        unsafe extern "C" fn sync_message_trampoline<
            F: Fn(&Bus, &Message) + Send + Sync + 'static,
        >(
            this: *mut ffi::GstBus,
            message: *mut ffi::GstMessage,
            f: glib::ffi::gpointer,
        ) {
            let f: &F = &*(f as *const F);
            f(&from_glib_borrow(this), &from_glib_borrow(message))
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            let detailed_signal_name = detail.map(|name| format!("sync-message::{name}\0"));
            let signal_name: &[u8] = detailed_signal_name
                .as_ref()
                .map_or(&b"sync-message\0"[..], |n| n.as_bytes());
            connect_raw(
                self.as_ptr() as *mut _,
                signal_name.as_ptr() as *const _,
                Some(std::mem::transmute::<*const (), unsafe extern "C" fn()>(
                    sync_message_trampoline::<F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }
}

impl Default for Bus {
    fn default() -> Self {
        Self::new()
    }
}

unsafe impl Send for Bus {}
unsafe impl Sync for Bus {}