gstreamer/subclass/
device_provider.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::borrow::Cow;
4
5use glib::{prelude::*, subclass::prelude::*, translate::*};
6
7use super::prelude::*;
8use crate::{ffi, Device, DeviceProvider, LoggableError};
9
10#[derive(Debug, Clone)]
11pub struct DeviceProviderMetadata {
12    long_name: Cow<'static, str>,
13    classification: Cow<'static, str>,
14    description: Cow<'static, str>,
15    author: Cow<'static, str>,
16    additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>,
17}
18
19impl DeviceProviderMetadata {
20    pub fn new(long_name: &str, classification: &str, description: &str, author: &str) -> Self {
21        Self {
22            long_name: Cow::Owned(long_name.into()),
23            classification: Cow::Owned(classification.into()),
24            description: Cow::Owned(description.into()),
25            author: Cow::Owned(author.into()),
26            additional: Cow::Borrowed(&[]),
27        }
28    }
29
30    pub fn with_additional(
31        long_name: &str,
32        classification: &str,
33        description: &str,
34        author: &str,
35        additional: &[(&str, &str)],
36    ) -> Self {
37        Self {
38            long_name: Cow::Owned(long_name.into()),
39            classification: Cow::Owned(classification.into()),
40            description: Cow::Owned(description.into()),
41            author: Cow::Owned(author.into()),
42            additional: additional
43                .iter()
44                .copied()
45                .map(|(key, value)| (Cow::Owned(key.into()), Cow::Owned(value.into())))
46                .collect(),
47        }
48    }
49
50    pub const fn with_cow(
51        long_name: Cow<'static, str>,
52        classification: Cow<'static, str>,
53        description: Cow<'static, str>,
54        author: Cow<'static, str>,
55        additional: Cow<'static, [(Cow<'static, str>, Cow<'static, str>)]>,
56    ) -> Self {
57        Self {
58            long_name,
59            classification,
60            description,
61            author,
62            additional,
63        }
64    }
65}
66
67pub trait DeviceProviderImpl: DeviceProviderImplExt + GstObjectImpl + Send + Sync {
68    fn metadata() -> Option<&'static DeviceProviderMetadata> {
69        None
70    }
71
72    fn probe(&self) -> Vec<Device> {
73        self.parent_probe()
74    }
75
76    fn start(&self) -> Result<(), LoggableError> {
77        self.parent_start()
78    }
79
80    fn stop(&self) {
81        self.parent_stop()
82    }
83}
84
85mod sealed {
86    pub trait Sealed {}
87    impl<T: super::DeviceProviderImplExt> Sealed for T {}
88}
89
90pub trait DeviceProviderImplExt: sealed::Sealed + ObjectSubclass {
91    fn parent_probe(&self) -> Vec<Device> {
92        unsafe {
93            let data = Self::type_data();
94            let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass;
95            if let Some(f) = (*parent_class).probe {
96                FromGlibPtrContainer::from_glib_full(f(self
97                    .obj()
98                    .unsafe_cast_ref::<DeviceProvider>()
99                    .to_glib_none()
100                    .0))
101            } else {
102                Vec::new()
103            }
104        }
105    }
106
107    fn parent_start(&self) -> Result<(), LoggableError> {
108        unsafe {
109            let data = Self::type_data();
110            let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass;
111            let f = (*parent_class).start.ok_or_else(|| {
112                loggable_error!(crate::CAT_RUST, "Parent function `start` is not defined")
113            })?;
114            result_from_gboolean!(
115                f(self
116                    .obj()
117                    .unsafe_cast_ref::<DeviceProvider>()
118                    .to_glib_none()
119                    .0),
120                crate::CAT_RUST,
121                "Failed to start the device provider using the parent function"
122            )
123        }
124    }
125
126    fn parent_stop(&self) {
127        unsafe {
128            let data = Self::type_data();
129            let parent_class = data.as_ref().parent_class() as *mut ffi::GstDeviceProviderClass;
130            if let Some(f) = (*parent_class).stop {
131                f(self
132                    .obj()
133                    .unsafe_cast_ref::<DeviceProvider>()
134                    .to_glib_none()
135                    .0);
136            }
137        }
138    }
139}
140
141impl<T: DeviceProviderImpl> DeviceProviderImplExt for T {}
142
143unsafe impl<T: DeviceProviderImpl> IsSubclassable<T> for DeviceProvider {
144    fn class_init(klass: &mut glib::Class<Self>) {
145        Self::parent_class_init::<T>(klass);
146        let klass = klass.as_mut();
147        klass.probe = Some(device_provider_probe::<T>);
148        klass.start = Some(device_provider_start::<T>);
149        klass.stop = Some(device_provider_stop::<T>);
150
151        unsafe {
152            if let Some(metadata) = T::metadata() {
153                ffi::gst_device_provider_class_set_metadata(
154                    klass,
155                    metadata.long_name.to_glib_none().0,
156                    metadata.classification.to_glib_none().0,
157                    metadata.description.to_glib_none().0,
158                    metadata.author.to_glib_none().0,
159                );
160
161                for (key, value) in metadata.additional.iter() {
162                    ffi::gst_device_provider_class_add_metadata(
163                        klass,
164                        key.to_glib_none().0,
165                        value.to_glib_none().0,
166                    );
167                }
168            }
169        }
170    }
171}
172
173unsafe extern "C" fn device_provider_probe<T: DeviceProviderImpl>(
174    ptr: *mut ffi::GstDeviceProvider,
175) -> *mut glib::ffi::GList {
176    let instance = &*(ptr as *mut T::Instance);
177    let imp = instance.imp();
178
179    imp.probe().to_glib_full()
180}
181
182unsafe extern "C" fn device_provider_start<T: DeviceProviderImpl>(
183    ptr: *mut ffi::GstDeviceProvider,
184) -> glib::ffi::gboolean {
185    let instance = &*(ptr as *mut T::Instance);
186    let imp = instance.imp();
187
188    match imp.start() {
189        Ok(()) => true,
190        Err(err) => {
191            err.log_with_imp(imp);
192            false
193        }
194    }
195    .into_glib()
196}
197
198unsafe extern "C" fn device_provider_stop<T: DeviceProviderImpl>(ptr: *mut ffi::GstDeviceProvider) {
199    let instance = &*(ptr as *mut T::Instance);
200    let imp = instance.imp();
201
202    imp.stop();
203}