Add callback for device format change (CoreAudio)

master
jp9000 2014-02-27 12:22:58 -08:00
parent 1a5220acf1
commit 1927dc7eaa
1 changed files with 38 additions and 26 deletions

View File

@ -11,6 +11,8 @@
#include "mac-helpers.h" #include "mac-helpers.h"
#define FORMAT_CHANGED kAudioStreamPropertyAvailablePhysicalFormats
#define SCOPE_OUTPUT kAudioUnitScope_Output #define SCOPE_OUTPUT kAudioUnitScope_Output
#define SCOPE_INPUT kAudioUnitScope_Input #define SCOPE_INPUT kAudioUnitScope_Input
#define SCOPE_GLOBAL kAudioUnitScope_Global #define SCOPE_GLOBAL kAudioUnitScope_Global
@ -315,42 +317,29 @@ static void coreaudio_begin_reconnect(struct coreaudio_data *ca)
"create thread, error code: %d", ret); "create thread, error code: %d", ret);
} }
static OSStatus disconnection_callback( static OSStatus notification_callback(
AudioObjectID id, AudioObjectID id,
UInt32 num_addresses, UInt32 num_addresses,
const AudioObjectPropertyAddress addresses[], const AudioObjectPropertyAddress addresses[],
void *data) void *data)
{ {
struct coreaudio_data *ca = data; struct coreaudio_data *ca = data;
UInt32 alive = 0;
UInt32 size = sizeof(alive);
OSStatus stat;
stat = AudioObjectGetPropertyData(id, addresses, 0, NULL, &size, coreaudio_stop(ca);
&alive); coreaudio_uninit(ca);
if (ca_success(stat, ca, "disconnection_callback", "get property")) {
if (!alive) {
coreaudio_stop(ca);
coreaudio_uninit(ca);
blog(LOG_INFO, "coreaudio: device '%s' disconnected. " blog(LOG_INFO, "coreaudio: device '%s' disconnected or format "
"attempting to reconnect", "changed. attempting to reconnect", ca->device_name);
ca->device_name);
coreaudio_begin_reconnect(ca); coreaudio_begin_reconnect(ca);
}
}
UNUSED_PARAMETER(id);
UNUSED_PARAMETER(num_addresses); UNUSED_PARAMETER(num_addresses);
UNUSED_PARAMETER(addresses);
return noErr; return noErr;
} }
static const AudioObjectPropertyAddress alive_addr = {
kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
static bool coreaudio_init_hooks(struct coreaudio_data *ca) static bool coreaudio_init_hooks(struct coreaudio_data *ca)
{ {
OSStatus stat; OSStatus stat;
@ -359,12 +348,25 @@ static bool coreaudio_init_hooks(struct coreaudio_data *ca)
.inputProcRefCon = ca .inputProcRefCon = ca
}; };
stat = AudioObjectAddPropertyListener(ca->device_id, &alive_addr, AudioObjectPropertyAddress addr = {
disconnection_callback, ca); kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
stat = AudioObjectAddPropertyListener(ca->device_id, &addr,
notification_callback, ca);
if (!ca_success(stat, ca, "coreaudio_init_hooks", if (!ca_success(stat, ca, "coreaudio_init_hooks",
"set disconnect callback")) "set disconnect callback"))
return false; return false;
addr.mSelector = FORMAT_CHANGED;
stat = AudioObjectAddPropertyListener(ca->device_id, &addr,
notification_callback, ca);
if (!ca_success(stat, ca, "coreaudio_init_hooks",
"set format change callback"))
return false;
stat = set_property(ca->unit, kAudioOutputUnitProperty_SetInputCallback, stat = set_property(ca->unit, kAudioOutputUnitProperty_SetInputCallback,
SCOPE_GLOBAL, 0, &callback_info, sizeof(callback_info)); SCOPE_GLOBAL, 0, &callback_info, sizeof(callback_info));
if (!ca_success(stat, ca, "coreaudio_init_hooks", "set input callback")) if (!ca_success(stat, ca, "coreaudio_init_hooks", "set input callback"))
@ -380,8 +382,18 @@ static void coreaudio_remove_hooks(struct coreaudio_data *ca)
.inputProcRefCon = NULL .inputProcRefCon = NULL
}; };
AudioObjectRemovePropertyListener(ca->device_id, &alive_addr, AudioObjectPropertyAddress addr = {
disconnection_callback, ca); kAudioDevicePropertyDeviceIsAlive,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
AudioObjectRemovePropertyListener(ca->device_id, &addr,
notification_callback, ca);
addr.mSelector = FORMAT_CHANGED;
AudioObjectRemovePropertyListener(ca->device_id, &addr,
notification_callback, ca);
set_property(ca->unit, kAudioOutputUnitProperty_SetInputCallback, set_property(ca->unit, kAudioOutputUnitProperty_SetInputCallback,
SCOPE_GLOBAL, 0, &callback_info, sizeof(callback_info)); SCOPE_GLOBAL, 0, &callback_info, sizeof(callback_info));