Commit 69c0f0fe authored by Max Kellermann's avatar Max Kellermann

apple/AudioUnit: wrapper functions for AudioObject properties

parent 28a00472
/*
* Copyright 2020 Max Kellermann <max.kellermann@gmail.com>
*
* 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 <CoreAudio/AudioHardware.h>
#include <cstddef>
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<typename T>
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<typename T>
AllocatedArray<T>
AudioObjectGetPropertyDataArray(AudioObjectID inObjectID,
const AudioObjectPropertyAddress &inAddress)
{
OSStatus status;
UInt32 size;
status = AudioObjectGetPropertyDataSize(inObjectID,
&inAddress,
0, nullptr, &size);
if (status != noErr)
Apple::ThrowOSStatus(status);
AllocatedArray<T> result(size / sizeof(T));
status = AudioObjectGetPropertyData(inObjectID, &inAddress,
0, nullptr,
&size, result.begin());
if (status != noErr)
Apple::ThrowOSStatus(status);
return result;
}
#endif
......@@ -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<Float32>(dev_id,
aopa);
return static_cast<int>(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);
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");
OSStatus err;
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<AudioStreamID>(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<UInt32>(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<AudioStreamRangedDescription>(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<pid_t>(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<AudioDeviceID[]> 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<AudioDeviceID>(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++) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment