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