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

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