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

Annotation of src/usr.bin/aucat/dev.c, Revision 1.36

1.36    ! ratchov     1: /*     $OpenBSD: dev.c,v 1.35 2009/10/27 22:24:27 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:  */
1.27      ratchov    17:
1.1       ratchov    18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <unistd.h>
                     21:
                     22: #include "abuf.h"
                     23: #include "aproc.h"
1.27      ratchov    24: #include "conf.h"
                     25: #include "dev.h"
1.3       ratchov    26: #include "pipe.h"
                     27: #include "safile.h"
1.28      ratchov    28: #include "midi.h"
1.1       ratchov    29:
1.3       ratchov    30: unsigned dev_bufsz, dev_round, dev_rate;
1.1       ratchov    31: struct aparams dev_ipar, dev_opar;
                     32: struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play;
1.28      ratchov    33: struct aproc *dev_midi;
                     34:
                     35: /*
                     36:  * Create a MIDI thru box as the MIDI end of the device
                     37:  */
                     38: void
                     39: dev_thruinit(void)
                     40: {
                     41:        dev_midi = thru_new("thru");
                     42:        dev_midi->refs++;
                     43: }
                     44:
                     45: /*
                     46:  * Attach a bi-directional MIDI stream to the MIDI device
                     47:  */
                     48: void
                     49: dev_midiattach(struct abuf *ibuf, struct abuf *obuf)
                     50: {
                     51:        if (ibuf)
                     52:                aproc_setin(dev_midi, ibuf);
                     53:        if (obuf) {
                     54:                aproc_setout(dev_midi, obuf);
                     55:                if (ibuf) {
                     56:                        ibuf->duplex = obuf;
                     57:                        obuf->duplex = ibuf;
                     58:                }
                     59:        }
                     60: }
1.24      ratchov    61:
                     62: /*
1.27      ratchov    63:  * Same as dev_init(), but create a fake device that records what is
                     64:  * played.
1.24      ratchov    65:  */
                     66: void
                     67: dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
                     68: {
                     69:        struct abuf *buf;
                     70:        struct aparams par;
                     71:        unsigned cmin, cmax, rate;
                     72:
                     73:        cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
                     74:        cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
                     75:        rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
                     76:        aparams_init(&par, cmin, cmax, rate);
                     77:        dev_ipar = par;
                     78:        dev_opar = par;
                     79:        dev_round = (bufsz + 1) / 2;
                     80:        dev_bufsz = dev_round * 2;
1.25      ratchov    81:        dev_rate  = rate;
1.24      ratchov    82:        dev_rec = NULL;
                     83:        dev_play = NULL;
1.25      ratchov    84:
1.24      ratchov    85:        buf = abuf_new(dev_bufsz, &par);
1.36    ! ratchov    86:        dev_mix = mix_new("mix", dev_bufsz, NULL);
1.24      ratchov    87:        dev_mix->refs++;
1.36    ! ratchov    88:        dev_sub = sub_new("sub", dev_bufsz, NULL);
1.24      ratchov    89:        dev_sub->refs++;
                     90:        aproc_setout(dev_mix, buf);
                     91:        aproc_setin(dev_sub, buf);
                     92:
1.36    ! ratchov    93:        dev_mix->flags |= APROC_QUIT;
        !            94:        dev_sub->flags |= APROC_QUIT;
1.24      ratchov    95:
                     96:        *dipar = dev_ipar;
                     97:        *dopar = dev_opar;
                     98: }
1.1       ratchov    99:
1.20      ratchov   100: unsigned
                    101: dev_roundof(unsigned newrate)
1.1       ratchov   102: {
1.20      ratchov   103:        return (dev_round * newrate + dev_rate / 2) / dev_rate;
1.1       ratchov   104: }
                    105:
                    106: /*
1.27      ratchov   107:  * Open the device with the given hardware parameters and create a mixer
1.1       ratchov   108:  * and a multiplexer connected to it with all necessary conversions
1.27      ratchov   109:  * setup.
1.1       ratchov   110:  */
1.26      ratchov   111: int
1.3       ratchov   112: dev_init(char *devpath,
1.36    ! ratchov   113:     struct aparams *dipar, struct aparams *dopar, unsigned bufsz, unsigned round)
1.1       ratchov   114: {
1.23      ratchov   115:        struct file *f;
1.1       ratchov   116:        struct aparams ipar, opar;
                    117:        struct aproc *conv;
                    118:        struct abuf *buf;
1.3       ratchov   119:        unsigned nfr, ibufsz, obufsz;
1.25      ratchov   120:
1.36    ! ratchov   121:        dev_midi = ctl_new("ctl");
        !           122:        dev_midi->refs++;
        !           123:
1.3       ratchov   124:        /*
1.27      ratchov   125:         * Ask for 1/4 of the buffer for the kernel ring and
                    126:         * limit the block size to 1/4 of the requested buffer.
1.3       ratchov   127:         */
1.36    ! ratchov   128:        dev_round = round;
        !           129:        dev_bufsz = (bufsz + 3) / 4 + (dev_round - 1);
        !           130:        dev_bufsz -= dev_bufsz % dev_round;
1.23      ratchov   131:        f = (struct file *)safile_new(&safile_ops, devpath,
1.20      ratchov   132:            dipar, dopar, &dev_bufsz, &dev_round);
1.23      ratchov   133:        if (f == NULL)
1.26      ratchov   134:                return 0;
1.3       ratchov   135:        if (dipar) {
1.20      ratchov   136:                dev_rate = dipar->rate;
1.3       ratchov   137:        }
                    138:        if (dopar) {
1.20      ratchov   139:                dev_rate = dopar->rate;
1.3       ratchov   140:        }
1.11      ratchov   141:        ibufsz = obufsz = dev_bufsz;
                    142:        bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0;
1.1       ratchov   143:
                    144:        /*
1.27      ratchov   145:         * Use 1/8 of the buffer for the mixer/converters.  Since we
1.11      ratchov   146:         * already consumed 1/4 for the device, bufsz represents the
1.27      ratchov   147:         * remaining 3/4. So 1/8 is 1/6 of 3/4.
1.11      ratchov   148:         */
                    149:        nfr = (bufsz + 5) / 6;
                    150:        nfr += dev_round - 1;
                    151:        nfr -= nfr % dev_round;
                    152:        if (nfr == 0)
                    153:                nfr = dev_round;
                    154:
                    155:        /*
1.27      ratchov   156:         * Create record chain.
1.1       ratchov   157:         */
                    158:        if (dipar) {
                    159:                aparams_init(&ipar, dipar->cmin, dipar->cmax, dipar->rate);
                    160:                /*
1.27      ratchov   161:                 * Create the read end.
1.1       ratchov   162:                 */
1.23      ratchov   163:                dev_rec = rpipe_new(f);
1.22      ratchov   164:                dev_rec->refs++;
1.4       ratchov   165:                buf = abuf_new(nfr, dipar);
1.1       ratchov   166:                aproc_setout(dev_rec, buf);
1.3       ratchov   167:                ibufsz += nfr;
1.1       ratchov   168:
                    169:                /*
1.27      ratchov   170:                 * Append a converter, if needed.
1.1       ratchov   171:                 */
1.4       ratchov   172:                if (!aparams_eqenc(dipar, &ipar)) {
1.30      ratchov   173:                        conv = dec_new("rec", dipar);
1.1       ratchov   174:                        aproc_setin(conv, buf);
1.4       ratchov   175:                        buf = abuf_new(nfr, &ipar);
1.1       ratchov   176:                        aproc_setout(conv, buf);
1.3       ratchov   177:                        ibufsz += nfr;
1.1       ratchov   178:                }
                    179:                dev_ipar = ipar;
                    180:
                    181:                /*
1.27      ratchov   182:                 * Append a "sub" to which clients will connect.
1.36    ! ratchov   183:                 * Link it to the controller only in record-only mode
1.1       ratchov   184:                 */
1.36    ! ratchov   185:                dev_sub = sub_new("rec", nfr, dopar ? NULL : dev_midi);
1.22      ratchov   186:                dev_sub->refs++;
1.1       ratchov   187:                aproc_setin(dev_sub, buf);
                    188:        } else {
                    189:                dev_rec = NULL;
                    190:                dev_sub = NULL;
                    191:        }
                    192:
                    193:        /*
1.27      ratchov   194:         * Create play chain.
1.1       ratchov   195:         */
                    196:        if (dopar) {
                    197:                aparams_init(&opar, dopar->cmin, dopar->cmax, dopar->rate);
                    198:                /*
1.27      ratchov   199:                 * Create the write end.
1.1       ratchov   200:                 */
1.23      ratchov   201:                dev_play = wpipe_new(f);
1.22      ratchov   202:                dev_play->refs++;
1.4       ratchov   203:                buf = abuf_new(nfr, dopar);
1.1       ratchov   204:                aproc_setin(dev_play, buf);
1.3       ratchov   205:                obufsz += nfr;
1.25      ratchov   206:
1.1       ratchov   207:                /*
1.27      ratchov   208:                 * Append a converter, if needed.
1.1       ratchov   209:                 */
1.4       ratchov   210:                if (!aparams_eqenc(&opar, dopar)) {
1.30      ratchov   211:                        conv = enc_new("play", dopar);
1.1       ratchov   212:                        aproc_setout(conv, buf);
1.4       ratchov   213:                        buf = abuf_new(nfr, &opar);
1.1       ratchov   214:                        aproc_setin(conv, buf);
1.3       ratchov   215:                        obufsz += nfr;
1.1       ratchov   216:                }
                    217:                dev_opar = opar;
                    218:
                    219:                /*
1.27      ratchov   220:                 * Append a "mix" to which clients will connect.
1.1       ratchov   221:                 */
1.36    ! ratchov   222:                dev_mix = mix_new("play", nfr, dev_midi);
1.22      ratchov   223:                dev_mix->refs++;
1.1       ratchov   224:                aproc_setout(dev_mix, buf);
                    225:        } else {
                    226:                dev_play = NULL;
                    227:                dev_mix = NULL;
                    228:        }
1.3       ratchov   229:        dev_bufsz = (dopar) ? obufsz : ibufsz;
                    230:        dev_start();
1.26      ratchov   231:        return 1;
1.1       ratchov   232: }
                    233:
                    234: /*
1.27      ratchov   235:  * Cleanly stop and drain everything and close the device
                    236:  * once both play chain and record chain are gone.
1.1       ratchov   237:  */
                    238: void
                    239: dev_done(void)
                    240: {
                    241:        struct file *f;
                    242:
1.3       ratchov   243:        if (dev_mix) {
                    244:                /*
1.32      ratchov   245:                 * Put the mixer in ``autoquit'' state and generate
                    246:                 * EOF on all inputs connected it. Once buffers are
                    247:                 * drained the mixer will terminate and shutdown the
                    248:                 * device.
1.3       ratchov   249:                 *
                    250:                 * NOTE: since file_eof() can destroy the file and
                    251:                 * reorder the file_list, we have to restart the loop
1.27      ratchov   252:                 * after each call to file_eof().
1.3       ratchov   253:                 */
1.36    ! ratchov   254:                dev_mix->flags |= APROC_QUIT;
1.32      ratchov   255:        restart_mix:
1.3       ratchov   256:                LIST_FOREACH(f, &file_list, entry) {
1.32      ratchov   257:                        if (f->rproc != NULL &&
                    258:                            aproc_depend(dev_mix, f->rproc)) {
1.3       ratchov   259:                                file_eof(f);
1.32      ratchov   260:                                goto restart_mix;
1.3       ratchov   261:                        }
                    262:                }
1.32      ratchov   263:        } else if (dev_sub) {
1.3       ratchov   264:                /*
1.32      ratchov   265:                 * Same as above, but since there's no mixer,
                    266:                 * we generate EOF on the record-end of the
                    267:                 * device.
                    268:                 */
                    269:        restart_sub:
                    270:                LIST_FOREACH(f, &file_list, entry) {
                    271:                        if (f->rproc != NULL &&
                    272:                            aproc_depend(dev_sub, f->rproc)) {
                    273:                                file_eof(f);
                    274:                                goto restart_sub;
1.23      ratchov   275:                        }
1.32      ratchov   276:                }
                    277:        }
1.36    ! ratchov   278:        if (dev_midi) {
        !           279:                dev_midi->flags |= APROC_QUIT;
        !           280:        restart_midi:
        !           281:                LIST_FOREACH(f, &file_list, entry) {
        !           282:                        if (f->rproc &&
        !           283:                            aproc_depend(dev_midi, f->rproc)) {
        !           284:                                file_eof(f);
        !           285:                                goto restart_midi;
        !           286:                        }
        !           287:                }
        !           288:        }
1.32      ratchov   289:        if (dev_mix) {
                    290:                dev_mix->refs--;
1.36    ! ratchov   291:                if (dev_mix->flags & APROC_ZOMB)
1.32      ratchov   292:                        aproc_del(dev_mix);
                    293:                dev_mix = NULL;
                    294:        }
                    295:        if (dev_play) {
                    296:                dev_play->refs--;
1.36    ! ratchov   297:                if (dev_play->flags & APROC_ZOMB)
1.23      ratchov   298:                        aproc_del(dev_play);
1.32      ratchov   299:                dev_play = NULL;
1.1       ratchov   300:        }
1.3       ratchov   301:        if (dev_sub) {
1.22      ratchov   302:                dev_sub->refs--;
1.36    ! ratchov   303:                if (dev_sub->flags & APROC_ZOMB)
1.32      ratchov   304:                        aproc_del(dev_sub);
1.22      ratchov   305:                dev_sub = NULL;
1.32      ratchov   306:        }
                    307:        if (dev_rec) {
                    308:                dev_rec->refs--;
1.36    ! ratchov   309:                if (dev_rec->flags & APROC_ZOMB)
1.23      ratchov   310:                        aproc_del(dev_rec);
1.32      ratchov   311:                dev_rec = NULL;
1.34      ratchov   312:        }
                    313:        if (dev_midi) {
                    314:                dev_midi->refs--;
1.36    ! ratchov   315:                if (dev_midi->flags & APROC_ZOMB)
1.34      ratchov   316:                        aproc_del(dev_midi);
                    317:                dev_midi = NULL;
1.32      ratchov   318:        }
                    319:        for (;;) {
                    320:                if (!file_poll())
                    321:                        break;
1.1       ratchov   322:        }
                    323: }
                    324:
                    325: /*
1.27      ratchov   326:  * Start the (paused) device. By default it's paused.
1.1       ratchov   327:  */
                    328: void
                    329: dev_start(void)
                    330: {
1.22      ratchov   331:        struct file *f;
                    332:
1.1       ratchov   333:        if (dev_mix)
1.36    ! ratchov   334:                dev_mix->flags |= APROC_DROP;
1.1       ratchov   335:        if (dev_sub)
1.36    ! ratchov   336:                dev_sub->flags |= APROC_DROP;
1.22      ratchov   337:        if (dev_play && dev_play->u.io.file) {
                    338:                f = dev_play->u.io.file;
                    339:                f->ops->start(f);
                    340:        } else if (dev_rec && dev_rec->u.io.file) {
                    341:                f = dev_rec->u.io.file;
                    342:                f->ops->start(f);
                    343:        }
1.1       ratchov   344: }
                    345:
                    346: /*
1.27      ratchov   347:  * Pause the device.
1.1       ratchov   348:  */
                    349: void
                    350: dev_stop(void)
                    351: {
1.22      ratchov   352:        struct file *f;
                    353:
                    354:        if (dev_play && dev_play->u.io.file) {
                    355:                f = dev_play->u.io.file;
                    356:                f->ops->stop(f);
                    357:        } else if (dev_rec && dev_rec->u.io.file) {
                    358:                f = dev_rec->u.io.file;
                    359:                f->ops->stop(f);
                    360:        }
1.1       ratchov   361:        if (dev_mix)
1.36    ! ratchov   362:                dev_mix->flags &= ~APROC_DROP;
1.1       ratchov   363:        if (dev_sub)
1.36    ! ratchov   364:                dev_sub->flags &= ~APROC_DROP;
1.1       ratchov   365: }
                    366:
                    367: /*
1.27      ratchov   368:  * Find the end points connected to the mix/sub.
1.14      ratchov   369:  */
                    370: int
                    371: dev_getep(struct abuf **sibuf, struct abuf **sobuf)
                    372: {
                    373:        struct abuf *ibuf, *obuf;
                    374:
                    375:        if (sibuf) {
                    376:                ibuf = *sibuf;
                    377:                for (;;) {
                    378:                        if (!ibuf || !ibuf->rproc) {
                    379:                                return 0;
                    380:                        }
                    381:                        if (ibuf->rproc == dev_mix)
                    382:                                break;
                    383:                        ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
                    384:                }
1.21      ratchov   385:                *sibuf = ibuf;
1.14      ratchov   386:        }
                    387:        if (sobuf) {
                    388:                obuf = *sobuf;
                    389:                for (;;) {
                    390:                        if (!obuf || !obuf->wproc) {
                    391:                                return 0;
                    392:                        }
                    393:                        if (obuf->wproc == dev_sub)
                    394:                                break;
                    395:                        obuf = LIST_FIRST(&obuf->wproc->ibuflist);
                    396:                }
1.21      ratchov   397:                *sobuf = obuf;
1.14      ratchov   398:        }
                    399:        return 1;
                    400: }
                    401:
                    402: /*
1.27      ratchov   403:  * Sync play buffer to rec buffer (for instance when one of
                    404:  * them underruns/overruns).
1.1       ratchov   405:  */
                    406: void
1.3       ratchov   407: dev_sync(struct abuf *ibuf, struct abuf *obuf)
1.1       ratchov   408: {
1.3       ratchov   409:        struct abuf *pbuf, *rbuf;
                    410:        int delta;
                    411:
                    412:        if (!dev_mix || !dev_sub)
                    413:                return;
                    414:        pbuf = LIST_FIRST(&dev_mix->obuflist);
                    415:        if (!pbuf)
                    416:                return;
                    417:        rbuf = LIST_FIRST(&dev_sub->ibuflist);
                    418:        if (!rbuf)
                    419:                return;
1.14      ratchov   420:        if (!dev_getep(&ibuf, &obuf))
                    421:                return;
1.3       ratchov   422:
                    423:        /*
1.27      ratchov   424:         * Calculate delta, the number of frames the play chain is ahead
1.3       ratchov   425:         * of the record chain. It's necessary to schedule silences (or
                    426:         * drops) in order to start playback and record in sync.
                    427:         */
1.25      ratchov   428:        delta =
                    429:            rbuf->bpf * (pbuf->abspos + pbuf->used) -
1.3       ratchov   430:            pbuf->bpf *  rbuf->abspos;
                    431:        delta /= pbuf->bpf * rbuf->bpf;
                    432:        if (delta > 0) {
                    433:                /*
1.27      ratchov   434:                 * If the play chain is ahead (most cases) drop some of
                    435:                 * the recorded input, to get both in sync.
1.3       ratchov   436:                 */
                    437:                obuf->drop += delta * obuf->bpf;
                    438:                abuf_ipos(obuf, -delta);
                    439:        } else if (delta < 0) {
                    440:                /*
1.27      ratchov   441:                 * If record chain is ahead (should never happen,
                    442:                 * right?) then insert silence to play.
1.3       ratchov   443:                 */
                    444:                ibuf->silence += -delta * ibuf->bpf;
                    445:                abuf_opos(ibuf, delta);
1.30      ratchov   446:        }
1.36    ! ratchov   447: }
        !           448:
        !           449: /*
        !           450:  * return the current latency (in frames), ie the latency that
        !           451:  * a stream would have if dev_attach() is called on it.
        !           452:  */
        !           453: int
        !           454: dev_getpos(void)
        !           455: {
        !           456:        struct abuf *pbuf = NULL, *rbuf = NULL;
        !           457:        int plat = 0, rlat = 0;
        !           458:        int delta;
        !           459:
        !           460:        if (dev_mix) {
        !           461:                pbuf = LIST_FIRST(&dev_mix->obuflist);
        !           462:                if (!pbuf)
        !           463:                        return 0;
        !           464:                plat = -dev_mix->u.mix.lat;
        !           465:        }
        !           466:        if (dev_sub) {
        !           467:                rbuf = LIST_FIRST(&dev_sub->ibuflist);
        !           468:                if (!rbuf)
        !           469:                        return 0;
        !           470:                rlat = -dev_sub->u.sub.lat;
        !           471:        }
        !           472:        if (dev_mix && dev_sub) {
        !           473:                delta =
        !           474:                    rbuf->bpf * (pbuf->abspos + pbuf->used) -
        !           475:                    pbuf->bpf *  rbuf->abspos;
        !           476:                delta /= pbuf->bpf * rbuf->bpf;
        !           477:                if (delta > 0)
        !           478:                        rlat -= delta;
        !           479:                else if (delta < 0)
        !           480:                        plat += delta;
        !           481:        }
        !           482:        return dev_mix ? plat : rlat;
1.1       ratchov   483: }
                    484:
                    485: /*
1.27      ratchov   486:  * Attach the given input and output buffers to the mixer and the
1.1       ratchov   487:  * multiplexer respectively. The operation is done synchronously, so
                    488:  * both buffers enter in sync. If buffers do not match play
1.27      ratchov   489:  * and rec.
1.1       ratchov   490:  */
                    491: void
1.25      ratchov   492: dev_attach(char *name,
                    493:     struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
1.18      ratchov   494:     struct abuf *obuf, struct aparams *sopar, unsigned overrun, int vol)
1.1       ratchov   495: {
                    496:        struct abuf *pbuf = NULL, *rbuf = NULL;
1.12      ratchov   497:        struct aparams ipar, opar;
1.1       ratchov   498:        struct aproc *conv;
1.20      ratchov   499:        unsigned round, nblk;
                    500:
1.1       ratchov   501:        if (ibuf) {
1.12      ratchov   502:                ipar = *sipar;
1.20      ratchov   503:                pbuf = LIST_FIRST(&dev_mix->obuflist);
                    504:                nblk = (dev_bufsz / dev_round + 3) / 4;
                    505:                round = dev_roundof(ipar.rate);
1.10      ratchov   506:                if (!aparams_eqenc(&ipar, &dev_opar)) {
                    507:                        conv = dec_new(name, &ipar);
                    508:                        ipar.bps = dev_opar.bps;
                    509:                        ipar.bits = dev_opar.bits;
                    510:                        ipar.sig = dev_opar.sig;
                    511:                        ipar.le = dev_opar.le;
                    512:                        ipar.msb = dev_opar.msb;
1.25      ratchov   513:                        aproc_setin(conv, ibuf);
1.20      ratchov   514:                        ibuf = abuf_new(nblk * round, &ipar);
1.9       ratchov   515:                        aproc_setout(conv, ibuf);
1.8       ratchov   516:                }
1.10      ratchov   517:                if (!aparams_subset(&ipar, &dev_opar)) {
                    518:                        conv = cmap_new(name, &ipar, &dev_opar);
                    519:                        ipar.cmin = dev_opar.cmin;
                    520:                        ipar.cmax = dev_opar.cmax;
1.7       ratchov   521:                        aproc_setin(conv, ibuf);
1.20      ratchov   522:                        ibuf = abuf_new(nblk * round, &ipar);
1.7       ratchov   523:                        aproc_setout(conv, ibuf);
1.6       ratchov   524:                }
1.10      ratchov   525:                if (!aparams_eqrate(&ipar, &dev_opar)) {
1.20      ratchov   526:                        conv = resamp_new(name, round, dev_round);
1.10      ratchov   527:                        ipar.rate = dev_opar.rate;
1.20      ratchov   528:                        round = dev_round;
1.5       ratchov   529:                        aproc_setin(conv, ibuf);
1.20      ratchov   530:                        ibuf = abuf_new(nblk * round, &ipar);
1.5       ratchov   531:                        aproc_setout(conv, ibuf);
1.1       ratchov   532:                }
                    533:                aproc_setin(dev_mix, ibuf);
1.3       ratchov   534:                abuf_opos(ibuf, -dev_mix->u.mix.lat);
1.31      ratchov   535:                ibuf->r.mix.xrun = underrun;
                    536:                ibuf->r.mix.maxweight = vol;
1.18      ratchov   537:                mix_setmaster(dev_mix);
1.1       ratchov   538:        }
                    539:        if (obuf) {
1.12      ratchov   540:                opar = *sopar;
1.1       ratchov   541:                rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.20      ratchov   542:                round = dev_roundof(opar.rate);
                    543:                nblk = (dev_bufsz / dev_round + 3) / 4;
1.10      ratchov   544:                if (!aparams_eqenc(&opar, &dev_ipar)) {
                    545:                        conv = enc_new(name, &opar);
                    546:                        opar.bps = dev_ipar.bps;
                    547:                        opar.bits = dev_ipar.bits;
                    548:                        opar.sig = dev_ipar.sig;
                    549:                        opar.le = dev_ipar.le;
                    550:                        opar.msb = dev_ipar.msb;
1.9       ratchov   551:                        aproc_setout(conv, obuf);
1.20      ratchov   552:                        obuf = abuf_new(nblk * round, &opar);
1.9       ratchov   553:                        aproc_setin(conv, obuf);
1.8       ratchov   554:                }
1.10      ratchov   555:                if (!aparams_subset(&opar, &dev_ipar)) {
                    556:                        conv = cmap_new(name, &dev_ipar, &opar);
                    557:                        opar.cmin = dev_ipar.cmin;
                    558:                        opar.cmax = dev_ipar.cmax;
1.7       ratchov   559:                        aproc_setout(conv, obuf);
1.20      ratchov   560:                        obuf = abuf_new(nblk * round, &opar);
1.7       ratchov   561:                        aproc_setin(conv, obuf);
1.6       ratchov   562:                }
1.10      ratchov   563:                if (!aparams_eqrate(&opar, &dev_ipar)) {
1.20      ratchov   564:                        conv = resamp_new(name, dev_round, round);
1.10      ratchov   565:                        opar.rate = dev_ipar.rate;
1.20      ratchov   566:                        round = dev_round;
1.1       ratchov   567:                        aproc_setout(conv, obuf);
1.20      ratchov   568:                        obuf = abuf_new(nblk * round, &opar);
1.1       ratchov   569:                        aproc_setin(conv, obuf);
                    570:                }
                    571:                aproc_setout(dev_sub, obuf);
1.3       ratchov   572:                abuf_ipos(obuf, -dev_sub->u.sub.lat);
1.31      ratchov   573:                obuf->w.sub.xrun = overrun;
1.1       ratchov   574:        }
                    575:
                    576:        /*
1.27      ratchov   577:         * Sync play to record.
1.1       ratchov   578:         */
                    579:        if (ibuf && obuf) {
1.3       ratchov   580:                ibuf->duplex = obuf;
                    581:                obuf->duplex = ibuf;
                    582:                dev_sync(ibuf, obuf);
1.13      ratchov   583:        }
1.14      ratchov   584: }
                    585:
                    586: /*
1.27      ratchov   587:  * Change the playback volume of the given stream.
1.14      ratchov   588:  */
                    589: void
                    590: dev_setvol(struct abuf *ibuf, int vol)
                    591: {
1.16      ratchov   592:        if (!dev_getep(&ibuf, NULL)) {
1.14      ratchov   593:                return;
1.16      ratchov   594:        }
1.31      ratchov   595:        ibuf->r.mix.vol = vol;
1.13      ratchov   596: }
                    597:
                    598: /*
1.27      ratchov   599:  * Clear buffers of the play and record chains so that when the device
                    600:  * is started, playback and record start in sync.
1.13      ratchov   601:  */
                    602: void
                    603: dev_clear(void)
                    604: {
                    605:        struct abuf *buf;
                    606:
                    607:        if (dev_mix) {
                    608:                buf = LIST_FIRST(&dev_mix->obuflist);
                    609:                while (buf) {
                    610:                        abuf_clear(buf);
                    611:                        buf = LIST_FIRST(&buf->rproc->obuflist);
                    612:                }
                    613:                mix_clear(dev_mix);
                    614:        }
                    615:        if (dev_sub) {
                    616:                buf = LIST_FIRST(&dev_sub->ibuflist);
                    617:                while (buf) {
                    618:                        abuf_clear(buf);
                    619:                        buf = LIST_FIRST(&buf->wproc->ibuflist);
                    620:                }
                    621:                sub_clear(dev_sub);
1.1       ratchov   622:        }
                    623: }