Annotation of src/usr.bin/aucat/abuf.c, Revision 1.5
1.5 ! ratchov 1: /* $OpenBSD: abuf.c,v 1.4 2008/08/14 09:44:15 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.5 ! ratchov 64: buf->abspos = 0;
1.4 ratchov 65: buf->silence = 0;
66: buf->drop = 0;
1.1 ratchov 67: buf->rproc = NULL;
68: buf->wproc = NULL;
1.2 ratchov 69: buf->data = (unsigned char *)buf + sizeof(*buf);
1.1 ratchov 70: return buf;
71: }
72:
73: void
74: abuf_del(struct abuf *buf)
75: {
76: DPRINTF("abuf_del:\n");
77: if (buf->rproc) {
78: fprintf(stderr, "abuf_del: has rproc: %s\n", buf->rproc->name);
79: abort();
80: }
81: if (buf->wproc) {
82: fprintf(stderr, "abuf_del: has wproc: %s\n", buf->wproc->name);
83: abort();
84: }
85: if (buf->used > 0)
86: fprintf(stderr, "abuf_del: used = %u\n", buf->used);
87: free(buf);
88: }
89:
90: /*
91: * Get a pointer to the readable block at the given offset.
92: */
93: unsigned char *
94: abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
95: {
96: unsigned count, start, used;
97:
98: start = buf->start + ofs;
99: used = buf->used - ofs;
100: count = buf->len - start;
101: if (count > used)
102: count = used;
103: *rsize = count;
104: return buf->data + start;
1.3 ratchov 105: }
106:
107: /*
108: * Discard the block at the start postion
109: */
110: void
111: abuf_rdiscard(struct abuf *buf, unsigned count)
112: {
113: buf->used -= count;
114: buf->start += count;
115: if (buf->start >= buf->len)
116: buf->start -= buf->len;
1.5 ! ratchov 117: buf->abspos += count;
1.3 ratchov 118: }
119:
120: /*
121: * Commit the data written at the end postion
122: */
123: void
124: abuf_wcommit(struct abuf *buf, unsigned count)
125: {
126: buf->used += count;
1.1 ratchov 127: }
128:
129: /*
130: * Get a pointer to the writable block at offset ofs.
131: */
132: unsigned char *
133: abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
134: {
135: unsigned end, avail, count;
136:
137:
138: end = buf->start + buf->used + ofs;
139: if (end >= buf->len)
140: end -= buf->len;
141: #ifdef DEBUG
142: if (end >= buf->len) {
143: fprintf(stderr, "abuf_wgetblk: %s -> %s: bad ofs, "
144: "start = %u, used = %u, len = %u, ofs = %u\n",
145: buf->wproc->name, buf->rproc->name,
146: buf->start, buf->used, buf->len, ofs);
147: abort();
148: }
149: #endif
150: avail = buf->len - (buf->used + ofs);
151: count = buf->len - end;
152: if (count > avail)
153: count = avail;
154: *rsize = count;
155: return buf->data + end;
156: }
157:
158: /*
1.4 ratchov 159: * flush buffer either by dropping samples or by calling the aproc
160: * call-back to consume data. Return 0 if blocked, 1 otherwise
161: */
162: int
163: abuf_flush_do(struct abuf *buf)
164: {
165: struct aproc *p;
166: unsigned count;
167:
168: if (buf->drop > 0) {
169: count = buf->drop;
170: if (count > buf->used)
171: count = buf->used;
172: abuf_rdiscard(buf, count);
173: buf->drop -= count;
174: DPRINTF("abuf_flush_do: drop = %u\n", buf->drop);
175: } else {
176: p = buf->rproc;
177: if (p == NULL || !p->ops->in(p, buf))
178: return 0;
179: }
180: return 1;
181: }
182:
183: /*
1.1 ratchov 184: * Notify the read end of the buffer that there is input available
185: * and that data can be processed again.
186: */
187: void
188: abuf_flush(struct abuf *buf)
189: {
190: for (;;) {
191: if (!ABUF_ROK(buf))
192: break;
1.4 ratchov 193: if (!abuf_flush_do(buf))
1.1 ratchov 194: break;
195: }
196: }
197:
198: /*
1.4 ratchov 199: * fill the buffer either by generating silence or by calling the aproc
200: * call-back to provide data. Return 0 if blocked, 1 otherwise
201: */
202: int
203: abuf_fill_do(struct abuf *buf)
204: {
205: struct aproc *p;
206: unsigned char *data;
207: unsigned count;
208:
209: if (buf->silence > 0) {
210: data = abuf_wgetblk(buf, &count, 0);
211: if (count >= buf->silence)
212: count = buf->silence;
213: memset(data, 0, count);
214: abuf_wcommit(buf, count);
215: buf->silence -= count;
216: DPRINTF("abuf_fill_do: silence = %u\n", buf->silence);
217: } else {
218: p = buf->wproc;
219: if (p == NULL || !p->ops->out(p, buf))
220: return 0;
221: }
222: return 1;
223: }
224:
225: /*
1.1 ratchov 226: * Notify the write end of the buffer that there is room and data can be
227: * written again. This routine can only be called from the out()
228: * call-back of the reader.
229: *
230: * NOTE: The abuf writer may reach eof condition and disappear, dont keep
231: * references to abuf->wproc.
232: */
233: void
234: abuf_fill(struct abuf *buf)
235: {
236: for (;;) {
237: if (!ABUF_WOK(buf))
238: break;
1.4 ratchov 239: if (!abuf_fill_do(buf))
1.1 ratchov 240: break;
241: }
242: }
243:
244: /*
245: * Run a read/write loop on the buffer until either the reader or the
246: * writer blocks, or until the buffer reaches eofs. We can not get hup hear,
247: * since hup() is only called from terminal nodes, from the main loop.
248: *
249: * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
250: * do not keep references to the buffer or to its writer or reader.
251: */
252: void
253: abuf_run(struct abuf *buf)
254: {
255: struct aproc *p;
256: int canfill = 1, canflush = 1;
257:
258: for (;;) {
259: if (ABUF_EOF(buf)) {
260: p = buf->rproc;
261: DPRINTFN(2, "abuf_run: %s: got eof\n", p->name);
262: p->ops->eof(p, buf);
263: buf->rproc = NULL;
264: abuf_del(buf);
265: return;
266: }
1.4 ratchov 267: if (ABUF_WOK(buf) && canfill) {
268: canfill = abuf_fill_do(buf);
1.1 ratchov 269: } else if (ABUF_ROK(buf) && canflush) {
1.4 ratchov 270: canflush = abuf_flush_do(buf);
1.1 ratchov 271: } else
272: break; /* can neither read nor write */
273: }
274: }
275:
276: /*
277: * Notify the reader that there will be no more input (producer
278: * disappeared). The buffer is flushed and eof() is called only if all
279: * data is flushed.
280: */
281: void
282: abuf_eof(struct abuf *buf)
283: {
284: #ifdef DEBUG
285: if (buf->wproc == NULL) {
286: fprintf(stderr, "abuf_eof: no writer\n");
287: abort();
288: }
289: #endif
290: DPRINTFN(2, "abuf_eof: requested by %s\n", buf->wproc->name);
291: buf->wproc = NULL;
292: if (buf->rproc != NULL) {
293: abuf_flush(buf);
294: if (ABUF_ROK(buf)) {
295: /*
296: * Could not flush everything, the reader will
297: * have a chance to delete the abuf later.
298: */
299: DPRINTFN(2, "abuf_eof: %s will drain the buf later\n",
300: buf->rproc->name);
301: return;
302: }
303: DPRINTFN(2, "abuf_eof: signaling %s\n", buf->rproc->name);
304: buf->rproc->ops->eof(buf->rproc, buf);
305: buf->rproc = NULL;
306: }
307: abuf_del(buf);
308: }
309:
310:
311: /*
312: * Notify the writer that the buffer has no more consumer,
313: * and that no more data will accepted.
314: */
315: void
316: abuf_hup(struct abuf *buf)
317: {
318: #ifdef DEBUG
319: if (buf->rproc == NULL) {
320: fprintf(stderr, "abuf_hup: no reader\n");
321: abort();
322: }
323: #endif
324: DPRINTFN(2, "abuf_hup: initiated by %s\n", buf->rproc->name);
325: buf->rproc = NULL;
326: if (buf->wproc != NULL) {
327: if (ABUF_ROK(buf)) {
328: warnx("abuf_hup: %s: lost %u bytes",
329: buf->wproc->name, buf->used);
330: buf->used = 0;
331: }
332: DPRINTFN(2, "abuf_hup: signaling %s\n", buf->wproc->name);
333: buf->wproc->ops->hup(buf->wproc, buf);
334: buf->wproc = NULL;
335: }
336: abuf_del(buf);
337: }