From 18777ecfe894ec9c7995a69e0786e56f45bc73f8 Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Sat, 13 Jul 2013 13:01:50 +0200 Subject: ao_coreaudio: refactor properties code Introduce some macros to deal with properties. These allow to work around the limitation of CoreAudio's API being `void **` based. The macros allow to keep their client's code DRY, by not asking size and other details which can be derived by the macro itself. I have no idea why Apple didn't design their API like this in the first place. --- audio/out/ao_coreaudio.c | 66 ++++++++++--------------- audio/out/ao_coreaudio_properties.c | 99 +++++++++++++++---------------------- audio/out/ao_coreaudio_properties.h | 43 +++++++++------- audio/out/ao_coreaudio_utils.c | 49 +++++++----------- 4 files changed, 111 insertions(+), 146 deletions(-) diff --git a/audio/out/ao_coreaudio.c b/audio/out/ao_coreaudio.c index 84a5524496..48fc3a4779 100644 --- a/audio/out/ao_coreaudio.c +++ b/audio/out/ao_coreaudio.c @@ -202,21 +202,17 @@ static void print_help(void) "Available output devices:\n"); AudioDeviceID *devs; - uint32_t devs_size = - GetGlobalAudioPropertyArray(kAudioObjectSystemObject, - kAudioHardwarePropertyDevices, - (void **)&devs); - if (!devs_size) { - ca_msg(MSGL_FATAL, "Failed to get list of output devices.\n"); - goto coreaudio_out; - } + size_t n_devs; + + OSStatus err = + CA_GET_ARY(kAudioObjectSystemObject, kAudioHardwarePropertyDevices, + &devs, &n_devs); - int devs_n = devs_size / sizeof(AudioDeviceID); + CHECK_CA_ERROR("Failed to get list of output devices."); - for (int i = 0; i < devs_n; i++) { + for (int i = 0; i < n_devs; i++) { char *name; - OSStatus err = - GetAudioPropertyString(devs[i], kAudioObjectPropertyName, &name); + OSStatus err = CA_GET_STR(devs[i], kAudioObjectPropertyName, &name); if (err == noErr) { help = talloc_asprintf_append(help, @@ -229,7 +225,7 @@ static void print_help(void) free(devs); -coreaudio_out: +coreaudio_error: ca_msg(MSGL_FATAL, "%s", help); talloc_free(help); } @@ -290,10 +286,7 @@ static int init(struct ao *ao, char *params) } char *device_name; - err = GetAudioPropertyString(selected_device, - kAudioObjectPropertyName, - &device_name); - + err = CA_GET_STR(selected_device, kAudioObjectPropertyName, &device_name); CHECK_CA_ERROR("could not get selected audio device name"); ca_msg(MSGL_V, @@ -548,11 +541,10 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd) struct priv *p = ao->priv; struct priv_d *d = p->digital; OSStatus err = noErr; - uint32_t size; uint32_t is_alive = 1; err = CA_GET(p->device, kAudioDevicePropertyDeviceIsAlive, &is_alive); - CHECK_CA_WARN( "could not check whether device is alive"); + CHECK_CA_WARN("could not check whether device is alive"); if (!is_alive) ca_msg(MSGL_WARN, "device is not alive\n"); @@ -565,44 +557,38 @@ static int init_digital(struct ao *ao, AudioStreamBasicDescription asbd) err = ca_disable_mixing(p->device, &d->changed_mixing); CHECK_CA_WARN("failed to disable mixing"); - AudioStreamID *streams = NULL; - /* Get a list of all the streams on this device. */ - size = GetAudioPropertyArray(p->device, - kAudioDevicePropertyStreams, - kAudioDevicePropertyScopeOutput, - (void **)&streams); + AudioStreamID *streams; + size_t n_streams; - if (!size) { - ca_msg(MSGL_WARN, "could not get number of streams\n"); - goto coreaudio_error; - } + /* Get a list of all the streams on this device. */ + err = CA_GET_ARY_O(p->device, kAudioDevicePropertyStreams, + &streams, &n_streams); - int streams_n = size / sizeof(AudioStreamID); + CHECK_CA_ERROR("could not get number of streams"); - for (int i = 0; i < streams_n && d->stream_idx < 0; i++) { + for (int i = 0; i < n_streams && d->stream_idx < 0; i++) { bool digital = ca_stream_supports_digital(streams[i]); if (digital) { - /* Find a stream with a cac3 stream. */ - AudioStreamRangedDescription *formats = NULL; - size = GetGlobalAudioPropertyArray(streams[i], - kAudioStreamPropertyAvailablePhysicalFormats, - (void **)&formats); + AudioStreamRangedDescription *formats; + size_t n_formats; + + err = CA_GET_ARY(streams[i], + kAudioStreamPropertyAvailablePhysicalFormats, + &formats, &n_formats); - if (!size) { + if (err != noErr) { ca_msg(MSGL_WARN, "could not get number of stream formats\n"); continue; // try next one } - int formats_n = size / sizeof(AudioStreamRangedDescription); - /* If this stream supports a digital (cac3) format, then set it. */ int req_rate_format = -1; int max_rate_format = -1; d->stream = streams[i]; d->stream_idx = i; - for (int j = 0; j < formats_n; j++) + for (int j = 0; j < n_formats; j++) if (ca_format_is_digital(formats[j].mFormat)) { // select the digital format that has exactly the same // samplerate. If an exact match cannot be found, select diff --git a/audio/out/ao_coreaudio_properties.c b/audio/out/ao_coreaudio_properties.c index ee6b06a153..da66f8b9d3 100644 --- a/audio/out/ao_coreaudio_properties.c +++ b/audio/out/ao_coreaudio_properties.c @@ -22,69 +22,65 @@ #include "audio/out/ao_coreaudio_properties.h" #include "audio/out/ao_coreaudio_utils.h" -OSStatus ca_get(AudioObjectID id, AudioObjectPropertySelector selector, +OSStatus ca_get(AudioObjectID id, ca_scope scope, ca_sel selector, uint32_t size, void *data) { AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { .mSelector = selector, - .mScope = kAudioObjectPropertyScopeGlobal, + .mScope = scope, .mElement = kAudioObjectPropertyElementMaster, }; return AudioObjectGetPropertyData(id, &p_addr, 0, NULL, &size, data); } -uint32_t GetAudioPropertyArray(AudioObjectID id, - AudioObjectPropertySelector selector, - AudioObjectPropertyScope scope, void **data) +OSStatus ca_set(AudioObjectID id, ca_scope scope, ca_sel selector, + uint32_t size, void *data) +{ + AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { + .mSelector = selector, + .mScope = scope, + .mElement = kAudioObjectPropertyElementMaster, + }; + + return AudioObjectSetPropertyData(id, &p_addr, 0, NULL, size, data); +} + +OSStatus ca_get_ary(AudioObjectID id, ca_scope scope, ca_sel selector, + uint32_t element_size, void **data, size_t *elements) { OSStatus err; - AudioObjectPropertyAddress p_addr; - UInt32 p_size; + uint32_t p_size; - p_addr.mSelector = selector; - p_addr.mScope = scope; - p_addr.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { + .mSelector = selector, + .mScope = scope, + .mElement = kAudioObjectPropertyElementMaster, + }; err = AudioObjectGetPropertyDataSize(id, &p_addr, 0, NULL, &p_size); - CHECK_CA_ERROR("Can't fetch property size"); + CHECK_CA_ERROR("can't fetch property size"); *data = malloc(p_size); + *elements = p_size / element_size; - err = AudioObjectGetPropertyData(id, &p_addr, 0, NULL, &p_size, *data); - CHECK_CA_ERROR_L(coreaudio_error_free, "Can't fetch property data %s"); - - return p_size; + err = ca_get(id, scope, selector, p_size, *data); + CHECK_CA_ERROR_L(coreaudio_error_free, "can't fetch property data"); + return err; coreaudio_error_free: free(*data); coreaudio_error: - return 0; -} - -uint32_t GetGlobalAudioPropertyArray(AudioObjectID id, - AudioObjectPropertySelector selector, - void **data) -{ - return GetAudioPropertyArray(id, selector, kAudioObjectPropertyScopeGlobal, - data); + return err; } -OSStatus GetAudioPropertyString(AudioObjectID id, - AudioObjectPropertySelector selector, - char **data) +OSStatus ca_get_str(AudioObjectID id, ca_scope scope, ca_sel selector, + char **data) { - OSStatus err; - AudioObjectPropertyAddress p_addr; - UInt32 p_size = sizeof(CFStringRef); CFStringRef string; - - p_addr.mSelector = selector; - p_addr.mScope = kAudioObjectPropertyScopeGlobal; - p_addr.mElement = kAudioObjectPropertyElementMaster; - - err = AudioObjectGetPropertyData(id, &p_addr, 0, NULL, &p_size, &string); - CHECK_CA_ERROR("Can't fetch array property"); + OSStatus err = + ca_get(id, scope, selector, sizeof(CFStringRef), (void **)&string); + CHECK_CA_ERROR("Can't fetch string property"); CFIndex size = CFStringGetMaximumSizeForEncoding( @@ -97,29 +93,14 @@ coreaudio_error: return err; } -OSStatus SetAudioProperty(AudioObjectID id, - AudioObjectPropertySelector selector, - uint32_t size, void *data) +Boolean ca_settable(AudioObjectID id, ca_scope scope, ca_sel selector, + Boolean *data) { - AudioObjectPropertyAddress p_addr; - - p_addr.mSelector = selector; - p_addr.mScope = kAudioObjectPropertyScopeGlobal; - p_addr.mElement = kAudioObjectPropertyElementMaster; - - return AudioObjectSetPropertyData(id, &p_addr, 0, NULL, - size, data); -} - -Boolean IsAudioPropertySettable(AudioObjectID id, - AudioObjectPropertySelector selector, - Boolean *data) -{ - AudioObjectPropertyAddress p_addr; - - p_addr.mSelector = selector; - p_addr.mScope = kAudioObjectPropertyScopeGlobal; - p_addr.mElement = kAudioObjectPropertyElementMaster; + AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { + .mSelector = selector, + .mScope = kAudioObjectPropertyScopeGlobal, + .mElement = kAudioObjectPropertyElementMaster, + }; return AudioObjectIsPropertySettable(id, &p_addr, data); } diff --git a/audio/out/ao_coreaudio_properties.h b/audio/out/ao_coreaudio_properties.h index 8f7cc2907b..88ba889c29 100644 --- a/audio/out/ao_coreaudio_properties.h +++ b/audio/out/ao_coreaudio_properties.h @@ -21,29 +21,38 @@ #include -OSStatus ca_get(AudioObjectID id, AudioObjectPropertySelector selector, +// CoreAudio names are way too verbose +#define ca_sel AudioObjectPropertySelector +#define ca_scope AudioObjectPropertyScope +#define CA_GLOBAL kAudioObjectPropertyScopeGlobal +#define CA_OUTPUT kAudioObjectPropertyScopeOutput + +OSStatus ca_get(AudioObjectID id, ca_scope scope, ca_sel selector, + uint32_t size, void *data); + +OSStatus ca_set(AudioObjectID id, ca_scope scope, ca_sel selector, uint32_t size, void *data); -#define CA_GET(id, selector, data) ca_get(id, selector, sizeof(*(data)), data) +#define CA_GET(id, sel, data) ca_get(id, CA_GLOBAL, sel, sizeof(*(data)), data) +#define CA_SET(id, sel, data) ca_set(id, CA_GLOBAL, sel, sizeof(*(data)), data) + +OSStatus ca_get_ary(AudioObjectID id, ca_scope scope, ca_sel selector, + uint32_t element_size, void **data, size_t *elements); + +#define CA_GET_ARY(id, sel, data, elements) \ + ca_get_ary(id, CA_GLOBAL, sel, sizeof(**(data)), (void **)data, elements) -uint32_t GetAudioPropertyArray(AudioObjectID id, - AudioObjectPropertySelector selector, - AudioObjectPropertyScope scope, void **data); +#define CA_GET_ARY_O(id, sel, data, elements) \ + ca_get_ary(id, CA_OUTPUT, sel, sizeof(**(data)), (void **)data, elements) -uint32_t GetGlobalAudioPropertyArray(AudioObjectID id, - AudioObjectPropertySelector selector, - void **data); +OSStatus ca_get_str(AudioObjectID id, ca_scope scope,ca_sel selector, + char **data); -OSStatus GetAudioPropertyString(AudioObjectID id, - AudioObjectPropertySelector selector, - char **data); +#define CA_GET_STR(id, sel, data) ca_get_str(id, CA_GLOBAL, sel, data) -OSStatus SetAudioProperty(AudioObjectID id, - AudioObjectPropertySelector selector, - uint32_t size, void *data); +Boolean ca_settable(AudioObjectID id, ca_scope scope, ca_sel selector, + Boolean *data); -Boolean IsAudioPropertySettable(AudioObjectID id, - AudioObjectPropertySelector selector, - Boolean *outData); +#define CA_SETTABLE(id, sel, data) ca_settable(id, CA_GLOBAL, sel, data) #endif /* MPV_COREAUDIO_PROPERTIES_H */ diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c index 9a0c184c40..221aeb4ddb 100644 --- a/audio/out/ao_coreaudio_utils.c +++ b/audio/out/ao_coreaudio_utils.c @@ -104,19 +104,14 @@ bool ca_format_is_digital(AudioStreamBasicDescription asbd) bool ca_stream_supports_digital(AudioStreamID stream) { AudioStreamRangedDescription *formats = NULL; + size_t n_formats; - /* Retrieve all the stream formats supported by each output stream. */ - uint32_t size = - GetGlobalAudioPropertyArray(stream, - kAudioStreamPropertyAvailablePhysicalFormats, - (void **)&formats); + OSStatus err = + CA_GET_ARY(stream, kAudioStreamPropertyAvailablePhysicalFormats, + &formats, &n_formats); - if (!size) { - ca_msg(MSGL_WARN, "Could not get number of stream formats.\n"); - return false; - } + CHECK_CA_ERROR("Could not get number of stream formats."); - const int n_formats = size / sizeof(AudioStreamRangedDescription); for (int i = 0; i < n_formats; i++) { AudioStreamBasicDescription asbd = formats[i].mFormat; ca_print_asbd("supported format:", &(asbd)); @@ -127,25 +122,21 @@ bool ca_stream_supports_digital(AudioStreamID stream) } free(formats); +coreaudio_error: return false; } bool ca_device_supports_digital(AudioDeviceID device) { AudioStreamID *streams = NULL; + size_t n_streams; /* Retrieve all the output streams. */ - uint32_t size = GetAudioPropertyArray(device, - kAudioDevicePropertyStreams, - kAudioDevicePropertyScopeOutput, - (void **)&streams); - - if (!size) { - ca_msg(MSGL_WARN, "could not get number of streams.\n"); - return CONTROL_FALSE; - } + OSStatus err = + CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams); + + CHECK_CA_ERROR("could not get number of streams."); - const int n_streams = size / sizeof(AudioStreamID); for (int i = 0; i < n_streams; i++) { if (ca_stream_supports_digital(streams[i])) { free(streams); @@ -154,6 +145,8 @@ bool ca_device_supports_digital(AudioDeviceID device) } free(streams); + +coreaudio_error: return false; } @@ -194,8 +187,7 @@ OSStatus ca_device_listener(AudioObjectID object, uint32_t n_addresses, OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) { *pid = getpid(); - OSStatus err = SetAudioProperty(device, kAudioDevicePropertyHogMode, - sizeof(*pid), pid); + OSStatus err = CA_SET(device, kAudioDevicePropertyHogMode, pid); if (err != noErr) *pid = -1; @@ -205,8 +197,7 @@ OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) { OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid) { if (*pid == getpid()) { *pid = -1; - return SetAudioProperty(device, kAudioDevicePropertyHogMode, - sizeof(*pid), &pid); + return CA_SET(device, kAudioDevicePropertyHogMode, &pid); } return noErr; } @@ -224,8 +215,8 @@ static OSStatus ca_change_mixing(AudioDeviceID device, uint32_t val, if (AudioObjectHasProperty(device, &p_addr)) { OSStatus err; Boolean writeable = 0; - err = IsAudioPropertySettable(device, kAudioDevicePropertySupportsMixing, - &writeable); + err = CA_SETTABLE(device, kAudioDevicePropertySupportsMixing, + &writeable); if (!CHECK_CA_WARN("can't tell if mixing property is settable")) { return err; @@ -234,8 +225,7 @@ static OSStatus ca_change_mixing(AudioDeviceID device, uint32_t val, if (!writeable) return noErr; - err = SetAudioProperty(device, kAudioDevicePropertySupportsMixing, - sizeof(uint32_t), &val); + err = CA_SET(device, kAudioDevicePropertySupportsMixing, &val); if (err != noErr) return err; @@ -311,8 +301,7 @@ bool ca_change_format(AudioStreamID stream, } /* Change the format. */ - err = SetAudioProperty(stream, kAudioStreamPropertyPhysicalFormat, - sizeof(AudioStreamBasicDescription), &change_format); + err = CA_SET(stream, kAudioStreamPropertyPhysicalFormat, &change_format); if (!CHECK_CA_WARN("error changing physical format")) { return false; } -- cgit v1.2.3