Browse Source

alsa: More efficient audio thread iteration.

Now we sleep the thread in WaitDevice until ALSA reawakens it because it
needs more data, and we feed it exactly as much as it can take at that
point.

Like the recent PulseAudio changes, this is both more efficient, reliable,
and consistent.
Ryan C. Gordon 1 year ago
parent
commit
64fee85c69
1 changed files with 22 additions and 13 deletions
  1. 22 13
      src/audio/alsa/SDL_alsa_audio.c

+ 22 - 13
src/audio/alsa/SDL_alsa_audio.c

@@ -333,33 +333,34 @@ static void no_swizzle(SDL_AudioDevice *device, void *buffer, Uint32 bufferlen)
 /* This function waits until it is possible to write a full sound buffer */
 /* This function waits until it is possible to write a full sound buffer */
 static void ALSA_WaitDevice(SDL_AudioDevice *device)
 static void ALSA_WaitDevice(SDL_AudioDevice *device)
 {
 {
-    const snd_pcm_sframes_t needed = (snd_pcm_sframes_t)device->sample_frames;
-    while (!SDL_AtomicGet(&device->shutdown)) {
-        const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
-        if (rc < 0 && rc != -EAGAIN) {
-            int status = rc;
+    const int fulldelay = (int) ((((Uint64) device->sample_frames) * 1000) / device->spec.freq);
+    const int delay = SDL_max(fulldelay, 10);
 
 
-            status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, status, 0);
+    while (!SDL_AtomicGet(&device->shutdown)) {
+        const int rc = ALSA_snd_pcm_wait(device->hidden->pcm_handle, delay);
+        if (rc < 0 && (rc != -EAGAIN)) {
+            const int status = ALSA_snd_pcm_recover(device->hidden->pcm_handle, rc, 0);
             if (status < 0) {
             if (status < 0) {
                 /* Hmm, not much we can do - abort */
                 /* Hmm, not much we can do - abort */
-                fprintf(stderr, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
+                SDL_LogError(SDL_LOG_CATEGORY_AUDIO, "ALSA snd_pcm_avail failed (unrecoverable): %s\n",
                         ALSA_snd_strerror(rc));
                         ALSA_snd_strerror(rc));
                 SDL_AudioDeviceDisconnected(device);
                 SDL_AudioDeviceDisconnected(device);
             }
             }
             return;
             return;
-        } else if (rc < needed) {
-            const Uint32 delay = ((needed - (SDL_max(rc, 0))) * 1000) / device->spec.freq;
-            SDL_Delay(SDL_max(delay, 10));
-        } else {
-            break; /* ready to go! */
         }
         }
+
+        if (rc > 0) {
+            break;  // ready to go!
+        }
+
+        // Timed out! Make sure we aren't shutting down and then wait again.
     }
     }
 }
 }
 
 
 static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
 static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
 {
 {
     SDL_assert(buffer == device->hidden->mixbuf);
     SDL_assert(buffer == device->hidden->mixbuf);
-    Uint8 *sample_buf = device->hidden->mixbuf;
+    Uint8 *sample_buf = (Uint8 *) buffer;  // !!! FIXME: deal with this without casting away constness
     const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
     const int frame_size = SDL_AUDIO_FRAMESIZE(device->spec);
     snd_pcm_uframes_t frames_left = (snd_pcm_uframes_t) (buflen / frame_size);
     snd_pcm_uframes_t frames_left = (snd_pcm_uframes_t) (buflen / frame_size);
 
 
@@ -368,6 +369,7 @@ static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
     while ((frames_left > 0) && !SDL_AtomicGet(&device->shutdown)) {
     while ((frames_left > 0) && !SDL_AtomicGet(&device->shutdown)) {
         int status = ALSA_snd_pcm_writei(device->hidden->pcm_handle,
         int status = ALSA_snd_pcm_writei(device->hidden->pcm_handle,
                                          sample_buf, frames_left);
                                          sample_buf, frames_left);
+        //SDL_Log("ALSA PLAYDEVICE: WROTE %d of %d bytes", (status >= 0) ? ((int) (status * frame_size)) : status, (int) (frames_left * frame_size));
         if (status < 0) {
         if (status < 0) {
             if (status == -EAGAIN) {
             if (status == -EAGAIN) {
                 /* Apparently snd_pcm_recover() doesn't handle this case -
                 /* Apparently snd_pcm_recover() doesn't handle this case -
@@ -399,6 +401,13 @@ static int ALSA_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buf
 
 
 static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
 static Uint8 *ALSA_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
 {
 {
+    const snd_pcm_sframes_t rc = ALSA_snd_pcm_avail(device->hidden->pcm_handle);
+    const int requested_frames = SDL_min(device->sample_frames, rc);
+    SDL_assert(requested_frames > 0);
+    const int requested_bytes = requested_frames * SDL_AUDIO_FRAMESIZE(device->spec);
+    SDL_assert(requested_bytes <= *buffer_size);
+    //SDL_Log("ALSA GETDEVICEBUF: NEED %d BYTES", requested_bytes);
+    *buffer_size = requested_bytes;
     return device->hidden->mixbuf;
     return device->hidden->mixbuf;
 }
 }