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

1.8     ! ratchov     1: /*     $OpenBSD: aproc.c,v 1.7 2008/08/14 09:44:15 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: {
1.8     ! ratchov    73:        if (p->ops->done)
        !            74:                p->ops->done(p);
1.1       ratchov    75:        DPRINTF("aproc_del: %s: %s: deleted\n", p->ops->name, p->name);
                     76:        free(p);
                     77: }
                     78:
                     79: void
                     80: aproc_setin(struct aproc *p, struct abuf *ibuf)
                     81: {
                     82:        LIST_INSERT_HEAD(&p->ibuflist, ibuf, ient);
                     83:        ibuf->rproc = p;
                     84:        if (p->ops->newin)
                     85:                p->ops->newin(p, ibuf);
                     86: }
                     87:
                     88: void
                     89: aproc_setout(struct aproc *p, struct abuf *obuf)
                     90: {
                     91:        LIST_INSERT_HEAD(&p->obuflist, obuf, oent);
                     92:        obuf->wproc = p;
                     93:        if (p->ops->newout)
                     94:                p->ops->newout(p, obuf);
                     95: }
                     96:
                     97: int
                     98: rpipe_in(struct aproc *p, struct abuf *ibuf_dummy)
                     99: {
                    100:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    101:        struct file *f = p->u.io.file;
                    102:        unsigned char *data;
                    103:        unsigned count;
                    104:
1.6       ratchov   105:        DPRINTFN(3, "rpipe_in: %s\n", p->name);
                    106:
1.1       ratchov   107:        if (ABUF_FULL(obuf))
                    108:                return 0;
                    109:        data = abuf_wgetblk(obuf, &count, 0);
1.6       ratchov   110:        count = file_read(f, data, count);
                    111:        abuf_wcommit(obuf, count);
1.1       ratchov   112:        abuf_flush(obuf);
                    113:        return !ABUF_FULL(obuf);
                    114: }
                    115:
                    116: int
                    117: rpipe_out(struct aproc *p, struct abuf *obuf)
                    118: {
                    119:        struct file *f = p->u.io.file;
                    120:        unsigned char *data;
                    121:        unsigned count;
                    122:
1.6       ratchov   123:        DPRINTFN(3, "rpipe_out: %s\n", p->name);
                    124:
1.1       ratchov   125:        if (!(f->state & FILE_ROK))
                    126:                return 0;
                    127:        data = abuf_wgetblk(obuf, &count, 0);
1.6       ratchov   128:        count = file_read(f, data, count);
                    129:        abuf_wcommit(obuf, count);
1.1       ratchov   130:        return f->state & FILE_ROK;
                    131: }
                    132:
                    133: void
1.8     ! ratchov   134: rpipe_done(struct aproc *p)
1.1       ratchov   135: {
                    136:        struct file *f = p->u.io.file;
                    137:
                    138:        f->rproc = NULL;
                    139:        f->events &= ~POLLIN;
                    140: }
                    141:
                    142: void
                    143: rpipe_eof(struct aproc *p, struct abuf *ibuf_dummy)
                    144: {
                    145:        DPRINTFN(3, "rpipe_eof: %s\n", p->name);
                    146:        abuf_eof(LIST_FIRST(&p->obuflist));
1.8     ! ratchov   147:        aproc_del(p);
1.1       ratchov   148: }
                    149:
                    150: void
                    151: rpipe_hup(struct aproc *p, struct abuf *obuf)
                    152: {
                    153:        DPRINTFN(3, "rpipe_hup: %s\n", p->name);
1.8     ! ratchov   154:        aproc_del(p);
1.1       ratchov   155: }
                    156:
                    157: struct aproc_ops rpipe_ops = {
1.8     ! ratchov   158:        "rpipe", rpipe_in, rpipe_out, rpipe_eof, rpipe_hup, NULL, NULL, rpipe_done
1.1       ratchov   159: };
                    160:
                    161: struct aproc *
                    162: rpipe_new(struct file *f)
                    163: {
                    164:        struct aproc *p;
                    165:
                    166:        p = aproc_new(&rpipe_ops, f->name);
                    167:        p->u.io.file = f;
                    168:        f->rproc = p;
                    169:        f->events |= POLLIN;
                    170:        return p;
                    171: }
                    172:
                    173: void
1.8     ! ratchov   174: wpipe_done(struct aproc *p)
1.1       ratchov   175: {
                    176:        struct file *f = p->u.io.file;
                    177:
                    178:        f->wproc = NULL;
                    179:        f->events &= ~POLLOUT;
                    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);
1.8     ! ratchov   217:                aproc_del(p);
1.1       ratchov   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);
1.8     ! ratchov   228:        aproc_del(p);
1.1       ratchov   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));
1.8     ! ratchov   236:        aproc_del(p);
1.1       ratchov   237: }
                    238:
                    239: struct aproc_ops wpipe_ops = {
1.8     ! ratchov   240:        "wpipe", wpipe_in, wpipe_out, wpipe_eof, wpipe_hup, NULL, NULL, wpipe_done
1.1       ratchov   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 = {
1.8     ! ratchov   457:        "mix", mix_in, mix_out, mix_eof, mix_hup, mix_newin, mix_newout, NULL
1.1       ratchov   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: int
                    500: sub_in(struct aproc *p, struct abuf *ibuf)
                    501: {
                    502:        struct abuf *i, *inext;
1.3       ratchov   503:        unsigned done, drop;
1.1       ratchov   504:        int again;
                    505:
                    506:        again = 1;
                    507:        done = ibuf->used;
1.2       ratchov   508:        for (i = LIST_FIRST(&p->obuflist); i != LIST_END(&p->obuflist); i = inext) {
1.1       ratchov   509:                inext = LIST_NEXT(i, oent);
1.5       ratchov   510:                if (!ABUF_WOK(i)) {
                    511:                        if ((p->u.sub.flags & SUB_DROP) && i->subdone == 0) {
                    512:                                if (i->xrun == XRUN_ERROR) {
                    513:                                        sub_rm(p, i);
                    514:                                        abuf_eof(i);
                    515:                                        continue;
                    516:                                }
                    517:                                drop = ibuf->used;
                    518:                                if (i->xrun == XRUN_SYNC)
1.7       ratchov   519:                                        i->silence += drop;
1.5       ratchov   520:                                i->subdone += drop;
1.7       ratchov   521:                                DPRINTF("sub_in: silence =  %u\n", i->silence);
1.5       ratchov   522:                        }
1.3       ratchov   523:                } else {
1.1       ratchov   524:                        sub_bcopy(ibuf, i);
                    525:                        abuf_flush(i);
                    526:                }
                    527:                if (!ABUF_WOK(i))
                    528:                        again = 0;
                    529:                if (done > i->subdone)
                    530:                        done = i->subdone;
                    531:        }
                    532:        LIST_FOREACH(i, &p->obuflist, oent) {
                    533:                i->subdone -= done;
                    534:        }
1.6       ratchov   535:        abuf_rdiscard(ibuf, done);
1.1       ratchov   536:        return again;
                    537: }
                    538:
                    539: int
                    540: sub_out(struct aproc *p, struct abuf *obuf)
                    541: {
                    542:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    543:        struct abuf *i, *inext;
                    544:        unsigned done;
                    545:
                    546:        if (obuf->subdone >= ibuf->used)
                    547:                return 0;
                    548:
                    549:        sub_bcopy(ibuf, obuf);
                    550:
                    551:        done = ibuf->used;
                    552:        LIST_FOREACH(i, &p->obuflist, oent) {
                    553:                if (i != obuf && ABUF_WOK(i)) {
                    554:                        sub_bcopy(ibuf, i);
                    555:                        abuf_flush(i);
                    556:                }
                    557:                if (done > i->subdone)
                    558:                        done = i->subdone;
                    559:        }
                    560:        if (done == 0)
                    561:                return 0;
                    562:        LIST_FOREACH(i, &p->obuflist, oent) {
                    563:                i->subdone -= done;
                    564:        }
1.6       ratchov   565:        abuf_rdiscard(ibuf, done);
1.1       ratchov   566:        if (ABUF_EOF(ibuf)) {
                    567:                abuf_hup(ibuf);
                    568:                for (i = LIST_FIRST(&p->obuflist);
1.2       ratchov   569:                     i != LIST_END(&p->obuflist);
1.1       ratchov   570:                     i = inext) {
                    571:                        inext = LIST_NEXT(i, oent);
                    572:                        if (i != ibuf)
                    573:                                abuf_eof(i);
                    574:                }
                    575:                ibuf->wproc = NULL;
1.8     ! ratchov   576:                aproc_del(p);
1.1       ratchov   577:                return 0;
                    578:        }
                    579:        abuf_fill(ibuf);
                    580:        return 1;
                    581: }
                    582:
                    583: void
                    584: sub_eof(struct aproc *p, struct abuf *ibuf)
                    585: {
                    586:        struct abuf *obuf;
                    587:
                    588:        while (!LIST_EMPTY(&p->obuflist)) {
                    589:                obuf = LIST_FIRST(&p->obuflist);
                    590:                sub_rm(p, obuf);
                    591:                abuf_eof(obuf);
                    592:        }
1.8     ! ratchov   593:        aproc_del(p);
1.1       ratchov   594: }
                    595:
                    596: void
                    597: sub_hup(struct aproc *p, struct abuf *obuf)
                    598: {
                    599:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    600:
                    601:        DPRINTF("sub_hup: %s: detached\n", p->name);
                    602:        sub_rm(p, obuf);
                    603:        if (LIST_EMPTY(&p->obuflist)) {
                    604:                abuf_hup(ibuf);
1.8     ! ratchov   605:                aproc_del(p);
1.1       ratchov   606:        } else
                    607:                abuf_run(ibuf);
                    608:        DPRINTF("sub_hup: done\n");
                    609: }
                    610:
                    611: void
                    612: sub_newout(struct aproc *p, struct abuf *obuf)
                    613: {
                    614:        obuf->subdone = 0;
1.5       ratchov   615:        obuf->xrun = XRUN_IGNORE;
1.1       ratchov   616: }
                    617:
                    618: struct aproc_ops sub_ops = {
1.8     ! ratchov   619:        "sub", sub_in, sub_out, sub_eof, sub_hup, NULL, sub_newout, NULL
1.1       ratchov   620: };
                    621:
                    622: struct aproc *
                    623: sub_new(void)
                    624: {
                    625:        struct aproc *p;
                    626:
                    627:        p = aproc_new(&sub_ops, "copy");
1.5       ratchov   628:        p->u.sub.flags = 0;
1.1       ratchov   629:        return p;
                    630: }
                    631:
                    632:
                    633: /*
                    634:  * Convert one block.
                    635:  */
                    636: void
                    637: conv_bcopy(struct aconv *ist, struct aconv *ost,
                    638:     struct abuf *ibuf, struct abuf *obuf)
                    639: {
                    640:        int *ictx;
                    641:        unsigned inch, ibps;
                    642:        unsigned char *idata;
                    643:        int ibnext, isigbit;
                    644:        unsigned ishift;
                    645:        int isnext;
                    646:        unsigned ipos, orate;
                    647:        unsigned ifr;
                    648:        int *octx;
                    649:        unsigned onch, oshift;
                    650:        int osigbit;
                    651:        unsigned obps;
                    652:        unsigned char *odata;
                    653:        int obnext, osnext;
                    654:        unsigned opos, irate;
                    655:        unsigned ofr;
                    656:        unsigned c, i;
                    657:        int s, *ctx;
                    658:        unsigned icount, ocount;
                    659:
                    660:        /*
                    661:         * It's ok to have s uninitialized, but we dont want the compiler to
                    662:         * complain about it.
                    663:         */
                    664:        s = (int)0xdeadbeef;
                    665:
                    666:        /*
                    667:         * Calculate max frames readable at once from the input buffer.
                    668:         */
                    669:        idata = abuf_rgetblk(ibuf, &icount, 0);
                    670:        ifr = icount / ibuf->bpf;
                    671:
                    672:        odata = abuf_wgetblk(obuf, &ocount, 0);
                    673:        ofr = ocount / obuf->bpf;
                    674:
                    675:        /*
                    676:         * Partially copy structures into local variables, to avoid
                    677:         * unnecessary indirections; this also allows the compiler to
                    678:         * order local variables more "cache-friendly".
                    679:         */
                    680:        ictx = ist->ctx + ist->cmin;
                    681:        octx = ist->ctx + ost->cmin;
                    682:        inch = ist->nch;
                    683:        ibps = ist->bps;
                    684:        ibnext = ist->bnext;
                    685:        isigbit = ist->sigbit;
                    686:        ishift = ist->shift;
                    687:        isnext = ist->snext;
                    688:        ipos = ist->pos;
                    689:        irate = ist->rate;
                    690:        onch = ost->nch;
                    691:        oshift = ost->shift;
                    692:        osigbit = ost->sigbit;
                    693:        obps = ost->bps;
                    694:        obnext = ost->bnext;
                    695:        osnext = ost->snext;
                    696:        opos = ost->pos;
                    697:        orate = ost->rate;
                    698:
                    699:        /*
                    700:         * Start conversion.
                    701:         */
                    702:        idata += ist->bfirst;
                    703:        odata += ost->bfirst;
                    704:        DPRINTFN(4, "conv_bcopy: ifr=%d ofr=%d\n", ifr, ofr);
                    705:        for (;;) {
                    706:                if ((int)(ipos - opos) > 0) {
                    707:                        if (ofr == 0)
                    708:                                break;
                    709:                        ctx = octx;
                    710:                        for (c = onch; c > 0; c--) {
                    711:                                s = *ctx++ << 16;
                    712:                                s >>= oshift;
                    713:                                s ^= osigbit;
                    714:                                for (i = obps; i > 0; i--) {
                    715:                                        *odata = (unsigned char)s;
                    716:                                        s >>= 8;
                    717:                                        odata += obnext;
                    718:                                }
                    719:                                odata += osnext;
                    720:                        }
                    721:                        opos += irate;
                    722:                        ofr--;
                    723:                } else {
                    724:                        if (ifr == 0)
                    725:                                break;
                    726:                        ctx = ictx;
                    727:                        for (c = inch; c > 0; c--) {
                    728:                                for (i = ibps; i > 0; i--) {
                    729:                                        s <<= 8;
                    730:                                        s |= *idata;
                    731:                                        idata += ibnext;
                    732:                                }
                    733:                                s ^= isigbit;
                    734:                                s <<= ishift;
                    735:                                *ctx++ = (short)(s >> 16);
                    736:                                idata += isnext;
                    737:                        }
                    738:                        ipos += orate;
                    739:                        ifr--;
                    740:                }
                    741:        }
                    742:        ist->pos = ipos;
                    743:        ost->pos = opos;
                    744:        DPRINTFN(4, "conv_bcopy: done, ifr=%d ofr=%d\n", ifr, ofr);
                    745:
                    746:        /*
                    747:         * Update FIFO pointers.
                    748:         */
                    749:        icount -= ifr * ist->bpf;
                    750:        ocount -= ofr * ost->bpf;
1.6       ratchov   751:        abuf_rdiscard(ibuf, icount);
                    752:        abuf_wcommit(obuf, ocount);
1.1       ratchov   753: }
                    754:
                    755: int
                    756: conv_in(struct aproc *p, struct abuf *ibuf)
                    757: {
                    758:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
                    759:
                    760:        if (!ABUF_WOK(obuf))
                    761:                return 0;
                    762:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
                    763:        abuf_flush(obuf);
                    764:        return ABUF_WOK(obuf);
                    765: }
                    766:
                    767: int
                    768: conv_out(struct aproc *p, struct abuf *obuf)
                    769: {
                    770:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
                    771:
                    772:        if (!ABUF_ROK(ibuf))
                    773:                return 0;
                    774:        conv_bcopy(&p->u.conv.ist, &p->u.conv.ost, ibuf, obuf);
                    775:        if (ABUF_EOF(ibuf)) {
                    776:                obuf->wproc = NULL;
                    777:                abuf_hup(ibuf);
1.8     ! ratchov   778:                aproc_del(p);
1.1       ratchov   779:                return 0;
                    780:        }
                    781:        abuf_fill(ibuf);
                    782:        return 1;
                    783: }
                    784:
                    785: void
                    786: conv_eof(struct aproc *p, struct abuf *ibuf)
                    787: {
                    788:        abuf_eof(LIST_FIRST(&p->obuflist));
1.8     ! ratchov   789:        aproc_del(p);
1.1       ratchov   790: }
                    791:
                    792: void
                    793: conv_hup(struct aproc *p, struct abuf *obuf)
                    794: {
                    795:        abuf_hup(LIST_FIRST(&p->ibuflist));
1.8     ! ratchov   796:        aproc_del(p);
1.1       ratchov   797: }
                    798:
                    799: void
                    800: aconv_init(struct aconv *st, struct aparams *par, int input)
                    801: {
                    802:        unsigned i;
                    803:
                    804:        st->bps = par->bps;
                    805:        st->sigbit = par->sig ? 0 : 1 << (par->bits - 1);
                    806:        if (par->msb) {
                    807:                st->shift = 32 - par->bps * 8;
                    808:        } else {
                    809:                st->shift = 32 - par->bits;
                    810:        }
                    811:        if ((par->le && input) || (!par->le && !input)) {
                    812:                st->bfirst = st->bps - 1;
                    813:                st->bnext = -1;
                    814:                st->snext = 2 * st->bps;
                    815:        } else {
                    816:                st->bfirst = 0;
                    817:                st->bnext = 1;
                    818:                st->snext = 0;
                    819:        }
                    820:        st->cmin = par->cmin;
                    821:        st->nch = par->cmax - par->cmin + 1;
                    822:        st->bpf = st->nch * st->bps;
                    823:        st->rate = par->rate;
                    824:        st->pos = 0;
                    825:
                    826:        for (i = 0; i < CHAN_MAX; i++)
                    827:                st->ctx[i] = 0;
                    828: }
                    829:
                    830: struct aproc_ops conv_ops = {
1.8     ! ratchov   831:        "conv", conv_in, conv_out, conv_eof, conv_hup, NULL, NULL, NULL
1.1       ratchov   832: };
                    833:
                    834: struct aproc *
                    835: conv_new(char *name, struct aparams *ipar, struct aparams *opar)
                    836: {
                    837:        struct aproc *p;
                    838:
                    839:        p = aproc_new(&conv_ops, name);
                    840:        aconv_init(&p->u.conv.ist, ipar, 1);
                    841:        aconv_init(&p->u.conv.ost, opar, 0);
                    842:        return p;
                    843: }