1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{boxed::Box as Box_, mem::transmute, path};
4
5use glib::{
6 prelude::*,
7 signal::{connect_raw, SignalHandlerId},
8 translate::*,
9 GString,
10};
11
12use crate::{prelude::*, Bin, BinFlags, Element, LoggableError};
13
14impl Bin {
15 // rustdoc-stripper-ignore-next
16 /// Creates a new [`Bin`] object with a default name.
17 ///
18 /// Use [`Bin::with_name()`] to create a [`Bin`] with a specific name.
19 /// Use [`Bin::builder()`] for additional configuration.
20 #[doc(alias = "gst_bin_new")]
21 pub fn new() -> Bin {
22 assert_initialized_main_thread!();
23 unsafe { Element::from_glib_none(ffi::gst_bin_new(std::ptr::null())).unsafe_cast() }
24 }
25
26 // rustdoc-stripper-ignore-next
27 /// Creates a new [`Bin`] object with the specified name.
28 ///
29 /// Use [`Bin::builder()`] for additional configuration.
30 #[doc(alias = "gst_bin_new")]
31 pub fn with_name(name: &str) -> Bin {
32 assert_initialized_main_thread!();
33 unsafe { Element::from_glib_none(ffi::gst_bin_new(name.to_glib_none().0)).unsafe_cast() }
34 }
35
36 // rustdoc-stripper-ignore-next
37 /// Creates a new builder-pattern struct instance to construct [`Bin`] objects.
38 ///
39 /// This method returns an instance of [`BinBuilder`] which can be used to create [`Bin`] objects.
40 pub fn builder() -> BinBuilder {
41 BinBuilder::new()
42 }
43}
44
45mod sealed {
46 pub trait Sealed {}
47 impl<T: super::IsA<super::Bin>> Sealed for T {}
48}
49
50pub trait GstBinExtManual: sealed::Sealed + IsA<Bin> + 'static {
51 #[doc(alias = "gst_bin_add_many")]
52 fn add_many(
53 &self,
54 elements: impl IntoIterator<Item = impl AsRef<Element>>,
55 ) -> Result<(), glib::BoolError> {
56 for e in elements {
57 unsafe {
58 glib::result_from_gboolean!(
59 ffi::gst_bin_add(self.as_ref().to_glib_none().0, e.as_ref().to_glib_none().0),
60 "Failed to add elements"
61 )?;
62 }
63 }
64
65 Ok(())
66 }
67
68 #[doc(alias = "gst_bin_remove_many")]
69 fn remove_many(
70 &self,
71 elements: impl IntoIterator<Item = impl AsRef<Element>>,
72 ) -> Result<(), glib::BoolError> {
73 for e in elements {
74 unsafe {
75 glib::result_from_gboolean!(
76 ffi::gst_bin_remove(
77 self.as_ref().to_glib_none().0,
78 e.as_ref().to_glib_none().0,
79 ),
80 "Failed to remove elements"
81 )?;
82 }
83 }
84
85 Ok(())
86 }
87
88 #[doc(alias = "do-latency")]
89 fn connect_do_latency<F: Fn(&Self) -> Result<(), LoggableError> + Send + Sync + 'static>(
90 &self,
91 f: F,
92 ) -> SignalHandlerId {
93 unsafe {
94 let f: Box_<F> = Box_::new(f);
95 connect_raw(
96 self.as_ptr() as *mut _,
97 b"do-latency\0".as_ptr() as *const _,
98 Some(transmute::<_, unsafe extern "C" fn()>(
99 do_latency_trampoline::<Self, F> as *const (),
100 )),
101 Box_::into_raw(f),
102 )
103 }
104 }
105
106 #[cfg(feature = "v1_18")]
107 #[cfg_attr(docsrs, doc(cfg(feature = "v1_18")))]
108 #[doc(alias = "gst_bin_iterate_all_by_element_factory_name")]
109 fn iterate_all_by_element_factory_name(&self, factory_name: &str) -> crate::Iterator<Element> {
110 unsafe {
111 from_glib_full(ffi::gst_bin_iterate_all_by_element_factory_name(
112 self.as_ref().to_glib_none().0,
113 factory_name.to_glib_none().0,
114 ))
115 }
116 }
117 #[doc(alias = "gst_bin_iterate_all_by_interface")]
118 fn iterate_all_by_interface(&self, iface: glib::types::Type) -> crate::Iterator<Element> {
119 unsafe {
120 from_glib_full(ffi::gst_bin_iterate_all_by_interface(
121 self.as_ref().to_glib_none().0,
122 iface.into_glib(),
123 ))
124 }
125 }
126
127 #[doc(alias = "gst_bin_iterate_elements")]
128 fn iterate_elements(&self) -> crate::Iterator<Element> {
129 unsafe {
130 from_glib_full(ffi::gst_bin_iterate_elements(
131 self.as_ref().to_glib_none().0,
132 ))
133 }
134 }
135
136 #[doc(alias = "gst_bin_iterate_recurse")]
137 fn iterate_recurse(&self) -> crate::Iterator<Element> {
138 unsafe { from_glib_full(ffi::gst_bin_iterate_recurse(self.as_ref().to_glib_none().0)) }
139 }
140
141 #[doc(alias = "gst_bin_iterate_sinks")]
142 fn iterate_sinks(&self) -> crate::Iterator<Element> {
143 unsafe { from_glib_full(ffi::gst_bin_iterate_sinks(self.as_ref().to_glib_none().0)) }
144 }
145
146 #[doc(alias = "gst_bin_iterate_sorted")]
147 fn iterate_sorted(&self) -> crate::Iterator<Element> {
148 unsafe { from_glib_full(ffi::gst_bin_iterate_sorted(self.as_ref().to_glib_none().0)) }
149 }
150
151 #[doc(alias = "gst_bin_iterate_sources")]
152 fn iterate_sources(&self) -> crate::Iterator<Element> {
153 unsafe { from_glib_full(ffi::gst_bin_iterate_sources(self.as_ref().to_glib_none().0)) }
154 }
155
156 #[doc(alias = "get_children")]
157 fn children(&self) -> Vec<Element> {
158 unsafe {
159 let bin: &ffi::GstBin = &*(self.as_ptr() as *const _);
160 let _guard = self.as_ref().object_lock();
161 FromGlibPtrContainer::from_glib_none(bin.children)
162 }
163 }
164
165 #[doc(alias = "gst_debug_bin_to_dot_data")]
166 fn debug_to_dot_data(&self, details: crate::DebugGraphDetails) -> GString {
167 crate::debug_bin_to_dot_data(self, details)
168 }
169
170 #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE")]
171 #[doc(alias = "gst_debug_bin_to_dot_file")]
172 fn debug_to_dot_file(
173 &self,
174 details: crate::DebugGraphDetails,
175 file_name: impl AsRef<path::Path>,
176 ) {
177 crate::debug_bin_to_dot_file(self, details, file_name)
178 }
179
180 #[doc(alias = "GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS")]
181 #[doc(alias = "gst_debug_bin_to_dot_file_with_ts")]
182 fn debug_to_dot_file_with_ts(
183 &self,
184 details: crate::DebugGraphDetails,
185 file_name: impl AsRef<path::Path>,
186 ) {
187 crate::debug_bin_to_dot_file_with_ts(self, details, file_name)
188 }
189
190 fn set_bin_flags(&self, flags: BinFlags) {
191 unsafe {
192 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
193 let _guard = self.as_ref().object_lock();
194 (*ptr).flags |= flags.into_glib();
195 }
196 }
197
198 fn unset_bin_flags(&self, flags: BinFlags) {
199 unsafe {
200 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
201 let _guard = self.as_ref().object_lock();
202 (*ptr).flags &= !flags.into_glib();
203 }
204 }
205
206 #[doc(alias = "get_bin_flags")]
207 fn bin_flags(&self) -> BinFlags {
208 unsafe {
209 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
210 let _guard = self.as_ref().object_lock();
211 from_glib((*ptr).flags)
212 }
213 }
214}
215
216impl<O: IsA<Bin>> GstBinExtManual for O {}
217
218impl Default for Bin {
219 fn default() -> Self {
220 glib::object::Object::new()
221 }
222}
223
224// rustdoc-stripper-ignore-next
225/// A [builder-pattern] type to construct [`Bin`] objects.
226///
227/// [builder-pattern]: https://doc.rust-lang.org/1.0.0/style/ownership/builders.html
228#[must_use = "The builder must be built to be used"]
229pub struct BinBuilder {
230 builder: glib::object::ObjectBuilder<'static, Bin>,
231}
232
233impl BinBuilder {
234 fn new() -> Self {
235 Self {
236 builder: glib::Object::builder(),
237 }
238 }
239
240 // rustdoc-stripper-ignore-next
241 /// Build the [`Bin`].
242 #[must_use = "Building the object from the builder is usually expensive and is not expected to have side effects"]
243 pub fn build(self) -> Bin {
244 self.builder.build()
245 }
246
247 pub fn async_handling(self, async_handling: bool) -> Self {
248 Self {
249 builder: self.builder.property("async-handling", async_handling),
250 }
251 }
252
253 pub fn message_forward(self, message_forward: bool) -> Self {
254 Self {
255 builder: self.builder.property("message-forward", message_forward),
256 }
257 }
258
259 pub fn name(self, name: impl Into<glib::GString>) -> Self {
260 Self {
261 builder: self.builder.property("name", name.into()),
262 }
263 }
264}
265
266unsafe extern "C" fn do_latency_trampoline<
267 P,
268 F: Fn(&P) -> Result<(), LoggableError> + Send + Sync + 'static,
269>(
270 this: *mut ffi::GstBin,
271 f: glib::ffi::gpointer,
272) -> glib::ffi::gboolean
273where
274 P: IsA<Bin>,
275{
276 let f: &F = &*(f as *const F);
277 matchbool f(Bin::from_glib_borrow(_ptr:this).unsafe_cast_ref()) {
278 Ok(()) => true,
279 Err(err: LoggableError) => {
280 err.log_with_object(&*Bin::from_glib_borrow(_ptr:this));
281 false
282 }
283 }
284 .into_glib()
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_get_children() {
293 crate::init().unwrap();
294
295 let bin = crate::Bin::new();
296 bin.add(
297 &crate::ElementFactory::make("identity")
298 .name("identity0")
299 .build()
300 .unwrap(),
301 )
302 .unwrap();
303 bin.add(
304 &crate::ElementFactory::make("identity")
305 .name("identity1")
306 .build()
307 .unwrap(),
308 )
309 .unwrap();
310
311 let mut child_names = bin
312 .children()
313 .iter()
314 .map(|c| c.name())
315 .collect::<Vec<GString>>();
316 child_names.sort();
317 assert_eq!(
318 child_names,
319 vec![String::from("identity0"), String::from("identity1")]
320 );
321 }
322}
323