From 0dc33e9bc0be8a056e958a4f778ebd00ae2355a6 Mon Sep 17 00:00:00 2001 From: ratchov Date: Fri, 6 Aug 2010 06:52:17 +0000 Subject: [PATCH] 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@ --- lib/libsndio/sun.c | 40 ++++++++++++++++++++++------------------ 1 file 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 * @@ -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; } /* -- 2.20.1