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

1.85    ! ratchov     1: /*     $OpenBSD: dev.c,v 1.84 2013/11/18 17:37: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:  */
1.1       ratchov    65: #include <stdio.h>
                     66: #include <stdlib.h>
1.71      ratchov    67: #include <string.h>
1.1       ratchov    68: #include <unistd.h>
                     69:
                     70: #include "abuf.h"
                     71: #include "aproc.h"
1.27      ratchov    72: #include "conf.h"
                     73: #include "dev.h"
1.3       ratchov    74: #include "pipe.h"
1.38      ratchov    75: #include "miofile.h"
1.42      ratchov    76: #include "siofile.h"
1.28      ratchov    77: #include "midi.h"
1.39      ratchov    78: #ifdef DEBUG
                     79: #include "dbg.h"
                     80: #endif
1.1       ratchov    81:
1.57      ratchov    82: int  dev_open(struct dev *);
                     83: void dev_close(struct dev *);
                     84: void dev_start(struct dev *);
                     85: void dev_stop(struct dev *);
                     86: void dev_clear(struct dev *);
1.71      ratchov    87: void dev_onmove(void *, int);
1.66      ratchov    88: int  devctl_open(struct dev *, struct devctl *);
1.84      ratchov    89: int  dev_getep(struct dev *, unsigned int, struct abuf **, struct abuf **);
                     90: void dev_sync(struct dev *, unsigned int, struct abuf *, struct abuf *);
                     91: int  dev_mkslot(struct dev *, char *);
                     92: int  dev_try(struct dev *, int);
                     93:
1.57      ratchov    94:
                     95: struct dev *dev_list = NULL;
1.79      ratchov    96: unsigned int dev_sndnum = 0, dev_thrnum = 0;
1.68      ratchov    97:
                     98: #ifdef DEBUG
                     99: void
                    100: dev_dbg(struct dev *d)
                    101: {
                    102:        if (d->num >= DEV_NMAX) {
                    103:                dbg_puts("thr");
                    104:                dbg_putu(d->num - DEV_NMAX);
                    105:        } else {
                    106:                dbg_puts("snd");
                    107:                dbg_putu(d->num);
                    108:        }
                    109: }
                    110: #endif
1.38      ratchov   111:
                    112: /*
1.51      ratchov   113:  * Create a sndio device
1.28      ratchov   114:  */
1.57      ratchov   115: struct dev *
1.79      ratchov   116: dev_new(char *path, unsigned int mode, unsigned int bufsz, unsigned int round,
                    117:     unsigned int hold, unsigned int autovol)
1.57      ratchov   118: {
                    119:        struct dev *d;
1.79      ratchov   120:        unsigned int *pnum, i;
1.57      ratchov   121:
1.68      ratchov   122:        pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum;
                    123:        if (*pnum == DEV_NMAX) {
                    124: #ifdef DEBUG
                    125:                if (debug_level >= 1)
                    126:                        dbg_puts("too many devices\n");
                    127: #endif
                    128:                return NULL;
1.78      ratchov   129:        }
                    130:        d = malloc(sizeof(struct dev));
                    131:        if (d == NULL) {
                    132:                perror("malloc");
                    133:                exit(1);
1.68      ratchov   134:        }
                    135:        d->num = (*pnum)++;
                    136:        if (mode & MODE_THRU)
                    137:                d->num += DEV_NMAX;
1.66      ratchov   138:        d->ctl_list = NULL;
1.57      ratchov   139:        d->path = path;
                    140:        d->reqmode = mode;
1.67      ratchov   141:        aparams_init(&d->reqopar, NCHAN_MAX, 0, 0);
                    142:        aparams_init(&d->reqipar, NCHAN_MAX, 0, 0);
1.57      ratchov   143:        d->reqbufsz = bufsz;
                    144:        d->reqround = round;
                    145:        d->hold = hold;
1.65      ratchov   146:        d->autovol = autovol;
1.67      ratchov   147:        d->autostart = 0;
1.72      ratchov   148:        d->refcnt = 0;
1.57      ratchov   149:        d->pstate = DEV_CLOSED;
1.71      ratchov   150:        d->serial = 0;
                    151:        for (i = 0; i < CTL_NSLOT; i++) {
                    152:                d->slot[i].unit = i;
                    153:                d->slot[i].ops = NULL;
                    154:                d->slot[i].vol = MIDI_MAXCTL;
                    155:                d->slot[i].tstate = CTL_OFF;
                    156:                d->slot[i].serial = d->serial++;
                    157:                d->slot[i].name[0] = '\0';
                    158:        }
1.77      ratchov   159:        d->master = MIDI_MAXCTL;
1.71      ratchov   160:        d->origin = 0;
                    161:        d->tstate = CTL_STOP;
1.57      ratchov   162:        d->next = dev_list;
1.68      ratchov   163:        dev_list = d;
1.57      ratchov   164:        return d;
1.28      ratchov   165: }
1.24      ratchov   166:
                    167: /*
1.67      ratchov   168:  * adjust device parameters and mode
1.24      ratchov   169:  */
1.67      ratchov   170: void
1.79      ratchov   171: dev_adjpar(struct dev *d, unsigned int mode,
1.67      ratchov   172:     struct aparams *ipar, struct aparams *opar)
1.24      ratchov   173: {
1.67      ratchov   174:        d->reqmode |= (mode | MODE_MIDIMASK);
                    175:        if (mode & MODE_REC)
                    176:                aparams_grow(&d->reqipar, ipar);
                    177:        if (mode & MODE_PLAY)
                    178:                aparams_grow(&d->reqopar, opar);
1.24      ratchov   179: }
1.1       ratchov   180:
1.51      ratchov   181: /*
1.67      ratchov   182:  * Initialize the device with the current parameters
1.51      ratchov   183:  */
1.67      ratchov   184: int
                    185: dev_init(struct dev *d)
1.1       ratchov   186: {
1.67      ratchov   187:        if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) {
                    188: #ifdef DEBUG
1.68      ratchov   189:                    dev_dbg(d);
1.67      ratchov   190:                    dbg_puts(": has no streams, skipped\n");
                    191: #endif
                    192:                    return 1;
                    193:        }
                    194:        if (d->hold && d->pstate == DEV_CLOSED && !dev_open(d)) {
                    195:                dev_del(d);
                    196:                return 0;
1.57      ratchov   197:        }
1.67      ratchov   198:        return 1;
1.1       ratchov   199: }
                    200:
                    201: /*
1.66      ratchov   202:  * Add a MIDI port to the device
                    203:  */
                    204: int
1.79      ratchov   205: devctl_add(struct dev *d, char *path, unsigned int mode)
1.66      ratchov   206: {
                    207:        struct devctl *c;
                    208:
                    209:        c = malloc(sizeof(struct devctl));
                    210:        if (c == NULL) {
                    211:                perror("malloc");
                    212:                exit(1);
                    213:        }
1.68      ratchov   214:        c->path = path;
1.66      ratchov   215:        c->mode = mode;
                    216:        c->next = d->ctl_list;
                    217:        d->ctl_list = c;
1.67      ratchov   218:        if (d->pstate != DEV_CLOSED && !devctl_open(d, c))
                    219:                return 0;
1.66      ratchov   220:        return 1;
                    221: }
                    222:
                    223: /*
                    224:  * Open a MIDI device and connect it to the thru box
                    225:  */
                    226: int
                    227: devctl_open(struct dev *d, struct devctl *c)
                    228: {
                    229:        struct file *f;
                    230:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    231:        struct aproc *rproc, *wproc;
                    232:
                    233:        f = (struct file *)miofile_new(&miofile_ops, c->path, c->mode);
                    234:        if (f == NULL)
                    235:                return 0;
                    236:        if (c->mode & MODE_MIDIIN) {
                    237:                rproc = rfile_new(f);
                    238:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                    239:                aproc_setout(rproc, rbuf);
                    240:        }
                    241:        if (c->mode & MODE_MIDIOUT) {
                    242:                wproc = wfile_new(f);
                    243:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
                    244:                aproc_setin(wproc, wbuf);
                    245:        }
                    246:        dev_midiattach(d, rbuf, wbuf);
                    247:        return 1;
                    248: }
                    249:
                    250: /*
1.51      ratchov   251:  * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
                    252:  * monitor, midi control, and any necessary conversions.
1.1       ratchov   253:  */
1.26      ratchov   254: int
1.57      ratchov   255: dev_open(struct dev *d)
1.1       ratchov   256: {
1.23      ratchov   257:        struct file *f;
1.66      ratchov   258:        struct devctl *c;
1.51      ratchov   259:        struct aparams par;
1.1       ratchov   260:        struct aproc *conv;
                    261:        struct abuf *buf;
1.79      ratchov   262:        unsigned int siomode, cmin, cmax, rate;
1.51      ratchov   263:
1.57      ratchov   264:        d->mode = d->reqmode;
                    265:        d->round = d->reqround;
                    266:        d->bufsz = d->reqbufsz;
                    267:        d->ipar = d->reqipar;
                    268:        d->opar = d->reqopar;
                    269:        d->rec = NULL;
                    270:        d->play = NULL;
                    271:        d->mon = NULL;
1.61      jakemsr   272:        d->mix = NULL;
                    273:        d->sub = NULL;
1.57      ratchov   274:        d->submon = NULL;
1.61      jakemsr   275:        d->midi = NULL;
1.57      ratchov   276:        d->rate = 0;
1.36      ratchov   277:
1.67      ratchov   278:        if (d->opar.cmin > d->opar.cmax) {
                    279:                d->opar.cmin = 0;
                    280:                d->opar.cmax = 1;
                    281:        }
                    282:        if (d->ipar.cmin > d->ipar.cmax) {
                    283:                d->ipar.cmin = 0;
                    284:                d->ipar.cmax = 1;
                    285:        }
                    286:        if (d->opar.rate > d->ipar.rate)
                    287:                d->ipar.rate = d->opar.rate;
                    288:        else
                    289:                d->opar.rate = d->ipar.rate;
                    290:        if (d->opar.rate == 0)
1.76      ratchov   291:                d->opar.rate = d->ipar.rate = 48000; /* XXX */
1.67      ratchov   292:
                    293:        if (d->mode & MODE_THRU)
                    294:                d->mode &= ~MODE_AUDIOMASK;
                    295:
1.3       ratchov   296:        /*
1.51      ratchov   297:         * If needed, open the device (ie create dev_rec and dev_play)
1.3       ratchov   298:         */
1.57      ratchov   299:        if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
                    300:                siomode = d->mode & (MODE_PLAY | MODE_REC);
1.51      ratchov   301:                f = (struct file *)siofile_new(&siofile_ops,
1.57      ratchov   302:                    d->path,
1.51      ratchov   303:                    &siomode,
1.57      ratchov   304:                    &d->ipar,
                    305:                    &d->opar,
                    306:                    &d->bufsz,
                    307:                    &d->round);
1.51      ratchov   308:                if (f == NULL) {
1.39      ratchov   309: #ifdef DEBUG
1.51      ratchov   310:                        if (debug_level >= 1) {
1.68      ratchov   311:                                dev_dbg(d);
                    312:                                dbg_puts(": ");
1.62      ratchov   313:                                dbg_puts(d->path);
1.51      ratchov   314:                                dbg_puts(": failed to open audio device\n");
                    315:                        }
                    316: #endif
                    317:                        return 0;
1.39      ratchov   318:                }
1.51      ratchov   319:                if (!(siomode & MODE_PLAY))
1.57      ratchov   320:                        d->mode &= ~(MODE_PLAY | MODE_MON);
1.51      ratchov   321:                if (!(siomode & MODE_REC))
1.57      ratchov   322:                        d->mode &= ~MODE_REC;
                    323:                if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
1.51      ratchov   324: #ifdef DEBUG
                    325:                        if (debug_level >= 1) {
1.68      ratchov   326:                                dev_dbg(d);
1.51      ratchov   327:                                dbg_puts(": mode not supported by device\n");
                    328:                        }
1.39      ratchov   329: #endif
1.51      ratchov   330:                        return 0;
                    331:                }
1.57      ratchov   332:                d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
1.67      ratchov   333:                if (d->mode & MODE_REC) {
                    334:                        d->rec = rsio_new(f);
                    335:                        d->rec->refs++;
                    336:                }
                    337:                if (d->mode & MODE_PLAY) {
                    338:                        d->play = wsio_new(f);
                    339:                        d->play->refs++;
                    340:                }
                    341:        }
                    342:        if (d->mode & MODE_LOOP) {
                    343:                if (d->mode & MODE_MON) {
1.39      ratchov   344: #ifdef DEBUG
1.67      ratchov   345:                        if (debug_level >= 1) {
                    346:                                dbg_puts("monitoring not allowed "
                    347:                                    "in loopback mode\n");
1.51      ratchov   348:                        }
1.67      ratchov   349: #endif
                    350:                        return 0;
                    351:                }
                    352:                if ((d->mode & MODE_PLAYREC) != MODE_PLAYREC) {
                    353: #ifdef DEBUG
                    354:                        if (debug_level >= 1) {
                    355:                                dbg_puts("both play and record streams "
                    356:                                    "required in loopback mode\n");
1.51      ratchov   357:                        }
1.67      ratchov   358: #endif
                    359:                        return 0;
1.39      ratchov   360:                }
1.67      ratchov   361:                if (d->ctl_list) {
                    362: #ifdef DEBUG
                    363:                        if (debug_level >= 1) {
                    364:                                dbg_puts("MIDI control not allowed "
                    365:                                    "in loopback mode\n");
                    366:                        }
1.39      ratchov   367: #endif
1.67      ratchov   368:                        return 0;
                    369:                }
                    370:                cmin = (d->ipar.cmin < d->opar.cmin) ?
                    371:                    d->ipar.cmin : d->opar.cmin;
                    372:                cmax = (d->ipar.cmax > d->opar.cmax) ?
                    373:                    d->ipar.cmax : d->opar.cmax;
                    374:                rate = (d->ipar.rate > d->opar.rate) ?
                    375:                    d->ipar.rate : d->opar.rate;
                    376:                aparams_init(&par, cmin, cmax, rate);
                    377:                d->ipar = par;
                    378:                d->opar = par;
                    379:                d->rate = rate;
1.81      ratchov   380:                /*
                    381:                 * block sizes in the resampling code are limited to
                    382:                 * 2^15, so use 1/15 of the rate, since all standard
                    383:                 * sample rates are multiple of 15
                    384:                 */
                    385:                d->round = rate / 15;
1.67      ratchov   386:                d->bufsz = 2 * d->round;
                    387:        }
                    388: #ifdef DEBUG
                    389:        if (debug_level >= 2) {
1.57      ratchov   390:                if (d->mode & MODE_REC) {
1.68      ratchov   391:                        dev_dbg(d);
1.67      ratchov   392:                        dbg_puts(": recording ");
                    393:                        aparams_dbg(&d->ipar);
                    394:                        dbg_puts("\n");
1.57      ratchov   395:                }
                    396:                if (d->mode & MODE_PLAY) {
1.68      ratchov   397:                        dev_dbg(d);
1.67      ratchov   398:                        dbg_puts(": playing ");
                    399:                        aparams_dbg(&d->opar);
                    400:                        dbg_puts("\n");
1.51      ratchov   401:                }
1.3       ratchov   402:        }
1.67      ratchov   403: #endif
1.11      ratchov   404:        /*
1.51      ratchov   405:         * Create the midi control end, or a simple thru box
                    406:         * if there's no device
                    407:         */
1.64      ratchov   408:        if (d->mode & MODE_MIDIMASK) {
1.73      ratchov   409:                d->midi = midi_new("midi", (d->mode & MODE_THRU) ? NULL : d);
1.64      ratchov   410:                d->midi->refs++;
                    411:        }
1.51      ratchov   412:
                    413:        /*
                    414:         * Create mixer, demuxer and monitor
1.1       ratchov   415:         */
1.57      ratchov   416:        if (d->mode & MODE_PLAY) {
1.77      ratchov   417:                d->mix = mix_new("play", d->bufsz, d->round,
                    418:                    d->autovol, MIDI_TO_ADATA(d->master));
1.57      ratchov   419:                d->mix->refs++;
                    420:        }
                    421:        if (d->mode & MODE_REC) {
                    422:                d->sub = sub_new("rec", d->bufsz, d->round);
                    423:                d->sub->refs++;
1.51      ratchov   424:        }
1.57      ratchov   425:        if (d->mode & MODE_LOOP) {
1.51      ratchov   426:                /*
                    427:                 * connect mixer out to demuxer in
                    428:                 */
1.57      ratchov   429:                buf = abuf_new(d->bufsz, &d->opar);
                    430:                aproc_setout(d->mix, buf);
                    431:                aproc_setin(d->sub, buf);
                    432:
                    433:                d->mix->flags |= APROC_QUIT;
                    434:                d->sub->flags |= APROC_QUIT;
1.51      ratchov   435:        }
1.57      ratchov   436:        if (d->rec) {
                    437:                aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
1.51      ratchov   438:
1.1       ratchov   439:                /*
1.51      ratchov   440:                 * Create device <-> demuxer buffer
1.1       ratchov   441:                 */
1.57      ratchov   442:                buf = abuf_new(d->bufsz, &d->ipar);
                    443:                aproc_setout(d->rec, buf);
1.1       ratchov   444:
                    445:                /*
1.51      ratchov   446:                 * Insert a converter, if needed.
1.1       ratchov   447:                 */
1.57      ratchov   448:                if (!aparams_eqenc(&d->ipar, &par)) {
                    449:                        conv = dec_new("rec", &d->ipar);
1.1       ratchov   450:                        aproc_setin(conv, buf);
1.57      ratchov   451:                        buf = abuf_new(d->round, &par);
1.1       ratchov   452:                        aproc_setout(conv, buf);
                    453:                }
1.57      ratchov   454:                d->ipar = par;
                    455:                aproc_setin(d->sub, buf);
1.1       ratchov   456:        }
1.57      ratchov   457:        if (d->play) {
                    458:                aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
1.1       ratchov   459:
                    460:                /*
1.51      ratchov   461:                 * Create device <-> mixer buffer
1.1       ratchov   462:                 */
1.57      ratchov   463:                buf = abuf_new(d->bufsz, &d->opar);
                    464:                aproc_setin(d->play, buf);
1.25      ratchov   465:
1.1       ratchov   466:                /*
1.27      ratchov   467:                 * Append a converter, if needed.
1.1       ratchov   468:                 */
1.57      ratchov   469:                if (!aparams_eqenc(&par, &d->opar)) {
                    470:                        conv = enc_new("play", &d->opar);
1.1       ratchov   471:                        aproc_setout(conv, buf);
1.57      ratchov   472:                        buf = abuf_new(d->round, &par);
1.1       ratchov   473:                        aproc_setin(conv, buf);
                    474:                }
1.57      ratchov   475:                d->opar = par;
                    476:                aproc_setout(d->mix, buf);
1.1       ratchov   477:        }
1.57      ratchov   478:        if (d->mode & MODE_MON) {
                    479:                d->mon = mon_new("mon", d->bufsz);
                    480:                d->mon->refs++;
                    481:                buf = abuf_new(d->bufsz, &d->opar);
                    482:                aproc_setout(d->mon, buf);
1.46      ratchov   483:
                    484:                /*
                    485:                 * Append a "sub" to which clients will connect.
                    486:                 */
1.57      ratchov   487:                d->submon = sub_new("mon", d->bufsz, d->round);
                    488:                d->submon->refs++;
                    489:                aproc_setin(d->submon, buf);
1.46      ratchov   490:
                    491:                /*
1.51      ratchov   492:                 * Attach to the mixer
1.46      ratchov   493:                 */
1.57      ratchov   494:                d->mix->u.mix.mon = d->mon;
                    495:                d->mon->refs++;
1.46      ratchov   496:        }
1.39      ratchov   497: #ifdef DEBUG
1.51      ratchov   498:        if (debug_level >= 2) {
1.57      ratchov   499:                if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
1.68      ratchov   500:                        dev_dbg(d);
1.62      ratchov   501:                        dbg_puts(": block size is ");
1.57      ratchov   502:                        dbg_putu(d->round);
1.51      ratchov   503:                        dbg_puts(" frames, using ");
1.57      ratchov   504:                        dbg_putu(d->bufsz / d->round);
1.51      ratchov   505:                        dbg_puts(" blocks\n");
                    506:                }
1.39      ratchov   507:        }
                    508: #endif
1.57      ratchov   509:        d->pstate = DEV_INIT;
1.66      ratchov   510:        for (c = d->ctl_list; c != NULL; c = c->next) {
                    511:                if (!devctl_open(d, c)) {
                    512: #ifdef DEBUG
                    513:                        if (debug_level >= 1) {
                    514:                                dbg_puts(c->path);
                    515:                                dbg_puts(": couldn't open MIDI port\n");
                    516:                        }
                    517: #endif
                    518:                        dev_close(d);
                    519:                        return 0;
                    520:                }
                    521:        }
1.26      ratchov   522:        return 1;
1.1       ratchov   523: }
                    524:
                    525: /*
1.27      ratchov   526:  * Cleanly stop and drain everything and close the device
                    527:  * once both play chain and record chain are gone.
1.1       ratchov   528:  */
                    529: void
1.57      ratchov   530: dev_close(struct dev *d)
1.1       ratchov   531: {
                    532:        struct file *f;
                    533:
1.50      ratchov   534:        /*
                    535:         * if the device is starting, ensure it actually starts
                    536:         * so buffers are drained, else clear any buffers
                    537:         */
1.57      ratchov   538:        switch (d->pstate) {
1.50      ratchov   539:        case DEV_START:
                    540: #ifdef DEBUG
1.69      ratchov   541:                if (debug_level >= 3) {
                    542:                        dev_dbg(d);
                    543:                        dbg_puts(": draining device\n");
                    544:                }
1.50      ratchov   545: #endif
1.57      ratchov   546:                dev_start(d);
1.50      ratchov   547:                break;
                    548:        case DEV_INIT:
                    549: #ifdef DEBUG
1.69      ratchov   550:                if (debug_level >= 3) {
                    551:                        dev_dbg(d);
                    552:                        dbg_puts(": flushing device\n");
                    553:                }
1.50      ratchov   554: #endif
1.57      ratchov   555:                dev_clear(d);
1.50      ratchov   556:                break;
                    557:        }
1.39      ratchov   558: #ifdef DEBUG
1.69      ratchov   559:        if (debug_level >= 2) {
                    560:                dev_dbg(d);
                    561:                dbg_puts(": closing device\n");
                    562:        }
1.39      ratchov   563: #endif
1.70      ratchov   564:        d->pstate = DEV_CLOSED;
1.57      ratchov   565:        if (d->mix) {
1.3       ratchov   566:                /*
1.32      ratchov   567:                 * Put the mixer in ``autoquit'' state and generate
                    568:                 * EOF on all inputs connected it. Once buffers are
                    569:                 * drained the mixer will terminate and shutdown the
                    570:                 * device.
1.3       ratchov   571:                 *
                    572:                 * NOTE: since file_eof() can destroy the file and
                    573:                 * reorder the file_list, we have to restart the loop
1.27      ratchov   574:                 * after each call to file_eof().
1.3       ratchov   575:                 */
1.57      ratchov   576:                if (APROC_OK(d->mix))
                    577:                        mix_quit(d->mix);
1.51      ratchov   578:
                    579:                /*
                    580:                 * XXX: handle this in mix_done()
                    581:                 */
1.57      ratchov   582:                if (APROC_OK(d->mix->u.mix.mon)) {
                    583:                        d->mix->u.mix.mon->refs--;
                    584:                        aproc_del(d->mix->u.mix.mon);
                    585:                        d->mix->u.mix.mon = NULL;
1.46      ratchov   586:                }
1.32      ratchov   587:        restart_mix:
1.3       ratchov   588:                LIST_FOREACH(f, &file_list, entry) {
1.32      ratchov   589:                        if (f->rproc != NULL &&
1.57      ratchov   590:                            aproc_depend(d->mix, f->rproc)) {
1.3       ratchov   591:                                file_eof(f);
1.32      ratchov   592:                                goto restart_mix;
1.3       ratchov   593:                        }
                    594:                }
1.59      ratchov   595:        } else if (d->sub) {
1.3       ratchov   596:                /*
1.32      ratchov   597:                 * Same as above, but since there's no mixer,
                    598:                 * we generate EOF on the record-end of the
                    599:                 * device.
                    600:                 */
                    601:        restart_sub:
                    602:                LIST_FOREACH(f, &file_list, entry) {
                    603:                        if (f->rproc != NULL &&
1.59      ratchov   604:                            aproc_depend(d->sub, f->rproc)) {
1.32      ratchov   605:                                file_eof(f);
                    606:                                goto restart_sub;
1.59      ratchov   607:                        }
                    608:                }
                    609:        } else if (d->submon) {
                    610:                /*
                    611:                 * Same as above
                    612:                 */
                    613:        restart_submon:
                    614:                LIST_FOREACH(f, &file_list, entry) {
                    615:                        if (f->rproc != NULL &&
                    616:                            aproc_depend(d->submon, f->rproc)) {
                    617:                                file_eof(f);
                    618:                                goto restart_submon;
1.23      ratchov   619:                        }
1.32      ratchov   620:                }
                    621:        }
1.57      ratchov   622:        if (d->midi) {
                    623:                d->midi->flags |= APROC_QUIT;
                    624:                if (LIST_EMPTY(&d->midi->ins))
                    625:                        aproc_del(d->midi);
1.36      ratchov   626:        restart_midi:
                    627:                LIST_FOREACH(f, &file_list, entry) {
                    628:                        if (f->rproc &&
1.57      ratchov   629:                            aproc_depend(d->midi, f->rproc)) {
1.36      ratchov   630:                                file_eof(f);
                    631:                                goto restart_midi;
                    632:                        }
                    633:                }
                    634:        }
1.57      ratchov   635:        if (d->mix) {
                    636:                if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
                    637:                        aproc_del(d->mix);
                    638:                d->mix = NULL;
                    639:        }
                    640:        if (d->play) {
                    641:                if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
                    642:                        aproc_del(d->play);
                    643:                d->play = NULL;
                    644:        }
                    645:        if (d->sub) {
                    646:                if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
                    647:                        aproc_del(d->sub);
                    648:                d->sub = NULL;
                    649:        }
                    650:        if (d->rec) {
                    651:                if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
                    652:                        aproc_del(d->rec);
                    653:                d->rec = NULL;
                    654:        }
                    655:        if (d->submon) {
                    656:                if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
                    657:                        aproc_del(d->submon);
                    658:                d->submon = NULL;
                    659:        }
                    660:        if (d->mon) {
                    661:                if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
                    662:                        aproc_del(d->mon);
                    663:                d->mon = NULL;
                    664:        }
                    665:        if (d->midi) {
                    666:                if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
                    667:                        aproc_del(d->midi);
                    668:                d->midi = NULL;
1.32      ratchov   669:        }
1.51      ratchov   670: }
                    671:
                    672: /*
1.60      ratchov   673:  * Unless the device is already in process of closing, request it to close
                    674:  */
                    675: void
                    676: dev_drain(struct dev *d)
                    677: {
1.79      ratchov   678:        unsigned int i;
1.71      ratchov   679:        struct ctl_slot *s;
                    680:
                    681:        for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
                    682:                if (s->ops)
                    683:                        s->ops->quit(s->arg);
                    684:        }
1.60      ratchov   685:        if (d->pstate != DEV_CLOSED)
                    686:                dev_close(d);
                    687: }
                    688:
                    689: /*
1.51      ratchov   690:  * Free the device
                    691:  */
                    692: void
1.57      ratchov   693: dev_del(struct dev *d)
1.51      ratchov   694: {
1.57      ratchov   695:        struct dev **p;
                    696:
1.60      ratchov   697:        dev_drain(d);
1.57      ratchov   698:        for (p = &dev_list; *p != d; p = &(*p)->next) {
                    699: #ifdef DEBUG
                    700:                if (*p == NULL) {
                    701:                        dbg_puts("device to delete not on the list\n");
                    702:                        dbg_panic();
                    703:                }
                    704: #endif
                    705:        }
                    706:        *p = d->next;
                    707:        free(d);
1.51      ratchov   708: }
                    709:
                    710: /*
                    711:  * Attach a bi-directional MIDI stream to the MIDI device
                    712:  */
                    713: void
1.57      ratchov   714: dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
1.51      ratchov   715: {
                    716:        if (ibuf)
1.57      ratchov   717:                aproc_setin(d->midi, ibuf);
1.51      ratchov   718:        if (obuf) {
1.57      ratchov   719:                aproc_setout(d->midi, obuf);
1.51      ratchov   720:                if (ibuf) {
                    721:                        ibuf->duplex = obuf;
                    722:                        obuf->duplex = ibuf;
                    723:                }
1.1       ratchov   724:        }
                    725: }
                    726:
1.79      ratchov   727: unsigned int
                    728: dev_roundof(struct dev *d, unsigned int newrate)
1.51      ratchov   729: {
1.57      ratchov   730:        return (d->round * newrate + d->rate / 2) / d->rate;
1.51      ratchov   731: }
                    732:
1.1       ratchov   733: /*
1.27      ratchov   734:  * Start the (paused) device. By default it's paused.
1.1       ratchov   735:  */
                    736: void
1.57      ratchov   737: dev_start(struct dev *d)
1.1       ratchov   738: {
1.22      ratchov   739:        struct file *f;
                    740:
1.46      ratchov   741: #ifdef DEBUG
                    742:        if (debug_level >= 2)
1.51      ratchov   743:                dbg_puts("starting device\n");
1.46      ratchov   744: #endif
1.57      ratchov   745:        d->pstate = DEV_RUN;
                    746:        if (d->mode & MODE_LOOP)
1.52      ratchov   747:                return;
1.57      ratchov   748:        if (APROC_OK(d->mix))
                    749:                d->mix->flags |= APROC_DROP;
                    750:        if (APROC_OK(d->sub))
                    751:                d->sub->flags |= APROC_DROP;
                    752:        if (APROC_OK(d->submon))
                    753:                d->submon->flags |= APROC_DROP;
                    754:        if (APROC_OK(d->play) && d->play->u.io.file) {
                    755:                f = d->play->u.io.file;
1.71      ratchov   756:                f->ops->start(f, dev_onmove, d);
1.57      ratchov   757:        } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
                    758:                f = d->rec->u.io.file;
1.71      ratchov   759:                f->ops->start(f, dev_onmove, d);
1.22      ratchov   760:        }
1.1       ratchov   761: }
                    762:
                    763: /*
1.46      ratchov   764:  * Pause the device. This may trigger context switches,
                    765:  * so it shouldn't be called from aproc methods
1.1       ratchov   766:  */
                    767: void
1.57      ratchov   768: dev_stop(struct dev *d)
1.1       ratchov   769: {
1.22      ratchov   770:        struct file *f;
                    771:
1.52      ratchov   772: #ifdef DEBUG
1.69      ratchov   773:        if (debug_level >= 2) {
                    774:                dev_dbg(d);
                    775:                dbg_puts(": device stopped\n");
                    776:        }
1.52      ratchov   777: #endif
1.57      ratchov   778:        d->pstate = DEV_INIT;
                    779:        if (d->mode & MODE_LOOP)
1.52      ratchov   780:                return;
1.57      ratchov   781:        if (APROC_OK(d->play) && d->play->u.io.file) {
                    782:                f = d->play->u.io.file;
1.22      ratchov   783:                f->ops->stop(f);
1.57      ratchov   784:        } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
                    785:                f = d->rec->u.io.file;
1.22      ratchov   786:                f->ops->stop(f);
                    787:        }
1.57      ratchov   788:        if (APROC_OK(d->mix))
                    789:                d->mix->flags &= ~APROC_DROP;
                    790:        if (APROC_OK(d->sub))
                    791:                d->sub->flags &= ~APROC_DROP;
                    792:        if (APROC_OK(d->submon))
                    793:                d->submon->flags &= ~APROC_DROP;
1.51      ratchov   794: }
                    795:
                    796: int
1.57      ratchov   797: dev_ref(struct dev *d)
1.51      ratchov   798: {
                    799: #ifdef DEBUG
1.69      ratchov   800:        if (debug_level >= 3) {
                    801:                dev_dbg(d);
                    802:                dbg_puts(": device requested\n");
                    803:        }
1.51      ratchov   804: #endif
1.57      ratchov   805:        if (d->pstate == DEV_CLOSED && !dev_open(d)) {
                    806:                if (d->hold)
                    807:                        dev_del(d);
1.51      ratchov   808:                return 0;
1.57      ratchov   809:        }
                    810:        d->refcnt++;
1.51      ratchov   811:        return 1;
                    812: }
                    813:
                    814: void
1.57      ratchov   815: dev_unref(struct dev *d)
1.51      ratchov   816: {
                    817: #ifdef DEBUG
1.69      ratchov   818:        if (debug_level >= 3) {
                    819:                dev_dbg(d);
                    820:                dbg_puts(": device released\n");
                    821:        }
1.51      ratchov   822: #endif
1.57      ratchov   823:        d->refcnt--;
                    824:        if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
                    825:                dev_close(d);
1.51      ratchov   826: }
                    827:
                    828: /*
                    829:  * There are actions (like start/stop/close ... ) that may trigger aproc
                    830:  * operations, a thus cannot be started from aproc context.
                    831:  * To avoid problems, aprocs only change the s!tate of the device,
                    832:  * and actual operations are triggered from the main loop,
                    833:  * outside the aproc code path.
                    834:  *
                    835:  * The following routine invokes pending actions, returns 0
                    836:  * on fatal error
                    837:  */
                    838: int
1.57      ratchov   839: dev_run(struct dev *d)
1.51      ratchov   840: {
1.57      ratchov   841:        if (d->pstate == DEV_CLOSED)
1.51      ratchov   842:                return 1;
                    843:        /*
                    844:         * check if device isn't gone
                    845:         */
1.57      ratchov   846:        if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
                    847:            ((d->mode & MODE_REC)  && !APROC_OK(d->sub)) ||
                    848:            ((d->mode & MODE_MON)  && !APROC_OK(d->submon))) {
1.51      ratchov   849: #ifdef DEBUG
1.74      ratchov   850:                if (debug_level >= 2) {
1.69      ratchov   851:                        dev_dbg(d);
                    852:                        dbg_puts(": device disappeared\n");
                    853:                }
1.51      ratchov   854: #endif
1.57      ratchov   855:                if (d->hold) {
                    856:                        dev_del(d);
                    857:                        return 0;
                    858:                }
                    859:                dev_close(d);
                    860:                return 1;
1.51      ratchov   861:        }
1.57      ratchov   862:        switch (d->pstate) {
1.51      ratchov   863:        case DEV_INIT:
                    864:                /* nothing */
                    865:                break;
                    866:        case DEV_START:
1.57      ratchov   867:                dev_start(d);
1.51      ratchov   868:                /* PASSTHROUGH */
                    869:        case DEV_RUN:
                    870:                /*
                    871:                 * if the device is not used, then stop it
                    872:                 */
1.57      ratchov   873:                if ((!APROC_OK(d->mix) ||
                    874:                        d->mix->u.mix.idle > 2 * d->bufsz) &&
                    875:                    (!APROC_OK(d->sub) ||
                    876:                        d->sub->u.sub.idle > 2 * d->bufsz) &&
                    877:                    (!APROC_OK(d->submon) ||
                    878:                        d->submon->u.sub.idle > 2 * d->bufsz) &&
                    879:                    (!APROC_OK(d->midi) ||
1.71      ratchov   880:                        d->tstate != CTL_RUN)) {
1.51      ratchov   881: #ifdef DEBUG
1.69      ratchov   882:                        if (debug_level >= 3) {
                    883:                                dev_dbg(d);
                    884:                                dbg_puts(": device idle, suspending\n");
                    885:                        }
1.46      ratchov   886: #endif
1.57      ratchov   887:                        dev_stop(d);
                    888:                        if (d->refcnt == 0 && !d->hold)
                    889:                                dev_close(d);
1.58      ratchov   890:                        else
1.57      ratchov   891:                                dev_clear(d);
1.51      ratchov   892:                }
                    893:                break;
                    894:        }
                    895:        return 1;
                    896: }
                    897:
                    898: /*
1.58      ratchov   899:  * If the device is paused, then resume it.
1.51      ratchov   900:  * This routine can be called from aproc context.
                    901:  */
                    902: void
1.57      ratchov   903: dev_wakeup(struct dev *d)
1.51      ratchov   904: {
1.57      ratchov   905:        if (d->pstate == DEV_INIT)
                    906:                d->pstate = DEV_START;
1.1       ratchov   907: }
                    908:
                    909: /*
1.27      ratchov   910:  * Find the end points connected to the mix/sub.
1.14      ratchov   911:  */
                    912: int
1.57      ratchov   913: dev_getep(struct dev *d,
1.79      ratchov   914:     unsigned int mode, struct abuf **sibuf, struct abuf **sobuf)
1.14      ratchov   915: {
                    916:        struct abuf *ibuf, *obuf;
                    917:
1.46      ratchov   918:        if (mode & MODE_PLAY) {
1.57      ratchov   919:                if (!APROC_OK(d->mix))
1.46      ratchov   920:                        return 0;
1.14      ratchov   921:                ibuf = *sibuf;
                    922:                for (;;) {
                    923:                        if (!ibuf || !ibuf->rproc) {
1.39      ratchov   924: #ifdef DEBUG
                    925:                                if (debug_level >= 3) {
                    926:                                        abuf_dbg(*sibuf);
                    927:                                        dbg_puts(": not connected to device\n");
                    928:                                }
                    929: #endif
1.14      ratchov   930:                                return 0;
                    931:                        }
1.57      ratchov   932:                        if (ibuf->rproc == d->mix)
1.14      ratchov   933:                                break;
1.49      ratchov   934:                        ibuf = LIST_FIRST(&ibuf->rproc->outs);
1.14      ratchov   935:                }
1.21      ratchov   936:                *sibuf = ibuf;
1.14      ratchov   937:        }
1.46      ratchov   938:        if (mode & MODE_REC) {
1.57      ratchov   939:                if (!APROC_OK(d->sub))
1.46      ratchov   940:                        return 0;
1.14      ratchov   941:                obuf = *sobuf;
                    942:                for (;;) {
                    943:                        if (!obuf || !obuf->wproc) {
1.39      ratchov   944: #ifdef DEBUG
                    945:                                if (debug_level >= 3) {
                    946:                                        abuf_dbg(*sobuf);
                    947:                                        dbg_puts(": not connected to device\n");
                    948:                                }
                    949: #endif
1.14      ratchov   950:                                return 0;
                    951:                        }
1.57      ratchov   952:                        if (obuf->wproc == d->sub)
1.14      ratchov   953:                                break;
1.49      ratchov   954:                        obuf = LIST_FIRST(&obuf->wproc->ins);
1.14      ratchov   955:                }
1.21      ratchov   956:                *sobuf = obuf;
1.14      ratchov   957:        }
1.46      ratchov   958:        if (mode & MODE_MON) {
1.57      ratchov   959:                if (!APROC_OK(d->submon))
1.46      ratchov   960:                        return 0;
                    961:                obuf = *sobuf;
                    962:                for (;;) {
                    963:                        if (!obuf || !obuf->wproc) {
                    964: #ifdef DEBUG
                    965:                                if (debug_level >= 3) {
                    966:                                        abuf_dbg(*sobuf);
                    967:                                        dbg_puts(": not connected to device\n");
                    968:                                }
                    969: #endif
                    970:                                return 0;
                    971:                        }
1.57      ratchov   972:                        if (obuf->wproc == d->submon)
1.46      ratchov   973:                                break;
1.49      ratchov   974:                        obuf = LIST_FIRST(&obuf->wproc->ins);
1.46      ratchov   975:                }
                    976:                *sobuf = obuf;
                    977:        }
1.14      ratchov   978:        return 1;
                    979: }
                    980:
                    981: /*
1.27      ratchov   982:  * Sync play buffer to rec buffer (for instance when one of
                    983:  * them underruns/overruns).
1.1       ratchov   984:  */
                    985: void
1.79      ratchov   986: dev_sync(struct dev *d, unsigned int mode,
                    987:     struct abuf *ibuf, struct abuf *obuf)
1.1       ratchov   988: {
1.53      ratchov   989:        int delta, offs;
1.57      ratchov   990:        struct abuf *mbuf = NULL;
1.3       ratchov   991:
1.57      ratchov   992:        if (!dev_getep(d, mode, &ibuf, &obuf))
1.3       ratchov   993:                return;
                    994:        /*
1.27      ratchov   995:         * Calculate delta, the number of frames the play chain is ahead
1.3       ratchov   996:         * of the record chain. It's necessary to schedule silences (or
                    997:         * drops) in order to start playback and record in sync.
                    998:         */
1.53      ratchov   999:        offs = 0;
                   1000:        delta = 0;
1.57      ratchov  1001:        if (APROC_OK(d->mix)) {
                   1002:                mbuf = LIST_FIRST(&d->mix->outs);
1.53      ratchov  1003:                offs += mbuf->w.mix.todo;
1.57      ratchov  1004:                delta += d->mix->u.mix.lat;
1.53      ratchov  1005:        }
1.57      ratchov  1006:        if (APROC_OK(d->sub))
                   1007:                delta += d->sub->u.sub.lat;
1.39      ratchov  1008: #ifdef DEBUG
                   1009:        if (debug_level >= 3) {
1.69      ratchov  1010:                dev_dbg(d);
                   1011:                dbg_puts(": syncing device");
1.57      ratchov  1012:                if (APROC_OK(d->mix)) {
1.51      ratchov  1013:                        dbg_puts(", ");
1.57      ratchov  1014:                        aproc_dbg(d->mix);
1.53      ratchov  1015:                        dbg_puts(": todo = ");
                   1016:                        dbg_putu(mbuf->w.mix.todo);
                   1017:                        dbg_puts(": lat = ");
1.57      ratchov  1018:                        dbg_putu(d->mix->u.mix.lat);
1.46      ratchov  1019:                }
1.57      ratchov  1020:                if (APROC_OK(d->sub)) {
1.51      ratchov  1021:                        dbg_puts(", ");
1.57      ratchov  1022:                        aproc_dbg(d->sub);
1.53      ratchov  1023:                        dbg_puts(": lat = ");
1.57      ratchov  1024:                        dbg_putu(d->sub->u.sub.lat);
1.46      ratchov  1025:                }
1.39      ratchov  1026:                dbg_puts("\n");
                   1027:        }
                   1028: #endif
1.53      ratchov  1029:        if (mode & MODE_PLAY)
                   1030:                mix_drop(ibuf, -offs);
                   1031:        if (mode & MODE_RECMASK)
                   1032:                sub_silence(obuf, -(offs + delta));
1.36      ratchov  1033: }
                   1034:
                   1035: /*
                   1036:  * return the current latency (in frames), ie the latency that
                   1037:  * a stream would have if dev_attach() is called on it.
1.71      ratchov  1038:  *
1.79      ratchov  1039:  * XXX: return a "unsigned int", since result is always positive, isn't it?
1.36      ratchov  1040:  */
                   1041: int
1.57      ratchov  1042: dev_getpos(struct dev *d)
1.36      ratchov  1043: {
1.53      ratchov  1044:        struct abuf *mbuf = NULL;
1.36      ratchov  1045:
1.57      ratchov  1046:        if (APROC_OK(d->mix)) {
                   1047:                mbuf = LIST_FIRST(&d->mix->outs);
                   1048:                return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
1.54      ratchov  1049:        } else
                   1050:                return 0;
1.1       ratchov  1051: }
                   1052:
                   1053: /*
1.27      ratchov  1054:  * Attach the given input and output buffers to the mixer and the
1.1       ratchov  1055:  * multiplexer respectively. The operation is done synchronously, so
                   1056:  * both buffers enter in sync. If buffers do not match play
1.27      ratchov  1057:  * and rec.
1.1       ratchov  1058:  */
                   1059: void
1.79      ratchov  1060: dev_attach(struct dev *d, char *name, unsigned int mode,
                   1061:     struct abuf *ibuf, struct aparams *sipar, unsigned int inch,
                   1062:     struct abuf *obuf, struct aparams *sopar, unsigned int onch,
                   1063:     unsigned int xrun, int vol)
1.1       ratchov  1064: {
1.12      ratchov  1065:        struct aparams ipar, opar;
1.1       ratchov  1066:        struct aproc *conv;
1.79      ratchov  1067:        unsigned int round, nblk, nch;
1.20      ratchov  1068:
1.46      ratchov  1069: #ifdef DEBUG
1.57      ratchov  1070:        if ((!APROC_OK(d->mix)    && (mode & MODE_PLAY)) ||
                   1071:            (!APROC_OK(d->sub)    && (mode & MODE_REC)) ||
                   1072:            (!APROC_OK(d->submon) && (mode & MODE_MON))) {
1.69      ratchov  1073:                dev_dbg(d);
                   1074:                dbg_puts(": mode beyond device mode, not attaching\n");
1.46      ratchov  1075:                return;
                   1076:        }
                   1077: #endif
                   1078:        if (mode & MODE_PLAY) {
1.12      ratchov  1079:                ipar = *sipar;
1.57      ratchov  1080:                nblk = (d->bufsz / d->round + 3) / 4;
                   1081:                round = dev_roundof(d, ipar.rate);
1.48      ratchov  1082:                nch = ipar.cmax - ipar.cmin + 1;
1.57      ratchov  1083:                if (!aparams_eqenc(&ipar, &d->opar)) {
1.10      ratchov  1084:                        conv = dec_new(name, &ipar);
1.57      ratchov  1085:                        ipar.bps = d->opar.bps;
                   1086:                        ipar.bits = d->opar.bits;
                   1087:                        ipar.sig = d->opar.sig;
                   1088:                        ipar.le = d->opar.le;
                   1089:                        ipar.msb = d->opar.msb;
1.25      ratchov  1090:                        aproc_setin(conv, ibuf);
1.20      ratchov  1091:                        ibuf = abuf_new(nblk * round, &ipar);
1.9       ratchov  1092:                        aproc_setout(conv, ibuf);
1.8       ratchov  1093:                }
1.48      ratchov  1094:                if (inch > 0 && nch >= inch * 2) {
                   1095:                        conv = join_new(name);
                   1096:                        aproc_setin(conv, ibuf);
                   1097:                        ipar.cmax = ipar.cmin + inch - 1;
                   1098:                        ibuf = abuf_new(nblk * round, &ipar);
                   1099:                        aproc_setout(conv, ibuf);
                   1100:                }
1.57      ratchov  1101:                if (!aparams_eqrate(&ipar, &d->opar)) {
                   1102:                        conv = resamp_new(name, round, d->round);
                   1103:                        ipar.rate = d->opar.rate;
                   1104:                        round = d->round;
1.5       ratchov  1105:                        aproc_setin(conv, ibuf);
1.20      ratchov  1106:                        ibuf = abuf_new(nblk * round, &ipar);
1.5       ratchov  1107:                        aproc_setout(conv, ibuf);
1.1       ratchov  1108:                }
1.48      ratchov  1109:                if (inch > 0 && nch * 2 <= inch) {
                   1110:                        conv = join_new(name);
                   1111:                        aproc_setin(conv, ibuf);
                   1112:                        ipar.cmax = ipar.cmin + inch - 1;
                   1113:                        ibuf = abuf_new(nblk * round, &ipar);
                   1114:                        aproc_setout(conv, ibuf);
                   1115:                }
1.57      ratchov  1116:                aproc_setin(d->mix, ibuf);
1.46      ratchov  1117:                ibuf->r.mix.xrun = xrun;
1.31      ratchov  1118:                ibuf->r.mix.maxweight = vol;
1.57      ratchov  1119:                mix_setmaster(d->mix);
1.1       ratchov  1120:        }
1.46      ratchov  1121:        if (mode & MODE_REC) {
1.12      ratchov  1122:                opar = *sopar;
1.57      ratchov  1123:                round = dev_roundof(d, opar.rate);
                   1124:                nblk = (d->bufsz / d->round + 3) / 4;
1.48      ratchov  1125:                nch = opar.cmax - opar.cmin + 1;
1.57      ratchov  1126:                if (!aparams_eqenc(&opar, &d->ipar)) {
1.10      ratchov  1127:                        conv = enc_new(name, &opar);
1.57      ratchov  1128:                        opar.bps = d->ipar.bps;
                   1129:                        opar.bits = d->ipar.bits;
                   1130:                        opar.sig = d->ipar.sig;
                   1131:                        opar.le = d->ipar.le;
                   1132:                        opar.msb = d->ipar.msb;
1.9       ratchov  1133:                        aproc_setout(conv, obuf);
1.20      ratchov  1134:                        obuf = abuf_new(nblk * round, &opar);
1.9       ratchov  1135:                        aproc_setin(conv, obuf);
1.8       ratchov  1136:                }
1.48      ratchov  1137:                if (onch > 0 && nch >= onch * 2) {
                   1138:                        conv = join_new(name);
                   1139:                        aproc_setout(conv, obuf);
                   1140:                        opar.cmax = opar.cmin + onch - 1;
                   1141:                        obuf = abuf_new(nblk * round, &opar);
                   1142:                        aproc_setin(conv, obuf);
                   1143:                }
1.57      ratchov  1144:                if (!aparams_eqrate(&opar, &d->ipar)) {
                   1145:                        conv = resamp_new(name, d->round, round);
                   1146:                        opar.rate = d->ipar.rate;
                   1147:                        round = d->round;
1.1       ratchov  1148:                        aproc_setout(conv, obuf);
1.20      ratchov  1149:                        obuf = abuf_new(nblk * round, &opar);
1.1       ratchov  1150:                        aproc_setin(conv, obuf);
                   1151:                }
1.48      ratchov  1152:                if (onch > 0 && nch * 2 <= onch) {
                   1153:                        conv = join_new(name);
                   1154:                        aproc_setout(conv, obuf);
                   1155:                        opar.cmax = opar.cmin + onch - 1;
                   1156:                        obuf = abuf_new(nblk * round, &opar);
                   1157:                        aproc_setin(conv, obuf);
                   1158:                }
1.57      ratchov  1159:                aproc_setout(d->sub, obuf);
1.46      ratchov  1160:                obuf->w.sub.xrun = xrun;
                   1161:        }
                   1162:        if (mode & MODE_MON) {
                   1163:                opar = *sopar;
1.57      ratchov  1164:                round = dev_roundof(d, opar.rate);
                   1165:                nblk = (d->bufsz / d->round + 3) / 4;
1.48      ratchov  1166:                nch = opar.cmax - opar.cmin + 1;
1.57      ratchov  1167:                if (!aparams_eqenc(&opar, &d->opar)) {
1.46      ratchov  1168:                        conv = enc_new(name, &opar);
1.57      ratchov  1169:                        opar.bps = d->opar.bps;
                   1170:                        opar.bits = d->opar.bits;
                   1171:                        opar.sig = d->opar.sig;
                   1172:                        opar.le = d->opar.le;
                   1173:                        opar.msb = d->opar.msb;
1.46      ratchov  1174:                        aproc_setout(conv, obuf);
                   1175:                        obuf = abuf_new(nblk * round, &opar);
                   1176:                        aproc_setin(conv, obuf);
                   1177:                }
1.48      ratchov  1178:                if (onch > 0 && nch >= onch * 2) {
                   1179:                        conv = join_new(name);
                   1180:                        aproc_setout(conv, obuf);
                   1181:                        opar.cmax = opar.cmin + onch - 1;
                   1182:                        obuf = abuf_new(nblk * round, &opar);
                   1183:                        aproc_setin(conv, obuf);
                   1184:                }
1.57      ratchov  1185:                if (!aparams_eqrate(&opar, &d->opar)) {
                   1186:                        conv = resamp_new(name, d->round, round);
                   1187:                        opar.rate = d->opar.rate;
                   1188:                        round = d->round;
1.46      ratchov  1189:                        aproc_setout(conv, obuf);
1.48      ratchov  1190:                        obuf = abuf_new(nblk * round, &opar);
                   1191:                        aproc_setin(conv, obuf);
                   1192:                }
                   1193:                if (onch > 0 && nch * 2 <= onch) {
                   1194:                        conv = join_new(name);
                   1195:                        aproc_setout(conv, obuf);
                   1196:                        opar.cmax = opar.cmin + onch - 1;
1.46      ratchov  1197:                        obuf = abuf_new(nblk * round, &opar);
                   1198:                        aproc_setin(conv, obuf);
                   1199:                }
1.57      ratchov  1200:                aproc_setout(d->submon, obuf);
1.46      ratchov  1201:                obuf->w.sub.xrun = xrun;
1.1       ratchov  1202:        }
                   1203:
                   1204:        /*
1.27      ratchov  1205:         * Sync play to record.
1.1       ratchov  1206:         */
1.46      ratchov  1207:        if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
1.3       ratchov  1208:                ibuf->duplex = obuf;
                   1209:                obuf->duplex = ibuf;
1.13      ratchov  1210:        }
1.57      ratchov  1211:        dev_sync(d, mode, ibuf, obuf);
1.14      ratchov  1212: }
                   1213:
                   1214: /*
1.27      ratchov  1215:  * Change the playback volume of the given stream.
1.14      ratchov  1216:  */
                   1217: void
1.57      ratchov  1218: dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
1.14      ratchov  1219: {
1.39      ratchov  1220: #ifdef DEBUG
                   1221:        if (debug_level >= 3) {
                   1222:                abuf_dbg(ibuf);
                   1223:                dbg_puts(": setting volume to ");
                   1224:                dbg_putu(vol);
                   1225:                dbg_puts("\n");
                   1226:        }
                   1227: #endif
1.57      ratchov  1228:        if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
1.14      ratchov  1229:                return;
1.16      ratchov  1230:        }
1.31      ratchov  1231:        ibuf->r.mix.vol = vol;
1.13      ratchov  1232: }
                   1233:
                   1234: /*
1.27      ratchov  1235:  * Clear buffers of the play and record chains so that when the device
                   1236:  * is started, playback and record start in sync.
1.13      ratchov  1237:  */
                   1238: void
1.57      ratchov  1239: dev_clear(struct dev *d)
1.13      ratchov  1240: {
                   1241:        struct abuf *buf;
                   1242:
1.57      ratchov  1243:        if (APROC_OK(d->mix)) {
1.39      ratchov  1244: #ifdef DEBUG
1.57      ratchov  1245:                if (!LIST_EMPTY(&d->mix->ins)) {
1.69      ratchov  1246:                        dev_dbg(d);
                   1247:                        dbg_puts(": play end not idle, can't clear device\n");
1.39      ratchov  1248:                        dbg_panic();
                   1249:                }
                   1250: #endif
1.57      ratchov  1251:                buf = LIST_FIRST(&d->mix->outs);
1.13      ratchov  1252:                while (buf) {
                   1253:                        abuf_clear(buf);
1.49      ratchov  1254:                        buf = LIST_FIRST(&buf->rproc->outs);
1.13      ratchov  1255:                }
1.57      ratchov  1256:                mix_clear(d->mix);
1.13      ratchov  1257:        }
1.57      ratchov  1258:        if (APROC_OK(d->sub)) {
1.39      ratchov  1259: #ifdef DEBUG
1.57      ratchov  1260:                if (!LIST_EMPTY(&d->sub->outs)) {
1.69      ratchov  1261:                        dev_dbg(d);
                   1262:                        dbg_puts(": record end not idle, can't clear device\n");
1.39      ratchov  1263:                        dbg_panic();
                   1264:                }
                   1265: #endif
1.57      ratchov  1266:                buf = LIST_FIRST(&d->sub->ins);
1.13      ratchov  1267:                while (buf) {
                   1268:                        abuf_clear(buf);
1.49      ratchov  1269:                        buf = LIST_FIRST(&buf->wproc->ins);
1.13      ratchov  1270:                }
1.57      ratchov  1271:                sub_clear(d->sub);
1.40      ratchov  1272:        }
1.57      ratchov  1273:        if (APROC_OK(d->submon)) {
1.46      ratchov  1274: #ifdef DEBUG
1.57      ratchov  1275:                if (!LIST_EMPTY(&d->submon->outs)) {
1.69      ratchov  1276:                        dev_dbg(d);
                   1277:                        dbg_puts(": monitoring end not idle, can't clear device\n");
1.46      ratchov  1278:                        dbg_panic();
                   1279:                }
                   1280: #endif
1.57      ratchov  1281:                buf = LIST_FIRST(&d->submon->ins);
1.46      ratchov  1282:                while (buf) {
                   1283:                        abuf_clear(buf);
1.49      ratchov  1284:                        buf = LIST_FIRST(&buf->wproc->ins);
1.46      ratchov  1285:                }
1.57      ratchov  1286:                sub_clear(d->submon);
                   1287:                mon_clear(d->mon);
1.1       ratchov  1288:        }
1.71      ratchov  1289: }
                   1290:
                   1291: #ifdef DEBUG
                   1292: void
                   1293: dev_slotdbg(struct dev *d, int slot)
                   1294: {
                   1295:        struct ctl_slot *s;
                   1296:
                   1297:        if (slot < 0) {
                   1298:                dbg_puts("none");
                   1299:        } else {
                   1300:                s = d->slot + slot;
                   1301:                dbg_puts(s->name);
                   1302:                dbg_putu(s->unit);
                   1303:                dbg_puts("(");
                   1304:                dbg_putu(s->vol);
                   1305:                dbg_puts(")/");
                   1306:                switch (s->tstate) {
                   1307:                case CTL_OFF:
                   1308:                        dbg_puts("off");
                   1309:                        break;
                   1310:                case CTL_RUN:
                   1311:                        dbg_puts("run");
                   1312:                        break;
                   1313:                case CTL_START:
                   1314:                        dbg_puts("sta");
                   1315:                        break;
                   1316:                case CTL_STOP:
                   1317:                        dbg_puts("stp");
                   1318:                        break;
                   1319:                default:
                   1320:                        dbg_puts("unk");
                   1321:                        break;
                   1322:                }
                   1323:        }
                   1324: }
                   1325: #endif
                   1326:
                   1327: /*
                   1328:  * find the best matching free slot index (ie midi channel).
                   1329:  * return -1, if there are no free slots anymore
                   1330:  */
                   1331: int
                   1332: dev_mkslot(struct dev *d, char *who)
                   1333: {
                   1334:        char *s;
                   1335:        struct ctl_slot *slot;
                   1336:        char name[CTL_NAMEMAX];
1.79      ratchov  1337:        unsigned int i, unit, umap = 0;
                   1338:        unsigned int ser, bestser, bestidx;
1.71      ratchov  1339:
                   1340:        /*
                   1341:         * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
                   1342:         */
                   1343:        for (i = 0, s = who; ; s++) {
                   1344:                if (i == CTL_NAMEMAX - 1 || *s == '\0') {
                   1345:                        name[i] = '\0';
                   1346:                        break;
                   1347:                } else if (*s >= 'A' && *s <= 'Z') {
                   1348:                        name[i++] = *s + 'a' - 'A';
                   1349:                } else if (*s >= 'a' && *s <= 'z')
                   1350:                        name[i++] = *s;
                   1351:        }
                   1352:        if (i == 0)
                   1353:                strlcpy(name, "noname", CTL_NAMEMAX);
                   1354:
                   1355:        /*
                   1356:         * find the instance number of the control name
                   1357:         */
                   1358:        for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
                   1359:                if (slot->ops == NULL)
                   1360:                        continue;
                   1361:                if (strcmp(slot->name, name) == 0)
1.80      ratchov  1362:                        umap |= (1 << slot->unit);
1.71      ratchov  1363:        }
                   1364:        for (unit = 0; ; unit++) {
                   1365:                if (unit == CTL_NSLOT) {
                   1366: #ifdef DEBUG
                   1367:                        if (debug_level >= 1) {
                   1368:                                dbg_puts(name);
                   1369:                                dbg_puts(": too many instances\n");
                   1370:                        }
                   1371: #endif
                   1372:                        return -1;
                   1373:                }
                   1374:                if ((umap & (1 << unit)) == 0)
                   1375:                        break;
                   1376:        }
                   1377:
                   1378:        /*
                   1379:         * find a free controller slot with the same name/unit
                   1380:         */
                   1381:        for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
                   1382:                if (slot->ops == NULL &&
                   1383:                    strcmp(slot->name, name) == 0 &&
                   1384:                    slot->unit == unit) {
                   1385: #ifdef DEBUG
                   1386:                        if (debug_level >= 3) {
                   1387:                                dbg_puts(name);
                   1388:                                dbg_putu(unit);
                   1389:                                dbg_puts(": found slot ");
                   1390:                                dbg_putu(i);
                   1391:                                dbg_puts("\n");
                   1392:                        }
                   1393: #endif
                   1394:                        return i;
                   1395:                }
                   1396:        }
                   1397:
                   1398:        /*
                   1399:         * couldn't find a matching slot, pick oldest free slot
                   1400:         * and set its name/unit
                   1401:         */
                   1402:        bestser = 0;
                   1403:        bestidx = CTL_NSLOT;
                   1404:        for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
                   1405:                if (slot->ops != NULL)
                   1406:                        continue;
                   1407:                ser = d->serial - slot->serial;
                   1408:                if (ser > bestser) {
                   1409:                        bestser = ser;
                   1410:                        bestidx = i;
                   1411:                }
                   1412:        }
                   1413:        if (bestidx == CTL_NSLOT) {
                   1414: #ifdef DEBUG
                   1415:                if (debug_level >= 1) {
                   1416:                        dbg_puts(name);
                   1417:                        dbg_putu(unit);
                   1418:                        dbg_puts(": out of mixer slots\n");
                   1419:                }
                   1420: #endif
                   1421:                return -1;
                   1422:        }
                   1423:        slot = d->slot + bestidx;
                   1424:        if (slot->name[0] != '\0')
                   1425:                slot->vol = MIDI_MAXCTL;
                   1426:        strlcpy(slot->name, name, CTL_NAMEMAX);
                   1427:        slot->serial = d->serial++;
                   1428:        slot->unit = unit;
                   1429: #ifdef DEBUG
                   1430:        if (debug_level >= 3) {
                   1431:                dbg_puts(name);
                   1432:                dbg_putu(unit);
                   1433:                dbg_puts(": overwritten slot ");
                   1434:                dbg_putu(bestidx);
                   1435:                dbg_puts("\n");
                   1436:        }
                   1437: #endif
                   1438:        return bestidx;
                   1439: }
                   1440:
                   1441: /*
                   1442:  * allocate a new slot and register the given call-backs
                   1443:  */
                   1444: int
                   1445: dev_slotnew(struct dev *d, char *who, struct ctl_ops *ops, void *arg, int mmc)
                   1446: {
                   1447:        int slot;
                   1448:        struct ctl_slot *s;
                   1449:
                   1450:        slot = dev_mkslot(d, who);
                   1451:        if (slot < 0)
                   1452:                return -1;
                   1453:
                   1454:        s = d->slot + slot;
                   1455:        s->ops = ops;
                   1456:        s->arg = arg;
                   1457:        s->tstate = mmc ? CTL_STOP : CTL_OFF;
                   1458:        s->ops->vol(s->arg, s->vol);
                   1459:
                   1460:        if (APROC_OK(d->midi)) {
1.73      ratchov  1461:                midi_send_slot(d->midi, slot);
                   1462:                midi_send_vol(d->midi, slot, s->vol);
                   1463:                midi_flush(d->midi);
1.71      ratchov  1464:        } else {
                   1465: #ifdef DEBUG
                   1466:                if (debug_level >= 2) {
                   1467:                        dev_slotdbg(d, slot);
                   1468:                        dbg_puts(": MIDI control not available\n");
                   1469:                }
                   1470: #endif
                   1471:        }
                   1472:        return slot;
                   1473: }
                   1474:
                   1475: /*
                   1476:  * release the given slot
                   1477:  */
                   1478: void
                   1479: dev_slotdel(struct dev *d, int slot)
                   1480: {
                   1481:        struct ctl_slot *s;
                   1482:
                   1483:        s = d->slot + slot;
                   1484:        s->ops = NULL;
                   1485: }
                   1486:
                   1487: /*
                   1488:  * notifty the mixer that volume changed, called by whom allocad the slot using
                   1489:  * ctl_slotnew(). Note: it doesn't make sens to call this from within the
                   1490:  * call-back.
                   1491:  *
                   1492:  * XXX: set actual volume here and use only this interface. Now, this
                   1493:  *     can work because all streams have a slot
                   1494:  */
                   1495: void
1.79      ratchov  1496: dev_slotvol(struct dev *d, int slot, unsigned int vol)
1.71      ratchov  1497: {
                   1498: #ifdef DEBUG
                   1499:        if (debug_level >= 3) {
                   1500:                dev_slotdbg(d, slot);
                   1501:                dbg_puts(": changing volume to ");
                   1502:                dbg_putu(vol);
                   1503:                dbg_puts("\n");
                   1504:        }
                   1505: #endif
                   1506:        d->slot[slot].vol = vol;
1.73      ratchov  1507:        if (APROC_OK(d->midi)) {
                   1508:                midi_send_vol(d->midi, slot, vol);
                   1509:                midi_flush(d->midi);
1.71      ratchov  1510:        }
                   1511: }
                   1512:
                   1513: /*
                   1514:  * check that all clients controlled by MMC are ready to start,
                   1515:  * if so, start them all but the caller
                   1516:  */
                   1517: int
                   1518: dev_try(struct dev *d, int slot)
                   1519: {
1.79      ratchov  1520:        unsigned int i;
1.71      ratchov  1521:        struct ctl_slot *s;
                   1522:
                   1523:        if (d->tstate != CTL_START) {
                   1524: #ifdef DEBUG
                   1525:                if (debug_level >= 3) {
                   1526:                        dev_slotdbg(d, slot);
1.85    ! ratchov  1527:                        dbg_puts(": server not started, delayed\n");
1.71      ratchov  1528:                }
                   1529: #endif
                   1530:                return 0;
                   1531:        }
                   1532:        for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
                   1533:                if (!s->ops || i == slot)
                   1534:                        continue;
                   1535:                if (s->tstate != CTL_OFF && s->tstate != CTL_START) {
                   1536: #ifdef DEBUG
                   1537:                        if (debug_level >= 3) {
                   1538:                                dev_slotdbg(d, i);
                   1539:                                dbg_puts(": not ready, server delayed\n");
                   1540:                        }
                   1541: #endif
                   1542:                        return 0;
                   1543:                }
                   1544:        }
                   1545:        for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
                   1546:                if (!s->ops || i == slot)
                   1547:                        continue;
                   1548:                if (s->tstate == CTL_START) {
                   1549: #ifdef DEBUG
                   1550:                        if (debug_level >= 3) {
                   1551:                                dev_slotdbg(d, i);
                   1552:                                dbg_puts(": started\n");
                   1553:                        }
                   1554: #endif
                   1555:                        s->tstate = CTL_RUN;
                   1556:                        s->ops->start(s->arg);
                   1557:                }
                   1558:        }
                   1559:        if (slot >= 0)
                   1560:                d->slot[slot].tstate = CTL_RUN;
                   1561:        d->tstate = CTL_RUN;
1.73      ratchov  1562:        if (APROC_OK(d->midi)) {
                   1563:                midi_send_full(d->midi,
                   1564:                    d->origin, d->rate, d->round, dev_getpos(d));
                   1565:                midi_flush(d->midi);
                   1566:        }
1.71      ratchov  1567:        dev_wakeup(d);
                   1568:        return 1;
                   1569: }
                   1570:
                   1571: /*
                   1572:  * notify the MMC layer that the stream is attempting
                   1573:  * to start. If other streams are not ready, 0 is returned meaning
                   1574:  * that the stream should wait. If other streams are ready, they
                   1575:  * are started, and the caller should start immediately.
                   1576:  */
                   1577: int
                   1578: dev_slotstart(struct dev *d, int slot)
                   1579: {
                   1580:        struct ctl_slot *s = d->slot + slot;
                   1581:
                   1582:        if (s->tstate == CTL_OFF || d->tstate == CTL_OFF)
                   1583:                return 1;
                   1584:
                   1585:        /*
                   1586:         * if the server already started (the client missed the
                   1587:         * start rendez-vous) or the server is stopped, then
                   1588:         * tag the client as ``wanting to start''
                   1589:         */
                   1590:        s->tstate = CTL_START;
                   1591:        return dev_try(d, slot);
                   1592: }
                   1593:
                   1594: /*
                   1595:  * notify the MMC layer that the stream no longer is trying to
                   1596:  * start (or that it just stopped), meaning that its ``start'' call-back
                   1597:  * shouldn't be called anymore
                   1598:  */
                   1599: void
                   1600: dev_slotstop(struct dev *d, int slot)
                   1601: {
                   1602:        struct ctl_slot *s = d->slot + slot;
                   1603:
                   1604:        /*
                   1605:         * tag the stream as not trying to start,
                   1606:         * unless MMC is turned off
                   1607:         */
                   1608:        if (s->tstate != CTL_OFF)
                   1609:                s->tstate = CTL_STOP;
                   1610: }
                   1611:
                   1612: /*
                   1613:  * start all slots simultaneously
                   1614:  */
                   1615: void
                   1616: dev_mmcstart(struct dev *d)
                   1617: {
                   1618:        if (d->tstate == CTL_STOP) {
                   1619:                d->tstate = CTL_START;
                   1620:                (void)dev_try(d, -1);
                   1621: #ifdef DEBUG
                   1622:        } else {
                   1623:                if (debug_level >= 3) {
                   1624:                        dev_dbg(d);
                   1625:                        dbg_puts(": ignoring mmc start\n");
                   1626:                }
                   1627: #endif
                   1628:        }
                   1629: }
                   1630:
                   1631: /*
                   1632:  * stop all slots simultaneously
                   1633:  */
                   1634: void
                   1635: dev_mmcstop(struct dev *d)
                   1636: {
1.79      ratchov  1637:        unsigned int i;
1.71      ratchov  1638:        struct ctl_slot *s;
                   1639:
                   1640:        switch (d->tstate) {
                   1641:        case CTL_START:
                   1642:                d->tstate = CTL_STOP;
                   1643:                return;
                   1644:        case CTL_RUN:
                   1645:                d->tstate = CTL_STOP;
                   1646:                break;
                   1647:        default:
                   1648: #ifdef DEBUG
                   1649:                if (debug_level >= 3) {
                   1650:                        dev_dbg(d);
                   1651:                        dbg_puts(": ignored mmc stop\n");
                   1652:                }
                   1653: #endif
                   1654:                return;
                   1655:        }
                   1656:        for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
                   1657:                if (!s->ops)
                   1658:                        continue;
                   1659:                if (s->tstate == CTL_RUN) {
                   1660: #ifdef DEBUG
                   1661:                        if (debug_level >= 3) {
                   1662:                                dev_slotdbg(d, i);
                   1663:                                dbg_puts(": requested to stop\n");
                   1664:                        }
                   1665: #endif
                   1666:                        s->ops->stop(s->arg);
                   1667:                }
                   1668:        }
                   1669: }
                   1670:
                   1671: /*
                   1672:  * relocate all slots simultaneously
                   1673:  */
                   1674: void
1.79      ratchov  1675: dev_loc(struct dev *d, unsigned int origin)
1.71      ratchov  1676: {
1.79      ratchov  1677:        unsigned int i;
1.71      ratchov  1678:        struct ctl_slot *s;
                   1679:
                   1680: #ifdef DEBUG
                   1681:        if (debug_level >= 2) {
                   1682:                dbg_puts("server relocated to ");
                   1683:                dbg_putu(origin);
                   1684:                dbg_puts("\n");
                   1685:        }
                   1686: #endif
                   1687:        if (d->tstate == CTL_RUN)
                   1688:                dev_mmcstop(d);
                   1689:        d->origin = origin;
                   1690:        for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
                   1691:                if (!s->ops)
                   1692:                        continue;
                   1693:                s->ops->loc(s->arg, d->origin);
                   1694:        }
                   1695:        if (d->tstate == CTL_RUN)
                   1696:                dev_mmcstart(d);
                   1697: }
                   1698:
                   1699: /*
                   1700:  * called at every clock tick by the mixer, delta is positive, unless
                   1701:  * there's an overrun/underrun
                   1702:  */
                   1703: void
                   1704: dev_onmove(void *arg, int delta)
                   1705: {
                   1706:        struct dev *d = (struct dev *)arg;
                   1707:
                   1708:        /*
                   1709:         * don't send ticks before the start signal
                   1710:         */
                   1711:        if (d->tstate != CTL_RUN)
                   1712:                return;
1.73      ratchov  1713:        if (APROC_OK(d->midi)) {
                   1714:                midi_send_qfr(d->midi, d->rate, delta);
1.77      ratchov  1715:                midi_flush(d->midi);
                   1716:        }
                   1717: }
                   1718:
                   1719: void
1.79      ratchov  1720: dev_master(struct dev *d, unsigned int master)
1.77      ratchov  1721: {
                   1722: #ifdef DEBUG
                   1723:        if (debug_level >= 3) {
                   1724:                dev_dbg(d);
                   1725:                dbg_puts(": changing master volume to ");
                   1726:                dbg_putu(master);
                   1727:                dbg_puts("\n");
                   1728:        }
                   1729: #endif
                   1730:        d->master = master;
                   1731:        if (APROC_OK(d->mix)) {
                   1732:                d->mix->u.mix.master = MIDI_TO_ADATA(master);
                   1733:                mix_setmaster(d->mix);
1.73      ratchov  1734:        }
1.1       ratchov  1735: }