Skip to content

Commit

Permalink
Disconnected/broken/lost audio devices now continue to fire their cal…
Browse files Browse the repository at this point in the history
…lback.

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.
  • Loading branch information
icculus committed Mar 19, 2015
1 parent 75973f8 commit 5cbb32e
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 31 deletions.
63 changes: 33 additions & 30 deletions src/audio/SDL_audio.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/audio/SDL_sysaudio.h
Expand Up @@ -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;

Expand Down

0 comments on commit 5cbb32e

Please sign in to comment.