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

1.68    ! ratchov     1: /*     $OpenBSD: dev.c,v 1.67 2011/10/12 07:20:04 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.51      ratchov    17: /*
                     18:  * Device abstraction module
                     19:  *
                     20:  * This module exposes a ``enhanced device'' that uses aproc
                     21:  * structures framework; it does conversions on the fly and can
                     22:  * handle multiple streams.  The enhanced device starts and stops
                     23:  * automatically, when streams are attached, and provides
                     24:  * primitives for MIDI control
                     25:  *
                     26:  * From the main loop, the device is used as follows:
                     27:  *
1.57      ratchov    28:  *   1. create the device using dev_new_xxx()
1.51      ratchov    29:  *   2. call dev_run() in the event loop
1.57      ratchov    30:  *   3. destroy the device using dev_del()
1.51      ratchov    31:  *   4. continue running the event loop to drain
                     32:  *
                     33:  * The device is used as follows from aproc context:
                     34:  *
                     35:  *   1. open the device with dev_ref()
                     36:  *   2. negociate parameters (mode, rate, ...)
                     37:  *   3. create your stream (ie allocate and fill abufs)
                     38:  *   4. attach your stream atomically:
                     39:  *       - first call dev_wakeup() to ensure device is not suspended
                     40:  *       - possibly fetch dynamic parameters (eg. dev_getpos())
                     41:  *       - attach your buffers with dev_attach()
                     42:  *   5. close your stream, ie abuf_eof() or abuf_hup()
                     43:  *   6. close the device with dev_unref()
                     44:  *
                     45:  * The device has the following states:
                     46:  *
                     47:  * CLOSED      sio_open() is not called, it's not ready and
                     48:  *             no streams can be attached; dev_ref() must
                     49:  *             be called to open the device
                     50:  *
                     51:  * INIT                device is opened, processing chain is ready, but
                     52:  *             DMA is not started yet. Streams can attach,
                     53:  *             in which case device will automatically switch
                     54:  *             to the START state
                     55:  *
                     56:  * START       at least one stream is attached, play buffers
                     57:  *             are primed (if necessary) DMA is ready and
                     58:  *             will start immeadiately (next cycle)
                     59:  *
                     60:  * RUN         DMA is started. New streams can attach. If the
                     61:  *             device is idle (all streams are closed and
                     62:  *             finished draining), then the device
                     63:  *             automatically switches to INIT or CLOSED
                     64:  */
1.1       ratchov    65: #include <stdio.h>
                     66: #include <stdlib.h>
                     67: #include <unistd.h>
                     68:
                     69: #include "abuf.h"
                     70: #include "aproc.h"
1.27      ratchov    71: #include "conf.h"
                     72: #include "dev.h"
1.3       ratchov    73: #include "pipe.h"
1.38      ratchov    74: #include "miofile.h"
1.42      ratchov    75: #include "siofile.h"
1.28      ratchov    76: #include "midi.h"
1.46      ratchov    77: #include "opt.h"
1.39      ratchov    78: #ifdef DEBUG
                     79: #include "dbg.h"
                     80: #endif
1.1       ratchov    81:
1.57      ratchov    82: int  dev_open(struct dev *);
                     83: void dev_close(struct dev *);
                     84: void dev_start(struct dev *);
                     85: void dev_stop(struct dev *);
                     86: void dev_clear(struct dev *);
1.66      ratchov    87: int  devctl_open(struct dev *, struct devctl *);
1.57      ratchov    88:
                     89: struct dev *dev_list = NULL;
1.68    ! ratchov    90: unsigned dev_sndnum = 0, dev_thrnum = 0;
        !            91:
        !            92: #ifdef DEBUG
        !            93: void
        !            94: dev_dbg(struct dev *d)
        !            95: {
        !            96:        if (d->num >= DEV_NMAX) {
        !            97:                dbg_puts("thr");
        !            98:                dbg_putu(d->num - DEV_NMAX);
        !            99:        } else {
        !           100:                dbg_puts("snd");
        !           101:                dbg_putu(d->num);
        !           102:        }
        !           103: }
        !           104: #endif
1.38      ratchov   105:
                    106: /*
1.51      ratchov   107:  * Create a sndio device
1.28      ratchov   108:  */
1.57      ratchov   109: struct dev *
1.67      ratchov   110: dev_new(char *path, unsigned mode,
1.65      ratchov   111:     unsigned bufsz, unsigned round, unsigned hold, unsigned autovol)
1.57      ratchov   112: {
                    113:        struct dev *d;
1.68    ! ratchov   114:        unsigned *pnum;
1.57      ratchov   115:
                    116:        d = malloc(sizeof(struct dev));
                    117:        if (d == NULL) {
                    118:                perror("malloc");
                    119:                exit(1);
                    120:        }
1.68    ! ratchov   121:        pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum;
        !           122:        if (*pnum == DEV_NMAX) {
        !           123: #ifdef DEBUG
        !           124:                if (debug_level >= 1)
        !           125:                        dbg_puts("too many devices\n");
        !           126: #endif
        !           127:                return NULL;
        !           128:        }
        !           129:        d->num = (*pnum)++;
        !           130:        if (mode & MODE_THRU)
        !           131:                d->num += DEV_NMAX;
1.66      ratchov   132:        d->ctl_list = NULL;
1.57      ratchov   133:        d->path = path;
                    134:        d->reqmode = mode;
1.67      ratchov   135:        aparams_init(&d->reqopar, NCHAN_MAX, 0, 0);
                    136:        aparams_init(&d->reqipar, NCHAN_MAX, 0, 0);
1.57      ratchov   137:        d->reqbufsz = bufsz;
                    138:        d->reqround = round;
                    139:        d->hold = hold;
1.65      ratchov   140:        d->autovol = autovol;
1.67      ratchov   141:        d->autostart = 0;
1.57      ratchov   142:        d->pstate = DEV_CLOSED;
                    143:        d->next = dev_list;
1.68    ! ratchov   144:        dev_list = d;
1.57      ratchov   145:        return d;
1.28      ratchov   146: }
1.24      ratchov   147:
                    148: /*
1.67      ratchov   149:  * adjust device parameters and mode
1.24      ratchov   150:  */
1.67      ratchov   151: void
                    152: dev_adjpar(struct dev *d, unsigned mode,
                    153:     struct aparams *ipar, struct aparams *opar)
1.24      ratchov   154: {
1.67      ratchov   155:        d->reqmode |= (mode | MODE_MIDIMASK);
                    156:        if (mode & MODE_REC)
                    157:                aparams_grow(&d->reqipar, ipar);
                    158:        if (mode & MODE_PLAY)
                    159:                aparams_grow(&d->reqopar, opar);
1.24      ratchov   160: }
1.1       ratchov   161:
1.51      ratchov   162: /*
1.67      ratchov   163:  * Initialize the device with the current parameters
1.51      ratchov   164:  */
1.67      ratchov   165: int
                    166: dev_init(struct dev *d)
1.1       ratchov   167: {
1.67      ratchov   168:        if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) {
                    169: #ifdef DEBUG
1.68    ! ratchov   170:                    dev_dbg(d);
1.67      ratchov   171:                    dbg_puts(": has no streams, skipped\n");
                    172: #endif
                    173:                    return 1;
                    174:        }
                    175:        if (d->hold && d->pstate == DEV_CLOSED && !dev_open(d)) {
                    176:                dev_del(d);
                    177:                return 0;
1.57      ratchov   178:        }
1.67      ratchov   179:        return 1;
1.1       ratchov   180: }
                    181:
                    182: /*
1.66      ratchov   183:  * Add a MIDI port to the device
                    184:  */
                    185: int
1.68    ! ratchov   186: devctl_add(struct dev *d, char *path, unsigned mode)
1.66      ratchov   187: {
                    188:        struct devctl *c;
                    189:
                    190:        c = malloc(sizeof(struct devctl));
                    191:        if (c == NULL) {
                    192:                perror("malloc");
                    193:                exit(1);
                    194:        }
1.68    ! ratchov   195:        c->path = path;
1.66      ratchov   196:        c->mode = mode;
                    197:        c->next = d->ctl_list;
                    198:        d->ctl_list = c;
1.67      ratchov   199:        if (d->pstate != DEV_CLOSED && !devctl_open(d, c))
                    200:                return 0;
1.66      ratchov   201:        return 1;
                    202: }
                    203:
                    204: /*
                    205:  * Open a MIDI device and connect it to the thru box
                    206:  */
                    207: int
                    208: devctl_open(struct dev *d, struct devctl *c)
                    209: {
                    210:        struct file *f;
                    211:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    212:        struct aproc *rproc, *wproc;
                    213:
                    214:        f = (struct file *)miofile_new(&miofile_ops, c->path, c->mode);
                    215:        if (f == NULL)
                    216:                return 0;
                    217:        if (c->mode & MODE_MIDIIN) {
                    218:                rproc = rfile_new(f);
                    219:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                    220:                aproc_setout(rproc, rbuf);
                    221:        }
                    222:        if (c->mode & MODE_MIDIOUT) {
                    223:                wproc = wfile_new(f);
                    224:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                    225:                aproc_setin(wproc, wbuf);
                    226:        }
                    227:        dev_midiattach(d, rbuf, wbuf);
                    228:        return 1;
                    229: }
                    230:
                    231: /*
1.51      ratchov   232:  * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
                    233:  * monitor, midi control, and any necessary conversions.
1.1       ratchov   234:  */
1.26      ratchov   235: int
1.57      ratchov   236: dev_open(struct dev *d)
1.1       ratchov   237: {
1.23      ratchov   238:        struct file *f;
1.66      ratchov   239:        struct devctl *c;
1.51      ratchov   240:        struct aparams par;
1.1       ratchov   241:        struct aproc *conv;
                    242:        struct abuf *buf;
1.67      ratchov   243:        unsigned siomode, cmin, cmax, rate;
1.51      ratchov   244:
1.57      ratchov   245:        d->mode = d->reqmode;
                    246:        d->round = d->reqround;
                    247:        d->bufsz = d->reqbufsz;
                    248:        d->ipar = d->reqipar;
                    249:        d->opar = d->reqopar;
                    250:        d->rec = NULL;
                    251:        d->play = NULL;
                    252:        d->mon = NULL;
1.61      jakemsr   253:        d->mix = NULL;
                    254:        d->sub = NULL;
1.57      ratchov   255:        d->submon = NULL;
1.61      jakemsr   256:        d->midi = NULL;
1.57      ratchov   257:        d->rate = 0;
1.36      ratchov   258:
1.67      ratchov   259:        if (d->opar.cmin > d->opar.cmax) {
                    260:                d->opar.cmin = 0;
                    261:                d->opar.cmax = 1;
                    262:        }
                    263:        if (d->ipar.cmin > d->ipar.cmax) {
                    264:                d->ipar.cmin = 0;
                    265:                d->ipar.cmax = 1;
                    266:        }
                    267:        if (d->opar.rate > d->ipar.rate)
                    268:                d->ipar.rate = d->opar.rate;
                    269:        else
                    270:                d->opar.rate = d->ipar.rate;
                    271:        if (d->opar.rate == 0)
                    272:                d->opar.rate = d->ipar.rate = 44100; /* XXX */
                    273:
                    274:        if (d->mode & MODE_THRU)
                    275:                d->mode &= ~MODE_AUDIOMASK;
                    276:
1.3       ratchov   277:        /*
1.51      ratchov   278:         * If needed, open the device (ie create dev_rec and dev_play)
1.3       ratchov   279:         */
1.57      ratchov   280:        if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
                    281:                siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51      ratchov   282:                f = (struct file *)siofile_new(&siofile_ops,
1.57      ratchov   283:                    d->path,
1.51      ratchov   284:                    &siomode,
1.57      ratchov   285:                    &d->ipar,
                    286:                    &d->opar,
                    287:                    &d->bufsz,
                    288:                    &d->round);
1.51      ratchov   289:                if (f == NULL) {
1.39      ratchov   290: #ifdef DEBUG
1.51      ratchov   291:                        if (debug_level >= 1) {
1.68    ! ratchov   292:                                dev_dbg(d);
        !           293:                                dbg_puts(": ");
1.62      ratchov   294:                                dbg_puts(d->path);
1.51      ratchov   295:                                dbg_puts(": failed to open audio device\n");
                    296:                        }
                    297: #endif
                    298:                        return 0;
1.39      ratchov   299:                }
1.51      ratchov   300:                if (!(siomode & MODE_PLAY))
1.57      ratchov   301:                        d->mode &= ~(MODE_PLAY | MODE_MON);
1.51      ratchov   302:                if (!(siomode & MODE_REC))
1.57      ratchov   303:                        d->mode &= ~MODE_REC;
                    304:                if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51      ratchov   305: #ifdef DEBUG
                    306:                        if (debug_level >= 1) {
1.68    ! ratchov   307:                                dev_dbg(d);
1.51      ratchov   308:                                dbg_puts(": mode not supported by device\n");
                    309:                        }
1.39      ratchov   310: #endif
1.51      ratchov   311:                        return 0;
                    312:                }
1.57      ratchov   313:                d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.67      ratchov   314:                if (d->mode & MODE_REC) {
                    315:                        d->rec = rsio_new(f);
                    316:                        d->rec->refs++;
                    317:                }
                    318:                if (d->mode & MODE_PLAY) {
                    319:                        d->play = wsio_new(f);
                    320:                        d->play->refs++;
                    321:                }
                    322:        }
                    323:        if (d->mode & MODE_LOOP) {
                    324:                if (d->mode & MODE_MON) {
1.39      ratchov   325: #ifdef DEBUG
1.67      ratchov   326:                        if (debug_level >= 1) {
                    327:                                dbg_puts("monitoring not allowed "
                    328:                                    "in loopback mode\n");
1.51      ratchov   329:                        }
1.67      ratchov   330: #endif
                    331:                        return 0;
                    332:                }
                    333:                if ((d->mode & MODE_PLAYREC) != MODE_PLAYREC) {
                    334: #ifdef DEBUG
                    335:                        if (debug_level >= 1) {
                    336:                                dbg_puts("both play and record streams "
                    337:                                    "required in loopback mode\n");
1.51      ratchov   338:                        }
1.67      ratchov   339: #endif
                    340:                        return 0;
1.39      ratchov   341:                }
1.67      ratchov   342:                if (d->ctl_list) {
                    343: #ifdef DEBUG
                    344:                        if (debug_level >= 1) {
                    345:                                dbg_puts("MIDI control not allowed "
                    346:                                    "in loopback mode\n");
                    347:                        }
1.39      ratchov   348: #endif
1.67      ratchov   349:                        return 0;
                    350:                }
                    351:                cmin = (d->ipar.cmin < d->opar.cmin) ?
                    352:                    d->ipar.cmin : d->opar.cmin;
                    353:                cmax = (d->ipar.cmax > d->opar.cmax) ?
                    354:                    d->ipar.cmax : d->opar.cmax;
                    355:                rate = (d->ipar.rate > d->opar.rate) ?
                    356:                    d->ipar.rate : d->opar.rate;
                    357:                aparams_init(&par, cmin, cmax, rate);
                    358:                d->ipar = par;
                    359:                d->opar = par;
                    360:                d->rate = rate;
                    361:                d->round = rate;
                    362:                d->bufsz = 2 * d->round;
                    363:        }
                    364: #ifdef DEBUG
                    365:        if (debug_level >= 2) {
1.57      ratchov   366:                if (d->mode & MODE_REC) {
1.68    ! ratchov   367:                        dev_dbg(d);
1.67      ratchov   368:                        dbg_puts(": recording ");
                    369:                        aparams_dbg(&d->ipar);
                    370:                        dbg_puts("\n");
1.57      ratchov   371:                }
                    372:                if (d->mode & MODE_PLAY) {
1.68    ! ratchov   373:                        dev_dbg(d);
1.67      ratchov   374:                        dbg_puts(": playing ");
                    375:                        aparams_dbg(&d->opar);
                    376:                        dbg_puts("\n");
1.51      ratchov   377:                }
1.3       ratchov   378:        }
1.67      ratchov   379: #endif
1.11      ratchov   380:        /*
1.51      ratchov   381:         * Create the midi control end, or a simple thru box
                    382:         * if there's no device
                    383:         */
1.64      ratchov   384:        if (d->mode & MODE_MIDIMASK) {
1.67      ratchov   385:                d->midi = (d->mode & MODE_THRU) ?
                    386:                    thru_new("thru") : ctl_new("ctl", d);
1.64      ratchov   387:                d->midi->refs++;
                    388:        }
1.51      ratchov   389:
                    390:        /*
                    391:         * Create mixer, demuxer and monitor
1.1       ratchov   392:         */
1.57      ratchov   393:        if (d->mode & MODE_PLAY) {
1.65      ratchov   394:                d->mix = mix_new("play", d->bufsz, d->round, d->autovol);
1.57      ratchov   395:                d->mix->refs++;
                    396:                d->mix->u.mix.ctl = d->midi;
                    397:        }
                    398:        if (d->mode & MODE_REC) {
                    399:                d->sub = sub_new("rec", d->bufsz, d->round);
                    400:                d->sub->refs++;
1.51      ratchov   401:                /*
                    402:                 * If not playing, use the record end as clock source
                    403:                 */
1.57      ratchov   404:                if (!(d->mode & MODE_PLAY))
                    405:                        d->sub->u.sub.ctl = d->midi;
1.51      ratchov   406:        }
1.57      ratchov   407:        if (d->mode & MODE_LOOP) {
1.51      ratchov   408:                /*
                    409:                 * connect mixer out to demuxer in
                    410:                 */
1.57      ratchov   411:                buf = abuf_new(d->bufsz, &d->opar);
                    412:                aproc_setout(d->mix, buf);
                    413:                aproc_setin(d->sub, buf);
                    414:
                    415:                d->mix->flags |= APROC_QUIT;
                    416:                d->sub->flags |= APROC_QUIT;
1.51      ratchov   417:        }
1.57      ratchov   418:        if (d->rec) {
                    419:                aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51      ratchov   420:
1.1       ratchov   421:                /*
1.51      ratchov   422:                 * Create device <-> demuxer buffer
1.1       ratchov   423:                 */
1.57      ratchov   424:                buf = abuf_new(d->bufsz, &d->ipar);
                    425:                aproc_setout(d->rec, buf);
1.1       ratchov   426:
                    427:                /*
1.51      ratchov   428:                 * Insert a converter, if needed.
1.1       ratchov   429:                 */
1.57      ratchov   430:                if (!aparams_eqenc(&d->ipar, &par)) {
                    431:                        conv = dec_new("rec", &d->ipar);
1.1       ratchov   432:                        aproc_setin(conv, buf);
1.57      ratchov   433:                        buf = abuf_new(d->round, &par);
1.1       ratchov   434:                        aproc_setout(conv, buf);
                    435:                }
1.57      ratchov   436:                d->ipar = par;
                    437:                aproc_setin(d->sub, buf);
1.1       ratchov   438:        }
1.57      ratchov   439:        if (d->play) {
                    440:                aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1       ratchov   441:
                    442:                /*
1.51      ratchov   443:                 * Create device <-> mixer buffer
1.1       ratchov   444:                 */
1.57      ratchov   445:                buf = abuf_new(d->bufsz, &d->opar);
                    446:                aproc_setin(d->play, buf);
1.25      ratchov   447:
1.1       ratchov   448:                /*
1.27      ratchov   449:                 * Append a converter, if needed.
1.1       ratchov   450:                 */
1.57      ratchov   451:                if (!aparams_eqenc(&par, &d->opar)) {
                    452:                        conv = enc_new("play", &d->opar);
1.1       ratchov   453:                        aproc_setout(conv, buf);
1.57      ratchov   454:                        buf = abuf_new(d->round, &par);
1.1       ratchov   455:                        aproc_setin(conv, buf);
                    456:                }
1.57      ratchov   457:                d->opar = par;
                    458:                aproc_setout(d->mix, buf);
1.1       ratchov   459:        }
1.57      ratchov   460:        if (d->mode & MODE_MON) {
                    461:                d->mon = mon_new("mon", d->bufsz);
                    462:                d->mon->refs++;
                    463:                buf = abuf_new(d->bufsz, &d->opar);
                    464:                aproc_setout(d->mon, buf);
1.46      ratchov   465:
                    466:                /*
                    467:                 * Append a "sub" to which clients will connect.
                    468:                 */
1.57      ratchov   469:                d->submon = sub_new("mon", d->bufsz, d->round);
                    470:                d->submon->refs++;
                    471:                aproc_setin(d->submon, buf);
1.46      ratchov   472:
                    473:                /*
1.51      ratchov   474:                 * Attach to the mixer
1.46      ratchov   475:                 */
1.57      ratchov   476:                d->mix->u.mix.mon = d->mon;
                    477:                d->mon->refs++;
1.46      ratchov   478:        }
1.39      ratchov   479: #ifdef DEBUG
1.51      ratchov   480:        if (debug_level >= 2) {
1.57      ratchov   481:                if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.68    ! ratchov   482:                        dev_dbg(d);
1.62      ratchov   483:                        dbg_puts(": block size is ");
1.57      ratchov   484:                        dbg_putu(d->round);
1.51      ratchov   485:                        dbg_puts(" frames, using ");
1.57      ratchov   486:                        dbg_putu(d->bufsz / d->round);
1.51      ratchov   487:                        dbg_puts(" blocks\n");
                    488:                }
1.39      ratchov   489:        }
                    490: #endif
1.57      ratchov   491:        d->pstate = DEV_INIT;
1.66      ratchov   492:        for (c = d->ctl_list; c != NULL; c = c->next) {
                    493:                if (!devctl_open(d, c)) {
                    494: #ifdef DEBUG
                    495:                        if (debug_level >= 1) {
                    496:                                dbg_puts(c->path);
                    497:                                dbg_puts(": couldn't open MIDI port\n");
                    498:                        }
                    499: #endif
                    500:                        dev_close(d);
                    501:                        return 0;
                    502:                }
                    503:        }
1.26      ratchov   504:        return 1;
1.1       ratchov   505: }
                    506:
                    507: /*
1.27      ratchov   508:  * Cleanly stop and drain everything and close the device
                    509:  * once both play chain and record chain are gone.
1.1       ratchov   510:  */
                    511: void
1.57      ratchov   512: dev_close(struct dev *d)
1.1       ratchov   513: {
                    514:        struct file *f;
                    515:
1.50      ratchov   516:        /*
                    517:         * if the device is starting, ensure it actually starts
                    518:         * so buffers are drained, else clear any buffers
                    519:         */
1.57      ratchov   520:        switch (d->pstate) {
1.50      ratchov   521:        case DEV_START:
                    522: #ifdef DEBUG
                    523:                if (debug_level >= 3)
                    524:                        dbg_puts("draining device\n");
                    525: #endif
1.57      ratchov   526:                dev_start(d);
1.50      ratchov   527:                break;
                    528:        case DEV_INIT:
                    529: #ifdef DEBUG
                    530:                if (debug_level >= 3)
                    531:                        dbg_puts("flushing device\n");
                    532: #endif
1.57      ratchov   533:                dev_clear(d);
1.50      ratchov   534:                break;
                    535:        }
1.39      ratchov   536: #ifdef DEBUG
                    537:        if (debug_level >= 2)
1.51      ratchov   538:                dbg_puts("closing device\n");
1.39      ratchov   539: #endif
1.51      ratchov   540:
1.57      ratchov   541:        if (d->mix) {
1.3       ratchov   542:                /*
1.32      ratchov   543:                 * Put the mixer in ``autoquit'' state and generate
                    544:                 * EOF on all inputs connected it. Once buffers are
                    545:                 * drained the mixer will terminate and shutdown the
                    546:                 * device.
1.3       ratchov   547:                 *
                    548:                 * NOTE: since file_eof() can destroy the file and
                    549:                 * reorder the file_list, we have to restart the loop
1.27      ratchov   550:                 * after each call to file_eof().
1.3       ratchov   551:                 */
1.57      ratchov   552:                if (APROC_OK(d->mix))
                    553:                        mix_quit(d->mix);
1.51      ratchov   554:
                    555:                /*
                    556:                 * XXX: handle this in mix_done()
                    557:                 */
1.57      ratchov   558:                if (APROC_OK(d->mix->u.mix.mon)) {
                    559:                        d->mix->u.mix.mon->refs--;
                    560:                        aproc_del(d->mix->u.mix.mon);
                    561:                        d->mix->u.mix.mon = NULL;
1.46      ratchov   562:                }
1.32      ratchov   563:        restart_mix:
1.3       ratchov   564:                LIST_FOREACH(f, &file_list, entry) {
1.32      ratchov   565:                        if (f->rproc != NULL &&
1.57      ratchov   566:                            aproc_depend(d->mix, f->rproc)) {
1.3       ratchov   567:                                file_eof(f);
1.32      ratchov   568:                                goto restart_mix;
1.3       ratchov   569:                        }
                    570:                }
1.59      ratchov   571:        } else if (d->sub) {
1.3       ratchov   572:                /*
1.32      ratchov   573:                 * Same as above, but since there's no mixer,
                    574:                 * we generate EOF on the record-end of the
                    575:                 * device.
                    576:                 */
                    577:        restart_sub:
                    578:                LIST_FOREACH(f, &file_list, entry) {
                    579:                        if (f->rproc != NULL &&
1.59      ratchov   580:                            aproc_depend(d->sub, f->rproc)) {
1.32      ratchov   581:                                file_eof(f);
                    582:                                goto restart_sub;
1.59      ratchov   583:                        }
                    584:                }
                    585:        } else if (d->submon) {
                    586:                /*
                    587:                 * Same as above
                    588:                 */
                    589:        restart_submon:
                    590:                LIST_FOREACH(f, &file_list, entry) {
                    591:                        if (f->rproc != NULL &&
                    592:                            aproc_depend(d->submon, f->rproc)) {
                    593:                                file_eof(f);
                    594:                                goto restart_submon;
1.23      ratchov   595:                        }
1.32      ratchov   596:                }
                    597:        }
1.57      ratchov   598:        if (d->midi) {
                    599:                d->midi->flags |= APROC_QUIT;
                    600:                if (LIST_EMPTY(&d->midi->ins))
                    601:                        aproc_del(d->midi);
1.36      ratchov   602:        restart_midi:
                    603:                LIST_FOREACH(f, &file_list, entry) {
                    604:                        if (f->rproc &&
1.57      ratchov   605:                            aproc_depend(d->midi, f->rproc)) {
1.36      ratchov   606:                                file_eof(f);
                    607:                                goto restart_midi;
                    608:                        }
                    609:                }
                    610:        }
1.57      ratchov   611:        if (d->mix) {
                    612:                if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
                    613:                        aproc_del(d->mix);
                    614:                d->mix = NULL;
                    615:        }
                    616:        if (d->play) {
                    617:                if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
                    618:                        aproc_del(d->play);
                    619:                d->play = NULL;
                    620:        }
                    621:        if (d->sub) {
                    622:                if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
                    623:                        aproc_del(d->sub);
                    624:                d->sub = NULL;
                    625:        }
                    626:        if (d->rec) {
                    627:                if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
                    628:                        aproc_del(d->rec);
                    629:                d->rec = NULL;
                    630:        }
                    631:        if (d->submon) {
                    632:                if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
                    633:                        aproc_del(d->submon);
                    634:                d->submon = NULL;
                    635:        }
                    636:        if (d->mon) {
                    637:                if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
                    638:                        aproc_del(d->mon);
                    639:                d->mon = NULL;
                    640:        }
                    641:        if (d->midi) {
                    642:                if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
                    643:                        aproc_del(d->midi);
                    644:                d->midi = NULL;
1.32      ratchov   645:        }
1.57      ratchov   646:        d->pstate = DEV_CLOSED;
1.51      ratchov   647: }
                    648:
                    649: /*
1.60      ratchov   650:  * Unless the device is already in process of closing, request it to close
                    651:  */
                    652: void
                    653: dev_drain(struct dev *d)
                    654: {
                    655:        if (d->pstate != DEV_CLOSED)
                    656:                dev_close(d);
                    657: }
                    658:
                    659: /*
1.51      ratchov   660:  * Free the device
                    661:  */
                    662: void
1.57      ratchov   663: dev_del(struct dev *d)
1.51      ratchov   664: {
1.57      ratchov   665:        struct dev **p;
                    666:
1.60      ratchov   667:        dev_drain(d);
1.57      ratchov   668:        for (p = &dev_list; *p != d; p = &(*p)->next) {
                    669: #ifdef DEBUG
                    670:                if (*p == NULL) {
                    671:                        dbg_puts("device to delete not on the list\n");
                    672:                        dbg_panic();
                    673:                }
                    674: #endif
                    675:        }
                    676:        *p = d->next;
                    677:        free(d);
1.51      ratchov   678: }
                    679:
                    680: /*
                    681:  * Attach a bi-directional MIDI stream to the MIDI device
                    682:  */
                    683: void
1.57      ratchov   684: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51      ratchov   685: {
                    686:        if (ibuf)
1.57      ratchov   687:                aproc_setin(d->midi, ibuf);
1.51      ratchov   688:        if (obuf) {
1.57      ratchov   689:                aproc_setout(d->midi, obuf);
1.51      ratchov   690:                if (ibuf) {
                    691:                        ibuf->duplex = obuf;
                    692:                        obuf->duplex = ibuf;
                    693:                }
1.1       ratchov   694:        }
                    695: }
                    696:
1.51      ratchov   697: unsigned
1.57      ratchov   698: dev_roundof(struct dev *d, unsigned newrate)
1.51      ratchov   699: {
1.57      ratchov   700:        return (d->round * newrate + d->rate / 2) / d->rate;
1.51      ratchov   701: }
                    702:
1.1       ratchov   703: /*
1.27      ratchov   704:  * Start the (paused) device. By default it's paused.
1.1       ratchov   705:  */
                    706: void
1.57      ratchov   707: dev_start(struct dev *d)
1.1       ratchov   708: {
1.22      ratchov   709:        struct file *f;
                    710:
1.46      ratchov   711: #ifdef DEBUG
                    712:        if (debug_level >= 2)
1.51      ratchov   713:                dbg_puts("starting device\n");
1.46      ratchov   714: #endif
1.57      ratchov   715:        d->pstate = DEV_RUN;
                    716:        if (d->mode & MODE_LOOP)
1.52      ratchov   717:                return;
1.57      ratchov   718:        if (APROC_OK(d->mix))
                    719:                d->mix->flags |= APROC_DROP;
                    720:        if (APROC_OK(d->sub))
                    721:                d->sub->flags |= APROC_DROP;
                    722:        if (APROC_OK(d->submon))
                    723:                d->submon->flags |= APROC_DROP;
                    724:        if (APROC_OK(d->play) && d->play->u.io.file) {
                    725:                f = d->play->u.io.file;
1.22      ratchov   726:                f->ops->start(f);
1.57      ratchov   727:        } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
                    728:                f = d->rec->u.io.file;
1.22      ratchov   729:                f->ops->start(f);
                    730:        }
1.1       ratchov   731: }
                    732:
                    733: /*
1.46      ratchov   734:  * Pause the device. This may trigger context switches,
                    735:  * so it shouldn't be called from aproc methods
1.1       ratchov   736:  */
                    737: void
1.57      ratchov   738: dev_stop(struct dev *d)
1.1       ratchov   739: {
1.22      ratchov   740:        struct file *f;
                    741:
1.52      ratchov   742: #ifdef DEBUG
                    743:        if (debug_level >= 2)
1.57      ratchov   744:                dbg_puts("device stopped\n");
1.52      ratchov   745: #endif
1.57      ratchov   746:        d->pstate = DEV_INIT;
                    747:        if (d->mode & MODE_LOOP)
1.52      ratchov   748:                return;
1.57      ratchov   749:        if (APROC_OK(d->play) && d->play->u.io.file) {
                    750:                f = d->play->u.io.file;
1.22      ratchov   751:                f->ops->stop(f);
1.57      ratchov   752:        } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
                    753:                f = d->rec->u.io.file;
1.22      ratchov   754:                f->ops->stop(f);
                    755:        }
1.57      ratchov   756:        if (APROC_OK(d->mix))
                    757:                d->mix->flags &= ~APROC_DROP;
                    758:        if (APROC_OK(d->sub))
                    759:                d->sub->flags &= ~APROC_DROP;
                    760:        if (APROC_OK(d->submon))
                    761:                d->submon->flags &= ~APROC_DROP;
1.51      ratchov   762: }
                    763:
                    764: int
1.57      ratchov   765: dev_ref(struct dev *d)
1.51      ratchov   766: {
                    767: #ifdef DEBUG
                    768:        if (debug_level >= 3)
                    769:                dbg_puts("device requested\n");
                    770: #endif
1.57      ratchov   771:        if (d->pstate == DEV_CLOSED && !dev_open(d)) {
                    772:                if (d->hold)
                    773:                        dev_del(d);
1.51      ratchov   774:                return 0;
1.57      ratchov   775:        }
                    776:        d->refcnt++;
1.51      ratchov   777:        return 1;
                    778: }
                    779:
                    780: void
1.57      ratchov   781: dev_unref(struct dev *d)
1.51      ratchov   782: {
                    783: #ifdef DEBUG
                    784:        if (debug_level >= 3)
                    785:                dbg_puts("device released\n");
                    786: #endif
1.57      ratchov   787:        d->refcnt--;
                    788:        if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
                    789:                dev_close(d);
1.51      ratchov   790: }
                    791:
                    792: /*
                    793:  * There are actions (like start/stop/close ... ) that may trigger aproc
                    794:  * operations, a thus cannot be started from aproc context.
                    795:  * To avoid problems, aprocs only change the s!tate of the device,
                    796:  * and actual operations are triggered from the main loop,
                    797:  * outside the aproc code path.
                    798:  *
                    799:  * The following routine invokes pending actions, returns 0
                    800:  * on fatal error
                    801:  */
                    802: int
1.57      ratchov   803: dev_run(struct dev *d)
1.51      ratchov   804: {
1.57      ratchov   805:        if (d->pstate == DEV_CLOSED)
1.51      ratchov   806:                return 1;
                    807:        /*
                    808:         * check if device isn't gone
                    809:         */
1.57      ratchov   810:        if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
                    811:            ((d->mode & MODE_REC)  && !APROC_OK(d->sub)) ||
                    812:            ((d->mode & MODE_MON)  && !APROC_OK(d->submon))) {
1.51      ratchov   813: #ifdef DEBUG
                    814:                if (debug_level >= 1)
                    815:                        dbg_puts("device disappeared\n");
                    816: #endif
1.57      ratchov   817:                if (d->hold) {
                    818:                        dev_del(d);
                    819:                        return 0;
                    820:                }
                    821:                dev_close(d);
                    822:                return 1;
1.51      ratchov   823:        }
1.57      ratchov   824:        switch (d->pstate) {
1.51      ratchov   825:        case DEV_INIT:
                    826:                /* nothing */
                    827:                break;
                    828:        case DEV_START:
1.57      ratchov   829:                dev_start(d);
1.51      ratchov   830:                /* PASSTHROUGH */
                    831:        case DEV_RUN:
                    832:                /*
                    833:                 * if the device is not used, then stop it
                    834:                 */
1.57      ratchov   835:                if ((!APROC_OK(d->mix) ||
                    836:                        d->mix->u.mix.idle > 2 * d->bufsz) &&
                    837:                    (!APROC_OK(d->sub) ||
                    838:                        d->sub->u.sub.idle > 2 * d->bufsz) &&
                    839:                    (!APROC_OK(d->submon) ||
                    840:                        d->submon->u.sub.idle > 2 * d->bufsz) &&
                    841:                    (!APROC_OK(d->midi) ||
                    842:                        d->midi->u.ctl.tstate != CTL_RUN)) {
1.51      ratchov   843: #ifdef DEBUG
                    844:                        if (debug_level >= 3)
                    845:                                dbg_puts("device idle, suspending\n");
1.46      ratchov   846: #endif
1.57      ratchov   847:                        dev_stop(d);
                    848:                        if (d->refcnt == 0 && !d->hold)
                    849:                                dev_close(d);
1.58      ratchov   850:                        else
1.57      ratchov   851:                                dev_clear(d);
1.51      ratchov   852:                }
                    853:                break;
                    854:        }
                    855:        return 1;
                    856: }
                    857:
                    858: /*
1.58      ratchov   859:  * If the device is paused, then resume it.
1.51      ratchov   860:  * This routine can be called from aproc context.
                    861:  */
                    862: void
1.57      ratchov   863: dev_wakeup(struct dev *d)
1.51      ratchov   864: {
1.57      ratchov   865:        if (d->pstate == DEV_INIT)
                    866:                d->pstate = DEV_START;
1.1       ratchov   867: }
                    868:
                    869: /*
1.27      ratchov   870:  * Find the end points connected to the mix/sub.
1.14      ratchov   871:  */
                    872: int
1.57      ratchov   873: dev_getep(struct dev *d,
                    874:     unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
1.14      ratchov   875: {
                    876:        struct abuf *ibuf, *obuf;
                    877:
1.46      ratchov   878:        if (mode & MODE_PLAY) {
1.57      ratchov   879:                if (!APROC_OK(d->mix))
1.46      ratchov   880:                        return 0;
1.14      ratchov   881:                ibuf = *sibuf;
                    882:                for (;;) {
                    883:                        if (!ibuf || !ibuf->rproc) {
1.39      ratchov   884: #ifdef DEBUG
                    885:                                if (debug_level >= 3) {
                    886:                                        abuf_dbg(*sibuf);
                    887:                                        dbg_puts(": not connected to device\n");
                    888:                                }
                    889: #endif
1.14      ratchov   890:                                return 0;
                    891:                        }
1.57      ratchov   892:                        if (ibuf->rproc == d->mix)
1.14      ratchov   893:                                break;
1.49      ratchov   894:                        ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14      ratchov   895:                }
1.21      ratchov   896:                *sibuf = ibuf;
1.14      ratchov   897:        }
1.46      ratchov   898:        if (mode & MODE_REC) {
1.57      ratchov   899:                if (!APROC_OK(d->sub))
1.46      ratchov   900:                        return 0;
1.14      ratchov   901:                obuf = *sobuf;
                    902:                for (;;) {
                    903:                        if (!obuf || !obuf->wproc) {
1.39      ratchov   904: #ifdef DEBUG
                    905:                                if (debug_level >= 3) {
                    906:                                        abuf_dbg(*sobuf);
                    907:                                        dbg_puts(": not connected to device\n");
                    908:                                }
                    909: #endif
1.14      ratchov   910:                                return 0;
                    911:                        }
1.57      ratchov   912:                        if (obuf->wproc == d->sub)
1.14      ratchov   913:                                break;
1.49      ratchov   914:                        obuf = LIST_FIRST(&obuf->wproc->ins);
1.14      ratchov   915:                }
1.21      ratchov   916:                *sobuf = obuf;
1.14      ratchov   917:        }
1.46      ratchov   918:        if (mode & MODE_MON) {
1.57      ratchov   919:                if (!APROC_OK(d->submon))
1.46      ratchov   920:                        return 0;
                    921:                obuf = *sobuf;
                    922:                for (;;) {
                    923:                        if (!obuf || !obuf->wproc) {
                    924: #ifdef DEBUG
                    925:                                if (debug_level >= 3) {
                    926:                                        abuf_dbg(*sobuf);
                    927:                                        dbg_puts(": not connected to device\n");
                    928:                                }
                    929: #endif
                    930:                                return 0;
                    931:                        }
1.57      ratchov   932:                        if (obuf->wproc == d->submon)
1.46      ratchov   933:                                break;
1.49      ratchov   934:                        obuf = LIST_FIRST(&obuf->wproc->ins);
1.46      ratchov   935:                }
                    936:                *sobuf = obuf;
                    937:        }
1.14      ratchov   938:        return 1;
                    939: }
                    940:
                    941: /*
1.27      ratchov   942:  * Sync play buffer to rec buffer (for instance when one of
                    943:  * them underruns/overruns).
1.1       ratchov   944:  */
                    945: void
1.57      ratchov   946: dev_sync(struct dev *d, unsigned mode, struct abuf *ibuf, struct abuf *obuf)
1.1       ratchov   947: {
1.53      ratchov   948:        int delta, offs;
1.57      ratchov   949:        struct abuf *mbuf = NULL;
1.3       ratchov   950:
1.57      ratchov   951:        if (!dev_getep(d, mode, &ibuf, &obuf))
1.3       ratchov   952:                return;
                    953:        /*
1.27      ratchov   954:         * Calculate delta, the number of frames the play chain is ahead
1.3       ratchov   955:         * of the record chain. It's necessary to schedule silences (or
                    956:         * drops) in order to start playback and record in sync.
                    957:         */
1.53      ratchov   958:        offs = 0;
                    959:        delta = 0;
1.57      ratchov   960:        if (APROC_OK(d->mix)) {
                    961:                mbuf = LIST_FIRST(&d->mix->outs);
1.53      ratchov   962:                offs += mbuf->w.mix.todo;
1.57      ratchov   963:                delta += d->mix->u.mix.lat;
1.53      ratchov   964:        }
1.57      ratchov   965:        if (APROC_OK(d->sub))
                    966:                delta += d->sub->u.sub.lat;
1.39      ratchov   967: #ifdef DEBUG
                    968:        if (debug_level >= 3) {
1.53      ratchov   969:                dbg_puts("syncing device");
1.57      ratchov   970:                if (APROC_OK(d->mix)) {
1.51      ratchov   971:                        dbg_puts(", ");
1.57      ratchov   972:                        aproc_dbg(d->mix);
1.53      ratchov   973:                        dbg_puts(": todo = ");
                    974:                        dbg_putu(mbuf->w.mix.todo);
                    975:                        dbg_puts(": lat = ");
1.57      ratchov   976:                        dbg_putu(d->mix->u.mix.lat);
1.46      ratchov   977:                }
1.57      ratchov   978:                if (APROC_OK(d->sub)) {
1.51      ratchov   979:                        dbg_puts(", ");
1.57      ratchov   980:                        aproc_dbg(d->sub);
1.53      ratchov   981:                        dbg_puts(": lat = ");
1.57      ratchov   982:                        dbg_putu(d->sub->u.sub.lat);
1.46      ratchov   983:                }
1.39      ratchov   984:                dbg_puts("\n");
                    985:        }
                    986: #endif
1.53      ratchov   987:        if (mode & MODE_PLAY)
                    988:                mix_drop(ibuf, -offs);
                    989:        if (mode & MODE_RECMASK)
                    990:                sub_silence(obuf, -(offs + delta));
1.36      ratchov   991: }
                    992:
                    993: /*
                    994:  * return the current latency (in frames), ie the latency that
                    995:  * a stream would have if dev_attach() is called on it.
                    996:  */
                    997: int
1.57      ratchov   998: dev_getpos(struct dev *d)
1.36      ratchov   999: {
1.53      ratchov  1000:        struct abuf *mbuf = NULL;
1.36      ratchov  1001:
1.57      ratchov  1002:        if (APROC_OK(d->mix)) {
                   1003:                mbuf = LIST_FIRST(&d->mix->outs);
                   1004:                return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54      ratchov  1005:        } else
                   1006:                return 0;
1.1       ratchov  1007: }
                   1008:
                   1009: /*
1.27      ratchov  1010:  * Attach the given input and output buffers to the mixer and the
1.1       ratchov  1011:  * multiplexer respectively. The operation is done synchronously, so
                   1012:  * both buffers enter in sync. If buffers do not match play
1.27      ratchov  1013:  * and rec.
1.1       ratchov  1014:  */
                   1015: void
1.57      ratchov  1016: dev_attach(struct dev *d, char *name, unsigned mode,
1.48      ratchov  1017:     struct abuf *ibuf, struct aparams *sipar, unsigned inch,
                   1018:     struct abuf *obuf, struct aparams *sopar, unsigned onch,
1.46      ratchov  1019:     unsigned xrun, int vol)
1.1       ratchov  1020: {
                   1021:        struct abuf *pbuf = NULL, *rbuf = NULL;
1.12      ratchov  1022:        struct aparams ipar, opar;
1.1       ratchov  1023:        struct aproc *conv;
1.48      ratchov  1024:        unsigned round, nblk, nch;
1.20      ratchov  1025:
1.46      ratchov  1026: #ifdef DEBUG
1.57      ratchov  1027:        if ((!APROC_OK(d->mix)    && (mode & MODE_PLAY)) ||
                   1028:            (!APROC_OK(d->sub)    && (mode & MODE_REC)) ||
                   1029:            (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.46      ratchov  1030:                dbg_puts("mode beyond device mode, not attaching\n");
                   1031:                return;
                   1032:        }
                   1033: #endif
                   1034:        if (mode & MODE_PLAY) {
1.12      ratchov  1035:                ipar = *sipar;
1.57      ratchov  1036:                pbuf = LIST_FIRST(&d->mix->outs);
                   1037:                nblk = (d->bufsz / d->round + 3) / 4;
                   1038:                round = dev_roundof(d, ipar.rate);
1.48      ratchov  1039:                nch = ipar.cmax - ipar.cmin + 1;
1.57      ratchov  1040:                if (!aparams_eqenc(&ipar, &d->opar)) {
1.10      ratchov  1041:                        conv = dec_new(name, &ipar);
1.57      ratchov  1042:                        ipar.bps = d->opar.bps;
                   1043:                        ipar.bits = d->opar.bits;
                   1044:                        ipar.sig = d->opar.sig;
                   1045:                        ipar.le = d->opar.le;
                   1046:                        ipar.msb = d->opar.msb;
1.25      ratchov  1047:                        aproc_setin(conv, ibuf);
1.20      ratchov  1048:                        ibuf = abuf_new(nblk * round, &ipar);
1.9       ratchov  1049:                        aproc_setout(conv, ibuf);
1.8       ratchov  1050:                }
1.48      ratchov  1051:                if (inch > 0 && nch >= inch * 2) {
                   1052:                        conv = join_new(name);
                   1053:                        aproc_setin(conv, ibuf);
                   1054:                        ipar.cmax = ipar.cmin + inch - 1;
                   1055:                        ibuf = abuf_new(nblk * round, &ipar);
                   1056:                        aproc_setout(conv, ibuf);
                   1057:                }
1.57      ratchov  1058:                if (!aparams_eqrate(&ipar, &d->opar)) {
                   1059:                        conv = resamp_new(name, round, d->round);
                   1060:                        ipar.rate = d->opar.rate;
                   1061:                        round = d->round;
1.5       ratchov  1062:                        aproc_setin(conv, ibuf);
1.20      ratchov  1063:                        ibuf = abuf_new(nblk * round, &ipar);
1.5       ratchov  1064:                        aproc_setout(conv, ibuf);
1.1       ratchov  1065:                }
1.48      ratchov  1066:                if (inch > 0 && nch * 2 <= inch) {
                   1067:                        conv = join_new(name);
                   1068:                        aproc_setin(conv, ibuf);
                   1069:                        ipar.cmax = ipar.cmin + inch - 1;
                   1070:                        ibuf = abuf_new(nblk * round, &ipar);
                   1071:                        aproc_setout(conv, ibuf);
                   1072:                }
1.57      ratchov  1073:                aproc_setin(d->mix, ibuf);
1.46      ratchov  1074:                ibuf->r.mix.xrun = xrun;
1.31      ratchov  1075:                ibuf->r.mix.maxweight = vol;
1.57      ratchov  1076:                mix_setmaster(d->mix);
1.1       ratchov  1077:        }
1.46      ratchov  1078:        if (mode & MODE_REC) {
1.12      ratchov  1079:                opar = *sopar;
1.57      ratchov  1080:                rbuf = LIST_FIRST(&d->sub->ins);
                   1081:                round = dev_roundof(d, opar.rate);
                   1082:                nblk = (d->bufsz / d->round + 3) / 4;
1.48      ratchov  1083:                nch = opar.cmax - opar.cmin + 1;
1.57      ratchov  1084:                if (!aparams_eqenc(&opar, &d->ipar)) {
1.10      ratchov  1085:                        conv = enc_new(name, &opar);
1.57      ratchov  1086:                        opar.bps = d->ipar.bps;
                   1087:                        opar.bits = d->ipar.bits;
                   1088:                        opar.sig = d->ipar.sig;
                   1089:                        opar.le = d->ipar.le;
                   1090:                        opar.msb = d->ipar.msb;
1.9       ratchov  1091:                        aproc_setout(conv, obuf);
1.20      ratchov  1092:                        obuf = abuf_new(nblk * round, &opar);
1.9       ratchov  1093:                        aproc_setin(conv, obuf);
1.8       ratchov  1094:                }
1.48      ratchov  1095:                if (onch > 0 && nch >= onch * 2) {
                   1096:                        conv = join_new(name);
                   1097:                        aproc_setout(conv, obuf);
                   1098:                        opar.cmax = opar.cmin + onch - 1;
                   1099:                        obuf = abuf_new(nblk * round, &opar);
                   1100:                        aproc_setin(conv, obuf);
                   1101:                }
1.57      ratchov  1102:                if (!aparams_eqrate(&opar, &d->ipar)) {
                   1103:                        conv = resamp_new(name, d->round, round);
                   1104:                        opar.rate = d->ipar.rate;
                   1105:                        round = d->round;
1.1       ratchov  1106:                        aproc_setout(conv, obuf);
1.20      ratchov  1107:                        obuf = abuf_new(nblk * round, &opar);
1.1       ratchov  1108:                        aproc_setin(conv, obuf);
                   1109:                }
1.48      ratchov  1110:                if (onch > 0 && nch * 2 <= onch) {
                   1111:                        conv = join_new(name);
                   1112:                        aproc_setout(conv, obuf);
                   1113:                        opar.cmax = opar.cmin + onch - 1;
                   1114:                        obuf = abuf_new(nblk * round, &opar);
                   1115:                        aproc_setin(conv, obuf);
                   1116:                }
1.57      ratchov  1117:                aproc_setout(d->sub, obuf);
1.46      ratchov  1118:                obuf->w.sub.xrun = xrun;
                   1119:        }
                   1120:        if (mode & MODE_MON) {
                   1121:                opar = *sopar;
1.57      ratchov  1122:                rbuf = LIST_FIRST(&d->submon->ins);
                   1123:                round = dev_roundof(d, opar.rate);
                   1124:                nblk = (d->bufsz / d->round + 3) / 4;
1.48      ratchov  1125:                nch = opar.cmax - opar.cmin + 1;
1.57      ratchov  1126:                if (!aparams_eqenc(&opar, &d->opar)) {
1.46      ratchov  1127:                        conv = enc_new(name, &opar);
1.57      ratchov  1128:                        opar.bps = d->opar.bps;
                   1129:                        opar.bits = d->opar.bits;
                   1130:                        opar.sig = d->opar.sig;
                   1131:                        opar.le = d->opar.le;
                   1132:                        opar.msb = d->opar.msb;
1.46      ratchov  1133:                        aproc_setout(conv, obuf);
                   1134:                        obuf = abuf_new(nblk * round, &opar);
                   1135:                        aproc_setin(conv, obuf);
                   1136:                }
1.48      ratchov  1137:                if (onch > 0 && nch >= onch * 2) {
                   1138:                        conv = join_new(name);
                   1139:                        aproc_setout(conv, obuf);
                   1140:                        opar.cmax = opar.cmin + onch - 1;
                   1141:                        obuf = abuf_new(nblk * round, &opar);
                   1142:                        aproc_setin(conv, obuf);
                   1143:                }
1.57      ratchov  1144:                if (!aparams_eqrate(&opar, &d->opar)) {
                   1145:                        conv = resamp_new(name, d->round, round);
                   1146:                        opar.rate = d->opar.rate;
                   1147:                        round = d->round;
1.46      ratchov  1148:                        aproc_setout(conv, obuf);
1.48      ratchov  1149:                        obuf = abuf_new(nblk * round, &opar);
                   1150:                        aproc_setin(conv, obuf);
                   1151:                }
                   1152:                if (onch > 0 && nch * 2 <= onch) {
                   1153:                        conv = join_new(name);
                   1154:                        aproc_setout(conv, obuf);
                   1155:                        opar.cmax = opar.cmin + onch - 1;
1.46      ratchov  1156:                        obuf = abuf_new(nblk * round, &opar);
                   1157:                        aproc_setin(conv, obuf);
                   1158:                }
1.57      ratchov  1159:                aproc_setout(d->submon, obuf);
1.46      ratchov  1160:                obuf->w.sub.xrun = xrun;
1.1       ratchov  1161:        }
                   1162:
                   1163:        /*
1.27      ratchov  1164:         * Sync play to record.
1.1       ratchov  1165:         */
1.46      ratchov  1166:        if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3       ratchov  1167:                ibuf->duplex = obuf;
                   1168:                obuf->duplex = ibuf;
1.13      ratchov  1169:        }
1.57      ratchov  1170:        dev_sync(d, mode, ibuf, obuf);
1.14      ratchov  1171: }
                   1172:
                   1173: /*
1.27      ratchov  1174:  * Change the playback volume of the given stream.
1.14      ratchov  1175:  */
                   1176: void
1.57      ratchov  1177: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14      ratchov  1178: {
1.39      ratchov  1179: #ifdef DEBUG
                   1180:        if (debug_level >= 3) {
                   1181:                abuf_dbg(ibuf);
                   1182:                dbg_puts(": setting volume to ");
                   1183:                dbg_putu(vol);
                   1184:                dbg_puts("\n");
                   1185:        }
                   1186: #endif
1.57      ratchov  1187:        if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14      ratchov  1188:                return;
1.16      ratchov  1189:        }
1.31      ratchov  1190:        ibuf->r.mix.vol = vol;
1.13      ratchov  1191: }
                   1192:
                   1193: /*
1.27      ratchov  1194:  * Clear buffers of the play and record chains so that when the device
                   1195:  * is started, playback and record start in sync.
1.13      ratchov  1196:  */
                   1197: void
1.57      ratchov  1198: dev_clear(struct dev *d)
1.13      ratchov  1199: {
                   1200:        struct abuf *buf;
                   1201:
1.57      ratchov  1202:        if (APROC_OK(d->mix)) {
1.39      ratchov  1203: #ifdef DEBUG
1.57      ratchov  1204:                if (!LIST_EMPTY(&d->mix->ins)) {
1.39      ratchov  1205:                        dbg_puts("play end not idle, can't clear device\n");
                   1206:                        dbg_panic();
                   1207:                }
                   1208: #endif
1.57      ratchov  1209:                buf = LIST_FIRST(&d->mix->outs);
1.13      ratchov  1210:                while (buf) {
                   1211:                        abuf_clear(buf);
1.49      ratchov  1212:                        buf = LIST_FIRST(&buf->rproc->outs);
1.13      ratchov  1213:                }
1.57      ratchov  1214:                mix_clear(d->mix);
1.13      ratchov  1215:        }
1.57      ratchov  1216:        if (APROC_OK(d->sub)) {
1.39      ratchov  1217: #ifdef DEBUG
1.57      ratchov  1218:                if (!LIST_EMPTY(&d->sub->outs)) {
1.39      ratchov  1219:                        dbg_puts("record end not idle, can't clear device\n");
                   1220:                        dbg_panic();
                   1221:                }
                   1222: #endif
1.57      ratchov  1223:                buf = LIST_FIRST(&d->sub->ins);
1.13      ratchov  1224:                while (buf) {
                   1225:                        abuf_clear(buf);
1.49      ratchov  1226:                        buf = LIST_FIRST(&buf->wproc->ins);
1.13      ratchov  1227:                }
1.57      ratchov  1228:                sub_clear(d->sub);
1.40      ratchov  1229:        }
1.57      ratchov  1230:        if (APROC_OK(d->submon)) {
1.46      ratchov  1231: #ifdef DEBUG
1.57      ratchov  1232:                if (!LIST_EMPTY(&d->submon->outs)) {
1.46      ratchov  1233:                        dbg_puts("monitoring end not idle, can't clear device\n");
                   1234:                        dbg_panic();
                   1235:                }
                   1236: #endif
1.57      ratchov  1237:                buf = LIST_FIRST(&d->submon->ins);
1.46      ratchov  1238:                while (buf) {
                   1239:                        abuf_clear(buf);
1.49      ratchov  1240:                        buf = LIST_FIRST(&buf->wproc->ins);
1.46      ratchov  1241:                }
1.57      ratchov  1242:                sub_clear(d->submon);
                   1243:                mon_clear(d->mon);
1.1       ratchov  1244:        }
                   1245: }