1use std::{mem, ptr::NonNull};
2
3use core_audio_types::{AudioBufferList, AudioTimeStamp};
4use core_foundation::base::OSStatus;
5use libc::c_void;
6use objc2_audio_toolbox as sys;
7pub use sys::{AudioUnitElement, AudioUnitParameterID, AudioUnitParameterValue, AudioUnitPropertyID, AudioUnitRenderActionFlags, AudioUnitScope};
8
9use crate::{audio_component::ComponentInstance, base::status_to_result};
10
11pub type Unit = ComponentInstance;
12
13impl Unit {
14 #[inline]
15 pub fn initialize(&self) -> Result<(), OSStatus> {
16 let status = unsafe { sys::AudioUnitInitialize(self.as_raw()) };
17 status_to_result(status)
18 }
19
20 #[inline]
21 pub fn uninitialize(&self) -> Result<(), OSStatus> {
22 let status = unsafe { sys::AudioUnitUninitialize(self.as_raw()) };
23 status_to_result(status)
24 }
25
26 #[inline]
27 pub fn start_output_unit(&self) -> Result<(), OSStatus> {
28 let status = unsafe { sys::AudioOutputUnitStart(self.as_raw()) };
29 status_to_result(status)
30 }
31
32 #[inline]
33 pub fn stop_output_unit(&self) -> Result<(), OSStatus> {
34 let status = unsafe { sys::AudioOutputUnitStop(self.as_raw()) };
35 status_to_result(status)
36 }
37
38 pub fn property_info(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(u32, bool), OSStatus> {
39 let mut size: u32 = 0;
40 let mut writable: u8 = 0;
41 let status = unsafe { sys::AudioUnitGetPropertyInfo(self.as_raw(), property_id, scope, element, &mut size, &mut writable) };
42 status_to_result(status).map(|_| (size, writable != 0))
43 }
44
45 #[inline]
46 pub fn get_property<T: Copy>(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<T, OSStatus> {
47 let mut value = mem::MaybeUninit::<T>::uninit();
48 let mut size = mem::size_of::<T>() as u32;
49 let status = unsafe {
50 sys::AudioUnitGetProperty(
51 self.as_raw(),
52 property_id,
53 scope,
54 element,
55 NonNull::new_unchecked(value.as_mut_ptr().cast()),
56 NonNull::from(&mut size),
57 )
58 };
59 status_to_result(status)?;
60 Ok(unsafe { value.assume_init() })
61 }
62
63 pub fn get_property_bytes(
64 &self,
65 property_id: AudioUnitPropertyID,
66 scope: AudioUnitScope,
67 element: AudioUnitElement,
68 ) -> Result<Vec<u8>, OSStatus> {
69 let (size, _) = self.property_info(property_id, scope, element)?;
70 let mut bytes = vec![0u8; size as usize];
71 let mut io_size = size;
72 let out_data = NonNull::new(bytes.as_mut_ptr().cast::<c_void>()).unwrap_or_else(NonNull::dangling);
73 let status = unsafe { sys::AudioUnitGetProperty(self.as_raw(), property_id, scope, element, out_data, NonNull::from(&mut io_size)) };
74 status_to_result(status)?;
75 bytes.truncate(io_size as usize);
76 Ok(bytes)
77 }
78
79 #[inline]
80 pub fn set_property<T: Copy>(
81 &self,
82 property_id: AudioUnitPropertyID,
83 scope: AudioUnitScope,
84 element: AudioUnitElement,
85 value: &T,
86 ) -> Result<(), OSStatus> {
87 let status = unsafe {
88 sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, (value as *const T).cast::<c_void>(), mem::size_of::<T>() as u32)
89 };
90 status_to_result(status)
91 }
92
93 pub fn set_property_bytes(
94 &self,
95 property_id: AudioUnitPropertyID,
96 scope: AudioUnitScope,
97 element: AudioUnitElement,
98 bytes: &[u8],
99 ) -> Result<(), OSStatus> {
100 let status =
101 unsafe { sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, bytes.as_ptr().cast::<c_void>(), bytes.len() as u32) };
102 status_to_result(status)
103 }
104
105 #[inline]
106 pub fn clear_property(&self, property_id: AudioUnitPropertyID, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(), OSStatus> {
107 let status = unsafe { sys::AudioUnitSetProperty(self.as_raw(), property_id, scope, element, std::ptr::null(), 0) };
108 status_to_result(status)
109 }
110
111 pub fn get_parameter(
112 &self,
113 parameter_id: AudioUnitParameterID,
114 scope: AudioUnitScope,
115 element: AudioUnitElement,
116 ) -> Result<AudioUnitParameterValue, OSStatus> {
117 let mut value: AudioUnitParameterValue = 0.0;
118 let status = unsafe { sys::AudioUnitGetParameter(self.as_raw(), parameter_id, scope, element, NonNull::from(&mut value)) };
119 status_to_result(status).map(|_| value)
120 }
121
122 #[inline]
123 pub fn set_parameter(
124 &self,
125 parameter_id: AudioUnitParameterID,
126 scope: AudioUnitScope,
127 element: AudioUnitElement,
128 value: AudioUnitParameterValue,
129 buffer_offset_in_frames: u32,
130 ) -> Result<(), OSStatus> {
131 let status = unsafe { sys::AudioUnitSetParameter(self.as_raw(), parameter_id, scope, element, value, buffer_offset_in_frames) };
132 status_to_result(status)
133 }
134
135 #[inline]
136 pub fn reset(&self, scope: AudioUnitScope, element: AudioUnitElement) -> Result<(), OSStatus> {
137 let status = unsafe { sys::AudioUnitReset(self.as_raw(), scope, element) };
138 status_to_result(status)
139 }
140
141 pub unsafe fn render(
142 &self,
143 action_flags: Option<&mut AudioUnitRenderActionFlags>,
144 time_stamp: &AudioTimeStamp,
145 output_bus_number: u32,
146 number_frames: u32,
147 io_data: &mut AudioBufferList,
148 ) -> Result<(), OSStatus> {
149 let action_flags = action_flags.map_or(std::ptr::null_mut(), |flags| flags as *mut AudioUnitRenderActionFlags);
150 let status =
151 sys::AudioUnitRender(self.as_raw(), action_flags, NonNull::from(time_stamp), output_bus_number, number_frames, NonNull::from(io_data));
152 status_to_result(status)
153 }
154}