1
0
mirror of https://github.com/mpv-player/mpv synced 2024-12-19 21:31:52 +00:00

ao_coreaudio: move device related functions to the new AO

This commit is contained in:
Stefano Pigozzi 2014-07-01 19:05:43 +02:00
parent a8ef70b0f8
commit f317d24a39
3 changed files with 255 additions and 277 deletions

View File

@ -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

View File

@ -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 },

View File

@ -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);