Annotation of src/usr.bin/aucat/abuf.c, Revision 1.4
1.4 ! ratchov 1: /* $OpenBSD: abuf.c,v 1.3 2008/08/14 09:39:16 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: /*
18: * Simple byte fifo. It has one reader and one writer. The abuf
19: * structure is used to interconnect audio processing units (aproc
20: * structures).
21: *
22: * The abuf data is split in two parts: (1) valid data available to the reader
23: * (2) space available to the writer, which is not necessarily unused. It works
24: * as follows: the write starts filling at offset (start + used), once the data
25: * is ready, the writer adds to used the count of bytes available.
26: *
27: * TODO:
28: *
29: * (hard) make abuf_fill() a boolean depending on whether
30: * eof is reached. So the caller can do:
31: *
32: * if (!abuf_fill(buf)) {
33: * ...
34: * }
35: */
36: #include <err.h>
37: #include <stdio.h>
38: #include <stdlib.h>
1.4 ! ratchov 39: #include <string.h>
1.1 ratchov 40:
41: #include "conf.h"
42: #include "aproc.h"
43: #include "abuf.h"
44:
45: struct abuf *
46: abuf_new(unsigned nfr, unsigned bpf)
47: {
48: struct abuf *buf;
49: unsigned len;
50:
51: len = nfr * bpf;
52: buf = malloc(sizeof(struct abuf) + len);
53: if (buf == NULL) {
54: err(1, "abuf_new: malloc");
55: }
56: buf->bpf = bpf;
57:
58: /*
59: * fill fifo pointers
60: */
61: buf->len = len;
62: buf->used = 0;
63: buf->start = 0;
1.4 ! ratchov 64: buf->silence = 0;
! 65: buf->drop = 0;
1.1 ratchov 66: buf->rproc = NULL;
67: buf->wproc = NULL;
1.2 ratchov 68: buf->data = (unsigned char *)buf + sizeof(*buf);
1.1 ratchov 69: return buf;
70: }
71:
72: void
73: abuf_del(struct abuf *buf)
74: {
75: DPRINTF("abuf_del:\n");
76: if (buf->rproc) {
77: fprintf(stderr, "abuf_del: has rproc: %s\n", buf->rproc->name);
78: abort();
79: }
80: if (buf->wproc) {
81: fprintf(stderr, "abuf_del: has wproc: %s\n", buf->wproc->name);
82: abort();
83: }
84: if (buf->used > 0)
85: fprintf(stderr, "abuf_del: used = %u\n", buf->used);
86: free(buf);
87: }
88:
89: /*
90: * Get a pointer to the readable block at the given offset.
91: */
92: unsigned char *
93: abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
94: {
95: unsigned count, start, used;
96:
97: start = buf->start + ofs;
98: used = buf->used - ofs;
99: count = buf->len - start;
100: if (count > used)
101: count = used;
102: *rsize = count;
103: return buf->data + start;
1.3 ratchov 104: }
105:
106: /*
107: * Discard the block at the start postion
108: */
109: void
110: abuf_rdiscard(struct abuf *buf, unsigned count)
111: {
112: buf->used -= count;
113: buf->start += count;
114: if (buf->start >= buf->len)
115: buf->start -= buf->len;
116: }
117:
118: /*
119: * Commit the data written at the end postion
120: */
121: void
122: abuf_wcommit(struct abuf *buf, unsigned count)
123: {
124: buf->used += count;
1.1 ratchov 125: }
126:
127: /*
128: * Get a pointer to the writable block at offset ofs.
129: */
130: unsigned char *
131: abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
132: {
133: unsigned end, avail, count;
134:
135:
136: end = buf->start + buf->used + ofs;
137: if (end >= buf->len)
138: end -= buf->len;
139: #ifdef DEBUG
140: if (end >= buf->len) {
141: fprintf(stderr, "abuf_wgetblk: %s -> %s: bad ofs, "
142: "start = %u, used = %u, len = %u, ofs = %u\n",
143: buf->wproc->name, buf->rproc->name,
144: buf->start, buf->used, buf->len, ofs);
145: abort();
146: }
147: #endif
148: avail = buf->len - (buf->used + ofs);
149: count = buf->len - end;
150: if (count > avail)
151: count = avail;
152: *rsize = count;
153: return buf->data + end;
154: }
155:
156: /*
1.4 ! ratchov 157: * flush buffer either by dropping samples or by calling the aproc
! 158: * call-back to consume data. Return 0 if blocked, 1 otherwise
! 159: */
! 160: int
! 161: abuf_flush_do(struct abuf *buf)
! 162: {
! 163: struct aproc *p;
! 164: unsigned count;
! 165:
! 166: if (buf->drop > 0) {
! 167: count = buf->drop;
! 168: if (count > buf->used)
! 169: count = buf->used;
! 170: abuf_rdiscard(buf, count);
! 171: buf->drop -= count;
! 172: DPRINTF("abuf_flush_do: drop = %u\n", buf->drop);
! 173: } else {
! 174: p = buf->rproc;
! 175: if (p == NULL || !p->ops->in(p, buf))
! 176: return 0;
! 177: }
! 178: return 1;
! 179: }
! 180:
! 181: /*
1.1 ratchov 182: * Notify the read end of the buffer that there is input available
183: * and that data can be processed again.
184: */
185: void
186: abuf_flush(struct abuf *buf)
187: {
188: for (;;) {
189: if (!ABUF_ROK(buf))
190: break;
1.4 ! ratchov 191: if (!abuf_flush_do(buf))
1.1 ratchov 192: break;
193: }
194: }
195:
196: /*
1.4 ! ratchov 197: * fill the buffer either by generating silence or by calling the aproc
! 198: * call-back to provide data. Return 0 if blocked, 1 otherwise
! 199: */
! 200: int
! 201: abuf_fill_do(struct abuf *buf)
! 202: {
! 203: struct aproc *p;
! 204: unsigned char *data;
! 205: unsigned count;
! 206:
! 207: if (buf->silence > 0) {
! 208: data = abuf_wgetblk(buf, &count, 0);
! 209: if (count >= buf->silence)
! 210: count = buf->silence;
! 211: memset(data, 0, count);
! 212: abuf_wcommit(buf, count);
! 213: buf->silence -= count;
! 214: DPRINTF("abuf_fill_do: silence = %u\n", buf->silence);
! 215: } else {
! 216: p = buf->wproc;
! 217: if (p == NULL || !p->ops->out(p, buf))
! 218: return 0;
! 219: }
! 220: return 1;
! 221: }
! 222:
! 223: /*
1.1 ratchov 224: * Notify the write end of the buffer that there is room and data can be
225: * written again. This routine can only be called from the out()
226: * call-back of the reader.
227: *
228: * NOTE: The abuf writer may reach eof condition and disappear, dont keep
229: * references to abuf->wproc.
230: */
231: void
232: abuf_fill(struct abuf *buf)
233: {
234: for (;;) {
235: if (!ABUF_WOK(buf))
236: break;
1.4 ! ratchov 237: if (!abuf_fill_do(buf))
1.1 ratchov 238: break;
239: }
240: }
241:
242: /*
243: * Run a read/write loop on the buffer until either the reader or the
244: * writer blocks, or until the buffer reaches eofs. We can not get hup hear,
245: * since hup() is only called from terminal nodes, from the main loop.
246: *
247: * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
248: * do not keep references to the buffer or to its writer or reader.
249: */
250: void
251: abuf_run(struct abuf *buf)
252: {
253: struct aproc *p;
254: int canfill = 1, canflush = 1;
255:
256: for (;;) {
257: if (ABUF_EOF(buf)) {
258: p = buf->rproc;
259: DPRINTFN(2, "abuf_run: %s: got eof\n", p->name);
260: p->ops->eof(p, buf);
261: buf->rproc = NULL;
262: abuf_del(buf);
263: return;
264: }
1.4 ! ratchov 265: if (ABUF_WOK(buf) && canfill) {
! 266: canfill = abuf_fill_do(buf);
1.1 ratchov 267: } else if (ABUF_ROK(buf) && canflush) {
1.4 ! ratchov 268: canflush = abuf_flush_do(buf);
1.1 ratchov 269: } else
270: break; /* can neither read nor write */
271: }
272: }
273:
274: /*
275: * Notify the reader that there will be no more input (producer
276: * disappeared). The buffer is flushed and eof() is called only if all
277: * data is flushed.
278: */
279: void
280: abuf_eof(struct abuf *buf)
281: {
282: #ifdef DEBUG
283: if (buf->wproc == NULL) {
284: fprintf(stderr, "abuf_eof: no writer\n");
285: abort();
286: }
287: #endif
288: DPRINTFN(2, "abuf_eof: requested by %s\n", buf->wproc->name);
289: buf->wproc = NULL;
290: if (buf->rproc != NULL) {
291: abuf_flush(buf);
292: if (ABUF_ROK(buf)) {
293: /*
294: * Could not flush everything, the reader will
295: * have a chance to delete the abuf later.
296: */
297: DPRINTFN(2, "abuf_eof: %s will drain the buf later\n",
298: buf->rproc->name);
299: return;
300: }
301: DPRINTFN(2, "abuf_eof: signaling %s\n", buf->rproc->name);
302: buf->rproc->ops->eof(buf->rproc, buf);
303: buf->rproc = NULL;
304: }
305: abuf_del(buf);
306: }
307:
308:
309: /*
310: * Notify the writer that the buffer has no more consumer,
311: * and that no more data will accepted.
312: */
313: void
314: abuf_hup(struct abuf *buf)
315: {
316: #ifdef DEBUG
317: if (buf->rproc == NULL) {
318: fprintf(stderr, "abuf_hup: no reader\n");
319: abort();
320: }
321: #endif
322: DPRINTFN(2, "abuf_hup: initiated by %s\n", buf->rproc->name);
323: buf->rproc = NULL;
324: if (buf->wproc != NULL) {
325: if (ABUF_ROK(buf)) {
326: warnx("abuf_hup: %s: lost %u bytes",
327: buf->wproc->name, buf->used);
328: buf->used = 0;
329: }
330: DPRINTFN(2, "abuf_hup: signaling %s\n", buf->wproc->name);
331: buf->wproc->ops->hup(buf->wproc, buf);
332: buf->wproc = NULL;
333: }
334: abuf_del(buf);
335: }