Skip to content

Commit ee50128

Browse files
author
Andres de Lago Gomez
committed
Add support for querying devices on a specific scope
1 parent a365ce5 commit ee50128

File tree

1 file changed

+76
-6
lines changed

1 file changed

+76
-6
lines changed

src/audio_unit/macos_helpers.rs

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,19 @@ use sys::pid_t;
1717
use sys::{
1818
kAudioDevicePropertyAvailableNominalSampleRates, kAudioDevicePropertyDeviceIsAlive,
1919
kAudioDevicePropertyDeviceNameCFString, kAudioDevicePropertyHogMode,
20-
kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput, kAudioHardwareNoError,
20+
kAudioDevicePropertyNominalSampleRate, kAudioDevicePropertyScopeOutput,
21+
kAudioDevicePropertyStreamConfiguration, kAudioHardwareNoError,
2122
kAudioHardwarePropertyDefaultInputDevice, kAudioHardwarePropertyDefaultOutputDevice,
2223
kAudioHardwarePropertyDevices, kAudioObjectPropertyElementMaster,
23-
kAudioObjectPropertyScopeGlobal, kAudioObjectSystemObject,
24+
kAudioObjectPropertyElementWildcard, kAudioObjectPropertyScopeGlobal,
25+
kAudioObjectPropertyScopeInput, kAudioObjectPropertyScopeOutput, kAudioObjectSystemObject,
2426
kAudioOutputUnitProperty_CurrentDevice, kAudioOutputUnitProperty_EnableIO,
2527
kAudioStreamPropertyAvailablePhysicalFormats, kAudioStreamPropertyPhysicalFormat,
2628
kCFStringEncodingUTF8, AudioDeviceID, AudioObjectAddPropertyListener,
2729
AudioObjectGetPropertyData, AudioObjectGetPropertyDataSize, AudioObjectID,
28-
AudioObjectPropertyAddress, AudioObjectRemovePropertyListener, AudioObjectSetPropertyData,
29-
AudioStreamBasicDescription, AudioStreamRangedDescription, AudioValueRange, OSStatus,
30+
AudioObjectPropertyAddress, AudioObjectPropertyScope, AudioObjectRemovePropertyListener,
31+
AudioObjectSetPropertyData, AudioStreamBasicDescription, AudioStreamRangedDescription,
32+
AudioValueRange, OSStatus,
3033
};
3134

3235
use crate::audio_unit::audio_format::{AudioFormat, LinearPcmFlags};
@@ -115,10 +118,15 @@ pub fn audio_unit_from_device_id(
115118
}
116119

117120
/// List all audio device ids on the system.
118-
pub fn get_audio_device_ids() -> Result<Vec<AudioDeviceID>, Error> {
121+
pub fn get_audio_device_ids_for_scope(scope: Scope) -> Result<Vec<AudioDeviceID>, Error> {
122+
let dev_scope = match scope {
123+
Scope::Input => kAudioObjectPropertyScopeInput,
124+
Scope::Output => kAudioObjectPropertyScopeOutput,
125+
_ => kAudioObjectPropertyScopeGlobal,
126+
};
119127
let property_address = AudioObjectPropertyAddress {
120128
mSelector: kAudioHardwarePropertyDevices,
121-
mScope: kAudioObjectPropertyScopeGlobal,
129+
mScope: dev_scope,
122130
mElement: kAudioObjectPropertyElementMaster,
123131
};
124132

@@ -161,6 +169,68 @@ pub fn get_audio_device_ids() -> Result<Vec<AudioDeviceID>, Error> {
161169
Ok(audio_devices)
162170
}
163171

172+
pub fn get_audio_device_ids() -> Result<Vec<AudioDeviceID>, Error> {
173+
get_audio_device_ids_for_scope(Scope::Global)
174+
}
175+
176+
/// does this device support input / ouptut?
177+
pub fn get_audio_device_supports_scope(devid: AudioDeviceID, scope: Scope) -> Result<bool, Error> {
178+
let dev_scope: AudioObjectPropertyScope = match scope {
179+
Scope::Input => kAudioObjectPropertyScopeInput,
180+
Scope::Output => kAudioObjectPropertyScopeOutput,
181+
_ => kAudioObjectPropertyScopeGlobal,
182+
};
183+
let property_address = AudioObjectPropertyAddress {
184+
mSelector: kAudioDevicePropertyStreamConfiguration,
185+
mScope: dev_scope,
186+
mElement: kAudioObjectPropertyElementWildcard,
187+
};
188+
189+
macro_rules! try_status_or_return {
190+
($status:expr) => {
191+
if $status != kAudioHardwareNoError as i32 {
192+
return Err(Error::Unknown($status));
193+
}
194+
};
195+
}
196+
197+
let data_size = 0u32;
198+
let status = unsafe {
199+
AudioObjectGetPropertyDataSize(
200+
devid,
201+
&property_address as *const _,
202+
0,
203+
null(),
204+
&data_size as *const _ as *mut _,
205+
)
206+
};
207+
try_status_or_return!(status);
208+
209+
let mut bfrs: Vec<u8> = Vec::with_capacity(data_size as usize);
210+
let buffers = bfrs.as_mut_ptr() as *mut sys::AudioBufferList;
211+
unsafe {
212+
let status = AudioObjectGetPropertyData(
213+
devid,
214+
&property_address as *const _,
215+
0,
216+
null(),
217+
&data_size as *const _ as *mut _,
218+
buffers as *mut _,
219+
);
220+
if status != kAudioHardwareNoError as i32 {
221+
return Err(Error::Unknown(status));
222+
}
223+
224+
for i in 0..(*buffers).mNumberBuffers {
225+
let buf = (*buffers).mBuffers[i as usize];
226+
if buf.mNumberChannels > 0 {
227+
return Ok(true);
228+
}
229+
}
230+
}
231+
Ok(false)
232+
}
233+
164234
/// Get the device name for a device id.
165235
pub fn get_device_name(device_id: AudioDeviceID) -> Result<String, Error> {
166236
let property_address = AudioObjectPropertyAddress {

0 commit comments

Comments
 (0)