[BACK]Return to opt.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / sndiod

Annotation of src/usr.bin/sndiod/opt.c, Revision 1.10

1.10    ! ratchov     1: /*     $OpenBSD: opt.c,v 1.9 2021/11/01 14:43:25 ratchov Exp $ */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2011 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:  */
                     17: #include <string.h>
                     18:
                     19: #include "dev.h"
1.7       ratchov    20: #include "midi.h"
1.1       ratchov    21: #include "opt.h"
1.7       ratchov    22: #include "sysex.h"
1.1       ratchov    23: #include "utils.h"
                     24:
1.5       ratchov    25: struct opt *opt_list;
                     26:
1.7       ratchov    27: void opt_midi_imsg(void *, unsigned char *, int);
                     28: void opt_midi_omsg(void *, unsigned char *, int);
                     29: void opt_midi_fill(void *, int);
                     30: void opt_midi_exit(void *);
                     31:
                     32: struct midiops opt_midiops = {
                     33:        opt_midi_imsg,
                     34:        opt_midi_omsg,
                     35:        opt_midi_fill,
                     36:        opt_midi_exit
                     37: };
                     38:
                     39: void
                     40: opt_midi_imsg(void *arg, unsigned char *msg, int len)
                     41: {
                     42: #ifdef DEBUG
                     43:        struct opt *o = arg;
                     44:
                     45:        log_puts(o->name);
                     46:        log_puts(": can't receive midi messages\n");
                     47:        panic();
                     48: #endif
                     49: }
                     50:
                     51: void
                     52: opt_midi_omsg(void *arg, unsigned char *msg, int len)
                     53: {
                     54:        struct opt *o = arg;
                     55:        struct sysex *x;
                     56:        unsigned int fps, chan;
                     57:
                     58:        if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
                     59:                chan = msg[0] & MIDI_CHANMASK;
                     60:                if (chan >= DEV_NSLOT)
                     61:                        return;
1.9       ratchov    62:                if (slot_array[chan].opt != o)
1.7       ratchov    63:                        return;
                     64:                slot_setvol(slot_array + chan, msg[2]);
                     65:                ctl_onval(CTL_SLOT_LEVEL, slot_array + chan, NULL, msg[2]);
                     66:                return;
                     67:        }
                     68:        x = (struct sysex *)msg;
                     69:        if (x->start != SYSEX_START)
                     70:                return;
                     71:        if (len < SYSEX_SIZE(empty))
                     72:                return;
                     73:        switch (x->type) {
                     74:        case SYSEX_TYPE_RT:
                     75:                if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
                     76:                        if (len == SYSEX_SIZE(master)) {
                     77:                                dev_master(o->dev, x->u.master.coarse);
                     78:                                if (o->dev->master_enabled) {
                     79:                                        ctl_onval(CTL_DEV_MASTER, o->dev, NULL,
                     80:                                           x->u.master.coarse);
                     81:                                }
                     82:                        }
                     83:                        return;
                     84:                }
                     85:                if (x->id0 != SYSEX_MMC)
                     86:                        return;
                     87:                switch (x->id1) {
                     88:                case SYSEX_MMC_STOP:
                     89:                        if (len != SYSEX_SIZE(stop))
                     90:                                return;
1.8       ratchov    91:                        if (o->mtc == NULL)
1.7       ratchov    92:                                return;
1.9       ratchov    93:                        mtc_setdev(o->mtc, o->dev);
1.7       ratchov    94:                        if (log_level >= 2) {
                     95:                                log_puts(o->name);
                     96:                                log_puts(": mmc stop\n");
                     97:                        }
1.8       ratchov    98:                        mtc_stop(o->mtc);
1.7       ratchov    99:                        break;
                    100:                case SYSEX_MMC_START:
                    101:                        if (len != SYSEX_SIZE(start))
                    102:                                return;
1.8       ratchov   103:                        if (o->mtc == NULL)
1.7       ratchov   104:                                return;
1.9       ratchov   105:                        mtc_setdev(o->mtc, o->dev);
1.7       ratchov   106:                        if (log_level >= 2) {
                    107:                                log_puts(o->name);
                    108:                                log_puts(": mmc start\n");
                    109:                        }
1.8       ratchov   110:                        mtc_start(o->mtc);
1.7       ratchov   111:                        break;
                    112:                case SYSEX_MMC_LOC:
                    113:                        if (len != SYSEX_SIZE(loc) ||
                    114:                            x->u.loc.len != SYSEX_MMC_LOC_LEN ||
                    115:                            x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
                    116:                                return;
1.8       ratchov   117:                        if (o->mtc == NULL)
1.7       ratchov   118:                                return;
1.9       ratchov   119:                        mtc_setdev(o->mtc, o->dev);
1.7       ratchov   120:                        switch (x->u.loc.hr >> 5) {
                    121:                        case MTC_FPS_24:
                    122:                                fps = 24;
                    123:                                break;
                    124:                        case MTC_FPS_25:
                    125:                                fps = 25;
                    126:                                break;
                    127:                        case MTC_FPS_30:
                    128:                                fps = 30;
                    129:                                break;
                    130:                        default:
1.8       ratchov   131:                                mtc_stop(o->mtc);
1.7       ratchov   132:                                return;
                    133:                        }
1.8       ratchov   134:                        mtc_loc(o->mtc,
1.7       ratchov   135:                            (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
                    136:                             x->u.loc.min * 60 * MTC_SEC +
                    137:                             x->u.loc.sec * MTC_SEC +
                    138:                             x->u.loc.fr * (MTC_SEC / fps));
                    139:                        break;
                    140:                }
                    141:                break;
                    142:        case SYSEX_TYPE_EDU:
                    143:                if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
                    144:                        return;
                    145:                if (len != SYSEX_SIZE(dumpreq))
                    146:                        return;
                    147:                dev_midi_dump(o->dev);
                    148:                break;
                    149:        }
                    150: }
                    151:
                    152: void
                    153: opt_midi_fill(void *arg, int count)
                    154: {
                    155:        /* nothing to do */
                    156: }
                    157:
                    158: void
                    159: opt_midi_exit(void *arg)
                    160: {
                    161:        struct opt *o = arg;
                    162:
                    163:        if (log_level >= 1) {
                    164:                log_puts(o->name);
                    165:                log_puts(": midi end point died\n");
                    166:                panic();
                    167:        }
                    168: }
                    169:
1.1       ratchov   170: /*
                    171:  * create a new audio sub-device "configuration"
                    172:  */
                    173: struct opt *
1.4       ratchov   174: opt_new(struct dev *d, char *name,
1.1       ratchov   175:     int pmin, int pmax, int rmin, int rmax,
                    176:     int maxweight, int mmc, int dup, unsigned int mode)
                    177: {
1.9       ratchov   178:        struct dev *a;
1.6       ratchov   179:        struct opt *o, **po;
                    180:        unsigned int len, num;
1.1       ratchov   181:        char c;
                    182:
1.9       ratchov   183:        if (name == NULL) {
                    184:                name = d->name;
                    185:                len = strlen(name);
                    186:        } else {
                    187:                for (len = 0; name[len] != '\0'; len++) {
                    188:                        if (len == OPT_NAMEMAX) {
                    189:                                log_puts(name);
                    190:                                log_puts(": too long\n");
                    191:                                return NULL;
                    192:                        }
                    193:                        c = name[len];
                    194:                        if ((c < 'a' || c > 'z') &&
                    195:                            (c < 'A' || c > 'Z')) {
                    196:                                log_puts(name);
                    197:                                log_puts(": only alphabetic chars allowed\n");
                    198:                                return NULL;
                    199:                        }
1.1       ratchov   200:                }
                    201:        }
1.6       ratchov   202:        num = 0;
                    203:        for (po = &opt_list; *po != NULL; po = &(*po)->next)
                    204:                num++;
                    205:        if (num >= OPT_NMAX) {
                    206:                log_puts(name);
                    207:                log_puts(": too many opts\n");
                    208:                return NULL;
                    209:        }
1.9       ratchov   210:
                    211:        if (opt_byname(name)) {
1.6       ratchov   212:                log_puts(name);
                    213:                log_puts(": already defined\n");
                    214:                return NULL;
                    215:        }
1.8       ratchov   216:
                    217:        if (mmc) {
                    218:                if (mtc_array[0].dev != NULL && mtc_array[0].dev != d) {
                    219:                        log_puts(name);
                    220:                        log_puts(": MTC already setup for another device\n");
                    221:                        return NULL;
                    222:                }
                    223:                mtc_array[0].dev = d;
                    224:                if (log_level >= 2) {
                    225:                        dev_log(d);
                    226:                        log_puts(": initial MTC source, controlled by MMC\n");
                    227:                }
                    228:        }
                    229:
1.9       ratchov   230:        if (strcmp(d->name, name) == 0)
                    231:                a = d;
                    232:        else {
                    233:                /* circulate to the first "alternate" device (greatest num) */
                    234:                for (a = d; a->alt_next->num > a->num; a = a->alt_next)
                    235:                        ;
                    236:        }
                    237:
1.1       ratchov   238:        o = xmalloc(sizeof(struct opt));
1.6       ratchov   239:        o->num = num;
1.9       ratchov   240:        o->alt_first = o->dev = a;
                    241:        o->refcnt = 0;
1.7       ratchov   242:
                    243:        /*
                    244:         * XXX: below, we allocate a midi input buffer, since we don't
                    245:         *      receive raw midi data, so no need to allocate a input
                    246:         *      ibuf.  Possibly set imsg & fill callbacks to NULL and
                    247:         *      use this to in midi_new() to check if buffers need to be
                    248:         *      allocated
                    249:         */
                    250:        o->midi = midi_new(&opt_midiops, o, MODE_MIDIIN | MODE_MIDIOUT);
                    251:        midi_tag(o->midi, o->num);
                    252:
1.1       ratchov   253:        if (mode & MODE_PLAY) {
                    254:                o->pmin = pmin;
                    255:                o->pmax = pmax;
                    256:        }
                    257:        if (mode & MODE_RECMASK) {
                    258:                o->rmin = rmin;
                    259:                o->rmax = rmax;
                    260:        }
                    261:        o->maxweight = maxweight;
1.8       ratchov   262:        o->mtc = mmc ? &mtc_array[0] : NULL;
1.1       ratchov   263:        o->dup = dup;
                    264:        o->mode = mode;
                    265:        memcpy(o->name, name, len + 1);
1.6       ratchov   266:        o->next = *po;
                    267:        *po = o;
1.1       ratchov   268:        if (log_level >= 2) {
1.4       ratchov   269:                dev_log(d);
1.1       ratchov   270:                log_puts(".");
                    271:                log_puts(o->name);
                    272:                log_puts(":");
                    273:                if (o->mode & MODE_REC) {
                    274:                        log_puts(" rec=");
                    275:                        log_putu(o->rmin);
                    276:                        log_puts(":");
                    277:                        log_putu(o->rmax);
                    278:                }
                    279:                if (o->mode & MODE_PLAY) {
                    280:                        log_puts(" play=");
                    281:                        log_putu(o->pmin);
                    282:                        log_puts(":");
                    283:                        log_putu(o->pmax);
                    284:                        log_puts(" vol=");
                    285:                        log_putu(o->maxweight);
                    286:                }
                    287:                if (o->mode & MODE_MON) {
                    288:                        log_puts(" mon=");
                    289:                        log_putu(o->rmin);
                    290:                        log_puts(":");
                    291:                        log_putu(o->rmax);
                    292:                }
                    293:                if (o->mode & (MODE_RECMASK | MODE_PLAY)) {
1.8       ratchov   294:                        if (o->mtc)
                    295:                                log_puts(" mtc");
1.1       ratchov   296:                        if (o->dup)
                    297:                                log_puts(" dup");
                    298:                }
                    299:                log_puts("\n");
                    300:        }
                    301:        return o;
                    302: }
                    303:
                    304: struct opt *
1.9       ratchov   305: opt_byname(char *name)
1.1       ratchov   306: {
                    307:        struct opt *o;
                    308:
1.5       ratchov   309:        for (o = opt_list; o != NULL; o = o->next) {
1.1       ratchov   310:                if (strcmp(name, o->name) == 0)
                    311:                        return o;
                    312:        }
                    313:        return NULL;
                    314: }
                    315:
1.9       ratchov   316: struct opt *
                    317: opt_bynum(int num)
                    318: {
                    319:        struct opt *o;
                    320:
                    321:        for (o = opt_list; o != NULL; o = o->next) {
                    322:                if (o->num == num)
                    323:                        return o;
                    324:        }
                    325:        return NULL;
                    326: }
                    327:
1.1       ratchov   328: void
1.5       ratchov   329: opt_del(struct opt *o)
1.1       ratchov   330: {
                    331:        struct opt **po;
                    332:
1.5       ratchov   333:        for (po = &opt_list; *po != o; po = &(*po)->next) {
1.1       ratchov   334: #ifdef DEBUG
                    335:                if (*po == NULL) {
                    336:                        log_puts("opt_del: not on list\n");
                    337:                        panic();
                    338:                }
                    339: #endif
                    340:        }
1.7       ratchov   341:        midi_del(o->midi);
1.1       ratchov   342:        *po = o->next;
                    343:        xfree(o);
1.9       ratchov   344: }
                    345:
                    346: void
                    347: opt_init(struct opt *o)
                    348: {
                    349:        struct dev *d;
                    350:
                    351:        if (strcmp(o->name, o->dev->name) != 0) {
                    352:                for (d = dev_list; d != NULL; d = d->next) {
                    353:                        ctl_new(CTL_OPT_DEV, o, d,
                    354:                            CTL_SEL, o->name, "server", -1, "device",
                    355:                            d->name, -1, 1, o->dev == d);
                    356:                }
                    357:        }
                    358: }
                    359:
                    360: void
                    361: opt_done(struct opt *o)
                    362: {
                    363:        struct dev *d;
                    364:
                    365:        if (o->refcnt != 0) {
                    366:                // XXX: all clients are already kicked, so this never happens
                    367:                log_puts(o->name);
                    368:                log_puts(": still has refs\n");
                    369:        }
                    370:        for (d = dev_list; d != NULL; d = d->next)
                    371:                ctl_del(CTL_OPT_DEV, o, d);
                    372: }
                    373:
                    374: /*
                    375:  * Set opt's device, and (if necessary) move clients to
                    376:  * to the new device
                    377:  */
1.10    ! ratchov   378: int
1.9       ratchov   379: opt_setdev(struct opt *o, struct dev *ndev)
                    380: {
                    381:        struct dev *odev;
                    382:        struct ctl *c;
                    383:        struct ctlslot *p;
                    384:        struct slot *s;
                    385:        int i;
                    386:
                    387:        if (!dev_ref(ndev))
1.10    ! ratchov   388:                return 0;
1.9       ratchov   389:
                    390:        odev = o->dev;
                    391:        if (odev == ndev) {
                    392:                dev_unref(ndev);
1.10    ! ratchov   393:                return 1;
1.9       ratchov   394:        }
                    395:
                    396:        /* check if clients can use new device */
                    397:        for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
                    398:                if (s->opt != o)
                    399:                        continue;
                    400:                if (s->ops != NULL && !dev_iscompat(odev, ndev)) {
                    401:                        dev_unref(ndev);
1.10    ! ratchov   402:                        return 0;
1.9       ratchov   403:                }
                    404:        }
                    405:
                    406:        /*
                    407:         * if we're using MMC, move all opts to the new device, mtc_setdev()
                    408:         * will call us back
1.10    ! ratchov   409:         *
        !           410:         * XXX: move this to the end to avoid the recursion
1.9       ratchov   411:         */
                    412:        if (o->mtc != NULL && o->mtc->dev != ndev) {
                    413:                mtc_setdev(o->mtc, ndev);
                    414:                dev_unref(ndev);
1.10    ! ratchov   415:                return 1;
1.9       ratchov   416:        }
                    417:
                    418:        c = ctl_find(CTL_OPT_DEV, o, o->dev);
                    419:        if (c != NULL)
                    420:                c->curval = 0;
                    421:
                    422:        /* detach clients from old device */
                    423:        for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
                    424:                if (s->opt != o)
                    425:                        continue;
                    426:
                    427:                if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
                    428:                        slot_detach(s);
                    429:        }
                    430:
                    431:        o->dev = ndev;
                    432:
                    433:        if (o->refcnt > 0) {
                    434:                dev_unref(odev);
                    435:                dev_ref(o->dev);
                    436:        }
                    437:
                    438:        c = ctl_find(CTL_OPT_DEV, o, o->dev);
                    439:        if (c != NULL) {
                    440:                c->curval = 1;
                    441:                c->val_mask = ~0;
                    442:        }
                    443:
                    444:        /* attach clients to new device */
                    445:        for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
                    446:                if (s->opt != o)
                    447:                        continue;
                    448:
                    449:                if (ndev != odev) {
                    450:                        dev_midi_slotdesc(odev, s);
                    451:                        dev_midi_slotdesc(ndev, s);
                    452:                        dev_midi_vol(ndev, s);
                    453:                }
                    454:
                    455:                c = ctl_find(CTL_SLOT_LEVEL, s, NULL);
                    456:                ctl_update(c);
                    457:
                    458:                if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP) {
                    459:                        slot_initconv(s);
                    460:                        slot_attach(s);
                    461:                }
                    462:        }
                    463:
                    464:        /* move controlling clients to new device */
                    465:        for (p = ctlslot_array, i = 0; i < DEV_NCTLSLOT; i++, p++) {
                    466:                if (p->ops == NULL)
                    467:                        continue;
                    468:                if (p->opt == o)
                    469:                        ctlslot_update(p);
                    470:        }
                    471:
                    472:        dev_unref(ndev);
1.10    ! ratchov   473:        return 1;
1.9       ratchov   474: }
                    475:
                    476: /*
                    477:  * Get a reference to opt's device
                    478:  */
                    479: struct dev *
                    480: opt_ref(struct opt *o)
                    481: {
                    482:        struct dev *d;
                    483:
                    484:        if (o->refcnt == 0) {
                    485:                if (strcmp(o->name, o->dev->name) == 0) {
                    486:                        if (!dev_ref(o->dev))
                    487:                                return NULL;
                    488:                } else {
                    489:                        /* find first working one */
                    490:                        d = o->alt_first;
                    491:                        while (1) {
                    492:                                if (dev_ref(d))
                    493:                                        break;
                    494:                                d = d->alt_next;
                    495:                                if (d == o->alt_first)
                    496:                                        return NULL;
                    497:                        }
                    498:
                    499:                        /* if device changed, move everything to the new one */
                    500:                        if (d != o->dev)
                    501:                                opt_setdev(o, d);
                    502:                }
                    503:        }
                    504:
                    505:        o->refcnt++;
                    506:        return o->dev;
                    507: }
                    508:
                    509: /*
                    510:  * Release opt's device
                    511:  */
                    512: void
                    513: opt_unref(struct opt *o)
                    514: {
                    515:        o->refcnt--;
                    516:        if (o->refcnt == 0)
                    517:                dev_unref(o->dev);
1.1       ratchov   518: }