[BACK]Return to abuf.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Annotation of src/usr.bin/aucat/abuf.c, Revision 1.4

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