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

Annotation of src/usr.bin/aucat/aucat.c, Revision 1.84

1.84    ! ratchov     1: /*     $OpenBSD: aucat.c,v 1.83 2010/04/06 20:07:01 ratchov Exp $      */
1.1       kstailey    2: /*
1.15      ratchov     3:  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
1.1       kstailey    4:  *
1.15      ratchov     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 <sys/param.h>
                     18: #include <sys/queue.h>
1.55      ratchov    19: #include <sys/stat.h>
1.62      ratchov    20: #include <sys/types.h>
1.13      uwe        21:
1.15      ratchov    22: #include <err.h>
1.55      ratchov    23: #include <errno.h>
1.1       kstailey   24: #include <fcntl.h>
1.55      ratchov    25: #include <limits.h>
1.15      ratchov    26: #include <signal.h>
1.1       kstailey   27: #include <stdio.h>
1.4       millert    28: #include <stdlib.h>
1.8       david      29: #include <string.h>
1.1       kstailey   30: #include <unistd.h>
1.15      ratchov    31: #include <varargs.h>
1.1       kstailey   32:
1.62      ratchov    33: #include "abuf.h"
1.15      ratchov    34: #include "aparams.h"
                     35: #include "aproc.h"
1.62      ratchov    36: #include "conf.h"
                     37: #include "dev.h"
1.28      ratchov    38: #include "listen.h"
1.61      ratchov    39: #include "midi.h"
                     40: #include "opt.h"
1.62      ratchov    41: #include "wav.h"
1.78      ratchov    42: #ifdef DEBUG
                     43: #include "dbg.h"
                     44: #endif
1.11      jaredy     45:
1.61      ratchov    46: #define PROG_AUCAT     "aucat"
                     47: #define PROG_MIDICAT   "midicat"
                     48:
1.78      ratchov    49: #ifdef DEBUG
                     50: int debug_level = 0;
                     51: #endif
1.28      ratchov    52: volatile int quit_flag = 0;
1.7       deraadt    53:
1.28      ratchov    54: /*
                     55:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                     56:  * that means that the last SIGINT was not handled, because the process
1.62      ratchov    57:  * is blocked somewhere, so exit.
1.28      ratchov    58:  */
                     59: void
                     60: sigint(int s)
                     61: {
                     62:        if (quit_flag)
                     63:                _exit(1);
                     64:        quit_flag = 1;
                     65: }
1.22      ratchov    66:
1.78      ratchov    67: #ifdef DEBUG
                     68: /*
                     69:  * Increase debug level on SIGUSR1.
                     70:  */
                     71: void
                     72: sigusr1(int s)
                     73: {
                     74:        if (debug_level < 4)
                     75:                debug_level++;
                     76: }
                     77:
                     78: /*
                     79:  * Decrease debug level on SIGUSR2.
                     80:  */
                     81: void
                     82: sigusr2(int s)
                     83: {
                     84:        if (debug_level > 0)
                     85:                debug_level--;
                     86: }
                     87: #endif
1.15      ratchov    88:
                     89: void
                     90: opt_ch(struct aparams *par)
                     91: {
1.76      ratchov    92:        char *next, *end;
                     93:        long cmin, cmax;
1.13      uwe        94:
1.76      ratchov    95:        errno = 0;
                     96:        cmin = strtol(optarg, &next, 10);
                     97:        if (next == optarg || *next != ':')
                     98:                goto failed;
                     99:        if (errno == ERANGE && (cmin == LONG_MIN || cmin == LONG_MAX))
                    100:                goto failed;
                    101:        cmax = strtol(++next, &end, 10);
                    102:        if (end == next || *end != '\0')
                    103:                goto failed;
                    104:        if (errno == ERANGE && (cmax == LONG_MIN || cmax == LONG_MAX))
                    105:                goto failed;
                    106:        if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
                    107:                goto failed;
                    108:        par->cmin = cmin;
                    109:        par->cmax = cmax;
                    110:        return;
                    111: failed:
                    112:        errx(1, "%s: bad channel range", optarg);
1.15      ratchov   113: }
1.13      uwe       114:
1.15      ratchov   115: void
                    116: opt_enc(struct aparams *par)
                    117: {
1.28      ratchov   118:        int len;
                    119:
                    120:        len = aparams_strtoenc(par, optarg);
                    121:        if (len == 0 || optarg[len] != '\0')
                    122:                errx(1, "%s: bad encoding", optarg);
1.15      ratchov   123: }
1.4       millert   124:
1.15      ratchov   125: int
                    126: opt_hdr(void)
                    127: {
                    128:        if (strcmp("auto", optarg) == 0)
                    129:                return HDR_AUTO;
                    130:        if (strcmp("raw", optarg) == 0)
                    131:                return HDR_RAW;
                    132:        if (strcmp("wav", optarg) == 0)
                    133:                return HDR_WAV;
1.35      ratchov   134:        errx(1, "%s: bad header specification", optarg);
1.1       kstailey  135: }
                    136:
1.22      ratchov   137: int
1.74      ratchov   138: opt_mmc(void)
                    139: {
                    140:        if (strcmp("off", optarg) == 0)
                    141:                return 0;
                    142:        if (strcmp("slave", optarg) == 0)
                    143:                return 1;
                    144:        errx(1, "%s: bad MMC mode", optarg);
                    145: }
                    146:
                    147: int
1.84    ! ratchov   148: opt_join(void)
        !           149: {
        !           150:        if (strcmp("off", optarg) == 0)
        !           151:                return 0;
        !           152:        if (strcmp("on", optarg) == 0)
        !           153:                return 1;
        !           154:        errx(1, "%s: bad join/expand setting", optarg);
        !           155: }
        !           156:
        !           157: int
1.22      ratchov   158: opt_xrun(void)
                    159: {
                    160:        if (strcmp("ignore", optarg) == 0)
                    161:                return XRUN_IGNORE;
                    162:        if (strcmp("sync", optarg) == 0)
                    163:                return XRUN_SYNC;
                    164:        if (strcmp("error", optarg) == 0)
                    165:                return XRUN_ERROR;
1.73      ratchov   166:        errx(1, "%s: bad underrun/overrun policy", optarg);
1.22      ratchov   167: }
                    168:
1.83      ratchov   169: unsigned
1.43      ratchov   170: opt_mode(void)
                    171: {
1.83      ratchov   172:        unsigned mode = 0;
                    173:        char *p = optarg;
                    174:        size_t len;
                    175:
                    176:        for (p = optarg; *p != NULL; p++) {
                    177:                len = strcspn(p, ",");
                    178:                if (strncmp("play", p, len) == 0) {
                    179:                        mode |= MODE_PLAY;
                    180:                } else if (strncmp("rec", p, len) == 0) {
                    181:                        mode |= MODE_REC;
                    182:                } else if (strncmp("mon", p, len) == 0) {
                    183:                        mode |= MODE_MON;
                    184:                } else if (strncmp("duplex", p, len) == 0) {
                    185:                        /* XXX: backward compat, remove this */
                    186:                        mode |= MODE_REC | MODE_PLAY;
                    187:                } else
                    188:                        errx(1, "%s: bad mode", optarg);
                    189:                p += len;
                    190:                if (*p == '\0')
                    191:                        break;
                    192:        }
                    193:        if (mode == 0)
                    194:                errx(1, "empty mode");
                    195:        return mode;
1.43      ratchov   196: }
                    197:
1.13      uwe       198: /*
1.42      ratchov   199:  * Arguments of -i, -o and -s options are stored in a list.
1.13      uwe       200:  */
1.15      ratchov   201: struct farg {
                    202:        SLIST_ENTRY(farg) entry;
1.42      ratchov   203:        struct aparams ipar;    /* input (read) parameters */
                    204:        struct aparams opar;    /* output (write) parameters */
1.15      ratchov   205:        unsigned vol;           /* last requested volume */
                    206:        char *name;             /* optarg pointer (no need to copy it */
                    207:        int hdr;                /* header format */
1.22      ratchov   208:        int xrun;               /* overrun/underrun policy */
1.74      ratchov   209:        int mmc;                /* MMC mode */
1.84    ! ratchov   210:        int join;               /* join/expand enabled */
1.83      ratchov   211:        unsigned mode;
1.15      ratchov   212: };
1.13      uwe       213:
1.15      ratchov   214: SLIST_HEAD(farglist, farg);
1.13      uwe       215:
1.15      ratchov   216: /*
                    217:  * Add a farg entry to the given list, corresponding
                    218:  * to the given file name.
                    219:  */
                    220: void
1.52      ratchov   221: farg_add(struct farglist *list,
1.42      ratchov   222:     struct aparams *ipar, struct aparams *opar, unsigned vol,
1.84    ! ratchov   223:     int hdr, int xrun, int mmc, int join, unsigned mode, char *name)
1.15      ratchov   224: {
                    225:        struct farg *fa;
                    226:        size_t namelen;
1.52      ratchov   227:
1.15      ratchov   228:        fa = malloc(sizeof(struct farg));
                    229:        if (fa == NULL)
1.77      ratchov   230:                err(1, "%s", name);
1.15      ratchov   231:
                    232:        if (hdr == HDR_AUTO) {
1.77      ratchov   233:                if (name != NULL && (namelen = strlen(name)) >= 4 &&
                    234:                    strcasecmp(name + namelen - 4, ".wav") == 0) {
1.15      ratchov   235:                        fa->hdr = HDR_WAV;
                    236:                } else {
                    237:                        fa->hdr = HDR_RAW;
1.13      uwe       238:                }
1.52      ratchov   239:        } else
1.15      ratchov   240:                fa->hdr = hdr;
1.83      ratchov   241:        if (mmc && xrun == XRUN_IGNORE)
                    242:                xrun = XRUN_SYNC;
1.22      ratchov   243:        fa->xrun = xrun;
1.42      ratchov   244:        fa->ipar = *ipar;
                    245:        fa->opar = *opar;
1.15      ratchov   246:        fa->vol = vol;
1.77      ratchov   247:        fa->name = name;
1.74      ratchov   248:        fa->mmc = mmc;
1.84    ! ratchov   249:        fa->join = join;
1.83      ratchov   250:        fa->mode = mode;
1.15      ratchov   251:        SLIST_INSERT_HEAD(list, fa, entry);
                    252: }
1.13      uwe       253:
1.61      ratchov   254: void
                    255: setsig(void)
                    256: {
                    257:        struct sigaction sa;
                    258:
                    259:        quit_flag = 0;
                    260:        sigfillset(&sa.sa_mask);
                    261:        sa.sa_flags = SA_RESTART;
                    262:        sa.sa_handler = sigint;
                    263:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   264:                err(1, "sigaction(int) failed");
1.61      ratchov   265:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   266:                err(1, "sigaction(term) failed");
1.61      ratchov   267:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   268:                err(1, "sigaction(hup) failed");
1.78      ratchov   269: #ifdef DEBUG
                    270:        sa.sa_handler = sigusr1;
                    271:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    272:                err(1, "sigaction(usr1) failed");
                    273:        sa.sa_handler = sigusr2;
                    274:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    275:                err(1, "sigaction(usr2) failed1n");
                    276: #endif
1.61      ratchov   277: }
                    278:
                    279: void
                    280: unsetsig(void)
                    281: {
                    282:        struct sigaction sa;
                    283:
                    284:        sigfillset(&sa.sa_mask);
                    285:        sa.sa_flags = SA_RESTART;
                    286:        sa.sa_handler = SIG_DFL;
1.78      ratchov   287: #ifdef DEBUG
                    288:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    289:                err(1, "unsetsig(usr2): sigaction failed");
                    290:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    291:                err(1, "unsetsig(usr1): sigaction failed");
                    292: #endif
1.61      ratchov   293:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   294:                err(1, "unsetsig(hup): sigaction failed\n");
1.61      ratchov   295:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   296:                err(1, "unsetsig(term): sigaction failed\n");
1.61      ratchov   297:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   298:                err(1, "unsetsig(int): sigaction failed\n");
1.61      ratchov   299: }
                    300:
                    301: void
                    302: getbasepath(char *base, size_t size)
                    303: {
                    304:        uid_t uid;
                    305:        struct stat sb;
                    306:
                    307:        uid = geteuid();
                    308:        snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
                    309:        if (mkdir(base, 0700) < 0) {
                    310:                if (errno != EEXIST)
                    311:                        err(1, "mkdir(\"%s\")", base);
                    312:        }
                    313:        if (stat(base, &sb) < 0)
                    314:                err(1, "stat(\"%s\")", base);
                    315:        if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
                    316:                errx(1, "%s has wrong permissions", base);
                    317: }
                    318:
                    319: void
1.83      ratchov   320: stopall(char *base)
                    321: {
                    322:        struct file *f;
                    323:
                    324:   restart:
                    325:        LIST_FOREACH(f, &file_list, entry) {
                    326:                /*
                    327:                 * skip connected streams (handled by dev_done())
                    328:                 */
                    329:                if (APROC_OK(dev_mix) && f->rproc &&
                    330:                    aproc_depend(dev_mix, f->rproc))
                    331:                        continue;
                    332:                if (APROC_OK(dev_sub) && f->wproc &&
                    333:                    aproc_depend(f->wproc, dev_sub))
                    334:                        continue;
                    335:                if (APROC_OK(dev_midi)) {
                    336:                        if (f->rproc && aproc_depend(dev_midi, f->rproc))
                    337:                                continue;
                    338:                        if (f->wproc && aproc_depend(f->wproc, dev_midi))
                    339:                                continue;
                    340:                }
                    341:                /*
                    342:                 * kill anything else
                    343:                 */
                    344:                file_close(f);
                    345:                goto restart;
                    346:        }
                    347: }
                    348:
                    349: void
1.61      ratchov   350: aucat_usage(void)
                    351: {
1.69      ratchov   352:        (void)fputs("usage: " PROG_AUCAT " [-dlnu] [-b nframes] "
1.83      ratchov   353:            "[-C min:max] [-c min:max] [-e enc]\n\t"
1.84    ! ratchov   354:            "[-f device] [-h fmt] [-i file] [-j flag] [-m mode]"
1.83      ratchov   355:            "[-o file] [-q device]\n\t"
                    356:            "[-r rate] [-s name] [-t mode] [-U unit] "
                    357:            "[-v volume] [-x policy]\n\t"
                    358:            "[-z nframes]\n",
1.61      ratchov   359:            stderr);
                    360: }
                    361:
1.1       kstailey  362: int
1.61      ratchov   363: aucat_main(int argc, char **argv)
1.1       kstailey  364: {
1.83      ratchov   365:        int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, unit;
1.15      ratchov   366:        struct farg *fa;
1.83      ratchov   367:        struct farglist ifiles, ofiles, sfiles, qfiles;
1.26      ratchov   368:        struct aparams ipar, opar, dipar, dopar;
1.77      ratchov   369:        char base[PATH_MAX], path[PATH_MAX], *file;
1.74      ratchov   370:        unsigned bufsz, round, mode;
1.61      ratchov   371:        char *devpath;
1.76      ratchov   372:        const char *str;
1.40      ratchov   373:        unsigned volctl;
1.84    ! ratchov   374:        int mmc, autostart, join;
1.19      ratchov   375:
1.15      ratchov   376:        aparams_init(&ipar, 0, 1, 44100);
                    377:        aparams_init(&opar, 0, 1, 44100);
1.26      ratchov   378:        u_flag = 0;
1.69      ratchov   379:        d_flag = 0;
1.28      ratchov   380:        l_flag = 0;
1.51      ratchov   381:        n_flag = 0;
1.61      ratchov   382:        unit = -1;
1.74      ratchov   383:        mmc = 0;
1.15      ratchov   384:        devpath = NULL;
                    385:        SLIST_INIT(&ifiles);
                    386:        SLIST_INIT(&ofiles);
1.42      ratchov   387:        SLIST_INIT(&sfiles);
1.83      ratchov   388:        SLIST_INIT(&qfiles);
1.28      ratchov   389:        hdr = HDR_AUTO;
                    390:        xrun = XRUN_IGNORE;
1.40      ratchov   391:        volctl = MIDI_MAXCTL;
1.83      ratchov   392:        mode = MODE_PLAY | MODE_REC;
1.74      ratchov   393:        bufsz = 0;
                    394:        round = 0;
1.83      ratchov   395:        autostart = 1;
1.84    ! ratchov   396:        join = 1;
1.15      ratchov   397:
1.84    ! ratchov   398:        while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:j:z:")) != -1) {
1.15      ratchov   399:                switch (c) {
1.69      ratchov   400:                case 'd':
1.78      ratchov   401: #ifdef DEBUG
                    402:                        if (d_flag)
                    403:                                debug_level++;
                    404: #endif
1.69      ratchov   405:                        d_flag = 1;
                    406:                        break;
1.51      ratchov   407:                case 'n':
                    408:                        n_flag = 1;
                    409:                        break;
1.43      ratchov   410:                case 'm':
                    411:                        mode = opt_mode();
                    412:                        break;
1.15      ratchov   413:                case 'h':
1.28      ratchov   414:                        hdr = opt_hdr();
1.15      ratchov   415:                        break;
1.22      ratchov   416:                case 'x':
1.28      ratchov   417:                        xrun = opt_xrun();
1.22      ratchov   418:                        break;
1.84    ! ratchov   419:                case 'j':
        !           420:                        join = opt_join();
        !           421:                        break;
1.74      ratchov   422:                case 't':
                    423:                        mmc = opt_mmc();
1.83      ratchov   424:                        if (mmc)
                    425:                                autostart = 0;
1.74      ratchov   426:                        break;
1.15      ratchov   427:                case 'c':
                    428:                        opt_ch(&ipar);
                    429:                        break;
                    430:                case 'C':
                    431:                        opt_ch(&opar);
                    432:                        break;
                    433:                case 'e':
                    434:                        opt_enc(&ipar);
1.28      ratchov   435:                        aparams_copyenc(&opar, &ipar);
1.15      ratchov   436:                        break;
                    437:                case 'r':
1.76      ratchov   438:                        ipar.rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
                    439:                        if (str)
                    440:                                errx(1, "%s: rate is %s", optarg, str);
1.28      ratchov   441:                        opar.rate = ipar.rate;
1.15      ratchov   442:                        break;
1.35      ratchov   443:                case 'v':
1.76      ratchov   444:                        volctl = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    445:                        if (str)
                    446:                                errx(1, "%s: volume is %s", optarg, str);
1.35      ratchov   447:                        break;
1.15      ratchov   448:                case 'i':
1.77      ratchov   449:                        file = optarg;
                    450:                        if (strcmp(file, "-") == 0)
                    451:                                file = NULL;
1.42      ratchov   452:                        farg_add(&ifiles, &ipar, &opar, volctl,
1.84    ! ratchov   453:                            hdr, xrun, mmc, join, mode & MODE_PLAY, file);
1.15      ratchov   454:                        break;
                    455:                case 'o':
1.77      ratchov   456:                        file = optarg;
                    457:                        if (strcmp(file, "-") == 0)
                    458:                                file = NULL;
1.42      ratchov   459:                        farg_add(&ofiles, &ipar, &opar, volctl,
1.84    ! ratchov   460:                            hdr, xrun, mmc, join, mode & MODE_RECMASK, file);
1.42      ratchov   461:                        break;
                    462:                case 's':
                    463:                        farg_add(&sfiles, &ipar, &opar, volctl,
1.84    ! ratchov   464:                            hdr, xrun, mmc, join, mode, optarg);
1.83      ratchov   465:                        break;
                    466:                case 'q':
                    467:                        farg_add(&qfiles, &aparams_none, &aparams_none,
1.84    ! ratchov   468:                            0, HDR_RAW, 0, 0, 0, 0, optarg);
1.15      ratchov   469:                        break;
1.4       millert   470:                case 'f':
1.15      ratchov   471:                        if (devpath)
                    472:                                err(1, "only one -f allowed");
                    473:                        devpath = optarg;
1.28      ratchov   474:                        dipar = opar;
                    475:                        dopar = ipar;
1.15      ratchov   476:                        break;
1.28      ratchov   477:                case 'l':
                    478:                        l_flag = 1;
1.83      ratchov   479:                        autostart = 0;
1.17      jakemsr   480:                        break;
1.15      ratchov   481:                case 'u':
                    482:                        u_flag = 1;
1.4       millert   483:                        break;
1.28      ratchov   484:                case 'b':
1.76      ratchov   485:                        bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
                    486:                        if (str)
                    487:                                errx(1, "%s: buffer size is %s", optarg, str);
1.28      ratchov   488:                        break;
1.61      ratchov   489:                case 'U':
1.76      ratchov   490:                        unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    491:                        if (str)
                    492:                                errx(1, "%s: device number is %s", optarg, str);
1.61      ratchov   493:                        break;
1.74      ratchov   494:                case 'z':
1.76      ratchov   495:                        round = strtonum(optarg, 1, SHRT_MAX, &str);
                    496:                        if (str)
                    497:                                errx(1, "%s: block size is %s", optarg, str);
1.74      ratchov   498:                        break;
1.11      jaredy    499:                default:
1.61      ratchov   500:                        aucat_usage();
1.15      ratchov   501:                        exit(1);
1.4       millert   502:                }
                    503:        }
                    504:        argc -= optind;
                    505:        argv += optind;
                    506:
1.15      ratchov   507:        if (!devpath) {
1.47      ratchov   508:                dopar = ipar;
                    509:                dipar = opar;
1.15      ratchov   510:        }
1.28      ratchov   511:        if (!l_flag && SLIST_EMPTY(&ifiles) &&
                    512:            SLIST_EMPTY(&ofiles) && argc > 0) {
1.15      ratchov   513:                /*
                    514:                 * Legacy mode: if no -i or -o options are provided, and
                    515:                 * there are arguments then assume the arguments are files
                    516:                 * to play.
                    517:                 */
                    518:                for (c = 0; c < argc; c++)
                    519:                        if (legacy_play(devpath, argv[c]) != 0) {
1.17      jakemsr   520:                                errx(1, "%s: could not play\n", argv[c]);
1.15      ratchov   521:                        }
                    522:                exit(0);
                    523:        } else if (argc > 0) {
1.61      ratchov   524:                aucat_usage();
1.15      ratchov   525:                exit(1);
                    526:        }
                    527:
1.61      ratchov   528:        if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0))
                    529:                errx(1, "can't use -s or -U without -l");
1.83      ratchov   530:        if (l_flag && (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
                    531:                errx(1, "can't use -l, and -s with -o or -i");
1.51      ratchov   532:        if (n_flag) {
1.83      ratchov   533:                if (devpath != NULL || !SLIST_EMPTY(&qfiles) ||
                    534:                    l_flag || !autostart)
                    535:                        errx(1, "can't use -n with -f, -q, -t or -l");
1.51      ratchov   536:                if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
                    537:                        errx(1, "both -i and -o are required with -n");
                    538:        }
1.15      ratchov   539:
1.46      ratchov   540:        /*
1.62      ratchov   541:         * If there are no sockets paths provided use the default.
1.46      ratchov   542:         */
                    543:        if (l_flag && SLIST_EMPTY(&sfiles)) {
                    544:                farg_add(&sfiles, &dopar, &dipar,
1.84    ! ratchov   545:                    volctl, HDR_RAW, XRUN_IGNORE, mmc, 0, mode, DEFAULT_OPT);
1.46      ratchov   546:        }
                    547:
1.83      ratchov   548:        /*
                    549:         * Check modes and calculate "best" device parameters. Iterate over all
                    550:         * inputs and outputs and find the maximum sample rate and channel
                    551:         * number.
                    552:         */
                    553:        mode = 0;
                    554:        aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
                    555:        aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
                    556:        SLIST_FOREACH(fa, &ifiles, entry) {
                    557:                if (fa->mode == 0)
                    558:                        errx(1, "%s: not in play mode", fa->name);
                    559:                mode |= fa->mode;
                    560:                if (!u_flag)
1.46      ratchov   561:                        aparams_grow(&dopar, &fa->ipar);
1.83      ratchov   562:        }
                    563:        SLIST_FOREACH(fa, &ofiles, entry) {
                    564:                if (fa->mode == 0)
                    565:                        errx(1, "%s: not in rec/mon mode", fa->name);
                    566:                if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON))
                    567:                        errx(1, "%s: can't record and monitor", fa->name);
                    568:                mode |= fa->mode;
                    569:                if (!u_flag)
1.46      ratchov   570:                        aparams_grow(&dipar, &fa->opar);
1.83      ratchov   571:        }
                    572:        SLIST_FOREACH(fa, &sfiles, entry) {
                    573:                if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON))
                    574:                        errx(1, "%s: can't record and monitor", fa->name);
                    575:                mode |= fa->mode;
                    576:                if (!u_flag) {
1.46      ratchov   577:                        aparams_grow(&dopar, &fa->ipar);
                    578:                        aparams_grow(&dipar, &fa->opar);
1.17      jakemsr   579:                }
1.42      ratchov   580:        }
1.83      ratchov   581:
1.74      ratchov   582:        if (!round)
                    583:                round = ((mode & MODE_REC) ? dipar.rate : dopar.rate) / 15;
                    584:        if (!bufsz)
                    585:                bufsz = ((mode & MODE_REC) ? dipar.rate : dopar.rate) * 4 / 15;
1.42      ratchov   586:
1.55      ratchov   587:        if (l_flag) {
1.61      ratchov   588:                getbasepath(base, sizeof(base));
                    589:                if (unit < 0)
                    590:                        unit = 0;
1.55      ratchov   591:        }
1.61      ratchov   592:        setsig();
1.28      ratchov   593:        filelist_init();
1.51      ratchov   594:
1.15      ratchov   595:        /*
1.32      ratchov   596:         * Open the device. Give half of the buffer to the device,
1.62      ratchov   597:         * the other half is for the socket/files.
1.15      ratchov   598:         */
1.51      ratchov   599:        if (n_flag) {
1.83      ratchov   600:                if (mode & MODE_MON)
                    601:                        errx(1, "monitoring not allowed in loopback mode");
1.51      ratchov   602:                dev_loopinit(&dipar, &dopar, bufsz);
                    603:        } else {
1.83      ratchov   604:                if ((mode & MODE_MON) && !(mode & MODE_PLAY))
                    605:                        errx(1, "no playback stream to monitor");
                    606:                if (!dev_init(devpath, mode, &dipar, &dopar, bufsz, round)) {
1.58      ratchov   607:                        errx(1, "%s: can't open device",
                    608:                            devpath ? devpath : "<default>");
                    609:                }
1.51      ratchov   610:        }
1.52      ratchov   611:
1.15      ratchov   612:        /*
                    613:         * Create buffers for all input and output pipes.
                    614:         */
1.83      ratchov   615:        while (!SLIST_EMPTY(&qfiles)) {
                    616:                fa = SLIST_FIRST(&qfiles);
                    617:                SLIST_REMOVE_HEAD(&qfiles, entry);
                    618:                if (!dev_thruadd(fa->name, 1, 1))
                    619:                        errx(1, "%s: can't open device", fa->name);
                    620:                free(fa);
                    621:        }
1.26      ratchov   622:        while (!SLIST_EMPTY(&ifiles)) {
                    623:                fa = SLIST_FIRST(&ifiles);
                    624:                SLIST_REMOVE_HEAD(&ifiles, entry);
1.83      ratchov   625:                if (!wav_new_in(&wav_ops, fa->mode, fa->name,
1.84    ! ratchov   626:                        fa->hdr, &fa->ipar, fa->xrun, fa->vol, fa->mmc,
        !           627:                        fa->join))
1.77      ratchov   628:                        exit(1);
1.26      ratchov   629:                free(fa);
                    630:        }
                    631:        while (!SLIST_EMPTY(&ofiles)) {
                    632:                fa = SLIST_FIRST(&ofiles);
                    633:                SLIST_REMOVE_HEAD(&ofiles, entry);
1.83      ratchov   634:                if (!wav_new_out(&wav_ops, fa->mode, fa->name,
1.84    ! ratchov   635:                        fa->hdr, &fa->opar, fa->xrun, fa->mmc,
        !           636:                        fa->join))
1.42      ratchov   637:                free(fa);
                    638:        }
                    639:        while (!SLIST_EMPTY(&sfiles)) {
                    640:                fa = SLIST_FIRST(&sfiles);
                    641:                SLIST_REMOVE_HEAD(&sfiles, entry);
1.74      ratchov   642:                opt_new(fa->name, &fa->opar, &fa->ipar,
1.84    ! ratchov   643:                    MIDI_TO_ADATA(fa->vol), fa->mmc, fa->join, fa->mode);
1.26      ratchov   644:                free(fa);
1.56      ratchov   645:        }
1.61      ratchov   646:        if (l_flag) {
                    647:                snprintf(path, sizeof(path), "%s/%s%u", base,
                    648:                    DEFAULT_SOFTAUDIO, unit);
                    649:                listen_new(&listen_ops, path);
1.69      ratchov   650:                if (!d_flag && daemon(0, 0) < 0)
1.56      ratchov   651:                        err(1, "daemon");
1.15      ratchov   652:        }
1.83      ratchov   653:        if (autostart) {
                    654:                /*
                    655:                 * inject artificial mmc start
                    656:                 */
                    657:                ctl_start(dev_midi);
                    658:        }
                    659:        if (l_flag)
                    660:                dev_prime();
1.13      uwe       661:
1.15      ratchov   662:        /*
1.62      ratchov   663:         * Loop, start audio.
1.15      ratchov   664:         */
1.28      ratchov   665:        for (;;) {
                    666:                if (quit_flag) {
                    667:                        break;
                    668:                }
1.83      ratchov   669:                if ((APROC_OK(dev_mix) && LIST_EMPTY(&dev_mix->obuflist)) ||
                    670:                    (APROC_OK(dev_sub) && LIST_EMPTY(&dev_sub->ibuflist))) {
1.75      deraadt   671:                        fprintf(stderr, "device disappeared, terminating\n");
1.50      ratchov   672:                        break;
1.38      ratchov   673:                }
1.83      ratchov   674:                if (!l_flag && ctl_idle(dev_midi))
                    675:                        break;
1.50      ratchov   676:                if (!file_poll())
                    677:                        break;
1.83      ratchov   678:                if ((!APROC_OK(dev_mix)    || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
                    679:                    (!APROC_OK(dev_sub)    || dev_sub->u.sub.idle > 2 * dev_bufsz) &&
                    680:                    (!APROC_OK(dev_submon) || dev_submon->u.sub.idle > 2 * dev_bufsz) &&
                    681:                    (!APROC_OK(dev_midi)   || dev_midi->u.ctl.tstate != CTL_RUN)) {
                    682:                        if (dev_pstate == DEV_RUN) {
                    683:                                dev_pstate = DEV_INIT;
1.34      ratchov   684:                                dev_stop();
                    685:                                dev_clear();
1.83      ratchov   686:                                /*
                    687:                                 * priming buffer in non-server mode is not
                    688:                                 * ok, because it will insert silence and
                    689:                                 * break synchronization
                    690:                                 */
                    691:                                if (l_flag)
                    692:                                        dev_prime();
1.34      ratchov   693:                        }
                    694:                }
1.83      ratchov   695:                /*
                    696:                 * move device state machine
                    697:                 * XXX: move this to dev.c
                    698:                 */
                    699:                if (dev_pstate == DEV_START) {
                    700:                        dev_pstate = DEV_RUN;
                    701:                        dev_start();
1.34      ratchov   702:                }
                    703:        }
1.83      ratchov   704:        stopall(base);
                    705:        dev_done();
                    706:        filelist_done();
1.55      ratchov   707:        if (l_flag) {
1.83      ratchov   708:                if (rmdir(base) < 0 && errno != ENOTEMPTY)
1.55      ratchov   709:                        warn("rmdir(\"%s\")", base);
                    710:        }
1.61      ratchov   711:        unsetsig();
                    712:        return 0;
                    713: }
                    714:
                    715: void
                    716: midicat_usage(void)
                    717: {
1.83      ratchov   718:        (void)fputs("usage: " PROG_MIDICAT " [-dl] "
                    719:            "[-i file] [-o file] [-q device] [-U unit]\n",
1.61      ratchov   720:            stderr);
                    721: }
                    722: int
                    723: midicat_main(int argc, char **argv)
                    724: {
1.69      ratchov   725:        int c, d_flag, l_flag, unit, fd;
1.64      ratchov   726:        struct farglist dfiles, ifiles, ofiles;
1.61      ratchov   727:        char base[PATH_MAX], path[PATH_MAX];
1.63      ratchov   728:        struct farg *fa;
1.65      ratchov   729:        struct file *stdx;
1.63      ratchov   730:        struct aproc *p;
1.61      ratchov   731:        struct abuf *buf;
1.76      ratchov   732:        const char *str;
1.61      ratchov   733:
1.69      ratchov   734:        d_flag = 0;
1.61      ratchov   735:        l_flag = 0;
                    736:        unit = -1;
1.63      ratchov   737:        SLIST_INIT(&dfiles);
1.64      ratchov   738:        SLIST_INIT(&ifiles);
                    739:        SLIST_INIT(&ofiles);
1.61      ratchov   740:
1.83      ratchov   741:        while ((c = getopt(argc, argv, "di:o:lf:q:U:")) != -1) {
1.61      ratchov   742:                switch (c) {
1.69      ratchov   743:                case 'd':
1.78      ratchov   744: #ifdef DEBUG
                    745:                        if (d_flag)
                    746:                                debug_level++;
                    747: #endif
1.69      ratchov   748:                        d_flag = 1;
                    749:                        break;
1.61      ratchov   750:                case 'i':
1.64      ratchov   751:                        farg_add(&ifiles, &aparams_none, &aparams_none,
1.84    ! ratchov   752:                            0, HDR_RAW, 0, 0, 0, 0, optarg);
1.61      ratchov   753:                        break;
                    754:                case 'o':
1.64      ratchov   755:                        farg_add(&ofiles, &aparams_none, &aparams_none,
1.84    ! ratchov   756:                            0, HDR_RAW, 0, 0, 0, 0, optarg);
1.61      ratchov   757:                        break;
1.83      ratchov   758:                        /* XXX: backward compat, remove this */
                    759:                case 'f':
                    760:                case 'q':
1.63      ratchov   761:                        farg_add(&dfiles, &aparams_none, &aparams_none,
1.84    ! ratchov   762:                            0, HDR_RAW, 0, 0, 0, 0, optarg);
1.61      ratchov   763:                        break;
                    764:                case 'l':
                    765:                        l_flag = 1;
                    766:                        break;
                    767:                case 'U':
1.76      ratchov   768:                        unit = strtonum(optarg, 0, MIDI_MAXCTL, &str);
                    769:                        if (str)
                    770:                                errx(1, "%s: device number is %s", optarg, str);
1.61      ratchov   771:                        break;
                    772:                default:
                    773:                        midicat_usage();
                    774:                        exit(1);
                    775:                }
                    776:        }
                    777:        argc -= optind;
                    778:        argv += optind;
                    779:
1.64      ratchov   780:        if (argc > 0 || (SLIST_EMPTY(&ifiles) && SLIST_EMPTY(&ofiles) &&
                    781:            !l_flag)) {
1.61      ratchov   782:                midicat_usage();
                    783:                exit(1);
                    784:        }
                    785:        if (!l_flag && unit >= 0)
                    786:                errx(1, "can't use -U without -l");
                    787:        if (l_flag) {
1.64      ratchov   788:                if (!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles))
1.61      ratchov   789:                        errx(1, "can't use -i or -o with -l");
                    790:                getbasepath(base, sizeof(path));
                    791:                if (unit < 0)
                    792:                        unit = 0;
                    793:        }
                    794:        setsig();
                    795:        filelist_init();
                    796:
1.65      ratchov   797:        dev_thruinit();
1.83      ratchov   798:        if (!l_flag && APROC_OK(dev_midi))
1.74      ratchov   799:                dev_midi->flags |= APROC_QUIT;
1.64      ratchov   800:        if ((!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles)) &&
                    801:            SLIST_EMPTY(&dfiles)) {
1.63      ratchov   802:                farg_add(&dfiles, &aparams_none, &aparams_none,
1.84    ! ratchov   803:                    0, HDR_RAW, 0, 0, 0, 0, NULL);
1.63      ratchov   804:        }
                    805:        while (!SLIST_EMPTY(&dfiles)) {
                    806:                fa = SLIST_FIRST(&dfiles);
                    807:                SLIST_REMOVE_HEAD(&dfiles, entry);
1.77      ratchov   808:                if (!dev_thruadd(fa->name,
                    809:                        !SLIST_EMPTY(&ofiles) || l_flag,
                    810:                        !SLIST_EMPTY(&ifiles) || l_flag)) {
                    811:                        errx(1, "%s: can't open device",
                    812:                            fa->name ? fa->name : "<default>");
                    813:                }
1.63      ratchov   814:                free(fa);
                    815:        }
1.61      ratchov   816:        if (l_flag) {
                    817:                snprintf(path, sizeof(path), "%s/%s%u", base,
                    818:                    DEFAULT_MIDITHRU, unit);
                    819:                listen_new(&listen_ops, path);
1.69      ratchov   820:                if (!d_flag && daemon(0, 0) < 0)
1.61      ratchov   821:                        err(1, "daemon");
                    822:        }
1.64      ratchov   823:        while (!SLIST_EMPTY(&ifiles)) {
                    824:                fa = SLIST_FIRST(&ifiles);
                    825:                SLIST_REMOVE_HEAD(&ifiles, entry);
                    826:                if (strcmp(fa->name, "-") == 0) {
1.61      ratchov   827:                        fd = STDIN_FILENO;
                    828:                        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    829:                                warn("stdin");
                    830:                } else {
1.64      ratchov   831:                        fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
1.61      ratchov   832:                        if (fd < 0)
1.64      ratchov   833:                                err(1, "%s", fa->name);
1.61      ratchov   834:                }
1.64      ratchov   835:                stdx = (struct file *)pipe_new(&pipe_ops, fd, fa->name);
1.77      ratchov   836:                p = rfile_new(stdx);
1.64      ratchov   837:                buf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.61      ratchov   838:                aproc_setout(p, buf);
1.65      ratchov   839:                dev_midiattach(buf, NULL);
1.64      ratchov   840:                free(fa);
1.63      ratchov   841:        }
1.64      ratchov   842:        while (!SLIST_EMPTY(&ofiles)) {
1.66      ratchov   843:                fa = SLIST_FIRST(&ofiles);
                    844:                SLIST_REMOVE_HEAD(&ofiles, entry);
1.64      ratchov   845:                if (strcmp(fa->name, "-") == 0) {
1.61      ratchov   846:                        fd = STDOUT_FILENO;
                    847:                        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    848:                                warn("stdout");
                    849:                } else {
1.64      ratchov   850:                        fd = open(fa->name,
1.61      ratchov   851:                            O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                    852:                        if (fd < 0)
1.64      ratchov   853:                                err(1, "%s", fa->name);
1.61      ratchov   854:                }
1.64      ratchov   855:                stdx = (struct file *)pipe_new(&pipe_ops, fd, fa->name);
1.77      ratchov   856:                p = wfile_new(stdx);
1.64      ratchov   857:                buf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.61      ratchov   858:                aproc_setin(p, buf);
1.65      ratchov   859:                dev_midiattach(NULL, buf);
1.64      ratchov   860:                free(fa);
1.63      ratchov   861:        }
1.61      ratchov   862:        /*
                    863:         * loop, start processing
                    864:         */
                    865:        for (;;) {
                    866:                if (quit_flag) {
                    867:                        break;
                    868:                }
                    869:                if (!file_poll())
                    870:                        break;
                    871:        }
1.83      ratchov   872:        stopall(base);
                    873:        dev_done();
                    874:        filelist_done();
1.61      ratchov   875:        if (l_flag) {
1.83      ratchov   876:                if (rmdir(base) < 0 && errno != ENOTEMPTY)
1.61      ratchov   877:                        warn("rmdir(\"%s\")", base);
                    878:        }
                    879:        unsetsig();
1.15      ratchov   880:        return 0;
1.61      ratchov   881: }
                    882:
                    883:
                    884: int
                    885: main(int argc, char **argv)
                    886: {
                    887:        char *prog;
                    888:
                    889:        prog = strrchr(argv[0], '/');
                    890:        if (prog == NULL)
                    891:                prog = argv[0];
                    892:        else
                    893:                prog++;
                    894:        if (strcmp(prog, PROG_AUCAT) == 0) {
                    895:                return aucat_main(argc, argv);
                    896:        } else if (strcmp(prog, PROG_MIDICAT) == 0) {
                    897:                return midicat_main(argc, argv);
                    898:        } else {
                    899:                fprintf(stderr, "%s: can't determine program to run\n", prog);
                    900:        }
                    901:        return 1;
1.1       kstailey  902: }