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

1.140     ratchov     1: /*     $OpenBSD$       */
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.138     ratchov    26: #include <grp.h>
1.55      ratchov    27: #include <limits.h>
1.86      ratchov    28: #include <pwd.h>
1.15      ratchov    29: #include <signal.h>
1.135     ratchov    30: #include <sndio.h>
1.1       kstailey   31: #include <stdio.h>
1.4       millert    32: #include <stdlib.h>
1.8       david      33: #include <string.h>
1.1       kstailey   34: #include <unistd.h>
                     35:
1.62      ratchov    36: #include "abuf.h"
1.112     ratchov    37: #include "amsg.h"
1.15      ratchov    38: #include "aparams.h"
                     39: #include "aproc.h"
1.62      ratchov    40: #include "conf.h"
                     41: #include "dev.h"
1.61      ratchov    42: #include "midi.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.61      ratchov    48: #define PROG_AUCAT     "aucat"
                     49:
1.108     ratchov    50: /*
                     51:  * sample rate if no ``-r'' is used
                     52:  */
                     53: #ifndef DEFAULT_RATE
1.132     ratchov    54: #define DEFAULT_RATE   48000
1.108     ratchov    55: #endif
                     56:
1.120     ratchov    57: /*
1.133     ratchov    58:  * block size if neither ``-z'' nor ``-b'' is used
1.120     ratchov    59:  */
                     60: #ifndef DEFAULT_ROUND
1.133     ratchov    61: #define DEFAULT_ROUND  960
                     62: #endif
                     63:
                     64: /*
                     65:  * buffer size if neither ``-z'' nor ``-b'' is used
                     66:  */
                     67: #ifndef DEFAULT_BUFSZ
                     68: #define DEFAULT_BUFSZ  7860
1.120     ratchov    69: #endif
                     70:
1.78      ratchov    71: #ifdef DEBUG
1.120     ratchov    72: volatile sig_atomic_t debug_level = 1;
1.78      ratchov    73: #endif
1.111     deraadt    74: volatile sig_atomic_t quit_flag = 0;
1.7       deraadt    75:
1.142   ! ratchov    76: char aucat_usage[] = "usage: " PROG_AUCAT " [-dMn]\n\t"
1.141     ratchov    77:     "[-C min:max] [-c min:max] [-e enc] [-f device]\n\t"
1.142   ! ratchov    78:     "[-h fmt] [-i file] [-j flag] [-o file] [-q port]\n\t"
1.141     ratchov    79:     "[-r rate] [-t mode] [-v volume] [-w flag] [-x policy]\n";
1.129     ratchov    80:
1.28      ratchov    81: /*
                     82:  * SIGINT handler, it raises the quit flag. If the flag is already set,
                     83:  * that means that the last SIGINT was not handled, because the process
1.62      ratchov    84:  * is blocked somewhere, so exit.
1.28      ratchov    85:  */
                     86: void
                     87: sigint(int s)
                     88: {
                     89:        if (quit_flag)
                     90:                _exit(1);
                     91:        quit_flag = 1;
                     92: }
1.22      ratchov    93:
1.78      ratchov    94: #ifdef DEBUG
                     95: /*
                     96:  * Increase debug level on SIGUSR1.
                     97:  */
                     98: void
                     99: sigusr1(int s)
                    100: {
                    101:        if (debug_level < 4)
                    102:                debug_level++;
                    103: }
                    104:
                    105: /*
                    106:  * Decrease debug level on SIGUSR2.
                    107:  */
                    108: void
                    109: sigusr2(int s)
                    110: {
                    111:        if (debug_level > 0)
                    112:                debug_level--;
                    113: }
                    114: #endif
1.15      ratchov   115:
                    116: void
                    117: opt_ch(struct aparams *par)
                    118: {
1.76      ratchov   119:        char *next, *end;
                    120:        long cmin, cmax;
1.13      uwe       121:
1.76      ratchov   122:        errno = 0;
                    123:        cmin = strtol(optarg, &next, 10);
                    124:        if (next == optarg || *next != ':')
                    125:                goto failed;
                    126:        cmax = strtol(++next, &end, 10);
                    127:        if (end == next || *end != '\0')
                    128:                goto failed;
                    129:        if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
                    130:                goto failed;
                    131:        par->cmin = cmin;
                    132:        par->cmax = cmax;
                    133:        return;
                    134: failed:
                    135:        errx(1, "%s: bad channel range", optarg);
1.15      ratchov   136: }
1.13      uwe       137:
1.15      ratchov   138: void
                    139: opt_enc(struct aparams *par)
                    140: {
1.28      ratchov   141:        int len;
                    142:
                    143:        len = aparams_strtoenc(par, optarg);
                    144:        if (len == 0 || optarg[len] != '\0')
                    145:                errx(1, "%s: bad encoding", optarg);
1.15      ratchov   146: }
1.4       millert   147:
1.15      ratchov   148: int
                    149: opt_hdr(void)
                    150: {
                    151:        if (strcmp("auto", optarg) == 0)
                    152:                return HDR_AUTO;
                    153:        if (strcmp("raw", optarg) == 0)
                    154:                return HDR_RAW;
                    155:        if (strcmp("wav", optarg) == 0)
                    156:                return HDR_WAV;
1.35      ratchov   157:        errx(1, "%s: bad header specification", optarg);
1.1       kstailey  158: }
                    159:
1.22      ratchov   160: int
1.74      ratchov   161: opt_mmc(void)
                    162: {
                    163:        if (strcmp("off", optarg) == 0)
                    164:                return 0;
                    165:        if (strcmp("slave", optarg) == 0)
                    166:                return 1;
                    167:        errx(1, "%s: bad MMC mode", optarg);
                    168: }
                    169:
                    170: int
1.90      ratchov   171: opt_onoff(void)
1.84      ratchov   172: {
                    173:        if (strcmp("off", optarg) == 0)
                    174:                return 0;
                    175:        if (strcmp("on", optarg) == 0)
                    176:                return 1;
                    177:        errx(1, "%s: bad join/expand setting", optarg);
                    178: }
                    179:
                    180: int
1.22      ratchov   181: opt_xrun(void)
                    182: {
                    183:        if (strcmp("ignore", optarg) == 0)
                    184:                return XRUN_IGNORE;
                    185:        if (strcmp("sync", optarg) == 0)
                    186:                return XRUN_SYNC;
                    187:        if (strcmp("error", optarg) == 0)
                    188:                return XRUN_ERROR;
1.73      ratchov   189:        errx(1, "%s: bad underrun/overrun policy", optarg);
1.22      ratchov   190: }
                    191:
1.113     ratchov   192: void
1.61      ratchov   193: setsig(void)
                    194: {
                    195:        struct sigaction sa;
                    196:
                    197:        quit_flag = 0;
                    198:        sigfillset(&sa.sa_mask);
                    199:        sa.sa_flags = SA_RESTART;
                    200:        sa.sa_handler = sigint;
                    201:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   202:                err(1, "sigaction(int) failed");
1.61      ratchov   203:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   204:                err(1, "sigaction(term) failed");
1.61      ratchov   205:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   206:                err(1, "sigaction(hup) failed");
1.78      ratchov   207: #ifdef DEBUG
                    208:        sa.sa_handler = sigusr1;
                    209:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    210:                err(1, "sigaction(usr1) failed");
                    211:        sa.sa_handler = sigusr2;
                    212:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    213:                err(1, "sigaction(usr2) failed1n");
                    214: #endif
1.61      ratchov   215: }
                    216:
                    217: void
                    218: unsetsig(void)
                    219: {
                    220:        struct sigaction sa;
                    221:
                    222:        sigfillset(&sa.sa_mask);
                    223:        sa.sa_flags = SA_RESTART;
                    224:        sa.sa_handler = SIG_DFL;
1.78      ratchov   225: #ifdef DEBUG
                    226:        if (sigaction(SIGUSR2, &sa, NULL) < 0)
                    227:                err(1, "unsetsig(usr2): sigaction failed");
                    228:        if (sigaction(SIGUSR1, &sa, NULL) < 0)
                    229:                err(1, "unsetsig(usr1): sigaction failed");
                    230: #endif
1.61      ratchov   231:        if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68      ratchov   232:                err(1, "unsetsig(hup): sigaction failed\n");
1.61      ratchov   233:        if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68      ratchov   234:                err(1, "unsetsig(term): sigaction failed\n");
1.61      ratchov   235:        if (sigaction(SIGINT, &sa, NULL) < 0)
1.68      ratchov   236:                err(1, "unsetsig(int): sigaction failed\n");
1.61      ratchov   237: }
                    238:
1.120     ratchov   239: struct dev *
                    240: mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol)
1.61      ratchov   241: {
1.120     ratchov   242:        struct dev *d;
                    243:
                    244:        if (path) {
                    245:                for (d = dev_list; d != NULL; d = d->next) {
                    246:                        if (d->reqmode & (MODE_LOOP | MODE_THRU))
                    247:                                continue;
                    248:                        if (strcmp(d->path, path) == 0)
                    249:                                return d;
                    250:                }
                    251:        } else {
                    252:                if (dev_list)
                    253:                        return dev_list;
1.135     ratchov   254:                path = SIO_DEVANY;
1.120     ratchov   255:        }
1.133     ratchov   256:        if (!bufsz && !round) {
                    257:                round = DEFAULT_ROUND;
                    258:                bufsz = DEFAULT_BUFSZ;
                    259:        } else if (!bufsz) {
1.132     ratchov   260:                bufsz = round * 2;
1.120     ratchov   261:        } else if (!round)
1.132     ratchov   262:                round = bufsz / 2;
1.125     ratchov   263:        d = dev_new(path, mode, bufsz, round, hold, autovol);
                    264:        if (d == NULL)
                    265:                exit(1);
                    266:        return d;
1.120     ratchov   267: }
                    268:
1.1       kstailey  269: int
1.120     ratchov   270: main(int argc, char **argv)
1.1       kstailey  271: {
1.128     ratchov   272:        int c, background, unit, active;
1.134     ratchov   273:        unsigned int mode, hdr, xrun, rate, join, mmc, vol;
                    274:        unsigned int hold, autovol, bufsz, round;
1.76      ratchov   275:        const char *str;
1.120     ratchov   276:        struct aparams ppar, rpar;
1.92      ratchov   277:        struct dev *d, *dnext;
1.120     ratchov   278:        struct wav *w;
1.19      ratchov   279:
1.92      ratchov   280:        /*
                    281:         * global options defaults
                    282:         */
1.120     ratchov   283:        hdr = HDR_AUTO;
                    284:        xrun = XRUN_IGNORE;
                    285:        vol = MIDI_MAXCTL;
1.124     ratchov   286:        join = 1;
1.120     ratchov   287:        mmc = 0;
1.124     ratchov   288:        hold = 0;
                    289:        autovol = 1;
1.120     ratchov   290:        bufsz = 0;
                    291:        round = 0;
                    292:        unit = 0;
                    293:        background = 0;
                    294:        aparams_init(&ppar, 0, 1, DEFAULT_RATE);
                    295:        aparams_init(&rpar, 0, 1, DEFAULT_RATE);
1.123     ratchov   296:        mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC;
1.120     ratchov   297:
                    298: #ifdef DEBUG
                    299:        atexit(dbg_flush);
                    300: #endif
                    301:        setsig();
                    302:        filelist_init();
                    303:
1.142   ! ratchov   304:        while ((c = getopt(argc, argv,
        !           305:                    "a:b:c:C:de:f:h:i:j:Mno:q:r:t:v:w:x:z:")) != -1) {
1.15      ratchov   306:                switch (c) {
1.69      ratchov   307:                case 'd':
1.78      ratchov   308: #ifdef DEBUG
1.120     ratchov   309:                        if (debug_level < 4)
1.78      ratchov   310:                                debug_level++;
                    311: #endif
1.129     ratchov   312:                        background = 0;
1.51      ratchov   313:                        break;
1.15      ratchov   314:                case 'h':
1.120     ratchov   315:                        hdr = opt_hdr();
1.15      ratchov   316:                        break;
1.22      ratchov   317:                case 'x':
1.120     ratchov   318:                        xrun = opt_xrun();
1.22      ratchov   319:                        break;
1.84      ratchov   320:                case 'j':
1.120     ratchov   321:                        join = opt_onoff();
1.84      ratchov   322:                        break;
1.74      ratchov   323:                case 't':
1.120     ratchov   324:                        mmc = opt_mmc();
1.74      ratchov   325:                        break;
1.15      ratchov   326:                case 'c':
1.120     ratchov   327:                        opt_ch(&ppar);
1.15      ratchov   328:                        break;
                    329:                case 'C':
1.120     ratchov   330:                        opt_ch(&rpar);
1.15      ratchov   331:                        break;
                    332:                case 'e':
1.120     ratchov   333:                        opt_enc(&ppar);
                    334:                        aparams_copyenc(&rpar, &ppar);
1.15      ratchov   335:                        break;
                    336:                case 'r':
1.92      ratchov   337:                        rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
1.76      ratchov   338:                        if (str)
                    339:                                errx(1, "%s: rate is %s", optarg, str);
1.120     ratchov   340:                        ppar.rate = rpar.rate = rate;
1.15      ratchov   341:                        break;
1.35      ratchov   342:                case 'v':
1.120     ratchov   343:                        vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
1.76      ratchov   344:                        if (str)
                    345:                                errx(1, "%s: volume is %s", optarg, str);
1.35      ratchov   346:                        break;
1.15      ratchov   347:                case 'i':
1.120     ratchov   348:                        d = mkdev(NULL, 0, bufsz, round, 1, autovol);
                    349:                        w = wav_new_in(&wav_ops, d,
                    350:                            mode & (MODE_PLAY | MODE_MIDIOUT), optarg,
                    351:                            hdr, &ppar, xrun, vol, mmc, join);
                    352:                        if (w == NULL)
                    353:                                errx(1, "%s: couldn't create stream", optarg);
                    354:                        dev_adjpar(d, w->mode, NULL, &w->hpar);
                    355:                        break;
                    356:                case 'o':
                    357:                        d = mkdev(NULL, 0, bufsz, round, 1, autovol);
                    358:                        w = wav_new_out(&wav_ops, d,
                    359:                            mode & (MODE_RECMASK | MODE_MIDIIN), optarg,
                    360:                            hdr, &rpar, xrun, mmc, join);
                    361:                        if (w == NULL)
                    362:                                errx(1, "%s: couldn't create stream", optarg);
                    363:                        dev_adjpar(d, w->mode, &w->hpar, NULL);
1.15      ratchov   364:                        break;
1.120     ratchov   365:                case 'q':
                    366:                        d = mkdev(NULL, mode, bufsz, round, 1, autovol);
                    367:                        if (!devctl_add(d, optarg, MODE_MIDIMASK))
                    368:                                errx(1, "%s: can't open port", optarg);
                    369:                        d->reqmode |= MODE_MIDIMASK;
1.92      ratchov   370:                        break;
1.115     ratchov   371:                case 'w':
1.120     ratchov   372:                        autovol = opt_onoff();
1.4       millert   373:                        break;
1.28      ratchov   374:                case 'b':
1.120     ratchov   375:                        bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
1.76      ratchov   376:                        if (str)
                    377:                                errx(1, "%s: buffer size is %s", optarg, str);
1.28      ratchov   378:                        break;
1.74      ratchov   379:                case 'z':
1.120     ratchov   380:                        round = strtonum(optarg, 1, SHRT_MAX, &str);
1.76      ratchov   381:                        if (str)
                    382:                                errx(1, "%s: block size is %s", optarg, str);
1.74      ratchov   383:                        break;
1.92      ratchov   384:                case 'f':
1.120     ratchov   385:                        mkdev(optarg, 0, bufsz, round, hold, autovol);
                    386:                        break;
                    387:                case 'n':
                    388:                        mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
                    389:                        break;
                    390:                case 'M':
1.127     ratchov   391:                        mkdev("midithru", MODE_THRU, 0, 0, hold, 0);
1.92      ratchov   392:                        break;
1.11      jaredy    393:                default:
1.142   ! ratchov   394:                        fputs(aucat_usage, stderr);
1.15      ratchov   395:                        exit(1);
1.4       millert   396:                }
                    397:        }
                    398:        argc -= optind;
                    399:        argv += optind;
1.92      ratchov   400:        if (argc > 0) {
1.142   ! ratchov   401:                fputs(aucat_usage, stderr);
1.102     ratchov   402:                exit(1);
1.15      ratchov   403:        }
1.125     ratchov   404:        if (wav_list) {
                    405:                if ((d = dev_list) && d->next)
1.142   ! ratchov   406:                        errx(1, "only one device allowed");
1.125     ratchov   407:                if ((d->reqmode & MODE_THRU) && d->ctl_list == NULL) {
1.120     ratchov   408:                        if (!devctl_add(d, "default", MODE_MIDIMASK))
                    409:                                errx(1, "%s: can't open port", optarg);
                    410:                        d->reqmode |= MODE_MIDIMASK;
1.125     ratchov   411:                }
                    412:        } else {
1.142   ! ratchov   413:                fputs(aucat_usage, stderr);
        !           414:                exit(1);
1.120     ratchov   415:        }
                    416:        for (w = wav_list; w != NULL; w = w->next) {
                    417:                if (!wav_init(w))
                    418:                        exit(1);
1.55      ratchov   419:        }
1.120     ratchov   420:        for (d = dev_list; d != NULL; d = d->next) {
                    421:                if (!dev_init(d))
                    422:                        exit(1);
                    423:                if (d->autostart && (d->mode & MODE_AUDIOMASK))
1.126     ratchov   424:                        dev_mmcstart(d);
1.56      ratchov   425:        }
1.13      uwe       426:
1.15      ratchov   427:        /*
1.62      ratchov   428:         * Loop, start audio.
1.15      ratchov   429:         */
1.28      ratchov   430:        for (;;) {
1.90      ratchov   431:                if (quit_flag)
1.28      ratchov   432:                        break;
1.92      ratchov   433:                active = 0;
                    434:                for (d = dev_list; d != NULL; d = dnext) {
                    435:                        dnext = d->next;
                    436:                        if (!dev_run(d))
                    437:                                goto fatal;
1.127     ratchov   438:                        if (d->refcnt > 0)
1.92      ratchov   439:                                active = 1;
                    440:                }
                    441:                if (dev_list == NULL)
1.50      ratchov   442:                        break;
1.142   ! ratchov   443:                if (!active)
1.83      ratchov   444:                        break;
1.50      ratchov   445:                if (!file_poll())
                    446:                        break;
1.34      ratchov   447:        }
1.92      ratchov   448:   fatal:
1.110     ratchov   449:
1.90      ratchov   450:        /*
                    451:         * give a chance to drain
                    452:         */
1.96      ratchov   453:        for (d = dev_list; d != NULL; d = d->next)
                    454:                dev_drain(d);
1.90      ratchov   455:        while (file_poll())
                    456:                ; /* nothing */
1.96      ratchov   457:
                    458:        while (dev_list)
                    459:                dev_del(dev_list);
1.83      ratchov   460:        filelist_done();
1.61      ratchov   461:        unsetsig();
                    462:        return 0;
1.1       kstailey  463: }