summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-05-25 06:49:14 +0000
committerAlexandre Ratchov <ratchov@cvs.openbsd.org>2010-05-25 06:49:14 +0000
commitcaa98131b6201db6b03f510485fa9109b1082243 (patch)
tree5c07c60f7a85524327952c2947543a9af3de0b5a
parent8f446a15c6051ad1df8059a302e5337411cde0a6 (diff)
drop samples or insert silence in sun_revents(). Otherwise, in
full-duplex, we may detect a xrun in the play direction and discard the clock tick, this would cause sio_revents() to return POLLIN without the clock being advanced, causing apps relying on the clock for flow control to enter a busy loop.
-rw-r--r--lib/libsndio/sun.c72
1 files changed, 54 insertions, 18 deletions
diff --git a/lib/libsndio/sun.c b/lib/libsndio/sun.c
index d6c275dafdd..962a0d3063e 100644
--- a/lib/libsndio/sun.c
+++ b/lib/libsndio/sun.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sun.c,v 1.36 2010/05/09 18:24:24 jakemsr Exp $ */
+/* $OpenBSD: sun.c,v 1.37 2010/05/25 06:49:13 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -458,7 +458,7 @@ sun_start(struct sio_hdl *sh)
if (hdl->sio.mode & SIO_PLAY) {
/*
- * pause the device and let sun_write() trigger the
+ * keep the device paused and let sun_write() trigger the
* start later, to avoid buffer underruns
*/
hdl->filling = 1;
@@ -728,12 +728,14 @@ sun_getpar(struct sio_hdl *sh, struct sio_par *par)
return 1;
}
-static size_t
-sun_read(struct sio_hdl *sh, void *buf, size_t len)
+/*
+ * drop recorded samples to compensate xruns
+ */
+static int
+sun_rdrop(struct sun_hdl *hdl)
{
#define DROP_NMAX 0x1000
static char dropbuf[DROP_NMAX];
- struct sun_hdl *hdl = (struct sun_hdl *)sh;
ssize_t n, todo;
while (hdl->offset > 0) {
@@ -744,21 +746,30 @@ sun_read(struct sio_hdl *sh, void *buf, size_t len)
if (errno == EINTR)
continue;
if (errno != EAGAIN) {
- DPERROR("sun_read: read");
+ DPERROR("sun_rdrop: read");
hdl->sio.eof = 1;
}
return 0;
}
if (n == 0) {
- DPRINTF("sun_read: eof\n");
+ DPRINTF("sun_rdrop: eof\n");
hdl->sio.eof = 1;
return 0;
}
hdl->offset -= (int)n / (int)hdl->ibpf;
- DPRINTF("sun_read: dropped %ld/%ld bytes "
- "to resync\n", n, todo);
+ DPRINTF("sun_rdrop: dropped %ld/%ld bytes\n", n, todo);
}
+ return 1;
+}
+
+static size_t
+sun_read(struct sio_hdl *sh, void *buf, size_t len)
+{
+ struct sun_hdl *hdl = (struct sun_hdl *)sh;
+ ssize_t n;
+ if (!sun_rdrop(hdl))
+ return 0;
while ((n = read(hdl->fd, buf, len)) < 0) {
if (errno == EINTR)
continue;
@@ -808,13 +819,14 @@ sun_autostart(struct sun_hdl *hdl)
return 1;
}
-static size_t
-sun_write(struct sio_hdl *sh, const void *buf, size_t len)
+/*
+ * insert silence to play to compensate xruns
+ */
+static int
+sun_wsil(struct sun_hdl *hdl)
{
#define ZERO_NMAX 0x1000
static char zero[ZERO_NMAX];
- struct sun_hdl *hdl = (struct sun_hdl *)sh;
- const unsigned char *data = buf;
ssize_t n, todo;
while (hdl->offset < 0) {
@@ -825,17 +837,28 @@ sun_write(struct sio_hdl *sh, const void *buf, size_t len)
if (errno == EINTR)
continue;
if (errno != EAGAIN) {
- DPERROR("sun_write: sil");
+ DPERROR("sun_wsil: write");
hdl->sio.eof = 1;
return 0;
}
return 0;
}
hdl->offset += (int)n / (int)hdl->obpf;
- DPRINTF("sun_write: inserted %ld/%ld bytes "
- "of silence to resync\n", n, todo);
+ DPRINTF("sun_wsil: inserted %ld/%ld bytes\n", n, todo);
}
+ return 1;
+}
+
+
+static size_t
+sun_write(struct sio_hdl *sh, const void *buf, size_t len)
+{
+ struct sun_hdl *hdl = (struct sun_hdl *)sh;
+ const unsigned char *data = buf;
+ ssize_t n, todo;
+ if (!sun_wsil(hdl))
+ return 0;
todo = len;
while ((n = write(hdl->fd, data, todo)) < 0) {
if (errno == EINTR)
@@ -885,6 +908,7 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
}
if (hdl->sio.mode & SIO_REC) {
if (ioctl(hdl->fd, AUDIO_RERROR, &xrun) < 0) {
+ DPERROR("sun_revents: RERROR");
hdl->sio.eof = 1;
return POLLHUP;
}
@@ -924,7 +948,19 @@ sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
hdl->idelta = 0;
}
}
- if (hdl->filling)
- revents |= POLLOUT;
+
+ /*
+ * drop recorded samples or insert silence to play
+ * right now to adjust revents, and avoid busy loops
+ * programs
+ */
+ if (hdl->sio.started) {
+ if (hdl->filling)
+ revents |= POLLOUT;
+ if ((hdl->sio.mode & SIO_PLAY) && !sun_wsil(hdl))
+ revents &= ~POLLOUT;
+ if ((hdl->sio.mode & SIO_REC) && !sun_rdrop(hdl))
+ revents &= ~POLLIN;
+ }
return revents;
}