1 // Copyright (C) 2017 Sebastian Dröge <sebastian@centricular.com>
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8
9 use glib;
10 #[cfg(any(feature = "v1_16", feature = "dox"))]
11 use glib::prelude::*;
12 use glib::translate::*;
13 use glib::IsA;
14 use glib_sys::{gboolean, gpointer};
15 use gst_sys;
16 use libc::c_void;
17 use std::cmp;
18 use std::ptr;
19 use Clock;
20 use ClockEntryType;
21 use ClockError;
22 use ClockFlags;
23 use ClockReturn;
24 use ClockSuccess;
25 use ClockTime;
26 use ClockTimeDiff;
27
28 use std::sync::atomic;
29 use std::sync::atomic::AtomicI32;
30
31 glib_wrapper! {
32 #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
33 pub struct ClockId(Shared<c_void>);
34
35 match fn {
36 ref => |ptr| gst_sys::gst_clock_id_ref(ptr),
37 unref => |ptr| gst_sys::gst_clock_id_unref(ptr),
38 }
39 }
40
trampoline_wait_async<F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static>( clock: *mut gst_sys::GstClock, time: gst_sys::GstClockTime, id: gpointer, func: gpointer, ) -> gboolean41 unsafe extern "C" fn trampoline_wait_async<F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static>(
42 clock: *mut gst_sys::GstClock,
43 time: gst_sys::GstClockTime,
44 id: gpointer,
45 func: gpointer,
46 ) -> gboolean {
47 let f: &F = &*(func as *const F);
48 f(
49 &from_glib_borrow(clock),
50 from_glib(time),
51 &from_glib_borrow(id),
52 );
53 glib_sys::GTRUE
54 }
55
destroy_closure_wait_async< F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static, >( ptr: gpointer, )56 unsafe extern "C" fn destroy_closure_wait_async<
57 F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static,
58 >(
59 ptr: gpointer,
60 ) {
61 Box::<F>::from_raw(ptr as *mut _);
62 }
63
into_raw_wait_async<F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static>(func: F) -> gpointer64 fn into_raw_wait_async<F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static>(func: F) -> gpointer {
65 #[allow(clippy::type_complexity)]
66 let func: Box<F> = Box::new(func);
67 Box::into_raw(func) as gpointer
68 }
69
70 impl ClockId {
get_time(&self) -> ClockTime71 pub fn get_time(&self) -> ClockTime {
72 unsafe { from_glib(gst_sys::gst_clock_id_get_time(self.to_glib_none().0)) }
73 }
74
unschedule(&self)75 pub fn unschedule(&self) {
76 unsafe { gst_sys::gst_clock_id_unschedule(self.to_glib_none().0) }
77 }
78
wait(&self) -> (Result<ClockSuccess, ClockError>, ClockTimeDiff)79 pub fn wait(&self) -> (Result<ClockSuccess, ClockError>, ClockTimeDiff) {
80 unsafe {
81 let mut jitter = 0;
82 let res: ClockReturn = from_glib(gst_sys::gst_clock_id_wait(
83 self.to_glib_none().0,
84 &mut jitter,
85 ));
86 (res.into_result(), jitter)
87 }
88 }
89
wait_async<F>(&self, func: F) -> Result<ClockSuccess, ClockError> where F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static,90 pub fn wait_async<F>(&self, func: F) -> Result<ClockSuccess, ClockError>
91 where
92 F: Fn(&Clock, ClockTime, &ClockId) + Send + 'static,
93 {
94 let ret: ClockReturn = unsafe {
95 from_glib(gst_sys::gst_clock_id_wait_async(
96 self.to_glib_none().0,
97 Some(trampoline_wait_async::<F>),
98 into_raw_wait_async(func),
99 Some(destroy_closure_wait_async::<F>),
100 ))
101 };
102 ret.into_result()
103 }
104
compare_by_time(&self, other: &Self) -> cmp::Ordering105 pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering {
106 unsafe {
107 let res =
108 gst_sys::gst_clock_id_compare_func(self.to_glib_none().0, other.to_glib_none().0);
109 res.cmp(&0)
110 }
111 }
112
113 #[cfg(any(feature = "v1_16", feature = "dox"))]
get_clock(&self) -> Option<Clock>114 pub fn get_clock(&self) -> Option<Clock> {
115 unsafe { from_glib_full(gst_sys::gst_clock_id_get_clock(self.to_glib_none().0)) }
116 }
117
118 #[cfg(any(feature = "v1_16", feature = "dox"))]
uses_clock<P: IsA<Clock>>(&self, clock: &P) -> bool119 pub fn uses_clock<P: IsA<Clock>>(&self, clock: &P) -> bool {
120 unsafe {
121 from_glib(gst_sys::gst_clock_id_uses_clock(
122 self.to_glib_none().0,
123 clock.as_ref().as_ptr(),
124 ))
125 }
126 }
127
get_type(&self) -> ClockEntryType128 pub fn get_type(&self) -> ClockEntryType {
129 unsafe {
130 let ptr: *mut gst_sys::GstClockEntry = self.to_glib_none().0 as *mut _;
131 from_glib((*ptr).type_)
132 }
133 }
134
get_interval(&self) -> Option<ClockTime>135 pub fn get_interval(&self) -> Option<ClockTime> {
136 if self.get_type() != ClockEntryType::Periodic {
137 return None;
138 }
139
140 unsafe {
141 let ptr: *mut gst_sys::GstClockEntry = self.to_glib_none().0 as *mut _;
142 Some(from_glib((*ptr).interval))
143 }
144 }
145
get_status(&self) -> &AtomicClockReturn146 pub fn get_status(&self) -> &AtomicClockReturn {
147 unsafe {
148 let ptr: *mut gst_sys::GstClockEntry = self.to_glib_none().0 as *mut _;
149 &*((&(*ptr).status) as *const i32 as *const AtomicClockReturn)
150 }
151 }
152 }
153
154 #[repr(C)]
155 #[derive(Debug)]
156 pub struct AtomicClockReturn(AtomicI32);
157
158 impl AtomicClockReturn {
load(&self) -> ClockReturn159 pub fn load(&self) -> ClockReturn {
160 from_glib(self.0.load(atomic::Ordering::SeqCst))
161 }
162
store(&self, val: ClockReturn)163 pub fn store(&self, val: ClockReturn) {
164 self.0.store(val.to_glib(), atomic::Ordering::SeqCst)
165 }
166
swap(&self, val: ClockReturn) -> ClockReturn167 pub fn swap(&self, val: ClockReturn) -> ClockReturn {
168 from_glib(self.0.swap(val.to_glib(), atomic::Ordering::SeqCst))
169 }
170
compare_and_swap(&self, current: ClockReturn, new: ClockReturn) -> ClockReturn171 pub fn compare_and_swap(&self, current: ClockReturn, new: ClockReturn) -> ClockReturn {
172 from_glib(self.0.compare_and_swap(
173 current.to_glib(),
174 new.to_glib(),
175 atomic::Ordering::SeqCst,
176 ))
177 }
178 }
179
180 unsafe impl Send for ClockId {}
181 unsafe impl Sync for ClockId {}
182
183 impl Clock {
adjust_with_calibration( internal_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: ClockTime, cdenom: ClockTime, ) -> ClockTime184 pub fn adjust_with_calibration(
185 internal_target: ClockTime,
186 cinternal: ClockTime,
187 cexternal: ClockTime,
188 cnum: ClockTime,
189 cdenom: ClockTime,
190 ) -> ClockTime {
191 unsafe {
192 from_glib(gst_sys::gst_clock_adjust_with_calibration(
193 ptr::null_mut(),
194 internal_target.to_glib(),
195 cinternal.to_glib(),
196 cexternal.to_glib(),
197 cnum.to_glib(),
198 cdenom.to_glib(),
199 ))
200 }
201 }
202
unadjust_with_calibration( external_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: ClockTime, cdenom: ClockTime, ) -> ClockTime203 pub fn unadjust_with_calibration(
204 external_target: ClockTime,
205 cinternal: ClockTime,
206 cexternal: ClockTime,
207 cnum: ClockTime,
208 cdenom: ClockTime,
209 ) -> ClockTime {
210 unsafe {
211 from_glib(gst_sys::gst_clock_unadjust_with_calibration(
212 ptr::null_mut(),
213 external_target.to_glib(),
214 cinternal.to_glib(),
215 cexternal.to_glib(),
216 cnum.to_glib(),
217 cdenom.to_glib(),
218 ))
219 }
220 }
221 }
222
223 pub trait ClockExtManual: 'static {
new_periodic_id( &self, start_time: ClockTime, interval: ClockTime, ) -> Result<ClockId, glib::BoolError>224 fn new_periodic_id(
225 &self,
226 start_time: ClockTime,
227 interval: ClockTime,
228 ) -> Result<ClockId, glib::BoolError>;
229
periodic_id_reinit( &self, id: &ClockId, start_time: ClockTime, interval: ClockTime, ) -> Result<(), glib::BoolError>230 fn periodic_id_reinit(
231 &self,
232 id: &ClockId,
233 start_time: ClockTime,
234 interval: ClockTime,
235 ) -> Result<(), glib::BoolError>;
236
new_single_shot_id(&self, time: ClockTime) -> Result<ClockId, glib::BoolError>237 fn new_single_shot_id(&self, time: ClockTime) -> Result<ClockId, glib::BoolError>;
238
single_shot_id_reinit(&self, id: &ClockId, time: ClockTime) -> Result<(), glib::BoolError>239 fn single_shot_id_reinit(&self, id: &ClockId, time: ClockTime) -> Result<(), glib::BoolError>;
240
set_clock_flags(&self, flags: ClockFlags)241 fn set_clock_flags(&self, flags: ClockFlags);
242
unset_clock_flags(&self, flags: ClockFlags)243 fn unset_clock_flags(&self, flags: ClockFlags);
244
get_clock_flags(&self) -> ClockFlags245 fn get_clock_flags(&self) -> ClockFlags;
246 }
247
248 impl<O: IsA<Clock>> ClockExtManual for O {
new_periodic_id( &self, start_time: ClockTime, interval: ClockTime, ) -> Result<ClockId, glib::BoolError>249 fn new_periodic_id(
250 &self,
251 start_time: ClockTime,
252 interval: ClockTime,
253 ) -> Result<ClockId, glib::BoolError> {
254 unsafe {
255 Option::<_>::from_glib_full(gst_sys::gst_clock_new_periodic_id(
256 self.as_ref().to_glib_none().0,
257 start_time.to_glib(),
258 interval.to_glib(),
259 ))
260 .ok_or_else(|| glib_bool_error!("Failed to create new periodic clock id"))
261 }
262 }
263
periodic_id_reinit( &self, id: &ClockId, start_time: ClockTime, interval: ClockTime, ) -> Result<(), glib::BoolError>264 fn periodic_id_reinit(
265 &self,
266 id: &ClockId,
267 start_time: ClockTime,
268 interval: ClockTime,
269 ) -> Result<(), glib::BoolError> {
270 skip_assert_initialized!();
271 unsafe {
272 let res: bool = from_glib(gst_sys::gst_clock_periodic_id_reinit(
273 self.as_ref().to_glib_none().0,
274 id.to_glib_none().0,
275 start_time.to_glib(),
276 interval.to_glib(),
277 ));
278 if res {
279 Ok(())
280 } else {
281 Err(glib_bool_error!("Failed to reinit periodic clock id"))
282 }
283 }
284 }
285
new_single_shot_id(&self, time: ClockTime) -> Result<ClockId, glib::BoolError>286 fn new_single_shot_id(&self, time: ClockTime) -> Result<ClockId, glib::BoolError> {
287 unsafe {
288 Option::<_>::from_glib_full(gst_sys::gst_clock_new_single_shot_id(
289 self.as_ref().to_glib_none().0,
290 time.to_glib(),
291 ))
292 .ok_or_else(|| glib_bool_error!("Failed to create new single shot clock id"))
293 }
294 }
295
single_shot_id_reinit(&self, id: &ClockId, time: ClockTime) -> Result<(), glib::BoolError>296 fn single_shot_id_reinit(&self, id: &ClockId, time: ClockTime) -> Result<(), glib::BoolError> {
297 unsafe {
298 let res: bool = from_glib(gst_sys::gst_clock_single_shot_id_reinit(
299 self.as_ref().to_glib_none().0,
300 id.to_glib_none().0,
301 time.to_glib(),
302 ));
303 if res {
304 Ok(())
305 } else {
306 Err(glib_bool_error!("Failed to reinit single shot clock id"))
307 }
308 }
309 }
310
set_clock_flags(&self, flags: ClockFlags)311 fn set_clock_flags(&self, flags: ClockFlags) {
312 unsafe {
313 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
314 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
315 (*ptr).flags |= flags.to_glib();
316 }
317 }
318
unset_clock_flags(&self, flags: ClockFlags)319 fn unset_clock_flags(&self, flags: ClockFlags) {
320 unsafe {
321 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
322 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
323 (*ptr).flags &= !flags.to_glib();
324 }
325 }
326
get_clock_flags(&self) -> ClockFlags327 fn get_clock_flags(&self) -> ClockFlags {
328 unsafe {
329 let ptr: *mut gst_sys::GstObject = self.as_ptr() as *mut _;
330 let _guard = ::utils::MutexGuard::lock(&(*ptr).lock);
331 from_glib((*ptr).flags)
332 }
333 }
334 }
335
336 #[cfg(test)]
337 mod tests {
338 use super::super::*;
339 use super::*;
340 use std::sync::mpsc::channel;
341
342 #[test]
test_wait()343 fn test_wait() {
344 ::init().unwrap();
345
346 let clock = SystemClock::obtain();
347 let now = clock.get_time();
348 let id = clock.new_single_shot_id(now + 20 * ::MSECOND).unwrap();
349 let (res, _) = id.wait();
350
351 assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early));
352 }
353
354 #[test]
test_wait_async()355 fn test_wait_async() {
356 ::init().unwrap();
357
358 let (sender, receiver) = channel();
359
360 let clock = SystemClock::obtain();
361 let now = clock.get_time();
362 let id = clock.new_single_shot_id(now + 20 * ::MSECOND).unwrap();
363 let res = id.wait_async(move |_, _, _| {
364 sender.send(()).unwrap();
365 });
366
367 assert!(res == Ok(ClockSuccess::Ok));
368
369 assert_eq!(receiver.recv(), Ok(()));
370 }
371 }
372