gstreamer/
object.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, signal::SignalHandlerId, translate::*};
4
5use crate::{ffi, ClockTime, Object, ObjectFlags};
6
7pub trait GstObjectExtManual: IsA<Object> + 'static {
8    #[doc(alias = "deep-notify")]
9    fn connect_deep_notify<
10        F: Fn(&Self, &crate::Object, &glib::ParamSpec) + Send + Sync + 'static,
11    >(
12        &self,
13        name: Option<&str>,
14        f: F,
15    ) -> SignalHandlerId {
16        let signal_name = if let Some(name) = name {
17            format!("deep-notify::{name}")
18        } else {
19            "deep-notify".into()
20        };
21
22        let obj: Borrowed<glib::Object> =
23            unsafe { from_glib_borrow(self.as_ptr() as *mut glib::gobject_ffi::GObject) };
24
25        obj.connect(signal_name.as_str(), false, move |values| {
26            // It would be nice to display the actual signal name in the panic messages below,
27            // but that would require to copy `signal_name` so as to move it into the closure
28            // which seems too much for the messages of development errors
29            let obj: Self = unsafe {
30                values[0]
31                    .get::<crate::Object>()
32                    .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[0]: {err}"))
33                    .unsafe_cast()
34            };
35            let prop_obj: crate::Object = values[1]
36                .get()
37                .unwrap_or_else(|err| panic!("Object signal \"deep-notify\": values[1]: {err}"));
38
39            let pspec = unsafe {
40                let pspec = glib::gobject_ffi::g_value_get_param(values[2].to_glib_none().0);
41                from_glib_none(pspec)
42            };
43
44            f(&obj, &prop_obj, &pspec);
45
46            None
47        })
48    }
49
50    fn set_object_flags(&self, flags: ObjectFlags) {
51        unsafe {
52            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
53            let _guard = self.as_ref().object_lock();
54            (*ptr).flags |= flags.into_glib();
55        }
56    }
57
58    fn unset_object_flags(&self, flags: ObjectFlags) {
59        unsafe {
60            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
61            let _guard = self.as_ref().object_lock();
62            (*ptr).flags &= !flags.into_glib();
63        }
64    }
65
66    #[doc(alias = "get_object_flags")]
67    fn object_flags(&self) -> ObjectFlags {
68        unsafe {
69            let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
70            let _guard = self.as_ref().object_lock();
71            from_glib((*ptr).flags)
72        }
73    }
74
75    #[doc(alias = "get_g_value_array")]
76    #[doc(alias = "gst_object_get_g_value_array")]
77    fn g_value_array(
78        &self,
79        property_name: &str,
80        timestamp: ClockTime,
81        interval: ClockTime,
82        values: &mut [glib::Value],
83    ) -> Result<(), glib::error::BoolError> {
84        let n_values = values.len() as u32;
85        unsafe {
86            glib::result_from_gboolean!(
87                ffi::gst_object_get_g_value_array(
88                    self.as_ref().to_glib_none().0,
89                    property_name.to_glib_none().0,
90                    timestamp.into_glib(),
91                    interval.into_glib(),
92                    n_values,
93                    values.as_mut_ptr() as *mut glib::gobject_ffi::GValue,
94                ),
95                "Failed to get value array"
96            )
97        }
98    }
99
100    #[inline]
101    fn object_lock(&self) -> crate::utils::ObjectLockGuard<Self> {
102        crate::utils::ObjectLockGuard::acquire(self)
103    }
104}
105
106impl<O: IsA<Object>> GstObjectExtManual for O {}
107
108#[cfg(test)]
109mod tests {
110    use std::sync::{Arc, Mutex};
111
112    use super::*;
113    use crate::prelude::*;
114
115    #[test]
116    fn test_deep_notify() {
117        crate::init().unwrap();
118
119        let bin = crate::Bin::new();
120        let identity = crate::ElementFactory::make("identity")
121            .name("id")
122            .build()
123            .unwrap();
124        bin.add(&identity).unwrap();
125
126        let notify = Arc::new(Mutex::new(None));
127        let notify_clone = notify.clone();
128        bin.connect_deep_notify(None, move |_, id, prop| {
129            *notify_clone.lock().unwrap() = Some((id.clone(), prop.name()));
130        });
131
132        identity.set_property("silent", false);
133        assert_eq!(
134            *notify.lock().unwrap(),
135            Some((identity.upcast::<crate::Object>(), "silent"))
136        );
137    }
138}