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