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

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