From c2a6b6e58307034ad8febd3f7d296c9bd8727ca6 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 5 Aug 2022 20:37:13 +0200 Subject: [PATCH] reshuffle XRUN recovery somewhat perform it prior to invoking read()/write() if necessary, not right after a failure event. this makes things more uniform and predictable. we don't use snd_pcm_recover() any more, as we used it only for the EPIPE case anyway, which boils down to snd_pcm_prepare() exactly. handling ESTRPIPE as well might be desirable, but that's a separate consideration. --- alsaaudio.c | 39 ++++++++++++++------------------------- 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/alsaaudio.c b/alsaaudio.c index f4089b9..d4d9747 100644 --- a/alsaaudio.c +++ b/alsaaudio.c @@ -1311,6 +1311,7 @@ alsapcm_setperiodsize(alsapcm_t *self, PyObject *args) static PyObject * alsapcm_read(alsapcm_t *self, PyObject *args) { + snd_pcm_state_t state; int res; int size = self->framesize * self->periodsize; int sizeout = 0; @@ -1344,14 +1345,13 @@ alsapcm_read(alsapcm_t *self, PyObject *args) buffer = PyBytes_AS_STRING(buffer_obj); #endif - Py_BEGIN_ALLOW_THREADS - res = snd_pcm_readi(self->handle, buffer, self->periodsize); - if (res == -EPIPE) - { - /* EPIPE means overrun */ - snd_pcm_prepare(self->handle); + state = snd_pcm_state(self->handle); + if ((state != SND_PCM_STATE_XRUN && state != SND_PCM_STATE_SETUP) || + (res = snd_pcm_prepare(self->handle)) >= 0) { + Py_BEGIN_ALLOW_THREADS + res = snd_pcm_readi(self->handle, buffer, self->periodsize); + Py_END_ALLOW_THREADS } - Py_END_ALLOW_THREADS if (res != -EPIPE) { @@ -1404,6 +1404,7 @@ alsapcm_read(alsapcm_t *self, PyObject *args) static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) { + snd_pcm_state_t state; int res; int datalen; char *data; @@ -1435,16 +1436,13 @@ static PyObject *alsapcm_write(alsapcm_t *self, PyObject *args) return NULL; } - Py_BEGIN_ALLOW_THREADS - res = snd_pcm_writei(self->handle, data, datalen/self->framesize); - if (res == -EPIPE) - { - /* EPIPE means underrun */ - res = snd_pcm_recover(self->handle, res, 1); - if (res >= 0) - res = snd_pcm_writei(self->handle, data, datalen/self->framesize); + state = snd_pcm_state(self->handle); + if ((state != SND_PCM_STATE_XRUN && state != SND_PCM_STATE_SETUP) || + (res = snd_pcm_prepare(self->handle)) >= 0) { + Py_BEGIN_ALLOW_THREADS + res = snd_pcm_writei(self->handle, data, datalen/self->framesize); + Py_END_ALLOW_THREADS } - Py_END_ALLOW_THREADS if (res == -EAGAIN) { rc = PyLong_FromLong(0); @@ -1507,15 +1505,6 @@ static PyObject *alsapcm_drop(alsapcm_t *self) return NULL; } - res = snd_pcm_prepare(self->handle); - if (res < 0) - { - PyErr_Format(ALSAAudioError, "%s [%s]", snd_strerror(res), - self->cardname); - - return NULL; - } - return PyLong_FromLong(res); }