gstreamer/subclass/
clock.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use glib::{prelude::*, subclass::prelude::*, translate::*};
4
5use super::prelude::*;
6use crate::{ffi, Clock, ClockError, ClockId, ClockReturn, ClockSuccess, ClockTime, ClockTimeDiff};
7
8pub trait ClockImpl: ClockImplExt + GstObjectImpl + Send + Sync {
9    fn change_resolution(&self, old_resolution: ClockTime, new_resolution: ClockTime) -> ClockTime {
10        self.parent_change_resolution(old_resolution, new_resolution)
11    }
12
13    fn resolution(&self) -> ClockTime {
14        self.parent_resolution()
15    }
16
17    fn internal_time(&self) -> ClockTime {
18        self.parent_internal_time()
19    }
20
21    fn wait(&self, id: &ClockId) -> (Result<ClockSuccess, ClockError>, ClockTimeDiff) {
22        self.parent_wait(id)
23    }
24
25    fn wait_async(&self, id: &ClockId) -> Result<ClockSuccess, ClockError> {
26        self.parent_wait_async(id)
27    }
28
29    fn unschedule(&self, id: &ClockId) {
30        self.parent_unschedule(id)
31    }
32}
33
34mod sealed {
35    pub trait Sealed {}
36    impl<T: super::ClockImplExt> Sealed for T {}
37}
38
39pub trait ClockImplExt: sealed::Sealed + ObjectSubclass {
40    fn parent_change_resolution(
41        &self,
42        old_resolution: ClockTime,
43        new_resolution: ClockTime,
44    ) -> ClockTime;
45
46    fn parent_resolution(&self) -> ClockTime {
47        unsafe {
48            let data = Self::type_data();
49            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
50
51            try_from_glib(
52                (*parent_class)
53                    .get_resolution
54                    .map(|f| f(self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0))
55                    .unwrap_or(1),
56            )
57            .expect("undefined resolution")
58        }
59    }
60
61    fn parent_internal_time(&self) -> ClockTime {
62        unsafe {
63            let data = Self::type_data();
64            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
65
66            try_from_glib(
67                (*parent_class)
68                    .get_internal_time
69                    .map(|f| f(self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0))
70                    .unwrap_or(0),
71            )
72            .expect("undefined internal_time")
73        }
74    }
75
76    fn parent_wait(&self, id: &ClockId) -> (Result<ClockSuccess, ClockError>, ClockTimeDiff) {
77        unsafe {
78            let data = Self::type_data();
79            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
80            let mut jitter = 0;
81
82            (
83                try_from_glib(
84                    (*parent_class)
85                        .wait
86                        .map(|f| {
87                            f(
88                                self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0,
89                                id.as_ptr() as *mut ffi::GstClockEntry,
90                                &mut jitter,
91                            )
92                        })
93                        .unwrap_or(ffi::GST_CLOCK_UNSUPPORTED),
94                ),
95                jitter,
96            )
97        }
98    }
99
100    fn parent_wait_async(&self, id: &ClockId) -> Result<ClockSuccess, ClockError> {
101        unsafe {
102            let data = Self::type_data();
103            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
104            try_from_glib(
105                (*parent_class)
106                    .wait_async
107                    .map(|f| {
108                        f(
109                            self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0,
110                            id.as_ptr() as *mut ffi::GstClockEntry,
111                        )
112                    })
113                    .unwrap_or(ffi::GST_CLOCK_UNSUPPORTED),
114            )
115        }
116    }
117
118    fn parent_unschedule(&self, id: &ClockId) {
119        unsafe {
120            let data = Self::type_data();
121            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
122            if let Some(func) = (*parent_class).unschedule {
123                func(
124                    self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0,
125                    id.as_ptr() as *mut ffi::GstClockEntry,
126                );
127            }
128        }
129    }
130
131    fn wake_id(&self, id: &ClockId) {
132        let clock = self.obj();
133        let clock = unsafe { clock.unsafe_cast_ref::<Clock>() };
134
135        cfg_if::cfg_if! {
136            if #[cfg(feature = "v1_16")] {
137                assert!(id.uses_clock(clock));
138            } else {
139                unsafe {
140                    let ptr = id.as_ptr() as *mut ffi::GstClockEntry;
141                    assert_eq!((*ptr).clock, clock.to_glib_none().0);
142                }
143            }
144        }
145
146        unsafe {
147            let ptr = id.as_ptr() as *mut ffi::GstClockEntry;
148            if let Some(func) = (*ptr).func {
149                func(
150                    clock.to_glib_none().0,
151                    (*ptr).time,
152                    ptr as ffi::GstClockID,
153                    (*ptr).user_data,
154                );
155            }
156            if (*ptr).type_ == ffi::GST_CLOCK_ENTRY_PERIODIC {
157                (*ptr).time += (*ptr).interval;
158            }
159        }
160    }
161}
162
163impl<T: ClockImpl> ClockImplExt for T {
164    fn parent_change_resolution(
165        &self,
166        old_resolution: ClockTime,
167        new_resolution: ClockTime,
168    ) -> ClockTime {
169        unsafe {
170            let data = Self::type_data();
171            let parent_class = data.as_ref().parent_class() as *mut ffi::GstClockClass;
172
173            if let Some(func) = (*parent_class).change_resolution {
174                try_from_glib(func(
175                    self.obj().unsafe_cast_ref::<Clock>().to_glib_none().0,
176                    old_resolution.into_glib(),
177                    new_resolution.into_glib(),
178                ))
179                .expect("undefined resolution")
180            } else {
181                self.resolution()
182            }
183        }
184    }
185}
186
187unsafe impl<T: ClockImpl> IsSubclassable<T> for Clock {
188    fn class_init(klass: &mut glib::Class<Self>) {
189        Self::parent_class_init::<T>(klass);
190        let klass = klass.as_mut();
191        klass.change_resolution = Some(clock_change_resolution::<T>);
192        klass.get_resolution = Some(clock_get_resolution::<T>);
193        klass.get_internal_time = Some(clock_get_internal_time::<T>);
194        klass.wait = Some(clock_wait::<T>);
195        klass.wait_async = Some(clock_wait_async::<T>);
196        klass.unschedule = Some(clock_unschedule::<T>);
197    }
198}
199
200unsafe extern "C" fn clock_change_resolution<T: ClockImpl>(
201    ptr: *mut ffi::GstClock,
202    old_resolution: ffi::GstClockTime,
203    new_resolution: ffi::GstClockTime,
204) -> ffi::GstClockTime {
205    let instance = &*(ptr as *mut T::Instance);
206    let imp = instance.imp();
207
208    let old_resolution = match from_glib(old_resolution) {
209        Some(old_resolution) => old_resolution,
210        None => return ffi::GST_CLOCK_TIME_NONE,
211    };
212    let new_resolution = match from_glib(new_resolution) {
213        Some(new_resolution) => new_resolution,
214        None => return ffi::GST_CLOCK_TIME_NONE,
215    };
216
217    imp.change_resolution(old_resolution, new_resolution)
218        .into_glib()
219}
220
221unsafe extern "C" fn clock_get_resolution<T: ClockImpl>(
222    ptr: *mut ffi::GstClock,
223) -> ffi::GstClockTime {
224    let instance = &*(ptr as *mut T::Instance);
225    let imp = instance.imp();
226
227    imp.resolution().into_glib()
228}
229
230unsafe extern "C" fn clock_get_internal_time<T: ClockImpl>(
231    ptr: *mut ffi::GstClock,
232) -> ffi::GstClockTime {
233    let instance = &*(ptr as *mut T::Instance);
234    let imp = instance.imp();
235
236    imp.internal_time().into_glib()
237}
238
239unsafe extern "C" fn clock_wait<T: ClockImpl>(
240    ptr: *mut ffi::GstClock,
241    id: *mut ffi::GstClockEntry,
242    jitter: *mut ffi::GstClockTimeDiff,
243) -> ffi::GstClockReturn {
244    let instance = &*(ptr as *mut T::Instance);
245    let imp = instance.imp();
246
247    let (res, j) = imp.wait(&from_glib_borrow(id as ffi::GstClockID));
248    if !jitter.is_null() {
249        *jitter = j;
250    }
251
252    ClockReturn::from(res).into_glib()
253}
254
255unsafe extern "C" fn clock_wait_async<T: ClockImpl>(
256    ptr: *mut ffi::GstClock,
257    id: *mut ffi::GstClockEntry,
258) -> ffi::GstClockReturn {
259    let instance = &*(ptr as *mut T::Instance);
260    let imp = instance.imp();
261
262    ClockReturn::from(imp.wait_async(&from_glib_borrow(id as ffi::GstClockID))).into_glib()
263}
264
265unsafe extern "C" fn clock_unschedule<T: ClockImpl>(
266    ptr: *mut ffi::GstClock,
267    id: *mut ffi::GstClockEntry,
268) {
269    let instance = &*(ptr as *mut T::Instance);
270    let imp = instance.imp();
271
272    imp.unschedule(&from_glib_borrow(id as ffi::GstClockID));
273}