From 6abfcad7c2896811f8f3a66487be98ff34ce7441 Mon Sep 17 00:00:00 2001 From: ratchov Date: Thu, 14 Aug 2008 09:44:15 +0000 Subject: [PATCH] move mix/sub underrun/overrun handling code and data in the generic abuf structure, so it can reused. Required for an audio server. No behaviour change. ok jakemsr --- usr.bin/aucat/abuf.c | 73 ++++++++++++++++++++++++++++++++++++------- usr.bin/aucat/abuf.h | 8 ++--- usr.bin/aucat/aproc.c | 50 +++++------------------------ 3 files changed, 72 insertions(+), 59 deletions(-) diff --git a/usr.bin/aucat/abuf.c b/usr.bin/aucat/abuf.c index a3143d9ac18..a6f2ebc1bc9 100644 --- a/usr.bin/aucat/abuf.c +++ b/usr.bin/aucat/abuf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: abuf.c,v 1.3 2008/08/14 09:39:16 ratchov Exp $ */ +/* $OpenBSD: abuf.c,v 1.4 2008/08/14 09:44:15 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -36,6 +36,7 @@ #include #include #include +#include #include "conf.h" #include "aproc.h" @@ -60,6 +61,8 @@ abuf_new(unsigned nfr, unsigned bpf) buf->len = len; buf->used = 0; buf->start = 0; + buf->silence = 0; + buf->drop = 0; buf->rproc = NULL; buf->wproc = NULL; buf->data = (unsigned char *)buf + sizeof(*buf); @@ -150,6 +153,31 @@ abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs) return buf->data + end; } +/* + * flush buffer either by dropping samples or by calling the aproc + * call-back to consume data. Return 0 if blocked, 1 otherwise + */ +int +abuf_flush_do(struct abuf *buf) +{ + struct aproc *p; + unsigned count; + + if (buf->drop > 0) { + count = buf->drop; + if (count > buf->used) + count = buf->used; + abuf_rdiscard(buf, count); + buf->drop -= count; + DPRINTF("abuf_flush_do: drop = %u\n", buf->drop); + } else { + p = buf->rproc; + if (p == NULL || !p->ops->in(p, buf)) + return 0; + } + return 1; +} + /* * Notify the read end of the buffer that there is input available * and that data can be processed again. @@ -157,16 +185,41 @@ abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs) void abuf_flush(struct abuf *buf) { - struct aproc *p = buf->rproc; - for (;;) { if (!ABUF_ROK(buf)) break; - if (p == NULL || !p->ops->in(p, buf)) + if (!abuf_flush_do(buf)) break; } } +/* + * fill the buffer either by generating silence or by calling the aproc + * call-back to provide data. Return 0 if blocked, 1 otherwise + */ +int +abuf_fill_do(struct abuf *buf) +{ + struct aproc *p; + unsigned char *data; + unsigned count; + + if (buf->silence > 0) { + data = abuf_wgetblk(buf, &count, 0); + if (count >= buf->silence) + count = buf->silence; + memset(data, 0, count); + abuf_wcommit(buf, count); + buf->silence -= count; + DPRINTF("abuf_fill_do: silence = %u\n", buf->silence); + } else { + p = buf->wproc; + if (p == NULL || !p->ops->out(p, buf)) + return 0; + } + return 1; +} + /* * Notify the write end of the buffer that there is room and data can be * written again. This routine can only be called from the out() @@ -178,12 +231,10 @@ abuf_flush(struct abuf *buf) void abuf_fill(struct abuf *buf) { - struct aproc *p = buf->wproc; - for (;;) { if (!ABUF_WOK(buf)) break; - if (p == NULL || !p->ops->out(p, buf)) + if (!abuf_fill_do(buf)) break; } } @@ -211,12 +262,10 @@ abuf_run(struct abuf *buf) abuf_del(buf); return; } - if (ABUF_WOK(buf) && canfill && buf->wproc) { - p = buf->wproc; - canfill = p->ops->out(p, buf); + if (ABUF_WOK(buf) && canfill) { + canfill = abuf_fill_do(buf); } else if (ABUF_ROK(buf) && canflush) { - p = buf->rproc; - canflush = p->ops->in(p, buf); + canflush = abuf_flush_do(buf); } else break; /* can neither read nor write */ } diff --git a/usr.bin/aucat/abuf.h b/usr.bin/aucat/abuf.h index d7345e0dcd5..860a6c5be6b 100644 --- a/usr.bin/aucat/abuf.h +++ b/usr.bin/aucat/abuf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: abuf.h,v 1.5 2008/08/14 09:39:16 ratchov Exp $ */ +/* $OpenBSD: abuf.h,v 1.6 2008/08/14 09:44:15 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -34,9 +34,7 @@ struct abuf { int mixvol; /* input gain */ unsigned mixdone; /* input of mixer */ unsigned mixtodo; /* output of mixer */ - unsigned mixdrop; /* frames mix_in() will discard */ unsigned subdone; /* output if sub */ - unsigned subdrop; /* silence frames sub_out() will insert */ #define XRUN_IGNORE 0 /* on xrun silently insert/discard samples */ #define XRUN_SYNC 1 /* catchup to sync to the mix/sub */ #define XRUN_ERROR 2 /* xruns are errors, eof/hup buffer */ @@ -51,9 +49,11 @@ struct abuf { unsigned start; /* offset where data starts */ unsigned used; /* valid data */ unsigned len; /* size of the ring */ + unsigned silence; /* silence to insert on next write */ + unsigned drop; /* frames to drop on next read */ struct aproc *rproc; /* reader */ struct aproc *wproc; /* writer */ - unsigned char *data; /* pointer to actual data (immediately following) */ + unsigned char *data; /* actual data (immediately following) */ }; /* diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c index b938bb6907d..b98959069b8 100644 --- a/usr.bin/aucat/aproc.c +++ b/usr.bin/aucat/aproc.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aproc.c,v 1.6 2008/08/14 09:39:16 ratchov Exp $ */ +/* $OpenBSD: aproc.c,v 1.7 2008/08/14 09:44:15 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -320,25 +320,10 @@ int mix_in(struct aproc *p, struct abuf *ibuf) { struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist); - unsigned icount, ocount; + unsigned ocount; - DPRINTFN(4, "mix_in: used = %u, done = %u, zero = %u\n", + DPRINTFN(4, "mix_in: used = %u, done = %u, todo = %u\n", ibuf->used, ibuf->mixdone, obuf->mixtodo); - - /* - * discard data already sent as silence - */ - if (ibuf->mixdrop > 0) { - icount = ibuf->mixdrop; - if (icount > ibuf->used) - icount = ibuf->used; - ibuf->used -= icount; - ibuf->start += icount; - if (ibuf->start >= ibuf->len) - ibuf->start -= ibuf->len; - ibuf->mixdrop -= icount; - DPRINTF("mix_in: catched xruns, drop = %u\n", ibuf->mixdrop); - } if (ibuf->mixdone >= obuf->mixtodo) return 0; @@ -394,9 +379,8 @@ mix_out(struct aproc *p, struct abuf *obuf) drop = obuf->mixtodo; i->mixdone += drop; if (i->xrun == XRUN_SYNC) - i->mixdrop += drop; - DPRINTF("mix_out: xrun, drop = %u\n", - i->mixdrop); + i->drop += drop; + DPRINTF("mix_out: drop = %u\n", i->drop); } } else mix_badd(i, obuf); @@ -458,7 +442,6 @@ void mix_newin(struct aproc *p, struct abuf *ibuf) { ibuf->mixdone = 0; - ibuf->mixdrop = 0; ibuf->mixvol = ADATA_UNIT; ibuf->xrun = XRUN_IGNORE; } @@ -539,10 +522,9 @@ sub_in(struct aproc *p, struct abuf *ibuf) } drop = ibuf->used; if (i->xrun == XRUN_SYNC) - i->subdrop += drop; + i->silence += drop; i->subdone += drop; - DPRINTF("sub_in: xrun, drop = %u\n", - i->subdrop); + DPRINTF("sub_in: silence = %u\n", i->silence); } } else { sub_bcopy(ibuf, i); @@ -565,25 +547,8 @@ sub_out(struct aproc *p, struct abuf *obuf) { struct abuf *ibuf = LIST_FIRST(&p->ibuflist); struct abuf *i, *inext; - unsigned char *odata; - unsigned ocount; unsigned done; - /* - * generate silence for dropped samples - */ - while (obuf->subdrop > 0) { - odata = abuf_wgetblk(obuf, &ocount, 0); - if (ocount >= obuf->subdrop) - ocount = obuf->subdrop; - if (ocount == 0) - break; - memset(odata, 0, ocount); - obuf->used += ocount; - obuf->subdrop -= ocount; - DPRINTF("sub_out: catch, drop = %u\n", obuf->subdrop); - } - if (obuf->subdone >= ibuf->used) return 0; @@ -653,7 +618,6 @@ void sub_newout(struct aproc *p, struct abuf *obuf) { obuf->subdone = 0; - obuf->subdrop = 0; obuf->xrun = XRUN_IGNORE; } -- 2.20.1