Annotation of src/usr.bin/aucat/abuf.c, Revision 1.18
1.18 ! ratchov 1: /* $OpenBSD: abuf.c,v 1.17 2010/01/10 21:47:41 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>
1.11 ratchov 35: #include <stdarg.h>
1.1 ratchov 36: #include <stdio.h>
37: #include <stdlib.h>
1.4 ratchov 38: #include <string.h>
1.1 ratchov 39:
1.13 ratchov 40: #include "abuf.h"
1.8 ratchov 41: #include "aparams.h"
1.1 ratchov 42: #include "aproc.h"
1.13 ratchov 43: #include "conf.h"
1.17 ratchov 44: #ifdef DEBUG
45: #include "dbg.h"
46: #endif
1.1 ratchov 47:
1.17 ratchov 48: #ifdef DEBUG
49: void
50: abuf_dbg(struct abuf *buf)
51: {
52: if (buf->wproc) {
53: aproc_dbg(buf->wproc);
54: } else {
55: dbg_puts("none");
56: }
57: dbg_puts(buf->inuse ? "=>" : "->");
58: if (buf->rproc) {
59: aproc_dbg(buf->rproc);
60: } else {
61: dbg_puts("none");
62: }
63: }
64:
65: void
66: abuf_dump(struct abuf *buf)
67: {
68: abuf_dbg(buf);
69: dbg_puts(": used = ");
70: dbg_putu(buf->used);
71: dbg_puts("/");
72: dbg_putu(buf->len);
73: dbg_puts(" start = ");
74: dbg_putu(buf->start);
75: dbg_puts("\n");
76: }
77: #endif
1.7 ratchov 78:
1.1 ratchov 79: struct abuf *
1.8 ratchov 80: abuf_new(unsigned nfr, struct aparams *par)
1.1 ratchov 81: {
82: struct abuf *buf;
1.8 ratchov 83: unsigned len, bpf;
1.1 ratchov 84:
1.8 ratchov 85: bpf = aparams_bpf(par);
1.1 ratchov 86: len = nfr * bpf;
87: buf = malloc(sizeof(struct abuf) + len);
88: if (buf == NULL) {
1.17 ratchov 89: #ifdef DEBUG
90: dbg_puts("couldn't allocate abuf of ");
91: dbg_putu(nfr);
92: dbg_puts("fr * ");
93: dbg_putu(bpf);
94: dbg_puts("bpf\n");
95: dbg_panic();
96: #else
1.15 ratchov 97: err(1, "malloc");
1.17 ratchov 98: #endif
1.1 ratchov 99: }
100: buf->bpf = bpf;
1.8 ratchov 101: buf->cmin = par->cmin;
102: buf->cmax = par->cmax;
1.7 ratchov 103: buf->inuse = 0;
1.1 ratchov 104:
105: /*
106: * fill fifo pointers
107: */
108: buf->len = len;
109: buf->used = 0;
110: buf->start = 0;
1.5 ratchov 111: buf->abspos = 0;
1.4 ratchov 112: buf->silence = 0;
113: buf->drop = 0;
1.1 ratchov 114: buf->rproc = NULL;
115: buf->wproc = NULL;
1.7 ratchov 116: buf->duplex = NULL;
1.1 ratchov 117: return buf;
118: }
119:
120: void
121: abuf_del(struct abuf *buf)
122: {
1.7 ratchov 123: if (buf->duplex)
124: buf->duplex->duplex = NULL;
1.17 ratchov 125: #ifdef DEBUG
126: if (buf->rproc || buf->wproc) {
127: abuf_dbg(buf);
128: dbg_puts(": can't delete referenced buffer\n");
129: dbg_panic();
130: }
131: if (ABUF_ROK(buf)) {
132: /*
133: * XXX : we should call abort(), here.
134: * However, poll() doesn't seem to return POLLHUP,
135: * so the reader is never destroyed; instead it appears
136: * as blocked. Fix file_poll(), if fixable, and add
137: * a call to abord() here.
138: */
139: if (debug_level >= 3) {
140: abuf_dbg(buf);
141: dbg_puts(": deleting non-empty buffer, used = ");
142: dbg_putu(buf->used);
143: dbg_puts("\n");
144: }
145: }
146: #endif
1.1 ratchov 147: free(buf);
1.9 ratchov 148: }
149:
150: /*
1.13 ratchov 151: * Clear buffer contents.
1.9 ratchov 152: */
153: void
154: abuf_clear(struct abuf *buf)
155: {
1.17 ratchov 156: #ifdef DEBUG
157: if (debug_level >= 3) {
158: abuf_dbg(buf);
159: dbg_puts(": cleared\n");
160: }
161: #endif
1.9 ratchov 162: buf->used = 0;
163: buf->start = 0;
164: buf->abspos = 0;
165: buf->silence = 0;
166: buf->drop = 0;
1.1 ratchov 167: }
168:
169: /*
170: * Get a pointer to the readable block at the given offset.
171: */
172: unsigned char *
173: abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
174: {
175: unsigned count, start, used;
176:
177: start = buf->start + ofs;
178: used = buf->used - ofs;
1.6 ratchov 179: if (start >= buf->len)
180: start -= buf->len;
1.17 ratchov 181: #ifdef DEBUG
182: if (start >= buf->len || used > buf->used) {
183: abuf_dump(buf);
184: dbg_puts(": rgetblk: bad ofs = ");
185: dbg_putu(ofs);
186: dbg_puts("\n");
187: dbg_panic();
188: }
189: #endif
1.1 ratchov 190: count = buf->len - start;
191: if (count > used)
192: count = used;
193: *rsize = count;
1.16 ratchov 194: return (unsigned char *)buf + sizeof(struct abuf) + start;
1.3 ratchov 195: }
196:
197: /*
1.13 ratchov 198: * Discard the block at the start postion.
1.3 ratchov 199: */
200: void
201: abuf_rdiscard(struct abuf *buf, unsigned count)
202: {
1.17 ratchov 203: #ifdef DEBUG
204: if (count > buf->used) {
205: abuf_dump(buf);
206: dbg_puts(": rdiscard: bad count = ");
207: dbg_putu(count);
208: dbg_puts("\n");
209: dbg_panic();
210: }
211: #endif
1.3 ratchov 212: buf->used -= count;
213: buf->start += count;
214: if (buf->start >= buf->len)
215: buf->start -= buf->len;
1.5 ratchov 216: buf->abspos += count;
1.3 ratchov 217: }
218:
219: /*
1.13 ratchov 220: * Commit the data written at the end postion.
1.3 ratchov 221: */
222: void
223: abuf_wcommit(struct abuf *buf, unsigned count)
224: {
1.17 ratchov 225: #ifdef DEBUG
226: if (count > (buf->len - buf->used)) {
227: abuf_dump(buf);
228: dbg_puts(": rdiscard: bad count = ");
229: dbg_putu(count);
230: dbg_puts("\n");
231: dbg_panic();
232: }
233: #endif
1.3 ratchov 234: buf->used += count;
1.1 ratchov 235: }
236:
237: /*
238: * Get a pointer to the writable block at offset ofs.
239: */
240: unsigned char *
241: abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
242: {
243: unsigned end, avail, count;
244:
245:
246: end = buf->start + buf->used + ofs;
247: if (end >= buf->len)
248: end -= buf->len;
1.17 ratchov 249: #ifdef DEBUG
250: if (end >= buf->len) {
251: abuf_dump(buf);
1.18 ! ratchov 252: dbg_puts(": wgetblk: bad ofs = ");
1.17 ratchov 253: dbg_putu(ofs);
254: dbg_puts("\n");
255: dbg_panic();
256: }
257: #endif
1.1 ratchov 258: avail = buf->len - (buf->used + ofs);
259: count = buf->len - end;
260: if (count > avail)
261: count = avail;
262: *rsize = count;
1.16 ratchov 263: return (unsigned char *)buf + sizeof(struct abuf) + end;
1.1 ratchov 264: }
265:
266: /*
1.13 ratchov 267: * Flush buffer either by dropping samples or by calling the aproc
268: * call-back to consume data. Return 0 if blocked, 1 otherwise.
1.4 ratchov 269: */
270: int
271: abuf_flush_do(struct abuf *buf)
272: {
273: struct aproc *p;
274: unsigned count;
275:
276: if (buf->drop > 0) {
277: count = buf->drop;
278: if (count > buf->used)
279: count = buf->used;
1.7 ratchov 280: if (count == 0) {
1.17 ratchov 281: #ifdef DEBUG
282: if (debug_level >= 4) {
283: abuf_dbg(buf);
284: dbg_puts(": flush: no data to drop\n");
285: }
286: #endif
1.7 ratchov 287: return 0;
288: }
1.4 ratchov 289: abuf_rdiscard(buf, count);
290: buf->drop -= count;
1.17 ratchov 291: #ifdef DEBUG
292: if (debug_level >= 4) {
293: abuf_dbg(buf);
294: dbg_puts(": flush: dropped ");
295: dbg_putu(count);
296: dbg_puts(", to drop = ");
297: dbg_putu(buf->drop);
298: dbg_puts("\n");
299: }
300: #endif
1.4 ratchov 301: } else {
302: p = buf->rproc;
1.15 ratchov 303: if (!p)
304: return 0;
1.17 ratchov 305: #ifdef DEBUG
306: if (debug_level >= 4) {
307: aproc_dbg(p);
308: dbg_puts(": in\n");
309: }
310: #endif
1.15 ratchov 311: if (!p->ops->in(p, buf))
1.4 ratchov 312: return 0;
313: }
314: return 1;
315: }
316:
317: /*
1.13 ratchov 318: * Fill the buffer either by generating silence or by calling the aproc
319: * call-back to provide data. Return 0 if blocked, 1 otherwise.
1.4 ratchov 320: */
321: int
322: abuf_fill_do(struct abuf *buf)
323: {
324: struct aproc *p;
325: unsigned char *data;
326: unsigned count;
327:
328: if (buf->silence > 0) {
329: data = abuf_wgetblk(buf, &count, 0);
330: if (count >= buf->silence)
331: count = buf->silence;
1.7 ratchov 332: if (count == 0) {
1.17 ratchov 333: #ifdef DEBUG
334: if (debug_level >= 4) {
335: abuf_dbg(buf);
336: dbg_puts(": fill: no space for silence\n");
337: }
338: #endif
1.7 ratchov 339: return 0;
340: }
1.4 ratchov 341: memset(data, 0, count);
342: abuf_wcommit(buf, count);
343: buf->silence -= count;
1.17 ratchov 344: #ifdef DEBUG
345: if (debug_level >= 4) {
346: abuf_dbg(buf);
347: dbg_puts(": fill: inerted ");
348: dbg_putu(count);
349: dbg_puts(", remaining silence = ");
350: dbg_putu(buf->silence);
351: dbg_puts("\n");
352: }
353: #endif
1.7 ratchov 354: p = buf->wproc;
1.4 ratchov 355: } else {
356: p = buf->wproc;
1.15 ratchov 357: if (!p)
358: return 0;
1.17 ratchov 359: #ifdef DEBUG
360: if (debug_level >= 4) {
361: aproc_dbg(p);
362: dbg_puts(": out\n");
363: }
364: #endif
1.15 ratchov 365: if (!p->ops->out(p, buf)) {
1.4 ratchov 366: return 0;
1.7 ratchov 367: }
368: }
369: return 1;
370: }
371:
372: /*
373: * Notify the reader that there will be no more input (producer
1.13 ratchov 374: * disappeared) and destroy the buffer.
1.7 ratchov 375: */
376: void
377: abuf_eof_do(struct abuf *buf)
378: {
379: struct aproc *p;
380:
381: p = buf->rproc;
382: if (p) {
383: buf->rproc = NULL;
384: LIST_REMOVE(buf, ient);
385: buf->inuse++;
1.17 ratchov 386: #ifdef DEBUG
387: if (debug_level >= 4) {
388: aproc_dbg(p);
389: dbg_puts(": eof\n");
390: }
391: #endif
1.7 ratchov 392: p->ops->eof(p, buf);
393: buf->inuse--;
1.15 ratchov 394: }
1.7 ratchov 395: abuf_del(buf);
396: }
397:
398: /*
399: * Notify the writer that the buffer has no more consumer,
1.13 ratchov 400: * and destroy the buffer.
1.7 ratchov 401: */
402: void
403: abuf_hup_do(struct abuf *buf)
404: {
405: struct aproc *p;
406:
407: if (ABUF_ROK(buf)) {
1.17 ratchov 408: #ifdef DEBUG
409: if (debug_level >= 3) {
410: abuf_dbg(buf);
411: dbg_puts(": hup: lost ");
412: dbg_putu(buf->used);
413: dbg_puts(" bytes\n");
414: }
415: #endif
1.7 ratchov 416: buf->used = 0;
417: }
418: p = buf->wproc;
419: if (p != NULL) {
420: buf->wproc = NULL;
421: LIST_REMOVE(buf, oent);
422: buf->inuse++;
1.17 ratchov 423: #ifdef DEBUG
424: if (debug_level >= 3) {
425: aproc_dbg(p);
426: dbg_puts(": hup\n");
427: }
428: #endif
1.7 ratchov 429: p->ops->hup(p, buf);
430: buf->inuse--;
1.15 ratchov 431: }
1.7 ratchov 432: abuf_del(buf);
433: }
434:
435: /*
436: * Notify the read end of the buffer that there is input available
437: * and that data can be processed again.
438: */
439: int
440: abuf_flush(struct abuf *buf)
1.10 ratchov 441: {
1.7 ratchov 442: if (buf->inuse) {
1.17 ratchov 443: #ifdef DEBUG
444: if (debug_level >= 4) {
445: abuf_dbg(buf);
446: dbg_puts(": flush blocked (inuse)\n");
447: }
448: #endif
1.7 ratchov 449: } else {
450: buf->inuse++;
451: for (;;) {
452: if (!abuf_flush_do(buf))
453: break;
454: }
455: buf->inuse--;
456: if (ABUF_HUP(buf)) {
457: abuf_hup_do(buf);
458: return 0;
459: }
1.4 ratchov 460: }
461: return 1;
462: }
463:
464: /*
1.1 ratchov 465: * Notify the write end of the buffer that there is room and data can be
466: * written again. This routine can only be called from the out()
467: * call-back of the reader.
468: *
1.7 ratchov 469: * Return 1 if the buffer was filled, and 0 if eof condition occured. The
1.13 ratchov 470: * reader must detach the buffer on EOF condition, since its aproc->eof()
1.7 ratchov 471: * call-back will never be called.
1.1 ratchov 472: */
1.7 ratchov 473: int
1.1 ratchov 474: abuf_fill(struct abuf *buf)
475: {
1.7 ratchov 476: if (buf->inuse) {
1.17 ratchov 477: #ifdef DEBUG
478: if (debug_level >= 4) {
479: abuf_dbg(buf);
480: dbg_puts(": fill blocked (inuse)\n");
481: }
482: #endif
1.7 ratchov 483: } else {
484: buf->inuse++;
485: for (;;) {
486: if (!abuf_fill_do(buf))
487: break;
488: }
489: buf->inuse--;
490: if (ABUF_EOF(buf)) {
491: abuf_eof_do(buf);
492: return 0;
493: }
1.1 ratchov 494: }
1.7 ratchov 495: return 1;
1.1 ratchov 496: }
497:
498: /*
499: * Run a read/write loop on the buffer until either the reader or the
1.13 ratchov 500: * writer blocks, or until the buffer reaches eofs. We can not get hup here,
1.1 ratchov 501: * since hup() is only called from terminal nodes, from the main loop.
502: *
503: * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
504: * do not keep references to the buffer or to its writer or reader.
505: */
506: void
507: abuf_run(struct abuf *buf)
508: {
509: int canfill = 1, canflush = 1;
510:
1.7 ratchov 511: if (buf->inuse) {
1.17 ratchov 512: #ifdef DEBUG
513: if (debug_level >= 4) {
514: abuf_dbg(buf);
515: dbg_puts(": run blocked (inuse)\n");
516: }
517: #endif
1.7 ratchov 518: return;
519: }
520: buf->inuse++;
1.1 ratchov 521: for (;;) {
1.7 ratchov 522: if (canfill) {
523: if (!abuf_fill_do(buf))
524: canfill = 0;
525: else
526: canflush = 1;
527: } else if (canflush) {
528: if (!abuf_flush_do(buf))
529: canflush = 0;
530: else
531: canfill = 1;
1.1 ratchov 532: } else
1.7 ratchov 533: break;
534: }
535: buf->inuse--;
536: if (ABUF_EOF(buf)) {
537: abuf_eof_do(buf);
538: return;
539: }
540: if (ABUF_HUP(buf)) {
541: abuf_hup_do(buf);
542: return;
1.1 ratchov 543: }
544: }
545:
546: /*
547: * Notify the reader that there will be no more input (producer
548: * disappeared). The buffer is flushed and eof() is called only if all
549: * data is flushed.
550: */
551: void
552: abuf_eof(struct abuf *buf)
553: {
1.17 ratchov 554: #ifdef DEBUG
555: if (debug_level >= 3) {
556: abuf_dbg(buf);
557: dbg_puts(": eof requested\n");
558: }
559: if (buf->wproc == NULL) {
560: abuf_dbg(buf);
561: dbg_puts(": eof, no writer\n");
562: dbg_panic();
563: }
564: #endif
1.7 ratchov 565: LIST_REMOVE(buf, oent);
1.1 ratchov 566: buf->wproc = NULL;
567: if (buf->rproc != NULL) {
1.7 ratchov 568: if (!abuf_flush(buf))
1.10 ratchov 569: return;
1.1 ratchov 570: if (ABUF_ROK(buf)) {
571: /*
572: * Could not flush everything, the reader will
573: * have a chance to delete the abuf later.
574: */
1.17 ratchov 575: #ifdef DEBUG
576: if (debug_level >= 3) {
577: abuf_dbg(buf);
578: dbg_puts(": eof, blocked (drain)\n");
579: }
580: #endif
1.1 ratchov 581: return;
582: }
583: }
1.7 ratchov 584: if (buf->inuse) {
1.17 ratchov 585: #ifdef DEBUG
586: if (debug_level >= 3) {
587: abuf_dbg(buf);
588: dbg_puts(": eof, blocked (inuse)\n");
589: }
590: #endif
1.7 ratchov 591: return;
592: }
593: abuf_eof_do(buf);
1.1 ratchov 594: }
595:
596: /*
597: * Notify the writer that the buffer has no more consumer,
598: * and that no more data will accepted.
599: */
600: void
601: abuf_hup(struct abuf *buf)
602: {
1.17 ratchov 603: #ifdef DEBUG
604: if (debug_level >= 3) {
605: abuf_dbg(buf);
606: dbg_puts(": hup requested\n");
607: }
608: if (buf->rproc == NULL) {
609: abuf_dbg(buf);
610: dbg_puts(": hup, no reader\n");
611: dbg_panic();
612: }
613: #endif
1.1 ratchov 614: buf->rproc = NULL;
1.7 ratchov 615: LIST_REMOVE(buf, ient);
1.1 ratchov 616: if (buf->wproc != NULL) {
1.7 ratchov 617: if (buf->inuse) {
1.17 ratchov 618: #ifdef DEBUG
619: if (debug_level >= 3) {
620: abuf_dbg(buf);
621: dbg_puts(": eof, blocked (inuse)\n");
622: }
623: #endif
1.7 ratchov 624: return;
1.1 ratchov 625: }
626: }
1.7 ratchov 627: abuf_hup_do(buf);
628: }
629:
630: /*
631: * Notify the reader of the change of its real-time position
632: */
633: void
634: abuf_ipos(struct abuf *buf, int delta)
635: {
636: struct aproc *p = buf->rproc;
637:
638: if (p && p->ops->ipos) {
639: buf->inuse++;
1.17 ratchov 640: #ifdef DEBUG
641: if (debug_level >= 4) {
642: aproc_dbg(p);
643: dbg_puts(": ipos delta = ");
644: dbg_puti(delta);
645: dbg_puts("\n");
646: }
647: #endif
1.10 ratchov 648: p->ops->ipos(p, buf, delta);
1.7 ratchov 649: buf->inuse--;
650: }
651: if (ABUF_HUP(buf))
652: abuf_hup_do(buf);
653: }
654:
655: /*
656: * Notify the writer of the change of its real-time position
657: */
658: void
659: abuf_opos(struct abuf *buf, int delta)
660: {
661: struct aproc *p = buf->wproc;
1.10 ratchov 662:
1.7 ratchov 663: if (p && p->ops->opos) {
664: buf->inuse++;
1.17 ratchov 665: #ifdef DEBUG
666: if (debug_level >= 4) {
667: aproc_dbg(p);
668: dbg_puts(": opos delta = ");
669: dbg_puti(delta);
670: dbg_puts("\n");
671: }
672: #endif
1.7 ratchov 673: p->ops->opos(p, buf, delta);
674: buf->inuse--;
675: }
676: if (ABUF_HUP(buf))
677: abuf_hup_do(buf);
1.1 ratchov 678: }