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

1.4     ! ratchov     1: /*     $OpenBSD: aproc.c,v 1.3 2008/06/02 17:03:25 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) handle underruns in rpipe and mix
                     41:  *
                     42:  *     (hard) handle overruns in wpipe and sub
                     43:  *
                     44:  *     (hard) add a lowpass filter for the resampler. Quality is
                     45:  *     not acceptable as is.
                     46:  */
                     47: #include <err.h>
                     48: #include <limits.h>
                     49: #include <stdio.h>
                     50: #include <stdlib.h>
                     51: #include <string.h>
                     52:
                     53: #include "conf.h"
                     54: #include "aparams.h"
                     55: #include "abuf.h"
                     56: #include "aproc.h"
                     57: #include "file.h"
                     58:
                     59: struct aproc *
                     60: aproc_new(struct aproc_ops *ops, char *name)
                     61: {
                     62:        struct aproc *p;
                     63:
                     64:        p = malloc(sizeof(struct aproc));
                     65:        if (p == NULL)
                     66:                err(1, name);
                     67:        LIST_INIT(&p->ibuflist);
                     68:        LIST_INIT(&p->obuflist);
                     69:        p->name = name;
                     70:        p->ops = ops;
                     71:        return p;
                     72: }
                     73:
                     74: void
                     75: aproc_del(struct aproc *p)
                     76: {
                     77:        DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
                     78:        free(p);
                     79: }
                     80:
                     81: void
                     82: aproc_setin(struct aproc *p, struct abuf *ibuf)
                     83: {
                     84:        LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
                     85:        ibuf->rproc = p;
                     86:        if (p->ops->newin)
                     87:                p->ops->newin(p, ibuf);
                     88: }
                     89:
                     90: void
                     91: aproc_setout(struct aproc *p, struct abuf *obuf)
                     92: {
                     93:        LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
                     94:        obuf->wproc = p;
                     95:        if (p->ops->newout)
                     96:                p->ops->newout(p, obuf);
                     97: }
                     98:
                     99: int
                    100: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
                    101: {
                    102:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    103:        struct file *f = p->u.io.file;
                    104:        unsigned char *data;
                    105:        unsigned count;
                    106:
                    107:        if (ABUF_FULL(obuf))
                    108:                return 0;
                    109:        data = abuf_wgetblk(obuf, &count, 0);
                    110:        obuf->used += file_read(f, data, count);
                    111:        abuf_flush(obuf);
                    112:        return !ABUF_FULL(obuf);
                    113: }
                    114:
                    115: int
                    116: rpipe_out(struct aproc *p, struct abuf *obuf)
                    117: {
                    118:        struct file *f = p->u.io.file;
                    119:        unsigned char *data;
                    120:        unsigned count;
                    121:
                    122:        if (!(f->state & FILE_ROK))
                    123:                return 0;
                    124:        data = abuf_wgetblk(obuf, &count, 0);
                    125:        obuf->used += file_read(f, data, count);
                    126:        return f->state & FILE_ROK;
                    127: }
                    128:
                    129: void
                    130: rpipe_del(struct aproc *p)
                    131: {
                    132:        struct file *f = p->u.io.file;
                    133:
                    134:        f->rproc = NULL;
                    135:        f->events &= ~POLLIN;
                    136:        aproc_del(p);
                    137: }
                    138:
                    139: void
                    140: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
                    141: {
                    142:        DPRINTFN(3, "rpipe_eof: %s\n", p->name);
                    143:        abuf_eof(LIST_FIRST(&p->obuflist));
                    144:        rpipe_del(p);
                    145: }
                    146:
                    147: void
                    148: rpipe_hup(struct aproc *p, struct abuf *obuf)
                    149: {
                    150:        DPRINTFN(3, "rpipe_hup: %s\n", p->name);
                    151:        rpipe_del(p);
                    152: }
                    153:
                    154: struct aproc_ops rpipe_ops = {
                    155:        "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL
                    156: };
                    157:
                    158: struct aproc *
                    159: rpipe_new(struct file *f)
                    160: {
                    161:        struct aproc *p;
                    162:
                    163:        p = aproc_new(&rpipe_ops, f->name);
                    164:        p->u.io.file = f;
                    165:        f->rproc = p;
                    166:        f->events |= POLLIN;
                    167:        return p;
                    168: }
                    169:
                    170: void
                    171: wpipe_del(struct aproc *p)
                    172: {
                    173:        struct file *f = p->u.io.file;
                    174:
                    175:        f->wproc = NULL;
                    176:        f->events &= ~POLLOUT;
                    177:        aproc_del(p);
                    178: }
                    179:
                    180: int
                    181: wpipe_in(struct aproc *p, struct abuf *ibuf)
                    182: {
                    183:        struct file *f = p->u.io.file;
                    184:        unsigned char *data;
                    185:        unsigned count;
                    186:
                    187:        if (!(f->state & FILE_WOK))
                    188:                return 0;
                    189:
                    190:        data = abuf_rgetblk(ibuf, &count, 0);
                    191:        count = file_write(f, data, count);
                    192:        ibuf->used -= count;
                    193:        ibuf->start += count;
                    194:        if (ibuf->start >= ibuf->len)
                    195:                ibuf->start -= ibuf->len;
                    196:        return f->state & FILE_WOK;
                    197: }
                    198:
                    199: int
                    200: wpipe_out(struct aproc *p, struct abuf *obuf_dummy)
                    201: {
                    202:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    203:        struct file *f = p->u.io.file;
                    204:        unsigned char *data;
                    205:        unsigned count;
                    206:
                    207:        if (ABUF_EMPTY(ibuf))
                    208:                return 0;
                    209:        data = abuf_rgetblk(ibuf, &count, 0);
                    210:        count = file_write(f, data, count);
                    211:        ibuf->used -= count;
                    212:        ibuf->start += count;
                    213:        if (ibuf->start >= ibuf->len)
                    214:                ibuf->start -= ibuf->len;
                    215:        if (ABUF_EOF(ibuf)) {
                    216:                abuf_hup(ibuf);
                    217:                wpipe_del(p);
                    218:                return 0;
                    219:        }
                    220:        abuf_fill(ibuf);
                    221:        return 1;
                    222: }
                    223:
                    224: void
                    225: wpipe_eof(struct aproc *p, struct abuf *ibuf)
                    226: {
                    227:        DPRINTFN(3, "wpipe_eof: %s\n", p->name);
                    228:        wpipe_del(p);
                    229: }
                    230:
                    231: void
                    232: wpipe_hup(struct aproc *p, struct abuf *obuf_dummy)
                    233: {
                    234:        DPRINTFN(3, "wpipe_hup: %s\n", p->name);
                    235:        abuf_hup(LIST_FIRST(&p->ibuflist));
                    236:        wpipe_del(p);
                    237: }
                    238:
                    239: struct aproc_ops wpipe_ops = {
                    240:        "wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL
                    241: };
                    242:
                    243: struct aproc *
                    244: wpipe_new(struct file *f)
                    245: {
                    246:        struct aproc *p;
                    247:
                    248:        p = aproc_new(&wpipe_ops, f->name);
                    249:        p->u.io.file = f;
                    250:        f->wproc = p;
                    251:        f->events |= POLLOUT;
                    252:        return p;
                    253: }
                    254:
                    255: /*
                    256:  * Fill an output block with silence.
                    257:  */
                    258: void
                    259: mix_bzero(struct aproc *p)
                    260: {
                    261:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    262:        short *odata;
                    263:        unsigned ocount;
                    264:
                    265:        DPRINTFN(4, "mix_bzero: used = %u, zero = %u\n",
                    266:            obuf->used, obuf->mixtodo);
                    267:        odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->mixtodo);
                    268:        if (ocount == 0)
                    269:                return;
                    270:        memset(odata, 0, ocount);
                    271:        obuf->mixtodo += ocount;
                    272:        DPRINTFN(4, "mix_bzero: ocount %u, todo %u\n", ocount, obuf->mixtodo);
                    273: }
                    274:
                    275: /*
                    276:  * Mix an input block over an output block.
                    277:  */
                    278: void
                    279: mix_badd(struct abuf *ibuf, struct abuf *obuf)
                    280: {
                    281:        short *idata, *odata;
                    282:        unsigned i, scount, icount, ocount;
                    283:        int vol = ibuf->mixvol;
                    284:
                    285:        DPRINTFN(4, "mix_badd: zero = %u, done = %u\n",
                    286:            obuf->mixtodo, ibuf->mixdone);
                    287:
                    288:        idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
                    289:        if (icount == 0)
                    290:                return;
                    291:
                    292:        odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->mixdone);
                    293:        if (ocount == 0)
                    294:                return;
                    295:
                    296:        scount = (icount < ocount) ? icount : ocount;
                    297:        for (i = scount / sizeof(short); i > 0; i--) {
                    298:                *odata += (*idata * vol) >> ADATA_SHIFT;
                    299:                idata++;
                    300:                odata++;
                    301:        }
                    302:
                    303:        ibuf->used -= scount;
                    304:        ibuf->mixdone += scount;
                    305:        ibuf->start += scount;
                    306:        if (ibuf->start >= ibuf->len)
                    307:                ibuf->start -= ibuf->len;
                    308:
                    309:        DPRINTFN(4, "mix_badd: added %u, done = %u, zero = %u\n",
                    310:            scount, ibuf->mixdone, obuf->mixtodo);
                    311: }
                    312:
                    313: /*
                    314:  * Remove an input stream from the mixer.
                    315:  */
                    316: void
                    317: mix_rm(struct aproc *p, struct abuf *ibuf)
                    318: {
                    319:        LIST_REMOVE(ibuf, ient);
                    320:        DPRINTF("mix_rm: %s\n", p->name);
                    321: }
                    322:
                    323: int
                    324: mix_in(struct aproc *p, struct abuf *ibuf)
                    325: {
                    326:        struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
1.3       ratchov   327:        unsigned icount, ocount;
1.1       ratchov   328:
                    329:        DPRINTFN(4, "mix_in: used = %u, done = %u, zero = %u\n",
                    330:            ibuf->used, ibuf->mixdone, obuf->mixtodo);
                    331:
1.3       ratchov   332:        /*
                    333:         * discard data already sent as silence
                    334:         */
                    335:        if (ibuf->mixdrop > 0) {
                    336:                icount = ibuf->mixdrop;
                    337:                if (icount > ibuf->used)
                    338:                        icount = ibuf->used;
                    339:                ibuf->used -= icount;
                    340:                ibuf->start += icount;
                    341:                if (ibuf->start >= ibuf->len)
                    342:                        ibuf->start -= ibuf->len;
                    343:                ibuf->mixdrop -= icount;
                    344:                DPRINTF("mix_in: catched xruns, drop = %u\n", ibuf->mixdrop);
                    345:        }
                    346:
1.1       ratchov   347:        if (ibuf->mixdone >= obuf->mixtodo)
                    348:                return 0;
                    349:        mix_badd(ibuf, obuf);
                    350:        ocount = obuf->mixtodo;
                    351:        LIST_FOREACH(i, &p->ibuflist, ient) {
                    352:                if (ocount > i->mixdone)
                    353:                        ocount = i->mixdone;
                    354:        }
                    355:        if (ocount == 0)
                    356:                return 0;
                    357:
                    358:        obuf->used += ocount;
                    359:        obuf->mixtodo -= ocount;
                    360:        abuf_flush(obuf);
                    361:        mix_bzero(p);
1.2       ratchov   362:        for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1       ratchov   363:                inext = LIST_NEXT(i, ient);
                    364:                i->mixdone -= ocount;
                    365:                if (i != ibuf && i->mixdone < obuf->mixtodo) {
                    366:                        if (ABUF_EOF(i)) {
                    367:                                mix_rm(p, i);
                    368:                                abuf_hup(i);
                    369:                                continue;
                    370:                        }
                    371:                        mix_badd(i, obuf);
                    372:                        abuf_fill(i);
                    373:                }
                    374:        }
                    375:        return 1;
                    376: }
                    377:
                    378: int
                    379: mix_out(struct aproc *p, struct abuf *obuf)
                    380: {
                    381:        struct abuf *i, *inext;
1.3       ratchov   382:        unsigned ocount, drop;
1.1       ratchov   383:
                    384:        DPRINTFN(4, "mix_out: used = %u, zero = %u\n",
                    385:            obuf->used, obuf->mixtodo);
                    386:
                    387:        mix_bzero(p);
                    388:        ocount = obuf->mixtodo;
1.2       ratchov   389:        for (i = LIST_FIRST(&p->ibuflist); i != LIST_END(&p->ibuflist); i = inext) {
1.1       ratchov   390:                inext = LIST_NEXT(i, ient);
1.3       ratchov   391:                if (!ABUF_ROK(i) && i->mixdone == 0) {
                    392:                        drop = obuf->mixtodo;
                    393:                        i->mixdone += drop;
                    394:                        i->mixdrop += drop;
                    395:                        DPRINTF("mix_out: xrun, drop = %u\n", i->mixdrop);
                    396:                } else
                    397:                        mix_badd(i, obuf);
1.1       ratchov   398:                if (ocount > i->mixdone)
                    399:                        ocount = i->mixdone;
                    400:                if (ABUF_EOF(i)) {
                    401:                        mix_rm(p, i);
                    402:                        abuf_hup(i);
                    403:                        continue;
                    404:                }
                    405:                abuf_fill(i);
                    406:        }
                    407:        if (ocount == 0)
                    408:                return 0;
                    409:        if (LIST_EMPTY(&p->ibuflist)) {
                    410:                DPRINTF("mix_out: nothing more to do...\n");
                    411:                obuf->wproc = NULL;
                    412:                aproc_del(p);
                    413:                return 0;
                    414:        }
                    415:        obuf->used += ocount;
                    416:        obuf->mixtodo -= ocount;
                    417:        LIST_FOREACH(i, &p->ibuflist, ient) {
                    418:                i->mixdone -= ocount;
                    419:        }
                    420:        return 1;
                    421: }
                    422:
                    423: void
                    424: mix_eof(struct aproc *p, struct abuf *ibuf)
                    425: {
                    426:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    427:
                    428:        DPRINTF("mix_eof: %s: detached\n", p->name);
                    429:        mix_rm(p, ibuf);
                    430:        /*
                    431:         * If there's no more inputs, abuf_run() will trigger the eof
                    432:         * condition and propagate it, so no need to handle it here.
                    433:         */
                    434:        abuf_run(obuf);
                    435:        DPRINTF("mix_eof: done\n");
                    436: }
                    437:
                    438: void
                    439: mix_hup(struct aproc *p, struct abuf *obuf)
                    440: {
                    441:        struct abuf *ibuf;
                    442:
                    443:        while (!LIST_EMPTY(&p->ibuflist)) {
                    444:                ibuf = LIST_FIRST(&p->ibuflist);
                    445:                mix_rm(p, ibuf);
                    446:                abuf_hup(ibuf);
                    447:        }
                    448:        DPRINTF("mix_hup: %s: done\n", p->name);
                    449:        aproc_del(p);
                    450: }
                    451:
                    452: void
                    453: mix_newin(struct aproc *p, struct abuf *ibuf)
                    454: {
                    455:        ibuf->mixdone = 0;
1.3       ratchov   456:        ibuf->mixdrop = 0;
1.1       ratchov   457:        ibuf->mixvol = ADATA_UNIT;
                    458: }
                    459:
                    460: void
                    461: mix_newout(struct aproc *p, struct abuf *obuf)
                    462: {
                    463:        obuf->mixtodo = 0;
                    464:        mix_bzero(p);
                    465: }
                    466:
                    467: struct aproc_ops mix_ops = {
                    468:        "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout
                    469: };
                    470:
                    471: struct aproc *
                    472: mix_new(void)
                    473: {
                    474:        struct aproc *p;
                    475:
                    476:        p = aproc_new(&mix_ops, "softmix");
                    477:        return p;
                    478: }
                    479:
                    480: /*
                    481:  * Copy data from ibuf to obuf.
                    482:  */
                    483: void
                    484: sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
                    485: {
                    486:        unsigned char *idata, *odata;
                    487:        unsigned icount, ocount, scount;
                    488:
                    489:        idata = abuf_rgetblk(ibuf, &icount, obuf->subdone);
                    490:        if (icount == 0)
                    491:                return;
                    492:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    493:        if (ocount == 0)
                    494:                return;
                    495:        scount = (icount < ocount) ? icount : ocount;
                    496:        memcpy(odata, idata, scount);
                    497:        obuf->subdone += scount;
                    498:        obuf->used += scount;
                    499:        DPRINTFN(4, "sub_bcopy: %u bytes\n", scount);
                    500: }
                    501:
                    502: void
                    503: sub_rm(struct aproc *p, struct abuf *obuf)
                    504: {
                    505:        LIST_REMOVE(obuf, oent);
                    506:        DPRINTF("sub_rm: %s\n", p->name);
                    507: }
                    508:
                    509: void
                    510: sub_del(struct aproc *p)
                    511: {
                    512:        aproc_del(p);
                    513: }
                    514:
                    515: int
                    516: sub_in(struct aproc *p, struct abuf *ibuf)
                    517: {
                    518:        struct abuf *i, *inext;
1.3       ratchov   519:        unsigned done, drop;
1.1       ratchov   520:        int again;
                    521:
                    522:        again = 1;
                    523:        done = ibuf->used;
1.2       ratchov   524:        for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1       ratchov   525:                inext = LIST_NEXT(i, oent);
1.3       ratchov   526:                if (!ABUF_WOK(i) && i->subdone == 0) {
                    527:                        drop = ibuf->used;
                    528:                        i->subdrop += drop;
                    529:                        i->subdone += drop;
                    530:                        DPRINTF("sub_in: xrun, drop =  %u\n", i->subdrop);
                    531:                } else {
1.1       ratchov   532:                        sub_bcopy(ibuf, i);
                    533:                        abuf_flush(i);
                    534:                }
1.3       ratchov   535: #ifdef sub_xrun_disabled
1.1       ratchov   536:                if (!ABUF_WOK(i))
                    537:                        again = 0;
1.3       ratchov   538: #endif
1.1       ratchov   539:                if (done > i->subdone)
                    540:                        done = i->subdone;
                    541:        }
                    542:        LIST_FOREACH(i, &p->obuflist, oent) {
                    543:                i->subdone -= done;
                    544:        }
                    545:        ibuf->used -= done;
                    546:        ibuf->start += done;
                    547:        if (ibuf->start >= ibuf->len)
                    548:                ibuf->start -= ibuf->len;
                    549:        return again;
                    550: }
                    551:
                    552: int
                    553: sub_out(struct aproc *p, struct abuf *obuf)
                    554: {
                    555:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    556:        struct abuf *i, *inext;
1.3       ratchov   557:        unsigned char *odata;
                    558:        unsigned ocount;
1.1       ratchov   559:        unsigned done;
                    560:
1.3       ratchov   561:        /*
                    562:         * generate silence for dropped samples
                    563:         */
                    564:        while (obuf->subdrop > 0) {
                    565:                odata = abuf_wgetblk(obuf, &ocount, 0);
                    566:                if (ocount >= obuf->subdrop)
                    567:                        ocount = obuf->subdrop;
                    568:                if (ocount == 0)
                    569:                        break;
                    570:                memset(odata, 0, ocount);
                    571:                obuf->used += ocount;
                    572:                obuf->subdrop -= ocount;
                    573:                DPRINTF("sub_out: catched, drop = %u\n", obuf->subdrop);
                    574:        }
                    575:
1.1       ratchov   576:        if (obuf->subdone >= ibuf->used)
                    577:                return 0;
                    578:
                    579:        sub_bcopy(ibuf, obuf);
                    580:
                    581:        done = ibuf->used;
                    582:        LIST_FOREACH(i, &p->obuflist, oent) {
                    583:                if (i != obuf && ABUF_WOK(i)) {
                    584:                        sub_bcopy(ibuf, i);
                    585:                        abuf_flush(i);
                    586:                }
                    587:                if (done > i->subdone)
                    588:                        done = i->subdone;
                    589:        }
                    590:        if (done == 0)
                    591:                return 0;
                    592:        LIST_FOREACH(i, &p->obuflist, oent) {
                    593:                i->subdone -= done;
                    594:        }
                    595:        ibuf->used -= done;
                    596:        ibuf->start += done;
                    597:        if (ibuf->start >= ibuf->len)
                    598:                ibuf->start -= ibuf->len;
                    599:        if (ABUF_EOF(ibuf)) {
                    600:                abuf_hup(ibuf);
                    601:                for (i = LIST_FIRST(&p->obuflist);
1.2       ratchov   602:                     i != LIST_END(&p->obuflist);
1.1       ratchov   603:                     i = inext) {
                    604:                        inext = LIST_NEXT(i, oent);
                    605:                        if (i != ibuf)
                    606:                                abuf_eof(i);
                    607:                }
                    608:                ibuf->wproc = NULL;
                    609:                sub_del(p);
                    610:                return 0;
                    611:        }
                    612:        abuf_fill(ibuf);
                    613:        return 1;
                    614: }
                    615:
                    616: void
                    617: sub_eof(struct aproc *p, struct abuf *ibuf)
                    618: {
                    619:        struct abuf *obuf;
                    620:
                    621:        while (!LIST_EMPTY(&p->obuflist)) {
                    622:                obuf = LIST_FIRST(&p->obuflist);
                    623:                sub_rm(p, obuf);
                    624:                abuf_eof(obuf);
                    625:        }
                    626:        sub_del(p);
                    627: }
                    628:
                    629: void
                    630: sub_hup(struct aproc *p, struct abuf *obuf)
                    631: {
                    632:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    633:
                    634:        DPRINTF("sub_hup: %s: detached\n", p->name);
                    635:        sub_rm(p, obuf);
                    636:        if (LIST_EMPTY(&p->obuflist)) {
                    637:                abuf_hup(ibuf);
                    638:                sub_del(p);
                    639:        } else
                    640:                abuf_run(ibuf);
                    641:        DPRINTF("sub_hup: done\n");
                    642: }
                    643:
                    644: void
                    645: sub_newout(struct aproc *p, struct abuf *obuf)
                    646: {
                    647:        obuf->subdone = 0;
1.3       ratchov   648:        obuf->subdrop = 0;
1.1       ratchov   649: }
                    650:
                    651: struct aproc_ops sub_ops = {
                    652:        "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout
                    653: };
                    654:
                    655: struct aproc *
                    656: sub_new(void)
                    657: {
                    658:        struct aproc *p;
                    659:
                    660:        p = aproc_new(&sub_ops, "copy");
                    661:        return p;
                    662: }
                    663:
                    664:
                    665: /*
                    666:  * Convert one block.
                    667:  */
                    668: void
                    669: conv_bcopy(struct aconv *ist, struct aconv *ost,
                    670:     struct abuf *ibuf, struct abuf *obuf)
                    671: {
                    672:        int *ictx;
                    673:        unsigned inch, ibps;
                    674:        unsigned char *idata;
                    675:        int ibnext, isigbit;
                    676:        unsigned ishift;
                    677:        int isnext;
                    678:        unsigned ipos, orate;
                    679:        unsigned ifr;
                    680:        int *octx;
                    681:        unsigned onch, oshift;
                    682:        int osigbit;
                    683:        unsigned obps;
                    684:        unsigned char *odata;
                    685:        int obnext, osnext;
                    686:        unsigned opos, irate;
                    687:        unsigned ofr;
                    688:        unsigned c, i;
                    689:        int s, *ctx;
                    690:        unsigned icount, ocount;
                    691:
                    692:        /*
                    693:         * It's ok to have s uninitialized, but we dont want the compiler to
                    694:         * complain about it.
                    695:         */
                    696:        s = (int)0xdeadbeef;
                    697:
                    698:        /*
                    699:         * Calculate max frames readable at once from the input buffer.
                    700:         */
                    701:        idata = abuf_rgetblk(ibuf, &icount, 0);
                    702:        ifr = icount / ibuf->bpf;
                    703:
                    704:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    705:        ofr = ocount / obuf->bpf;
                    706:
                    707:        /*
                    708:         * Partially copy structures into local variables, to avoid
                    709:         * unnecessary indirections; this also allows the compiler to
                    710:         * order local variables more "cache-friendly".
                    711:         */
                    712:        ictx = ist->ctx + ist->cmin;
                    713:        octx = ist->ctx + ost->cmin;
                    714:        inch = ist->nch;
                    715:        ibps = ist->bps;
                    716:        ibnext = ist->bnext;
                    717:        isigbit = ist->sigbit;
                    718:        ishift = ist->shift;
                    719:        isnext = ist->snext;
                    720:        ipos = ist->pos;
                    721:        irate = ist->rate;
                    722:        onch = ost->nch;
                    723:        oshift = ost->shift;
                    724:        osigbit = ost->sigbit;
                    725:        obps = ost->bps;
                    726:        obnext = ost->bnext;
                    727:        osnext = ost->snext;
                    728:        opos = ost->pos;
                    729:        orate = ost->rate;
                    730:
                    731:        /*
                    732:         * Start conversion.
                    733:         */
                    734:        idata += ist->bfirst;
                    735:        odata += ost->bfirst;
                    736:        DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
                    737:        for (;;) {
                    738:                if ((int)(ipos - opos) > 0) {
                    739:                        if (ofr == 0)
                    740:                                break;
                    741:                        ctx = octx;
                    742:                        for (c = onch; c > 0; c--) {
                    743:                                s = *ctx++ << 16;
                    744:                                s >>= oshift;
                    745:                                s ^= osigbit;
                    746:                                for (i = obps; i > 0; i--) {
                    747:                                        *odata = (unsigned char)s;
                    748:                                        s >>= 8;
                    749:                                        odata += obnext;
                    750:                                }
                    751:                                odata += osnext;
                    752:                        }
                    753:                        opos += irate;
                    754:                        ofr--;
                    755:                } else {
                    756:                        if (ifr == 0)
                    757:                                break;
                    758:                        ctx = ictx;
                    759:                        for (c = inch; c > 0; c--) {
                    760:                                for (i = ibps; i > 0; i--) {
                    761:                                        s <<= 8;
                    762:                                        s |= *idata;
                    763:                                        idata += ibnext;
                    764:                                }
                    765:                                s ^= isigbit;
                    766:                                s <<= ishift;
                    767:                                *ctx++ = (short)(s >> 16);
                    768:                                idata += isnext;
                    769:                        }
                    770:                        ipos += orate;
                    771:                        ifr--;
                    772:                }
                    773:        }
                    774:        ist->pos = ipos;
                    775:        ost->pos = opos;
                    776:        DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
                    777:
                    778:        /*
                    779:         * Update FIFO pointers.
                    780:         */
                    781:        icount -= ifr * ist->bpf;
                    782:        ibuf->used -= icount;
                    783:        ibuf->start += icount;
                    784:        if (ibuf->start >= ibuf->len)
                    785:                ibuf->start -= ibuf->len;
                    786:
                    787:        ocount -= ofr * ost->bpf;
                    788:        obuf->used += ocount;
                    789: }
                    790:
                    791: void
                    792: conv_del(struct aproc *p)
                    793: {
                    794:        aproc_del(p);
                    795: }
                    796:
                    797: int
                    798: conv_in(struct aproc *p, struct abuf *ibuf)
                    799: {
                    800:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    801:
                    802:        if (!ABUF_WOK(obuf))
                    803:                return 0;
                    804:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
                    805:        abuf_flush(obuf);
                    806:        return ABUF_WOK(obuf);
                    807: }
                    808:
                    809: int
                    810: conv_out(struct aproc *p, struct abuf *obuf)
                    811: {
                    812:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    813:
                    814:        if (!ABUF_ROK(ibuf))
                    815:                return 0;
                    816:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
                    817:        if (ABUF_EOF(ibuf)) {
                    818:                obuf->wproc = NULL;
                    819:                abuf_hup(ibuf);
                    820:                conv_del(p);
                    821:                return 0;
                    822:        }
                    823:        abuf_fill(ibuf);
                    824:        return 1;
                    825: }
                    826:
                    827: void
                    828: conv_eof(struct aproc *p, struct abuf *ibuf)
                    829: {
                    830:        abuf_eof(LIST_FIRST(&p->obuflist));
                    831:        conv_del(p);
                    832: }
                    833:
                    834: void
                    835: conv_hup(struct aproc *p, struct abuf *obuf)
                    836: {
                    837:        abuf_hup(LIST_FIRST(&p->ibuflist));
                    838:        conv_del(p);
                    839: }
                    840:
                    841: void
                    842: aconv_init(struct aconv *st, struct aparams *par, int input)
                    843: {
                    844:        unsigned i;
                    845:
                    846:        st->bps = par->bps;
                    847:        st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
                    848:        if (par->msb) {
                    849:                st->shift = 32 - par->bps * 8;
                    850:        } else {
                    851:                st->shift = 32 - par->bits;
                    852:        }
                    853:        if ((par->le && input) || (!par->le && !input)) {
                    854:                st->bfirst = st->bps - 1;
                    855:                st->bnext = -1;
                    856:                st->snext = 2 * st->bps;
                    857:        } else {
                    858:                st->bfirst = 0;
                    859:                st->bnext = 1;
                    860:                st->snext = 0;
                    861:        }
                    862:        st->cmin = par->cmin;
                    863:        st->nch = par->cmax - par->cmin + 1;
                    864:        st->bpf = st->nch * st->bps;
                    865:        st->rate = par->rate;
                    866:        st->pos = 0;
                    867:
                    868:        for (i = 0; i < CHAN_MAX; i++)
                    869:                st->ctx[i] = 0;
                    870: }
                    871:
                    872: struct aproc_ops conv_ops = {
                    873:        "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL
                    874: };
                    875:
                    876: struct aproc *
                    877: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
                    878: {
                    879:        struct aproc *p;
                    880:
                    881:        p = aproc_new(&conv_ops, name);
                    882:        aconv_init(&p->u.conv.ist, ipar, 1);
                    883:        aconv_init(&p->u.conv.ost, opar, 0);
                    884:        return p;
                    885: }