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.
|
||||
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 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;
|
||||
|
|
|
@ -42,6 +42,28 @@
|
|||
#endif
|
||||
|
||||
#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 = {
|
||||
kAudioHardwarePropertyDevices,
|
||||
kAudioObjectPropertyScopeGlobal,
|
||||
|
@ -70,7 +92,7 @@ static const AudioObjectPropertyAddress alive_address = {
|
|||
static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, const AudioObjectPropertyAddress *addrs, void *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 size = sizeof(alive);
|
||||
|
@ -95,8 +117,9 @@ static OSStatus DeviceAliveNotification(AudioObjectID devid, UInt32 num_addr, co
|
|||
|
||||
static void COREAUDIO_FreeDeviceHandle(SDL_AudioDevice *device)
|
||||
{
|
||||
const AudioDeviceID devid = (AudioDeviceID)(size_t)device->handle;
|
||||
AudioObjectRemovePropertyListener(devid, &alive_address, DeviceAliveNotification, device);
|
||||
SDLCoreAudioHandle *handle = (SDLCoreAudioHandle *) device->handle;
|
||||
AudioObjectRemovePropertyListener(handle->devid, &alive_address, DeviceAliveNotification, device);
|
||||
SDL_free(handle);
|
||||
}
|
||||
|
||||
// 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));
|
||||
for (UInt32 i = 0; i < total_devices; i++) {
|
||||
SDL_AudioDevice *device = SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devs[i]));
|
||||
if (device) {
|
||||
if (FindCoreAudioDeviceByHandle(devs[i], SDL_TRUE) || FindCoreAudioDeviceByHandle(devs[i], SDL_FALSE)) {
|
||||
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"),
|
||||
(int)i, name, (int)dev);
|
||||
#endif
|
||||
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(iscapture ? SDL_TRUE : SDL_FALSE, name, &spec, (void *)((size_t)dev));
|
||||
SDLCoreAudioHandle *newhandle = (SDLCoreAudioHandle *) SDL_calloc(1, sizeof (*newhandle));
|
||||
if (newhandle) {
|
||||
newhandle->devid = dev;
|
||||
newhandle->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
|
||||
SDL_AudioDevice *device = SDL_AddAudioDevice(newhandle->iscapture, name, &spec, newhandle);
|
||||
if (device) {
|
||||
AudioObjectAddPropertyListener(dev, &alive_address, DeviceAliveNotification, device);
|
||||
} else {
|
||||
SDL_free(newhandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
SDL_free(name); // SDL_AddAudioDevice() would have copied the string.
|
||||
|
@ -226,12 +254,12 @@ static OSStatus DeviceListChangedNotification(AudioObjectID systemObj, UInt32 nu
|
|||
return noErr;
|
||||
}
|
||||
|
||||
static OSStatus DefaultAudioDeviceChangedNotification(AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
||||
static OSStatus DefaultAudioDeviceChangedNotification(const SDL_bool iscapture, AudioObjectID inObjectID, const AudioObjectPropertyAddress *addr)
|
||||
{
|
||||
AudioDeviceID devid;
|
||||
UInt32 size = sizeof(devid);
|
||||
if (AudioObjectGetPropertyData(inObjectID, addr, 0, NULL, &size, &devid) == noErr) {
|
||||
SDL_DefaultAudioDeviceChanged(SDL_FindPhysicalAudioDeviceByHandle((void *)((size_t)devid)));
|
||||
SDL_DefaultAudioDeviceChanged(FindCoreAudioDeviceByHandle(devid, iscapture));
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
@ -242,7 +270,7 @@ static OSStatus DefaultOutputDeviceChangedNotification(AudioObjectID inObjectID,
|
|||
SDL_Log("COREAUDIO: default output device changed!");
|
||||
#endif
|
||||
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)
|
||||
|
@ -251,7 +279,7 @@ static OSStatus DefaultInputDeviceChangedNotification(AudioObjectID inObjectID,
|
|||
SDL_Log("COREAUDIO: default input device changed!");
|
||||
#endif
|
||||
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)
|
||||
|
@ -266,7 +294,7 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
|
|||
|
||||
size = sizeof(AudioDeviceID);
|
||||
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) {
|
||||
*default_output = device;
|
||||
}
|
||||
|
@ -275,7 +303,7 @@ static void COREAUDIO_DetectDevices(SDL_AudioDevice **default_output, SDL_AudioD
|
|||
|
||||
size = sizeof(AudioDeviceID);
|
||||
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) {
|
||||
*default_capture = device;
|
||||
}
|
||||
|
@ -631,10 +659,10 @@ static void COREAUDIO_CloseDevice(SDL_AudioDevice *device)
|
|||
#ifdef MACOSX_COREAUDIO
|
||||
static int PrepareDevice(SDL_AudioDevice *device)
|
||||
{
|
||||
void *handle = device->handle;
|
||||
SDL_assert(handle != NULL); // this meant "system default" in SDL2, but doesn't anymore
|
||||
SDL_assert(device->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;
|
||||
UInt32 size = 0;
|
||||
|
||||
|
|
Loading…
Reference in New Issue