forked from auracaster/pyalsaaudio
unbreak read buffer overrun handling
my commit c2a6b6e broke it big time; we'd now just paper over overruns.
:}
the previous handling was fundamentally correct, needing only two
adjustments:
- to recover from drop()/drain(), we need to call snd_pcm_prepare() when
the stream state is SND_PCM_STATE_SETUP. notably, we must not do this
when the state is SND_PCM_STATE_XRUN.
- we should error-check the unlikely case that the recovery from an xrun
fails.
that way we now have two snd_pcm_prepare() call sites in read(), which
looks a bit messy, but it's actually correct.
as a drive-by, simplify the return value check of snd_pcm_prepare() -
values higher than zero are impossible.
This commit is contained in:
committed by
Lars Immisch
parent
7d9c16618b
commit
8ff3e169cd
15
alsaaudio.c
15
alsaaudio.c
@@ -1364,12 +1364,23 @@ alsapcm_read(alsapcm_t *self, PyObject *args)
|
||||
buffer = PyBytes_AS_STRING(buffer_obj);
|
||||
#endif
|
||||
|
||||
// After drop() and drain(), we need to prepare the stream again.
|
||||
// Note that fresh streams are already prepared by snd_pcm_hw_params().
|
||||
state = snd_pcm_state(self->handle);
|
||||
if ((state != SND_PCM_STATE_XRUN && state != SND_PCM_STATE_SETUP) ||
|
||||
(res = snd_pcm_prepare(self->handle)) >= 0) {
|
||||
if ((state != SND_PCM_STATE_SETUP) ||
|
||||
!(res = snd_pcm_prepare(self->handle))) {
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = snd_pcm_readi(self->handle, buffer, self->periodsize);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (res == -EPIPE) {
|
||||
// This means buffer overrun, which we need to report.
|
||||
// However, we recover the stream, so the next PCM.read() will work
|
||||
// again. If recovery fails (very unlikely), report that instead.
|
||||
if (!(res = snd_pcm_prepare(self->handle)))
|
||||
res = -EPIPE;
|
||||
}
|
||||
}
|
||||
|
||||
if (res != -EPIPE)
|
||||
|
||||
Reference in New Issue
Block a user