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

Annotation of src/usr.bin/aucat/aproc.c, Revision 1.12

1.11      ratchov     1: /*     $OpenBSD: aproc.c,v 1.10 2008/08/14 09:58:55 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:  * aproc structures are simple audio processing units. They are
                     19:  * interconnected by abuf structures and form a kind of circuit. aproc
                     20:  * structure have call-backs that do the actual processing.
                     21:  *
                     22:  * This module implements the following processing units:
                     23:  *
                     24:  *  - rpipe: read end of an unix file (pipe, socket, device...)
                     25:  *
                     26:  *  - wpipe: write end of an unix file (pipe, socket, device...)
                     27:  *
                     28:  *  - mix: mix N inputs -> 1 output
                     29:  *
                     30:  *  - sub: from 1 input -> extract/copy N outputs
                     31:  *
                     32:  *  - conv: converts/resamples/remaps a single stream
                     33:  *
                     34:  * TODO
                     35:  *
                     36:  *     (easy) split the "conv" into 2 converters: one for input (that
                     37:  *     convers anything to 16bit signed) and one for the output (that
                     38:  *     converts 16bit signed to anything)
                     39:  *
                     40:  *     (hard) add a lowpass filter for the resampler. Quality is
                     41:  *     not acceptable as is.
1.12    ! ratchov    42:  *
1.1       ratchov    43:  */
                     44: #include <err.h>
                     45: #include <limits.h>
                     46: #include <stdio.h>
                     47: #include <stdlib.h>
                     48: #include <string.h>
                     49:
                     50: #include "conf.h"
                     51: #include "aparams.h"
                     52: #include "abuf.h"
                     53: #include "aproc.h"
                     54: #include "file.h"
                     55:
                     56: struct aproc *
                     57: aproc_new(struct aproc_ops *ops, char *name)
                     58: {
                     59:        struct aproc *p;
                     60:
                     61:        p = malloc(sizeof(struct aproc));
                     62:        if (p == NULL)
                     63:                err(1, name);
                     64:        LIST_INIT(&p->ibuflist);
                     65:        LIST_INIT(&p->obuflist);
                     66:        p->name = name;
                     67:        p->ops = ops;
                     68:        return p;
                     69: }
                     70:
                     71: void
                     72: aproc_del(struct aproc *p)
                     73: {
1.12    ! ratchov    74:        struct abuf *i;
        !            75:
        !            76:        DPRINTF("aproc_del: %s(%s): terminating...\n", p->ops->name, p->name);
        !            77:
1.8       ratchov    78:        if (p->ops->done)
                     79:                p->ops->done(p);
1.12    ! ratchov    80:
        !            81:        while (!LIST_EMPTY(&p->ibuflist)) {
        !            82:                i = LIST_FIRST(&p->ibuflist);
        !            83:                abuf_hup(i);
        !            84:        }
        !            85:        while (!LIST_EMPTY(&p->obuflist)) {
        !            86:                i = LIST_FIRST(&p->obuflist);
        !            87:                abuf_eof(i);
        !            88:        }
        !            89:        DPRINTF("aproc_del: %s(%s): freed\n", p->ops->name, p->name);
1.1       ratchov    90:        free(p);
                     91: }
                     92:
                     93: void
                     94: aproc_setin(struct aproc *p, struct abuf *ibuf)
                     95: {
                     96:        LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
                     97:        ibuf->rproc = p;
                     98:        if (p->ops->newin)
                     99:                p->ops->newin(p, ibuf);
                    100: }
                    101:
                    102: void
                    103: aproc_setout(struct aproc *p, struct abuf *obuf)
                    104: {
                    105:        LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
                    106:        obuf->wproc = p;
                    107:        if (p->ops->newout)
                    108:                p->ops->newout(p, obuf);
                    109: }
                    110:
1.12    ! ratchov   111: void
        !           112: aproc_ipos(struct aproc *p, struct abuf *ibuf, int delta)
        !           113: {
        !           114:        struct abuf *obuf;
        !           115:
        !           116:        DPRINTFN(3, "aproc_ipos: %s: delta = %d\n", p->name, delta);
        !           117:
        !           118:        LIST_FOREACH(obuf, &p->obuflist, oent) {
        !           119:                abuf_ipos(obuf, delta);
        !           120:        }
        !           121: }
        !           122:
        !           123: void
        !           124: aproc_opos(struct aproc *p, struct abuf *obuf, int delta)
        !           125: {
        !           126:        struct abuf *ibuf;
        !           127:
        !           128:        DPRINTFN(3, "aproc_opos: %s: delta = %d\n", p->name, delta);
        !           129:
        !           130:        LIST_FOREACH(ibuf, &p->ibuflist, ient) {
        !           131:                abuf_opos(ibuf, delta);
        !           132:        }
        !           133: }
        !           134:
1.1       ratchov   135: int
                    136: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
                    137: {
                    138:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    139:        struct file *f = p->u.io.file;
                    140:        unsigned char *data;
                    141:        unsigned count;
                    142:
1.6       ratchov   143:        DPRINTFN(3, "rpipe_in: %s\n", p->name);
                    144:
1.12    ! ratchov   145:        if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
1.1       ratchov   146:                return 0;
                    147:        data = abuf_wgetblk(obuf, &count, 0);
1.6       ratchov   148:        count = file_read(f, data, count);
1.12    ! ratchov   149:        if (count == 0)
        !           150:                return 0;
1.6       ratchov   151:        abuf_wcommit(obuf, count);
1.12    ! ratchov   152:        if (!abuf_flush(obuf))
        !           153:                return 0;
        !           154:        return 1;
1.1       ratchov   155: }
                    156:
                    157: int
                    158: rpipe_out(struct aproc *p, struct abuf *obuf)
                    159: {
                    160:        struct file *f = p->u.io.file;
                    161:        unsigned char *data;
                    162:        unsigned count;
                    163:
1.12    ! ratchov   164:        if (f->refs > 0)
        !           165:                return 0;
1.6       ratchov   166:        DPRINTFN(3, "rpipe_out: %s\n", p->name);
1.12    ! ratchov   167:
        !           168:        if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
1.1       ratchov   169:                return 0;
                    170:        data = abuf_wgetblk(obuf, &count, 0);
1.6       ratchov   171:        count = file_read(f, data, count);
1.12    ! ratchov   172:        if (count == 0)
        !           173:                return 0;
1.6       ratchov   174:        abuf_wcommit(obuf, count);
1.12    ! ratchov   175:        return 1;
1.1       ratchov   176: }
                    177:
                    178: void
1.8       ratchov   179: rpipe_done(struct aproc *p)
1.1       ratchov   180: {
                    181:        struct file *f = p->u.io.file;
                    182:
                    183:        f->rproc = NULL;
1.12    ! ratchov   184:        if (f->wproc == NULL)
        !           185:                file_del(f);
1.1       ratchov   186: }
                    187:
                    188: void
                    189: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
                    190: {
                    191:        DPRINTFN(3, "rpipe_eof: %s\n", p->name);
1.8       ratchov   192:        aproc_del(p);
1.1       ratchov   193: }
                    194:
                    195: void
                    196: rpipe_hup(struct aproc *p, struct abuf *obuf)
                    197: {
                    198:        DPRINTFN(3, "rpipe_hup: %s\n", p->name);
1.8       ratchov   199:        aproc_del(p);
1.1       ratchov   200: }
                    201:
                    202: struct aproc_ops rpipe_ops = {
1.12    ! ratchov   203:        "rpipe",
        !           204:        rpipe_in,
        !           205:        rpipe_out,
        !           206:        rpipe_eof,
        !           207:        rpipe_hup,
        !           208:        NULL, /* newin */
        !           209:        NULL, /* newout */
        !           210:        aproc_ipos,
        !           211:        aproc_opos,
        !           212:        rpipe_done
1.1       ratchov   213: };
                    214:
                    215: struct aproc *
                    216: rpipe_new(struct file *f)
                    217: {
                    218:        struct aproc *p;
                    219:
                    220:        p = aproc_new(&rpipe_ops, f->name);
                    221:        p->u.io.file = f;
1.12    ! ratchov   222:        f->rproc = p;
1.1       ratchov   223:        return p;
                    224: }
                    225:
                    226: void
1.8       ratchov   227: wpipe_done(struct aproc *p)
1.1       ratchov   228: {
                    229:        struct file *f = p->u.io.file;
                    230:
                    231:        f->wproc = NULL;
1.12    ! ratchov   232:        if (f->rproc == NULL)
        !           233:                file_del(f);
1.1       ratchov   234: }
                    235:
                    236: int
                    237: wpipe_in(struct aproc *p, struct abuf *ibuf)
                    238: {
                    239:        struct file *f = p->u.io.file;
                    240:        unsigned char *data;
                    241:        unsigned count;
                    242:
1.12    ! ratchov   243:        if (f->refs > 0)
        !           244:                return 0;
1.6       ratchov   245:        DPRINTFN(3, "wpipe_in: %s\n", p->name);
                    246:
1.12    ! ratchov   247:        if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
1.1       ratchov   248:                return 0;
                    249:        data = abuf_rgetblk(ibuf, &count, 0);
                    250:        count = file_write(f, data, count);
1.12    ! ratchov   251:        if (count == 0)
        !           252:                return 0;
1.6       ratchov   253:        abuf_rdiscard(ibuf, count);
1.12    ! ratchov   254:        return 1;
1.1       ratchov   255: }
                    256:
                    257: int
                    258: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
                    259: {
                    260:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    261:        struct file *f = p->u.io.file;
                    262:        unsigned char *data;
                    263:        unsigned count;
                    264:
1.6       ratchov   265:        DPRINTFN(3, "wpipe_out: %s\n", p->name);
                    266:
1.12    ! ratchov   267:        if (!abuf_fill(ibuf)) {
        !           268:                DPRINTFN(3, "wpipe_out: fill failed\n");
        !           269:                return 0;
        !           270:        }
        !           271:        if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
1.1       ratchov   272:                return 0;
                    273:        data = abuf_rgetblk(ibuf, &count, 0);
1.12    ! ratchov   274:        if (count == 0) {
        !           275:                DPRINTF("wpipe_out: %s: underrun\n", p->name);
        !           276:                return 0;
        !           277:        }
1.1       ratchov   278:        count = file_write(f, data, count);
1.12    ! ratchov   279:        if (count == 0)
        !           280:                return 0;
1.6       ratchov   281:        abuf_rdiscard(ibuf, count);
1.1       ratchov   282:        return 1;
                    283: }
                    284:
                    285: void
                    286: wpipe_eof(struct aproc *p, struct abuf *ibuf)
                    287: {
                    288:        DPRINTFN(3, "wpipe_eof: %s\n", p->name);
1.8       ratchov   289:        aproc_del(p);
1.1       ratchov   290: }
                    291:
                    292: void
                    293: wpipe_hup(struct aproc *p, struct abuf *obuf_dummy)
                    294: {
                    295:        DPRINTFN(3, "wpipe_hup: %s\n", p->name);
1.8       ratchov   296:        aproc_del(p);
1.1       ratchov   297: }
                    298:
                    299: struct aproc_ops wpipe_ops = {
1.12    ! ratchov   300:        "wpipe",
        !           301:        wpipe_in,
        !           302:        wpipe_out,
        !           303:        wpipe_eof,
        !           304:        wpipe_hup,
        !           305:        NULL, /* newin */
        !           306:        NULL, /* newout */
        !           307:        aproc_ipos,
        !           308:        aproc_opos,
        !           309:        wpipe_done
1.1       ratchov   310: };
                    311:
                    312: struct aproc *
                    313: wpipe_new(struct file *f)
                    314: {
                    315:        struct aproc *p;
                    316:
                    317:        p = aproc_new(&wpipe_ops, f->name);
                    318:        p->u.io.file = f;
                    319:        f->wproc = p;
                    320:        return p;
                    321: }
                    322:
                    323: /*
                    324:  * Fill an output block with silence.
                    325:  */
                    326: void
                    327: mix_bzero(struct aproc *p)
                    328: {
                    329:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    330:        short *odata;
                    331:        unsigned ocount;
                    332:
1.6       ratchov   333:        DPRINTFN(4, "mix_bzero: used = %u, todo = %u\n",
1.1       ratchov   334:            obuf->used, obuf->mixtodo);
                    335:        odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo);
1.12    ! ratchov   336:        ocount -= ocount % obuf->bpf;
1.1       ratchov   337:        if (ocount == 0)
                    338:                return;
                    339:        memset(odata, 0, ocount);
                    340:        obuf->mixtodo += ocount;
                    341:        DPRINTFN(4, "mix_bzero: ocount %u, todo %u\n", ocount, obuf->mixtodo);
                    342: }
                    343:
                    344: /*
                    345:  * Mix an input block over an output block.
                    346:  */
                    347: void
                    348: mix_badd(struct abuf *ibuf, struct abuf *obuf)
                    349: {
                    350:        short *idata, *odata;
                    351:        unsigned i, scount, icount, ocount;
                    352:        int vol = ibuf->mixvol;
                    353:
1.6       ratchov   354:        DPRINTFN(4, "mix_badd: todo = %u, done = %u\n",
1.1       ratchov   355:            obuf->mixtodo, ibuf->mixdone);
                    356:
                    357:        idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
1.12    ! ratchov   358:        icount -= icount % ibuf->bpf;
1.1       ratchov   359:        if (icount == 0)
                    360:                return;
                    361:
                    362:        odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone);
1.12    ! ratchov   363:        ocount -= ocount % obuf->bpf;
1.1       ratchov   364:        if (ocount == 0)
                    365:                return;
                    366:
                    367:        scount = (icount < ocount) ? icount : ocount;
                    368:        for (i = scount / sizeof(short); i > 0; i--) {
                    369:                *odata += (*idata * vol) >> ADATA_SHIFT;
                    370:                idata++;
                    371:                odata++;
1.6       ratchov   372:        }
                    373:        abuf_rdiscard(ibuf, scount);
1.1       ratchov   374:        ibuf->mixdone += scount;
                    375:
1.6       ratchov   376:        DPRINTFN(4, "mix_badd: added %u, done = %u, todo = %u\n",
1.1       ratchov   377:            scount, ibuf->mixdone, obuf->mixtodo);
                    378: }
                    379:
                    380: int
                    381: mix_in(struct aproc *p, struct abuf *ibuf)
                    382: {
                    383:        struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
1.7       ratchov   384:        unsigned ocount;
1.1       ratchov   385:
1.7       ratchov   386:        DPRINTFN(4, "mix_in: used = %u, done = %u, todo = %u\n",
1.1       ratchov   387:            ibuf->used, ibuf->mixdone, obuf->mixtodo);
1.3       ratchov   388:
1.12    ! ratchov   389:        if (!ABUF_ROK(ibuf) || ibuf->mixdone == obuf->mixtodo)
1.1       ratchov   390:                return 0;
1.12    ! ratchov   391:
1.1       ratchov   392:        mix_badd(ibuf, obuf);
                    393:        ocount = obuf->mixtodo;
                    394:        LIST_FOREACH(i, &p->ibuflist, ient) {
                    395:                if (ocount > i->mixdone)
                    396:                        ocount = i->mixdone;
                    397:        }
                    398:        if (ocount == 0)
                    399:                return 0;
                    400:
1.6       ratchov   401:        abuf_wcommit(obuf, ocount);
1.12    ! ratchov   402:        p->u.mix.lat += ocount / obuf->bpf;
1.1       ratchov   403:        obuf->mixtodo -= ocount;
1.12    ! ratchov   404:        if (!abuf_flush(obuf))
        !           405:                return 0; /* hup */
1.1       ratchov   406:        mix_bzero(p);
1.12    ! ratchov   407:        for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
1.1       ratchov   408:                inext = LIST_NEXT(i, ient);
                    409:                i->mixdone -= ocount;
1.12    ! ratchov   410:                if (i->mixdone < obuf->mixtodo)
1.1       ratchov   411:                        mix_badd(i, obuf);
1.12    ! ratchov   412:                if (!abuf_fill(i))
        !           413:                        continue;
1.1       ratchov   414:        }
                    415:        return 1;
                    416: }
                    417:
                    418: int
                    419: mix_out(struct aproc *p, struct abuf *obuf)
                    420: {
                    421:        struct abuf *i, *inext;
1.3       ratchov   422:        unsigned ocount, drop;
1.1       ratchov   423:
1.6       ratchov   424:        DPRINTFN(4, "mix_out: used = %u, todo = %u\n",
1.1       ratchov   425:            obuf->used, obuf->mixtodo);
                    426:
1.12    ! ratchov   427:        if (!ABUF_WOK(obuf))
        !           428:                return 0;
        !           429:
1.1       ratchov   430:        mix_bzero(p);
                    431:        ocount = obuf->mixtodo;
1.12    ! ratchov   432:        for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
1.1       ratchov   433:                inext = LIST_NEXT(i, ient);
1.12    ! ratchov   434:                if (!abuf_fill(i))
        !           435:                        continue;
1.5       ratchov   436:                if (!ABUF_ROK(i)) {
                    437:                        if ((p->u.mix.flags & MIX_DROP) && i->mixdone == 0) {
                    438:                                if (i->xrun == XRUN_ERROR) {
                    439:                                        abuf_hup(i);
                    440:                                        continue;
                    441:                                }
                    442:                                drop = obuf->mixtodo;
                    443:                                i->mixdone += drop;
                    444:                                if (i->xrun == XRUN_SYNC)
1.7       ratchov   445:                                        i->drop += drop;
1.12    ! ratchov   446:                                else {
        !           447:                                        abuf_opos(i, -(int)(drop / i->bpf));
        !           448:                                        if (i->duplex) {
        !           449:                                                DPRINTF("mix_out: duplex %u\n",
        !           450:                                                    drop);
        !           451:                                                i->duplex->drop += drop *
        !           452:                                                    i->duplex->bpf / i->bpf;
        !           453:                                                abuf_ipos(i->duplex,
        !           454:                                                    -(int)(drop / i->bpf));
        !           455:                                        }
        !           456:                                }
1.7       ratchov   457:                                DPRINTF("mix_out: drop = %u\n", i->drop);
1.5       ratchov   458:                        }
1.3       ratchov   459:                } else
                    460:                        mix_badd(i, obuf);
1.1       ratchov   461:                if (ocount > i->mixdone)
                    462:                        ocount = i->mixdone;
                    463:        }
                    464:        if (ocount == 0)
                    465:                return 0;
1.9       ratchov   466:        if (LIST_EMPTY(&p->ibuflist) && (p->u.mix.flags & MIX_AUTOQUIT)) {
1.1       ratchov   467:                DPRINTF("mix_out: nothing more to do...\n");
                    468:                aproc_del(p);
                    469:                return 0;
                    470:        }
1.6       ratchov   471:        abuf_wcommit(obuf, ocount);
1.12    ! ratchov   472:        p->u.mix.lat += ocount / obuf->bpf;
1.1       ratchov   473:        obuf->mixtodo -= ocount;
                    474:        LIST_FOREACH(i, &p->ibuflist, ient) {
                    475:                i->mixdone -= ocount;
                    476:        }
                    477:        return 1;
                    478: }
                    479:
                    480: void
                    481: mix_eof(struct aproc *p, struct abuf *ibuf)
                    482: {
                    483:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    484:
                    485:        DPRINTF("mix_eof: %s: detached\n", p->name);
1.12    ! ratchov   486:        mix_setmaster(p);
        !           487:
1.1       ratchov   488:        /*
                    489:         * If there's no more inputs, abuf_run() will trigger the eof
                    490:         * condition and propagate it, so no need to handle it here.
                    491:         */
                    492:        abuf_run(obuf);
                    493:        DPRINTF("mix_eof: done\n");
                    494: }
                    495:
                    496: void
                    497: mix_hup(struct aproc *p, struct abuf *obuf)
                    498: {
                    499:        struct abuf *ibuf;
                    500:
                    501:        while (!LIST_EMPTY(&p->ibuflist)) {
                    502:                ibuf = LIST_FIRST(&p->ibuflist);
                    503:                abuf_hup(ibuf);
                    504:        }
                    505:        DPRINTF("mix_hup: %s: done\n", p->name);
                    506:        aproc_del(p);
                    507: }
                    508:
                    509: void
                    510: mix_newin(struct aproc *p, struct abuf *ibuf)
                    511: {
                    512:        ibuf->mixdone = 0;
                    513:        ibuf->mixvol = ADATA_UNIT;
1.5       ratchov   514:        ibuf->xrun = XRUN_IGNORE;
1.12    ! ratchov   515:        mix_setmaster(p);
1.1       ratchov   516: }
                    517:
                    518: void
                    519: mix_newout(struct aproc *p, struct abuf *obuf)
                    520: {
                    521:        obuf->mixtodo = 0;
                    522:        mix_bzero(p);
                    523: }
                    524:
1.12    ! ratchov   525: void
        !           526: mix_opos(struct aproc *p, struct abuf *obuf, int delta)
        !           527: {
        !           528:        DPRINTFN(3, "mix_opos: lat = %d/%d\n", p->u.mix.lat, p->u.mix.maxlat);
        !           529:        p->u.mix.lat -= delta;
        !           530:        aproc_opos(p, obuf, delta);
        !           531: }
        !           532:
1.1       ratchov   533: struct aproc_ops mix_ops = {
1.12    ! ratchov   534:        "mix",
        !           535:        mix_in,
        !           536:        mix_out,
        !           537:        mix_eof,
        !           538:        mix_hup,
        !           539:        mix_newin,
        !           540:        mix_newout,
        !           541:        aproc_ipos,
        !           542:        mix_opos,
        !           543:        NULL
1.1       ratchov   544: };
                    545:
                    546: struct aproc *
1.12    ! ratchov   547: mix_new(char *name, int maxlat)
1.1       ratchov   548: {
                    549:        struct aproc *p;
                    550:
1.12    ! ratchov   551:        p = aproc_new(&mix_ops, name);
1.5       ratchov   552:        p->u.mix.flags = 0;
1.12    ! ratchov   553:        p->u.mix.lat = 0;
        !           554:        p->u.mix.maxlat = maxlat;
1.1       ratchov   555:        return p;
1.10      ratchov   556: }
                    557:
                    558: void
                    559: mix_pushzero(struct aproc *p)
                    560: {
                    561:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    562:
                    563:        abuf_wcommit(obuf, obuf->mixtodo);
1.12    ! ratchov   564:        p->u.mix.lat += obuf->mixtodo / obuf->bpf;
1.10      ratchov   565:        obuf->mixtodo = 0;
1.11      ratchov   566:        abuf_run(obuf);
1.10      ratchov   567:        mix_bzero(p);
                    568: }
                    569:
                    570: /*
                    571:  * Normalize input levels
                    572:  */
                    573: void
                    574: mix_setmaster(struct aproc *p)
                    575: {
                    576:        unsigned n;
                    577:        struct abuf *buf;
                    578:
                    579:        n = 0;
                    580:        LIST_FOREACH(buf, &p->ibuflist, ient)
                    581:            n++;
                    582:        LIST_FOREACH(buf, &p->ibuflist, ient)
                    583:            buf->mixvol = ADATA_UNIT / n;
1.1       ratchov   584: }
                    585:
                    586: /*
                    587:  * Copy data from ibuf to obuf.
                    588:  */
                    589: void
                    590: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
                    591: {
                    592:        unsigned char *idata, *odata;
                    593:        unsigned icount, ocount, scount;
                    594:
                    595:        idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
1.12    ! ratchov   596:        icount -= icount % ibuf->bpf;
1.1       ratchov   597:        if (icount == 0)
                    598:                return;
                    599:        odata = abuf_wgetblk(obuf, &ocount, 0);
1.12    ! ratchov   600:        ocount -= icount % obuf->bpf;
1.1       ratchov   601:        if (ocount == 0)
                    602:                return;
                    603:        scount = (icount < ocount) ? icount : ocount;
                    604:        memcpy(odata, idata, scount);
1.12    ! ratchov   605:        abuf_wcommit(obuf, scount);
1.1       ratchov   606:        obuf->subdone += scount;
                    607:        DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
                    608: }
                    609:
                    610: int
                    611: sub_in(struct aproc *p, struct abuf *ibuf)
                    612: {
                    613:        struct abuf *i, *inext;
1.3       ratchov   614:        unsigned done, drop;
1.12    ! ratchov   615:
        !           616:        if (!ABUF_ROK(ibuf))
        !           617:                return 0;
1.1       ratchov   618:        done = ibuf->used;
1.12    ! ratchov   619:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
1.1       ratchov   620:                inext = LIST_NEXT(i, oent);
1.5       ratchov   621:                if (!ABUF_WOK(i)) {
                    622:                        if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) {
                    623:                                if (i->xrun == XRUN_ERROR) {
                    624:                                        abuf_eof(i);
                    625:                                        continue;
                    626:                                }
                    627:                                drop = ibuf->used;
                    628:                                if (i->xrun == XRUN_SYNC)
1.7       ratchov   629:                                        i->silence += drop;
1.12    ! ratchov   630:                                else {
        !           631:                                        abuf_ipos(i, -(int)(drop / i->bpf));
        !           632:                                        if (i->duplex) {
        !           633:                                                DPRINTF("sub_in: duplex %u\n",
        !           634:                                                    drop);
        !           635:                                                i->duplex->silence += drop *
        !           636:                                                    i->duplex->bpf / i->bpf;
        !           637:                                                abuf_opos(i->duplex,
        !           638:                                                    -(int)(drop / i->bpf));
        !           639:                                        }
        !           640:                                }
1.5       ratchov   641:                                i->subdone += drop;
1.12    ! ratchov   642:                                DPRINTF("sub_in: silence = %u\n", i->silence);
1.5       ratchov   643:                        }
1.12    ! ratchov   644:                } else
1.1       ratchov   645:                        sub_bcopy(ibuf, i);
                    646:                if (done > i->subdone)
                    647:                        done = i->subdone;
1.12    ! ratchov   648:                if (!abuf_flush(i))
        !           649:                        continue;
1.1       ratchov   650:        }
                    651:        LIST_FOREACH(i, &p->obuflist, oent) {
                    652:                i->subdone -= done;
                    653:        }
1.6       ratchov   654:        abuf_rdiscard(ibuf, done);
1.12    ! ratchov   655:        p->u.sub.lat -= done / ibuf->bpf;
        !           656:        return 1;
1.1       ratchov   657: }
                    658:
                    659: int
                    660: sub_out(struct aproc *p, struct abuf *obuf)
                    661: {
                    662:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    663:        struct abuf *i, *inext;
                    664:        unsigned done;
                    665:
1.12    ! ratchov   666:        if (!ABUF_WOK(obuf))
        !           667:                return 0;
        !           668:        if (!abuf_fill(ibuf)) {
        !           669:                return 0;
        !           670:        }
        !           671:        if (obuf->subdone == ibuf->used)
1.1       ratchov   672:                return 0;
                    673:
                    674:        done = ibuf->used;
1.12    ! ratchov   675:        for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
        !           676:                inext = LIST_NEXT(i, oent);
        !           677:                if (!abuf_flush(i))
        !           678:                        continue;
        !           679:                sub_bcopy(ibuf, i);
1.1       ratchov   680:                if (done > i->subdone)
                    681:                        done = i->subdone;
                    682:        }
                    683:        LIST_FOREACH(i, &p->obuflist, oent) {
                    684:                i->subdone -= done;
                    685:        }
1.6       ratchov   686:        abuf_rdiscard(ibuf, done);
1.12    ! ratchov   687:        p->u.sub.lat -= done / ibuf->bpf;
1.1       ratchov   688:        return 1;
                    689: }
                    690:
                    691: void
                    692: sub_eof(struct aproc *p, struct abuf *ibuf)
                    693: {
                    694:        struct abuf *obuf;
                    695:
                    696:        while (!LIST_EMPTY(&p->obuflist)) {
                    697:                obuf = LIST_FIRST(&p->obuflist);
                    698:                abuf_eof(obuf);
                    699:        }
1.8       ratchov   700:        aproc_del(p);
1.1       ratchov   701: }
                    702:
                    703: void
                    704: sub_hup(struct aproc *p, struct abuf *obuf)
                    705: {
                    706:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    707:
                    708:        DPRINTF("sub_hup: %s: detached\n", p->name);
1.12    ! ratchov   709:        abuf_run(ibuf);
1.1       ratchov   710:        DPRINTF("sub_hup: done\n");
                    711: }
                    712:
                    713: void
                    714: sub_newout(struct aproc *p, struct abuf *obuf)
                    715: {
                    716:        obuf->subdone = 0;
1.5       ratchov   717:        obuf->xrun = XRUN_IGNORE;
1.1       ratchov   718: }
                    719:
1.12    ! ratchov   720: void
        !           721: sub_ipos(struct aproc *p, struct abuf *ibuf, int delta)
        !           722: {
        !           723:        p->u.sub.lat += delta;
        !           724:        DPRINTFN(3, "sub_ipos: lat = %d/%d\n", p->u.sub.lat, p->u.sub.maxlat);
        !           725:        aproc_ipos(p, ibuf, delta);
        !           726: }
        !           727:
1.1       ratchov   728: struct aproc_ops sub_ops = {
1.12    ! ratchov   729:        "sub",
        !           730:        sub_in,
        !           731:        sub_out,
        !           732:        sub_eof,
        !           733:        sub_hup,
        !           734:        NULL,
        !           735:        sub_newout,
        !           736:        sub_ipos,
        !           737:        aproc_opos,
        !           738:        NULL
1.1       ratchov   739: };
                    740:
                    741: struct aproc *
1.12    ! ratchov   742: sub_new(char *name, int maxlat)
1.1       ratchov   743: {
                    744:        struct aproc *p;
                    745:
1.12    ! ratchov   746:        p = aproc_new(&sub_ops, name);
1.5       ratchov   747:        p->u.sub.flags = 0;
1.12    ! ratchov   748:        p->u.sub.lat = 0;
        !           749:        p->u.sub.maxlat = maxlat;
1.1       ratchov   750:        return p;
                    751: }
                    752:
                    753: /*
                    754:  * Convert one block.
                    755:  */
                    756: void
                    757: conv_bcopy(struct aconv *ist, struct aconv *ost,
                    758:     struct abuf *ibuf, struct abuf *obuf)
                    759: {
                    760:        int *ictx;
                    761:        unsigned inch, ibps;
                    762:        unsigned char *idata;
                    763:        int ibnext, isigbit;
                    764:        unsigned ishift;
                    765:        int isnext;
                    766:        unsigned ipos, orate;
                    767:        unsigned ifr;
                    768:        int *octx;
                    769:        unsigned onch, oshift;
                    770:        int osigbit;
                    771:        unsigned obps;
                    772:        unsigned char *odata;
                    773:        int obnext, osnext;
                    774:        unsigned opos, irate;
                    775:        unsigned ofr;
                    776:        unsigned c, i;
                    777:        int s, *ctx;
                    778:        unsigned icount, ocount;
                    779:
                    780:        /*
                    781:         * It's ok to have s uninitialized, but we dont want the compiler to
                    782:         * complain about it.
                    783:         */
                    784:        s = (int)0xdeadbeef;
                    785:
                    786:        /*
                    787:         * Calculate max frames readable at once from the input buffer.
                    788:         */
                    789:        idata = abuf_rgetblk(ibuf, &icount, 0);
                    790:        ifr = icount / ibuf->bpf;
1.12    ! ratchov   791:        icount = ifr * ibuf->bpf;
1.1       ratchov   792:
                    793:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    794:        ofr = ocount / obuf->bpf;
1.12    ! ratchov   795:        ocount = ofr * obuf->bpf;
1.1       ratchov   796:
                    797:        /*
                    798:         * Partially copy structures into local variables, to avoid
                    799:         * unnecessary indirections; this also allows the compiler to
                    800:         * order local variables more "cache-friendly".
                    801:         */
                    802:        ictx = ist->ctx + ist->cmin;
                    803:        octx = ist->ctx + ost->cmin;
                    804:        inch = ist->nch;
                    805:        ibps = ist->bps;
                    806:        ibnext = ist->bnext;
                    807:        isigbit = ist->sigbit;
                    808:        ishift = ist->shift;
                    809:        isnext = ist->snext;
                    810:        ipos = ist->pos;
                    811:        irate = ist->rate;
                    812:        onch = ost->nch;
                    813:        oshift = ost->shift;
                    814:        osigbit = ost->sigbit;
                    815:        obps = ost->bps;
                    816:        obnext = ost->bnext;
                    817:        osnext = ost->snext;
                    818:        opos = ost->pos;
                    819:        orate = ost->rate;
                    820:
                    821:        /*
                    822:         * Start conversion.
                    823:         */
                    824:        idata += ist->bfirst;
                    825:        odata += ost->bfirst;
                    826:        DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
                    827:        for (;;) {
                    828:                if ((int)(ipos - opos) > 0) {
                    829:                        if (ofr == 0)
                    830:                                break;
                    831:                        ctx = octx;
                    832:                        for (c = onch; c > 0; c--) {
                    833:                                s = *ctx++ << 16;
                    834:                                s >>= oshift;
                    835:                                s ^= osigbit;
                    836:                                for (i = obps; i > 0; i--) {
                    837:                                        *odata = (unsigned char)s;
                    838:                                        s >>= 8;
                    839:                                        odata += obnext;
                    840:                                }
                    841:                                odata += osnext;
                    842:                        }
                    843:                        opos += irate;
                    844:                        ofr--;
                    845:                } else {
                    846:                        if (ifr == 0)
                    847:                                break;
                    848:                        ctx = ictx;
                    849:                        for (c = inch; c > 0; c--) {
                    850:                                for (i = ibps; i > 0; i--) {
                    851:                                        s <<= 8;
                    852:                                        s |= *idata;
                    853:                                        idata += ibnext;
                    854:                                }
                    855:                                s ^= isigbit;
                    856:                                s <<= ishift;
                    857:                                *ctx++ = (short)(s >> 16);
                    858:                                idata += isnext;
                    859:                        }
                    860:                        ipos += orate;
                    861:                        ifr--;
                    862:                }
                    863:        }
                    864:        ist->pos = ipos;
                    865:        ost->pos = opos;
                    866:        DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
                    867:
                    868:        /*
                    869:         * Update FIFO pointers.
                    870:         */
                    871:        icount -= ifr * ist->bpf;
                    872:        ocount -= ofr * ost->bpf;
1.6       ratchov   873:        abuf_rdiscard(ibuf, icount);
                    874:        abuf_wcommit(obuf, ocount);
1.1       ratchov   875: }
                    876:
                    877: int
                    878: conv_in(struct aproc *p, struct abuf *ibuf)
                    879: {
                    880:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    881:
1.12    ! ratchov   882:        DPRINTFN(4, "conv_in: %s\n", p->name);
        !           883:
        !           884:        if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1.1       ratchov   885:                return 0;
                    886:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
1.12    ! ratchov   887:        if (!abuf_flush(obuf))
        !           888:                return 0;
        !           889:        return 1;
1.1       ratchov   890: }
                    891:
                    892: int
                    893: conv_out(struct aproc *p, struct abuf *obuf)
                    894: {
                    895:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    896:
1.12    ! ratchov   897:        DPRINTFN(4, "conv_out: %s\n", p->name);
        !           898:
        !           899:        if (!abuf_fill(ibuf))
        !           900:                return 0;
        !           901:        if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
1.1       ratchov   902:                return 0;
                    903:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
                    904:        return 1;
                    905: }
                    906:
                    907: void
                    908: conv_eof(struct aproc *p, struct abuf *ibuf)
                    909: {
1.12    ! ratchov   910:        DPRINTFN(4, "conv_eof: %s\n", p->name);
        !           911:
1.8       ratchov   912:        aproc_del(p);
1.1       ratchov   913: }
                    914:
                    915: void
                    916: conv_hup(struct aproc *p, struct abuf *obuf)
                    917: {
1.12    ! ratchov   918:        DPRINTFN(4, "conv_hup: %s\n", p->name);
        !           919:
1.8       ratchov   920:        aproc_del(p);
1.1       ratchov   921: }
                    922:
                    923: void
                    924: aconv_init(struct aconv *st, struct aparams *par, int input)
                    925: {
                    926:        unsigned i;
                    927:
                    928:        st->bps = par->bps;
                    929:        st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
                    930:        if (par->msb) {
                    931:                st->shift = 32 - par->bps * 8;
                    932:        } else {
                    933:                st->shift = 32 - par->bits;
                    934:        }
                    935:        if ((par->le && input) || (!par->le && !input)) {
                    936:                st->bfirst = st->bps - 1;
                    937:                st->bnext = -1;
                    938:                st->snext = 2 * st->bps;
                    939:        } else {
                    940:                st->bfirst = 0;
                    941:                st->bnext = 1;
                    942:                st->snext = 0;
                    943:        }
                    944:        st->cmin = par->cmin;
                    945:        st->nch = par->cmax - par->cmin + 1;
                    946:        st->bpf = st->nch * st->bps;
                    947:        st->rate = par->rate;
                    948:        st->pos = 0;
                    949:
1.12    ! ratchov   950:        for (i = 0; i < NCHAN_MAX; i++)
1.1       ratchov   951:                st->ctx[i] = 0;
                    952: }
                    953:
1.12    ! ratchov   954: void
        !           955: conv_ipos(struct aproc *p, struct abuf *ibuf, int delta)
        !           956: {
        !           957:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
        !           958:        long long ipos;
        !           959:        int ifac, ofac;
        !           960:
        !           961:        DPRINTFN(3, "conv_ipos: %d\n", delta);
        !           962:
        !           963:        ifac = p->u.conv.ist.rate;
        !           964:        ofac = p->u.conv.ost.rate;
        !           965:        ipos = p->u.conv.idelta + (long long)delta * ofac;
        !           966:        delta = (ipos + ifac - 1) / ifac;
        !           967:        p->u.conv.idelta = ipos - (long long)delta * ifac;
        !           968:        abuf_ipos(obuf, delta);
        !           969: }
        !           970:
        !           971: void
        !           972: conv_opos(struct aproc *p, struct abuf *obuf, int delta)
        !           973: {
        !           974:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
        !           975:        long long opos;
        !           976:        int ifac, ofac;
        !           977:
        !           978:        DPRINTFN(3, "conv_opos: %d\n", delta);
        !           979:
        !           980:        ifac = p->u.conv.ist.rate;
        !           981:        ofac = p->u.conv.ost.rate;
        !           982:        opos = p->u.conv.odelta + (long long)delta * ifac;
        !           983:        delta = (opos + ofac - 1) / ofac;
        !           984:        p->u.conv.odelta = opos - (long long)delta * ofac;
        !           985:        abuf_opos(ibuf, delta);
        !           986: }
        !           987:
1.1       ratchov   988: struct aproc_ops conv_ops = {
1.12    ! ratchov   989:        "conv",
        !           990:        conv_in,
        !           991:        conv_out,
        !           992:        conv_eof,
        !           993:        conv_hup,
        !           994:        NULL,
        !           995:        NULL,
        !           996:        conv_ipos,
        !           997:        conv_opos,
        !           998:        NULL
1.1       ratchov   999: };
                   1000:
                   1001: struct aproc *
                   1002: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
                   1003: {
                   1004:        struct aproc *p;
                   1005:
                   1006:        p = aproc_new(&conv_ops, name);
                   1007:        aconv_init(&p->u.conv.ist, ipar, 1);
                   1008:        aconv_init(&p->u.conv.ost, opar, 0);
1.12    ! ratchov  1009:        p->u.conv.idelta = 0;
        !          1010:        p->u.conv.odelta = 0;
        !          1011:        if (debug_level > 0) {
        !          1012:                DPRINTF("conv_new: %s: ", p->name);
        !          1013:                aparams_print2(ipar, opar);
        !          1014:                DPRINTF("\n");
        !          1015:        }
1.1       ratchov  1016:        return p;
                   1017: }