diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2010-08-06 06:52:18 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2010-08-06 06:52:18 +0000 |
commit | 7fcf71d8426de9e49252a4f7a6f602946c47c800 (patch) | |
tree | 5b8136f2513bef677583b1f4adc41bebc26e0478 | |
parent | 22b8f0d08d76145b167f22083325c52b23c958cc (diff) |
If audio interrupts are missed (as this happens on some MP systems
now), play and record directons may be out of sync, and since the play
direction is used as clock source, we may end up with data ariving
_before_ the time it was recorded. This breaks the sndio ``device
model'' and most full-duplex apps relying on it, starting with aucat
in its default mode.
Workaround this by using the direction that's ahead as clock source,
ensuring that recorded data never arrives before the clock tick it was
recorded. This prevents apps from crashing but won't fix stuttering
caused by missed interrupts.
ok deraadt@
-rw-r--r-- | lib/libsndio/sun.c | 40 |
1 files changed, 22 insertions, 18 deletions
diff --git a/lib/libsndio/sun.c b/lib/libsndio/sun.c index 914fd5d1d01..946e493a4cc 100644 --- a/lib/libsndio/sun.c +++ b/lib/libsndio/sun.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sun.c,v 1.39 2010/07/21 23:00:16 ratchov Exp $ */ +/* $OpenBSD: sun.c,v 1.40 2010/08/06 06:52:17 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -891,7 +891,7 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd) { struct sun_hdl *hdl = (struct sun_hdl *)sh; struct audio_offset ao; - int xrun, dmove, dierr = 0, doerr = 0, doffset = 0; + int xrun, dmove, dierr = 0, doerr = 0, delta; int revents = pfd->revents; if (hdl->sio.mode & SIO_PLAY) { @@ -902,8 +902,8 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd) } doerr = xrun - hdl->oerr; hdl->oerr = xrun; - if (hdl->sio.mode & SIO_REC) - doffset += doerr; + if (!(hdl->sio.mode & SIO_REC)) + dierr = doerr; } if (hdl->sio.mode & SIO_REC) { if (ioctl(hdl->fd, AUDIO_RERROR, &xrun) < 0) { @@ -913,10 +913,10 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd) } dierr = xrun - hdl->ierr; hdl->ierr = xrun; - if (hdl->sio.mode & SIO_PLAY) - doffset -= dierr; + if (!(hdl->sio.mode & SIO_PLAY)) + doerr = dierr; } - hdl->offset += doffset; + hdl->offset += doerr - dierr; dmove = dierr > doerr ? dierr : doerr; hdl->idelta -= dmove; hdl->odelta -= dmove; @@ -927,25 +927,29 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd) hdl->sio.eof = 1; return POLLHUP; } - hdl->odelta += (ao.samples - hdl->obytes) / hdl->obpf; + delta = (ao.samples - hdl->obytes) / hdl->obpf; hdl->obytes = ao.samples; - if (hdl->odelta > 0) { - sio_onmove_cb(&hdl->sio, hdl->odelta); - hdl->odelta = 0; - } + hdl->odelta += delta; + if (!(hdl->sio.mode & SIO_REC)) + hdl->idelta += delta; } - if ((revents & POLLIN) && !(hdl->sio.mode & SIO_PLAY)) { + if ((revents & POLLIN) && (hdl->sio.mode & SIO_REC)) { if (ioctl(hdl->fd, AUDIO_GETIOFFS, &ao) < 0) { DPERROR("sun_revents: GETIOFFS"); hdl->sio.eof = 1; return POLLHUP; } - hdl->idelta += (ao.samples - hdl->ibytes) / hdl->ibpf; + delta = (ao.samples - hdl->ibytes) / hdl->ibpf; hdl->ibytes = ao.samples; - if (hdl->idelta > 0) { - sio_onmove_cb(&hdl->sio, hdl->idelta); - hdl->idelta = 0; - } + hdl->idelta += delta; + if (!(hdl->sio.mode & SIO_PLAY)) + hdl->odelta += delta; + } + delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta; + if (delta > 0) { + sio_onmove_cb(&hdl->sio, delta); + hdl->idelta -= delta; + hdl->odelta -= delta; } /* |