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.
parent
75973f81b2
commit
5cbb32ef57
|
@ -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
|
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.
|
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) {
|
if (device->paused) {
|
||||||
SDL_Delay(delay);
|
SDL_Delay(delay);
|
||||||
|
@ -810,31 +810,27 @@ SDL_RunAudio(void *devicep)
|
||||||
const int silence = (int) device->spec.silence;
|
const int silence = (int) device->spec.silence;
|
||||||
|
|
||||||
/* Loop, filling the audio buffers */
|
/* Loop, filling the audio buffers */
|
||||||
while (device->enabled) {
|
while (!device->shutdown) {
|
||||||
|
|
||||||
/* Fill the current buffer with sound */
|
/* Fill the current buffer with sound */
|
||||||
if (device->convert.needed) {
|
if (device->convert.needed) {
|
||||||
if (device->convert.buf) {
|
stream = device->convert.buf;
|
||||||
stream = device->convert.buf;
|
} else if (device->enabled) {
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
stream = current_audio.impl.GetDeviceBuf(device);
|
stream = current_audio.impl.GetDeviceBuf(device);
|
||||||
if (stream == NULL) {
|
} else {
|
||||||
stream = device->fake_stream;
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream == NULL) {
|
||||||
|
stream = device->fake_stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* !!! FIXME: this should be LockDevice. */
|
/* !!! FIXME: this should be LockDevice. */
|
||||||
SDL_LockMutex(device->mixer_lock);
|
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 (device->paused) {
|
if (device->paused) {
|
||||||
SDL_memset(stream, silence, stream_len);
|
SDL_memset(stream, silence, stream_len);
|
||||||
} else {
|
} else {
|
||||||
|
@ -843,14 +839,15 @@ SDL_RunAudio(void *devicep)
|
||||||
SDL_UnlockMutex(device->mixer_lock);
|
SDL_UnlockMutex(device->mixer_lock);
|
||||||
|
|
||||||
/* Convert the audio if necessary */
|
/* Convert the audio if necessary */
|
||||||
if (device->convert.needed) {
|
if (device->enabled && device->convert.needed) {
|
||||||
SDL_ConvertAudio(&device->convert);
|
SDL_ConvertAudio(&device->convert);
|
||||||
stream = current_audio.impl.GetDeviceBuf(device);
|
stream = current_audio.impl.GetDeviceBuf(device);
|
||||||
if (stream == NULL) {
|
if (stream == NULL) {
|
||||||
stream = device->fake_stream;
|
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 */
|
/* Ready current buffer for play and change current buffer */
|
||||||
|
@ -1084,6 +1081,7 @@ static void
|
||||||
close_audio_device(SDL_AudioDevice * device)
|
close_audio_device(SDL_AudioDevice * device)
|
||||||
{
|
{
|
||||||
device->enabled = 0;
|
device->enabled = 0;
|
||||||
|
device->shutdown = 1;
|
||||||
if (device->thread != NULL) {
|
if (device->thread != NULL) {
|
||||||
SDL_WaitThread(device->thread, NULL);
|
SDL_WaitThread(device->thread, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1178,6 +1176,7 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
SDL_AudioDevice *device;
|
SDL_AudioDevice *device;
|
||||||
SDL_bool build_cvt;
|
SDL_bool build_cvt;
|
||||||
void *handle = NULL;
|
void *handle = NULL;
|
||||||
|
int stream_len;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
|
||||||
|
@ -1304,14 +1303,6 @@ open_audio_device(const char *devname, int iscapture,
|
||||||
}
|
}
|
||||||
device->opened = 1;
|
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 */
|
/* See if we need to do any conversion */
|
||||||
build_cvt = SDL_FALSE;
|
build_cvt = SDL_FALSE;
|
||||||
if (obtained->freq != device->spec.freq) {
|
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? */
|
if (device->spec.callback == NULL) { /* use buffer queueing? */
|
||||||
/* pool a few packets to start. Enough for two callbacks. */
|
/* pool a few packets to start. Enough for two callbacks. */
|
||||||
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
|
const int packetlen = SDL_AUDIOBUFFERQUEUE_PACKETLEN;
|
||||||
|
|
|
@ -155,7 +155,8 @@ struct SDL_AudioDevice
|
||||||
/* Current state flags */
|
/* Current state flags */
|
||||||
/* !!! FIXME: should be SDL_bool */
|
/* !!! FIXME: should be SDL_bool */
|
||||||
int iscapture;
|
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 paused;
|
||||||
int opened;
|
int opened;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue