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