use super::coreaudio::sys::{
AudioObjectAddPropertyListener, AudioObjectID, AudioObjectPropertyAddress,
AudioObjectRemovePropertyListener, OSStatus,
};
use crate::BuildStreamError;
struct PropertyListenerCallbackWrapper(Box<dyn FnMut() -> ()>);
pub struct AudioObjectPropertyListener {
callback: Box<PropertyListenerCallbackWrapper>,
property_address: AudioObjectPropertyAddress,
audio_object_id: AudioObjectID,
removed: bool,
}
impl AudioObjectPropertyListener {
pub fn new<F: FnMut() -> () + 'static>(
audio_object_id: AudioObjectID,
property_address: AudioObjectPropertyAddress,
callback: F,
) -> Result<Self, BuildStreamError> {
let callback = Box::new(PropertyListenerCallbackWrapper(Box::new(callback)));
unsafe {
coreaudio::Error::from_os_status(AudioObjectAddPropertyListener(
audio_object_id,
&property_address as *const _,
Some(property_listener_handler_shim),
&*callback as *const _ as *mut _,
))?;
};
Ok(Self {
callback,
audio_object_id,
property_address,
removed: false,
})
}
pub fn remove(mut self) -> Result<(), BuildStreamError> {
self.remove_inner()
}
fn remove_inner(&mut self) -> Result<(), BuildStreamError> {
unsafe {
coreaudio::Error::from_os_status(AudioObjectRemovePropertyListener(
self.audio_object_id,
&self.property_address as *const _,
Some(property_listener_handler_shim),
&*self.callback as *const _ as *mut _,
))?;
}
self.removed = true;
Ok(())
}
}
impl Drop for AudioObjectPropertyListener {
fn drop(&mut self) {
if !self.removed {
let _ = self.remove_inner();
}
}
}
unsafe extern "C" fn property_listener_handler_shim(
_: AudioObjectID,
_: u32,
_: *const AudioObjectPropertyAddress,
callback: *mut ::std::os::raw::c_void,
) -> OSStatus {
let wrapper = callback as *mut PropertyListenerCallbackWrapper;
(*wrapper).0();
0
}