Skip to main content

apple_cf/cm/
timebase.rs

1//! `CMTimebase` wrapper.
2//!
3#![allow(clippy::missing_errors_doc)]
4
5//! ```rust,no_run
6//! use apple_cf::cm::{CMClock, CMTime, CMTimebase};
7//!
8//! let clock = CMClock::host_time_clock();
9//! let timebase = CMTimebase::with_master_clock(&clock).expect("timebase");
10//! assert!(timebase.time().is_valid());
11//! assert_eq!(timebase.set_rate(1.0), 0);
12//! assert_eq!(timebase.set_time(CMTime::new(0, 600)), 0);
13//! ```
14
15use super::{CMClock, CMTime};
16use std::ffi::c_void;
17use std::fmt;
18
19/// Owned wrapper around `CMTimebaseRef`.
20pub struct CMTimebase {
21    ptr: *const c_void,
22}
23
24impl CMTimebase {
25    /// Create a timebase that uses `master_clock` as its time source.
26    pub fn with_master_clock(master_clock: &CMClock) -> Result<Self, i32> {
27        extern "C" {
28            fn CMTimebaseCreateWithMasterClock(
29                allocator: *const c_void,
30                masterClock: *const c_void,
31                timebaseOut: *mut *const c_void,
32            ) -> i32;
33        }
34        let mut ptr = std::ptr::null();
35        let status = unsafe {
36            CMTimebaseCreateWithMasterClock(std::ptr::null(), master_clock.as_ptr(), &mut ptr)
37        };
38        if status == 0 && !ptr.is_null() {
39            Ok(Self { ptr })
40        } else {
41            Err(status)
42        }
43    }
44
45    /// Adopt a retained raw pointer.
46    #[must_use]
47    pub fn from_raw(ptr: *const c_void) -> Option<Self> {
48        if ptr.is_null() {
49            None
50        } else {
51            Some(Self { ptr })
52        }
53    }
54
55    /// Borrow the underlying `CMTimebaseRef`.
56    #[must_use]
57    pub const fn as_ptr(&self) -> *const c_void {
58        self.ptr
59    }
60
61    /// Current time.
62    #[must_use]
63    pub fn time(&self) -> CMTime {
64        extern "C" {
65            fn CMTimebaseGetTime(timebase: *const c_void) -> CMTime;
66        }
67        unsafe { CMTimebaseGetTime(self.ptr) }
68    }
69
70    /// Set the current time.
71    #[must_use]
72    pub fn set_time(&self, time: CMTime) -> i32 {
73        extern "C" {
74            fn CMTimebaseSetTime(timebase: *const c_void, time: CMTime) -> i32;
75        }
76        unsafe { CMTimebaseSetTime(self.ptr, time) }
77    }
78
79    /// Playback rate relative to the master clock.
80    #[must_use]
81    pub fn rate(&self) -> f64 {
82        extern "C" {
83            fn CMTimebaseGetRate(timebase: *const c_void) -> f64;
84        }
85        unsafe { CMTimebaseGetRate(self.ptr) }
86    }
87
88    /// Set the playback rate relative to the master clock.
89    #[must_use]
90    pub fn set_rate(&self, rate: f64) -> i32 {
91        extern "C" {
92            fn CMTimebaseSetRate(timebase: *const c_void, rate: f64) -> i32;
93        }
94        unsafe { CMTimebaseSetRate(self.ptr, rate) }
95    }
96
97    /// Copy the master clock.
98    #[must_use]
99    pub fn master_clock(&self) -> Option<CMClock> {
100        extern "C" {
101            fn CMTimebaseCopyMasterClock(timebase: *const c_void) -> *const c_void;
102        }
103        let ptr = unsafe { CMTimebaseCopyMasterClock(self.ptr) };
104        CMClock::from_raw(ptr)
105    }
106}
107
108impl Clone for CMTimebase {
109    fn clone(&self) -> Self {
110        extern "C" {
111            fn CFRetain(cf: *const c_void) -> *const c_void;
112        }
113        let ptr = unsafe { CFRetain(self.ptr) };
114        Self { ptr }
115    }
116}
117
118impl Drop for CMTimebase {
119    fn drop(&mut self) {
120        extern "C" {
121            fn CFRelease(cf: *const c_void);
122        }
123        unsafe { CFRelease(self.ptr) };
124    }
125}
126
127impl PartialEq for CMTimebase {
128    fn eq(&self, other: &Self) -> bool {
129        self.ptr == other.ptr
130    }
131}
132
133impl Eq for CMTimebase {}
134
135impl std::hash::Hash for CMTimebase {
136    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
137        self.ptr.hash(state);
138    }
139}
140
141impl fmt::Debug for CMTimebase {
142    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143        f.debug_struct("CMTimebase")
144            .field("ptr", &self.ptr)
145            .field("time", &self.time())
146            .field("rate", &self.rate())
147            .finish()
148    }
149}
150
151unsafe impl Send for CMTimebase {}
152unsafe impl Sync for CMTimebase {}