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; }