diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2014-03-05 20:40:50 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2014-03-05 20:40:50 +0000 |
commit | b44d0b8f3ec7db2b4ec2a73b639b3b990bdd7c94 (patch) | |
tree | 8755deebb0979f62f2f4bffa835577a478cd0413 /lib/libsndio | |
parent | a18588b445edf7039f38a835c60b47c33d0d623c (diff) |
- use relative read/write positions to keep track of buffer
usage as seen by the caller
- refresh current position before reading/writing data, to keep the
current position always consistent with read & write pointers
- fix confusion between processed samples by the hardware (as reported
by GET{I,O}OFFS) and samples played as reported by GETINFO(). Fixes
incorrect delta propagated after xruns in play-only and rec-only
modes
- don't wait for POLLIN or POLLOUT to be set to refresh ring pointers,
as they may not be set in certain cases. Fixes sndiod crash after
few days of continuous playback.
- save current parameters instead of calling getpar() too often
Diffstat (limited to 'lib/libsndio')
-rw-r--r-- | lib/libsndio/sio.c | 81 | ||||
-rw-r--r-- | lib/libsndio/sio_aucat.c | 14 | ||||
-rw-r--r-- | lib/libsndio/sio_priv.h | 10 | ||||
-rw-r--r-- | lib/libsndio/sio_sun.c | 27 |
4 files changed, 74 insertions, 58 deletions
diff --git a/lib/libsndio/sio.c b/lib/libsndio/sio.c index 184731e6ee1..74e858755b1 100644 --- a/lib/libsndio/sio.c +++ b/lib/libsndio/sio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sio.c,v 1.16 2013/12/20 08:51:28 ratchov Exp $ */ +/* $OpenBSD: sio.c,v 1.17 2014/03/05 20:40:49 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -111,10 +111,12 @@ sio_start(struct sio_hdl *hdl) hdl->eof = 1; return 0; } -#ifdef DEBUG + hdl->cpos = 0; + hdl->rused = hdl->wused = 0; if (!sio_getpar(hdl, &hdl->par)) return 0; - hdl->pollcnt = hdl->wcnt = hdl->rcnt = hdl->cpos = 0; +#ifdef DEBUG + hdl->pollcnt = 0; clock_gettime(CLOCK_MONOTONIC, &ts); hdl->start_nsec = 1000000000LL * ts.tv_sec + ts.tv_nsec; #endif @@ -140,8 +142,8 @@ sio_stop(struct sio_hdl *hdl) if (!hdl->ops->stop(hdl)) return 0; #ifdef DEBUG - DPRINTFN(2, "libsndio: polls: %llu, written = %llu, read: %llu\n", - hdl->pollcnt, hdl->wcnt, hdl->rcnt); + DPRINTFN(2, "libsndio: polls: %llu, samples = %llu\n", + hdl->pollcnt, hdl->cpos); #endif hdl->started = 0; return 1; @@ -287,7 +289,7 @@ sio_read(struct sio_hdl *hdl, void *buf, size_t len) { unsigned int n; char *data = buf; - size_t todo = len; + size_t todo = len, maxread; if (hdl->eof) { DPRINTF("sio_read: eof\n"); @@ -302,10 +304,13 @@ sio_read(struct sio_hdl *hdl, void *buf, size_t len) DPRINTF("sio_read: zero length read ignored\n"); return 0; } - if (!sio_rdrop(hdl)) - return 0; while (todo > 0) { - n = hdl->ops->read(hdl, data, todo); + if (!sio_rdrop(hdl)) + return 0; + maxread = hdl->rused; + if (maxread > todo) + maxread = todo; + n = maxread > 0 ? hdl->ops->read(hdl, data, maxread) : 0; if (n == 0) { if (hdl->nbio || hdl->eof || todo < len) break; @@ -315,9 +320,7 @@ sio_read(struct sio_hdl *hdl, void *buf, size_t len) } data += n; todo -= n; -#ifdef DEBUG - hdl->rcnt += n; -#endif + hdl->rused -= n; } return len - todo; } @@ -327,7 +330,7 @@ sio_write(struct sio_hdl *hdl, const void *buf, size_t len) { unsigned int n; const unsigned char *data = buf; - size_t todo = len; + size_t todo = len, maxwrite; if (hdl->eof) { DPRINTF("sio_write: eof\n"); @@ -342,10 +345,14 @@ sio_write(struct sio_hdl *hdl, const void *buf, size_t len) DPRINTF("sio_write: zero length write ignored\n"); return 0; } - if (!sio_wsil(hdl)) - return 0; while (todo > 0) { - n = hdl->ops->write(hdl, data, todo); + if (!sio_wsil(hdl)) + return 0; + maxwrite = hdl->par.bufsz * hdl->par.pchan * hdl->par.bps - + hdl->wused; + if (maxwrite > todo) + maxwrite = todo; + n = maxwrite > 0 ? hdl->ops->write(hdl, data, maxwrite) : 0; if (n == 0) { if (hdl->nbio || hdl->eof) break; @@ -355,9 +362,7 @@ sio_write(struct sio_hdl *hdl, const void *buf, size_t len) } data += n; todo -= n; -#ifdef DEBUG - hdl->wcnt += n; -#endif + hdl->wused += n; } return len - todo; } @@ -397,7 +402,7 @@ sio_revents(struct sio_hdl *hdl, struct pollfd *pfd) if (!hdl->started) return revents & POLLHUP; #ifdef DEBUG - if (_sndio_debug >= 3) { + if (_sndio_debug >= 4) { clock_gettime(CLOCK_MONOTONIC, &ts1); DPRINTF("%09lld: sio_revents: revents = 0x%x, took %lldns\n", 1000000000LL * ts0.tv_sec + @@ -440,13 +445,18 @@ _sio_printpos(struct sio_hdl *hdl) long long rpos, rdiff; long long cpos, cdiff; long long wpos, wdiff; + unsigned rbpf, wbpf, rround, wround; clock_gettime(CLOCK_MONOTONIC, &ts); + rbpf = (hdl->mode & SIO_REC) ? hdl->par.bps * hdl->par.rchan : 1; + wbpf = (hdl->mode & SIO_PLAY) ? hdl->par.bps * hdl->par.pchan : 1; + rround = hdl->par.round * rbpf; + wround = hdl->par.round * wbpf; rpos = (hdl->mode & SIO_REC) ? - hdl->rcnt / (hdl->par.bps * hdl->par.rchan) : 0; + hdl->cpos * rbpf - hdl->rused : 0; wpos = (hdl->mode & SIO_PLAY) ? - hdl->wcnt / (hdl->par.bps * hdl->par.pchan) : 0; + hdl->cpos * wbpf + hdl->wused : 0; cdiff = hdl->cpos % hdl->par.round; cpos = hdl->cpos / hdl->par.round; @@ -454,17 +464,17 @@ _sio_printpos(struct sio_hdl *hdl) cpos++; cdiff = cdiff - hdl->par.round; } - rdiff = rpos % hdl->par.round; - rpos = rpos / hdl->par.round; - if (rdiff > hdl->par.round / 2) { + rdiff = rpos % rround; + rpos = rpos / rround; + if (rdiff > rround / 2) { rpos++; - rdiff = rdiff - hdl->par.round; + rdiff = rdiff - rround; } - wdiff = wpos % hdl->par.round; - wpos = wpos / hdl->par.round; - if (wdiff > hdl->par.round / 2) { + wdiff = wpos % wround; + wpos = wpos / wround; + if (wdiff > wround / 2) { wpos++; - wdiff = wdiff - hdl->par.round; + wdiff = wdiff - wround; } DPRINTF("%011lld: " "clk %+5lld%+5lld, wr %+5lld%+5lld rd: %+5lld%+5lld\n", @@ -476,10 +486,19 @@ _sio_printpos(struct sio_hdl *hdl) void _sio_onmove_cb(struct sio_hdl *hdl, int delta) { -#ifdef DEBUG hdl->cpos += delta; + if (hdl->mode & SIO_REC) + hdl->rused += delta * (hdl->par.bps * hdl->par.rchan); + if (hdl->mode & SIO_PLAY) + hdl->wused -= delta * (hdl->par.bps * hdl->par.pchan); +#ifdef DEBUG if (_sndio_debug >= 3) _sio_printpos(hdl); + if ((hdl->mode & SIO_PLAY) && hdl->wused < 0) { + DPRINTFN(1, "sndio: h/w failure: negative buffer usage\n"); + hdl->eof = 1; + return; + } #endif if (hdl->move_cb) hdl->move_cb(hdl->move_addr, delta); diff --git a/lib/libsndio/sio_aucat.c b/lib/libsndio/sio_aucat.c index e1cdab28f2c..3e0e23d3f69 100644 --- a/lib/libsndio/sio_aucat.c +++ b/lib/libsndio/sio_aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sio_aucat.c,v 1.16 2013/12/20 08:51:28 ratchov Exp $ */ +/* $OpenBSD: sio_aucat.c,v 1.17 2014/03/05 20:40:49 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -180,17 +180,11 @@ static int sio_aucat_start(struct sio_hdl *sh) { struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh; - struct sio_par par; - /* - * save bpf - */ - if (!sio_getpar(&hdl->sio, &par)) - return 0; - hdl->wbpf = par.bps * par.pchan; - hdl->rbpf = par.bps * par.rchan; + hdl->wbpf = hdl->sio.par.bps * hdl->sio.par.pchan; + hdl->rbpf = hdl->sio.par.bps * hdl->sio.par.rchan; hdl->aucat.maxwrite = 0; - hdl->round = par.round; + hdl->round = hdl->sio.par.round; hdl->delta = 0; DPRINTFN(2, "aucat: start, maxwrite = %d\n", hdl->aucat.maxwrite); diff --git a/lib/libsndio/sio_priv.h b/lib/libsndio/sio_priv.h index 40ff7089780..b74647fa683 100644 --- a/lib/libsndio/sio_priv.h +++ b/lib/libsndio/sio_priv.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sio_priv.h,v 1.7 2013/11/13 22:38:22 ratchov Exp $ */ +/* $OpenBSD: sio_priv.h,v 1.8 2014/03/05 20:40:49 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -37,13 +37,13 @@ struct sio_hdl { int eof; /* true if error occured */ int rdrop; /* recorded bytes to drop */ int wsil; /* silence to play */ + int rused; /* bytes used in read buffer */ + int wused; /* bytes used in write buffer */ + long long cpos; /* clock since start */ + struct sio_par par; #ifdef DEBUG unsigned long long pollcnt; /* times sio_revents was called */ - long long wcnt; /* bytes written with sio_write() */ - long long rcnt; /* bytes read with sio_read() */ - long long cpos; long long start_nsec; - struct sio_par par; #endif }; diff --git a/lib/libsndio/sio_sun.c b/lib/libsndio/sio_sun.c index 023ff4b1b5a..948302eaa96 100644 --- a/lib/libsndio/sio_sun.c +++ b/lib/libsndio/sio_sun.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sio_sun.c,v 1.10 2013/12/20 08:51:28 ratchov Exp $ */ +/* $OpenBSD: sio_sun.c,v 1.11 2014/03/05 20:40:49 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -436,14 +436,11 @@ sio_sun_close(struct sio_hdl *sh) static int sio_sun_start(struct sio_hdl *sh) { - struct sio_par par; struct sio_sun_hdl *hdl = (struct sio_sun_hdl *)sh; struct audio_info aui; - if (!sio_getpar(&hdl->sio, &par)) - return 0; - hdl->obpf = par.pchan * par.bps; - hdl->ibpf = par.rchan * par.bps; + hdl->obpf = hdl->sio.par.pchan * hdl->sio.par.bps; + hdl->ibpf = hdl->sio.par.rchan * hdl->sio.par.bps; hdl->ibytes = 0; hdl->obytes = 0; hdl->ierr = 0; @@ -828,7 +825,7 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd) if (!hdl->sio.started) return pfd->revents; - if ((revents & POLLOUT) && (hdl->sio.mode & SIO_PLAY)) { + if (hdl->sio.mode & SIO_PLAY) { if (ioctl(hdl->fd, AUDIO_GETOOFFS, &ao) < 0) { DPERROR("sio_sun_revents: GETOOFFS"); hdl->sio.eof = 1; @@ -840,7 +837,7 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd) if (!(hdl->sio.mode & SIO_REC)) hdl->idelta += delta; } - if ((revents & POLLIN) && (hdl->sio.mode & SIO_REC)) { + if (hdl->sio.mode & SIO_REC) { if (ioctl(hdl->fd, AUDIO_GETIOFFS, &ao) < 0) { DPERROR("sio_sun_revents: GETIOFFS"); hdl->sio.eof = 1; @@ -878,16 +875,22 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd) if (dierr > 0) DPRINTFN(2, "rec xrun %d\n", dierr); } + + /* + * GET{I,O}OFFS report positions including xruns, + * so we have to substract to get the real position + */ + hdl->idelta -= dierr; + hdl->odelta -= doerr; + offset = doerr - dierr; if (offset > 0) { hdl->sio.rdrop += offset * hdl->ibpf; - hdl->idelta -= doerr; - hdl->odelta -= doerr; + hdl->idelta -= offset; DPRINTFN(2, "will drop %d and pause %d\n", offset, doerr); } else if (offset < 0) { hdl->sio.wsil += -offset * hdl->obpf; - hdl->idelta -= dierr; - hdl->odelta -= dierr; + hdl->odelta -= offset; DPRINTFN(2, "will insert %d and pause %d\n", -offset, dierr); } |