summaryrefslogtreecommitdiff
path: root/usr.bin/aucat/aproc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/aucat/aproc.c')
-rw-r--r--usr.bin/aucat/aproc.c729
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;
+}