From f317d24a3972b65349d7860da48822fbd058f36c Mon Sep 17 00:00:00 2001 From: Stefano Pigozzi Date: Tue, 1 Jul 2014 19:05:43 +0200 Subject: ao_coreaudio: move device related functions to the new AO --- audio/out/ao_coreaudio_device.c | 255 ++++++++++++++++++++++++++++++++++++++++ audio/out/ao_coreaudio_utils.c | 249 --------------------------------------- audio/out/ao_coreaudio_utils.h | 28 ----- 3 files changed, 255 insertions(+), 277 deletions(-) (limited to 'audio/out') diff --git a/audio/out/ao_coreaudio_device.c b/audio/out/ao_coreaudio_device.c index 89fd9305f0..a0610a34d5 100644 --- a/audio/out/ao_coreaudio_device.c +++ b/audio/out/ao_coreaudio_device.c @@ -50,6 +50,261 @@ static void audio_pause(struct ao *ao); static void audio_resume(struct ao *ao); static void reset(struct ao *ao); +static bool ca_format_is_digital(AudioStreamBasicDescription asbd) +{ + switch (asbd.mFormatID) + case 'IAC3': + case 'iac3': + case kAudioFormat60958AC3: + case kAudioFormatAC3: + return true; + return false; +} + +static bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream) +{ + AudioStreamRangedDescription *formats = NULL; + size_t n_formats; + + OSStatus err = + CA_GET_ARY(stream, kAudioStreamPropertyAvailablePhysicalFormats, + &formats, &n_formats); + + CHECK_CA_ERROR("Could not get number of stream formats."); + + for (int i = 0; i < n_formats; i++) { + AudioStreamBasicDescription asbd = formats[i].mFormat; + ca_print_asbd(ao, "supported format:", &(asbd)); + if (ca_format_is_digital(asbd)) { + talloc_free(formats); + return true; + } + } + + talloc_free(formats); +coreaudio_error: + return false; +} + +static bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device) +{ + AudioStreamID *streams = NULL; + size_t n_streams; + + /* Retrieve all the output streams. */ + OSStatus err = + CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams); + + CHECK_CA_ERROR("could not get number of streams."); + + for (int i = 0; i < n_streams; i++) { + if (ca_stream_supports_digital(ao, streams[i])) { + talloc_free(streams); + return true; + } + } + + talloc_free(streams); + +coreaudio_error: + return false; +} + +static OSStatus ca_property_listener( + AudioObjectPropertySelector selector, + AudioObjectID object, uint32_t n_addresses, + const AudioObjectPropertyAddress addresses[], + void *data) +{ + void *talloc_ctx = talloc_new(NULL); + + for (int i = 0; i < n_addresses; i++) { + if (addresses[i].mSelector == selector) { + if (data) *(volatile int *)data = 1; + break; + } + } + talloc_free(talloc_ctx); + return noErr; +} + +static OSStatus ca_stream_listener( + AudioObjectID object, uint32_t n_addresses, + const AudioObjectPropertyAddress addresses[], + void *data) +{ + return ca_property_listener(kAudioStreamPropertyPhysicalFormat, + object, n_addresses, addresses, data); +} + +static OSStatus ca_device_listener( + AudioObjectID object, uint32_t n_addresses, + const AudioObjectPropertyAddress addresses[], + void *data) +{ + return ca_property_listener(kAudioDevicePropertyDeviceHasChanged, + object, n_addresses, addresses, data); +} + +static OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) { + *pid = getpid(); + OSStatus err = CA_SET(device, kAudioDevicePropertyHogMode, pid); + if (err != noErr) + *pid = -1; + + return err; +} + +static OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid) { + if (*pid == getpid()) { + *pid = -1; + return CA_SET(device, kAudioDevicePropertyHogMode, &pid); + } + return noErr; +} + +static OSStatus ca_change_mixing(struct ao *ao, AudioDeviceID device, + uint32_t val, bool *changed) { + *changed = false; + + AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { + .mSelector = kAudioDevicePropertySupportsMixing, + .mScope = kAudioObjectPropertyScopeGlobal, + .mElement = kAudioObjectPropertyElementMaster, + }; + + if (AudioObjectHasProperty(device, &p_addr)) { + OSStatus err; + Boolean writeable = 0; + err = CA_SETTABLE(device, kAudioDevicePropertySupportsMixing, + &writeable); + + if (!CHECK_CA_WARN("can't tell if mixing property is settable")) { + return err; + } + + if (!writeable) + return noErr; + + err = CA_SET(device, kAudioDevicePropertySupportsMixing, &val); + if (err != noErr) + return err; + + if (!CHECK_CA_WARN("can't set mix mode")) { + return err; + } + + *changed = true; + } + + return noErr; +} + +static OSStatus ca_disable_mixing(struct ao *ao, + AudioDeviceID device, bool *changed) { + return ca_change_mixing(ao, device, 0, changed); +} + +static OSStatus ca_enable_mixing(struct ao *ao, + AudioDeviceID device, bool changed) { + if (changed) { + bool dont_care = false; + return ca_change_mixing(ao, device, 1, &dont_care); + } + + return noErr; +} + +static OSStatus ca_change_device_listening(AudioDeviceID device, + void *flag, bool enabled) +{ + AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { + .mSelector = kAudioDevicePropertyDeviceHasChanged, + .mScope = kAudioObjectPropertyScopeGlobal, + .mElement = kAudioObjectPropertyElementMaster, + }; + + if (enabled) { + return AudioObjectAddPropertyListener( + device, &p_addr, ca_device_listener, flag); + } else { + return AudioObjectRemovePropertyListener( + device, &p_addr, ca_device_listener, flag); + } +} + +static OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag) { + return ca_change_device_listening(device, flag, true); +} + +static OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag) { + return ca_change_device_listening(device, flag, false); +} + +static bool ca_change_format(struct ao *ao, AudioStreamID stream, + AudioStreamBasicDescription change_format) +{ + OSStatus err = noErr; + AudioObjectPropertyAddress p_addr; + volatile int stream_format_changed = 0; + + ca_print_asbd(ao, "setting stream format:", &change_format); + + /* Install the callback. */ + p_addr = (AudioObjectPropertyAddress) { + .mSelector = kAudioStreamPropertyPhysicalFormat, + .mScope = kAudioObjectPropertyScopeGlobal, + .mElement = kAudioObjectPropertyElementMaster, + }; + + err = AudioObjectAddPropertyListener(stream, &p_addr, ca_stream_listener, + (void *)&stream_format_changed); + if (!CHECK_CA_WARN("can't add property listener during format change")) { + return false; + } + + /* Change the format. */ + err = CA_SET(stream, kAudioStreamPropertyPhysicalFormat, &change_format); + if (!CHECK_CA_WARN("error changing physical format")) { + return false; + } + + /* The AudioStreamSetProperty is not only asynchronious, + * it is also not Atomic, in its behaviour. + * Therefore we check 5 times before we really give up. */ + bool format_set = false; + for (int i = 0; !format_set && i < 5; i++) { + for (int j = 0; !stream_format_changed && j < 50; j++) + mp_sleep_us(10000); + + if (stream_format_changed) { + stream_format_changed = 0; + } else { + MP_VERBOSE(ao, "reached timeout\n"); + } + + AudioStreamBasicDescription actual_format; + err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format); + + ca_print_asbd(ao, "actual format in use:", &actual_format); + if (actual_format.mSampleRate == change_format.mSampleRate && + actual_format.mFormatID == change_format.mFormatID && + actual_format.mFramesPerPacket == change_format.mFramesPerPacket) { + format_set = true; + } + } + + err = AudioObjectRemovePropertyListener(stream, &p_addr, ca_stream_listener, + (void *)&stream_format_changed); + + if (!CHECK_CA_WARN("can't remove property listener")) { + return false; + } + + return format_set; +} + + struct priv { AudioDeviceID device; // selected device diff --git a/audio/out/ao_coreaudio_utils.c b/audio/out/ao_coreaudio_utils.c index 4656c2c508..f5cc43db0b 100644 --- a/audio/out/ao_coreaudio_utils.c +++ b/audio/out/ao_coreaudio_utils.c @@ -149,255 +149,6 @@ void ca_print_asbd(struct ao *ao, const char *description, talloc_free(format); } -bool ca_format_is_digital(AudioStreamBasicDescription asbd) -{ - switch (asbd.mFormatID) - case 'IAC3': - case 'iac3': - case kAudioFormat60958AC3: - case kAudioFormatAC3: - return true; - return false; -} - -bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream) -{ - AudioStreamRangedDescription *formats = NULL; - size_t n_formats; - - OSStatus err = - CA_GET_ARY(stream, kAudioStreamPropertyAvailablePhysicalFormats, - &formats, &n_formats); - - CHECK_CA_ERROR("Could not get number of stream formats."); - - for (int i = 0; i < n_formats; i++) { - AudioStreamBasicDescription asbd = formats[i].mFormat; - ca_print_asbd(ao, "supported format:", &(asbd)); - if (ca_format_is_digital(asbd)) { - talloc_free(formats); - return true; - } - } - - talloc_free(formats); -coreaudio_error: - return false; -} - -bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device) -{ - AudioStreamID *streams = NULL; - size_t n_streams; - - /* Retrieve all the output streams. */ - OSStatus err = - CA_GET_ARY_O(device, kAudioDevicePropertyStreams, &streams, &n_streams); - - CHECK_CA_ERROR("could not get number of streams."); - - for (int i = 0; i < n_streams; i++) { - if (ca_stream_supports_digital(ao, streams[i])) { - talloc_free(streams); - return true; - } - } - - talloc_free(streams); - -coreaudio_error: - return false; -} - -OSStatus ca_property_listener(AudioObjectPropertySelector selector, - AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data) -{ - void *talloc_ctx = talloc_new(NULL); - - for (int i = 0; i < n_addresses; i++) { - if (addresses[i].mSelector == selector) { - if (data) *(volatile int *)data = 1; - break; - } - } - talloc_free(talloc_ctx); - return noErr; -} - -OSStatus ca_stream_listener(AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data) -{ - return ca_property_listener(kAudioStreamPropertyPhysicalFormat, - object, n_addresses, addresses, data); -} - -OSStatus ca_device_listener(AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data) -{ - return ca_property_listener(kAudioDevicePropertyDeviceHasChanged, - object, n_addresses, addresses, data); -} - -OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid) { - *pid = getpid(); - OSStatus err = CA_SET(device, kAudioDevicePropertyHogMode, pid); - if (err != noErr) - *pid = -1; - - return err; -} - -OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid) { - if (*pid == getpid()) { - *pid = -1; - return CA_SET(device, kAudioDevicePropertyHogMode, &pid); - } - return noErr; -} - -static OSStatus ca_change_mixing(struct ao *ao, AudioDeviceID device, - uint32_t val, bool *changed) { - *changed = false; - - AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { - .mSelector = kAudioDevicePropertySupportsMixing, - .mScope = kAudioObjectPropertyScopeGlobal, - .mElement = kAudioObjectPropertyElementMaster, - }; - - if (AudioObjectHasProperty(device, &p_addr)) { - OSStatus err; - Boolean writeable = 0; - err = CA_SETTABLE(device, kAudioDevicePropertySupportsMixing, - &writeable); - - if (!CHECK_CA_WARN("can't tell if mixing property is settable")) { - return err; - } - - if (!writeable) - return noErr; - - err = CA_SET(device, kAudioDevicePropertySupportsMixing, &val); - if (err != noErr) - return err; - - if (!CHECK_CA_WARN("can't set mix mode")) { - return err; - } - - *changed = true; - } - - return noErr; -} - -OSStatus ca_disable_mixing(struct ao *ao, AudioDeviceID device, bool *changed) { - return ca_change_mixing(ao, device, 0, changed); -} - -OSStatus ca_enable_mixing(struct ao *ao, AudioDeviceID device, bool changed) { - if (changed) { - bool dont_care = false; - return ca_change_mixing(ao, device, 1, &dont_care); - } - - return noErr; -} - -static OSStatus ca_change_device_listening(AudioDeviceID device, - void *flag, bool enabled) -{ - AudioObjectPropertyAddress p_addr = (AudioObjectPropertyAddress) { - .mSelector = kAudioDevicePropertyDeviceHasChanged, - .mScope = kAudioObjectPropertyScopeGlobal, - .mElement = kAudioObjectPropertyElementMaster, - }; - - if (enabled) { - return AudioObjectAddPropertyListener( - device, &p_addr, ca_device_listener, flag); - } else { - return AudioObjectRemovePropertyListener( - device, &p_addr, ca_device_listener, flag); - } -} - -OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag) { - return ca_change_device_listening(device, flag, true); -} - -OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag) { - return ca_change_device_listening(device, flag, false); -} - -bool ca_change_format(struct ao *ao, AudioStreamID stream, - AudioStreamBasicDescription change_format) -{ - OSStatus err = noErr; - AudioObjectPropertyAddress p_addr; - volatile int stream_format_changed = 0; - - ca_print_asbd(ao, "setting stream format:", &change_format); - - /* Install the callback. */ - p_addr = (AudioObjectPropertyAddress) { - .mSelector = kAudioStreamPropertyPhysicalFormat, - .mScope = kAudioObjectPropertyScopeGlobal, - .mElement = kAudioObjectPropertyElementMaster, - }; - - err = AudioObjectAddPropertyListener(stream, &p_addr, ca_stream_listener, - (void *)&stream_format_changed); - if (!CHECK_CA_WARN("can't add property listener during format change")) { - return false; - } - - /* Change the format. */ - err = CA_SET(stream, kAudioStreamPropertyPhysicalFormat, &change_format); - if (!CHECK_CA_WARN("error changing physical format")) { - return false; - } - - /* The AudioStreamSetProperty is not only asynchronious, - * it is also not Atomic, in its behaviour. - * Therefore we check 5 times before we really give up. */ - bool format_set = false; - for (int i = 0; !format_set && i < 5; i++) { - for (int j = 0; !stream_format_changed && j < 50; j++) - mp_sleep_us(10000); - - if (stream_format_changed) { - stream_format_changed = 0; - } else { - MP_VERBOSE(ao, "reached timeout\n"); - } - - AudioStreamBasicDescription actual_format; - err = CA_GET(stream, kAudioStreamPropertyPhysicalFormat, &actual_format); - - ca_print_asbd(ao, "actual format in use:", &actual_format); - if (actual_format.mSampleRate == change_format.mSampleRate && - actual_format.mFormatID == change_format.mFormatID && - actual_format.mFramesPerPacket == change_format.mFramesPerPacket) { - format_set = true; - } - } - - err = AudioObjectRemovePropertyListener(stream, &p_addr, ca_stream_listener, - (void *)&stream_format_changed); - - if (!CHECK_CA_WARN("can't remove property listener")) { - return false; - } - - return format_set; -} - static const int speaker_map[][2] = { { kAudioChannelLabel_Left, MP_SPEAKER_ID_FL }, { kAudioChannelLabel_Right, MP_SPEAKER_ID_FR }, diff --git a/audio/out/ao_coreaudio_utils.h b/audio/out/ao_coreaudio_utils.h index f44ea28e82..b9b65eb5be 100644 --- a/audio/out/ao_coreaudio_utils.h +++ b/audio/out/ao_coreaudio_utils.h @@ -52,34 +52,6 @@ OSStatus ca_select_device(struct ao *ao, int selection, AudioDeviceID *device); void ca_print_asbd(struct ao *ao, const char *description, const AudioStreamBasicDescription *asbd); -bool ca_format_is_digital(AudioStreamBasicDescription asbd); -bool ca_stream_supports_digital(struct ao *ao, AudioStreamID stream); -bool ca_device_supports_digital(struct ao *ao, AudioDeviceID device); - -OSStatus ca_property_listener(AudioObjectPropertySelector selector, - AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data); - -OSStatus ca_stream_listener(AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data); - -OSStatus ca_device_listener(AudioObjectID object, uint32_t n_addresses, - const AudioObjectPropertyAddress addresses[], - void *data); - -OSStatus ca_lock_device(AudioDeviceID device, pid_t *pid); -OSStatus ca_unlock_device(AudioDeviceID device, pid_t *pid); -OSStatus ca_disable_mixing(struct ao *ao, AudioDeviceID device, bool *changed); -OSStatus ca_enable_mixing(struct ao *ao, AudioDeviceID device, bool changed); - -OSStatus ca_enable_device_listener(AudioDeviceID device, void *flag); -OSStatus ca_disable_device_listener(AudioDeviceID device, void *flag); - -bool ca_change_format(struct ao *ao, AudioStreamID stream, - AudioStreamBasicDescription change_format); - bool ca_layout_to_mp_chmap(struct ao *ao, AudioChannelLayout *layout, struct mp_chmap *chmap); -- cgit v1.2.3