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.main
parent
47cba08259
commit
64fee85c69
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue