-/* $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 <alex@caoua.org>
*
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "conf.h"
#include "aproc.h"
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);
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.
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()
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;
}
}
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 */
}
-/* $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 <alex@caoua.org>
*
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 */
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) */
};
/*
-/* $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 <alex@caoua.org>
*
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;
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);
mix_newin(struct aproc *p, struct abuf *ibuf)
{
ibuf->mixdone = 0;
- ibuf->mixdrop = 0;
ibuf->mixvol = ADATA_UNIT;
ibuf->xrun = XRUN_IGNORE;
}
}
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);
{
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;
sub_newout(struct aproc *p, struct abuf *obuf)
{
obuf->subdone = 0;
- obuf->subdrop = 0;
obuf->xrun = XRUN_IGNORE;
}