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