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

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