coreaudio: Make sure device handles are unique.
AudioDeviceID is not unique (hardware that can do both capture and output will expose both interfaces off the same AudioDeviceID!).main
parent
87235e0f6d
commit
2fd9447670
|
@ -594,6 +594,9 @@ static SDL_AudioDevice *CreateAudioOutputDevice(const char *name, const SDL_Audi
|
||||||
// The audio backends call this when a new device is plugged in.
|
// The audio backends call this when a new device is plugged in.
|
||||||
SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, const SDL_AudioSpec *inspec, void *handle)
|
SDL_AudioDevice *SDL_AddAudioDevice(const SDL_bool iscapture, const char *name, const SDL_AudioSpec *inspec, void *handle)
|
||||||
{
|
{
|
||||||
|
// device handles MUST be unique! If the target reuses the same handle for hardware with both input and output interfaces, wrap it in a pointer you SDL_malloc'd!
|
||||||
|
SDL_assert(SDL_FindPhysicalAudioDeviceByHandle(handle) == NULL);
|
||||||
|
|
||||||
const SDL_AudioFormat default_format = iscapture ? DEFAULT_AUDIO_CAPTURE_FORMAT : DEFAULT_AUDIO_OUTPUT_FORMAT;
|
const SDL_AudioFormat default_format = iscapture ? DEFAULT_AUDIO_CAPTURE_FORMAT : DEFAULT_AUDIO_OUTPUT_FORMAT;
|
||||||
const int default_channels = iscapture ? DEFAULT_AUDIO_CAPTURE_CHANNELS : DEFAULT_AUDIO_OUTPUT_CHANNELS;
|
const int default_channels = iscapture ? DEFAULT_AUDIO_CAPTURE_CHANNELS : DEFAULT_AUDIO_OUTPUT_CHANNELS;
|
||||||
const int default_freq = iscapture ? DEFAULT_AUDIO_CAPTURE_FREQUENCY : DEFAULT_AUDIO_OUTPUT_FREQUENCY;
|
const int default_freq = iscapture ? DEFAULT_AUDIO_CAPTURE_FREQUENCY : DEFAULT_AUDIO_OUTPUT_FREQUENCY;
|
||||||
|
|
|
@ -42,6 +42,28 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
|
// Apparently AudioDeviceID values might not be unique, so we wrap it in an SDL_malloc()'d pointer
|
||||||
|
// to make it so. Use FindCoreAudioDeviceByHandle to deal with this redirection, if you need to
|
||||||
|
// map from an AudioDeviceID to a SDL handle.
|
||||||
|
typedef struct SDLCoreAudioHandle
|
||||||
|
{
|
||||||
|
AudioDeviceID devid;
|
||||||
|
SDL_bool iscapture;
|
||||||
|
} SDLCoreAudioHandle;
|
||||||
|
|
||||||
|
static SDL_bool TestCoreAudioDeviceHandleCallback(SDL_AudioDevice *device, void *handle)
|
||||||
|
{
|
||||||
|
const SDLCoreAudioHandle *a = (const SDLCoreAudioHandle *) device->handle;
|
||||||
|
const SDLCoreAudioHandle *b = (const SDLCoreAudioHandle *) handle;
|
||||||
|
return (a->devid == b->devid) && (!!a->iscapture == !!b->iscapture);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SDL_AudioDevice *FindCoreAudioDeviceByHandle(const AudioDeviceID devid, const SDL_bool iscapture)
|
||||||
|
{
|
||||||
|
SDLCoreAudioHandle handle = { devid, iscapture };
|
||||||
|
return SDL_FindPhysicalAudioDeviceByCallback(TestCoreAudioDeviceHandleCallback, &handle);
|
||||||
|
}
|
||||||
|
|
||||||
static const AudioObjectPropertyAddress devlist_address = {
|
static const AudioObjectPropertyAddress devlist_address = {
|
||||||
kAudioHardwarePropertyDevices,
|
kAudioHardwarePropertyDevices,
|
||||||
kAudioObjectPropertyScopeGlobal,
|
kAudioObjectPropertyScopeGlobal,
|
||||||
|
@ -70,7 +92,7 @@ static const AudioObjectPropertyAddress alive_address = {
|
||||||
static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
|
static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *data)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *device = (SDL_AudioDevice *)data;
|
SDL_AudioDevice *device = (SDL_AudioDevice *)data;
|
||||||
SDL_assert(((AudioObjectID)(size_t)device->handle) == devid);
|
SDL_assert(((const SDLCoreAudioHandle *) device->handle)->devid == devid);
|
||||||
|
|
||||||
UInt32 alive = 1;
|
UInt32 alive = 1;
|
||||||
UInt32 size = sizeof(alive);
|
UInt32 size = sizeof(alive);
|
||||||
|
@ -95,8 +117,9 @@ static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, co
|
||||||
|
|
||||||
static void COREAUDIO_FreeDeviceHandle(SDL_AudioDevice *device)
|
static void COREAUDIO_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||||
{
|
{
|
||||||
const AudioDeviceID devid = (AudioDeviceID)(size_t)device->handle;
|
SDLCoreAudioHandle *handle = (SDLCoreAudioHandle *) device->handle;
|
||||||
AudioObjectRemovePropertyListener(devid, &alive_address, DeviceAliveNotification, device);
|
AudioObjectRemovePropertyListener(handle->devid, &alive_address, DeviceAliveNotification, device);
|
||||||
|
SDL_free(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This only _adds_ new devices. Removal is handled by devices triggering kAudioDevicePropertyDeviceIsAlive property changes.
|
// This only _adds_ new devices. Removal is handled by devices triggering kAudioDevicePropertyDeviceIsAlive property changes.
|
||||||
|
@ -117,8 +140,7 @@ static void RefreshPhysicalDevices(void)
|
||||||
|
|
||||||
const UInt32 total_devices = (UInt32) (size / sizeof(AudioDeviceID));
|
const UInt32 total_devices = (UInt32) (size / sizeof(AudioDeviceID));
|
||||||
for (UInt32 i = 0; i < total_devices; i++) {
|
for (UInt32 i = 0; i < total_devices; i++) {
|
||||||
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devs[i]));
|
if (FindCoreAudioDeviceByHandle(devs[i], SDL_TRUE) || FindCoreAudioDeviceByHandle(devs[i], SDL_FALSE)) {
|
||||||
if (device) {
|
|
||||||
devs[i] = 0; // The system and SDL both agree it's already here, don't check it again.
|
devs[i] = 0; // The system and SDL both agree it's already here, don't check it again.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,10 +228,16 @@ static void RefreshPhysicalDevices(void)
|
||||||
((iscapture) ? "capture" : "output"),
|
((iscapture) ? "capture" : "output"),
|
||||||
(int)i, name, (int)dev);
|
(int)i, name, (int)dev);
|
||||||
#endif
|
#endif
|
||||||
|
SDLCoreAudioHandle *newhandle = (SDLCoreAudioHandle *) SDL_calloc(1, sizeof (*newhandle));
|
||||||
SDL_AudioDevice *device = SDL_AddAudioDevice(iscapture ? SDL_TRUE : SDL_FALSE, name, &spec, (void *)((size_t)dev));
|
if (newhandle) {
|
||||||
|
newhandle->devid = dev;
|
||||||
|
newhandle->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||||
|
SDL_AudioDevice *device = SDL_AddAudioDevice(newhandle->iscapture, name, &spec, newhandle);
|
||||||
if (device) {
|
if (device) {
|
||||||
AudioObjectAddPropertyListener(dev, &alive_address, DeviceAliveNotification, device);
|
AudioObjectAddPropertyListener(dev, &alive_address, DeviceAliveNotification, device);
|
||||||
|
} else {
|
||||||
|
SDL_free(newhandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SDL_free(name); // SDL_AddAudioDevice() would have copied the string.
|
SDL_free(name); // SDL_AddAudioDevice() would have copied the string.
|
||||||
|
@ -226,12 +254,12 @@ static OSStatus DeviceListChangedNotification(AudioObjectID systemObj, UInt32 nu
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus DefaultAudioDeviceChangedNotification(AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
static OSStatus DefaultAudioDeviceChangedNotification(const SDL_bool iscapture, AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
||||||
{
|
{
|
||||||
AudioDeviceID devid;
|
AudioDeviceID devid;
|
||||||
UInt32 size = sizeof(devid);
|
UInt32 size = sizeof(devid);
|
||||||
if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
|
if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
|
||||||
SDL_DefaultAudioDeviceChanged(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devid)));
|
SDL_DefaultAudioDeviceChanged(FindCoreAudioDeviceByHandle(devid, iscapture));
|
||||||
}
|
}
|
||||||
return noErr;
|
return noErr;
|
||||||
}
|
}
|
||||||
|
@ -242,7 +270,7 @@ static OSStatus DefaultOutputDeviceChangedNotification(AudioObjectID inObjectID,
|
||||||
SDL_Log("COREAUDIO: default output device changed!");
|
SDL_Log("COREAUDIO: default output device changed!");
|
||||||
#endif
|
#endif
|
||||||
SDL_assert(inNumberAddresses == 1);
|
SDL_assert(inNumberAddresses == 1);
|
||||||
return DefaultAudioDeviceChangedNotification(inObjectID, inAddresses);
|
return DefaultAudioDeviceChangedNotification(SDL_FALSE, inObjectID, inAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *inUserData)
|
||||||
|
@ -251,7 +279,7 @@ static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID,
|
||||||
SDL_Log("COREAUDIO: default input device changed!");
|
SDL_Log("COREAUDIO: default input device changed!");
|
||||||
#endif
|
#endif
|
||||||
SDL_assert(inNumberAddresses == 1);
|
SDL_assert(inNumberAddresses == 1);
|
||||||
return DefaultAudioDeviceChangedNotification(inObjectID, inAddresses);
|
return DefaultAudioDeviceChangedNotification(SDL_TRUE, inObjectID, inAddresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioDevice **default_capture)
|
||||||
|
@ -266,7 +294,7 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
|
||||||
|
|
||||||
size = sizeof(AudioDeviceID);
|
size = sizeof(AudioDeviceID);
|
||||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_output_device_address, 0, NULL, &size, &devid) == noErr) {
|
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_output_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||||
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devid));
|
SDL_AudioDevice *device = FindCoreAudioDeviceByHandle(devid, SDL_FALSE);
|
||||||
if (device) {
|
if (device) {
|
||||||
*default_output = device;
|
*default_output = device;
|
||||||
}
|
}
|
||||||
|
@ -275,7 +303,7 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
|
||||||
|
|
||||||
size = sizeof(AudioDeviceID);
|
size = sizeof(AudioDeviceID);
|
||||||
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_input_device_address, 0, NULL, &size, &devid) == noErr) {
|
if (AudioObjectGetPropertyData(kAudioObjectSystemObject, &default_input_device_address, 0, NULL, &size, &devid) == noErr) {
|
||||||
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devid));
|
SDL_AudioDevice *device = FindCoreAudioDeviceByHandle(devid, SDL_TRUE);
|
||||||
if (device) {
|
if (device) {
|
||||||
*default_capture = device;
|
*default_capture = device;
|
||||||
}
|
}
|
||||||
|
@ -631,10 +659,10 @@ static void COREAUDIO_CloseDevice(SDL_AudioDevice *device)
|
||||||
#ifdef MACOSX_COREAUDIO
|
#ifdef MACOSX_COREAUDIO
|
||||||
static int PrepareDevice(SDL_AudioDevice *device)
|
static int PrepareDevice(SDL_AudioDevice *device)
|
||||||
{
|
{
|
||||||
void *handle = device->handle;
|
SDL_assert(device->handle != NULL); // this meant "system default" in SDL2, but doesn't anymore
|
||||||
SDL_assert(handle != NULL); // this meant "system default" in SDL2, but doesn't anymore
|
|
||||||
|
|
||||||
const AudioDeviceID devid = (AudioDeviceID)((size_t)handle);
|
const SDLCoreAudioHandle *handle = (const SDLCoreAudioHandle *) device->handle;
|
||||||
|
const AudioDeviceID devid = handle->devid;
|
||||||
OSStatus result = noErr;
|
OSStatus result = noErr;
|
||||||
UInt32 size = 0;
|
UInt32 size = 0;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue