audio: run the audio callback even if device was lost.
authorRyan C. Gordon <icculus@icculus.org>
Sun, 26 Feb 2017 00:12:33 -0500
changeset 10913a02b673351cc
parent 10912 6aca05df632b
child 10914 ebc7ff92677d
audio: run the audio callback even if device was lost.

We will throw away the data anyhow, but some apps depend on the callback
firing to make progress; testmultiaudio.c, if nothing else, is an example
of this.

Capture also will now fire the callback in these conditions, offering nothing
but silence.

Apps can check SDL_GetAudioDeviceStatus() or listen for the
SDL_AUDIODEVICEREMOVED event if they want to gracefully deal with
an opened audio device that has been unexpectedly lost.
src/audio/SDL_audio.c
     1.1 --- a/src/audio/SDL_audio.c	Sun Feb 26 00:10:02 2017 -0500
     1.2 +++ b/src/audio/SDL_audio.c	Sun Feb 26 00:12:33 2017 -0500
     1.3 @@ -672,18 +672,14 @@
     1.4              data = device->work_buffer;
     1.5          }
     1.6  
     1.7 -        if ( SDL_AtomicGet(&device->enabled) ) {
     1.8 -            /* !!! FIXME: this should be LockDevice. */
     1.9 -            SDL_LockMutex(device->mixer_lock);
    1.10 -            if (SDL_AtomicGet(&device->paused)) {
    1.11 -                SDL_memset(data, silence, data_len);
    1.12 -            } else {
    1.13 -                callback(udata, data, data_len);
    1.14 -            }
    1.15 -            SDL_UnlockMutex(device->mixer_lock);
    1.16 +        /* !!! FIXME: this should be LockDevice. */
    1.17 +        SDL_LockMutex(device->mixer_lock);
    1.18 +        if (SDL_AtomicGet(&device->paused)) {
    1.19 +            SDL_memset(data, silence, data_len);
    1.20          } else {
    1.21 -            SDL_memset(data, silence, data_len);
    1.22 +            callback(udata, data, data_len);
    1.23          }
    1.24 +        SDL_UnlockMutex(device->mixer_lock);
    1.25  
    1.26          if (device->stream) {
    1.27              /* Stream available audio to device, converting/resampling. */
    1.28 @@ -752,7 +748,7 @@
    1.29          int still_need;
    1.30          Uint8 *ptr;
    1.31  
    1.32 -        if (!SDL_AtomicGet(&device->enabled) || SDL_AtomicGet(&device->paused)) {
    1.33 +        if (SDL_AtomicGet(&device->paused)) {
    1.34              SDL_Delay(delay);  /* just so we don't cook the CPU. */
    1.35              if (device->stream) {
    1.36                  SDL_AudioStreamClear(device->stream);
    1.37 @@ -774,7 +770,7 @@
    1.38             and block when there isn't data so this thread isn't eating CPU.
    1.39             But we don't process it further or call the app's callback. */
    1.40  
    1.41 -        while (still_need > 0) {
    1.42 +        while (SDL_AtomicGet(&device->enabled) && (still_need > 0)) {
    1.43              const int rc = current_audio.impl.CaptureFromDevice(device, ptr, still_need);
    1.44              SDL_assert(rc <= still_need);  /* device should not overflow buffer. :) */
    1.45              if (rc > 0) {