Annotation of src/usr.bin/aucat/abuf.c, Revision 1.10
1.10 ! ratchov 1: /* $OpenBSD: abuf.c,v 1.9 2008/11/09 16:26:07 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.
1.7 ratchov 26: */
27: /*
28: * TODO
1.1 ratchov 29: *
1.7 ratchov 30: * use blocks instead of frames for WOK and ROK macros. If necessary
31: * (unlikely) define reader block size and writer blocks size to
32: * ease pipe/socket implementation
1.1 ratchov 33: */
34: #include <err.h>
35: #include <stdio.h>
36: #include <stdlib.h>
1.4 ratchov 37: #include <string.h>
1.7 ratchov 38: #include <stdarg.h>
1.1 ratchov 39:
40: #include "conf.h"
1.8 ratchov 41: #include "aparams.h"
1.1 ratchov 42: #include "aproc.h"
43: #include "abuf.h"
44:
1.7 ratchov 45: #ifdef DEBUG
46: void
47: abuf_dprn(int n, struct abuf *buf, char *fmt, ...)
48: {
49: va_list ap;
50:
51: if (debug_level < n)
52: return;
1.10 ! ratchov 53: fprintf(stderr, "%s->%s: ",
1.7 ratchov 54: buf->wproc ? buf->wproc->name : "none",
55: buf->rproc ? buf->rproc->name : "none");
56: va_start(ap, fmt);
57: vfprintf(stderr, fmt, ap);
58: }
59: #define ABUF_DPRN(n, buf, ...) abuf_dprn((n), (buf), __VA_ARGS__)
60: #define ABUF_DPR(buf, ...) abuf_dprn(1, (buf), __VA_ARGS__)
61: #else
62: #define ABUF_DPRN(n, buf, ...) do {} while (0)
63: #define ABUF_DPR(buf, ...) do {} while (0)
64: #endif
65:
1.1 ratchov 66: struct abuf *
1.8 ratchov 67: abuf_new(unsigned nfr, struct aparams *par)
1.1 ratchov 68: {
69: struct abuf *buf;
1.8 ratchov 70: unsigned len, bpf;
1.1 ratchov 71:
1.8 ratchov 72: bpf = aparams_bpf(par);
1.1 ratchov 73: len = nfr * bpf;
74: buf = malloc(sizeof(struct abuf) + len);
75: if (buf == NULL) {
1.7 ratchov 76: fprintf(stderr, "abuf_new: out of mem: %u * %u\n", nfr, bpf);
77: abort();
1.1 ratchov 78: }
79: buf->bpf = bpf;
1.8 ratchov 80: buf->cmin = par->cmin;
81: buf->cmax = par->cmax;
1.7 ratchov 82: buf->inuse = 0;
1.1 ratchov 83:
84: /*
85: * fill fifo pointers
86: */
87: buf->len = len;
88: buf->used = 0;
89: buf->start = 0;
1.5 ratchov 90: buf->abspos = 0;
1.4 ratchov 91: buf->silence = 0;
92: buf->drop = 0;
1.1 ratchov 93: buf->rproc = NULL;
94: buf->wproc = NULL;
1.7 ratchov 95: buf->duplex = NULL;
1.2 ratchov 96: buf->data = (unsigned char *)buf + sizeof(*buf);
1.1 ratchov 97: return buf;
98: }
99:
100: void
101: abuf_del(struct abuf *buf)
102: {
1.7 ratchov 103: if (buf->duplex)
104: buf->duplex->duplex = NULL;
105: #ifdef DEBUG
106: if (buf->rproc || buf->wproc || ABUF_ROK(buf)) {
107: ABUF_DPRN(0, buf, "abuf_del: used = %u\n", buf->used);
1.1 ratchov 108: abort();
109: }
1.7 ratchov 110: #endif
1.1 ratchov 111: free(buf);
1.9 ratchov 112: }
113:
114: /*
115: * Clear buffer contents
116: */
117: void
118: abuf_clear(struct abuf *buf)
119: {
120: ABUF_DPR(buf, "abuf_clear:\n");
121: buf->used = 0;
122: buf->start = 0;
123: buf->abspos = 0;
124: buf->silence = 0;
125: buf->drop = 0;
1.1 ratchov 126: }
127:
128: /*
129: * Get a pointer to the readable block at the given offset.
130: */
131: unsigned char *
132: abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
133: {
134: unsigned count, start, used;
135:
136: start = buf->start + ofs;
137: used = buf->used - ofs;
1.6 ratchov 138: if (start >= buf->len)
139: start -= buf->len;
1.7 ratchov 140: #ifdef DEBUG
141: if (start >= buf->len || used > buf->used) {
142: ABUF_DPRN(0, buf, "abuf_rgetblk: "
143: "bad ofs: start = %u used = %u/%u, ofs = %u\n",
144: buf->start, buf->used, buf->len, ofs);
145: abort();
146: }
147: #endif
1.1 ratchov 148: count = buf->len - start;
149: if (count > used)
150: count = used;
151: *rsize = count;
152: return buf->data + start;
1.3 ratchov 153: }
154:
155: /*
156: * Discard the block at the start postion
157: */
158: void
159: abuf_rdiscard(struct abuf *buf, unsigned count)
160: {
1.7 ratchov 161: #ifdef DEBUG
162: if (count > buf->used) {
163: ABUF_DPRN(0, buf, "abuf_rdiscard: bad count %u\n", count);
164: abort();
165: }
166: #endif
1.3 ratchov 167: buf->used -= count;
168: buf->start += count;
169: if (buf->start >= buf->len)
170: buf->start -= buf->len;
1.5 ratchov 171: buf->abspos += count;
1.3 ratchov 172: }
173:
174: /*
175: * Commit the data written at the end postion
176: */
177: void
178: abuf_wcommit(struct abuf *buf, unsigned count)
179: {
1.7 ratchov 180: #ifdef DEBUG
181: if (count > (buf->len - buf->used)) {
182: ABUF_DPR(buf, "abuf_wcommit: bad count\n");
183: abort();
184: }
185: #endif
1.3 ratchov 186: buf->used += count;
1.1 ratchov 187: }
188:
189: /*
190: * Get a pointer to the writable block at offset ofs.
191: */
192: unsigned char *
193: abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
194: {
195: unsigned end, avail, count;
196:
197:
198: end = buf->start + buf->used + ofs;
199: if (end >= buf->len)
200: end -= buf->len;
201: #ifdef DEBUG
202: if (end >= buf->len) {
1.7 ratchov 203: ABUF_DPR(buf, "abuf_wgetblk: %s -> %s: bad ofs, "
1.1 ratchov 204: "start = %u, used = %u, len = %u, ofs = %u\n",
205: buf->wproc->name, buf->rproc->name,
206: buf->start, buf->used, buf->len, ofs);
207: abort();
208: }
209: #endif
210: avail = buf->len - (buf->used + ofs);
211: count = buf->len - end;
212: if (count > avail)
213: count = avail;
214: *rsize = count;
215: return buf->data + end;
216: }
217:
218: /*
1.4 ratchov 219: * flush buffer either by dropping samples or by calling the aproc
220: * call-back to consume data. Return 0 if blocked, 1 otherwise
221: */
222: int
223: abuf_flush_do(struct abuf *buf)
224: {
225: struct aproc *p;
226: unsigned count;
227:
228: if (buf->drop > 0) {
229: count = buf->drop;
230: if (count > buf->used)
231: count = buf->used;
1.7 ratchov 232: if (count == 0) {
233: ABUF_DPR(buf, "abuf_flush_do: no data to drop\n");
234: return 0;
235: }
1.4 ratchov 236: abuf_rdiscard(buf, count);
237: buf->drop -= count;
1.7 ratchov 238: ABUF_DPR(buf, "abuf_flush_do: drop = %u\n", buf->drop);
239: p = buf->rproc;
1.4 ratchov 240: } else {
1.7 ratchov 241: ABUF_DPRN(4, buf, "abuf_flush_do: in ready\n");
1.4 ratchov 242: p = buf->rproc;
1.7 ratchov 243: if (!p || !p->ops->in(p, buf))
1.4 ratchov 244: return 0;
245: }
246: return 1;
247: }
248:
249: /*
250: * fill the buffer either by generating silence or by calling the aproc
251: * call-back to provide data. Return 0 if blocked, 1 otherwise
252: */
253: int
254: abuf_fill_do(struct abuf *buf)
255: {
256: struct aproc *p;
257: unsigned char *data;
258: unsigned count;
259:
260: if (buf->silence > 0) {
261: data = abuf_wgetblk(buf, &count, 0);
262: if (count >= buf->silence)
263: count = buf->silence;
1.7 ratchov 264: if (count == 0) {
265: ABUF_DPR(buf, "abuf_fill_do: no space for silence\n");
266: return 0;
267: }
1.4 ratchov 268: memset(data, 0, count);
269: abuf_wcommit(buf, count);
270: buf->silence -= count;
1.7 ratchov 271: ABUF_DPR(buf, "abuf_fill_do: silence = %u\n", buf->silence);
272: p = buf->wproc;
1.4 ratchov 273: } else {
1.7 ratchov 274: ABUF_DPRN(4, buf, "abuf_fill_do: out avail\n");
1.4 ratchov 275: p = buf->wproc;
1.7 ratchov 276: if (p == NULL || !p->ops->out(p, buf)) {
1.4 ratchov 277: return 0;
1.7 ratchov 278: }
279: }
280: return 1;
281: }
282:
283: /*
284: * Notify the reader that there will be no more input (producer
285: * disappeared) and destroy the buffer
286: */
287: void
288: abuf_eof_do(struct abuf *buf)
289: {
290: struct aproc *p;
291:
292: p = buf->rproc;
293: if (p) {
294: ABUF_DPRN(2, buf, "abuf_eof_do: signaling reader\n");
295: buf->rproc = NULL;
296: LIST_REMOVE(buf, ient);
297: buf->inuse++;
298: p->ops->eof(p, buf);
299: buf->inuse--;
300: } else
301: ABUF_DPR(buf, "abuf_eof_do: no reader, freeng buf\n");
302: abuf_del(buf);
303: }
304:
305: /*
306: * Notify the writer that the buffer has no more consumer,
307: * and destroy the buffer
308: */
309: void
310: abuf_hup_do(struct abuf *buf)
311: {
312: struct aproc *p;
313:
314: if (ABUF_ROK(buf)) {
315: ABUF_DPR(buf, "abuf_hup_do: lost %u bytes\n", buf->used);
316: buf->used = 0;
317: }
318: p = buf->wproc;
319: if (p != NULL) {
320: ABUF_DPRN(2, buf, "abuf_hup_do: signaling writer\n");
321: buf->wproc = NULL;
322: LIST_REMOVE(buf, oent);
323: buf->inuse++;
324: p->ops->hup(p, buf);
325: buf->inuse--;
326: } else
327: ABUF_DPR(buf, "abuf_hup_do: no writer, freeng buf\n");
328: abuf_del(buf);
329: }
330:
331: /*
332: * Notify the read end of the buffer that there is input available
333: * and that data can be processed again.
334: */
335: int
336: abuf_flush(struct abuf *buf)
1.10 ! ratchov 337: {
1.7 ratchov 338: if (buf->inuse) {
339: ABUF_DPRN(4, buf, "abuf_flush: blocked\n");
340: } else {
341: buf->inuse++;
342: for (;;) {
343: if (!abuf_flush_do(buf))
344: break;
345: }
346: buf->inuse--;
347: if (ABUF_HUP(buf)) {
348: abuf_hup_do(buf);
349: return 0;
350: }
1.4 ratchov 351: }
352: return 1;
353: }
354:
355: /*
1.1 ratchov 356: * Notify the write end of the buffer that there is room and data can be
357: * written again. This routine can only be called from the out()
358: * call-back of the reader.
359: *
1.7 ratchov 360: * Return 1 if the buffer was filled, and 0 if eof condition occured. The
361: * reader must detach the buffer on EOF condition, since it's aproc->eof()
362: * call-back will never be called.
1.1 ratchov 363: */
1.7 ratchov 364: int
1.1 ratchov 365: abuf_fill(struct abuf *buf)
366: {
1.7 ratchov 367: if (buf->inuse) {
368: ABUF_DPRN(4, buf, "abuf_fill: blocked\n");
369: } else {
370: buf->inuse++;
371: for (;;) {
372: if (!abuf_fill_do(buf))
373: break;
374: }
375: buf->inuse--;
376: if (ABUF_EOF(buf)) {
377: abuf_eof_do(buf);
378: return 0;
379: }
1.1 ratchov 380: }
1.7 ratchov 381: return 1;
1.1 ratchov 382: }
383:
384: /*
385: * Run a read/write loop on the buffer until either the reader or the
386: * writer blocks, or until the buffer reaches eofs. We can not get hup hear,
387: * since hup() is only called from terminal nodes, from the main loop.
388: *
389: * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
390: * do not keep references to the buffer or to its writer or reader.
391: */
392: void
393: abuf_run(struct abuf *buf)
394: {
395: int canfill = 1, canflush = 1;
396:
1.7 ratchov 397: if (buf->inuse) {
398: ABUF_DPRN(4, buf, "abuf_run: blocked\n");
399: return;
400: }
401: buf->inuse++;
1.1 ratchov 402: for (;;) {
1.7 ratchov 403: if (canfill) {
404: if (!abuf_fill_do(buf))
405: canfill = 0;
406: else
407: canflush = 1;
408: } else if (canflush) {
409: if (!abuf_flush_do(buf))
410: canflush = 0;
411: else
412: canfill = 1;
1.1 ratchov 413: } else
1.7 ratchov 414: break;
415: }
416: buf->inuse--;
417: if (ABUF_EOF(buf)) {
418: abuf_eof_do(buf);
419: return;
420: }
421: if (ABUF_HUP(buf)) {
422: abuf_hup_do(buf);
423: return;
1.1 ratchov 424: }
425: }
426:
427: /*
428: * Notify the reader that there will be no more input (producer
429: * disappeared). The buffer is flushed and eof() is called only if all
430: * data is flushed.
431: */
432: void
433: abuf_eof(struct abuf *buf)
434: {
435: #ifdef DEBUG
436: if (buf->wproc == NULL) {
1.7 ratchov 437: ABUF_DPR(buf, "abuf_eof: no writer\n");
1.1 ratchov 438: abort();
439: }
440: #endif
1.7 ratchov 441: ABUF_DPRN(2, buf, "abuf_eof: requested\n");
442: LIST_REMOVE(buf, oent);
1.1 ratchov 443: buf->wproc = NULL;
444: if (buf->rproc != NULL) {
1.7 ratchov 445: if (!abuf_flush(buf))
1.10 ! ratchov 446: return;
1.1 ratchov 447: if (ABUF_ROK(buf)) {
448: /*
449: * Could not flush everything, the reader will
450: * have a chance to delete the abuf later.
451: */
1.7 ratchov 452: ABUF_DPRN(2, buf, "abuf_eof: will drain later\n");
1.1 ratchov 453: return;
454: }
455: }
1.7 ratchov 456: if (buf->inuse) {
457: ABUF_DPRN(2, buf, "abuf_eof: signal blocked\n");
458: return;
459: }
460: abuf_eof_do(buf);
1.1 ratchov 461: }
462:
463: /*
464: * Notify the writer that the buffer has no more consumer,
465: * and that no more data will accepted.
466: */
467: void
468: abuf_hup(struct abuf *buf)
469: {
470: #ifdef DEBUG
471: if (buf->rproc == NULL) {
1.7 ratchov 472: ABUF_DPR(buf, "abuf_hup: no reader\n");
1.1 ratchov 473: abort();
474: }
475: #endif
1.7 ratchov 476: ABUF_DPRN(2, buf, "abuf_hup: initiated\n");
477:
1.1 ratchov 478: buf->rproc = NULL;
1.7 ratchov 479: LIST_REMOVE(buf, ient);
1.1 ratchov 480: if (buf->wproc != NULL) {
1.7 ratchov 481: if (buf->inuse) {
482: ABUF_DPRN(2, buf, "abuf_hup: signal blocked\n");
483: return;
1.1 ratchov 484: }
485: }
1.7 ratchov 486: abuf_hup_do(buf);
487: }
488:
489: /*
490: * Notify the reader of the change of its real-time position
491: */
492: void
493: abuf_ipos(struct abuf *buf, int delta)
494: {
495: struct aproc *p = buf->rproc;
496:
497: if (p && p->ops->ipos) {
498: buf->inuse++;
1.10 ! ratchov 499: p->ops->ipos(p, buf, delta);
1.7 ratchov 500: buf->inuse--;
501: }
502: if (ABUF_HUP(buf))
503: abuf_hup_do(buf);
504: }
505:
506: /*
507: * Notify the writer of the change of its real-time position
508: */
509: void
510: abuf_opos(struct abuf *buf, int delta)
511: {
512: struct aproc *p = buf->wproc;
513:
1.10 ! ratchov 514:
1.7 ratchov 515: if (p && p->ops->opos) {
516: buf->inuse++;
517: p->ops->opos(p, buf, delta);
518: buf->inuse--;
519: }
520: if (ABUF_HUP(buf))
521: abuf_hup_do(buf);
1.1 ratchov 522: }