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

1.27    ! sobrado     1: /*     $OpenBSD: aucat.c,v 1.26 2008/08/14 09:58:55 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: /*
                     18:  * TODO:
                     19:  *
                     20:  *     (hard) use parsable encoding names instead of the lookup
                     21:  *     table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example
                     22:  *     s8, s16le, s24le/3msb. This would give names that correspond to
                     23:  *     what use most linux-centric apps, but for which we have an
                     24:  *     algorithm to convert the name to a aparams structure.
                     25:  *
                     26:  *     (easy) uses {chmin-chmax} instead of chmin:chmax notation for
                     27:  *     channels specification to match the notation used in rmix.
                     28:  *
                     29:  *     (easy) use comma-separated parameters syntax, example:
                     30:  *     s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c
                     31:  *     flags, but only one -p flag that specify one or more parameters.
                     32:  *
                     33:  *     (hard) if all inputs are over, the mixer terminates and closes
                     34:  *     the write end of the device. It should continue writing zeros
                     35:  *     until the recording is over (or be able to stop write end of
                     36:  *     the device)
                     37:  *
                     38:  *     (hard) implement -n flag (no device) to connect all inputs to
                     39:  *     the outputs.
                     40:  *
                     41:  *     (hard) ignore input files that are not audible (because channels
                     42:  *     they provide are not used on the output). Similarly ignore
                     43:  *     outputs that are zero filled (because channels they consume are
                     44:  *     not provided).
1.1       kstailey   45:  */
                     46:
1.15      ratchov    47: #include <sys/param.h>
1.1       kstailey   48: #include <sys/types.h>
1.15      ratchov    49: #include <sys/queue.h>
1.13      uwe        50:
1.15      ratchov    51: #include <err.h>
1.1       kstailey   52: #include <fcntl.h>
1.15      ratchov    53: #include <signal.h>
1.1       kstailey   54: #include <stdio.h>
1.4       millert    55: #include <stdlib.h>
1.8       david      56: #include <string.h>
1.1       kstailey   57: #include <unistd.h>
1.15      ratchov    58: #include <varargs.h>
1.1       kstailey   59:
1.15      ratchov    60: #include "conf.h"
                     61: #include "aparams.h"
                     62: #include "aproc.h"
                     63: #include "abuf.h"
                     64: #include "file.h"
                     65: #include "dev.h"
1.11      jaredy     66:
1.26      ratchov    67: int debug_level = 0, quiet_flag = 0;
                     68: volatile int quit_flag = 0, pause_flag = 0;
1.7       deraadt    69:
1.26      ratchov    70: void suspend(struct file *);
                     71: void fill(struct file *);
                     72: void flush(struct file *);
1.22      ratchov    73:
1.15      ratchov    74: /*
                     75:  * List of allowed encodings and their names.
                     76:  */
                     77: struct enc {
                     78:        char *name;
                     79:        struct aparams par;
                     80: } enc_list[] = {
                     81:        /* name         bps,    bits,   le,     sign,   msb,    unused  */
                     82:        { "s8",         { 1,    8,      1,      1,      1,      0, 0, 0 } },
                     83:        { "u8",         { 1,    8,      1,      0,      1,      0, 0, 0 } },
                     84:        { "s16le",      { 2,    16,     1,      1,      1,      0, 0, 0 } },
                     85:        { "u16le",      { 2,    16,     1,      0,      1,      0, 0, 0 } },
                     86:        { "s16be",      { 2,    16,     0,      1,      1,      0, 0, 0 } },
                     87:        { "u16be",      { 2,    16,     0,      0,      1,      0, 0, 0 } },
                     88:        { "s24le",      { 4,    24,     1,      1,      1,      0, 0, 0 } },
                     89:        { "u24le",      { 4,    24,     1,      0,      1,      0, 0, 0 } },
                     90:        { "s24be",      { 4,    24,     0,      1,      1,      0, 0, 0 } },
                     91:        { "u24be",      { 4,    24,     0,      0,      1,      0, 0, 0 } },
                     92:        { "s32le",      { 4,    32,     1,      1,      1,      0, 0, 0 } },
                     93:        { "u32le",      { 4,    32,     1,      0,      1,      0, 0, 0 } },
                     94:        { "s32be",      { 4,    32,     0,      1,      1,      0, 0, 0 } },
                     95:        { "u32be",      { 4,    32,     0,      0,      1,      0, 0, 0 } },
                     96:        { "s24le3",     { 3,    24,     1,      1,      1,      0, 0, 0 } },
                     97:        { "u24le3",     { 3,    24,     1,      0,      1,      0, 0, 0 } },
                     98:        { "s24be3",     { 3,    24,     0,      1,      1,      0, 0, 0 } },
                     99:        { "u24be3",     { 3,    24,     0,      0,      1,      0, 0, 0 } },
                    100:        { "s20le3",     { 3,    20,     1,      1,      1,      0, 0, 0 } },
                    101:        { "u20le3",     { 3,    20,     1,      0,      1,      0, 0, 0 } },
                    102:        { "s20be3",     { 3,    20,     0,      1,      1,      0, 0, 0 } },
                    103:        { "u20be3",     { 3,    20,     0,      0,      1,      0, 0, 0 } },
                    104:        { "s18le3",     { 3,    18,     1,      1,      1,      0, 0, 0 } },
                    105:        { "u18le3",     { 3,    18,     1,      0,      1,      0, 0, 0 } },
                    106:        { "s18be3",     { 3,    18,     0,      1,      1,      0, 0, 0 } },
                    107:        { "u18be3",     { 3,    18,     0,      0,      1,      0, 0, 0 } },
                    108:        { NULL,         { 0,    0,      0,      0,      0,      0, 0, 0 } }
                    109: };
1.13      uwe       110:
1.11      jaredy    111: /*
1.15      ratchov   112:  * Search an encoding in the above table. On success fill encoding
                    113:  * part of "par" and return 1, otherwise return 0.
1.1       kstailey  114:  */
1.15      ratchov   115: unsigned
                    116: enc_lookup(char *name, struct aparams *par)
                    117: {
                    118:        struct enc *e;
                    119:
                    120:        for (e = enc_list; e->name != NULL; e++) {
                    121:                if (strcmp(e->name, name) == 0) {
                    122:                        par->bps = e->par.bps;
                    123:                        par->bits = e->par.bits;
                    124:                        par->sig = e->par.sig;
                    125:                        par->le = e->par.le;
                    126:                        par->msb = e->par.msb;
                    127:                        return 1;
                    128:                }
                    129:        }
                    130:        return 0;
                    131: }
                    132:
                    133: void
                    134: usage(void)
1.1       kstailey  135: {
1.15      ratchov   136:        extern char *__progname;
1.4       millert   137:
1.15      ratchov   138:        fprintf(stderr,
1.27    ! sobrado   139:            "usage: %s [-qu] [-C min:max] [-c min:max] [-E enc] [-e enc] "
        !           140:            "[-f device]\n"
        !           141:            "\t[-H fmt] [-h fmt] [-i file] [-o file] [-R rate] [-r rate]\n"
        !           142:            "\t[-X policy] [-x policy]\n",
1.15      ratchov   143:            __progname);
                    144: }
                    145:
                    146: void
                    147: opt_ch(struct aparams *par)
                    148: {
                    149:        if (sscanf(optarg, "%u:%u", &par->cmin, &par->cmax) != 2 ||
                    150:            par->cmin > CHAN_MAX || par->cmax > CHAN_MAX ||
                    151:            par->cmin > par->cmax)
                    152:                err(1, "%s: bad channel range", optarg);
                    153: }
1.13      uwe       154:
1.15      ratchov   155: void
                    156: opt_rate(struct aparams *par)
                    157: {
                    158:        if (sscanf(optarg, "%u", &par->rate) != 1 ||
                    159:            par->rate < RATE_MIN || par->rate > RATE_MAX)
                    160:                err(1, "%s: bad sample rate", optarg);
                    161: }
1.13      uwe       162:
1.15      ratchov   163: void
                    164: opt_enc(struct aparams *par)
                    165: {
                    166:        if (!enc_lookup(optarg, par))
                    167:                err(1, "%s: bad encoding", optarg);
                    168: }
1.4       millert   169:
1.15      ratchov   170: int
                    171: opt_hdr(void)
                    172: {
                    173:        if (strcmp("auto", optarg) == 0)
                    174:                return HDR_AUTO;
                    175:        if (strcmp("raw", optarg) == 0)
                    176:                return HDR_RAW;
                    177:        if (strcmp("wav", optarg) == 0)
                    178:                return HDR_WAV;
                    179:        err(1, "%s: bad header specification", optarg);
1.1       kstailey  180: }
                    181:
1.22      ratchov   182: int
                    183: opt_xrun(void)
                    184: {
                    185:        if (strcmp("ignore", optarg) == 0)
                    186:                return XRUN_IGNORE;
                    187:        if (strcmp("sync", optarg) == 0)
                    188:                return XRUN_SYNC;
                    189:        if (strcmp("error", optarg) == 0)
                    190:                return XRUN_ERROR;
                    191:        errx(1, "%s: onderrun/overrun policy", optarg);
                    192: }
                    193:
1.13      uwe       194: /*
1.15      ratchov   195:  * Arguments of -i and -o opations are stored in a list.
1.13      uwe       196:  */
1.15      ratchov   197: struct farg {
                    198:        SLIST_ENTRY(farg) entry;
                    199:        struct aparams par;     /* last requested format */
                    200:        unsigned vol;           /* last requested volume */
                    201:        char *name;             /* optarg pointer (no need to copy it */
                    202:        int hdr;                /* header format */
1.22      ratchov   203:        int xrun;               /* overrun/underrun policy */
1.15      ratchov   204: };
1.13      uwe       205:
1.15      ratchov   206: SLIST_HEAD(farglist, farg);
1.13      uwe       207:
1.15      ratchov   208: /*
                    209:  * Add a farg entry to the given list, corresponding
                    210:  * to the given file name.
                    211:  */
                    212: void
                    213: opt_file(struct farglist *list,
1.22      ratchov   214:     struct aparams *par, unsigned vol, int hdr, int xrun, char *optarg)
1.15      ratchov   215: {
                    216:        struct farg *fa;
                    217:        size_t namelen;
                    218:
                    219:        fa = malloc(sizeof(struct farg));
                    220:        if (fa == NULL)
                    221:                err(1, "%s", optarg);
                    222:
                    223:        if (hdr == HDR_AUTO) {
                    224:                namelen = strlen(optarg);
                    225:                if (namelen >= 4 &&
                    226:                    strcasecmp(optarg + namelen - 4, ".wav") == 0) {
                    227:                        fa->hdr = HDR_WAV;
                    228:                        DPRINTF("%s: assuming wav file format\n", optarg);
                    229:                } else {
                    230:                        fa->hdr = HDR_RAW;
                    231:                        DPRINTF("%s: assuming headerless file\n", optarg);
1.13      uwe       232:                }
1.15      ratchov   233:        } else
                    234:                fa->hdr = hdr;
1.22      ratchov   235:        fa->xrun = xrun;
1.15      ratchov   236:        fa->par = *par;
                    237:        fa->vol = vol;
                    238:        fa->name = optarg;
                    239:        SLIST_INSERT_HEAD(list, fa, entry);
                    240: }
1.13      uwe       241:
1.15      ratchov   242: /*
                    243:  * Open an input file and setup converter if necessary.
                    244:  */
                    245: void
1.26      ratchov   246: newinput(struct farg *fa)
1.15      ratchov   247: {
                    248:        int fd;
                    249:        struct file *f;
1.26      ratchov   250:        struct aproc *proc;
                    251:        struct abuf *buf;
                    252:        unsigned nfr;
1.15      ratchov   253:
                    254:        if (strcmp(fa->name, "-") == 0) {
                    255:                fd = STDIN_FILENO;
                    256:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    257:                        warn("stdin");
                    258:                fa->name = "stdin";
                    259:        } else {
                    260:                fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
                    261:                if (fd < 0)
                    262:                        err(1, "%s", fa->name);
1.13      uwe       263:        }
1.15      ratchov   264:        f = file_new(fd, fa->name);
1.26      ratchov   265:        f->hdr = 0;
                    266:        f->hpar = fa->par;
1.15      ratchov   267:        if (fa->hdr == HDR_WAV) {
1.26      ratchov   268:                if (!wav_readhdr(fd, &f->hpar, &f->rbytes))
1.15      ratchov   269:                        exit(1);
1.13      uwe       270:        }
1.26      ratchov   271:        nfr = dev_onfr * f->hpar.rate / dev_opar.rate;
                    272:        buf = abuf_new(nfr, aparams_bpf(&f->hpar));
                    273:        proc = rpipe_new(f);
                    274:        aproc_setout(proc, buf);
                    275:        dev_attach(fa->name, buf, &f->hpar, fa->xrun, NULL, NULL, 0);
1.15      ratchov   276: }
1.13      uwe       277:
1.15      ratchov   278: /*
                    279:  * Open an output file and setup converter if necessary.
                    280:  */
                    281: void
1.26      ratchov   282: newoutput(struct farg *fa)
1.15      ratchov   283: {
                    284:        int fd;
                    285:        struct file *f;
1.26      ratchov   286:        struct aproc *proc;
                    287:        struct abuf *buf;
                    288:        unsigned nfr;
1.15      ratchov   289:
                    290:        if (strcmp(fa->name, "-") == 0) {
                    291:                fd = STDOUT_FILENO;
                    292:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    293:                        warn("stdout");
                    294:                fa->name = "stdout";
                    295:        } else {
                    296:                fd = open(fa->name,
                    297:                    O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                    298:                if (fd < 0)
                    299:                        err(1, "%s", fa->name);
                    300:        }
                    301:        f = file_new(fd, fa->name);
1.26      ratchov   302:        f->hdr = fa->hdr;
                    303:        f->hpar = fa->par;
                    304:        if (f->hdr == HDR_WAV) {
1.15      ratchov   305:                f->wbytes = WAV_DATAMAX;
1.26      ratchov   306:                if (!wav_writehdr(fd, &f->hpar))
1.15      ratchov   307:                        exit(1);
1.13      uwe       308:        }
1.26      ratchov   309:        nfr = dev_infr * f->hpar.rate / dev_ipar.rate;
                    310:        proc = wpipe_new(f);
                    311:        buf = abuf_new(nfr, aparams_bpf(&f->hpar));
                    312:        aproc_setin(proc, buf);
                    313:        dev_attach(fa->name, NULL, NULL, 0, buf, &f->hpar, fa->xrun);
1.13      uwe       314: }
                    315:
1.1       kstailey  316: int
1.15      ratchov   317: main(int argc, char **argv)
1.1       kstailey  318: {
1.26      ratchov   319:        int c, u_flag, ohdr, ihdr, ixrun, oxrun;
1.15      ratchov   320:        struct farg *fa;
                    321:        struct farglist  ifiles, ofiles;
1.26      ratchov   322:        struct aparams ipar, opar, dipar, dopar;
1.15      ratchov   323:        unsigned ivol, ovol;
1.19      ratchov   324:        char *devpath, *dbgenv;
1.21      ratchov   325:        const char *errstr;
1.15      ratchov   326:
1.19      ratchov   327:        dbgenv = getenv("AUCAT_DEBUG");
                    328:        if (dbgenv) {
1.21      ratchov   329:                debug_level = strtonum(dbgenv, 0, 4, &errstr);
                    330:                if (errstr)
                    331:                        errx(1, "AUCAT_DEBUG is %s: %s", errstr, dbgenv);
1.19      ratchov   332:        }
                    333:
1.15      ratchov   334:        aparams_init(&ipar, 0, 1, 44100);
                    335:        aparams_init(&opar, 0, 1, 44100);
                    336:
1.26      ratchov   337:        u_flag = 0;
1.15      ratchov   338:        devpath = NULL;
                    339:        SLIST_INIT(&ifiles);
                    340:        SLIST_INIT(&ofiles);
                    341:        ihdr = ohdr = HDR_AUTO;
1.22      ratchov   342:        ixrun = oxrun = XRUN_IGNORE;
1.15      ratchov   343:        ivol = ovol = MIDI_TO_ADATA(127);
                    344:
1.22      ratchov   345:        while ((c = getopt(argc, argv, "c:C:e:E:r:R:h:H:x:X:i:o:f:qu"))
                    346:            != -1) {
1.15      ratchov   347:                switch (c) {
                    348:                case 'h':
                    349:                        ihdr = opt_hdr();
                    350:                        break;
                    351:                case 'H':
                    352:                        ohdr = opt_hdr();
                    353:                        break;
1.22      ratchov   354:                case 'x':
                    355:                        ixrun = opt_xrun();
                    356:                        break;
                    357:                case 'X':
                    358:                        oxrun = opt_xrun();
                    359:                        break;
1.15      ratchov   360:                case 'c':
                    361:                        opt_ch(&ipar);
                    362:                        break;
                    363:                case 'C':
                    364:                        opt_ch(&opar);
                    365:                        break;
                    366:                case 'e':
                    367:                        opt_enc(&ipar);
                    368:                        break;
                    369:                case 'E':
                    370:                        opt_enc(&opar);
                    371:                        break;
                    372:                case 'r':
                    373:                        opt_rate(&ipar);
                    374:                        break;
                    375:                case 'R':
                    376:                        opt_rate(&opar);
                    377:                        break;
                    378:                case 'i':
1.22      ratchov   379:                        opt_file(&ifiles, &ipar, 127, ihdr, ixrun, optarg);
1.15      ratchov   380:                        break;
                    381:                case 'o':
1.22      ratchov   382:                        opt_file(&ofiles, &opar, 127, ohdr, oxrun, optarg);
1.15      ratchov   383:                        break;
1.4       millert   384:                case 'f':
1.15      ratchov   385:                        if (devpath)
                    386:                                err(1, "only one -f allowed");
                    387:                        devpath = optarg;
                    388:                        dipar = ipar;
                    389:                        dopar = opar;
                    390:                        break;
1.17      jakemsr   391:                case 'q':
                    392:                        quiet_flag = 1;
                    393:                        break;
1.15      ratchov   394:                case 'u':
                    395:                        u_flag = 1;
1.4       millert   396:                        break;
1.11      jaredy    397:                default:
                    398:                        usage();
1.15      ratchov   399:                        exit(1);
1.4       millert   400:                }
                    401:        }
                    402:        argc -= optind;
                    403:        argv += optind;
                    404:
1.15      ratchov   405:        if (!devpath) {
                    406:                devpath = getenv("AUDIODEVICE");
                    407:                if (devpath == NULL)
                    408:                        devpath = DEFAULT_DEVICE;
                    409:                dipar = ipar;
                    410:                dopar = opar;
                    411:        }
                    412:
                    413:        if (SLIST_EMPTY(&ifiles) && SLIST_EMPTY(&ofiles) && argc > 0) {
                    414:                /*
                    415:                 * Legacy mode: if no -i or -o options are provided, and
                    416:                 * there are arguments then assume the arguments are files
                    417:                 * to play.
                    418:                 */
                    419:                for (c = 0; c < argc; c++)
                    420:                        if (legacy_play(devpath, argv[c]) != 0) {
1.17      jakemsr   421:                                errx(1, "%s: could not play\n", argv[c]);
1.15      ratchov   422:                        }
                    423:                exit(0);
                    424:        } else if (argc > 0) {
1.11      jaredy    425:                usage();
1.15      ratchov   426:                exit(1);
                    427:        }
                    428:
                    429:
                    430:        if (!u_flag) {
1.26      ratchov   431:                /*
                    432:                 * Calculate "best" device parameters. Iterate over all
                    433:                 * inputs and outputs and find the maximum sample rate
                    434:                 * and channel number.
                    435:                 */
                    436:                aparams_init(&dipar, CHAN_MAX, 0, RATE_MAX);
                    437:                aparams_init(&dopar, CHAN_MAX, 0, RATE_MIN);
                    438:                SLIST_FOREACH(fa, &ifiles, entry) {
                    439:                        if (dopar.cmin > fa->par.cmin)
                    440:                                dopar.cmin = fa->par.cmin;
                    441:                        if (dopar.cmax < fa->par.cmax)
                    442:                                dopar.cmax = fa->par.cmax;
                    443:                        if (dopar.rate < fa->par.rate)
                    444:                                dopar.rate = fa->par.rate;
                    445:                }
                    446:                SLIST_FOREACH(fa, &ofiles, entry) {
                    447:                        if (dipar.cmin > fa->par.cmin)
                    448:                                dipar.cmin = fa->par.cmin;
                    449:                        if (dipar.cmax < fa->par.cmax)
                    450:                                dipar.cmax = fa->par.cmax;
                    451:                        if (dipar.rate > fa->par.rate)
                    452:                                dipar.rate = fa->par.rate;
1.17      jakemsr   453:                }
1.15      ratchov   454:        }
1.26      ratchov   455:        file_start();
1.15      ratchov   456:
                    457:        /*
1.26      ratchov   458:         * Open the device, dev_init() will return new parameters
                    459:         * that must be used by all inputs and outputs.
1.15      ratchov   460:         */
1.26      ratchov   461:        dev_init(devpath,
                    462:            (!SLIST_EMPTY(&ofiles)) ? &dipar : NULL,
                    463:            (!SLIST_EMPTY(&ifiles)) ? &dopar : NULL);
1.15      ratchov   464:
                    465:        /*
                    466:         * Create buffers for all input and output pipes.
                    467:         */
1.26      ratchov   468:        while (!SLIST_EMPTY(&ifiles)) {
                    469:                fa = SLIST_FIRST(&ifiles);
                    470:                SLIST_REMOVE_HEAD(&ifiles, entry);
                    471:                newinput(fa);
                    472:                free(fa);
                    473:        }
                    474:        while (!SLIST_EMPTY(&ofiles)) {
                    475:                fa = SLIST_FIRST(&ofiles);
                    476:                SLIST_REMOVE_HEAD(&ofiles, entry);
                    477:                newoutput(fa);
                    478:                free(fa);
1.15      ratchov   479:        }
1.13      uwe       480:
1.15      ratchov   481:        /*
1.26      ratchov   482:         * Normalize input levels
1.15      ratchov   483:         */
1.26      ratchov   484:        if (dev_mix)
                    485:                mix_setmaster(dev_mix);
1.13      uwe       486:
1.15      ratchov   487:        /*
                    488:         * start audio
                    489:         */
1.17      jakemsr   490:        if (!quiet_flag)
                    491:                fprintf(stderr, "starting device...\n");
1.26      ratchov   492:        dev_start();
                    493:        if (!quiet_flag)
                    494:                fprintf(stderr, "process started...\n");
                    495:        dev_run(1);
1.17      jakemsr   496:        if (!quiet_flag)
1.26      ratchov   497:                fprintf(stderr, "stopping device...\n");
                    498:        dev_done();
1.11      jaredy    499:
1.15      ratchov   500:        file_stop();
                    501:        return 0;
1.1       kstailey  502: }