apple/AudioUnit: wrapper functions for AudioObject properties
This commit is contained in:
parent
28a00472ff
commit
69c0f0fe99
97
src/apple/AudioUnit.hxx
Normal file
97
src/apple/AudioUnit.hxx
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* 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 "config.h"
|
||||||
#include "OSXOutputPlugin.hxx"
|
#include "OSXOutputPlugin.hxx"
|
||||||
|
#include "apple/AudioUnit.hxx"
|
||||||
#include "apple/StringRef.hxx"
|
#include "apple/StringRef.hxx"
|
||||||
#include "apple/Throw.hxx"
|
#include "apple/Throw.hxx"
|
||||||
#include "../OutputAPI.hxx"
|
#include "../OutputAPI.hxx"
|
||||||
@ -184,22 +185,14 @@ OSXOutput::Create(EventLoop &, const ConfigBlock &block)
|
|||||||
int
|
int
|
||||||
OSXOutput::GetVolume()
|
OSXOutput::GetVolume()
|
||||||
{
|
{
|
||||||
Float32 vol;
|
|
||||||
static constexpr AudioObjectPropertyAddress aopa = {
|
static constexpr AudioObjectPropertyAddress aopa = {
|
||||||
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
|
||||||
kAudioObjectPropertyScopeOutput,
|
kAudioObjectPropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMaster,
|
kAudioObjectPropertyElementMaster,
|
||||||
};
|
};
|
||||||
UInt32 size = sizeof(vol);
|
|
||||||
OSStatus status = AudioObjectGetPropertyData(dev_id,
|
|
||||||
&aopa,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&size,
|
|
||||||
&vol);
|
|
||||||
|
|
||||||
if (status != noErr)
|
const auto vol = AudioObjectGetPropertyDataT<Float32>(dev_id,
|
||||||
Apple::ThrowOSStatus(status);
|
aopa);
|
||||||
|
|
||||||
return static_cast<int>(vol * 100.0);
|
return static_cast<int>(vol * 100.0);
|
||||||
}
|
}
|
||||||
@ -386,65 +379,27 @@ osx_output_set_device_format(AudioDeviceID dev_id,
|
|||||||
kAudioObjectPropertyElementMaster
|
kAudioObjectPropertyElementMaster
|
||||||
};
|
};
|
||||||
|
|
||||||
UInt32 property_size;
|
OSStatus err;
|
||||||
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);
|
const auto streams =
|
||||||
static constexpr size_t MAX_STREAMS = 64;
|
AudioObjectGetPropertyDataArray<AudioStreamID>(dev_id,
|
||||||
if (n_streams > MAX_STREAMS)
|
aopa_device_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);
|
|
||||||
|
|
||||||
bool format_found = false;
|
bool format_found = false;
|
||||||
int output_stream;
|
int output_stream;
|
||||||
AudioStreamBasicDescription output_format;
|
AudioStreamBasicDescription output_format;
|
||||||
|
|
||||||
for (size_t i = 0; i < n_streams; i++) {
|
for (const auto stream : streams) {
|
||||||
UInt32 direction;
|
const auto direction =
|
||||||
AudioStreamID stream = streams[i];
|
AudioObjectGetPropertyDataT<UInt32>(stream,
|
||||||
property_size = sizeof(direction);
|
aopa_stream_direction);
|
||||||
err = AudioObjectGetPropertyData(stream,
|
|
||||||
&aopa_stream_direction,
|
|
||||||
0,
|
|
||||||
NULL,
|
|
||||||
&property_size,
|
|
||||||
&direction);
|
|
||||||
if (err != noErr)
|
|
||||||
throw FormatRuntimeError("Cannot get streams direction: %d",
|
|
||||||
err);
|
|
||||||
|
|
||||||
if (direction != 0)
|
if (direction != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err = AudioObjectGetPropertyDataSize(stream,
|
const auto format_list =
|
||||||
&aopa_stream_phys_formats,
|
AudioObjectGetPropertyDataArray<AudioStreamRangedDescription>(stream,
|
||||||
0, NULL, &property_size);
|
aopa_stream_phys_formats);
|
||||||
if (err != noErr)
|
const size_t format_count = format_list.size();
|
||||||
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);
|
|
||||||
|
|
||||||
float output_score = 0;
|
float output_score = 0;
|
||||||
for (size_t j = 0; j < format_count; j++) {
|
for (size_t j = 0; j < format_count; j++) {
|
||||||
@ -542,26 +497,14 @@ osx_output_set_buffer_size(AudioUnit au, AudioStreamBasicDescription desc,
|
|||||||
static void
|
static void
|
||||||
osx_output_hog_device(AudioDeviceID dev_id, bool hog)
|
osx_output_hog_device(AudioDeviceID dev_id, bool hog)
|
||||||
{
|
{
|
||||||
pid_t hog_pid;
|
|
||||||
static constexpr AudioObjectPropertyAddress aopa = {
|
static constexpr AudioObjectPropertyAddress aopa = {
|
||||||
kAudioDevicePropertyHogMode,
|
kAudioDevicePropertyHogMode,
|
||||||
kAudioObjectPropertyScopeOutput,
|
kAudioObjectPropertyScopeOutput,
|
||||||
kAudioObjectPropertyElementMaster
|
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) {
|
||||||
if (hog_pid != -1) {
|
if (hog_pid != -1) {
|
||||||
FormatDebug(osx_output_domain,
|
FormatDebug(osx_output_domain,
|
||||||
@ -577,7 +520,8 @@ osx_output_hog_device(AudioDeviceID dev_id, bool hog)
|
|||||||
}
|
}
|
||||||
|
|
||||||
hog_pid = hog ? getpid() : -1;
|
hog_pid = hog ? getpid() : -1;
|
||||||
size = sizeof(hog_pid);
|
UInt32 size = sizeof(hog_pid);
|
||||||
|
OSStatus err;
|
||||||
err = AudioObjectSetPropertyData(dev_id,
|
err = AudioObjectSetPropertyData(dev_id,
|
||||||
&aopa,
|
&aopa,
|
||||||
0,
|
0,
|
||||||
@ -601,31 +545,21 @@ static void
|
|||||||
osx_output_set_device(OSXOutput *oo)
|
osx_output_set_device(OSXOutput *oo)
|
||||||
{
|
{
|
||||||
OSStatus status;
|
OSStatus status;
|
||||||
UInt32 size, numdevices;
|
UInt32 size;
|
||||||
|
|
||||||
if (oo->component_subtype != kAudioUnitSubType_HALOutput)
|
if (oo->component_subtype != kAudioUnitSubType_HALOutput)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* how many audio devices are there? */
|
/* what are the available audio device IDs? */
|
||||||
static constexpr AudioObjectPropertyAddress aopa_hw_devices{
|
static constexpr AudioObjectPropertyAddress aopa_hw_devices{
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
kAudioObjectPropertyElementMaster,
|
kAudioObjectPropertyElementMaster,
|
||||||
};
|
};
|
||||||
|
|
||||||
status = AudioObjectGetPropertyDataSize(kAudioObjectSystemObject,
|
const auto deviceids =
|
||||||
&aopa_hw_devices, 0, nullptr, &size);
|
AudioObjectGetPropertyDataArray<AudioDeviceID>(kAudioObjectSystemObject,
|
||||||
if (status != noErr)
|
aopa_hw_devices);
|
||||||
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);
|
|
||||||
|
|
||||||
/* which audio device matches oo->device_name? */
|
/* which audio device matches oo->device_name? */
|
||||||
static constexpr AudioObjectPropertyAddress aopa_name{
|
static constexpr AudioObjectPropertyAddress aopa_name{
|
||||||
@ -634,6 +568,7 @@ osx_output_set_device(OSXOutput *oo)
|
|||||||
kAudioObjectPropertyElementMaster,
|
kAudioObjectPropertyElementMaster,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unsigned numdevices = deviceids.size();
|
||||||
unsigned i;
|
unsigned i;
|
||||||
size = sizeof(CFStringRef);
|
size = sizeof(CFStringRef);
|
||||||
for (i = 0; i < numdevices; i++) {
|
for (i = 0; i < numdevices; i++) {
|
||||||
|
Loading…
Reference in New Issue
Block a user