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

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