summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-08-06 06:52:18 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-08-06 06:52:18 +0000
commit7fcf71d8426de9e49252a4f7a6f602946c47c800 (patch)
tree5b8136f2513bef677583b1f4adc41bebc26e0478
parent22b8f0d08d76145b167f22083325c52b23c958cc (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.c40
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;
}
/*