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

1.44      ratchov     1: /*     $OpenBSD: dev.c,v 1.43 2010/01/16 23:18: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.27      ratchov    17:
1.1       ratchov    18: #include <stdio.h>
                     19: #include <stdlib.h>
                     20: #include <unistd.h>
                     21:
                     22: #include "abuf.h"
                     23: #include "aproc.h"
1.27      ratchov    24: #include "conf.h"
                     25: #include "dev.h"
1.3       ratchov    26: #include "pipe.h"
1.38      ratchov    27: #include "miofile.h"
1.42      ratchov    28: #include "siofile.h"
1.28      ratchov    29: #include "midi.h"
1.39      ratchov    30: #ifdef DEBUG
                     31: #include "dbg.h"
                     32: #endif
1.1       ratchov    33:
1.3       ratchov    34: unsigned dev_bufsz, dev_round, dev_rate;
1.1       ratchov    35: struct aparams dev_ipar, dev_opar;
1.45    ! ratchov    36: struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play;
1.28      ratchov    37: struct aproc *dev_midi;
                     38:
                     39: /*
                     40:  * Create a MIDI thru box as the MIDI end of the device
                     41:  */
                     42: void
                     43: dev_thruinit(void)
                     44: {
                     45:        dev_midi = thru_new("thru");
                     46:        dev_midi->refs++;
                     47: }
                     48:
                     49: /*
1.38      ratchov    50:  * Open a MIDI device and connect it to the thru box
                     51:  */
                     52: int
                     53: dev_thruadd(char *name, int in, int out)
                     54: {
                     55:        struct file *f;
                     56:        struct abuf *rbuf = NULL, *wbuf = NULL;
                     57:        struct aproc *rproc, *wproc;
                     58:
                     59:        f = (struct file *)miofile_new(&miofile_ops, name, in, out);
                     60:        if (f == NULL)
                     61:                return 0;
                     62:        if (in) {
                     63:                rproc = rfile_new(f);
                     64:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                     65:                aproc_setout(rproc, rbuf);
                     66:        }
                     67:        if (out) {
                     68:                wproc = wfile_new(f);
                     69:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                     70:                aproc_setin(wproc, wbuf);
                     71:        }
                     72:        dev_midiattach(rbuf, wbuf);
                     73:        return 1;
                     74: }
                     75:
                     76: /*
1.28      ratchov    77:  * Attach a bi-directional MIDI stream to the MIDI device
                     78:  */
                     79: void
                     80: dev_midiattach(struct abuf *ibuf, struct abuf *obuf)
                     81: {
                     82:        if (ibuf)
                     83:                aproc_setin(dev_midi, ibuf);
                     84:        if (obuf) {
                     85:                aproc_setout(dev_midi, obuf);
                     86:                if (ibuf) {
                     87:                        ibuf->duplex = obuf;
                     88:                        obuf->duplex = ibuf;
                     89:                }
                     90:        }
                     91: }
1.24      ratchov    92:
                     93: /*
1.27      ratchov    94:  * Same as dev_init(), but create a fake device that records what is
                     95:  * played.
1.24      ratchov    96:  */
                     97: void
                     98: dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
                     99: {
                    100:        struct abuf *buf;
                    101:        struct aparams par;
                    102:        unsigned cmin, cmax, rate;
                    103:
                    104:        cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
                    105:        cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
                    106:        rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
                    107:        aparams_init(&par, cmin, cmax, rate);
                    108:        dev_ipar = par;
                    109:        dev_opar = par;
                    110:        dev_round = (bufsz + 1) / 2;
                    111:        dev_bufsz = dev_round * 2;
1.25      ratchov   112:        dev_rate  = rate;
1.24      ratchov   113:        dev_rec = NULL;
                    114:        dev_play = NULL;
1.25      ratchov   115:
1.24      ratchov   116:        buf = abuf_new(dev_bufsz, &par);
1.45    ! ratchov   117:        dev_mix = mix_new("mix", dev_bufsz, NULL);
1.24      ratchov   118:        dev_mix->refs++;
1.45    ! ratchov   119:        dev_sub = sub_new("sub", dev_bufsz, NULL);
1.24      ratchov   120:        dev_sub->refs++;
                    121:        aproc_setout(dev_mix, buf);
                    122:        aproc_setin(dev_sub, buf);
                    123:
1.36      ratchov   124:        dev_mix->flags |= APROC_QUIT;
                    125:        dev_sub->flags |= APROC_QUIT;
1.24      ratchov   126:
                    127:        *dipar = dev_ipar;
                    128:        *dopar = dev_opar;
                    129: }
1.1       ratchov   130:
1.20      ratchov   131: unsigned
                    132: dev_roundof(unsigned newrate)
1.1       ratchov   133: {
1.20      ratchov   134:        return (dev_round * newrate + dev_rate / 2) / dev_rate;
1.1       ratchov   135: }
                    136:
                    137: /*
1.27      ratchov   138:  * Open the device with the given hardware parameters and create a mixer
1.1       ratchov   139:  * and a multiplexer connected to it with all necessary conversions
1.27      ratchov   140:  * setup.
1.1       ratchov   141:  */
1.26      ratchov   142: int
1.45    ! ratchov   143: dev_init(char *devpath,
1.36      ratchov   144:     struct aparams *dipar, struct aparams *dopar, unsigned bufsz, unsigned round)
1.1       ratchov   145: {
1.23      ratchov   146:        struct file *f;
1.1       ratchov   147:        struct aparams ipar, opar;
                    148:        struct aproc *conv;
                    149:        struct abuf *buf;
1.45    ! ratchov   150:        unsigned nfr, ibufsz, obufsz;
1.25      ratchov   151:
1.36      ratchov   152:        dev_midi = ctl_new("ctl");
                    153:        dev_midi->refs++;
                    154:
1.3       ratchov   155:        /*
1.27      ratchov   156:         * Ask for 1/4 of the buffer for the kernel ring and
                    157:         * limit the block size to 1/4 of the requested buffer.
1.3       ratchov   158:         */
1.36      ratchov   159:        dev_round = round;
1.45    ! ratchov   160:        dev_bufsz = (bufsz + 3) / 4 + (dev_round - 1);
        !           161:        dev_bufsz -= dev_bufsz % dev_round;
1.42      ratchov   162:        f = (struct file *)siofile_new(&siofile_ops, devpath,
1.45    ! ratchov   163:            dipar, dopar, &dev_bufsz, &dev_round);
1.23      ratchov   164:        if (f == NULL)
1.26      ratchov   165:                return 0;
1.45    ! ratchov   166:        if (dipar) {
1.39      ratchov   167: #ifdef DEBUG
                    168:                if (debug_level >= 2) {
                    169:                        dbg_puts("hw recording ");
                    170:                        aparams_dbg(dipar);
                    171:                        dbg_puts("\n");
                    172:                }
                    173: #endif
1.20      ratchov   174:                dev_rate = dipar->rate;
1.3       ratchov   175:        }
1.45    ! ratchov   176:        if (dopar) {
1.39      ratchov   177: #ifdef DEBUG
                    178:                if (debug_level >= 2) {
                    179:                        dbg_puts("hw playing ");
                    180:                        aparams_dbg(dopar);
                    181:                        dbg_puts("\n");
                    182:                }
                    183: #endif
1.20      ratchov   184:                dev_rate = dopar->rate;
1.3       ratchov   185:        }
1.45    ! ratchov   186:        ibufsz = obufsz = dev_bufsz;
        !           187:        bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0;
        !           188:
        !           189:        /*
        !           190:         * Use 1/8 of the buffer for the mixer/converters.  Since we
        !           191:         * already consumed 1/4 for the device, bufsz represents the
        !           192:         * remaining 3/4. So 1/8 is 1/6 of 3/4.
        !           193:         */
        !           194:        nfr = (bufsz + 5) / 6;
        !           195:        nfr += dev_round - 1;
        !           196:        nfr -= nfr % dev_round;
        !           197:        if (nfr == 0)
        !           198:                nfr = dev_round;
1.11      ratchov   199:
                    200:        /*
1.27      ratchov   201:         * Create record chain.
1.1       ratchov   202:         */
1.45    ! ratchov   203:        if (dipar) {
1.1       ratchov   204:                aparams_init(&ipar, dipar->cmin, dipar->cmax, dipar->rate);
                    205:                /*
1.27      ratchov   206:                 * Create the read end.
1.1       ratchov   207:                 */
1.45    ! ratchov   208:                dev_rec = rfile_new(f);
1.22      ratchov   209:                dev_rec->refs++;
1.45    ! ratchov   210:                buf = abuf_new(nfr, dipar);
1.1       ratchov   211:                aproc_setout(dev_rec, buf);
1.45    ! ratchov   212:                ibufsz += nfr;
1.1       ratchov   213:
                    214:                /*
1.27      ratchov   215:                 * Append a converter, if needed.
1.1       ratchov   216:                 */
1.4       ratchov   217:                if (!aparams_eqenc(dipar, &ipar)) {
1.30      ratchov   218:                        conv = dec_new("rec", dipar);
1.1       ratchov   219:                        aproc_setin(conv, buf);
1.45    ! ratchov   220:                        buf = abuf_new(nfr, &ipar);
1.1       ratchov   221:                        aproc_setout(conv, buf);
1.45    ! ratchov   222:                        ibufsz += nfr;
1.1       ratchov   223:                }
                    224:                dev_ipar = ipar;
                    225:
                    226:                /*
1.27      ratchov   227:                 * Append a "sub" to which clients will connect.
1.36      ratchov   228:                 * Link it to the controller only in record-only mode
1.1       ratchov   229:                 */
1.45    ! ratchov   230:                dev_sub = sub_new("rec", ibufsz, dopar ? NULL : dev_midi);
1.22      ratchov   231:                dev_sub->refs++;
1.1       ratchov   232:                aproc_setin(dev_sub, buf);
                    233:        } else {
                    234:                dev_rec = NULL;
                    235:                dev_sub = NULL;
                    236:        }
                    237:
                    238:        /*
1.27      ratchov   239:         * Create play chain.
1.1       ratchov   240:         */
1.45    ! ratchov   241:        if (dopar) {
1.1       ratchov   242:                aparams_init(&opar, dopar->cmin, dopar->cmax, dopar->rate);
                    243:                /*
1.27      ratchov   244:                 * Create the write end.
1.1       ratchov   245:                 */
1.45    ! ratchov   246:                dev_play = wfile_new(f);
1.22      ratchov   247:                dev_play->refs++;
1.45    ! ratchov   248:                buf = abuf_new(nfr, dopar);
1.1       ratchov   249:                aproc_setin(dev_play, buf);
1.45    ! ratchov   250:                obufsz += nfr;
1.25      ratchov   251:
1.1       ratchov   252:                /*
1.27      ratchov   253:                 * Append a converter, if needed.
1.1       ratchov   254:                 */
1.4       ratchov   255:                if (!aparams_eqenc(&opar, dopar)) {
1.30      ratchov   256:                        conv = enc_new("play", dopar);
1.1       ratchov   257:                        aproc_setout(conv, buf);
1.45    ! ratchov   258:                        buf = abuf_new(nfr, &opar);
1.1       ratchov   259:                        aproc_setin(conv, buf);
1.45    ! ratchov   260:                        obufsz += nfr;
1.1       ratchov   261:                }
                    262:                dev_opar = opar;
                    263:
                    264:                /*
1.27      ratchov   265:                 * Append a "mix" to which clients will connect.
1.1       ratchov   266:                 */
1.45    ! ratchov   267:                dev_mix = mix_new("play", obufsz, dev_midi);
1.22      ratchov   268:                dev_mix->refs++;
1.1       ratchov   269:                aproc_setout(dev_mix, buf);
                    270:        } else {
                    271:                dev_play = NULL;
                    272:                dev_mix = NULL;
                    273:        }
1.45    ! ratchov   274:        dev_bufsz = (dopar) ? obufsz : ibufsz;
1.39      ratchov   275: #ifdef DEBUG
                    276:        if (debug_level >= 2) {
                    277:                dbg_puts("device block size is ");
                    278:                dbg_putu(dev_round);
                    279:                dbg_puts(" frames, using ");
                    280:                dbg_putu(dev_bufsz / dev_round);
                    281:                dbg_puts(" blocks\n");
                    282:        }
                    283: #endif
1.45    ! ratchov   284:        dev_start();
1.26      ratchov   285:        return 1;
1.1       ratchov   286: }
                    287:
                    288: /*
1.27      ratchov   289:  * Cleanly stop and drain everything and close the device
                    290:  * once both play chain and record chain are gone.
1.1       ratchov   291:  */
                    292: void
                    293: dev_done(void)
                    294: {
                    295:        struct file *f;
                    296:
1.39      ratchov   297: #ifdef DEBUG
                    298:        if (debug_level >= 2)
                    299:                dbg_puts("closing audio device\n");
                    300: #endif
1.3       ratchov   301:        if (dev_mix) {
                    302:                /*
1.32      ratchov   303:                 * Put the mixer in ``autoquit'' state and generate
                    304:                 * EOF on all inputs connected it. Once buffers are
                    305:                 * drained the mixer will terminate and shutdown the
                    306:                 * device.
1.3       ratchov   307:                 *
                    308:                 * NOTE: since file_eof() can destroy the file and
                    309:                 * reorder the file_list, we have to restart the loop
1.27      ratchov   310:                 * after each call to file_eof().
1.3       ratchov   311:                 */
1.36      ratchov   312:                dev_mix->flags |= APROC_QUIT;
1.32      ratchov   313:        restart_mix:
1.3       ratchov   314:                LIST_FOREACH(f, &file_list, entry) {
1.32      ratchov   315:                        if (f->rproc != NULL &&
                    316:                            aproc_depend(dev_mix, f->rproc)) {
1.3       ratchov   317:                                file_eof(f);
1.32      ratchov   318:                                goto restart_mix;
1.3       ratchov   319:                        }
                    320:                }
1.45    ! ratchov   321:        } else if (dev_sub) {
1.3       ratchov   322:                /*
1.32      ratchov   323:                 * Same as above, but since there's no mixer,
                    324:                 * we generate EOF on the record-end of the
                    325:                 * device.
                    326:                 */
                    327:        restart_sub:
                    328:                LIST_FOREACH(f, &file_list, entry) {
                    329:                        if (f->rproc != NULL &&
1.45    ! ratchov   330:                            aproc_depend(dev_sub, f->rproc)) {
1.32      ratchov   331:                                file_eof(f);
                    332:                                goto restart_sub;
1.23      ratchov   333:                        }
1.32      ratchov   334:                }
                    335:        }
1.36      ratchov   336:        if (dev_midi) {
                    337:                dev_midi->flags |= APROC_QUIT;
1.43      ratchov   338:                if (LIST_EMPTY(&dev_midi->ibuflist))
                    339:                        aproc_del(dev_midi);
1.36      ratchov   340:        restart_midi:
                    341:                LIST_FOREACH(f, &file_list, entry) {
                    342:                        if (f->rproc &&
                    343:                            aproc_depend(dev_midi, f->rproc)) {
                    344:                                file_eof(f);
                    345:                                goto restart_midi;
                    346:                        }
                    347:                }
                    348:        }
1.32      ratchov   349:        if (dev_mix) {
1.45    ! ratchov   350:                dev_mix->refs--;
        !           351:                if (dev_mix->flags & APROC_ZOMB)
1.32      ratchov   352:                        aproc_del(dev_mix);
                    353:                dev_mix = NULL;
                    354:        }
                    355:        if (dev_play) {
1.45    ! ratchov   356:                dev_play->refs--;
        !           357:                if (dev_play->flags & APROC_ZOMB)
1.23      ratchov   358:                        aproc_del(dev_play);
1.32      ratchov   359:                dev_play = NULL;
1.1       ratchov   360:        }
1.3       ratchov   361:        if (dev_sub) {
1.45    ! ratchov   362:                dev_sub->refs--;
        !           363:                if (dev_sub->flags & APROC_ZOMB)
1.32      ratchov   364:                        aproc_del(dev_sub);
1.22      ratchov   365:                dev_sub = NULL;
1.32      ratchov   366:        }
                    367:        if (dev_rec) {
1.45    ! ratchov   368:                dev_rec->refs--;
        !           369:                if (dev_rec->flags & APROC_ZOMB)
1.23      ratchov   370:                        aproc_del(dev_rec);
1.32      ratchov   371:                dev_rec = NULL;
1.34      ratchov   372:        }
                    373:        if (dev_midi) {
1.45    ! ratchov   374:                dev_midi->refs--;
        !           375:                if (dev_midi->flags & APROC_ZOMB)
1.34      ratchov   376:                        aproc_del(dev_midi);
                    377:                dev_midi = NULL;
1.32      ratchov   378:        }
                    379:        for (;;) {
                    380:                if (!file_poll())
                    381:                        break;
1.1       ratchov   382:        }
                    383: }
                    384:
                    385: /*
1.27      ratchov   386:  * Start the (paused) device. By default it's paused.
1.1       ratchov   387:  */
                    388: void
                    389: dev_start(void)
                    390: {
1.22      ratchov   391:        struct file *f;
                    392:
1.45    ! ratchov   393:        if (dev_mix)
1.36      ratchov   394:                dev_mix->flags |= APROC_DROP;
1.45    ! ratchov   395:        if (dev_sub)
1.36      ratchov   396:                dev_sub->flags |= APROC_DROP;
1.45    ! ratchov   397:        if (dev_play && dev_play->u.io.file) {
1.22      ratchov   398:                f = dev_play->u.io.file;
                    399:                f->ops->start(f);
1.45    ! ratchov   400:        } else if (dev_rec && dev_rec->u.io.file) {
1.22      ratchov   401:                f = dev_rec->u.io.file;
                    402:                f->ops->start(f);
                    403:        }
1.1       ratchov   404: }
                    405:
                    406: /*
1.45    ! ratchov   407:  * Pause the device.
1.1       ratchov   408:  */
                    409: void
                    410: dev_stop(void)
                    411: {
1.22      ratchov   412:        struct file *f;
                    413:
1.45    ! ratchov   414:        if (dev_play && dev_play->u.io.file) {
1.22      ratchov   415:                f = dev_play->u.io.file;
                    416:                f->ops->stop(f);
1.45    ! ratchov   417:        } else if (dev_rec && dev_rec->u.io.file) {
1.22      ratchov   418:                f = dev_rec->u.io.file;
                    419:                f->ops->stop(f);
                    420:        }
1.45    ! ratchov   421:        if (dev_mix)
1.36      ratchov   422:                dev_mix->flags &= ~APROC_DROP;
1.45    ! ratchov   423:        if (dev_sub)
1.36      ratchov   424:                dev_sub->flags &= ~APROC_DROP;
1.1       ratchov   425: }
                    426:
                    427: /*
1.27      ratchov   428:  * Find the end points connected to the mix/sub.
1.14      ratchov   429:  */
                    430: int
1.45    ! ratchov   431: dev_getep(struct abuf **sibuf, struct abuf **sobuf)
1.14      ratchov   432: {
                    433:        struct abuf *ibuf, *obuf;
                    434:
1.45    ! ratchov   435:        if (sibuf && *sibuf) {
1.14      ratchov   436:                ibuf = *sibuf;
                    437:                for (;;) {
                    438:                        if (!ibuf || !ibuf->rproc) {
1.39      ratchov   439: #ifdef DEBUG
                    440:                                if (debug_level >= 3) {
                    441:                                        abuf_dbg(*sibuf);
                    442:                                        dbg_puts(": not connected to device\n");
                    443:                                }
                    444: #endif
1.14      ratchov   445:                                return 0;
                    446:                        }
                    447:                        if (ibuf->rproc == dev_mix)
                    448:                                break;
                    449:                        ibuf = LIST_FIRST(&ibuf->rproc->obuflist);
                    450:                }
1.21      ratchov   451:                *sibuf = ibuf;
1.14      ratchov   452:        }
1.45    ! ratchov   453:        if (sobuf && *sobuf) {
1.14      ratchov   454:                obuf = *sobuf;
                    455:                for (;;) {
                    456:                        if (!obuf || !obuf->wproc) {
1.39      ratchov   457: #ifdef DEBUG
                    458:                                if (debug_level >= 3) {
                    459:                                        abuf_dbg(*sobuf);
                    460:                                        dbg_puts(": not connected to device\n");
                    461:                                }
                    462: #endif
1.14      ratchov   463:                                return 0;
                    464:                        }
                    465:                        if (obuf->wproc == dev_sub)
                    466:                                break;
                    467:                        obuf = LIST_FIRST(&obuf->wproc->ibuflist);
                    468:                }
1.21      ratchov   469:                *sobuf = obuf;
1.14      ratchov   470:        }
                    471:        return 1;
                    472: }
                    473:
                    474: /*
1.27      ratchov   475:  * Sync play buffer to rec buffer (for instance when one of
                    476:  * them underruns/overruns).
1.1       ratchov   477:  */
                    478: void
1.45    ! ratchov   479: dev_sync(struct abuf *ibuf, struct abuf *obuf)
1.1       ratchov   480: {
1.45    ! ratchov   481:        struct abuf *pbuf, *rbuf;
1.3       ratchov   482:        int delta;
                    483:
1.45    ! ratchov   484:        if (!dev_mix || !dev_sub)
1.3       ratchov   485:                return;
1.45    ! ratchov   486:        pbuf = LIST_FIRST(&dev_mix->obuflist);
        !           487:        if (!pbuf)
        !           488:                return;
        !           489:        rbuf = LIST_FIRST(&dev_sub->ibuflist);
        !           490:        if (!rbuf)
        !           491:                return;
        !           492:        if (!dev_getep(&ibuf, &obuf))
        !           493:                return;
        !           494:
1.3       ratchov   495:        /*
1.27      ratchov   496:         * Calculate delta, the number of frames the play chain is ahead
1.3       ratchov   497:         * of the record chain. It's necessary to schedule silences (or
                    498:         * drops) in order to start playback and record in sync.
                    499:         */
1.45    ! ratchov   500:        delta =
        !           501:            rbuf->bpf * (pbuf->abspos + pbuf->used) -
        !           502:            pbuf->bpf *  rbuf->abspos;
        !           503:        delta /= pbuf->bpf * rbuf->bpf;
1.39      ratchov   504: #ifdef DEBUG
                    505:        if (debug_level >= 3) {
                    506:                dbg_puts("syncing device, delta = ");
                    507:                dbg_putu(delta);
1.45    ! ratchov   508:                dbg_puts(": ");
        !           509:                abuf_dbg(pbuf);
        !           510:                dbg_puts(" abspos = ");
        !           511:                dbg_putu(pbuf->abspos);
        !           512:                dbg_puts(" used = ");
        !           513:                dbg_putu(pbuf->used);
        !           514:                dbg_puts(" <---> ");
        !           515:                abuf_dbg(rbuf);
        !           516:                dbg_puts(" abspos = ");
        !           517:                dbg_putu(rbuf->abspos);
1.39      ratchov   518:                dbg_puts("\n");
                    519:        }
                    520: #endif
1.3       ratchov   521:        if (delta > 0) {
                    522:                /*
1.37      ratchov   523:                 * The play chain is ahead (most cases) drop some of
1.27      ratchov   524:                 * the recorded input, to get both in sync.
1.3       ratchov   525:                 */
1.45    ! ratchov   526:                if (obuf) {
        !           527:                        obuf->drop += delta * obuf->bpf;
        !           528:                        abuf_ipos(obuf, -delta);
        !           529:                }
1.3       ratchov   530:        } else if (delta < 0) {
                    531:                /*
1.37      ratchov   532:                 * The record chain is ahead (should never happen,
1.27      ratchov   533:                 * right?) then insert silence to play.
1.3       ratchov   534:                 */
1.45    ! ratchov   535:                 if (ibuf) {
        !           536:                        ibuf->silence += -delta * ibuf->bpf;
        !           537:                        abuf_opos(ibuf, delta);
        !           538:                }
1.30      ratchov   539:        }
1.36      ratchov   540: }
                    541:
                    542: /*
                    543:  * return the current latency (in frames), ie the latency that
                    544:  * a stream would have if dev_attach() is called on it.
                    545:  */
                    546: int
                    547: dev_getpos(void)
                    548: {
                    549:        struct abuf *pbuf = NULL, *rbuf = NULL;
                    550:        int plat = 0, rlat = 0;
                    551:        int delta;
                    552:
1.45    ! ratchov   553:        if (dev_mix) {
1.36      ratchov   554:                pbuf = LIST_FIRST(&dev_mix->obuflist);
                    555:                if (!pbuf)
                    556:                        return 0;
                    557:                plat = -dev_mix->u.mix.lat;
                    558:        }
1.45    ! ratchov   559:        if (dev_sub) {
1.36      ratchov   560:                rbuf = LIST_FIRST(&dev_sub->ibuflist);
                    561:                if (!rbuf)
                    562:                        return 0;
                    563:                rlat = -dev_sub->u.sub.lat;
                    564:        }
1.45    ! ratchov   565:        if (dev_mix && dev_sub) {
        !           566:                delta =
        !           567:                    rbuf->bpf * (pbuf->abspos + pbuf->used) -
        !           568:                    pbuf->bpf *  rbuf->abspos;
        !           569:                delta /= pbuf->bpf * rbuf->bpf;
1.36      ratchov   570:                if (delta > 0)
                    571:                        rlat -= delta;
                    572:                else if (delta < 0)
                    573:                        plat += delta;
1.39      ratchov   574: #ifdef DEBUG
                    575:                if (rlat != plat) {
                    576:                        dbg_puts("dev_getpos: play/rec out of sync: plat = ");
                    577:                        dbg_puti(plat);
                    578:                        dbg_puts(", rlat = ");
                    579:                        dbg_puti(rlat);
                    580:                        dbg_puts("\n");
                    581:                }
                    582: #endif
1.36      ratchov   583:        }
1.45    ! ratchov   584:        return dev_mix ? plat : rlat;
1.1       ratchov   585: }
                    586:
                    587: /*
1.27      ratchov   588:  * Attach the given input and output buffers to the mixer and the
1.1       ratchov   589:  * multiplexer respectively. The operation is done synchronously, so
                    590:  * both buffers enter in sync. If buffers do not match play
1.27      ratchov   591:  * and rec.
1.1       ratchov   592:  */
                    593: void
1.45    ! ratchov   594: dev_attach(char *name,
        !           595:     struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
        !           596:     struct abuf *obuf, struct aparams *sopar, unsigned overrun, int vol)
1.1       ratchov   597: {
                    598:        struct abuf *pbuf = NULL, *rbuf = NULL;
1.12      ratchov   599:        struct aparams ipar, opar;
1.1       ratchov   600:        struct aproc *conv;
1.20      ratchov   601:        unsigned round, nblk;
                    602:
1.45    ! ratchov   603:        if (ibuf) {
1.12      ratchov   604:                ipar = *sipar;
1.20      ratchov   605:                pbuf = LIST_FIRST(&dev_mix->obuflist);
                    606:                nblk = (dev_bufsz / dev_round + 3) / 4;
                    607:                round = dev_roundof(ipar.rate);
1.10      ratchov   608:                if (!aparams_eqenc(&ipar, &dev_opar)) {
                    609:                        conv = dec_new(name, &ipar);
                    610:                        ipar.bps = dev_opar.bps;
                    611:                        ipar.bits = dev_opar.bits;
                    612:                        ipar.sig = dev_opar.sig;
                    613:                        ipar.le = dev_opar.le;
                    614:                        ipar.msb = dev_opar.msb;
1.25      ratchov   615:                        aproc_setin(conv, ibuf);
1.20      ratchov   616:                        ibuf = abuf_new(nblk * round, &ipar);
1.9       ratchov   617:                        aproc_setout(conv, ibuf);
1.8       ratchov   618:                }
1.10      ratchov   619:                if (!aparams_subset(&ipar, &dev_opar)) {
                    620:                        conv = cmap_new(name, &ipar, &dev_opar);
                    621:                        ipar.cmin = dev_opar.cmin;
                    622:                        ipar.cmax = dev_opar.cmax;
1.7       ratchov   623:                        aproc_setin(conv, ibuf);
1.20      ratchov   624:                        ibuf = abuf_new(nblk * round, &ipar);
1.7       ratchov   625:                        aproc_setout(conv, ibuf);
1.6       ratchov   626:                }
1.10      ratchov   627:                if (!aparams_eqrate(&ipar, &dev_opar)) {
1.20      ratchov   628:                        conv = resamp_new(name, round, dev_round);
1.10      ratchov   629:                        ipar.rate = dev_opar.rate;
1.20      ratchov   630:                        round = dev_round;
1.5       ratchov   631:                        aproc_setin(conv, ibuf);
1.20      ratchov   632:                        ibuf = abuf_new(nblk * round, &ipar);
1.5       ratchov   633:                        aproc_setout(conv, ibuf);
1.1       ratchov   634:                }
                    635:                aproc_setin(dev_mix, ibuf);
1.45    ! ratchov   636:                if (dev_mix->u.mix.lat > 0)
        !           637:                        abuf_opos(ibuf, -dev_mix->u.mix.lat);
        !           638:                ibuf->r.mix.xrun = underrun;
1.31      ratchov   639:                ibuf->r.mix.maxweight = vol;
1.18      ratchov   640:                mix_setmaster(dev_mix);
1.1       ratchov   641:        }
1.45    ! ratchov   642:        if (obuf) {
1.12      ratchov   643:                opar = *sopar;
1.1       ratchov   644:                rbuf = LIST_FIRST(&dev_sub->ibuflist);
1.20      ratchov   645:                round = dev_roundof(opar.rate);
                    646:                nblk = (dev_bufsz / dev_round + 3) / 4;
1.10      ratchov   647:                if (!aparams_eqenc(&opar, &dev_ipar)) {
                    648:                        conv = enc_new(name, &opar);
                    649:                        opar.bps = dev_ipar.bps;
                    650:                        opar.bits = dev_ipar.bits;
                    651:                        opar.sig = dev_ipar.sig;
                    652:                        opar.le = dev_ipar.le;
                    653:                        opar.msb = dev_ipar.msb;
1.9       ratchov   654:                        aproc_setout(conv, obuf);
1.20      ratchov   655:                        obuf = abuf_new(nblk * round, &opar);
1.9       ratchov   656:                        aproc_setin(conv, obuf);
1.8       ratchov   657:                }
1.10      ratchov   658:                if (!aparams_subset(&opar, &dev_ipar)) {
                    659:                        conv = cmap_new(name, &dev_ipar, &opar);
                    660:                        opar.cmin = dev_ipar.cmin;
                    661:                        opar.cmax = dev_ipar.cmax;
1.7       ratchov   662:                        aproc_setout(conv, obuf);
1.20      ratchov   663:                        obuf = abuf_new(nblk * round, &opar);
1.7       ratchov   664:                        aproc_setin(conv, obuf);
1.6       ratchov   665:                }
1.10      ratchov   666:                if (!aparams_eqrate(&opar, &dev_ipar)) {
1.20      ratchov   667:                        conv = resamp_new(name, dev_round, round);
1.10      ratchov   668:                        opar.rate = dev_ipar.rate;
1.20      ratchov   669:                        round = dev_round;
1.1       ratchov   670:                        aproc_setout(conv, obuf);
1.20      ratchov   671:                        obuf = abuf_new(nblk * round, &opar);
1.1       ratchov   672:                        aproc_setin(conv, obuf);
                    673:                }
                    674:                aproc_setout(dev_sub, obuf);
1.45    ! ratchov   675:                if (dev_sub->u.sub.lat > 0)
        !           676:                        abuf_ipos(obuf, -dev_sub->u.sub.lat);
        !           677:                obuf->w.sub.xrun = overrun;
1.1       ratchov   678:        }
                    679:
                    680:        /*
1.27      ratchov   681:         * Sync play to record.
1.1       ratchov   682:         */
1.45    ! ratchov   683:        if (ibuf && obuf) {
1.3       ratchov   684:                ibuf->duplex = obuf;
                    685:                obuf->duplex = ibuf;
1.13      ratchov   686:        }
1.45    ! ratchov   687:        dev_sync(ibuf, obuf);
1.14      ratchov   688: }
                    689:
                    690: /*
1.27      ratchov   691:  * Change the playback volume of the given stream.
1.14      ratchov   692:  */
                    693: void
                    694: dev_setvol(struct abuf *ibuf, int vol)
                    695: {
1.39      ratchov   696: #ifdef DEBUG
                    697:        if (debug_level >= 3) {
                    698:                abuf_dbg(ibuf);
                    699:                dbg_puts(": setting volume to ");
                    700:                dbg_putu(vol);
                    701:                dbg_puts("\n");
                    702:        }
                    703: #endif
1.45    ! ratchov   704:        if (!dev_getep(&ibuf, NULL)) {
1.14      ratchov   705:                return;
1.16      ratchov   706:        }
1.31      ratchov   707:        ibuf->r.mix.vol = vol;
1.13      ratchov   708: }
                    709:
                    710: /*
1.27      ratchov   711:  * Clear buffers of the play and record chains so that when the device
                    712:  * is started, playback and record start in sync.
1.13      ratchov   713:  */
                    714: void
                    715: dev_clear(void)
                    716: {
                    717:        struct abuf *buf;
                    718:
1.45    ! ratchov   719:        if (dev_mix) {
1.39      ratchov   720: #ifdef DEBUG
                    721:                if (!LIST_EMPTY(&dev_mix->ibuflist)) {
                    722:                        dbg_puts("play end not idle, can't clear device\n");
                    723:                        dbg_panic();
                    724:                }
                    725: #endif
1.13      ratchov   726:                buf = LIST_FIRST(&dev_mix->obuflist);
                    727:                while (buf) {
                    728:                        abuf_clear(buf);
                    729:                        buf = LIST_FIRST(&buf->rproc->obuflist);
                    730:                }
                    731:                mix_clear(dev_mix);
                    732:        }
1.45    ! ratchov   733:        if (dev_sub) {
1.39      ratchov   734: #ifdef DEBUG
                    735:                if (!LIST_EMPTY(&dev_sub->obuflist)) {
                    736:                        dbg_puts("record end not idle, can't clear device\n");
                    737:                        dbg_panic();
                    738:                }
                    739: #endif
1.13      ratchov   740:                buf = LIST_FIRST(&dev_sub->ibuflist);
                    741:                while (buf) {
                    742:                        abuf_clear(buf);
                    743:                        buf = LIST_FIRST(&buf->wproc->ibuflist);
                    744:                }
                    745:                sub_clear(dev_sub);
1.40      ratchov   746:        }
                    747: }
                    748:
                    749: /*
                    750:  * Fill with silence play buffers and schedule the same amount of recorded
                    751:  * samples to drop
                    752:  */
                    753: void
                    754: dev_prime(void)
                    755: {
1.45    ! ratchov   756:        if (dev_mix) {
1.40      ratchov   757: #ifdef DEBUG
                    758:                if (!LIST_EMPTY(&dev_mix->ibuflist)) {
                    759:                        dbg_puts("play end not idle, can't prime device\n");
                    760:                        dbg_panic();
                    761:                }
                    762: #endif
                    763:                mix_prime(dev_mix);
1.1       ratchov   764:        }
                    765: }