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

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