diff options
Diffstat (limited to 'usr.bin/aucat/aproc.c')
-rw-r--r-- | usr.bin/aucat/aproc.c | 729 |
1 files changed, 572 insertions, 157 deletions
diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c index 318326bbb42..b1001f2ab65 100644 --- a/usr.bin/aucat/aproc.c +++ b/usr.bin/aucat/aproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.c,v 1.50 2010/04/03 17:59:17 ratchov Exp $ */ +/* $OpenBSD: aproc.c,v 1.51 2010/04/06 20:07:01 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -48,6 +48,18 @@ #include "dbg.h" #endif +/* + * Same as ABUF_ROK(), but consider that a buffer is + * readable if there's silence pending to be inserted + */ +#define MIX_ROK(buf) (ABUF_ROK(buf) || (buf)->r.mix.drop < 0) + +/* + * Same as ABUF_WOK(), but consider that a buffer is + * writeable if there are samples to drop + */ +#define SUB_WOK(buf) (ABUF_WOK(buf) || (buf)->w.sub.silence < 0) + #ifdef DEBUG void aproc_dbg(struct aproc *p) @@ -275,20 +287,40 @@ aproc_depend(struct aproc *p, struct aproc *dep) } int -rfile_in(struct aproc *p, struct abuf *ibuf_dummy) +rfile_do(struct aproc *p, unsigned todo, unsigned *done) { struct abuf *obuf = LIST_FIRST(&p->obuflist); struct file *f = p->u.io.file; unsigned char *data; - unsigned count; + unsigned n, count, off; - if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) - return 0; + off = p->u.io.partial; data = abuf_wgetblk(obuf, &count, 0); - count = file_read(f, data, count); - if (count == 0) + if (count > todo) + count = todo; + n = file_read(f, data + off, count * obuf->bpf - off); + if (n == 0) + return 0; + n += off; + p->u.io.partial = n % obuf->bpf; + count = n / obuf->bpf; + if (count > 0) + abuf_wcommit(obuf, count); + if (done) + *done = count; + return 1; +} + +int +rfile_in(struct aproc *p, struct abuf *ibuf_dummy) +{ + struct abuf *obuf = LIST_FIRST(&p->obuflist); + struct file *f = p->u.io.file; + + if (!ABUF_WOK(obuf) || !(f->state & FILE_ROK)) + return 0; + if (!rfile_do(p, obuf->len, NULL)) return 0; - abuf_wcommit(obuf, count); if (!abuf_flush(obuf)) return 0; return 1; @@ -298,18 +330,13 @@ int rfile_out(struct aproc *p, struct abuf *obuf) { struct file *f = p->u.io.file; - unsigned char *data; - unsigned count; if (f->state & FILE_RINUSE) return 0; - if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) + if (!ABUF_WOK(obuf) || !(f->state & FILE_ROK)) return 0; - data = abuf_wgetblk(obuf, &count, 0); - count = file_read(f, data, count); - if (count == 0) + if (!rfile_do(p, obuf->len, NULL)) return 0; - abuf_wcommit(obuf, count); return 1; } @@ -322,6 +349,12 @@ rfile_done(struct aproc *p) if (f == NULL) return; /* + * disconnect from file structure + */ + f->rproc = NULL; + p->u.io.file = NULL; + + /* * all buffers must be detached before deleting f->wproc, * because otherwise it could trigger this code again */ @@ -329,11 +362,18 @@ rfile_done(struct aproc *p) if (obuf) abuf_eof(obuf); if (f->wproc) { - f->rproc = NULL; aproc_del(f->wproc); } else file_del(f); - p->u.io.file = NULL; + +#ifdef DEBUG + if (debug_level >= 2 && p->u.io.partial > 0) { + aproc_dbg(p); + dbg_puts(": "); + dbg_putu(p->u.io.partial); + dbg_puts(" bytes lost in partial read\n"); + } +#endif } void @@ -368,6 +408,7 @@ rfile_new(struct file *f) p = aproc_new(&rfile_ops, f->name); p->u.io.file = f; + p->u.io.partial = 0; f->rproc = p; return p; } @@ -381,6 +422,12 @@ wfile_done(struct aproc *p) if (f == NULL) return; /* + * disconnect from file structure + */ + f->wproc = NULL; + p->u.io.file = NULL; + + /* * all buffers must be detached before deleting f->rproc, * because otherwise it could trigger this code again */ @@ -388,29 +435,54 @@ wfile_done(struct aproc *p) if (ibuf) abuf_hup(ibuf); if (f->rproc) { - f->wproc = NULL; aproc_del(f->rproc); } else file_del(f); - p->u.io.file = NULL; +#ifdef DEBUG + if (debug_level >= 2 && p->u.io.partial > 0) { + aproc_dbg(p); + dbg_puts(": "); + dbg_putu(p->u.io.partial); + dbg_puts(" bytes lost in partial write\n"); + } +#endif } int -wfile_in(struct aproc *p, struct abuf *ibuf) +wfile_do(struct aproc *p, unsigned todo, unsigned *done) { + struct abuf *ibuf = LIST_FIRST(&p->ibuflist); struct file *f = p->u.io.file; unsigned char *data; - unsigned count; + unsigned n, count, off; + + off = p->u.io.partial; + data = abuf_rgetblk(ibuf, &count, 0); + if (count > todo) + count = todo; + n = file_write(f, data + off, count * ibuf->bpf - off); + if (n == 0) + return 0; + n += off; + p->u.io.partial = n % ibuf->bpf; + count = n / ibuf->bpf; + if (count > 0) + abuf_rdiscard(ibuf, count); + if (done) + *done = count; + return 1; +} +int +wfile_in(struct aproc *p, struct abuf *ibuf) +{ + struct file *f = p->u.io.file; if (f->state & FILE_WINUSE) return 0; - if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) + if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK)) return 0; - data = abuf_rgetblk(ibuf, &count, 0); - count = file_write(f, data, count); - if (count == 0) + if (!wfile_do(p, ibuf->len, NULL)) return 0; - abuf_rdiscard(ibuf, count); return 1; } @@ -419,22 +491,13 @@ wfile_out(struct aproc *p, struct abuf *obuf_dummy) { struct abuf *ibuf = LIST_FIRST(&p->ibuflist); struct file *f = p->u.io.file; - unsigned char *data; - unsigned count; if (!abuf_fill(ibuf)) return 0; - if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) - return 0; - data = abuf_rgetblk(ibuf, &count, 0); - if (count == 0) { - /* XXX: this can't happen, right ? */ + if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK)) return 0; - } - count = file_write(f, data, count); - if (count == 0) + if (!wfile_do(p, ibuf->len, NULL)) return 0; - abuf_rdiscard(ibuf, count); return 1; } @@ -470,45 +533,83 @@ wfile_new(struct file *f) p = aproc_new(&wfile_ops, f->name); p->u.io.file = f; + p->u.io.partial = 0; f->wproc = p; return p; } /* + * Drop as much as possible samples from the reader end, + * negative values mean ``insert silence''. + */ +void +mix_drop(struct abuf *buf, int extra) +{ + unsigned count; + + buf->r.mix.drop += extra; + while (buf->r.mix.drop > 0) { + count = buf->r.mix.drop; + if (count > buf->used) + count = buf->used; + if (count == 0) { +#ifdef DEBUG + if (debug_level >= 4) { + abuf_dbg(buf); + dbg_puts(": drop: no data\n"); + } +#endif + return; + } + abuf_rdiscard(buf, count); + buf->r.mix.drop -= count; +#ifdef DEBUG + if (debug_level >= 4) { + abuf_dbg(buf); + dbg_puts(": dropped "); + dbg_putu(count); + dbg_puts(", to drop = "); + dbg_putu(buf->r.mix.drop); + dbg_puts("\n"); + } +#endif + } +} + +/* * Append the given amount of silence (or less if there's not enough - * space), and crank mixitodo accordingly. + * space), and crank w.mix.todo accordingly. */ void -mix_bzero(struct abuf *obuf, unsigned zcount) +mix_bzero(struct abuf *obuf) { short *odata; unsigned ocount; + odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.todo); + if (ocount == 0) + return; + memset(odata, 0, ocount * obuf->bpf); + obuf->w.mix.todo += ocount; #ifdef DEBUG if (debug_level >= 4) { abuf_dbg(obuf); dbg_puts(": bzero("); - dbg_putu(zcount); + dbg_putu(obuf->w.mix.todo); dbg_puts(")\n"); } #endif - odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.todo); - ocount -= ocount % obuf->bpf; - if (ocount > zcount) - ocount = zcount; - memset(odata, 0, ocount); - obuf->w.mix.todo += ocount; } /* * Mix an input block over an output block. */ -void +unsigned mix_badd(struct abuf *ibuf, struct abuf *obuf) { short *idata, *odata; unsigned i, j, icnt, onext, ostart; - unsigned scount, icount, ocount, zcount; + unsigned scount, icount, ocount; int vol; #ifdef DEBUG @@ -518,31 +619,37 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf) dbg_putu(ibuf->r.mix.done); dbg_puts("/"); dbg_putu(obuf->w.mix.todo); + dbg_puts(", drop = "); + dbg_puti(ibuf->r.mix.drop); dbg_puts("\n"); } #endif /* - * Calculate the maximum we can read. + * Insert silence for xrun correction */ - idata = (short *)abuf_rgetblk(ibuf, &icount, 0); - icount /= ibuf->bpf; - if (icount == 0) - return; + if (ibuf->r.mix.drop < 0) { + icount = -ibuf->r.mix.drop; + ocount = obuf->len - obuf->used; + if (ocount > obuf->w.mix.todo) + ocount = obuf->w.mix.todo; + scount = (icount < ocount) ? icount : ocount; + ibuf->r.mix.done += scount; + ibuf->r.mix.drop += scount; + } /* - * Zero-fill if necessary. + * Calculate the maximum we can read. */ - zcount = ibuf->r.mix.done + icount * obuf->bpf; - if (zcount > obuf->w.mix.todo) - mix_bzero(obuf, zcount - obuf->w.mix.todo); + idata = (short *)abuf_rgetblk(ibuf, &icount, 0); + if (icount == 0) + return 0; /* * Calculate the maximum we can write. */ odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->r.mix.done); - ocount /= obuf->bpf; if (ocount == 0) - return; + return 0; vol = (ibuf->r.mix.weight * ibuf->r.mix.vol) >> ADATA_SHIFT; ostart = ibuf->cmin - obuf->cmin; @@ -558,30 +665,30 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf) } odata += onext; } - abuf_rdiscard(ibuf, scount * ibuf->bpf); - ibuf->r.mix.done += scount * obuf->bpf; + abuf_rdiscard(ibuf, scount); + ibuf->r.mix.done += scount; #ifdef DEBUG if (debug_level >= 4) { abuf_dbg(ibuf); dbg_puts(": badd: done = "); - dbg_putu(scount); - dbg_puts(", todo = "); dbg_putu(ibuf->r.mix.done); dbg_puts("/"); dbg_putu(obuf->w.mix.todo); dbg_puts("\n"); } #endif + return scount; } /* * Handle buffer underrun, return 0 if stream died. */ int -mix_xrun(struct abuf *i, struct abuf *obuf) +mix_xrun(struct aproc *p, struct abuf *i) { - unsigned fdrop; + struct abuf *obuf = LIST_FIRST(&p->obuflist); + unsigned fdrop, remain; if (i->r.mix.done > 0) return 1; @@ -589,22 +696,34 @@ mix_xrun(struct abuf *i, struct abuf *obuf) abuf_hup(i); return 0; } - mix_bzero(obuf, obuf->len); - fdrop = obuf->w.mix.todo / obuf->bpf; + fdrop = obuf->w.mix.todo; #ifdef DEBUG if (debug_level >= 3) { abuf_dbg(i); dbg_puts(": underrun, dropping "); dbg_putu(fdrop); dbg_puts(" + "); - dbg_putu(i->drop / i->bpf); + dbg_putu(i->r.mix.drop); dbg_puts("\n"); } #endif - i->r.mix.done += fdrop * obuf->bpf; + i->r.mix.done += fdrop; if (i->r.mix.xrun == XRUN_SYNC) - i->drop += fdrop * i->bpf; + mix_drop(i, fdrop); else { + remain = fdrop % p->u.mix.round; + if (remain) + remain = p->u.mix.round - remain; + mix_drop(i, -(int)remain); + fdrop += remain; +#ifdef DEBUG + if (debug_level >= 3) { + abuf_dbg(i); + dbg_puts(": underrun, adding "); + dbg_putu(remain); + dbg_puts("\n"); + } +#endif abuf_opos(i, -(int)fdrop); if (i->duplex) { #ifdef DEBUG @@ -613,7 +732,7 @@ mix_xrun(struct abuf *i, struct abuf *obuf) dbg_puts(": full-duplex resync\n"); } #endif - i->duplex->drop += fdrop * i->duplex->bpf; + sub_silence(i->duplex, -(int)fdrop); abuf_ipos(i->duplex, -(int)fdrop); } } @@ -625,6 +744,8 @@ mix_in(struct aproc *p, struct abuf *ibuf) { struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist); unsigned odone; + unsigned maxwrite; + unsigned scount; #ifdef DEBUG if (debug_level >= 4) { @@ -640,27 +761,50 @@ mix_in(struct aproc *p, struct abuf *ibuf) dbg_puts("\n"); } #endif - if (!ABUF_ROK(ibuf)) + if (!MIX_ROK(ibuf)) return 0; - odone = obuf->len; + mix_bzero(obuf); + scount = 0; + odone = obuf->w.mix.todo; for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) { inext = LIST_NEXT(i, ient); - if (!abuf_fill(i)) + if (i->r.mix.drop >= 0 && !abuf_fill(i)) continue; /* eof */ - mix_badd(i, obuf); + mix_drop(i, 0); + scount += mix_badd(i, obuf); if (odone > i->r.mix.done) odone = i->r.mix.done; } - if (LIST_EMPTY(&p->ibuflist) || odone == 0) + if (LIST_EMPTY(&p->ibuflist) || scount == 0) return 0; - p->u.mix.lat += odone / obuf->bpf; - LIST_FOREACH(i, &p->ibuflist, ient) { - i->r.mix.done -= odone; +#ifdef DEBUG + if (debug_level >= 4) { + aproc_dbg(p); + dbg_puts(": maxwrite = "); + dbg_putu(p->u.mix.maxlat); + dbg_puts(" - "); + dbg_putu(p->u.mix.lat); + dbg_puts(" = "); + dbg_putu(p->u.mix.maxlat - p->u.mix.lat); + dbg_puts("\n"); + } +#endif + maxwrite = p->u.mix.maxlat - p->u.mix.lat; + if (maxwrite > 0) { + if (odone > maxwrite) + odone = maxwrite; + p->u.mix.lat += odone; + p->u.mix.abspos += odone; + LIST_FOREACH(i, &p->ibuflist, ient) { + i->r.mix.done -= odone; + } + abuf_wcommit(obuf, odone); + obuf->w.mix.todo -= odone; + if (APROC_OK(p->u.mix.mon)) + mon_snoop(p->u.mix.mon, obuf, obuf->used - odone, odone); + if (!abuf_flush(obuf)) + return 0; /* hup */ } - abuf_wcommit(obuf, odone); - obuf->w.mix.todo -= odone; - if (!abuf_flush(obuf)) - return 0; /* hup */ return 1; } @@ -669,6 +813,8 @@ mix_out(struct aproc *p, struct abuf *obuf) { struct abuf *i, *inext; unsigned odone; + unsigned maxwrite; + unsigned scount; #ifdef DEBUG if (debug_level >= 4) { @@ -686,18 +832,34 @@ mix_out(struct aproc *p, struct abuf *obuf) #endif if (!ABUF_WOK(obuf)) return 0; +#ifdef DEBUG + if (debug_level >= 4) { + aproc_dbg(p); + dbg_puts(": maxwrite = "); + dbg_putu(p->u.mix.maxlat); + dbg_puts(" - "); + dbg_putu(p->u.mix.lat); + dbg_puts(" = "); + dbg_putu(p->u.mix.maxlat - p->u.mix.lat); + dbg_puts("\n"); + } +#endif + maxwrite = p->u.mix.maxlat - p->u.mix.lat; + mix_bzero(obuf); + scount = 0; odone = obuf->len; for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) { inext = LIST_NEXT(i, ient); - if (!abuf_fill(i)) + if (i->r.mix.drop >= 0 && !abuf_fill(i)) continue; /* eof */ - if (!ABUF_ROK(i)) { + mix_drop(i, 0); + if (maxwrite > 0 && !MIX_ROK(i)) { if (p->flags & APROC_DROP) { - if (!mix_xrun(i, obuf)) + if (!mix_xrun(p, i)) continue; } } else - mix_badd(i, obuf); + scount += mix_badd(i, obuf); if (odone > i->r.mix.done) odone = i->r.mix.done; } @@ -708,25 +870,31 @@ mix_out(struct aproc *p, struct abuf *obuf) } if (!(p->flags & APROC_DROP)) return 0; - mix_bzero(obuf, obuf->len); odone = obuf->w.mix.todo; - p->u.mix.idle += odone / obuf->bpf; + p->u.mix.idle += odone; } - if (odone == 0) - return 0; - p->u.mix.lat += odone / obuf->bpf; - LIST_FOREACH(i, &p->ibuflist, ient) { - i->r.mix.done -= odone; + if (maxwrite > 0) { + if (odone > maxwrite) + odone = maxwrite; + p->u.mix.lat += odone; + p->u.mix.abspos += odone; + LIST_FOREACH(i, &p->ibuflist, ient) { + i->r.mix.done -= odone; + } + abuf_wcommit(obuf, odone); + obuf->w.mix.todo -= odone; + if (APROC_OK(p->u.mix.mon)) + mon_snoop(p->u.mix.mon, obuf, obuf->used - odone, odone); } - abuf_wcommit(obuf, odone); - obuf->w.mix.todo -= odone; + if (scount == 0) + return 0; return 1; } void mix_eof(struct aproc *p, struct abuf *ibuf) { - struct abuf *i, *obuf = LIST_FIRST(&p->obuflist); + struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist); unsigned odone; mix_setmaster(p); @@ -742,8 +910,11 @@ mix_eof(struct aproc *p, struct abuf *ibuf) * Find a blocked input. */ odone = obuf->len; - LIST_FOREACH(i, &p->ibuflist, ient) { - if (ABUF_ROK(i) && i->r.mix.done < obuf->w.mix.todo) { + for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) { + inext = LIST_NEXT(i, ient); + if (!abuf_fill(i)) + continue; + if (MIX_ROK(i) && i->r.mix.done < obuf->w.mix.todo) { abuf_run(i); return; } @@ -781,6 +952,7 @@ mix_newin(struct aproc *p, struct abuf *ibuf) ibuf->r.mix.weight = ADATA_UNIT; ibuf->r.mix.maxweight = ADATA_UNIT; ibuf->r.mix.xrun = XRUN_IGNORE; + ibuf->r.mix.drop = 0; } void @@ -790,8 +962,8 @@ mix_newout(struct aproc *p, struct abuf *obuf) if (debug_level >= 3) { aproc_dbg(p); dbg_puts(": newin, will use "); - dbg_putu(obuf->len / obuf->bpf); - dbg_puts(" fr\n"); + dbg_putu(obuf->len); + dbg_puts("\n"); } #endif obuf->w.mix.todo = 0; @@ -800,6 +972,7 @@ mix_newout(struct aproc *p, struct abuf *obuf) void mix_opos(struct aproc *p, struct abuf *obuf, int delta) { + p->u.mix.lat -= delta; #ifdef DEBUG if (debug_level >= 4) { aproc_dbg(p); @@ -807,13 +980,14 @@ mix_opos(struct aproc *p, struct abuf *obuf, int delta) dbg_puti(p->u.mix.lat); dbg_puts("/"); dbg_puti(p->u.mix.maxlat); - dbg_puts(" fr\n"); + dbg_puts("\n"); } #endif - p->u.mix.lat -= delta; - if (p->u.mix.ctl) + if (APROC_OK(p->u.mix.ctl)) ctl_ontick(p->u.mix.ctl, delta); aproc_opos(p, obuf, delta); + if (APROC_OK(p->u.mix.mon)) + p->u.mix.mon->ops->ipos(p->u.mix.mon, NULL, delta); } struct aproc_ops mix_ops = { @@ -830,14 +1004,16 @@ struct aproc_ops mix_ops = { }; struct aproc * -mix_new(char *name, int maxlat, struct aproc *ctl) +mix_new(char *name, int maxlat, unsigned round, struct aproc *ctl) { struct aproc *p; p = aproc_new(&mix_ops, name); p->u.mix.idle = 0; p->u.mix.lat = 0; + p->u.mix.round = round; p->u.mix.maxlat = maxlat; + p->u.mix.abspos = 0; p->u.mix.ctl = ctl; return p; } @@ -895,6 +1071,7 @@ mix_clear(struct aproc *p) struct abuf *obuf = LIST_FIRST(&p->obuflist); p->u.mix.lat = 0; + p->u.mix.abspos = 0; obuf->w.mix.todo = 0; } @@ -907,16 +1084,19 @@ mix_prime(struct aproc *p) for (;;) { if (!ABUF_WOK(obuf)) break; - todo = (p->u.mix.maxlat - p->u.mix.lat) * obuf->bpf; + todo = p->u.mix.maxlat - p->u.mix.lat; if (todo == 0) break; - mix_bzero(obuf, obuf->len); + mix_bzero(obuf); count = obuf->w.mix.todo; if (count > todo) count = todo; obuf->w.mix.todo -= count; - p->u.mix.lat += count / obuf->bpf; + p->u.mix.lat += count; + p->u.mix.abspos += count; abuf_wcommit(obuf, count); + if (APROC_OK(p->u.mix.mon)) + mon_snoop(p->u.mix.mon, obuf, 0, count); abuf_flush(obuf); } #ifdef DEBUG @@ -932,6 +1112,45 @@ mix_prime(struct aproc *p) } /* + * Append as much as possible silence on the writer end + */ +void +sub_silence(struct abuf *buf, int extra) +{ + unsigned char *data; + unsigned count; + + buf->w.sub.silence += extra; + if (buf->w.sub.silence > 0) { + data = abuf_wgetblk(buf, &count, 0); + if (count >= buf->w.sub.silence) + count = buf->w.sub.silence; + if (count == 0) { +#ifdef DEBUG + if (debug_level >= 4) { + abuf_dbg(buf); + dbg_puts(": no space for silence\n"); + } +#endif + return; + } + memset(data, 0, count * buf->bpf); + abuf_wcommit(buf, count); + buf->w.sub.silence -= count; +#ifdef DEBUG + if (debug_level >= 4) { + abuf_dbg(buf); + dbg_puts(": appended "); + dbg_putu(count); + dbg_puts(", remaining silence = "); + dbg_putu(buf->w.sub.silence); + dbg_puts("\n"); + } +#endif + } +} + +/* * Copy data from ibuf to obuf. */ void @@ -941,12 +1160,21 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf) unsigned i, j, ocnt, inext, istart; unsigned icount, ocount, scount; + /* + * Drop samples for xrun correction + */ + if (obuf->w.sub.silence < 0) { + scount = -obuf->w.sub.silence; + if (scount > ibuf->used) + scount = ibuf->used; + obuf->w.sub.done += scount; + obuf->w.sub.silence += scount; + } + idata = (short *)abuf_rgetblk(ibuf, &icount, obuf->w.sub.done); - icount /= ibuf->bpf; if (icount == 0) return; odata = (short *)abuf_wgetblk(obuf, &ocount, 0); - ocount /= obuf->bpf; if (ocount == 0) return; istart = obuf->cmin - ibuf->cmin; @@ -962,14 +1190,14 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf) } idata += inext; } - abuf_wcommit(obuf, scount * obuf->bpf); - obuf->w.sub.done += scount * ibuf->bpf; + abuf_wcommit(obuf, scount); + obuf->w.sub.done += scount; #ifdef DEBUG if (debug_level >= 4) { abuf_dbg(obuf); dbg_puts(": bcopy "); dbg_putu(scount); - dbg_puts(" fr\n"); + dbg_puts("\n"); } #endif } @@ -978,9 +1206,10 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf) * Handle buffer overruns. Return 0 if the stream died. */ int -sub_xrun(struct abuf *ibuf, struct abuf *i) +sub_xrun(struct aproc *p, struct abuf *i) { - unsigned fdrop; + struct abuf *ibuf = LIST_FIRST(&p->ibuflist); + unsigned fdrop, remain; if (i->w.sub.done > 0) return 1; @@ -988,20 +1217,35 @@ sub_xrun(struct abuf *ibuf, struct abuf *i) abuf_eof(i); return 0; } - fdrop = ibuf->used / ibuf->bpf; + fdrop = ibuf->used; #ifdef DEBUG if (debug_level >= 3) { abuf_dbg(i); dbg_puts(": overrun, silence "); dbg_putu(fdrop); dbg_puts(" + "); - dbg_putu(i->silence / i->bpf); + dbg_putu(i->w.sub.silence); dbg_puts("\n"); } #endif + i->w.sub.done += fdrop; if (i->w.sub.xrun == XRUN_SYNC) - i->silence += fdrop * i->bpf; + sub_silence(i, fdrop); else { + remain = fdrop % p->u.sub.round; + if (remain) + remain = p->u.sub.round - remain; + sub_silence(i, -(int)remain); + fdrop += remain; +#ifdef DEBUG + if (debug_level >= 3) { + abuf_dbg(i); + dbg_puts(": overrun, adding "); + dbg_putu(remain); + dbg_puts("\n"); + } +#endif + abuf_ipos(i, -(int)fdrop); if (i->duplex) { #ifdef DEBUG @@ -1010,11 +1254,10 @@ sub_xrun(struct abuf *ibuf, struct abuf *i) dbg_puts(": full-duplex resync\n"); } #endif - i->duplex->silence += fdrop * i->duplex->bpf; + mix_drop(i->duplex, -(int)fdrop); abuf_opos(i->duplex, -(int)fdrop); } } - i->w.sub.done += fdrop * ibuf->bpf; return 1; } @@ -1029,9 +1272,10 @@ sub_in(struct aproc *p, struct abuf *ibuf) idone = ibuf->len; for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) { inext = LIST_NEXT(i, oent); - if (!ABUF_WOK(i)) { + sub_silence(i, 0); + if (!SUB_WOK(i)) { if (p->flags & APROC_DROP) { - if (!sub_xrun(ibuf, i)) + if (!sub_xrun(p, i)) continue; } } else @@ -1049,7 +1293,7 @@ sub_in(struct aproc *p, struct abuf *ibuf) if (!(p->flags & APROC_DROP)) return 0; idone = ibuf->used; - p->u.sub.idle += idone / ibuf->bpf; + p->u.sub.idle += idone; } if (idone == 0) return 0; @@ -1057,7 +1301,9 @@ sub_in(struct aproc *p, struct abuf *ibuf) i->w.sub.done -= idone; } abuf_rdiscard(ibuf, idone); - p->u.sub.lat -= idone / ibuf->bpf; + abuf_opos(ibuf, idone); + p->u.sub.lat -= idone; + p->u.sub.abspos += idone; return 1; } @@ -1068,13 +1314,14 @@ sub_out(struct aproc *p, struct abuf *obuf) struct abuf *i, *inext; unsigned idone; - if (!ABUF_WOK(obuf)) + if (!SUB_WOK(obuf)) return 0; if (!abuf_fill(ibuf)) return 0; /* eof */ idone = ibuf->len; for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) { inext = LIST_NEXT(i, oent); + sub_silence(i, 0); sub_bcopy(ibuf, i); if (idone > i->w.sub.done) idone = i->w.sub.done; @@ -1087,7 +1334,9 @@ sub_out(struct aproc *p, struct abuf *obuf) i->w.sub.done -= idone; } abuf_rdiscard(ibuf, idone); - p->u.sub.lat -= idone / ibuf->bpf; + abuf_opos(ibuf, idone); + p->u.sub.lat -= idone; + p->u.sub.abspos += idone; return 1; } @@ -1100,7 +1349,7 @@ sub_eof(struct aproc *p, struct abuf *ibuf) void sub_hup(struct aproc *p, struct abuf *obuf) { - struct abuf *i, *ibuf = LIST_FIRST(&p->ibuflist); + struct abuf *i, *inext, *ibuf = LIST_FIRST(&p->ibuflist); unsigned idone; if (!aproc_inuse(p)) { @@ -1114,8 +1363,11 @@ sub_hup(struct aproc *p, struct abuf *obuf) * Find a blocked output. */ idone = ibuf->len; - LIST_FOREACH(i, &p->obuflist, oent) { - if (ABUF_WOK(i) && i->w.sub.done < ibuf->used) { + for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) { + inext = LIST_NEXT(i, oent); + if (!abuf_flush(i)) + continue; + if (SUB_WOK(i) && i->w.sub.done < ibuf->used) { abuf_run(i); return; } @@ -1144,6 +1396,7 @@ sub_newout(struct aproc *p, struct abuf *obuf) p->u.sub.idle = 0; obuf->w.sub.done = 0; obuf->w.sub.xrun = XRUN_IGNORE; + obuf->w.sub.silence = 0; } void @@ -1157,10 +1410,10 @@ sub_ipos(struct aproc *p, struct abuf *ibuf, int delta) dbg_puti(p->u.sub.lat); dbg_puts("/"); dbg_puti(p->u.sub.maxlat); - dbg_puts(" fr\n"); + dbg_puts("\n"); } #endif - if (p->u.sub.ctl) + if (APROC_OK(p->u.sub.ctl)) ctl_ontick(p->u.sub.ctl, delta); aproc_ipos(p, ibuf, delta); } @@ -1179,14 +1432,16 @@ struct aproc_ops sub_ops = { }; struct aproc * -sub_new(char *name, int maxlat, struct aproc *ctl) +sub_new(char *name, int maxlat, unsigned round, struct aproc *ctl) { struct aproc *p; p = aproc_new(&sub_ops, name); p->u.sub.idle = 0; p->u.sub.lat = 0; + p->u.sub.round = round; p->u.sub.maxlat = maxlat; + p->u.sub.abspos = 0; p->u.sub.ctl = ctl; return p; } @@ -1194,7 +1449,8 @@ sub_new(char *name, int maxlat, struct aproc *ctl) void sub_clear(struct aproc *p) { - p->u.mix.lat = 0; + p->u.sub.lat = 0; + p->u.sub.abspos = 0; } /* @@ -1221,12 +1477,10 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) * Calculate max frames readable at once from the input buffer. */ idata = (short *)abuf_rgetblk(ibuf, &icount, 0); - ifr = icount / ibuf->bpf; - icount = ifr * ibuf->bpf; + ifr = icount; odata = (short *)abuf_wgetblk(obuf, &ocount, 0); - ofr = ocount / obuf->bpf; - ocount = ofr * obuf->bpf; + ofr = ocount; /* * Partially copy structures into local variables, to avoid @@ -1258,6 +1512,8 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) #endif for (;;) { if (diff < 0) { + if (ifr == 0) + break; ctx_start ^= 1; ctx = ctxbuf + ctx_start; for (c = inch; c > 0; c--) { @@ -1265,9 +1521,10 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) ctx += RESAMP_NCTX; } diff += oblksz; - if (--ifr == 0) - break; + ifr--; } else { + if (ofr == 0) + break; ctx = ctxbuf; for (c = onch; c > 0; c--) { s1 = ctx[ctx_start]; @@ -1276,8 +1533,7 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) *odata++ = s1 + (s2 - s1) * diff / (int)oblksz; } diff -= iblksz; - if (--ofr == 0) - break; + ofr--; } } p->u.resamp.diff = diff; @@ -1297,8 +1553,8 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) /* * Update FIFO pointers. */ - icount -= ifr * ibuf->bpf; - ocount -= ofr * obuf->bpf; + icount -= ifr; + ocount -= ofr; abuf_rdiscard(ibuf, icount); abuf_wcommit(obuf, ocount); } @@ -1421,11 +1677,9 @@ cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) * Calculate max frames readable at once from the input buffer. */ idata = (short *)abuf_rgetblk(ibuf, &icount, 0); - icount /= ibuf->bpf; if (icount == 0) return; odata = (short *)abuf_wgetblk(obuf, &ocount, 0); - ocount /= obuf->bpf; if (ocount == 0) return; scount = icount < ocount ? icount : ocount; @@ -1456,8 +1710,8 @@ cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) dbg_puts(" fr\n"); } #endif - abuf_rdiscard(ibuf, scount * ibuf->bpf); - abuf_wcommit(obuf, scount * obuf->bpf); + abuf_rdiscard(ibuf, scount); + abuf_wcommit(obuf, scount); } int @@ -1555,11 +1809,9 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) * Calculate max frames readable at once from the input buffer. */ idata = (short *)abuf_rgetblk(ibuf, &icount, 0); - icount /= ibuf->bpf; if (icount == 0) return; odata = abuf_wgetblk(obuf, &ocount, 0); - ocount /= obuf->bpf; if (ocount == 0) return; scount = (icount < ocount) ? icount : ocount; @@ -1569,7 +1821,7 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) aproc_dbg(p); dbg_puts(": bcopy "); dbg_putu(scount); - dbg_puts(" fr * "); + dbg_puts(" fr / "); dbg_putu(nch); dbg_puts(" ch\n"); } @@ -1605,8 +1857,8 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) /* * Update FIFO pointers. */ - abuf_rdiscard(ibuf, scount * ibuf->bpf); - abuf_wcommit(obuf, scount * obuf->bpf); + abuf_rdiscard(ibuf, scount); + abuf_wcommit(obuf, scount); } int @@ -1715,11 +1967,9 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) * Calculate max frames readable at once from the input buffer. */ idata = abuf_rgetblk(ibuf, &icount, 0); - icount /= ibuf->bpf; if (icount == 0) return; odata = (short *)abuf_wgetblk(obuf, &ocount, 0); - ocount /= obuf->bpf; if (ocount == 0) return; scount = (icount < ocount) ? icount : ocount; @@ -1729,7 +1979,7 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) aproc_dbg(p); dbg_puts(": bcopy "); dbg_putu(scount); - dbg_puts(" fr * "); + dbg_puts(" fr / "); dbg_putu(nch); dbg_puts(" ch\n"); } @@ -1765,8 +2015,8 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) /* * Update FIFO pointers. */ - abuf_rdiscard(ibuf, scount * ibuf->bpf); - abuf_wcommit(obuf, scount * obuf->bpf); + abuf_rdiscard(ibuf, scount); + abuf_wcommit(obuf, scount); } int @@ -1852,3 +2102,168 @@ dec_new(char *name, struct aparams *par) #endif return p; } + +/* + * Commit and flush part of the output buffer + */ +void +mon_flush(struct aproc *p) +{ + struct abuf *obuf = LIST_FIRST(&p->obuflist); + unsigned count; + +#ifdef DEBUG + if (debug_level >= 4) { + aproc_dbg(p); + dbg_puts(": delta = "); + dbg_puti(p->u.mon.delta); + dbg_puts("/"); + dbg_putu(p->u.mon.bufsz); + dbg_puts(" pending = "); + dbg_puti(p->u.mon.pending); + dbg_puts("\n"); + } +#endif + if (p->u.mon.delta <= 0 || p->u.mon.pending == 0) + return; + count = p->u.mon.delta; + if (count > p->u.mon.pending) + count = p->u.mon.pending; + abuf_wcommit(obuf, count); + p->u.mon.pending -= count; + p->u.mon.delta -= count; + abuf_flush(obuf); +} + +/* + * Copy one block. + */ +void +mon_snoop(struct aproc *p, struct abuf *ibuf, unsigned pos, unsigned todo) +{ + struct abuf *obuf = LIST_FIRST(&p->obuflist); + unsigned scount, icount, ocount; + short *idata, *odata; + +#ifdef DEBUG + if (debug_level >= 4) { + aproc_dbg(p); + dbg_puts(": snoop "); + dbg_putu(pos); + dbg_puts(".."); + dbg_putu(todo); + dbg_puts("\n"); + } +#endif + if (!abuf_flush(obuf)) + return; + + while (todo > 0) { + /* + * Calculate max frames readable at once from the input buffer. + */ + idata = (short *)abuf_rgetblk(ibuf, &icount, pos); + odata = (short *)abuf_wgetblk(obuf, &ocount, p->u.mon.pending); + scount = (icount < ocount) ? icount : ocount; +#ifdef DEBUG + if (debug_level >= 4) { + aproc_dbg(p); + dbg_puts(": snooping "); + dbg_putu(scount); + dbg_puts(" fr\n"); + } + if (scount == 0) { + dbg_puts("monitor xrun, not allowed\n"); + dbg_panic(); + } +#endif + memcpy(odata, idata, scount * obuf->bpf); + p->u.mon.pending += scount; + todo -= scount; + pos += scount; + } + mon_flush(p); +} + +int +mon_in(struct aproc *p, struct abuf *ibuf) +{ +#ifdef DEBUG + dbg_puts("monitor can't have inputs to read\n"); + dbg_panic(); +#endif + return 0; +} + +/* + * put the monitor into ``empty'' state + */ +void +mon_clear(struct aproc *p) +{ + p->u.mon.pending = 0; + p->u.mon.delta = 0; +} + +int +mon_out(struct aproc *p, struct abuf *obuf) +{ + /* + * can't trigger monitored stream to produce data + */ + return 0; +} + +void +mon_eof(struct aproc *p, struct abuf *ibuf) +{ +#ifdef DEBUG + dbg_puts("monitor can't have inputs to eof\n"); + dbg_panic(); +#endif +} + +void +mon_hup(struct aproc *p, struct abuf *obuf) +{ + aproc_del(p); +} + +void +mon_ipos(struct aproc *p, struct abuf *ibuf, int delta) +{ + aproc_ipos(p, ibuf, delta); + p->u.mon.delta += delta; + mon_flush(p); +} + +struct aproc_ops mon_ops = { + "mon", + mon_in, + mon_out, + mon_eof, + mon_hup, + NULL, + NULL, + mon_ipos, + aproc_opos, + NULL +}; + +struct aproc * +mon_new(char *name, unsigned bufsz) +{ + struct aproc *p; + + p = aproc_new(&mon_ops, name); + p->u.mon.pending = 0; + p->u.mon.delta = 0; + p->u.mon.bufsz = bufsz; +#ifdef DEBUG + if (debug_level >= 3) { + aproc_dbg(p); + dbg_puts(": new\n"); + } +#endif + return p; +} |