Commit 6d5c9c1e675718716cc117c6d8a71ce0c0818de2

Ryan C. Gordon 2016-08-02T13:48:52

audio: Made some SDL_AudioDevice fields atomic. This makes sure they're properly communicated to the audio threads.

diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 8fee9dc..934652a 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -366,14 +366,14 @@ void SDL_OpenedAudioDeviceDisconnected(SDL_AudioDevice *device)
 {
     SDL_assert(get_audio_device(device->id) == device);
 
-    if (!device->enabled) {
+    if (!SDL_AtomicGet(&device->enabled)) {
         return;
     }
 
     /* Ends the audio callback and mark the device as STOPPED, but the
        app still needs to close the device to free resources. */
     current_audio.impl.LockDevice(device);
-    device->enabled = SDL_FALSE;
+    SDL_AtomicSet(&device->enabled, 0);
     current_audio.impl.UnlockDevice(device);
 
     /* Post the event, if desired */
@@ -615,7 +615,7 @@ SDL_RunAudio(void *devicep)
         /* Fill the current buffer with sound */
         if (device->convert.needed) {
             stream = device->convert.buf;
-        } else if (device->enabled) {
+        } else if (SDL_AtomicGet(&device->enabled)) {
             stream = current_audio.impl.GetDeviceBuf(device);
         } else {
             /* if the device isn't enabled, we still write to the
@@ -632,7 +632,7 @@ SDL_RunAudio(void *devicep)
 
         /* !!! FIXME: this should be LockDevice. */
         SDL_LockMutex(device->mixer_lock);
-        if (device->paused) {
+        if (SDL_AtomicGet(&device->paused)) {
             SDL_memset(stream, silence, stream_len);
         } else {
             (*fill) (udata, stream, stream_len);
@@ -640,7 +640,7 @@ SDL_RunAudio(void *devicep)
         SDL_UnlockMutex(device->mixer_lock);
 
         /* Convert the audio if necessary */
-        if (device->enabled && device->convert.needed) {
+        if (device->convert.needed && SDL_AtomicGet(&device->enabled)) {
             SDL_ConvertAudio(&device->convert);
             stream = current_audio.impl.GetDeviceBuf(device);
             if (stream == NULL) {
@@ -873,8 +873,8 @@ SDL_GetAudioDeviceName(int index, int iscapture)
 static void
 close_audio_device(SDL_AudioDevice * device)
 {
-    device->enabled = SDL_FALSE;
     SDL_AtomicSet(&device->shutdown, 1);
+    SDL_AtomicSet(&device->enabled, 0);
     if (device->thread != NULL) {
         SDL_WaitThread(device->thread, NULL);
     }
@@ -1074,13 +1074,14 @@ open_audio_device(const char *devname, int iscapture,
         return 0;
     }
     SDL_zerop(device);
-    SDL_AtomicSet(&device->shutdown, 0);  /* just in case. */
     device->id = id + 1;
     device->spec = *obtained;
-    device->enabled = SDL_TRUE;
-    device->paused = SDL_TRUE;
     device->iscapture = iscapture ? SDL_TRUE : SDL_FALSE;
 
+    SDL_AtomicSet(&device->shutdown, 0);  /* just in case. */
+    SDL_AtomicSet(&device->paused, 1);
+    SDL_AtomicSet(&device->enabled, 1);
+
     /* Create a mutex for locking the sound buffers */
     if (!current_audio.impl.SkipMixerLock) {
         device->mixer_lock = SDL_CreateMutex();
@@ -1256,8 +1257,8 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
 {
     SDL_AudioDevice *device = get_audio_device(devid);
     SDL_AudioStatus status = SDL_AUDIO_STOPPED;
-    if (device && device->enabled) {
-        if (device->paused) {
+    if (device && SDL_AtomicGet(&device->enabled)) {
+        if (SDL_AtomicGet(&device->paused)) {
             status = SDL_AUDIO_PAUSED;
         } else {
             status = SDL_AUDIO_PLAYING;
@@ -1279,7 +1280,7 @@ SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
     SDL_AudioDevice *device = get_audio_device(devid);
     if (device) {
         current_audio.impl.LockDevice(device);
-        device->paused = pause_on ? SDL_TRUE : SDL_FALSE;
+        SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
         current_audio.impl.UnlockDevice(device);
     }
 }
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
index fcf441d..0b35b27 100644
--- a/src/audio/SDL_sysaudio.h
+++ b/src/audio/SDL_sysaudio.h
@@ -158,10 +158,10 @@ struct SDL_AudioDevice
 
     /* Current state flags */
     SDL_atomic_t shutdown; /* true if we are signaling the play thread to end. */
-    SDL_bool iscapture;
-    SDL_bool enabled;  /* true if device is functioning and connected. */
-    SDL_bool paused;
+    SDL_atomic_t enabled;  /* true if device is functioning and connected. */
+    SDL_atomic_t paused;
     SDL_bool opened;
+    SDL_bool iscapture;
 
     /* Fake audio buffer for when the audio hardware is busy */
     Uint8 *fake_stream;
diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c
index 1a84380..e9f672f 100644
--- a/src/audio/alsa/SDL_alsa_audio.c
+++ b/src/audio/alsa/SDL_alsa_audio.c
@@ -311,7 +311,7 @@ ALSA_PlayDevice(_THIS)
 
     swizzle_alsa_channels(this);
 
-    while ( frames_left > 0 && this->enabled ) {
+    while ( frames_left > 0 && SDL_AtomicGet(&this->enabled) ) {
         /* !!! FIXME: This works, but needs more testing before going live */
         /* ALSA_snd_pcm_wait(this->hidden->pcm_handle, -1); */
         status = ALSA_snd_pcm_writei(this->hidden->pcm_handle,
diff --git a/src/audio/android/SDL_androidaudio.c b/src/audio/android/SDL_androidaudio.c
index 4a4faad..047793a 100644
--- a/src/audio/android/SDL_androidaudio.c
+++ b/src/audio/android/SDL_androidaudio.c
@@ -151,13 +151,13 @@ void AndroidAUD_PauseDevices(void)
     struct SDL_PrivateAudioData *private;
     if(audioDevice != NULL && audioDevice->hidden != NULL) {
         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
-        if (audioDevice->paused) {
+        if (SDL_AtomicGet(&audioDevice->paused)) {
             /* The device is already paused, leave it alone */
             private->resume = SDL_FALSE;
         }
         else {
             SDL_LockMutex(audioDevice->mixer_lock);
-            audioDevice->paused = SDL_TRUE;
+            SDL_AtomicSet(&audioDevice->paused, 1);
             private->resume = SDL_TRUE;
         }
     }
@@ -171,7 +171,7 @@ void AndroidAUD_ResumeDevices(void)
     if(audioDevice != NULL && audioDevice->hidden != NULL) {
         private = (struct SDL_PrivateAudioData *) audioDevice->hidden;
         if (private->resume) {
-            audioDevice->paused = SDL_FALSE;
+            SDL_AtomicSet(&audioDevice->paused, 0);
             private->resume = SDL_FALSE;
             SDL_UnlockMutex(audioDevice->mixer_lock);
         }
diff --git a/src/audio/coreaudio/SDL_coreaudio.c b/src/audio/coreaudio/SDL_coreaudio.c
index 3bf66d6..2385995 100644
--- a/src/audio/coreaudio/SDL_coreaudio.c
+++ b/src/audio/coreaudio/SDL_coreaudio.c
@@ -283,7 +283,7 @@ outputCallback(void *inRefCon,
     UInt32 i;
 
     /* Only do anything if audio is enabled and not paused */
-    if (!this->enabled || this->paused) {
+    if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
         for (i = 0; i < ioData->mNumberBuffers; i++) {
             abuf = &ioData->mBuffers[i];
             SDL_memset(abuf->mData, this->spec.silence, abuf->mDataByteSize);
@@ -335,7 +335,7 @@ inputCallback(void *inRefCon,
               AudioBufferList *ioData)
 {
     SDL_AudioDevice *this = (SDL_AudioDevice *) inRefCon;
-    if (!this->enabled || this->paused) {
+    if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
         return noErr;  /* just drop this if we're not accepting input. */
     }
 
@@ -391,7 +391,7 @@ device_unplugged(AudioObjectID devid, UInt32 num_addr, const AudioObjectProperty
     UInt32 size = sizeof (isAlive);
     OSStatus error;
 
-    if (!this->enabled) {
+    if (!SDL_AtomicGet(&this->enabled)) {
         return 0;  /* already known to be dead. */
     }
 
diff --git a/src/audio/emscripten/SDL_emscriptenaudio.c b/src/audio/emscripten/SDL_emscriptenaudio.c
index 8378233..ea42723 100644
--- a/src/audio/emscripten/SDL_emscriptenaudio.c
+++ b/src/audio/emscripten/SDL_emscriptenaudio.c
@@ -63,12 +63,10 @@ HandleAudioProcess(_THIS)
     int bytes = SDL_AUDIO_BITSIZE(this->spec.format) / 8;
     int bytes_in = SDL_AUDIO_BITSIZE(this->convert.src_format) / 8;
 
-    /* Only do soemthing if audio is enabled */
-    if (!this->enabled)
-        return;
-
-    if (this->paused)
+    /* Only do something if audio is enabled */
+    if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
         return;
+    }
 
     if (this->convert.needed) {
         if (this->hidden->conv_in_len != 0) {
diff --git a/src/audio/haiku/SDL_haikuaudio.cc b/src/audio/haiku/SDL_haikuaudio.cc
index 38f3b96..de364b0 100644
--- a/src/audio/haiku/SDL_haikuaudio.cc
+++ b/src/audio/haiku/SDL_haikuaudio.cc
@@ -49,10 +49,11 @@ FillSound(void *device, void *stream, size_t len,
     SDL_AudioDevice *audio = (SDL_AudioDevice *) device;
 
     /* Only do soemthing if audio is enabled */
-    if (!audio->enabled)
+    if (!SDL_AtomicGet(&audio->enabled)) {
         return;
+    }
 
-    if (!audio->paused) {
+    if (!SDL_AtomicGet(&audio->paused)) {
         if (audio->convert.needed) {
             SDL_LockMutex(audio->mixer_lock);
             (*audio->spec.callback) (audio->spec.userdata,
diff --git a/src/audio/nacl/SDL_naclaudio.c b/src/audio/nacl/SDL_naclaudio.c
index 450a369..8f1c51a 100644
--- a/src/audio/nacl/SDL_naclaudio.c
+++ b/src/audio/nacl/SDL_naclaudio.c
@@ -53,7 +53,7 @@ static void nacl_audio_callback(void* samples, uint32_t buffer_size, PP_TimeDelt
     
     SDL_LockMutex(private->mutex);  /* !!! FIXME: is this mutex necessary? */
 
-    if (_this->enabled && !_this->paused) {
+    if (SDL_AtomicGet(&this->enabled) && !SDL_AtomicGet(&this->paused)) {
         if (_this->convert.needed) {
             SDL_LockMutex(_this->mixer_lock);
             (*_this->spec.callback) (_this->spec.userdata,
diff --git a/src/audio/pulseaudio/SDL_pulseaudio.c b/src/audio/pulseaudio/SDL_pulseaudio.c
index fdf38c8..4fed809 100644
--- a/src/audio/pulseaudio/SDL_pulseaudio.c
+++ b/src/audio/pulseaudio/SDL_pulseaudio.c
@@ -326,7 +326,7 @@ PULSEAUDIO_WaitDevice(_THIS)
 {
     struct SDL_PrivateAudioData *h = this->hidden;
 
-    while (this->enabled) {
+    while (SDL_AtomicGet(&this->enabled)) {
         if (PULSEAUDIO_pa_context_get_state(h->context) != PA_CONTEXT_READY ||
             PULSEAUDIO_pa_stream_get_state(h->stream) != PA_STREAM_READY ||
             PULSEAUDIO_pa_mainloop_iterate(h->mainloop, 1, NULL) < 0) {
@@ -344,7 +344,7 @@ PULSEAUDIO_PlayDevice(_THIS)
 {
     /* Write the audio data */
     struct SDL_PrivateAudioData *h = this->hidden;
-    if (this->enabled) {
+    if (SDL_AtomicGet(&this->enabled)) {
         if (PULSEAUDIO_pa_stream_write(h->stream, h->mixbuf, h->mixlen, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
             SDL_OpenedAudioDeviceDisconnected(this);
         }
@@ -360,7 +360,7 @@ stream_drain_complete(pa_stream *s, int success, void *userdata)
 static void
 PULSEAUDIO_WaitDone(_THIS)
 {
-    if (this->enabled) {
+    if (SDL_AtomicGet(&this->enabled)) {
         struct SDL_PrivateAudioData *h = this->hidden;
         pa_operation *o = PULSEAUDIO_pa_stream_drain(h->stream, stream_drain_complete, NULL);
         if (o) {
diff --git a/src/audio/qsa/SDL_qsa_audio.c b/src/audio/qsa/SDL_qsa_audio.c
index 1742fe3..88d29f9 100644
--- a/src/audio/qsa/SDL_qsa_audio.c
+++ b/src/audio/qsa/SDL_qsa_audio.c
@@ -229,7 +229,7 @@ QSA_PlayDevice(_THIS)
     int towrite;
     void *pcmbuffer;
 
-    if ((!this->enabled) || (!this->hidden)) {
+    if (!SDL_AtomicGet(&this->enabled) || !this->hidden) {
         return;
     }
 
@@ -305,7 +305,7 @@ QSA_PlayDevice(_THIS)
             towrite -= written;
             pcmbuffer += written * this->spec.channels;
         }
-    } while ((towrite > 0) && (this->enabled));
+    } while ((towrite > 0) && SDL_AtomicGet(&this->enabled));
 
     /* If we couldn't write, assume fatal error for now */
     if (towrite != 0) {
diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c
index dff234b..ba9ad9f 100644
--- a/src/audio/xaudio2/SDL_xaudio2.c
+++ b/src/audio/xaudio2/SDL_xaudio2.c
@@ -195,7 +195,7 @@ XAUDIO2_PlayDevice(_THIS)
     IXAudio2SourceVoice *source = this->hidden->source;
     HRESULT result = S_OK;
 
-    if (!this->enabled) { /* shutting down? */
+    if (!SDL_AtomicGet(&this->enabled)) { /* shutting down? */
         return;
     }
 
@@ -226,7 +226,7 @@ XAUDIO2_PlayDevice(_THIS)
 static void
 XAUDIO2_WaitDevice(_THIS)
 {
-    if (this->enabled) {
+    if (SDL_AtomicGet(&this->enabled)) {
         SDL_SemWait(this->hidden->semaphore);
     }
 }
@@ -236,7 +236,7 @@ XAUDIO2_WaitDone(_THIS)
 {
     IXAudio2SourceVoice *source = this->hidden->source;
     XAUDIO2_VOICE_STATE state;
-    SDL_assert(!this->enabled);  /* flag that stops playing. */
+    SDL_assert(!SDL_AtomicGet(&this->enabled));  /* flag that stops playing. */
     IXAudio2SourceVoice_Discontinuity(source);
 #if SDL_XAUDIO2_WIN8
     IXAudio2SourceVoice_GetState(source, &state, XAUDIO2_VOICE_NOSAMPLESPLAYED);