1use std::{
4 cmp, ptr,
5 sync::{atomic, atomic::AtomicI32},
6};
7
8#[cfg(feature = "futures")]
9use futures_core::{Future, Stream};
10#[cfg(feature = "futures")]
11use std::{marker::Unpin, pin::Pin};
12
13use glib::{
14 ffi::{gboolean, gpointer},
15 prelude::*,
16 translate::*,
17};
18use libc::c_void;
19
20use crate::{
21 Clock, ClockEntryType, ClockError, ClockFlags, ClockReturn, ClockSuccess, ClockTime,
22 ClockTimeDiff, ffi, prelude::*,
23};
24
25glib::wrapper! {
26 #[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
27 pub struct ClockId(Shared<c_void>);
28
29 match fn {
30 ref => |ptr| ffi::gst_clock_id_ref(ptr),
31 unref => |ptr| ffi::gst_clock_id_unref(ptr),
32 }
33}
34
35impl ClockId {
36 #[doc(alias = "get_time")]
37 #[doc(alias = "gst_clock_id_get_time")]
38 #[doc(alias = "GST_CLOCK_ENTRY_TIME")]
39 pub fn time(&self) -> ClockTime {
40 unsafe {
41 try_from_glib(ffi::gst_clock_id_get_time(self.to_glib_none().0))
42 .expect("undefined time")
43 }
44 }
45
46 #[doc(alias = "gst_clock_id_unschedule")]
47 pub fn unschedule(&self) {
48 unsafe { ffi::gst_clock_id_unschedule(self.to_glib_none().0) }
49 }
50
51 #[doc(alias = "gst_clock_id_wait")]
52 pub fn wait(&self) -> (Result<ClockSuccess, ClockError>, ClockTimeDiff) {
53 unsafe {
54 let mut jitter = 0;
55 let res = try_from_glib(ffi::gst_clock_id_wait(self.to_glib_none().0, &mut jitter));
56 (res, jitter)
57 }
58 }
59
60 #[doc(alias = "gst_clock_id_compare_func")]
61 pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering {
62 unsafe {
63 let res = ffi::gst_clock_id_compare_func(self.to_glib_none().0, other.to_glib_none().0);
64 res.cmp(&0)
65 }
66 }
67
68 #[cfg(feature = "v1_16")]
69 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
70 #[doc(alias = "get_clock")]
71 #[doc(alias = "gst_clock_id_get_clock")]
72 pub fn clock(&self) -> Option<Clock> {
73 unsafe { from_glib_full(ffi::gst_clock_id_get_clock(self.to_glib_none().0)) }
74 }
75
76 #[cfg(feature = "v1_16")]
77 #[cfg_attr(docsrs, doc(cfg(feature = "v1_16")))]
78 #[doc(alias = "gst_clock_id_uses_clock")]
79 pub fn uses_clock<P: IsA<Clock>>(&self, clock: &P) -> bool {
80 unsafe {
81 from_glib(ffi::gst_clock_id_uses_clock(
82 self.to_glib_none().0,
83 clock.as_ref().as_ptr(),
84 ))
85 }
86 }
87
88 #[doc(alias = "get_type")]
89 #[doc(alias = "GST_CLOCK_ENTRY_TYPE")]
90 pub fn type_(&self) -> ClockEntryType {
91 unsafe {
92 let ptr = self.as_ptr() as *mut ffi::GstClockEntry;
93 from_glib((*ptr).type_)
94 }
95 }
96
97 #[doc(alias = "get_status")]
98 #[doc(alias = "GST_CLOCK_ENTRY_STATUS")]
99 pub fn status(&self) -> &AtomicClockReturn {
100 unsafe {
101 let ptr = self.as_ptr() as *mut ffi::GstClockEntry;
102 &*((&(*ptr).status) as *const i32 as *const AtomicClockReturn)
103 }
104 }
105}
106
107#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
108pub struct SingleShotClockId(ClockId);
109
110impl std::ops::Deref for SingleShotClockId {
111 type Target = ClockId;
112
113 #[inline]
114 fn deref(&self) -> &Self::Target {
115 &self.0
116 }
117}
118
119impl From<SingleShotClockId> for ClockId {
120 #[inline]
121 fn from(id: SingleShotClockId) -> ClockId {
122 skip_assert_initialized!();
123 id.0
124 }
125}
126
127impl TryFrom<ClockId> for SingleShotClockId {
128 type Error = glib::BoolError;
129
130 #[inline]
131 fn try_from(id: ClockId) -> Result<SingleShotClockId, glib::BoolError> {
132 skip_assert_initialized!();
133 match id.type_() {
134 ClockEntryType::Single => Ok(SingleShotClockId(id)),
135 _ => Err(glib::bool_error!("Not a single-shot clock id")),
136 }
137 }
138}
139
140impl SingleShotClockId {
141 #[doc(alias = "gst_clock_id_compare_func")]
142 #[inline]
143 pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering {
144 self.0.compare_by_time(&other.0)
145 }
146
147 #[doc(alias = "gst_clock_id_wait_async")]
148 pub fn wait_async<F>(&self, func: F) -> Result<ClockSuccess, ClockError>
149 where
150 F: FnOnce(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
151 {
152 unsafe extern "C" fn trampoline<
153 F: FnOnce(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
154 >(
155 clock: *mut ffi::GstClock,
156 time: ffi::GstClockTime,
157 id: gpointer,
158 func: gpointer,
159 ) -> gboolean {
160 unsafe {
161 let f: &mut Option<F> = &mut *(func as *mut Option<F>);
162 let f = f.take().unwrap();
163
164 f(
165 &from_glib_borrow(clock),
166 from_glib(time),
167 &from_glib_borrow(id),
168 );
169
170 glib::ffi::GTRUE
171 }
172 }
173
174 unsafe extern "C" fn destroy_notify<
175 F: FnOnce(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
176 >(
177 ptr: gpointer,
178 ) {
179 unsafe {
180 let _ = Box::<Option<F>>::from_raw(ptr as *mut _);
181 }
182 }
183
184 let func: Box<Option<F>> = Box::new(Some(func));
185
186 unsafe {
187 try_from_glib(ffi::gst_clock_id_wait_async(
188 self.to_glib_none().0,
189 Some(trampoline::<F>),
190 Box::into_raw(func) as gpointer,
191 Some(destroy_notify::<F>),
192 ))
193 }
194 }
195
196 #[allow(clippy::type_complexity)]
197 #[cfg(feature = "futures")]
198 pub fn wait_async_future(
199 &self,
200 ) -> Result<
201 Pin<
202 Box<
203 dyn Future<Output = Result<(Option<ClockTime>, ClockId), ClockError>>
204 + Send
205 + 'static,
206 >,
207 >,
208 ClockError,
209 > {
210 use futures_channel::oneshot;
211
212 let (sender, receiver) = oneshot::channel();
213
214 self.wait_async(move |_clock, jitter, id| {
215 if sender.send((jitter, id.clone())).is_err() {
216 id.unschedule();
218 }
219 })?;
220
221 Ok(Box::pin(async move {
222 receiver.await.map_err(|_| ClockError::Unscheduled)
223 }))
224 }
225}
226
227#[derive(Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
228pub struct PeriodicClockId(ClockId);
229
230impl std::ops::Deref for PeriodicClockId {
231 type Target = ClockId;
232
233 #[inline]
234 fn deref(&self) -> &Self::Target {
235 &self.0
236 }
237}
238
239impl From<PeriodicClockId> for ClockId {
240 #[inline]
241 fn from(id: PeriodicClockId) -> ClockId {
242 skip_assert_initialized!();
243 id.0
244 }
245}
246
247impl TryFrom<ClockId> for PeriodicClockId {
248 type Error = glib::BoolError;
249
250 #[inline]
251 fn try_from(id: ClockId) -> Result<PeriodicClockId, glib::BoolError> {
252 skip_assert_initialized!();
253 match id.type_() {
254 ClockEntryType::Periodic => Ok(PeriodicClockId(id)),
255 _ => Err(glib::bool_error!("Not a periodic clock id")),
256 }
257 }
258}
259
260impl PeriodicClockId {
261 #[doc(alias = "get_interval")]
262 #[doc(alias = "GST_CLOCK_ENTRY_INTERVAL")]
263 #[inline]
264 pub fn interval(&self) -> ClockTime {
265 unsafe {
266 let ptr = self.as_ptr() as *mut ffi::GstClockEntry;
267 try_from_glib((*ptr).interval).expect("undefined interval")
268 }
269 }
270
271 #[doc(alias = "gst_clock_id_compare_func")]
272 #[inline]
273 pub fn compare_by_time(&self, other: &Self) -> cmp::Ordering {
274 self.0.compare_by_time(&other.0)
275 }
276
277 #[doc(alias = "gst_clock_id_wait_async")]
278 pub fn wait_async<F>(&self, func: F) -> Result<ClockSuccess, ClockError>
279 where
280 F: Fn(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
281 {
282 unsafe extern "C" fn trampoline<
283 F: Fn(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
284 >(
285 clock: *mut ffi::GstClock,
286 time: ffi::GstClockTime,
287 id: gpointer,
288 func: gpointer,
289 ) -> gboolean {
290 unsafe {
291 let f: &F = &*(func as *const F);
292 f(
293 &from_glib_borrow(clock),
294 from_glib(time),
295 &from_glib_borrow(id),
296 );
297 glib::ffi::GTRUE
298 }
299 }
300
301 unsafe extern "C" fn destroy_notify<
302 F: Fn(&Clock, Option<ClockTime>, &ClockId) + Send + 'static,
303 >(
304 ptr: gpointer,
305 ) {
306 unsafe {
307 let _ = Box::<F>::from_raw(ptr as *mut _);
308 }
309 }
310
311 let func: Box<F> = Box::new(func);
312 unsafe {
313 try_from_glib(ffi::gst_clock_id_wait_async(
314 self.to_glib_none().0,
315 Some(trampoline::<F>),
316 Box::into_raw(func) as gpointer,
317 Some(destroy_notify::<F>),
318 ))
319 }
320 }
321
322 #[allow(clippy::type_complexity)]
323 #[cfg(feature = "futures")]
324 pub fn wait_async_stream(
325 &self,
326 ) -> Result<
327 Pin<Box<dyn Stream<Item = (Option<ClockTime>, ClockId)> + Unpin + Send + 'static>>,
328 ClockError,
329 > {
330 use futures_channel::mpsc;
331
332 let (sender, receiver) = mpsc::unbounded();
333
334 self.wait_async(move |_clock, jitter, id| {
335 if sender.unbounded_send((jitter, id.clone())).is_err() {
336 id.unschedule();
338 }
339 })?;
340
341 Ok(Box::pin(receiver))
342 }
343}
344
345#[repr(transparent)]
346#[derive(Debug)]
347pub struct AtomicClockReturn(AtomicI32);
348
349impl AtomicClockReturn {
350 #[inline]
351 pub fn load(&self) -> ClockReturn {
352 unsafe { from_glib(self.0.load(atomic::Ordering::SeqCst)) }
353 }
354
355 #[inline]
356 pub fn store(&self, val: ClockReturn) {
357 self.0.store(val.into_glib(), atomic::Ordering::SeqCst)
358 }
359
360 #[inline]
361 pub fn swap(&self, val: ClockReturn) -> ClockReturn {
362 unsafe { from_glib(self.0.swap(val.into_glib(), atomic::Ordering::SeqCst)) }
363 }
364
365 #[inline]
366 pub fn compare_exchange(
367 &self,
368 current: ClockReturn,
369 new: ClockReturn,
370 ) -> Result<ClockReturn, ClockReturn> {
371 unsafe {
372 self.0
373 .compare_exchange(
374 current.into_glib(),
375 new.into_glib(),
376 atomic::Ordering::SeqCst,
377 atomic::Ordering::SeqCst,
378 )
379 .map(|v| from_glib(v))
380 .map_err(|v| from_glib(v))
381 }
382 }
383}
384
385unsafe impl Send for ClockId {}
386unsafe impl Sync for ClockId {}
387
388impl Clock {
389 #[doc(alias = "gst_clock_adjust_with_calibration")]
390 pub fn adjust_with_calibration(
391 internal_target: ClockTime,
392 cinternal: ClockTime,
393 cexternal: ClockTime,
394 cnum: u64,
395 cdenom: u64,
396 ) -> ClockTime {
397 skip_assert_initialized!();
398 unsafe {
399 try_from_glib(ffi::gst_clock_adjust_with_calibration(
400 ptr::null_mut(),
401 internal_target.into_glib(),
402 cinternal.into_glib(),
403 cexternal.into_glib(),
404 cnum,
405 cdenom,
406 ))
407 .expect("undefined ClockTime")
408 }
409 }
410
411 #[doc(alias = "gst_clock_unadjust_with_calibration")]
412 pub fn unadjust_with_calibration(
413 external_target: ClockTime,
414 cinternal: ClockTime,
415 cexternal: ClockTime,
416 cnum: u64,
417 cdenom: u64,
418 ) -> ClockTime {
419 skip_assert_initialized!();
420 unsafe {
421 try_from_glib(ffi::gst_clock_unadjust_with_calibration(
422 ptr::null_mut(),
423 external_target.into_glib(),
424 cinternal.into_glib(),
425 cexternal.into_glib(),
426 cnum,
427 cdenom,
428 ))
429 .expect("undefined ClockTime")
430 }
431 }
432}
433
434pub trait ClockExtManual: IsA<Clock> + 'static {
435 #[doc(alias = "gst_clock_new_periodic_id")]
448 fn new_periodic_id(&self, start_time: ClockTime, interval: ClockTime) -> PeriodicClockId {
449 assert_ne!(interval, ClockTime::ZERO);
450
451 unsafe {
452 PeriodicClockId(from_glib_full(ffi::gst_clock_new_periodic_id(
453 self.as_ref().to_glib_none().0,
454 start_time.into_glib(),
455 interval.into_glib(),
456 )))
457 }
458 }
459
460 #[doc(alias = "gst_clock_periodic_id_reinit")]
474 fn periodic_id_reinit(
475 &self,
476 id: &PeriodicClockId,
477 start_time: ClockTime,
478 interval: ClockTime,
479 ) -> Result<(), glib::BoolError> {
480 unsafe {
481 let res: bool = from_glib(ffi::gst_clock_periodic_id_reinit(
482 self.as_ref().to_glib_none().0,
483 id.to_glib_none().0,
484 start_time.into_glib(),
485 interval.into_glib(),
486 ));
487 if res {
488 Ok(())
489 } else {
490 Err(glib::bool_error!("Failed to reinit periodic clock id"))
491 }
492 }
493 }
494
495 #[doc(alias = "gst_clock_new_single_shot_id")]
505 fn new_single_shot_id(&self, time: ClockTime) -> SingleShotClockId {
506 unsafe {
507 SingleShotClockId(from_glib_full(ffi::gst_clock_new_single_shot_id(
508 self.as_ref().to_glib_none().0,
509 time.into_glib(),
510 )))
511 }
512 }
513
514 #[doc(alias = "gst_clock_single_shot_id_reinit")]
526 fn single_shot_id_reinit(
527 &self,
528 id: &SingleShotClockId,
529 time: ClockTime,
530 ) -> Result<(), glib::BoolError> {
531 unsafe {
532 let res: bool = from_glib(ffi::gst_clock_single_shot_id_reinit(
533 self.as_ref().to_glib_none().0,
534 id.to_glib_none().0,
535 time.into_glib(),
536 ));
537 if res {
538 Ok(())
539 } else {
540 Err(glib::bool_error!("Failed to reinit single shot clock id"))
541 }
542 }
543 }
544
545 fn set_clock_flags(&self, flags: ClockFlags) {
546 unsafe {
547 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
548 let _guard = self.as_ref().object_lock();
549 (*ptr).flags |= flags.into_glib();
550 }
551 }
552
553 fn unset_clock_flags(&self, flags: ClockFlags) {
554 unsafe {
555 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
556 let _guard = self.as_ref().object_lock();
557 (*ptr).flags &= !flags.into_glib();
558 }
559 }
560
561 #[doc(alias = "get_clock_flags")]
562 fn clock_flags(&self) -> ClockFlags {
563 unsafe {
564 let ptr: *mut ffi::GstObject = self.as_ptr() as *mut _;
565 let _guard = self.as_ref().object_lock();
566 from_glib((*ptr).flags)
567 }
568 }
569
570 #[doc(alias = "gst_clock_get_calibration")]
591 #[doc(alias = "get_calibration")]
592 fn calibration(&self) -> (ClockTime, ClockTime, u64, u64) {
593 unsafe {
594 let mut internal = std::mem::MaybeUninit::uninit();
595 let mut external = std::mem::MaybeUninit::uninit();
596 let mut rate_num = std::mem::MaybeUninit::uninit();
597 let mut rate_denom = std::mem::MaybeUninit::uninit();
598 ffi::gst_clock_get_calibration(
599 self.as_ref().to_glib_none().0,
600 internal.as_mut_ptr(),
601 external.as_mut_ptr(),
602 rate_num.as_mut_ptr(),
603 rate_denom.as_mut_ptr(),
604 );
605 (
606 try_from_glib(internal.assume_init()).expect("mandatory glib value is None"),
607 try_from_glib(external.assume_init()).expect("mandatory glib value is None"),
608 rate_num.assume_init(),
609 rate_denom.assume_init(),
610 )
611 }
612 }
613
614 #[doc(alias = "gst_clock_set_calibration")]
647 fn set_calibration(
648 &self,
649 internal: ClockTime,
650 external: ClockTime,
651 rate_num: u64,
652 rate_denom: u64,
653 ) {
654 unsafe {
655 ffi::gst_clock_set_calibration(
656 self.as_ref().to_glib_none().0,
657 internal.into_glib(),
658 external.into_glib(),
659 rate_num,
660 rate_denom,
661 );
662 }
663 }
664}
665
666impl<O: IsA<Clock>> ClockExtManual for O {}
667
668#[cfg(test)]
669mod tests {
670 use std::sync::mpsc::channel;
671
672 use super::*;
673 use crate::SystemClock;
674
675 #[test]
676 fn test_wait() {
677 crate::init().unwrap();
678
679 let clock = SystemClock::obtain();
680 let now = clock.time();
681 let id = clock.new_single_shot_id(now + 20 * ClockTime::MSECOND);
682 let (res, _) = id.wait();
683
684 assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early));
685 }
686
687 #[test]
688 fn test_wait_async() {
689 crate::init().unwrap();
690
691 let (sender, receiver) = channel();
692
693 let clock = SystemClock::obtain();
694 let now = clock.time();
695 let id = clock.new_single_shot_id(now + 20 * ClockTime::MSECOND);
696 let res = id.wait_async(move |_, _, _| {
697 sender.send(()).unwrap();
698 });
699
700 assert!(res == Ok(ClockSuccess::Ok));
701
702 assert_eq!(receiver.recv(), Ok(()));
703 }
704
705 #[test]
706 fn test_wait_periodic() {
707 crate::init().unwrap();
708
709 let clock = SystemClock::obtain();
710 let now = clock.time();
711 let id = clock.new_periodic_id(now + 20 * ClockTime::MSECOND, 20 * ClockTime::MSECOND);
712
713 let (res, _) = id.wait();
714 assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early));
715
716 let (res, _) = id.wait();
717 assert!(res == Ok(ClockSuccess::Ok) || res == Err(ClockError::Early));
718 }
719
720 #[test]
721 fn test_wait_async_periodic() {
722 crate::init().unwrap();
723
724 let (sender, receiver) = channel();
725
726 let clock = SystemClock::obtain();
727 let now = clock.time();
728 let id = clock.new_periodic_id(now + 20 * ClockTime::MSECOND, 20 * ClockTime::MSECOND);
729 let res = id.wait_async(move |_, _, _| {
730 let _ = sender.send(());
731 });
732
733 assert!(res == Ok(ClockSuccess::Ok));
734
735 assert_eq!(receiver.recv(), Ok(()));
736 assert_eq!(receiver.recv(), Ok(()));
737 }
738}