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

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