diff options
author | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2010-05-02 11:12:32 +0000 |
---|---|---|
committer | Alexandre Ratchov <ratchov@cvs.openbsd.org> | 2010-05-02 11:12:32 +0000 |
commit | aa21ef7541a3118da61e9f0b759077a58b9d0f00 (patch) | |
tree | b35dec178e979b1035dbcfeb23775c733cae8a15 /usr.bin | |
parent | 7be854c95ab4dfa991a51276b596cacb6a2e4b90 (diff) |
Don't systematically fill with silence the mixer output. This
might result in extra samples being written to the device
when the mixer is closed.
Diffstat (limited to 'usr.bin')
-rw-r--r-- | usr.bin/aucat/aproc.c | 81 | ||||
-rw-r--r-- | usr.bin/aucat/aproc.h | 7 | ||||
-rw-r--r-- | usr.bin/aucat/aucat.c | 34 | ||||
-rw-r--r-- | usr.bin/aucat/dev.c | 39 |
4 files changed, 114 insertions, 47 deletions
diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c index c626ab7aaf0..d5ab22176f4 100644 --- a/usr.bin/aucat/aproc.c +++ b/usr.bin/aucat/aproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.c,v 1.56 2010/05/02 10:40:48 ratchov Exp $ */ +/* $OpenBSD: aproc.c,v 1.57 2010/05/02 11:12:31 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -577,16 +577,21 @@ mix_drop(struct abuf *buf, int extra) } /* - * Append the given amount of silence (or less if there's not enough - * space), and crank w.mix.todo accordingly. + * Append the necessary amount of silence, in a way + * obuf->w.mix.todo doesn't exceed the given value */ void -mix_bzero(struct abuf *obuf) +mix_bzero(struct abuf *obuf, unsigned maxtodo) { short *odata; - unsigned ocount; + unsigned ocount, todo; + if (obuf->w.mix.todo >= maxtodo) + return; + todo = maxtodo - obuf->w.mix.todo; odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.todo); + if (ocount > todo) + ocount = todo; if (ocount == 0) return; memset(odata, 0, ocount * obuf->bpf); @@ -628,11 +633,12 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf) /* * Insert silence for xrun correction */ - if (ibuf->r.mix.drop < 0) { + while (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; + mix_bzero(obuf, ibuf->r.mix.done + icount); + ocount = obuf->w.mix.todo - ibuf->r.mix.done; + if (ocount == 0) + return 0; scount = (icount < ocount) ? icount : ocount; ibuf->r.mix.done += scount; ibuf->r.mix.drop += scount; @@ -652,6 +658,9 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf) if (ocount == 0) return 0; + scount = (icount < ocount) ? icount : ocount; + mix_bzero(obuf, scount + ibuf->r.mix.done); + vol = (ibuf->r.mix.weight * ibuf->r.mix.vol) >> ADATA_SHIFT; cmin = obuf->cmin > ibuf->cmin ? obuf->cmin : ibuf->cmin; cmax = obuf->cmax < ibuf->cmax ? obuf->cmax : ibuf->cmax; @@ -662,7 +671,6 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf) cc = cmax - cmin + 1; odata += ostart; idata += istart; - scount = (icount < ocount) ? icount : ocount; for (i = scount; i > 0; i--) { for (j = cc; j > 0; j--) { *odata += (*idata * vol) >> ADATA_SHIFT; @@ -770,7 +778,6 @@ mix_in(struct aproc *p, struct abuf *ibuf) #endif if (!MIX_ROK(ibuf)) return 0; - mix_bzero(obuf); scount = 0; odone = obuf->w.mix.todo; for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) { @@ -852,9 +859,11 @@ mix_out(struct aproc *p, struct abuf *obuf) } #endif maxwrite = p->u.mix.maxlat - p->u.mix.lat; - mix_bzero(obuf); + if (maxwrite > obuf->w.mix.todo) { + if ((p->flags & (APROC_QUIT | APROC_DROP)) == APROC_DROP) + mix_bzero(obuf, maxwrite); + } scount = 0; - /* XXX: can obuf->len be larger than obuf->w.mix.todo ? */ odone = obuf->len; for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) { inext = LIST_NEXT(i, ient); @@ -871,18 +880,19 @@ mix_out(struct aproc *p, struct abuf *obuf) if (odone > i->r.mix.done) odone = i->r.mix.done; } - if (LIST_EMPTY(&p->ins)) { + if (LIST_EMPTY(&p->ins) && obuf->w.mix.todo == 0) { if (p->flags & APROC_QUIT) { aproc_del(p); return 0; } if (!(p->flags & APROC_DROP)) return 0; - odone = obuf->w.mix.todo; } - if (maxwrite > 0) { - if (odone > maxwrite) - odone = maxwrite; + if (odone > obuf->w.mix.todo) + odone = obuf->w.mix.todo; + if (odone > maxwrite) + odone = maxwrite; + if (odone > 0) { p->u.mix.lat += odone; p->u.mix.abspos += odone; LIST_FOREACH(i, &p->ins, ient) { @@ -1005,7 +1015,7 @@ struct aproc_ops mix_ops = { }; struct aproc * -mix_new(char *name, int maxlat, unsigned round, struct aproc *ctl) +mix_new(char *name, int maxlat, unsigned round) { struct aproc *p; @@ -1015,7 +1025,8 @@ mix_new(char *name, int maxlat, unsigned round, struct aproc *ctl) p->u.mix.round = round; p->u.mix.maxlat = maxlat; p->u.mix.abspos = 0; - p->u.mix.ctl = ctl; + p->u.mix.ctl = NULL; + p->u.mix.mon = NULL; return p; } @@ -1086,12 +1097,12 @@ mix_prime(struct aproc *p) if (!ABUF_WOK(obuf)) break; todo = p->u.mix.maxlat - p->u.mix.lat; - if (todo == 0) - break; - mix_bzero(obuf); + mix_bzero(obuf, todo); count = obuf->w.mix.todo; if (count > todo) count = todo; + if (count == 0) + break; obuf->w.mix.todo -= count; p->u.mix.lat += count; p->u.mix.abspos += count; @@ -1113,6 +1124,26 @@ mix_prime(struct aproc *p) } /* + * Gracefully terminate the mixer: raise the APROC_QUIT flag + * and let the rest of the code do the job. If there are neither + * inputs nor uncommited data, then terminate right away + */ +void +mix_quit(struct aproc *p) +{ + struct abuf *obuf = LIST_FIRST(&p->outs); + + p->flags |= APROC_QUIT; + + /* + * eof the last input will trigger aproc_del() + */ + if (!LIST_EMPTY(&p->ins) || obuf->w.mix.todo > 0) + return; + aproc_del(p); +} + +/* * Append as much as possible silence on the writer end */ void @@ -1434,7 +1465,7 @@ struct aproc_ops sub_ops = { }; struct aproc * -sub_new(char *name, int maxlat, unsigned round, struct aproc *ctl) +sub_new(char *name, int maxlat, unsigned round) { struct aproc *p; @@ -1444,7 +1475,7 @@ sub_new(char *name, int maxlat, unsigned round, struct aproc *ctl) p->u.sub.round = round; p->u.sub.maxlat = maxlat; p->u.sub.abspos = 0; - p->u.sub.ctl = ctl; + p->u.sub.ctl = NULL; return p; } diff --git a/usr.bin/aucat/aproc.h b/usr.bin/aucat/aproc.h index 343743b55d5..ff5b4584d62 100644 --- a/usr.bin/aucat/aproc.h +++ b/usr.bin/aucat/aproc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.h,v 1.35 2010/04/24 06:18:23 ratchov Exp $ */ +/* $OpenBSD: aproc.h,v 1.36 2010/05/02 11:12:31 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -237,8 +237,8 @@ void aproc_opos(struct aproc *, struct abuf *, int); struct aproc *rfile_new(struct file *); struct aproc *wfile_new(struct file *); -struct aproc *mix_new(char *, int, unsigned, struct aproc *); -struct aproc *sub_new(char *, int, unsigned, struct aproc *); +struct aproc *mix_new(char *, int, unsigned); +struct aproc *sub_new(char *, int, unsigned); struct aproc *resamp_new(char *, unsigned, unsigned); struct aproc *enc_new(char *, struct aparams *); struct aproc *dec_new(char *, struct aparams *); @@ -262,6 +262,7 @@ int wfile_do(struct aproc *, unsigned, unsigned *); void mix_setmaster(struct aproc *); void mix_clear(struct aproc *); void mix_prime(struct aproc *); +void mix_quit(struct aproc *); void mix_drop(struct abuf *, int); void sub_silence(struct abuf *, int); void sub_clear(struct aproc *); diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c index 0ab623b116e..e7767c597cb 100644 --- a/usr.bin/aucat/aucat.c +++ b/usr.bin/aucat/aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.88 2010/04/24 14:33:46 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.89 2010/05/02 11:12:31 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -356,21 +356,33 @@ privdrop(void) } void -stopall(char *base) +stopall(void) { struct file *f; restart: LIST_FOREACH(f, &file_list, entry) { /* - * skip connected streams (handled by dev_done()) + * skip connected streams (handled by dev_close()) */ - if (APROC_OK(dev_mix) && f->rproc && - aproc_depend(dev_mix, f->rproc)) - continue; - if (APROC_OK(dev_sub) && f->wproc && - aproc_depend(f->wproc, dev_sub)) - continue; + if (APROC_OK(dev_mix)) { + if (f->rproc && aproc_depend(dev_mix, f->rproc)) + continue; + if (f->wproc && aproc_depend(f->wproc, dev_mix)) + continue; + } + if (APROC_OK(dev_sub)) { + if (f->rproc && aproc_depend(dev_sub, f->rproc)) + continue; + if (f->wproc && aproc_depend(f->wproc, dev_sub)) + continue; + } + if (APROC_OK(dev_submon)) { + if (f->rproc && aproc_depend(dev_submon, f->rproc)) + continue; + if (f->wproc && aproc_depend(f->wproc, dev_submon)) + continue; + } if (APROC_OK(dev_midi)) { if (f->rproc && aproc_depend(dev_midi, f->rproc)) continue; @@ -743,7 +755,7 @@ aucat_main(int argc, char **argv) dev_start(); } } - stopall(base); + stopall(); dev_done(); filelist_done(); if (l_flag) { @@ -913,7 +925,7 @@ midicat_main(int argc, char **argv) if (!file_poll()) break; } - stopall(base); + stopall(); dev_done(); filelist_done(); if (l_flag) { diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c index c155720e5ca..e963cef8d5b 100644 --- a/usr.bin/aucat/dev.c +++ b/usr.bin/aucat/dev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.c,v 1.49 2010/04/24 06:18:23 ratchov Exp $ */ +/* $OpenBSD: dev.c,v 1.50 2010/05/02 11:12:31 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org> * @@ -127,9 +127,9 @@ dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz) dev_pstate = DEV_INIT; buf = abuf_new(dev_bufsz, &par); - dev_mix = mix_new("mix", dev_bufsz, 1, NULL); + dev_mix = mix_new("mix", dev_bufsz, 1); dev_mix->refs++; - dev_sub = sub_new("sub", dev_bufsz, 1, NULL); + dev_sub = sub_new("sub", dev_bufsz, 1); dev_sub->refs++; aproc_setout(dev_mix, buf); aproc_setin(dev_sub, buf); @@ -224,9 +224,10 @@ dev_init(char *devpath, unsigned mode, * Append a "sub" to which clients will connect. * Link it to the controller only in record-only mode */ - dev_sub = sub_new("rec", dev_bufsz, dev_round, - dopar ? NULL : dev_midi); + dev_sub = sub_new("rec", dev_bufsz, dev_round); dev_sub->refs++; + if (!(mode & MODE_PLAY)) + dev_sub->u.sub.ctl = dev_midi; aproc_setin(dev_sub, buf); } else { dev_rec = NULL; @@ -260,8 +261,9 @@ dev_init(char *devpath, unsigned mode, /* * Append a "mix" to which clients will connect. */ - dev_mix = mix_new("play", dev_bufsz, dev_round, dev_midi); + dev_mix = mix_new("play", dev_bufsz, dev_round); dev_mix->refs++; + dev_mix->u.mix.ctl = dev_midi; aproc_setout(dev_mix, buf); } else { dev_play = NULL; @@ -281,7 +283,7 @@ dev_init(char *devpath, unsigned mode, * Append a "sub" to which clients will connect. * Link it to the controller only in record-only mode */ - dev_submon = sub_new("mon", dev_bufsz, dev_round, NULL); + dev_submon = sub_new("mon", dev_bufsz, dev_round); dev_submon->refs++; aproc_setin(dev_submon, buf); @@ -318,6 +320,26 @@ dev_done(void) { struct file *f; + /* + * if the device is starting, ensure it actually starts + * so buffers are drained, else clear any buffers + */ + switch (dev_pstate) { + case DEV_START: +#ifdef DEBUG + if (debug_level >= 3) + dbg_puts("draining device\n"); +#endif + dev_start(); + break; + case DEV_INIT: +#ifdef DEBUG + if (debug_level >= 3) + dbg_puts("flushing device\n"); +#endif + dev_clear(); + break; + } #ifdef DEBUG if (debug_level >= 2) dbg_puts("closing audio device\n"); @@ -333,7 +355,8 @@ dev_done(void) * reorder the file_list, we have to restart the loop * after each call to file_eof(). */ - dev_mix->flags |= APROC_QUIT; + if (APROC_OK(dev_mix)) + mix_quit(dev_mix); if (APROC_OK(dev_mix->u.mix.mon)) { dev_mix->u.mix.mon->refs--; aproc_del(dev_mix->u.mix.mon); |