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

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