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::{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: NonNull = Self::type_data();
171 let parent_class: *mut GstClockClass = data.as_ref().parent_class() as *mut ffi::GstClockClass;
172
173 if let Some(func: unsafe fn(*mut GstClock, …) -> …) = (*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(msg:"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>(class:klass);
190 let klass: &mut GstClockClass = 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: &::Instance = &*(ptr as *mut T::Instance);
206 let imp: &T = instance.imp();
207
208 let old_resolution: ClockTime = match from_glib(val:old_resolution) {
209 Some(old_resolution: ClockTime) => old_resolution,
210 None => return ffi::GST_CLOCK_TIME_NONE,
211 };
212 let new_resolution: ClockTime = match from_glib(val:new_resolution) {
213 Some(new_resolution: ClockTime) => new_resolution,
214 None => return ffi::GST_CLOCK_TIME_NONE,
215 };
216
217 impClockTime.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: &::Instance = &*(ptr as *mut T::Instance);
225 let imp: &T = 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: &::Instance = &*(ptr as *mut T::Instance);
234 let imp: &T = 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: &::Instance = &*(ptr as *mut T::Instance);
245 let imp: &T = instance.imp();
246
247 let (res: Result, j: i64) = imp.wait(&from_glib_borrow(ptr: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: &::Instance = &*(ptr as *mut T::Instance);
260 let imp: &T = instance.imp();
261
262 ClockReturn::from(imp.wait_async(&from_glib_borrow(ptr: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: &::Instance = &*(ptr as *mut T::Instance);
270 let imp: &T = instance.imp();
271
272 imp.unschedule(&from_glib_borrow(ptr:id as ffi::GstClockID));
273}
274