audio open: ensure 2 devices don't get the same id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index e2f7412..e33e41d 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -1313,7 +1313,7 @@ open_audio_device(const char *devname, int iscapture,
return 0;
}
- /* !!! FIXME: there is a race condition here if two devices open from two threads at once. */
+ SDL_LockMutex(current_audio.detectionLock);
/* Find an available device ID... */
for (id = min_id - 1; id < SDL_arraysize(open_devices); id++) {
if (open_devices[id] == NULL) {
@@ -1323,6 +1323,7 @@ open_audio_device(const char *devname, int iscapture,
if (id == SDL_arraysize(open_devices)) {
SDL_SetError("Too many open audio devices");
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
@@ -1330,6 +1331,7 @@ open_audio_device(const char *devname, int iscapture,
obtained = &_obtained;
}
if (!prepare_audiospec(desired, obtained)) {
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
@@ -1351,6 +1353,7 @@ open_audio_device(const char *devname, int iscapture,
if ((iscapture) && (current_audio.impl.OnlyHasDefaultCaptureDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_INPUT_DEVNAME) != 0)) {
SDL_SetError("No such device");
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
devname = NULL;
@@ -1358,11 +1361,13 @@ open_audio_device(const char *devname, int iscapture,
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if ((open_devices[i]) && (open_devices[i]->iscapture)) {
SDL_SetError("Audio device already open");
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
}
} else if ((!iscapture) && (current_audio.impl.OnlyHasDefaultOutputDevice)) {
if ((devname) && (SDL_strcmp(devname, DEFAULT_OUTPUT_DEVNAME) != 0)) {
+ SDL_UnlockMutex(current_audio.detectionLock);
SDL_SetError("No such device");
return 0;
}
@@ -1370,6 +1375,7 @@ open_audio_device(const char *devname, int iscapture,
for (i = 0; i < SDL_arraysize(open_devices); i++) {
if ((open_devices[i]) && (!open_devices[i]->iscapture)) {
+ SDL_UnlockMutex(current_audio.detectionLock);
SDL_SetError("Audio device already open");
return 0;
}
@@ -1382,20 +1388,19 @@ open_audio_device(const char *devname, int iscapture,
It might still need to open a device based on the string for,
say, a network audio server, but this optimizes some cases. */
SDL_AudioDeviceItem *item;
- SDL_LockMutex(current_audio.detectionLock);
for (item = iscapture ? current_audio.inputDevices : current_audio.outputDevices; item; item = item->next) {
if ((item->handle != NULL) && (SDL_strcmp(item->name, devname) == 0)) {
handle = item->handle;
break;
}
}
- SDL_UnlockMutex(current_audio.detectionLock);
}
if (!current_audio.impl.AllowsArbitraryDeviceNames) {
/* has to be in our device list, or the default device. */
if ((handle == NULL) && (devname != NULL)) {
SDL_SetError("No such device.");
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
}
@@ -1403,6 +1408,7 @@ open_audio_device(const char *devname, int iscapture,
device = (SDL_AudioDevice *) SDL_calloc(1, sizeof (SDL_AudioDevice));
if (device == NULL) {
SDL_OutOfMemory();
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
device->id = id + 1;
@@ -1419,6 +1425,7 @@ open_audio_device(const char *devname, int iscapture,
device->mixer_lock = SDL_CreateMutex();
if (device->mixer_lock == NULL) {
close_audio_device(device);
+ SDL_UnlockMutex(current_audio.detectionLock);
SDL_SetError("Couldn't create mixer lock");
return 0;
}
@@ -1433,6 +1440,7 @@ open_audio_device(const char *devname, int iscapture,
if (current_audio.impl.OpenDevice(device, devname) < 0) {
close_audio_device(device);
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
@@ -1488,6 +1496,7 @@ open_audio_device(const char *devname, int iscapture,
if (!device->stream) {
close_audio_device(device);
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
}
@@ -1497,6 +1506,7 @@ open_audio_device(const char *devname, int iscapture,
device->buffer_queue = SDL_NewDataQueue(SDL_AUDIOBUFFERQUEUE_PACKETLEN, obtained->size * 2);
if (!device->buffer_queue) {
close_audio_device(device);
+ SDL_UnlockMutex(current_audio.detectionLock);
SDL_SetError("Couldn't create audio buffer queue");
return 0;
}
@@ -1514,6 +1524,7 @@ open_audio_device(const char *devname, int iscapture,
device->work_buffer = (Uint8 *) SDL_malloc(device->work_buffer_len);
if (device->work_buffer == NULL) {
close_audio_device(device);
+ SDL_UnlockMutex(current_audio.detectionLock);
SDL_OutOfMemory();
return 0;
}
@@ -1534,9 +1545,11 @@ open_audio_device(const char *devname, int iscapture,
if (device->thread == NULL) {
close_audio_device(device);
SDL_SetError("Couldn't create audio thread");
+ SDL_UnlockMutex(current_audio.detectionLock);
return 0;
}
}
+ SDL_UnlockMutex(current_audio.detectionLock);
return device->id;
}