diff --git a/src/apple/AudioUnit.hxx b/src/apple/AudioUnit.hxx new file mode 100644 index 000000000..99b5b7bf2 --- /dev/null +++ b/src/apple/AudioUnit.hxx @@ -0,0 +1,97 @@ +/* + * Copyright 2020 Max Kellermann + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef APPLE_AUDIO_OBJECT_HXX +#define APPLE_AUDIO_OBJECT_HXX + +#include "Throw.hxx" +#include "util/AllocatedArray.hxx" + +#include + +#include + +std::size_t +AudioObjectGetPropertyDataSize(AudioObjectID inObjectID, + const AudioObjectPropertyAddress &inAddress) +{ + UInt32 size; + OSStatus status = AudioObjectGetPropertyDataSize(inObjectID, + &inAddress, + 0, nullptr, &size); + if (status != noErr) + Apple::ThrowOSStatus(status); + + return size; +} + +template +T +AudioObjectGetPropertyDataT(AudioObjectID inObjectID, + const AudioObjectPropertyAddress &inAddress) +{ + OSStatus status; + UInt32 size = sizeof(T); + T value; + + status = AudioObjectGetPropertyData(inObjectID, &inAddress, + 0, nullptr, + &size, &value); + if (status != noErr) + Apple::ThrowOSStatus(status); + + return value; +} + +template +AllocatedArray +AudioObjectGetPropertyDataArray(AudioObjectID inObjectID, + const AudioObjectPropertyAddress &inAddress) +{ + OSStatus status; + UInt32 size; + + status = AudioObjectGetPropertyDataSize(inObjectID, + &inAddress, + 0, nullptr, &size); + if (status != noErr) + Apple::ThrowOSStatus(status); + + AllocatedArray result(size / sizeof(T)); + + status = AudioObjectGetPropertyData(inObjectID, &inAddress, + 0, nullptr, + &size, result.begin()); + if (status != noErr) + Apple::ThrowOSStatus(status); + + return result; +} + +#endif diff --git a/src/output/plugins/OSXOutputPlugin.cxx b/src/output/plugins/OSXOutputPlugin.cxx index fddf6f398..a565a488b 100644 --- a/src/output/plugins/OSXOutputPlugin.cxx +++ b/src/output/plugins/OSXOutputPlugin.cxx @@ -19,6 +19,7 @@ #include "config.h" #include "OSXOutputPlugin.hxx" +#include "apple/AudioUnit.hxx" #include "apple/StringRef.hxx" #include "apple/Throw.hxx" #include "../OutputAPI.hxx" @@ -184,22 +185,14 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block) int OSXOutput::GetVolume() { - Float32 vol; static constexpr AudioObjectPropertyAddress aopa = { kAudioHardwareServiceDeviceProperty_VirtualMasterVolume, kAudioObjectPropertyScopeOutput, kAudioObjectPropertyElementMaster, }; - UInt32 size = sizeof(vol); - OSStatus status = AudioObjectGetPropertyData(dev_id, - &aopa, - 0, - NULL, - &size, - &vol); - if (status != noErr) - Apple::ThrowOSStatus(status); + const auto vol = AudioObjectGetPropertyDataT(dev_id, + aopa); return static_cast(vol * 100.0); } @@ -386,65 +379,27 @@ osx_output_set_device_format(AudioDeviceID dev_id, kAudioObjectPropertyElementMaster }; - UInt32 property_size; - OSStatus err = AudioObjectGetPropertyDataSize(dev_id, - &aopa_device_streams, - 0, NULL, &property_size); - if (err != noErr) - throw FormatRuntimeError("Cannot get number of streams: %d", err); + OSStatus err; - const size_t n_streams = property_size / sizeof(AudioStreamID); - static constexpr size_t MAX_STREAMS = 64; - if (n_streams > MAX_STREAMS) - throw std::runtime_error("Too many streams"); - - AudioStreamID streams[MAX_STREAMS]; - err = AudioObjectGetPropertyData(dev_id, &aopa_device_streams, 0, NULL, - &property_size, streams); - if (err != noErr) - throw FormatRuntimeError("Cannot get streams: %d", err); + const auto streams = + AudioObjectGetPropertyDataArray(dev_id, + aopa_device_streams); bool format_found = false; int output_stream; AudioStreamBasicDescription output_format; - for (size_t i = 0; i < n_streams; i++) { - UInt32 direction; - AudioStreamID stream = streams[i]; - property_size = sizeof(direction); - err = AudioObjectGetPropertyData(stream, - &aopa_stream_direction, - 0, - NULL, - &property_size, - &direction); - if (err != noErr) - throw FormatRuntimeError("Cannot get streams direction: %d", - err); - + for (const auto stream : streams) { + const auto direction = + AudioObjectGetPropertyDataT(stream, + aopa_stream_direction); if (direction != 0) continue; - err = AudioObjectGetPropertyDataSize(stream, - &aopa_stream_phys_formats, - 0, NULL, &property_size); - if (err != noErr) - throw FormatRuntimeError("Unable to get format size s for stream %d. Error = %s", - streams[i], err); - - const size_t format_count = property_size / sizeof(AudioStreamRangedDescription); - static constexpr size_t MAX_FORMATS = 256; - if (format_count > MAX_FORMATS) - throw std::runtime_error("Too many formats"); - - AudioStreamRangedDescription format_list[MAX_FORMATS]; - err = AudioObjectGetPropertyData(stream, - &aopa_stream_phys_formats, - 0, NULL, - &property_size, format_list); - if (err != noErr) - throw FormatRuntimeError("Unable to get available formats for stream %d. Error = %s", - streams[i], err); + const auto format_list = + AudioObjectGetPropertyDataArray(stream, + aopa_stream_phys_formats); + const size_t format_count = format_list.size(); float output_score = 0; for (size_t j = 0; j < format_count; j++) { @@ -542,26 +497,14 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc, static void osx_output_hog_device(AudioDeviceID dev_id, bool hog) { - pid_t hog_pid; static constexpr AudioObjectPropertyAddress aopa = { kAudioDevicePropertyHogMode, kAudioObjectPropertyScopeOutput, kAudioObjectPropertyElementMaster }; - UInt32 size = sizeof(hog_pid); - OSStatus err = AudioObjectGetPropertyData(dev_id, - &aopa, - 0, - NULL, - &size, - &hog_pid); - if (err != noErr) { - FormatDebug(osx_output_domain, - "Cannot get hog information: %d", - err); - return; - } + pid_t hog_pid = AudioObjectGetPropertyDataT(dev_id, + aopa); if (hog) { if (hog_pid != -1) { FormatDebug(osx_output_domain, @@ -577,7 +520,8 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog) } hog_pid = hog ? getpid() : -1; - size = sizeof(hog_pid); + UInt32 size = sizeof(hog_pid); + OSStatus err; err = AudioObjectSetPropertyData(dev_id, &aopa, 0, @@ -601,31 +545,21 @@ static void osx_output_set_device(OSXOutput *oo) { OSStatus status; - UInt32 size, numdevices; + UInt32 size; if (oo->component_subtype != kAudioUnitSubType_HALOutput) return; - /* how many audio devices are there? */ + /* what are the available audio device IDs? */ static constexpr AudioObjectPropertyAddress aopa_hw_devices{ kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster, }; - status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject, - &aopa_hw_devices, 0, nullptr, &size); - if (status != noErr) - Apple::ThrowOSStatus(status); - - /* what are the available audio device IDs? */ - numdevices = size / sizeof(AudioDeviceID); - std::unique_ptr deviceids(new AudioDeviceID[numdevices]); - status = AudioObjectGetPropertyData(kAudioObjectSystemObject, - &aopa_hw_devices, 0, nullptr, - &size, deviceids.get()); - if (status != noErr) - Apple::ThrowOSStatus(status); + const auto deviceids = + AudioObjectGetPropertyDataArray(kAudioObjectSystemObject, + aopa_hw_devices); /* which audio device matches oo->device_name? */ static constexpr AudioObjectPropertyAddress aopa_name{ @@ -634,6 +568,7 @@ osx_output_set_device(OSXOutput *oo) kAudioObjectPropertyElementMaster, }; + const unsigned numdevices = deviceids.size(); unsigned i; size = sizeof(CFStringRef); for (i = 0; i < numdevices; i++) {