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

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