2018-01-26 12:49:47 +00:00
|
|
|
use SupportedFormat;
|
|
|
|
use std::mem;
|
|
|
|
use std::ptr::null;
|
|
|
|
use std::vec::IntoIter as VecIntoIter;
|
|
|
|
use super::coreaudio::sys::{
|
|
|
|
AudioDeviceID,
|
|
|
|
AudioObjectPropertyAddress,
|
|
|
|
AudioObjectGetPropertyData,
|
|
|
|
AudioObjectGetPropertyDataSize,
|
|
|
|
kAudioHardwareNoError,
|
|
|
|
kAudioHardwarePropertyDefaultOutputDevice,
|
|
|
|
kAudioHardwarePropertyDevices,
|
|
|
|
kAudioObjectPropertyElementMaster,
|
|
|
|
kAudioObjectPropertyScopeGlobal,
|
|
|
|
kAudioObjectSystemObject,
|
|
|
|
OSStatus,
|
|
|
|
};
|
2015-09-24 03:02:28 +00:00
|
|
|
use super::Endpoint;
|
|
|
|
|
2018-01-26 12:49:47 +00:00
|
|
|
unsafe fn audio_output_devices() -> Result<Vec<AudioDeviceID>, OSStatus> {
|
|
|
|
let property_address = AudioObjectPropertyAddress {
|
|
|
|
mSelector: kAudioHardwarePropertyDevices,
|
|
|
|
mScope: kAudioObjectPropertyScopeGlobal,
|
|
|
|
mElement: kAudioObjectPropertyElementMaster,
|
|
|
|
};
|
2015-09-24 03:02:28 +00:00
|
|
|
|
2018-01-26 12:49:47 +00:00
|
|
|
macro_rules! try_status_or_return {
|
|
|
|
($status:expr) => {
|
|
|
|
if $status != kAudioHardwareNoError as i32 {
|
|
|
|
return Err($status);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2015-09-24 03:02:28 +00:00
|
|
|
|
2018-01-26 12:49:47 +00:00
|
|
|
let data_size = 0u32;
|
|
|
|
let status = AudioObjectGetPropertyDataSize(
|
|
|
|
kAudioObjectSystemObject,
|
|
|
|
&property_address as *const _,
|
|
|
|
0,
|
|
|
|
null(),
|
|
|
|
&data_size as *const _ as *mut _,
|
|
|
|
);
|
|
|
|
try_status_or_return!(status);
|
|
|
|
|
|
|
|
let device_count = data_size / mem::size_of::<AudioDeviceID>() as u32;
|
|
|
|
let mut audio_devices = vec![];
|
|
|
|
audio_devices.reserve_exact(device_count as usize);
|
|
|
|
|
|
|
|
let status = AudioObjectGetPropertyData(
|
|
|
|
kAudioObjectSystemObject,
|
|
|
|
&property_address as *const _,
|
|
|
|
0,
|
|
|
|
null(),
|
|
|
|
&data_size as *const _ as *mut _,
|
|
|
|
audio_devices.as_mut_ptr() as *mut _,
|
|
|
|
);
|
|
|
|
try_status_or_return!(status);
|
|
|
|
|
|
|
|
audio_devices.set_len(device_count as usize);
|
|
|
|
|
|
|
|
// Only keep the devices that have some supported output format.
|
|
|
|
audio_devices.retain(|&id| {
|
|
|
|
let e = Endpoint { audio_device_id: id };
|
|
|
|
match e.supported_formats() {
|
|
|
|
Err(_) => false,
|
|
|
|
Ok(mut fmts) => fmts.next().is_some(),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
Ok(audio_devices)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct EndpointsIterator(VecIntoIter<AudioDeviceID>);
|
2015-09-24 03:02:28 +00:00
|
|
|
|
2017-10-11 11:24:49 +00:00
|
|
|
unsafe impl Send for EndpointsIterator {
|
|
|
|
}
|
|
|
|
unsafe impl Sync for EndpointsIterator {
|
|
|
|
}
|
2015-09-24 03:02:28 +00:00
|
|
|
|
|
|
|
impl Default for EndpointsIterator {
|
|
|
|
fn default() -> Self {
|
2018-01-26 12:49:47 +00:00
|
|
|
let devices = unsafe {
|
|
|
|
audio_output_devices().expect("failed to get audio output devices")
|
|
|
|
};
|
|
|
|
EndpointsIterator(devices.into_iter())
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Iterator for EndpointsIterator {
|
|
|
|
type Item = Endpoint;
|
|
|
|
fn next(&mut self) -> Option<Endpoint> {
|
2018-01-26 12:49:47 +00:00
|
|
|
self.0.next().map(|id| Endpoint { audio_device_id: id })
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-12 09:54:09 +00:00
|
|
|
pub fn default_endpoint() -> Option<Endpoint> {
|
2018-01-26 12:49:47 +00:00
|
|
|
let property_address = AudioObjectPropertyAddress {
|
|
|
|
mSelector: kAudioHardwarePropertyDefaultOutputDevice,
|
|
|
|
mScope: kAudioObjectPropertyScopeGlobal,
|
|
|
|
mElement: kAudioObjectPropertyElementMaster,
|
|
|
|
};
|
|
|
|
|
|
|
|
let audio_device_id: AudioDeviceID = 0;
|
|
|
|
let data_size = mem::size_of::<AudioDeviceID>();;
|
|
|
|
let status = unsafe {
|
|
|
|
AudioObjectGetPropertyData(
|
|
|
|
kAudioObjectSystemObject,
|
|
|
|
&property_address as *const _,
|
|
|
|
0,
|
|
|
|
null(),
|
|
|
|
&data_size as *const _ as *mut _,
|
|
|
|
&audio_device_id as *const _ as *mut _,
|
|
|
|
)
|
|
|
|
};
|
|
|
|
if status != kAudioHardwareNoError as i32 {
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let endpoint = Endpoint {
|
|
|
|
audio_device_id: audio_device_id,
|
|
|
|
};
|
|
|
|
Some(endpoint)
|
2015-09-24 03:02:28 +00:00
|
|
|
}
|
|
|
|
|
2017-10-20 19:18:40 +00:00
|
|
|
pub type SupportedFormatsIterator = VecIntoIter<SupportedFormat>;
|