Selaa lähdekoodia

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.
jp9000 11 vuotta sitten
vanhempi
sitoutus
5cd8304dc0

+ 81 - 23
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;
+}

+ 1 - 0
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);

+ 4 - 7
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;
 }