From 64fee85c69b89011ec2d912f357b4ba8ae9cd3f6 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Sat, 30 Sep 2023 11:50:53 -0400 Subject: [PATCH] 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. --- src/audio/alsa/SDL_alsa_audio.c | 35 +++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/audio/alsa/SDL_alsa_audio.c b/src/audio/alsa/SDL_alsa_audio.c index 66672b9a1..bdc9e841f 100644 --- a/src/audio/alsa/SDL_alsa_audio.c +++ b/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 */ 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) { /* 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)); SDL_AudioDeviceDisconnected(device); } 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) { 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); 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)) { int status = ALSA_snd_pcm_writei(device->hidden->pcm_handle, 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 == -EAGAIN) { /* 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) { + 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; }