osx_output: allow user to specify other audio devices.
Add new config parameter 'device' to audio_output type "osx": - if not supplied or set to "default", open default device - if set to "system", open system device - otherwise 'device' should be an audio device name: mpd will find and open the specified audio device, falling back to the default device if it's not found
This commit is contained in:
		 Greg Ward
					Greg Ward
				
			
				
					committed by
					
						 Max Kellermann
						Max Kellermann
					
				
			
			
				
	
			
			
			 Max Kellermann
						Max Kellermann
					
				
			
						parent
						
							c7f5a87258
						
					
				
				
					commit
					80dc602193
				
			
							
								
								
									
										2
									
								
								NEWS
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								NEWS
									
									
									
									
									
								
							| @@ -1,4 +1,6 @@ | ||||
| ver 0.17 (2010/??/??) | ||||
| * output: | ||||
|   - osx: allow user to specify other audio devices | ||||
|  | ||||
|  | ||||
| ver 0.16 (2010/12/11) | ||||
|   | ||||
| @@ -1319,7 +1319,7 @@ enable_osx=no | ||||
| case "$host_os" in | ||||
| 	darwin*) | ||||
| 		AC_DEFINE(HAVE_OSX, 1, [Define for compiling OS X support]) | ||||
| 		MPD_LIBS="$MPD_LIBS -framework AudioUnit -framework CoreServices" | ||||
| 		MPD_LIBS="$MPD_LIBS -framework AudioUnit -framework CoreAudio -framework CoreServices" | ||||
| 		enable_osx=yes ;; | ||||
| esac | ||||
|  | ||||
|   | ||||
| @@ -28,6 +28,11 @@ | ||||
| #define G_LOG_DOMAIN "osx" | ||||
|  | ||||
| struct osx_output { | ||||
| 	/* configuration settings */ | ||||
| 	OSType component_subtype; | ||||
| 	/* only applicable with kAudioUnitSubType_HALOutput */ | ||||
| 	const char *device_name; | ||||
|  | ||||
| 	AudioUnit au; | ||||
| 	GMutex *mutex; | ||||
| 	GCond *condition; | ||||
| @@ -54,6 +59,26 @@ osx_output_test_default_device(void) | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| static void | ||||
| osx_output_configure(struct osx_output *oo, const struct config_param *param) | ||||
| { | ||||
| 	const char *device = config_get_block_string(param, "device", NULL); | ||||
|  | ||||
| 	if (device == NULL || 0 == strcmp(device, "default")) { | ||||
| 		oo->component_subtype = kAudioUnitSubType_DefaultOutput; | ||||
| 		oo->device_name = NULL; | ||||
| 	} | ||||
| 	else if (0 == strcmp(device, "system")) { | ||||
| 		oo->component_subtype = kAudioUnitSubType_SystemOutput; | ||||
| 		oo->device_name = NULL; | ||||
| 	} | ||||
| 	else { | ||||
| 		oo->component_subtype = kAudioUnitSubType_HALOutput; | ||||
| 		/* XXX am I supposed to g_strdup() this? */ | ||||
| 		oo->device_name = device; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void * | ||||
| osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, | ||||
| 		G_GNUC_UNUSED const struct config_param *param, | ||||
| @@ -61,6 +86,7 @@ osx_output_init(G_GNUC_UNUSED const struct audio_format *audio_format, | ||||
| { | ||||
| 	struct osx_output *oo = g_new(struct osx_output, 1); | ||||
|  | ||||
| 	osx_output_configure(oo, param); | ||||
| 	oo->mutex = g_mutex_new(); | ||||
| 	oo->condition = g_cond_new(); | ||||
|  | ||||
| @@ -155,6 +181,95 @@ osx_render(void *vdata, | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| osx_output_set_device(struct osx_output *oo, GError **error) | ||||
| { | ||||
| 	bool ret = true; | ||||
| 	OSStatus status; | ||||
| 	UInt32 size, numdevices; | ||||
| 	AudioDeviceID *deviceids = NULL; | ||||
| 	char name[256]; | ||||
| 	unsigned int i; | ||||
|  | ||||
| 	if (oo->component_subtype != kAudioUnitSubType_HALOutput) | ||||
| 		goto done; | ||||
|  | ||||
| 	/* how many audio devices are there? */ | ||||
| 	status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, | ||||
| 					      &size, | ||||
| 					      NULL); | ||||
| 	if (status != noErr) { | ||||
| 		g_set_error(error, osx_output_quark(), 0, | ||||
| 			    "Unable to determine number of OS X audio devices: %s", | ||||
| 			    GetMacOSStatusCommentString(status)); | ||||
| 		ret = false; | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* what are the available audio device IDs? */ | ||||
| 	numdevices = size / sizeof(AudioDeviceID); | ||||
| 	deviceids = g_malloc(size); | ||||
| 	status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, | ||||
| 					  &size, | ||||
| 					  deviceids); | ||||
| 	if (status != noErr) { | ||||
| 		g_set_error(error, osx_output_quark(), 0, | ||||
| 			    "Unable to determine OS X audio device IDs: %s", | ||||
| 			    GetMacOSStatusCommentString(status)); | ||||
| 		ret = false; | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	/* which audio device matches oo->device_name? */ | ||||
| 	for (i = 0; i < numdevices; i++) { | ||||
| 		size = sizeof(name); | ||||
| 		status = AudioDeviceGetProperty(deviceids[i], 0, false, | ||||
| 						kAudioDevicePropertyDeviceName, | ||||
| 						&size, name); | ||||
| 		if (status != noErr) { | ||||
| 			g_set_error(error, osx_output_quark(), 0, | ||||
| 				    "Unable to determine OS X device name " | ||||
| 				    "(device %u): %s", | ||||
| 				    (unsigned int) deviceids[i], | ||||
| 				    GetMacOSStatusCommentString(status)); | ||||
| 			ret = false; | ||||
| 			goto done; | ||||
| 		} | ||||
| 		if (strcmp(oo->device_name, name) == 0) { | ||||
| 			g_debug("found matching device: ID=%u, name=%s", | ||||
| 				(unsigned int) deviceids[i], name); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (i == numdevices) { | ||||
| 		g_warning("Found no audio device with name '%s' " | ||||
| 			  "(will use default audio device)", | ||||
| 			  oo->device_name); | ||||
| 		goto done; | ||||
| 	} | ||||
|  | ||||
| 	status = AudioUnitSetProperty(oo->au, | ||||
| 				      kAudioOutputUnitProperty_CurrentDevice, | ||||
| 				      kAudioUnitScope_Global, | ||||
| 				      0, | ||||
| 				      &(deviceids[i]), | ||||
| 				      sizeof(AudioDeviceID)); | ||||
| 	if (status != noErr) { | ||||
| 		g_set_error(error, osx_output_quark(), 0, | ||||
| 			    "Unable to set OS X audio output device: %s", | ||||
| 			    GetMacOSStatusCommentString(status)); | ||||
| 		ret = false; | ||||
| 		goto done; | ||||
| 	} | ||||
| 	g_debug("set OS X audio output device ID=%u, name=%s", | ||||
| 		(unsigned int) deviceids[i], name); | ||||
|  | ||||
| done: | ||||
| 	if (deviceids != NULL) | ||||
| 		g_free(deviceids); | ||||
| 	return ret; | ||||
| } | ||||
|  | ||||
| static bool | ||||
| osx_output_open(void *data, struct audio_format *audio_format, GError **error) | ||||
| { | ||||
| @@ -167,7 +282,7 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error) | ||||
| 	ComponentResult result; | ||||
|  | ||||
| 	desc.componentType = kAudioUnitType_Output; | ||||
| 	desc.componentSubType = kAudioUnitSubType_DefaultOutput; | ||||
| 	desc.componentSubType = od->component_subtype; | ||||
| 	desc.componentManufacturer = kAudioUnitManufacturer_Apple; | ||||
| 	desc.componentFlags = 0; | ||||
| 	desc.componentFlagsMask = 0; | ||||
| @@ -196,6 +311,9 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error) | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	if (!osx_output_set_device(od, error)) | ||||
| 		return false; | ||||
|  | ||||
| 	callback.inputProc = osx_render; | ||||
| 	callback.inputProcRefCon = od; | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user