core-media 0.7.1

Safe bindings to CoreMedia framework
Documentation
use std::ptr::{null, null_mut};

use core_foundation::{
    base::{kCFAllocatorDefault, Boolean, CFAllocatorRef, OSStatus, TCFType},
    string::{CFString, CFStringRef},
};

use crate::sync::{CMClock, CMClockRef};

pub type AudioObjectID = u32;

pub type AudioDeviceID = AudioObjectID;

pub const kAudioObjectUnknown: AudioObjectID = 0;
pub const kAudioStreamUnknown: AudioObjectID = kAudioObjectUnknown;

extern "C" {
    pub fn CMAudioDeviceClockCreate(allocator: CFAllocatorRef, deviceUID: CFStringRef, clockOut: *mut CMClockRef) -> OSStatus;
    pub fn CMAudioDeviceClockCreateFromAudioDeviceID(allocator: CFAllocatorRef, deviceID: AudioDeviceID, clockOut: *mut CMClockRef) -> OSStatus;
    pub fn CMAudioDeviceClockSetAudioDeviceUID(clock: CMClockRef, deviceUID: CFStringRef) -> OSStatus;
    pub fn CMAudioDeviceClockSetAudioDeviceID(clock: CMClockRef, deviceID: AudioDeviceID) -> OSStatus;
    pub fn CMAudioDeviceClockGetAudioDevice(
        clock: CMClockRef,
        deviceUIDOut: *mut CFStringRef,
        deviceIDOut: *mut AudioDeviceID,
        trackingDefaultDeviceOut: *mut Boolean,
    ) -> OSStatus;
}

impl CMClock {
    #[inline]
    pub fn new_audio_device_clock(device_uid: &CFString) -> Result<CMClock, OSStatus> {
        unsafe {
            let mut clock: CMClockRef = null_mut();
            let status = CMAudioDeviceClockCreate(kCFAllocatorDefault, device_uid.as_concrete_TypeRef(), &mut clock);
            if status == 0 {
                Ok(TCFType::wrap_under_create_rule(clock))
            } else {
                Err(status)
            }
        }
    }

    #[inline]
    pub fn new_audio_device_clock_from_device_id(device_id: AudioDeviceID) -> Result<CMClock, OSStatus> {
        unsafe {
            let mut clock: CMClockRef = null_mut();
            let status = CMAudioDeviceClockCreateFromAudioDeviceID(kCFAllocatorDefault, device_id, &mut clock);
            if status == 0 {
                Ok(TCFType::wrap_under_create_rule(clock))
            } else {
                Err(status)
            }
        }
    }

    #[inline]
    pub fn set_audio_device_uid(&self, device_uid: &CFString) -> Result<(), OSStatus> {
        unsafe {
            let status = CMAudioDeviceClockSetAudioDeviceUID(self.as_concrete_TypeRef(), device_uid.as_concrete_TypeRef());
            if status == 0 {
                Ok(())
            } else {
                Err(status)
            }
        }
    }

    #[inline]
    pub fn set_audio_device_id(&self, device_id: AudioDeviceID) -> Result<(), OSStatus> {
        unsafe {
            let status = CMAudioDeviceClockSetAudioDeviceID(self.as_concrete_TypeRef(), device_id);
            if status == 0 {
                Ok(())
            } else {
                Err(status)
            }
        }
    }

    #[inline]
    pub fn get_audio_device(&self) -> Result<(CFString, AudioDeviceID, Boolean), OSStatus> {
        unsafe {
            let mut device_uid = null();
            let mut device_id = 0;
            let mut tracking_default_device = 0;
            let status = CMAudioDeviceClockGetAudioDevice(self.as_concrete_TypeRef(), &mut device_uid, &mut device_id, &mut tracking_default_device);
            if status == 0 {
                Ok((TCFType::wrap_under_create_rule(device_uid), device_id, tracking_default_device))
            } else {
                Err(status)
            }
        }
    }
}