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