From 9c9f23eee90f1df49098080dee0c10c7b9883ea6 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 30 May 2014 23:54:11 +0200 Subject: ao_alsa: reduce spurious wakeups Apparently this can happen. So actually only return from waiting if ALSA excplicitly signals that new output is available, or if we are woken up externally. --- audio/out/ao_alsa.c | 22 ++++++++++++++-------- audio/out/push.c | 6 ++++-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/audio/out/ao_alsa.c b/audio/out/ao_alsa.c index 6b755a6d5c..081f9efebf 100644 --- a/audio/out/ao_alsa.c +++ b/audio/out/ao_alsa.c @@ -712,14 +712,20 @@ static int audio_wait(struct ao *ao, pthread_mutex_t *lock) err = snd_pcm_poll_descriptors(p->alsa, fds, num_fds); CHECK_ALSA_ERROR("cannot get pollfds"); - int r = ao_wait_poll(ao, fds, num_fds, lock); - if (r < 0) - return r; - - unsigned short revents; - snd_pcm_poll_descriptors_revents(p->alsa, fds, num_fds, &revents); - CHECK_ALSA_ERROR("cannot read poll events"); - + while (1) { + int r = ao_wait_poll(ao, fds, num_fds, lock); + if (r) + return r; + + unsigned short revents; + snd_pcm_poll_descriptors_revents(p->alsa, fds, num_fds, &revents); + CHECK_ALSA_ERROR("cannot read poll events"); + + if (revents & POLLERR) + return -1; + if (revents & POLLOUT) + return 0; + } return 0; alsa_error: diff --git a/audio/out/push.c b/audio/out/push.c index 409a5f50e0..cd7b8dc329 100644 --- a/audio/out/push.c +++ b/audio/out/push.c @@ -410,7 +410,7 @@ int ao_play_silence(struct ao *ao, int samples) // Call poll() for the given fds. This will extend the given fds with the // wakeup pipe, so ao_wakeup_poll() will basically interrupt this function. // Unlocks the lock temporarily. -// Returns <0 on error, 0 on success. +// Returns <0 on error, 0 on success, 1 if the caller should return immediately. int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, pthread_mutex_t *lock) { @@ -434,13 +434,15 @@ int ao_wait_poll(struct ao *ao, struct pollfd *fds, int num_fds, pthread_mutex_lock(&p->lock); memcpy(fds, p_fds, num_fds * sizeof(fds[0])); + bool wakeup = false; if (p_fds[num_fds].revents & POLLIN) { + wakeup = true; // flush the wakeup pipe contents - might "drown" some wakeups, but // that's ok for our use-case char buf[100]; read(p->wakeup_pipe[0], buf, sizeof(buf)); } - return (r >= 0 || r == -EINTR) ? 0 : -1; + return (r >= 0 || r == -EINTR) ? wakeup : -1; } void ao_wakeup_poll(struct ao *ao) -- cgit v1.2.3