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

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