From 80dc6021931e12cb465a46f7b61e7aef19012080 Mon Sep 17 00:00:00 2001 From: Greg Ward Date: Mon, 20 Dec 2010 22:21:46 -0500 Subject: 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 --- NEWS | 2 + configure.ac | 2 +- src/output/osx_plugin.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 122 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 6fa9bc0de..1a25bfd9b 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.17 (2010/??/??) +* output: + - osx: allow user to specify other audio devices ver 0.16 (2010/12/11) diff --git a/configure.ac b/configure.ac index ab1410dbe..d8b2c5834 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/src/output/osx_plugin.c b/src/output/osx_plugin.c index 17d138d35..db9dbdf8a 100644 --- a/src/output/osx_plugin.c +++ b/src/output/osx_plugin.c @@ -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; -- cgit v1.2.3