From 04cbf132613dbf425f328131150a9492f8efb2fb Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 10 Oct 2018 15:20:56 -0400 Subject: [PATCH] audio: All device names reported by SDL must be unique. This means that if you have two devices named "Soundblaster Pro" in your machine, one will be reported as "Soundblaster Pro" and the other as "Soundblaster Pro (2)". This makes it so you can't into a position where one of your devices can't be opened because another is sitting on the same name. --- src/audio/SDL_audio.c | 60 +++++++++++++++++++++++++++++++++++----- src/audio/SDL_sysaudio.h | 4 ++- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 69781eeaa6fe3..f4999f1363b52 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -378,21 +378,57 @@ static int add_audio_device(const char *name, void *handle, SDL_AudioDeviceItem **devices, int *devCount) { int retval = -1; - const size_t size = sizeof (SDL_AudioDeviceItem) + SDL_strlen(name) + 1; - SDL_AudioDeviceItem *item = (SDL_AudioDeviceItem *) SDL_malloc(size); - if (item == NULL) { - return -1; - } + SDL_AudioDeviceItem *item; + const SDL_AudioDeviceItem *i; + int dupenum = 0; SDL_assert(handle != NULL); /* we reserve NULL, audio backends can't use it. */ + SDL_assert(name != NULL); + item = (SDL_AudioDeviceItem *) SDL_malloc(sizeof (SDL_AudioDeviceItem)); + if (!item) { + return SDL_OutOfMemory(); + } + + item->original_name = SDL_strdup(name); + if (!item->original_name) { + SDL_free(item); + return SDL_OutOfMemory(); + } + + item->dupenum = 0; + item->name = item->original_name; item->handle = handle; - SDL_strlcpy(item->name, name, size - sizeof (SDL_AudioDeviceItem)); SDL_LockMutex(current_audio.detectionLock); + + for (i = *devices; i != NULL; i = i->next) { + if (SDL_strcmp(name, i->original_name) == 0) { + dupenum = i->dupenum + 1; + break; /* stop at the highest-numbered dupe. */ + } + } + + if (dupenum) { + const size_t len = SDL_strlen(name) + 16; + char *replacement = (char *) SDL_malloc(len); + if (!replacement) { + SDL_UnlockMutex(current_audio.detectionLock); + SDL_free(item->original_name); + SDL_free(item); + SDL_OutOfMemory(); + return -1; + } + + SDL_snprintf(replacement, len, "%s (%d)", name, dupenum + 1); + item->dupenum = dupenum; + item->name = replacement; + } + item->next = *devices; *devices = item; - retval = (*devCount)++; + retval = (*devCount)++; /* !!! FIXME: this should be an atomic increment */ + SDL_UnlockMutex(current_audio.detectionLock); return retval; @@ -420,6 +456,11 @@ free_device_list(SDL_AudioDeviceItem **devices, int *devCount) if (item->handle != NULL) { current_audio.impl.FreeDeviceHandle(item->handle); } + /* these two pointers are the same if not a duplicate devname */ + if (item->name != item->original_name) { + SDL_free(item->name); + } + SDL_free(item->original_name); SDL_free(item); } *devices = NULL; @@ -977,6 +1018,11 @@ clean_out_device_list(SDL_AudioDeviceItem **devices, int *devCount, SDL_bool *re } else { *devices = next; } + /* these two pointers are the same if not a duplicate devname */ + if (item->name != item->original_name) { + SDL_free(item->name); + } + SDL_free(item->original_name); SDL_free(item); } item = next; diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index f0e1f3dad7bf9..579dea5b40784 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.h @@ -98,8 +98,10 @@ typedef struct SDL_AudioDriverImpl typedef struct SDL_AudioDeviceItem { void *handle; + char *name; + char *original_name; + int dupenum; struct SDL_AudioDeviceItem *next; - char name[SDL_VARIABLE_LENGTH_ARRAY]; } SDL_AudioDeviceItem;