From 5cd8304dc08381940cd4418925a73cbb7728874c Mon Sep 17 00:00:00 2001 From: jp9000 Date: Sat, 7 Jun 2014 06:07:51 -0700 Subject: [PATCH] CoreAudio: Enumerate AudioDeviceID manually Apparently, despite the fact that Apple added kAudioHardwarePropertyTranslateUIDToDevice in 10.8, it's not actually usable in 10.8, only 10.9. So, instead of being able to use it like a normal, sane person, we have to enumerate all devices manually and find the AudioDeviceID ourselves. A slight annoyance and a mark against apple's competence, but audio devices should now be working again on 10.8 at least, so whatever. --- plugins/mac-capture/audio-device-enum.c | 104 ++++++++++++++++++------ plugins/mac-capture/audio-device-enum.h | 1 + plugins/mac-capture/mac-audio.c | 11 +-- 3 files changed, 86 insertions(+), 30 deletions(-) diff --git a/plugins/mac-capture/audio-device-enum.c b/plugins/mac-capture/audio-device-enum.c index 8da14a7d6..f41764936 100644 --- a/plugins/mac-capture/audio-device-enum.c +++ b/plugins/mac-capture/audio-device-enum.c @@ -23,14 +23,17 @@ static inline bool enum_success(OSStatus stat, const char *msg) return true; } -static void coreaudio_enum_add_device(struct device_list *list, - AudioDeviceID id, bool input) +typedef bool (*enum_device_proc_t)(void *param, CFStringRef cf_name, + CFStringRef cf_uid, AudioDeviceID id); + +static bool coreaudio_enum_device(enum_device_proc_t proc, void *param, + AudioDeviceID id) { - OSStatus stat; - UInt32 size = 0; - CFStringRef cf_name = NULL; - CFStringRef cf_value = NULL; - struct device_item item; + UInt32 size = 0; + CFStringRef cf_name = NULL; + CFStringRef cf_uid = NULL; + bool enum_next = true; + OSStatus stat; AudioObjectPropertyAddress addr = { kAudioDevicePropertyStreams, @@ -38,40 +41,32 @@ static void coreaudio_enum_add_device(struct device_list *list, kAudioObjectPropertyElementMaster }; - memset(&item, 0, sizeof(item)); - /* check to see if it's a mac input device */ AudioObjectGetPropertyDataSize(id, &addr, 0, NULL, &size); if (!size) - return; + return true; size = sizeof(CFStringRef); addr.mSelector = kAudioDevicePropertyDeviceUID; - stat = AudioObjectGetPropertyData(id, &addr, 0, NULL, &size, &cf_value); + stat = AudioObjectGetPropertyData(id, &addr, 0, NULL, &size, &cf_uid); if (!enum_success(stat, "get audio device UID")) - return; + return true; addr.mSelector = kAudioDevicePropertyDeviceNameCFString; stat = AudioObjectGetPropertyData(id, &addr, 0, NULL, &size, &cf_name); if (!enum_success(stat, "get audio device name")) goto fail; - if (!cf_to_dstr(cf_name, &item.name)) - goto fail; - if (!cf_to_dstr(cf_value, &item.value)) - goto fail; - - if (input || !device_is_input(item.value.array)) - device_list_add(list, &item); + enum_next = proc(param, cf_name, cf_uid, id); fail: - device_item_free(&item); CFRelease(cf_name); - CFRelease(cf_value); + CFRelease(cf_uid); + return enum_next; } -void coreaudio_enum_devices(struct device_list *list, bool input) +static void enum_devices(enum_device_proc_t proc, void *param) { AudioObjectPropertyAddress addr = { kAudioHardwarePropertyDevices, @@ -97,7 +92,70 @@ void coreaudio_enum_devices(struct device_list *list, bool input) if (enum_success(stat, "get kAudioObjectSystemObject data")) for (UInt32 i = 0; i < count; i++) - coreaudio_enum_add_device(list, ids[i], input); + if (!coreaudio_enum_device(proc, param, ids[i])) + break; bfree(ids); } + +struct add_data { + struct device_list *list; + bool input; +}; + +static bool coreaudio_enum_add_device(void *param, CFStringRef cf_name, + CFStringRef cf_uid, AudioDeviceID id) +{ + struct add_data *data = param; + struct device_item item; + + memset(&item, 0, sizeof(item)); + + if (!cf_to_dstr(cf_name, &item.name)) + goto fail; + if (!cf_to_dstr(cf_uid, &item.value)) + goto fail; + + if (data->input || !device_is_input(item.value.array)) + device_list_add(data->list, &item); + +fail: + device_item_free(&item); + + UNUSED_PARAMETER(id); + return true; +} + +void coreaudio_enum_devices(struct device_list *list, bool input) +{ + struct add_data data = {list, input}; + enum_devices(coreaudio_enum_add_device, &data); +} + +struct device_id_data { + CFStringRef uid; + AudioDeviceID *id; + bool found; +}; + +static bool get_device_id(void *param, CFStringRef cf_name, CFStringRef cf_uid, + AudioDeviceID id) +{ + struct device_id_data *data = param; + + if (CFStringCompare(cf_uid, data->uid, 0) == 0) { + *data->id = id; + data->found = true; + return false; + } + + UNUSED_PARAMETER(cf_name); + return true; +} + +bool coreaudio_get_device_id(CFStringRef uid, AudioDeviceID *id) +{ + struct device_id_data data = {uid, id, false}; + enum_devices(get_device_id, &data); + return data.found; +} diff --git a/plugins/mac-capture/audio-device-enum.h b/plugins/mac-capture/audio-device-enum.h index 14fa0968c..306fae54c 100644 --- a/plugins/mac-capture/audio-device-enum.h +++ b/plugins/mac-capture/audio-device-enum.h @@ -33,3 +33,4 @@ static inline void device_list_add(struct device_list *list, } extern void coreaudio_enum_devices(struct device_list *list, bool input); +extern bool coreaudio_get_device_id(CFStringRef uid, AudioDeviceID *id); diff --git a/plugins/mac-capture/mac-audio.c b/plugins/mac-capture/mac-audio.c index e48f943fc..50e6fc318 100644 --- a/plugins/mac-capture/mac-audio.c +++ b/plugins/mac-capture/mac-audio.c @@ -101,16 +101,13 @@ static bool find_device_id_by_uid(struct coreaudio_data *ca) if (ca->default_device) { addr.mSelector = PROPERTY_DEFAULT_DEVICE; + stat = AudioObjectGetPropertyData(kAudioObjectSystemObject, + &addr, qual_size, &qual, &size, &ca->device_id); + success = (stat == noErr); } else { - addr.mSelector = kAudioHardwarePropertyTranslateUIDToDevice; - qual = cf_uid; - qual_size = sizeof(CFStringRef); + success = coreaudio_get_device_id(cf_uid, &ca->device_id); } - stat = AudioObjectGetPropertyData(kAudioObjectSystemObject, &addr, - qual_size, &qual, &size, &ca->device_id); - success = (stat == noErr); - CFRelease(cf_uid); return success; }