Skip to main content

cidre/cm/
audio_device_clock.rs

1#[cfg(target_os = "macos")]
2use crate::{arc, cf, cm, os};
3
4#[cfg(feature = "core_audio")]
5use crate::core_audio;
6
7#[cfg(target_os = "macos")]
8impl cm::Clock {
9    /// Unified api with iOS
10    pub fn with_default_audio_output() -> os::Result<arc::R<Self>> {
11        Self::with_audio_device_uid(None)
12    }
13
14    #[doc(alias = "CMAudioDeviceClockCreate")]
15    pub fn with_audio_device_uid_in(
16        device_uid: Option<&cf::String>,
17        allocator: Option<&cf::Allocator>,
18    ) -> os::Result<Option<arc::R<Self>>> {
19        let mut res = None;
20        unsafe {
21            CMAudioDeviceClockCreate(allocator, device_uid, &mut res).result()?;
22        }
23
24        Ok(res)
25    }
26
27    #[doc(alias = "CMAudioDeviceClockCreate")]
28    pub fn with_audio_device_uid(device_uid: Option<&cf::String>) -> os::Result<arc::R<Self>> {
29        let mut res = None;
30        unsafe {
31            CMAudioDeviceClockCreate(None, device_uid, &mut res).result()?;
32        }
33
34        Ok(unsafe { std::mem::transmute(res) })
35    }
36
37    #[cfg(feature = "core_audio")]
38    #[doc(alias = "CMAudioDeviceClockCreateFromAudioDeviceID")]
39    pub fn with_audio_device_in(
40        audio_device: core_audio::Device,
41        allocator: Option<&cf::Allocator>,
42    ) -> os::Result<Option<arc::R<Self>>> {
43        let mut res = None;
44        unsafe {
45            CMAudioDeviceClockCreateFromAudioDeviceID(allocator, audio_device, &mut res)
46                .result()?;
47        }
48        Ok(res)
49    }
50
51    #[cfg(feature = "core_audio")]
52    #[doc(alias = "CMAudioDeviceClockCreateFromAudioDeviceID")]
53    pub fn with_audio_device(audio_device: core_audio::Device) -> os::Result<arc::R<Self>> {
54        let mut res = None;
55        unsafe {
56            CMAudioDeviceClockCreateFromAudioDeviceID(None, audio_device, &mut res).result()?;
57        }
58        Ok(unsafe { std::mem::transmute(res) })
59    }
60
61    #[doc(alias = "CMAudioDeviceClockSetAudioDeviceUID")]
62    pub fn set_audio_device_uid(&mut self, device_uid: Option<&cf::String>) -> os::Result {
63        unsafe { CMAudioDeviceClockSetAudioDeviceUID(self, device_uid).result() }
64    }
65
66    #[cfg(feature = "core_audio")]
67    #[doc(alias = "CMAudioDeviceClockSetAudioDeviceID")]
68    pub fn set_audio_device(&mut self, audio_device: core_audio::Device) -> os::Result {
69        unsafe { CMAudioDeviceClockSetAudioDeviceID(self, audio_device).result() }
70    }
71
72    #[cfg(feature = "core_audio")]
73    pub fn audio_device_uid(&self) -> os::Result<Option<&cf::String>> {
74        let mut device_uid_out = None;
75        unsafe {
76            CMAudioDeviceClockGetAudioDevice(
77                self,
78                &mut device_uid_out,
79                std::ptr::null_mut(),
80                std::ptr::null_mut(),
81            )
82            .result()?
83        }
84        Ok(device_uid_out)
85    }
86
87    #[cfg(feature = "core_audio")]
88    pub fn audio_device(&self) -> os::Result<core_audio::Device> {
89        let mut device_out = core_audio::Device(core_audio::Obj::UNKNOWN);
90        unsafe {
91            CMAudioDeviceClockGetAudioDevice(
92                self,
93                std::ptr::null_mut(),
94                &mut device_out,
95                std::ptr::null_mut(),
96            )
97            .result()?
98        }
99        Ok(device_out)
100    }
101
102    #[cfg(feature = "core_audio")]
103    pub fn is_tracking_default_device(&self) -> os::Result<bool> {
104        let mut tracking_default_device_out = false;
105        unsafe {
106            CMAudioDeviceClockGetAudioDevice(
107                self,
108                std::ptr::null_mut(),
109                std::ptr::null_mut(),
110                &mut tracking_default_device_out,
111            )
112            .result()?
113        }
114        Ok(tracking_default_device_out)
115    }
116}
117
118#[cfg(target_os = "macos")]
119unsafe extern "C" {
120    fn CMAudioDeviceClockCreate(
121        allocator: Option<&cf::Allocator>,
122        device_uid: Option<&cf::String>,
123        clock_out: *mut Option<arc::R<cm::Clock>>,
124    ) -> os::Status;
125
126    #[cfg(feature = "core_audio")]
127    fn CMAudioDeviceClockCreateFromAudioDeviceID(
128        allocator: Option<&cf::Allocator>,
129        audio_device: core_audio::Device,
130        clock_out: *mut Option<arc::R<cm::Clock>>,
131    ) -> os::Status;
132
133    fn CMAudioDeviceClockSetAudioDeviceUID(
134        clock: &mut cm::Clock,
135        device_uid: Option<&cf::String>,
136    ) -> os::Status;
137
138    #[cfg(feature = "core_audio")]
139    fn CMAudioDeviceClockSetAudioDeviceID(
140        clock: &mut cm::Clock,
141        audio_device: core_audio::Device,
142    ) -> os::Status;
143
144    #[cfg(feature = "core_audio")]
145    fn CMAudioDeviceClockGetAudioDevice(
146        clock: &cm::Clock,
147        device_uid_out: *mut Option<&cf::String>,
148        device_out: *mut core_audio::Device,
149        tracking_default_device_out: *mut bool,
150    ) -> os::Status;
151}
152
153#[cfg(target_os = "macos")]
154#[cfg(test)]
155mod tests {
156    use crate::{cm, core_audio};
157
158    #[test]
159    fn basics() {
160        let clock = cm::Clock::with_audio_device_uid(None).unwrap();
161        assert!(clock.audio_device_uid().unwrap().is_none());
162        let device = clock.audio_device().unwrap();
163        assert!(!device.is_unknown());
164
165        assert_eq!(device, core_audio::System::default_output_device().unwrap());
166
167        assert!(clock.is_tracking_default_device().unwrap());
168
169        let _time = clock.time();
170
171        let clock =
172            cm::Clock::with_audio_device(core_audio::System::default_output_device().unwrap())
173                .unwrap();
174        assert!(clock.audio_device_uid().unwrap().is_none());
175        let device = clock.audio_device().unwrap();
176        assert!(!device.is_unknown());
177
178        assert_eq!(device, core_audio::System::default_output_device().unwrap());
179
180        assert!(!clock.is_tracking_default_device().unwrap());
181        let _time = clock.time();
182    }
183}