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

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