From f6823cc6792c5a6d7577ee5a236ce75f38648a85 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Thu, 28 May 2020 15:46:48 +0200 Subject: [PATCH] output/osx: move code to FindAudioDeviceByName() --- src/output/plugins/OSXOutputPlugin.cxx | 99 ++++++++++++++------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/src/output/plugins/OSXOutputPlugin.cxx b/src/output/plugins/OSXOutputPlugin.cxx index a565a488b..5077a20b2 100644 --- a/src/output/plugins/OSXOutputPlugin.cxx +++ b/src/output/plugins/OSXOutputPlugin.cxx @@ -44,6 +44,7 @@ #include #include +#include static constexpr unsigned MPD_OSX_BUFFER_TIME_MS = 100; @@ -540,16 +541,36 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog) } } - -static void -osx_output_set_device(OSXOutput *oo) +gcc_pure +static bool +IsAudioDeviceName(AudioDeviceID id, const char *expected_name) noexcept { - OSStatus status; - UInt32 size; + static constexpr AudioObjectPropertyAddress aopa_name{ + kAudioObjectPropertyName, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster, + }; - if (oo->component_subtype != kAudioUnitSubType_HALOutput) - return; + CFStringRef cfname; + UInt32 size = sizeof(cfname); + if (AudioObjectGetPropertyData(id, &aopa_name, + 0, nullptr, + &size, &cfname) != noErr) + return false; + + const Apple::StringRef cfname_(cfname); + + char actual_name[256]; + if (!cfname_.GetCString(actual_name, sizeof(actual_name))) + return false; + + return StringIsEqual(actual_name, expected_name); +} + +static std::optional +FindAudioDeviceByName(const char *name) +{ /* what are the available audio device IDs? */ static constexpr AudioObjectPropertyAddress aopa_hw_devices{ kAudioHardwarePropertyDevices, @@ -557,60 +578,48 @@ osx_output_set_device(OSXOutput *oo) kAudioObjectPropertyElementMaster, }; - const auto deviceids = + const auto ids = AudioObjectGetPropertyDataArray(kAudioObjectSystemObject, aopa_hw_devices); - /* which audio device matches oo->device_name? */ - static constexpr AudioObjectPropertyAddress aopa_name{ - kAudioObjectPropertyName, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster, - }; - - const unsigned numdevices = deviceids.size(); - unsigned i; - size = sizeof(CFStringRef); - for (i = 0; i < numdevices; i++) { - CFStringRef cfname = nullptr; - status = AudioObjectGetPropertyData(deviceids[i], &aopa_name, - 0, nullptr, - &size, &cfname); - if (status != noErr) - continue; - - const Apple::StringRef cfname_(cfname); - - char name[256]; - if (!cfname_.GetCString(name, sizeof(name))) - continue; - - if (StringIsEqual(oo->device_name, name)) { - FormatDebug(osx_output_domain, - "found matching device: ID=%u, name=%s", - (unsigned)deviceids[i], name); - break; - } + for (const auto id : ids) { + if (IsAudioDeviceName(id, name)) + return id; } - if (i == numdevices) - throw FormatRuntimeError("Found no audio device with name '%s' ", - oo->device_name); + return {}; +} +static void +osx_output_set_device(OSXOutput *oo) +{ + if (oo->component_subtype != kAudioUnitSubType_HALOutput) + return; + + const auto id = FindAudioDeviceByName(oo->device_name); + if (!id.has_value()) + throw FormatRuntimeError("Found no audio device with name '%s' ", + oo->device_name); + + FormatDebug(osx_output_domain, + "found matching device: ID=%u, name=%s", + (unsigned)id.value(), oo->device_name); + + OSStatus status; status = AudioUnitSetProperty(oo->au, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, - &(deviceids[i]), - sizeof(AudioDeviceID)); + &id.value(), + sizeof(id.value())); if (status != noErr) Apple::ThrowOSStatus(status, "Unable to set OS X audio output device"); - oo->dev_id = deviceids[i]; + oo->dev_id = id.value(); FormatDebug(osx_output_domain, "set OS X audio output device ID=%u, name=%s", - (unsigned)deviceids[i], oo->device_name); + (unsigned)id.value(), oo->device_name); if (oo->channel_map) osx_output_set_channel_map(oo);