[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.5

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