Disconnected/broken/lost audio devices now continue to fire their callback. The data produced by the callback is just thrown away and the audio thread delays as if it's waiting for the hardware to drain. This lets apps that rely on their audio callback firing regularly continue to make progress to function as properly as possible in the face of disaster. Apps that want to know that the device is really gone and deal with that scenario can use the new hotplug functionality.
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 142
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index e00500b..5e6eb70 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -727,7 +727,7 @@ SDL_RunAudio(void *devicep)
resampling process can be any number. We will have to see what a good size for the
stream's maximum length is, but I suspect 2*max(len_cvt, stream_len) is a good figure.
*/
- while (device->enabled) {
+ while (!device->shutdown) {
if (device->paused) {
SDL_Delay(delay);
@@ -810,31 +810,27 @@ SDL_RunAudio(void *devicep)
const int silence = (int) device->spec.silence;
/* Loop, filling the audio buffers */
- while (device->enabled) {
-
+ while (!device->shutdown) {
/* Fill the current buffer with sound */
if (device->convert.needed) {
- if (device->convert.buf) {
- stream = device->convert.buf;
- } else {
- continue;
- }
- } else {
+ stream = device->convert.buf;
+ } else if (device->enabled) {
stream = current_audio.impl.GetDeviceBuf(device);
- if (stream == NULL) {
- stream = device->fake_stream;
- }
+ } else {
+ /* if the device isn't enabled, we still write to the
+ fake_stream, so the app's callback will fire with
+ a regular frequency, in case they depend on that
+ for timing or progress. They can use hotplug
+ now to know if the device failed. */
+ stream = NULL;
}
- /* !!! FIXME: this should be LockDevice. */
- SDL_LockMutex(device->mixer_lock);
-
- /* Check again, in case device was removed while a lock was held. */
- if (!device->enabled) {
- SDL_UnlockMutex(device->mixer_lock);
- break;
+ if (stream == NULL) {
+ stream = device->fake_stream;
}
+ /* !!! FIXME: this should be LockDevice. */
+ SDL_LockMutex(device->mixer_lock);
if (device->paused) {
SDL_memset(stream, silence, stream_len);
} else {
@@ -843,14 +839,15 @@ SDL_RunAudio(void *devicep)
SDL_UnlockMutex(device->mixer_lock);
/* Convert the audio if necessary */
- if (device->convert.needed) {
+ if (device->enabled && device->convert.needed) {
SDL_ConvertAudio(&device->convert);
stream = current_audio.impl.GetDeviceBuf(device);
if (stream == NULL) {
stream = device->fake_stream;
+ } else {
+ SDL_memcpy(stream, device->convert.buf,
+ device->convert.len_cvt);
}
- SDL_memcpy(stream, device->convert.buf,
- device->convert.len_cvt);
}
/* Ready current buffer for play and change current buffer */
@@ -1084,6 +1081,7 @@ static void
close_audio_device(SDL_AudioDevice * device)
{
device->enabled = 0;
+ device->shutdown = 1;
if (device->thread != NULL) {
SDL_WaitThread(device->thread, NULL);
}
@@ -1178,6 +1176,7 @@ open_audio_device(const char *devname, int iscapture,
SDL_AudioDevice *device;
SDL_bool build_cvt;
void *handle = NULL;
+ int stream_len;
int i = 0;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
@@ -1304,14 +1303,6 @@ open_audio_device(const char *devname, int iscapture,
}
device->opened = 1;
- /* Allocate a fake audio memory buffer */
- device->fake_stream = (Uint8 *)SDL_AllocAudioMem(device->spec.size);
- if (device->fake_stream == NULL) {
- close_audio_device(device);
- SDL_OutOfMemory();
- return 0;
- }
-
/* See if we need to do any conversion */
build_cvt = SDL_FALSE;
if (obtained->freq != device->spec.freq) {
@@ -1370,6 +1361,18 @@ open_audio_device(const char *devname, int iscapture,
}
}
+ /* Allocate a fake audio memory buffer */
+ stream_len = (device->convert.needed) ? device->convert.len_cvt : 0;
+ if (device->spec.size > stream_len) {
+ stream_len = device->spec.size;
+ }
+ device->fake_stream = (Uint8 *)SDL_AllocAudioMem(stream_len);
+ if (device->fake_stream == NULL) {
+ close_audio_device(device);
+ SDL_OutOfMemory();
+ return 0;
+ }
+
if (device->spec.callback == NULL) { /* use buffer queueing? */
/* pool a few packets to start. Enough for two callbacks. */
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
index fd8e687..a339f81 100644
--- a/src/audio/SDL_sysaudio.h
+++ b/src/audio/SDL_sysaudio.h
@@ -155,7 +155,8 @@ struct SDL_AudioDevice
/* Current state flags */
/* !!! FIXME: should be SDL_bool */
int iscapture;
- int enabled;
+ int enabled; /* true if device is functioning and connected. */
+ int shutdown; /* true if we are signaling the play thread to end. */
int paused;
int opened;