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

1.7     ! ratchov     1: /*     $OpenBSD: abuf.c,v 1.6 2008/08/14 10:02:10 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>
                     35: #include <stdio.h>
                     36: #include <stdlib.h>
1.4       ratchov    37: #include <string.h>
1.7     ! ratchov    38: #include <stdarg.h>
1.1       ratchov    39:
                     40: #include "conf.h"
                     41: #include "aproc.h"
                     42: #include "abuf.h"
                     43:
1.7     ! ratchov    44: #ifdef DEBUG
        !            45: void
        !            46: abuf_dprn(int n, struct abuf *buf, char *fmt, ...)
        !            47: {
        !            48:        va_list ap;
        !            49:
        !            50:        if (debug_level < n)
        !            51:                return;
        !            52:        fprintf(stderr, "%s->%s: ",
        !            53:            buf->wproc ? buf->wproc->name : "none",
        !            54:            buf->rproc ? buf->rproc->name : "none");
        !            55:        va_start(ap, fmt);
        !            56:        vfprintf(stderr, fmt, ap);
        !            57: }
        !            58: #define ABUF_DPRN(n, buf, ...) abuf_dprn((n), (buf), __VA_ARGS__)
        !            59: #define ABUF_DPR(buf, ...) abuf_dprn(1, (buf), __VA_ARGS__)
        !            60: #else
        !            61: #define ABUF_DPRN(n, buf, ...) do {} while (0)
        !            62: #define ABUF_DPR(buf, ...) do {} while (0)
        !            63: #endif
        !            64:
1.1       ratchov    65: struct abuf *
                     66: abuf_new(unsigned nfr, unsigned bpf)
                     67: {
                     68:        struct abuf *buf;
                     69:        unsigned len;
                     70:
                     71:        len = nfr * bpf;
                     72:        buf = malloc(sizeof(struct abuf) + len);
                     73:        if (buf == NULL) {
1.7     ! ratchov    74:                fprintf(stderr, "abuf_new: out of mem: %u * %u\n", nfr, bpf);
        !            75:                abort();
1.1       ratchov    76:        }
                     77:        buf->bpf = bpf;
1.7     ! ratchov    78:        buf->inuse = 0;
1.1       ratchov    79:
                     80:        /*
                     81:         * fill fifo pointers
                     82:         */
                     83:        buf->len = len;
                     84:        buf->used = 0;
                     85:        buf->start = 0;
1.5       ratchov    86:        buf->abspos = 0;
1.4       ratchov    87:        buf->silence = 0;
                     88:        buf->drop = 0;
1.1       ratchov    89:        buf->rproc = NULL;
                     90:        buf->wproc = NULL;
1.7     ! ratchov    91:        buf->duplex = NULL;
1.2       ratchov    92:        buf->data = (unsigned char *)buf + sizeof(*buf);
1.1       ratchov    93:        return buf;
                     94: }
                     95:
                     96: void
                     97: abuf_del(struct abuf *buf)
                     98: {
1.7     ! ratchov    99:        if (buf->duplex)
        !           100:                buf->duplex->duplex = NULL;
        !           101: #ifdef DEBUG
        !           102:        if (buf->rproc || buf->wproc || ABUF_ROK(buf)) {
        !           103:                ABUF_DPRN(0, buf, "abuf_del: used = %u\n", buf->used);
1.1       ratchov   104:                abort();
                    105:        }
1.7     ! ratchov   106: #endif
1.1       ratchov   107:        free(buf);
                    108: }
                    109:
                    110: /*
                    111:  * Get a pointer to the readable block at the given offset.
                    112:  */
                    113: unsigned char *
                    114: abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
                    115: {
                    116:        unsigned count, start, used;
                    117:
                    118:        start = buf->start + ofs;
                    119:        used = buf->used - ofs;
1.6       ratchov   120:        if (start >= buf->len)
                    121:                start -= buf->len;
1.7     ! ratchov   122: #ifdef DEBUG
        !           123:        if (start >= buf->len || used > buf->used) {
        !           124:                ABUF_DPRN(0, buf, "abuf_rgetblk: "
        !           125:                    "bad ofs: start = %u used = %u/%u, ofs = %u\n",
        !           126:                    buf->start, buf->used, buf->len, ofs);
        !           127:                abort();
        !           128:        }
        !           129: #endif
1.1       ratchov   130:        count = buf->len - start;
                    131:        if (count > used)
                    132:                count = used;
                    133:        *rsize = count;
                    134:        return buf->data + start;
1.3       ratchov   135: }
                    136:
                    137: /*
                    138:  * Discard the block at the start postion
                    139:  */
                    140: void
                    141: abuf_rdiscard(struct abuf *buf, unsigned count)
                    142: {
1.7     ! ratchov   143: #ifdef DEBUG
        !           144:        if (count > buf->used) {
        !           145:                ABUF_DPRN(0, buf, "abuf_rdiscard: bad count %u\n", count);
        !           146:                abort();
        !           147:        }
        !           148: #endif
1.3       ratchov   149:        buf->used -= count;
                    150:        buf->start += count;
                    151:        if (buf->start >= buf->len)
                    152:                buf->start -= buf->len;
1.5       ratchov   153:        buf->abspos += count;
1.3       ratchov   154: }
                    155:
                    156: /*
                    157:  * Commit the data written at the end postion
                    158:  */
                    159: void
                    160: abuf_wcommit(struct abuf *buf, unsigned count)
                    161: {
1.7     ! ratchov   162: #ifdef DEBUG
        !           163:        if (count > (buf->len - buf->used)) {
        !           164:                ABUF_DPR(buf, "abuf_wcommit: bad count\n");
        !           165:                abort();
        !           166:        }
        !           167: #endif
1.3       ratchov   168:        buf->used += count;
1.1       ratchov   169: }
                    170:
                    171: /*
                    172:  * Get a pointer to the writable block at offset ofs.
                    173:  */
                    174: unsigned char *
                    175: abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
                    176: {
                    177:        unsigned end, avail, count;
                    178:
                    179:
                    180:        end = buf->start + buf->used + ofs;
                    181:        if (end >= buf->len)
                    182:                end -= buf->len;
                    183: #ifdef DEBUG
                    184:        if (end >= buf->len) {
1.7     ! ratchov   185:                ABUF_DPR(buf, "abuf_wgetblk: %s -> %s: bad ofs, "
1.1       ratchov   186:                    "start = %u, used = %u, len = %u, ofs = %u\n",
                    187:                    buf->wproc->name, buf->rproc->name,
                    188:                    buf->start, buf->used, buf->len, ofs);
                    189:                abort();
                    190:        }
                    191: #endif
                    192:        avail = buf->len - (buf->used + ofs);
                    193:        count = buf->len - end;
                    194:        if (count > avail)
                    195:                        count = avail;
                    196:        *rsize = count;
                    197:        return buf->data + end;
                    198: }
                    199:
                    200: /*
1.4       ratchov   201:  * flush buffer either by dropping samples or by calling the aproc
                    202:  * call-back to consume data. Return 0 if blocked, 1 otherwise
                    203:  */
                    204: int
                    205: abuf_flush_do(struct abuf *buf)
                    206: {
                    207:        struct aproc *p;
                    208:        unsigned count;
                    209:
                    210:        if (buf->drop > 0) {
                    211:                count = buf->drop;
                    212:                if (count > buf->used)
                    213:                        count = buf->used;
1.7     ! ratchov   214:                if (count == 0) {
        !           215:                        ABUF_DPR(buf, "abuf_flush_do: no data to drop\n");
        !           216:                        return 0;
        !           217:                }
1.4       ratchov   218:                abuf_rdiscard(buf, count);
                    219:                buf->drop -= count;
1.7     ! ratchov   220:                ABUF_DPR(buf, "abuf_flush_do: drop = %u\n", buf->drop);
        !           221:                p = buf->rproc;
1.4       ratchov   222:        } else {
1.7     ! ratchov   223:                ABUF_DPRN(4, buf, "abuf_flush_do: in ready\n");
1.4       ratchov   224:                p = buf->rproc;
1.7     ! ratchov   225:                if (!p || !p->ops->in(p, buf))
1.4       ratchov   226:                        return 0;
                    227:        }
                    228:        return 1;
                    229: }
                    230:
                    231: /*
                    232:  * fill the buffer either by generating silence or by calling the aproc
                    233:  * call-back to provide data. Return 0 if blocked, 1 otherwise
                    234:  */
                    235: int
                    236: abuf_fill_do(struct abuf *buf)
                    237: {
                    238:        struct aproc *p;
                    239:        unsigned char *data;
                    240:        unsigned count;
                    241:
                    242:        if (buf->silence > 0) {
                    243:                data = abuf_wgetblk(buf, &count, 0);
                    244:                if (count >= buf->silence)
                    245:                        count = buf->silence;
1.7     ! ratchov   246:                if (count == 0) {
        !           247:                        ABUF_DPR(buf, "abuf_fill_do: no space for silence\n");
        !           248:                        return 0;
        !           249:                }
1.4       ratchov   250:                memset(data, 0, count);
                    251:                abuf_wcommit(buf, count);
                    252:                buf->silence -= count;
1.7     ! ratchov   253:                ABUF_DPR(buf, "abuf_fill_do: silence = %u\n", buf->silence);
        !           254:                p = buf->wproc;
1.4       ratchov   255:        } else {
1.7     ! ratchov   256:                ABUF_DPRN(4, buf, "abuf_fill_do: out avail\n");
1.4       ratchov   257:                p = buf->wproc;
1.7     ! ratchov   258:                if (p == NULL || !p->ops->out(p, buf)) {
1.4       ratchov   259:                        return 0;
1.7     ! ratchov   260:                }
        !           261:        }
        !           262:        return 1;
        !           263: }
        !           264:
        !           265: /*
        !           266:  * Notify the reader that there will be no more input (producer
        !           267:  * disappeared) and destroy the buffer
        !           268:  */
        !           269: void
        !           270: abuf_eof_do(struct abuf *buf)
        !           271: {
        !           272:        struct aproc *p;
        !           273:
        !           274:        p = buf->rproc;
        !           275:        if (p) {
        !           276:                ABUF_DPRN(2, buf, "abuf_eof_do: signaling reader\n");
        !           277:                buf->rproc = NULL;
        !           278:                LIST_REMOVE(buf, ient);
        !           279:                buf->inuse++;
        !           280:                p->ops->eof(p, buf);
        !           281:                buf->inuse--;
        !           282:        } else
        !           283:                ABUF_DPR(buf, "abuf_eof_do: no reader, freeng buf\n");
        !           284:        abuf_del(buf);
        !           285: }
        !           286:
        !           287: /*
        !           288:  * Notify the writer that the buffer has no more consumer,
        !           289:  * and destroy the buffer
        !           290:  */
        !           291: void
        !           292: abuf_hup_do(struct abuf *buf)
        !           293: {
        !           294:        struct aproc *p;
        !           295:
        !           296:        if (ABUF_ROK(buf)) {
        !           297:                ABUF_DPR(buf, "abuf_hup_do: lost %u bytes\n", buf->used);
        !           298:                buf->used = 0;
        !           299:        }
        !           300:        p = buf->wproc;
        !           301:        if (p != NULL) {
        !           302:                ABUF_DPRN(2, buf, "abuf_hup_do: signaling writer\n");
        !           303:                buf->wproc = NULL;
        !           304:                LIST_REMOVE(buf, oent);
        !           305:                buf->inuse++;
        !           306:                p->ops->hup(p, buf);
        !           307:                buf->inuse--;
        !           308:        } else
        !           309:                ABUF_DPR(buf, "abuf_hup_do: no writer, freeng buf\n");
        !           310:        abuf_del(buf);
        !           311: }
        !           312:
        !           313: /*
        !           314:  * Notify the read end of the buffer that there is input available
        !           315:  * and that data can be processed again.
        !           316:  */
        !           317: int
        !           318: abuf_flush(struct abuf *buf)
        !           319: {
        !           320:        if (buf->inuse) {
        !           321:                ABUF_DPRN(4, buf, "abuf_flush: blocked\n");
        !           322:        } else {
        !           323:                buf->inuse++;
        !           324:                for (;;) {
        !           325:                        if (!abuf_flush_do(buf))
        !           326:                                break;
        !           327:                }
        !           328:                buf->inuse--;
        !           329:                if (ABUF_HUP(buf)) {
        !           330:                        abuf_hup_do(buf);
        !           331:                        return 0;
        !           332:                }
1.4       ratchov   333:        }
                    334:        return 1;
                    335: }
                    336:
                    337: /*
1.1       ratchov   338:  * Notify the write end of the buffer that there is room and data can be
                    339:  * written again. This routine can only be called from the out()
                    340:  * call-back of the reader.
                    341:  *
1.7     ! ratchov   342:  * Return 1 if the buffer was filled, and 0 if eof condition occured. The
        !           343:  * reader must detach the buffer on EOF condition, since it's aproc->eof()
        !           344:  * call-back will never be called.
1.1       ratchov   345:  */
1.7     ! ratchov   346: int
1.1       ratchov   347: abuf_fill(struct abuf *buf)
                    348: {
1.7     ! ratchov   349:        if (buf->inuse) {
        !           350:                ABUF_DPRN(4, buf, "abuf_fill: blocked\n");
        !           351:        } else {
        !           352:                buf->inuse++;
        !           353:                for (;;) {
        !           354:                        if (!abuf_fill_do(buf))
        !           355:                                break;
        !           356:                }
        !           357:                buf->inuse--;
        !           358:                if (ABUF_EOF(buf)) {
        !           359:                        abuf_eof_do(buf);
        !           360:                        return 0;
        !           361:                }
1.1       ratchov   362:        }
1.7     ! ratchov   363:        return 1;
1.1       ratchov   364: }
                    365:
                    366: /*
                    367:  * Run a read/write loop on the buffer until either the reader or the
                    368:  * writer blocks, or until the buffer reaches eofs. We can not get hup hear,
                    369:  * since hup() is only called from terminal nodes, from the main loop.
                    370:  *
                    371:  * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
                    372:  * do not keep references to the buffer or to its writer or reader.
                    373:  */
                    374: void
                    375: abuf_run(struct abuf *buf)
                    376: {
                    377:        int canfill = 1, canflush = 1;
                    378:
1.7     ! ratchov   379:        if (buf->inuse) {
        !           380:                ABUF_DPRN(4, buf, "abuf_run: blocked\n");
        !           381:                return;
        !           382:        }
        !           383:        buf->inuse++;
1.1       ratchov   384:        for (;;) {
1.7     ! ratchov   385:                if (canfill) {
        !           386:                        if (!abuf_fill_do(buf))
        !           387:                                canfill = 0;
        !           388:                        else
        !           389:                                canflush = 1;
        !           390:                } else if (canflush) {
        !           391:                        if (!abuf_flush_do(buf))
        !           392:                                canflush = 0;
        !           393:                        else
        !           394:                                canfill = 1;
1.1       ratchov   395:                } else
1.7     ! ratchov   396:                        break;
        !           397:        }
        !           398:        buf->inuse--;
        !           399:        if (ABUF_EOF(buf)) {
        !           400:                abuf_eof_do(buf);
        !           401:                return;
        !           402:        }
        !           403:        if (ABUF_HUP(buf)) {
        !           404:                abuf_hup_do(buf);
        !           405:                return;
1.1       ratchov   406:        }
                    407: }
                    408:
                    409: /*
                    410:  * Notify the reader that there will be no more input (producer
                    411:  * disappeared). The buffer is flushed and eof() is called only if all
                    412:  * data is flushed.
                    413:  */
                    414: void
                    415: abuf_eof(struct abuf *buf)
                    416: {
                    417: #ifdef DEBUG
                    418:        if (buf->wproc == NULL) {
1.7     ! ratchov   419:                ABUF_DPR(buf, "abuf_eof: no writer\n");
1.1       ratchov   420:                abort();
                    421:        }
                    422: #endif
1.7     ! ratchov   423:        ABUF_DPRN(2, buf, "abuf_eof: requested\n");
        !           424:        LIST_REMOVE(buf, oent);
1.1       ratchov   425:        buf->wproc = NULL;
                    426:        if (buf->rproc != NULL) {
1.7     ! ratchov   427:                if (!abuf_flush(buf))
        !           428:                        return;
1.1       ratchov   429:                if (ABUF_ROK(buf)) {
                    430:                        /*
                    431:                         * Could not flush everything, the reader will
                    432:                         * have a chance to delete the abuf later.
                    433:                         */
1.7     ! ratchov   434:                        ABUF_DPRN(2, buf, "abuf_eof: will drain later\n");
1.1       ratchov   435:                        return;
                    436:                }
                    437:        }
1.7     ! ratchov   438:        if (buf->inuse) {
        !           439:                ABUF_DPRN(2, buf, "abuf_eof: signal blocked\n");
        !           440:                return;
        !           441:        }
        !           442:        abuf_eof_do(buf);
1.1       ratchov   443: }
                    444:
                    445: /*
                    446:  * Notify the writer that the buffer has no more consumer,
                    447:  * and that no more data will accepted.
                    448:  */
                    449: void
                    450: abuf_hup(struct abuf *buf)
                    451: {
                    452: #ifdef DEBUG
                    453:        if (buf->rproc == NULL) {
1.7     ! ratchov   454:                ABUF_DPR(buf, "abuf_hup: no reader\n");
1.1       ratchov   455:                abort();
                    456:        }
                    457: #endif
1.7     ! ratchov   458:        ABUF_DPRN(2, buf, "abuf_hup: initiated\n");
        !           459:
1.1       ratchov   460:        buf->rproc = NULL;
1.7     ! ratchov   461:        LIST_REMOVE(buf, ient);
1.1       ratchov   462:        if (buf->wproc != NULL) {
1.7     ! ratchov   463:                if (buf->inuse) {
        !           464:                        ABUF_DPRN(2, buf, "abuf_hup: signal blocked\n");
        !           465:                        return;
1.1       ratchov   466:                }
                    467:        }
1.7     ! ratchov   468:        abuf_hup_do(buf);
        !           469: }
        !           470:
        !           471: /*
        !           472:  * Notify the reader of the change of its real-time position
        !           473:  */
        !           474: void
        !           475: abuf_ipos(struct abuf *buf, int delta)
        !           476: {
        !           477:        struct aproc *p = buf->rproc;
        !           478:
        !           479:        if (p && p->ops->ipos) {
        !           480:                buf->inuse++;
        !           481:                p->ops->ipos(p, buf, delta);
        !           482:                buf->inuse--;
        !           483:        }
        !           484:        if (ABUF_HUP(buf))
        !           485:                abuf_hup_do(buf);
        !           486: }
        !           487:
        !           488: /*
        !           489:  * Notify the writer of the change of its real-time position
        !           490:  */
        !           491: void
        !           492: abuf_opos(struct abuf *buf, int delta)
        !           493: {
        !           494:        struct aproc *p = buf->wproc;
        !           495:
        !           496:
        !           497:        if (p && p->ops->opos) {
        !           498:                buf->inuse++;
        !           499:                p->ops->opos(p, buf, delta);
        !           500:                buf->inuse--;
        !           501:        }
        !           502:        if (ABUF_HUP(buf))
        !           503:                abuf_hup_do(buf);
1.1       ratchov   504: }