Add callback for device format change (CoreAudio)
parent
1a5220acf1
commit
1927dc7eaa
|
@ -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));
|
||||||
|
|
Loading…
Reference in New Issue