diff --git a/Cargo.toml b/Cargo.toml index 33d1fda80..822ca6ea4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ core_midi = ["coreaudio-sys/core_midi"] [dependencies] bitflags = "1.0" coreaudio-sys = { version = "0.2", default-features = false } -core-foundation-sys = "0.6.2" +core-foundation-sys = "0.8.3" [package.metadata.docs.rs] all-features = true diff --git a/examples/sine_advanced.rs b/examples/sine_advanced.rs index 62f1abe56..8e2685538 100644 --- a/examples/sine_advanced.rs +++ b/examples/sine_advanced.rs @@ -5,8 +5,8 @@ extern crate coreaudio; use coreaudio::audio_unit::audio_format::LinearPcmFlags; use coreaudio::audio_unit::macos_helpers::{ - audio_unit_from_device_id, find_matching_physical_format, get_default_device_id, get_hogging_pid, - get_supported_physical_stream_formats, set_device_physical_stream_format, + audio_unit_from_device_id, find_matching_physical_format, get_default_device_id, + get_hogging_pid, get_supported_physical_stream_formats, set_device_physical_stream_format, set_device_sample_rate, toggle_hog_mode, AliveListener, RateListener, }; use coreaudio::audio_unit::render_callback::{self, data}; diff --git a/src/audio_unit/macos_helpers.rs b/src/audio_unit/macos_helpers.rs index c723f2419..bd7c9815a 100644 --- a/src/audio_unit/macos_helpers.rs +++ b/src/audio_unit/macos_helpers.rs @@ -17,16 +17,19 @@ use sys::pid_t; use sys::{ kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceIsAlive, kAudioDevicePropertyDeviceNameCFString, kAudioDevicePropertyHogMode, - kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput, kAudioHardwareNoError, + kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput, + kAudioDevicePropertyStreamConfiguration, kAudioHardwareNoError, kAudioHardwarePropertyDefaultInputDevice, kAudioHardwarePropertyDefaultOutputDevice, kAudioHardwarePropertyDevices, kAudioObjectPropertyElementMaster, - kAudioObjectPropertyScopeGlobal, kAudioObjectSystemObject, + kAudioObjectPropertyElementWildcard, kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput, kAudioObjectSystemObject, kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO, kAudioStreamPropertyAvailablePhysicalFormats, kAudioStreamPropertyPhysicalFormat, kCFStringEncodingUTF8, AudioDeviceID, AudioObjectAddPropertyListener, AudioObjectGetPropertyData, AudioObjectGetPropertyDataSize, AudioObjectID, - AudioObjectPropertyAddress, AudioObjectRemovePropertyListener, AudioObjectSetPropertyData, - AudioStreamBasicDescription, AudioStreamRangedDescription, AudioValueRange, OSStatus, + AudioObjectPropertyAddress, AudioObjectPropertyScope, AudioObjectRemovePropertyListener, + AudioObjectSetPropertyData, AudioStreamBasicDescription, AudioStreamRangedDescription, + AudioValueRange, OSStatus, }; use crate::audio_unit::audio_format::{AudioFormat, LinearPcmFlags}; @@ -115,10 +118,15 @@ pub fn audio_unit_from_device_id( } /// List all audio device ids on the system. -pub fn get_audio_device_ids() -> Result, Error> { +pub fn get_audio_device_ids_for_scope(scope: Scope) -> Result, Error> { + let dev_scope = match scope { + Scope::Input => kAudioObjectPropertyScopeInput, + Scope::Output => kAudioObjectPropertyScopeOutput, + _ => kAudioObjectPropertyScopeGlobal, + }; let property_address = AudioObjectPropertyAddress { mSelector: kAudioHardwarePropertyDevices, - mScope: kAudioObjectPropertyScopeGlobal, + mScope: dev_scope, mElement: kAudioObjectPropertyElementMaster, }; @@ -161,6 +169,68 @@ pub fn get_audio_device_ids() -> Result, Error> { Ok(audio_devices) } +pub fn get_audio_device_ids() -> Result, Error> { + get_audio_device_ids_for_scope(Scope::Global) +} + +/// does this device support input / ouptut? +pub fn get_audio_device_supports_scope(devid: AudioDeviceID, scope: Scope) -> Result { + let dev_scope: AudioObjectPropertyScope = match scope { + Scope::Input => kAudioObjectPropertyScopeInput, + Scope::Output => kAudioObjectPropertyScopeOutput, + _ => kAudioObjectPropertyScopeGlobal, + }; + let property_address = AudioObjectPropertyAddress { + mSelector: kAudioDevicePropertyStreamConfiguration, + mScope: dev_scope, + mElement: kAudioObjectPropertyElementWildcard, + }; + + macro_rules! try_status_or_return { + ($status:expr) => { + if $status != kAudioHardwareNoError as i32 { + return Err(Error::Unknown($status)); + } + }; + } + + let data_size = 0u32; + let status = unsafe { + AudioObjectGetPropertyDataSize( + devid, + &property_address as *const _, + 0, + null(), + &data_size as *const _ as *mut _, + ) + }; + try_status_or_return!(status); + + let mut bfrs: Vec = Vec::with_capacity(data_size as usize); + let buffers = bfrs.as_mut_ptr() as *mut sys::AudioBufferList; + unsafe { + let status = AudioObjectGetPropertyData( + devid, + &property_address as *const _, + 0, + null(), + &data_size as *const _ as *mut _, + buffers as *mut _, + ); + if status != kAudioHardwareNoError as i32 { + return Err(Error::Unknown(status)); + } + + for i in 0..(*buffers).mNumberBuffers { + let buf = (*buffers).mBuffers[i as usize]; + if buf.mNumberChannels > 0 { + return Ok(true); + } + } + } + Ok(false) +} + /// Get the device name for a device id. pub fn get_device_name(device_id: AudioDeviceID) -> Result { let property_address = AudioObjectPropertyAddress { diff --git a/src/error.rs b/src/error.rs index 9b6b005b2..c39f80d6f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -41,6 +41,8 @@ pub mod audio { } } + impl std::error::Error for Error {} + impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { let description = match *self { @@ -93,6 +95,8 @@ pub mod audio_codec { } } + impl std::error::Error for Error {} + impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { let description = match *self { @@ -139,6 +143,8 @@ pub mod audio_format { } } + impl std::error::Error for Error {} + impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { let description = match *self { @@ -209,6 +215,8 @@ pub mod audio_unit { } } + impl std::error::Error for Error {} + impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { let description = match *self { @@ -302,6 +310,8 @@ impl Error { } } +impl std::error::Error for Error {} + impl ::std::fmt::Display for Error { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { match *self {