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

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