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

1.73    ! ratchov     1: /*     $OpenBSD: aucat.c,v 1.72 2009/10/10 13:55:37 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"
1.62      ratchov    40: #include "miofile.h"
1.61      ratchov    41: #include "opt.h"
1.62      ratchov    42: #include "wav.h"
1.11      jaredy     43:
1.43      ratchov    44: #define MODE_PLAY      1
                     45: #define MODE_REC       2
                     46:
1.61      ratchov    47: #define PROG_AUCAT     "aucat"
                     48: #define PROG_MIDICAT   "midicat"
                     49:
1.28      ratchov    50: volatile int quit_flag = 0;
1.7       deraadt    51:
1.28      ratchov    52: /*
                     53:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                     54:  * that means that the last SIGINT was not handled, because the process
1.62      ratchov    55:  * is blocked somewhere, so exit.
1.28      ratchov    56:  */
                     57: void
                     58: sigint(int s)
                     59: {
                     60:        if (quit_flag)
                     61:                _exit(1);
                     62:        quit_flag = 1;
                     63: }
1.22      ratchov    64:
1.15      ratchov    65:
                     66: void
                     67: opt_ch(struct aparams *par)
                     68: {
                     69:        if (sscanf(optarg, "%u:%u", &par->cmin, &par->cmax) != 2 ||
1.28      ratchov    70:            par->cmax < par->cmin || par->cmax > NCHAN_MAX - 1)
1.35      ratchov    71:                errx(1, "%s: bad channel range", optarg);
1.15      ratchov    72: }
1.13      uwe        73:
1.15      ratchov    74: void
                     75: opt_rate(struct aparams *par)
                     76: {
                     77:        if (sscanf(optarg, "%u", &par->rate) != 1 ||
                     78:            par->rate < RATE_MIN || par->rate > RATE_MAX)
1.35      ratchov    79:                errx(1, "%s: bad sample rate", optarg);
                     80: }
                     81:
                     82: void
                     83: opt_vol(unsigned *vol)
                     84: {
                     85:        if (sscanf(optarg, "%u", vol) != 1 ||
                     86:            *vol > MIDI_MAXCTL)
                     87:                errx(1, "%s: bad volume", optarg);
1.15      ratchov    88: }
1.13      uwe        89:
1.15      ratchov    90: void
                     91: opt_enc(struct aparams *par)
                     92: {
1.28      ratchov    93:        int len;
                     94:
                     95:        len = aparams_strtoenc(par, optarg);
                     96:        if (len == 0 || optarg[len] != '\0')
                     97:                errx(1, "%s: bad encoding", optarg);
1.15      ratchov    98: }
1.4       millert    99:
1.15      ratchov   100: int
                    101: opt_hdr(void)
                    102: {
                    103:        if (strcmp("auto", optarg) == 0)
                    104:                return HDR_AUTO;
                    105:        if (strcmp("raw", optarg) == 0)
                    106:                return HDR_RAW;
                    107:        if (strcmp("wav", optarg) == 0)
                    108:                return HDR_WAV;
1.35      ratchov   109:        errx(1, "%s: bad header specification", optarg);
1.1       kstailey  110: }
                    111:
1.22      ratchov   112: int
                    113: opt_xrun(void)
                    114: {
                    115:        if (strcmp("ignore", optarg) == 0)
                    116:                return XRUN_IGNORE;
                    117:        if (strcmp("sync", optarg) == 0)
                    118:                return XRUN_SYNC;
                    119:        if (strcmp("error", optarg) == 0)
                    120:                return XRUN_ERROR;
1.73    ! ratchov   121:        errx(1, "%s: bad underrun/overrun policy", optarg);
1.22      ratchov   122: }
                    123:
1.43      ratchov   124: int
                    125: opt_mode(void)
                    126: {
                    127:        if (strcmp("play", optarg) == 0)
                    128:                return MODE_PLAY;
                    129:        if (strcmp("rec", optarg) == 0)
                    130:                return MODE_REC;
                    131:        if (strcmp("duplex", optarg) == 0)
                    132:                return MODE_PLAY | MODE_REC;
                    133:        errx(1, "%s: bad mode", optarg);
                    134: }
                    135:
1.13      uwe       136: /*
1.42      ratchov   137:  * Arguments of -i, -o and -s options are stored in a list.
1.13      uwe       138:  */
1.15      ratchov   139: struct farg {
                    140:        SLIST_ENTRY(farg) entry;
1.42      ratchov   141:        struct aparams ipar;    /* input (read) parameters */
                    142:        struct aparams opar;    /* output (write) parameters */
1.15      ratchov   143:        unsigned vol;           /* last requested volume */
                    144:        char *name;             /* optarg pointer (no need to copy it */
                    145:        int hdr;                /* header format */
1.22      ratchov   146:        int xrun;               /* overrun/underrun policy */
1.15      ratchov   147: };
1.13      uwe       148:
1.15      ratchov   149: SLIST_HEAD(farglist, farg);
1.13      uwe       150:
1.15      ratchov   151: /*
                    152:  * Add a farg entry to the given list, corresponding
                    153:  * to the given file name.
                    154:  */
                    155: void
1.52      ratchov   156: farg_add(struct farglist *list,
1.42      ratchov   157:     struct aparams *ipar, struct aparams *opar, unsigned vol,
                    158:     int hdr, int xrun, char *optarg)
1.15      ratchov   159: {
                    160:        struct farg *fa;
                    161:        size_t namelen;
1.52      ratchov   162:
1.15      ratchov   163:        fa = malloc(sizeof(struct farg));
                    164:        if (fa == NULL)
                    165:                err(1, "%s", optarg);
                    166:
                    167:        if (hdr == HDR_AUTO) {
                    168:                namelen = strlen(optarg);
1.52      ratchov   169:                if (namelen >= 4 &&
1.15      ratchov   170:                    strcasecmp(optarg + namelen - 4, ".wav") == 0) {
                    171:                        fa->hdr = HDR_WAV;
                    172:                } else {
                    173:                        fa->hdr = HDR_RAW;
1.13      uwe       174:                }
1.52      ratchov   175:        } else
1.15      ratchov   176:                fa->hdr = hdr;
1.22      ratchov   177:        fa->xrun = xrun;
1.42      ratchov   178:        fa->ipar = *ipar;
                    179:        fa->opar = *opar;
1.15      ratchov   180:        fa->vol = vol;
                    181:        fa->name = optarg;
                    182:        SLIST_INSERT_HEAD(list, fa, entry);
                    183: }
1.13      uwe       184:
1.15      ratchov   185: /*
                    186:  * Open an input file and setup converter if necessary.
                    187:  */
                    188: void
1.26      ratchov   189: newinput(struct farg *fa)
1.15      ratchov   190: {
                    191:        int fd;
1.28      ratchov   192:        struct wav *f;
1.26      ratchov   193:        struct aproc *proc;
                    194:        struct abuf *buf;
                    195:        unsigned nfr;
1.15      ratchov   196:
                    197:        if (strcmp(fa->name, "-") == 0) {
                    198:                fd = STDIN_FILENO;
                    199:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    200:                        warn("stdin");
                    201:                fa->name = "stdin";
                    202:        } else {
                    203:                fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
                    204:                if (fd < 0)
                    205:                        err(1, "%s", fa->name);
1.13      uwe       206:        }
1.28      ratchov   207:        /*
                    208:         * XXX : we should round rate, right ?
                    209:         */
1.42      ratchov   210:        f = wav_new_in(&wav_ops, fd, fa->name, &fa->ipar, fa->hdr);
1.57      ratchov   211:        if (f == NULL) {
                    212:                if (fd != STDIN_FILENO)
                    213:                        close(fd);
                    214:                return;
                    215:        }
1.42      ratchov   216:        nfr = dev_bufsz * fa->ipar.rate / dev_rate;
                    217:        buf = abuf_new(nfr, &fa->ipar);
1.28      ratchov   218:        proc = rpipe_new((struct file *)f);
1.26      ratchov   219:        aproc_setout(proc, buf);
1.28      ratchov   220:        abuf_fill(buf); /* XXX: move this in dev_attach() ? */
1.42      ratchov   221:        dev_attach(fa->name, buf, &fa->ipar, fa->xrun,
1.40      ratchov   222:            NULL, NULL, 0, ADATA_UNIT);
1.35      ratchov   223:        dev_setvol(buf, MIDI_TO_ADATA(fa->vol));
1.15      ratchov   224: }
1.13      uwe       225:
1.15      ratchov   226: /*
                    227:  * Open an output file and setup converter if necessary.
                    228:  */
                    229: void
1.26      ratchov   230: newoutput(struct farg *fa)
1.15      ratchov   231: {
                    232:        int fd;
1.28      ratchov   233:        struct wav *f;
1.26      ratchov   234:        struct aproc *proc;
                    235:        struct abuf *buf;
                    236:        unsigned nfr;
1.15      ratchov   237:
                    238:        if (strcmp(fa->name, "-") == 0) {
                    239:                fd = STDOUT_FILENO;
                    240:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    241:                        warn("stdout");
                    242:                fa->name = "stdout";
                    243:        } else {
                    244:                fd = open(fa->name,
                    245:                    O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                    246:                if (fd < 0)
                    247:                        err(1, "%s", fa->name);
                    248:        }
1.28      ratchov   249:        /*
                    250:         * XXX : we should round rate, right ?
                    251:         */
1.42      ratchov   252:        f = wav_new_out(&wav_ops, fd, fa->name, &fa->opar, fa->hdr);
1.57      ratchov   253:        if (f == NULL) {
                    254:                if (fd != STDOUT_FILENO)
                    255:                        close(fd);
                    256:                return;
                    257:        }
1.42      ratchov   258:        nfr = dev_bufsz * fa->opar.rate / dev_rate;
1.28      ratchov   259:        proc = wpipe_new((struct file *)f);
1.42      ratchov   260:        buf = abuf_new(nfr, &fa->opar);
1.26      ratchov   261:        aproc_setin(proc, buf);
1.42      ratchov   262:        dev_attach(fa->name, NULL, NULL, 0, buf, &fa->opar, fa->xrun, 0);
1.13      uwe       263: }
                    264:
1.63      ratchov   265: /*
                    266:  * Open a MIDI device and connect it to the thru box
                    267:  */
                    268: void
                    269: newmidi(struct farg *fa, int in, int out)
                    270: {
                    271:        struct file *dev;
                    272:        struct abuf *rbuf = NULL, *wbuf = NULL;
                    273:        struct aproc *rproc, *wproc;
                    274:
                    275:        dev = (struct file *)miofile_new(&miofile_ops, fa->name, in, out);
                    276:        if (dev == NULL) {
                    277:                errx(1, "%s: can't open device",
                    278:                    fa->name ? fa->name : "<default>");
                    279:        }
                    280:        if (in) {
                    281:                rproc = rpipe_new(dev);
1.64      ratchov   282:                rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.63      ratchov   283:                aproc_setout(rproc, rbuf);
                    284:        }
                    285:        if (out) {
                    286:                wproc = wpipe_new(dev);
1.64      ratchov   287:                wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.63      ratchov   288:                aproc_setin(wproc, wbuf);
                    289:        }
1.65      ratchov   290:        dev_midiattach(rbuf, wbuf);
1.63      ratchov   291: }
                    292:
1.61      ratchov   293: void
                    294: setsig(void)
                    295: {
                    296:        struct sigaction sa;
                    297:
                    298:        quit_flag = 0;
                    299:        sigfillset(&sa.sa_mask);
                    300:        sa.sa_flags = SA_RESTART;
                    301:        sa.sa_handler = sigint;
                    302:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   303:                err(1, "sigaction(int) failed");
1.61      ratchov   304:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   305:                err(1, "sigaction(term) failed");
1.61      ratchov   306:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   307:                err(1, "sigaction(hup) failed");
1.61      ratchov   308: }
                    309:
                    310: void
                    311: unsetsig(void)
                    312: {
                    313:        struct sigaction sa;
                    314:
                    315:        sigfillset(&sa.sa_mask);
                    316:        sa.sa_flags = SA_RESTART;
                    317:        sa.sa_handler = SIG_DFL;
                    318:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   319:                err(1, "unsetsig(hup): sigaction failed\n");
1.61      ratchov   320:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   321:                err(1, "unsetsig(term): sigaction failed\n");
1.61      ratchov   322:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   323:                err(1, "unsetsig(int): sigaction failed\n");
1.61      ratchov   324: }
                    325:
                    326: void
                    327: getbasepath(char *base, size_t size)
                    328: {
                    329:        uid_t uid;
                    330:        struct stat sb;
                    331:
                    332:        uid = geteuid();
                    333:        snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
                    334:        if (mkdir(base, 0700) < 0) {
                    335:                if (errno != EEXIST)
                    336:                        err(1, "mkdir(\"%s\")", base);
                    337:        }
                    338:        if (stat(base, &sb) < 0)
                    339:                err(1, "stat(\"%s\")", base);
                    340:        if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
                    341:                errx(1, "%s has wrong permissions", base);
                    342: }
                    343:
                    344: void
                    345: aucat_usage(void)
                    346: {
1.69      ratchov   347:        (void)fputs("usage: " PROG_AUCAT " [-dlnu] [-b nframes] "
1.61      ratchov   348:            "[-C min:max] [-c min:max] [-e enc] [-f device]\n"
1.67      jmc       349:            "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s name]\n"
1.61      ratchov   350:            "\t[-U unit] [-v volume] [-x policy]\n",
                    351:            stderr);
                    352: }
                    353:
1.1       kstailey  354: int
1.61      ratchov   355: aucat_main(int argc, char **argv)
1.1       kstailey  356: {
1.69      ratchov   357:        int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, suspend = 0, unit;
1.15      ratchov   358:        struct farg *fa;
1.63      ratchov   359:        struct farglist ifiles, ofiles, sfiles;
1.26      ratchov   360:        struct aparams ipar, opar, dipar, dopar;
1.55      ratchov   361:        char base[PATH_MAX], path[PATH_MAX];
1.43      ratchov   362:        unsigned bufsz, mode;
1.61      ratchov   363:        char *devpath;
1.40      ratchov   364:        unsigned volctl;
1.19      ratchov   365:
1.15      ratchov   366:        aparams_init(&ipar, 0, 1, 44100);
                    367:        aparams_init(&opar, 0, 1, 44100);
1.26      ratchov   368:        u_flag = 0;
1.69      ratchov   369:        d_flag = 0;
1.28      ratchov   370:        l_flag = 0;
1.51      ratchov   371:        n_flag = 0;
1.61      ratchov   372:        unit = -1;
1.15      ratchov   373:        devpath = NULL;
                    374:        SLIST_INIT(&ifiles);
                    375:        SLIST_INIT(&ofiles);
1.42      ratchov   376:        SLIST_INIT(&sfiles);
1.28      ratchov   377:        hdr = HDR_AUTO;
                    378:        xrun = XRUN_IGNORE;
1.40      ratchov   379:        volctl = MIDI_MAXCTL;
1.32      ratchov   380:        bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */
1.43      ratchov   381:        mode = 0;
1.15      ratchov   382:
1.69      ratchov   383:        while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:lus:U:")) != -1) {
1.15      ratchov   384:                switch (c) {
1.69      ratchov   385:                case 'd':
                    386:                        d_flag = 1;
                    387:                        break;
1.51      ratchov   388:                case 'n':
                    389:                        n_flag = 1;
                    390:                        break;
1.43      ratchov   391:                case 'm':
                    392:                        mode = opt_mode();
                    393:                        break;
1.15      ratchov   394:                case 'h':
1.28      ratchov   395:                        hdr = opt_hdr();
1.15      ratchov   396:                        break;
1.22      ratchov   397:                case 'x':
1.28      ratchov   398:                        xrun = opt_xrun();
1.22      ratchov   399:                        break;
1.15      ratchov   400:                case 'c':
                    401:                        opt_ch(&ipar);
                    402:                        break;
                    403:                case 'C':
                    404:                        opt_ch(&opar);
                    405:                        break;
                    406:                case 'e':
                    407:                        opt_enc(&ipar);
1.28      ratchov   408:                        aparams_copyenc(&opar, &ipar);
1.15      ratchov   409:                        break;
                    410:                case 'r':
                    411:                        opt_rate(&ipar);
1.28      ratchov   412:                        opar.rate = ipar.rate;
1.15      ratchov   413:                        break;
1.35      ratchov   414:                case 'v':
1.40      ratchov   415:                        opt_vol(&volctl);
1.35      ratchov   416:                        break;
1.15      ratchov   417:                case 'i':
1.42      ratchov   418:                        farg_add(&ifiles, &ipar, &opar, volctl,
                    419:                            hdr, xrun, optarg);
1.15      ratchov   420:                        break;
                    421:                case 'o':
1.42      ratchov   422:                        farg_add(&ofiles, &ipar, &opar, volctl,
                    423:                            hdr, xrun, optarg);
                    424:                        break;
                    425:                case 's':
                    426:                        farg_add(&sfiles, &ipar, &opar, volctl,
                    427:                            hdr, xrun, optarg);
1.15      ratchov   428:                        break;
1.4       millert   429:                case 'f':
1.15      ratchov   430:                        if (devpath)
                    431:                                err(1, "only one -f allowed");
                    432:                        devpath = optarg;
1.28      ratchov   433:                        dipar = opar;
                    434:                        dopar = ipar;
1.15      ratchov   435:                        break;
1.28      ratchov   436:                case 'l':
                    437:                        l_flag = 1;
1.17      jakemsr   438:                        break;
1.15      ratchov   439:                case 'u':
                    440:                        u_flag = 1;
1.4       millert   441:                        break;
1.28      ratchov   442:                case 'b':
1.32      ratchov   443:                        if (sscanf(optarg, "%u", &bufsz) != 1 || bufsz == 0) {
1.28      ratchov   444:                                fprintf(stderr, "%s: bad buf size\n", optarg);
                    445:                                exit(1);
                    446:                        }
                    447:                        break;
1.61      ratchov   448:                case 'U':
                    449:                        if (sscanf(optarg, "%u", &unit) != 1) {
                    450:                                fprintf(stderr, "%s: bad device number\n", optarg);
                    451:                                exit(1);
                    452:                        }
                    453:                        break;
1.11      jaredy    454:                default:
1.61      ratchov   455:                        aucat_usage();
1.15      ratchov   456:                        exit(1);
1.4       millert   457:                }
                    458:        }
                    459:        argc -= optind;
                    460:        argv += optind;
                    461:
1.15      ratchov   462:        if (!devpath) {
1.47      ratchov   463:                dopar = ipar;
                    464:                dipar = opar;
1.15      ratchov   465:        }
1.28      ratchov   466:        if (!l_flag && SLIST_EMPTY(&ifiles) &&
                    467:            SLIST_EMPTY(&ofiles) && argc > 0) {
1.15      ratchov   468:                /*
                    469:                 * Legacy mode: if no -i or -o options are provided, and
                    470:                 * there are arguments then assume the arguments are files
                    471:                 * to play.
                    472:                 */
                    473:                for (c = 0; c < argc; c++)
                    474:                        if (legacy_play(devpath, argv[c]) != 0) {
1.17      jakemsr   475:                                errx(1, "%s: could not play\n", argv[c]);
1.15      ratchov   476:                        }
                    477:                exit(0);
                    478:        } else if (argc > 0) {
1.61      ratchov   479:                aucat_usage();
1.15      ratchov   480:                exit(1);
                    481:        }
                    482:
1.61      ratchov   483:        if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0))
                    484:                errx(1, "can't use -s or -U without -l");
1.43      ratchov   485:        if ((l_flag || mode != 0) &&
                    486:            (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
                    487:                errx(1, "can't use -l, -m and -s with -o or -i");
                    488:        if (!mode) {
                    489:                if (l_flag || !SLIST_EMPTY(&ifiles))
1.58      ratchov   490:                        mode |= MODE_PLAY;
1.43      ratchov   491:                if (l_flag || !SLIST_EMPTY(&ofiles))
                    492:                        mode |= MODE_REC;
1.61      ratchov   493:                if (!mode) {
                    494:                        aucat_usage();
                    495:                        exit(1);
                    496:                }
1.43      ratchov   497:        }
1.51      ratchov   498:        if (n_flag) {
                    499:                if (devpath != NULL || l_flag)
                    500:                        errx(1, "can't use -n with -f or -l");
                    501:                if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
                    502:                        errx(1, "both -i and -o are required with -n");
                    503:        }
1.15      ratchov   504:
1.46      ratchov   505:        /*
1.62      ratchov   506:         * If there are no sockets paths provided use the default.
1.46      ratchov   507:         */
                    508:        if (l_flag && SLIST_EMPTY(&sfiles)) {
                    509:                farg_add(&sfiles, &dopar, &dipar,
1.61      ratchov   510:                    volctl, HDR_RAW, XRUN_IGNORE, DEFAULT_OPT);
1.46      ratchov   511:        }
                    512:
                    513:        if (!u_flag) {
1.26      ratchov   514:                /*
                    515:                 * Calculate "best" device parameters. Iterate over all
                    516:                 * inputs and outputs and find the maximum sample rate
                    517:                 * and channel number.
                    518:                 */
1.49      ratchov   519:                aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
                    520:                aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
1.26      ratchov   521:                SLIST_FOREACH(fa, &ifiles, entry) {
1.46      ratchov   522:                        aparams_grow(&dopar, &fa->ipar);
1.26      ratchov   523:                }
                    524:                SLIST_FOREACH(fa, &ofiles, entry) {
1.46      ratchov   525:                        aparams_grow(&dipar, &fa->opar);
                    526:                }
                    527:                SLIST_FOREACH(fa, &sfiles, entry) {
                    528:                        aparams_grow(&dopar, &fa->ipar);
                    529:                        aparams_grow(&dipar, &fa->opar);
1.17      jakemsr   530:                }
1.42      ratchov   531:        }
                    532:
1.55      ratchov   533:        if (l_flag) {
1.61      ratchov   534:                getbasepath(base, sizeof(base));
                    535:                if (unit < 0)
                    536:                        unit = 0;
1.55      ratchov   537:        }
1.61      ratchov   538:        setsig();
1.28      ratchov   539:        filelist_init();
1.51      ratchov   540:
1.15      ratchov   541:        /*
1.32      ratchov   542:         * Open the device. Give half of the buffer to the device,
1.62      ratchov   543:         * the other half is for the socket/files.
1.15      ratchov   544:         */
1.51      ratchov   545:        if (n_flag) {
                    546:                dev_loopinit(&dipar, &dopar, bufsz);
                    547:        } else {
1.58      ratchov   548:                if (!dev_init(devpath,
                    549:                        (mode & MODE_REC) ? &dipar : NULL,
                    550:                        (mode & MODE_PLAY) ? &dopar : NULL,
                    551:                        bufsz)) {
                    552:                        errx(1, "%s: can't open device",
                    553:                            devpath ? devpath : "<default>");
                    554:                }
1.51      ratchov   555:        }
1.52      ratchov   556:
1.15      ratchov   557:        /*
                    558:         * Create buffers for all input and output pipes.
                    559:         */
1.26      ratchov   560:        while (!SLIST_EMPTY(&ifiles)) {
                    561:                fa = SLIST_FIRST(&ifiles);
                    562:                SLIST_REMOVE_HEAD(&ifiles, entry);
                    563:                newinput(fa);
                    564:                free(fa);
                    565:        }
                    566:        while (!SLIST_EMPTY(&ofiles)) {
                    567:                fa = SLIST_FIRST(&ofiles);
                    568:                SLIST_REMOVE_HEAD(&ofiles, entry);
                    569:                newoutput(fa);
1.42      ratchov   570:                free(fa);
                    571:        }
                    572:        while (!SLIST_EMPTY(&sfiles)) {
                    573:                fa = SLIST_FIRST(&sfiles);
                    574:                SLIST_REMOVE_HEAD(&sfiles, entry);
1.61      ratchov   575:                opt_new(fa->name, &fa->opar, &fa->ipar, MIDI_TO_ADATA(fa->vol));
1.26      ratchov   576:                free(fa);
1.56      ratchov   577:        }
1.61      ratchov   578:        if (l_flag) {
                    579:                snprintf(path, sizeof(path), "%s/%s%u", base,
                    580:                    DEFAULT_SOFTAUDIO, unit);
                    581:                listen_new(&listen_ops, path);
1.69      ratchov   582:                if (!d_flag && daemon(0, 0) < 0)
1.56      ratchov   583:                        err(1, "daemon");
1.15      ratchov   584:        }
1.13      uwe       585:
1.15      ratchov   586:        /*
1.62      ratchov   587:         * Loop, start audio.
1.15      ratchov   588:         */
1.28      ratchov   589:        for (;;) {
                    590:                if (quit_flag) {
                    591:                        break;
                    592:                }
1.72      ratchov   593:                if ((dev_mix && LIST_EMPTY(&dev_mix->obuflist)) ||
                    594:                    (dev_sub && LIST_EMPTY(&dev_sub->ibuflist))) {
1.50      ratchov   595:                        fprintf(stderr, "device desappeared, terminating\n");
                    596:                        break;
1.38      ratchov   597:                }
1.50      ratchov   598:                if (!file_poll())
                    599:                        break;
1.34      ratchov   600:                if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
                    601:                    (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz)) {
1.37      ratchov   602:                        if (!l_flag)
                    603:                                break;
1.34      ratchov   604:                        if (!suspend) {
                    605:                                suspend = 1;
                    606:                                dev_stop();
                    607:                                dev_clear();
                    608:                        }
                    609:                }
                    610:                if ((dev_mix && dev_mix->u.mix.idle == 0) ||
                    611:                    (dev_sub && dev_sub->u.sub.idle == 0)) {
                    612:                        if (suspend) {
                    613:                                suspend = 0;
                    614:                                dev_start();
                    615:                        }
                    616:                }
                    617:        }
1.55      ratchov   618:        if (l_flag) {
1.50      ratchov   619:                filelist_unlisten();
1.55      ratchov   620:                if (rmdir(base) < 0)
                    621:                        warn("rmdir(\"%s\")", base);
                    622:        }
1.34      ratchov   623:        if (suspend) {
                    624:                suspend = 0;
                    625:                dev_start();
1.28      ratchov   626:        }
1.70      ratchov   627:        dev_done();
1.28      ratchov   628:        filelist_done();
1.61      ratchov   629:        unsetsig();
                    630:        return 0;
                    631: }
                    632:
                    633: void
                    634: midicat_usage(void)
                    635: {
1.69      ratchov   636:        (void)fputs("usage: " PROG_MIDICAT " [-dl] [-f device] "
1.61      ratchov   637:            "[-i file] [-o file] [-U unit]\n",
                    638:            stderr);
                    639: }
                    640: int
                    641: midicat_main(int argc, char **argv)
                    642: {
1.69      ratchov   643:        int c, d_flag, l_flag, unit, fd;
1.64      ratchov   644:        struct farglist dfiles, ifiles, ofiles;
1.61      ratchov   645:        char base[PATH_MAX], path[PATH_MAX];
1.63      ratchov   646:        struct farg *fa;
1.65      ratchov   647:        struct file *stdx;
1.63      ratchov   648:        struct aproc *p;
1.61      ratchov   649:        struct abuf *buf;
                    650:
1.69      ratchov   651:        d_flag = 0;
1.61      ratchov   652:        l_flag = 0;
                    653:        unit = -1;
1.63      ratchov   654:        SLIST_INIT(&dfiles);
1.64      ratchov   655:        SLIST_INIT(&ifiles);
                    656:        SLIST_INIT(&ofiles);
1.61      ratchov   657:
1.69      ratchov   658:        while ((c = getopt(argc, argv, "di:o:lf:U:")) != -1) {
1.61      ratchov   659:                switch (c) {
1.69      ratchov   660:                case 'd':
                    661:                        d_flag = 1;
                    662:                        break;
1.61      ratchov   663:                case 'i':
1.64      ratchov   664:                        farg_add(&ifiles, &aparams_none, &aparams_none,
                    665:                            0, HDR_RAW, 0, optarg);
1.61      ratchov   666:                        break;
                    667:                case 'o':
1.64      ratchov   668:                        farg_add(&ofiles, &aparams_none, &aparams_none,
                    669:                            0, HDR_RAW, 0, optarg);
1.61      ratchov   670:                        break;
                    671:                case 'f':
1.63      ratchov   672:                        farg_add(&dfiles, &aparams_none, &aparams_none,
1.64      ratchov   673:                            0, HDR_RAW, 0, optarg);
1.61      ratchov   674:                        break;
                    675:                case 'l':
                    676:                        l_flag = 1;
                    677:                        break;
                    678:                case 'U':
                    679:                        if (sscanf(optarg, "%u", &unit) != 1) {
                    680:                                fprintf(stderr, "%s: bad device number\n", optarg);
                    681:                                exit(1);
                    682:                        }
                    683:                        break;
                    684:                default:
                    685:                        midicat_usage();
                    686:                        exit(1);
                    687:                }
                    688:        }
                    689:        argc -= optind;
                    690:        argv += optind;
                    691:
1.64      ratchov   692:        if (argc > 0 || (SLIST_EMPTY(&ifiles) && SLIST_EMPTY(&ofiles) &&
                    693:            !l_flag)) {
1.61      ratchov   694:                midicat_usage();
                    695:                exit(1);
                    696:        }
                    697:        if (!l_flag && unit >= 0)
                    698:                errx(1, "can't use -U without -l");
                    699:        if (l_flag) {
1.64      ratchov   700:                if (!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles))
1.61      ratchov   701:                        errx(1, "can't use -i or -o with -l");
                    702:                getbasepath(base, sizeof(path));
                    703:                if (unit < 0)
                    704:                        unit = 0;
                    705:        }
                    706:        setsig();
                    707:        filelist_init();
                    708:
1.65      ratchov   709:        dev_thruinit();
1.71      ratchov   710:        if (!l_flag)
                    711:                dev_midi->u.thru.flags |= THRU_AUTOQUIT;
1.64      ratchov   712:        if ((!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles)) &&
                    713:            SLIST_EMPTY(&dfiles)) {
1.63      ratchov   714:                farg_add(&dfiles, &aparams_none, &aparams_none,
                    715:                    0, HDR_RAW, 0, NULL);
                    716:        }
                    717:        while (!SLIST_EMPTY(&dfiles)) {
                    718:                fa = SLIST_FIRST(&dfiles);
                    719:                SLIST_REMOVE_HEAD(&dfiles, entry);
1.64      ratchov   720:                newmidi(fa,
                    721:                    !SLIST_EMPTY(&ofiles) || l_flag,
                    722:                    !SLIST_EMPTY(&ifiles) || l_flag);
1.63      ratchov   723:                free(fa);
                    724:        }
1.61      ratchov   725:        if (l_flag) {
                    726:                snprintf(path, sizeof(path), "%s/%s%u", base,
                    727:                    DEFAULT_MIDITHRU, unit);
                    728:                listen_new(&listen_ops, path);
1.69      ratchov   729:                if (!d_flag && daemon(0, 0) < 0)
1.61      ratchov   730:                        err(1, "daemon");
                    731:        }
1.64      ratchov   732:        while (!SLIST_EMPTY(&ifiles)) {
                    733:                fa = SLIST_FIRST(&ifiles);
                    734:                SLIST_REMOVE_HEAD(&ifiles, entry);
                    735:                if (strcmp(fa->name, "-") == 0) {
1.61      ratchov   736:                        fd = STDIN_FILENO;
                    737:                        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    738:                                warn("stdin");
                    739:                } else {
1.64      ratchov   740:                        fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
1.61      ratchov   741:                        if (fd < 0)
1.64      ratchov   742:                                err(1, "%s", fa->name);
1.61      ratchov   743:                }
1.64      ratchov   744:                stdx = (struct file *)pipe_new(&pipe_ops, fd, fa->name);
1.61      ratchov   745:                p = rpipe_new(stdx);
1.64      ratchov   746:                buf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.61      ratchov   747:                aproc_setout(p, buf);
1.65      ratchov   748:                dev_midiattach(buf, NULL);
1.64      ratchov   749:                free(fa);
1.63      ratchov   750:        }
1.64      ratchov   751:        while (!SLIST_EMPTY(&ofiles)) {
1.66      ratchov   752:                fa = SLIST_FIRST(&ofiles);
                    753:                SLIST_REMOVE_HEAD(&ofiles, entry);
1.64      ratchov   754:                if (strcmp(fa->name, "-") == 0) {
1.61      ratchov   755:                        fd = STDOUT_FILENO;
                    756:                        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    757:                                warn("stdout");
                    758:                } else {
1.64      ratchov   759:                        fd = open(fa->name,
1.61      ratchov   760:                            O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                    761:                        if (fd < 0)
1.64      ratchov   762:                                err(1, "%s", fa->name);
1.61      ratchov   763:                }
1.64      ratchov   764:                stdx = (struct file *)pipe_new(&pipe_ops, fd, fa->name);
1.61      ratchov   765:                p = wpipe_new(stdx);
1.64      ratchov   766:                buf = abuf_new(MIDI_BUFSZ, &aparams_none);
1.61      ratchov   767:                aproc_setin(p, buf);
1.65      ratchov   768:                dev_midiattach(NULL, buf);
1.64      ratchov   769:                free(fa);
1.63      ratchov   770:        }
1.11      jaredy    771:
1.61      ratchov   772:        /*
                    773:         * loop, start processing
                    774:         */
                    775:        for (;;) {
                    776:                if (quit_flag) {
                    777:                        break;
                    778:                }
                    779:                if (!file_poll())
                    780:                        break;
                    781:        }
                    782:        if (l_flag) {
                    783:                filelist_unlisten();
                    784:                if (rmdir(base) < 0)
                    785:                        warn("rmdir(\"%s\")", base);
                    786:        }
1.71      ratchov   787:        dev_done();
1.61      ratchov   788:        filelist_done();
                    789:        unsetsig();
1.15      ratchov   790:        return 0;
1.61      ratchov   791: }
                    792:
                    793:
                    794: int
                    795: main(int argc, char **argv)
                    796: {
                    797:        char *prog;
                    798:
                    799:        prog = strrchr(argv[0], '/');
                    800:        if (prog == NULL)
                    801:                prog = argv[0];
                    802:        else
                    803:                prog++;
                    804:        if (strcmp(prog, PROG_AUCAT) == 0) {
                    805:                return aucat_main(argc, argv);
                    806:        } else if (strcmp(prog, PROG_MIDICAT) == 0) {
                    807:                return midicat_main(argc, argv);
                    808:        } else {
                    809:                fprintf(stderr, "%s: can't determine program to run\n", prog);
                    810:        }
                    811:        return 1;
1.1       kstailey  812: }