Annotation of src/usr.bin/aucat/aucat.c, Revision 1.63
1.63 ! ratchov 1: /* $OpenBSD: aucat.c,v 1.62 2009/07/25 10:52:18 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);
! 318: rbuf = abuf_new(3125, &aparams_none);
! 319: aproc_setout(rproc, rbuf);
! 320: aproc_setin(thrubox, rbuf);
! 321: }
! 322: if (out) {
! 323: wproc = wpipe_new(dev);
! 324: wbuf = abuf_new(3125, &aparams_none);
! 325: aproc_setin(wproc, wbuf);
! 326: aproc_setout(thrubox, wbuf);
! 327: if (in) {
! 328: rbuf->duplex = wbuf;
! 329: wbuf->duplex = rbuf;
! 330: }
! 331: }
! 332: }
! 333:
1.61 ratchov 334: void
335: setsig(void)
336: {
337: struct sigaction sa;
338:
339: quit_flag = 0;
340: sigfillset(&sa.sa_mask);
341: sa.sa_flags = SA_RESTART;
342: sa.sa_handler = sigint;
343: if (sigaction(SIGINT, &sa, NULL) < 0)
344: DPRINTF("sigaction(int) failed\n");
345: if (sigaction(SIGTERM, &sa, NULL) < 0)
346: DPRINTF("sigaction(term) failed\n");
347: if (sigaction(SIGHUP, &sa, NULL) < 0)
348: DPRINTF("sigaction(hup) failed\n");
349: #ifdef DEBUG
350: sa.sa_handler = sigusr1;
351: if (sigaction(SIGUSR1, &sa, NULL) < 0)
352: DPRINTF("sigaction(usr1) failed\n");
353: sa.sa_handler = sigusr2;
354: if (sigaction(SIGUSR2, &sa, NULL) < 0)
355: DPRINTF("sigaction(usr2) failed1n");
356: #endif
357: }
358:
359: void
360: unsetsig(void)
361: {
362: struct sigaction sa;
363:
364: sigfillset(&sa.sa_mask);
365: sa.sa_flags = SA_RESTART;
366: sa.sa_handler = SIG_DFL;
367: #ifdef DEBUG
368: if (sigaction(SIGUSR2, &sa, NULL) < 0)
369: DPRINTF("unsetsig(usr2): sigaction failed\n");
370: if (sigaction(SIGUSR1, &sa, NULL) < 0)
371: DPRINTF("unsetsig(usr1): sigaction failed\n");
372: #endif
373: if (sigaction(SIGHUP, &sa, NULL) < 0)
374: DPRINTF("unsetsig(hup): sigaction failed\n");
375: if (sigaction(SIGTERM, &sa, NULL) < 0)
376: DPRINTF("unsetsig(term): sigaction failed\n");
377: if (sigaction(SIGINT, &sa, NULL) < 0)
378: DPRINTF("unsetsig(int): sigaction failed\n");
379: }
380:
381: void
382: getbasepath(char *base, size_t size)
383: {
384: uid_t uid;
385: struct stat sb;
386:
387: uid = geteuid();
388: snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
389: if (mkdir(base, 0700) < 0) {
390: if (errno != EEXIST)
391: err(1, "mkdir(\"%s\")", base);
392: }
393: if (stat(base, &sb) < 0)
394: err(1, "stat(\"%s\")", base);
395: if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
396: errx(1, "%s has wrong permissions", base);
397: }
398:
399: void
400: aucat_usage(void)
401: {
402: (void)fputs("usage: " PROG_AUCAT " [-lnu] [-b nframes] "
403: "[-C min:max] [-c min:max] [-e enc] [-f device]\n"
404: "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s socket]\n"
405: "\t[-U unit] [-v volume] [-x policy]\n",
406: stderr);
407: }
408:
1.1 kstailey 409: int
1.61 ratchov 410: aucat_main(int argc, char **argv)
1.1 kstailey 411: {
1.61 ratchov 412: int c, u_flag, l_flag, n_flag, hdr, xrun, suspend = 0, unit;
1.15 ratchov 413: struct farg *fa;
1.63 ! ratchov 414: struct farglist ifiles, ofiles, sfiles;
1.26 ratchov 415: struct aparams ipar, opar, dipar, dopar;
1.55 ratchov 416: char base[PATH_MAX], path[PATH_MAX];
1.43 ratchov 417: unsigned bufsz, mode;
1.61 ratchov 418: char *devpath;
1.40 ratchov 419: unsigned volctl;
1.19 ratchov 420:
1.15 ratchov 421: aparams_init(&ipar, 0, 1, 44100);
422: aparams_init(&opar, 0, 1, 44100);
1.26 ratchov 423: u_flag = 0;
1.28 ratchov 424: l_flag = 0;
1.51 ratchov 425: n_flag = 0;
1.61 ratchov 426: unit = -1;
1.15 ratchov 427: devpath = NULL;
428: SLIST_INIT(&ifiles);
429: SLIST_INIT(&ofiles);
1.42 ratchov 430: SLIST_INIT(&sfiles);
1.28 ratchov 431: hdr = HDR_AUTO;
432: xrun = XRUN_IGNORE;
1.40 ratchov 433: volctl = MIDI_MAXCTL;
1.32 ratchov 434: bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */
1.43 ratchov 435: mode = 0;
1.15 ratchov 436:
1.61 ratchov 437: while ((c = getopt(argc, argv, "nb:c:C:e:r:h:x:v:i:o:f:m:lus:U:")) != -1) {
1.15 ratchov 438: switch (c) {
1.51 ratchov 439: case 'n':
440: n_flag = 1;
441: break;
1.43 ratchov 442: case 'm':
443: mode = opt_mode();
444: break;
1.15 ratchov 445: case 'h':
1.28 ratchov 446: hdr = opt_hdr();
1.15 ratchov 447: break;
1.22 ratchov 448: case 'x':
1.28 ratchov 449: xrun = opt_xrun();
1.22 ratchov 450: break;
1.15 ratchov 451: case 'c':
452: opt_ch(&ipar);
453: break;
454: case 'C':
455: opt_ch(&opar);
456: break;
457: case 'e':
458: opt_enc(&ipar);
1.28 ratchov 459: aparams_copyenc(&opar, &ipar);
1.15 ratchov 460: break;
461: case 'r':
462: opt_rate(&ipar);
1.28 ratchov 463: opar.rate = ipar.rate;
1.15 ratchov 464: break;
1.35 ratchov 465: case 'v':
1.40 ratchov 466: opt_vol(&volctl);
1.35 ratchov 467: break;
1.15 ratchov 468: case 'i':
1.42 ratchov 469: farg_add(&ifiles, &ipar, &opar, volctl,
470: hdr, xrun, optarg);
1.15 ratchov 471: break;
472: case 'o':
1.42 ratchov 473: farg_add(&ofiles, &ipar, &opar, volctl,
474: hdr, xrun, optarg);
475: break;
476: case 's':
477: farg_add(&sfiles, &ipar, &opar, volctl,
478: hdr, xrun, optarg);
1.15 ratchov 479: break;
1.4 millert 480: case 'f':
1.15 ratchov 481: if (devpath)
482: err(1, "only one -f allowed");
483: devpath = optarg;
1.28 ratchov 484: dipar = opar;
485: dopar = ipar;
1.15 ratchov 486: break;
1.28 ratchov 487: case 'l':
488: l_flag = 1;
1.17 jakemsr 489: break;
1.15 ratchov 490: case 'u':
491: u_flag = 1;
1.4 millert 492: break;
1.28 ratchov 493: case 'b':
1.32 ratchov 494: if (sscanf(optarg, "%u", &bufsz) != 1 || bufsz == 0) {
1.28 ratchov 495: fprintf(stderr, "%s: bad buf size\n", optarg);
496: exit(1);
497: }
498: break;
1.61 ratchov 499: case 'U':
500: if (sscanf(optarg, "%u", &unit) != 1) {
501: fprintf(stderr, "%s: bad device number\n", optarg);
502: exit(1);
503: }
504: break;
1.11 jaredy 505: default:
1.61 ratchov 506: aucat_usage();
1.15 ratchov 507: exit(1);
1.4 millert 508: }
509: }
510: argc -= optind;
511: argv += optind;
512:
1.15 ratchov 513: if (!devpath) {
1.47 ratchov 514: dopar = ipar;
515: dipar = opar;
1.15 ratchov 516: }
1.28 ratchov 517: if (!l_flag && SLIST_EMPTY(&ifiles) &&
518: SLIST_EMPTY(&ofiles) && argc > 0) {
1.15 ratchov 519: /*
520: * Legacy mode: if no -i or -o options are provided, and
521: * there are arguments then assume the arguments are files
522: * to play.
523: */
524: for (c = 0; c < argc; c++)
525: if (legacy_play(devpath, argv[c]) != 0) {
1.17 jakemsr 526: errx(1, "%s: could not play\n", argv[c]);
1.15 ratchov 527: }
528: exit(0);
529: } else if (argc > 0) {
1.61 ratchov 530: aucat_usage();
1.15 ratchov 531: exit(1);
532: }
533:
1.61 ratchov 534: if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0))
535: errx(1, "can't use -s or -U without -l");
1.43 ratchov 536: if ((l_flag || mode != 0) &&
537: (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
538: errx(1, "can't use -l, -m and -s with -o or -i");
539: if (!mode) {
540: if (l_flag || !SLIST_EMPTY(&ifiles))
1.58 ratchov 541: mode |= MODE_PLAY;
1.43 ratchov 542: if (l_flag || !SLIST_EMPTY(&ofiles))
543: mode |= MODE_REC;
1.61 ratchov 544: if (!mode) {
545: aucat_usage();
546: exit(1);
547: }
1.43 ratchov 548: }
1.51 ratchov 549: if (n_flag) {
550: if (devpath != NULL || l_flag)
551: errx(1, "can't use -n with -f or -l");
552: if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
553: errx(1, "both -i and -o are required with -n");
554: }
1.15 ratchov 555:
1.46 ratchov 556: /*
1.62 ratchov 557: * If there are no sockets paths provided use the default.
1.46 ratchov 558: */
559: if (l_flag && SLIST_EMPTY(&sfiles)) {
560: farg_add(&sfiles, &dopar, &dipar,
1.61 ratchov 561: volctl, HDR_RAW, XRUN_IGNORE, DEFAULT_OPT);
1.46 ratchov 562: }
563:
564: if (!u_flag) {
1.26 ratchov 565: /*
566: * Calculate "best" device parameters. Iterate over all
567: * inputs and outputs and find the maximum sample rate
568: * and channel number.
569: */
1.49 ratchov 570: aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
571: aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
1.26 ratchov 572: SLIST_FOREACH(fa, &ifiles, entry) {
1.46 ratchov 573: aparams_grow(&dopar, &fa->ipar);
1.26 ratchov 574: }
575: SLIST_FOREACH(fa, &ofiles, entry) {
1.46 ratchov 576: aparams_grow(&dipar, &fa->opar);
577: }
578: SLIST_FOREACH(fa, &sfiles, entry) {
579: aparams_grow(&dopar, &fa->ipar);
580: aparams_grow(&dipar, &fa->opar);
1.17 jakemsr 581: }
1.42 ratchov 582: }
583:
1.55 ratchov 584: if (l_flag) {
1.61 ratchov 585: getbasepath(base, sizeof(base));
586: if (unit < 0)
587: unit = 0;
1.55 ratchov 588: }
1.61 ratchov 589: setsig();
1.28 ratchov 590: filelist_init();
1.51 ratchov 591:
1.15 ratchov 592: /*
1.32 ratchov 593: * Open the device. Give half of the buffer to the device,
1.62 ratchov 594: * the other half is for the socket/files.
1.15 ratchov 595: */
1.51 ratchov 596: if (n_flag) {
597: dev_loopinit(&dipar, &dopar, bufsz);
598: } else {
1.58 ratchov 599: if (!dev_init(devpath,
600: (mode & MODE_REC) ? &dipar : NULL,
601: (mode & MODE_PLAY) ? &dopar : NULL,
602: bufsz)) {
603: errx(1, "%s: can't open device",
604: devpath ? devpath : "<default>");
605: }
1.51 ratchov 606: }
1.52 ratchov 607:
1.15 ratchov 608: /*
609: * Create buffers for all input and output pipes.
610: */
1.26 ratchov 611: while (!SLIST_EMPTY(&ifiles)) {
612: fa = SLIST_FIRST(&ifiles);
613: SLIST_REMOVE_HEAD(&ifiles, entry);
614: newinput(fa);
615: free(fa);
616: }
617: while (!SLIST_EMPTY(&ofiles)) {
618: fa = SLIST_FIRST(&ofiles);
619: SLIST_REMOVE_HEAD(&ofiles, entry);
620: newoutput(fa);
1.42 ratchov 621: free(fa);
622: }
623: while (!SLIST_EMPTY(&sfiles)) {
624: fa = SLIST_FIRST(&sfiles);
625: SLIST_REMOVE_HEAD(&sfiles, entry);
1.61 ratchov 626: opt_new(fa->name, &fa->opar, &fa->ipar, MIDI_TO_ADATA(fa->vol));
1.26 ratchov 627: free(fa);
1.56 ratchov 628: }
1.61 ratchov 629: if (l_flag) {
630: snprintf(path, sizeof(path), "%s/%s%u", base,
631: DEFAULT_SOFTAUDIO, unit);
632: listen_new(&listen_ops, path);
633: if (debug_level == 0 && daemon(0, 0) < 0)
1.56 ratchov 634: err(1, "daemon");
1.15 ratchov 635: }
1.13 uwe 636:
1.15 ratchov 637: /*
1.62 ratchov 638: * Loop, start audio.
1.15 ratchov 639: */
1.28 ratchov 640: for (;;) {
641: if (quit_flag) {
642: break;
643: }
1.50 ratchov 644: if ((!dev_rec || dev_rec->u.io.file == NULL) &&
1.51 ratchov 645: (!dev_play || dev_play->u.io.file == NULL) && !n_flag) {
1.50 ratchov 646: fprintf(stderr, "device desappeared, terminating\n");
647: break;
1.38 ratchov 648: }
1.50 ratchov 649: if (!file_poll())
650: break;
1.34 ratchov 651: if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
652: (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz)) {
1.37 ratchov 653: if (!l_flag)
654: break;
1.34 ratchov 655: if (!suspend) {
656: DPRINTF("suspending\n");
657: suspend = 1;
658: dev_stop();
659: dev_clear();
660: }
661: }
662: if ((dev_mix && dev_mix->u.mix.idle == 0) ||
663: (dev_sub && dev_sub->u.sub.idle == 0)) {
664: if (suspend) {
665: DPRINTF("resuming\n");
666: suspend = 0;
667: dev_start();
668: }
669: }
670: }
1.55 ratchov 671: if (l_flag) {
1.50 ratchov 672: filelist_unlisten();
1.55 ratchov 673: if (rmdir(base) < 0)
674: warn("rmdir(\"%s\")", base);
675: }
1.34 ratchov 676: if (suspend) {
677: DPRINTF("resuming to drain\n");
678: suspend = 0;
679: dev_start();
1.28 ratchov 680: }
1.51 ratchov 681: if (n_flag) {
682: dev_loopdone();
683: } else
684: dev_done();
1.28 ratchov 685: filelist_done();
1.61 ratchov 686: unsetsig();
687: return 0;
688: }
689:
690: void
691: midicat_usage(void)
692: {
693: (void)fputs("usage: " PROG_MIDICAT " [-l] [-f device] "
694: "[-i file] [-o file] [-U unit]\n",
695: stderr);
696: }
697: int
698: midicat_main(int argc, char **argv)
699: {
700: int c, l_flag, unit, fd;
1.63 ! ratchov 701: struct farglist dfiles;
1.61 ratchov 702: char base[PATH_MAX], path[PATH_MAX];
1.63 ! ratchov 703: char *input, *output;
! 704: struct farg *fa;
! 705: struct file *stdx, *f;
! 706: struct aproc *p;
1.61 ratchov 707: struct abuf *buf;
708:
709: l_flag = 0;
710: unit = -1;
711: output = NULL;
712: input = NULL;
1.63 ! ratchov 713: SLIST_INIT(&dfiles);
1.61 ratchov 714:
715: while ((c = getopt(argc, argv, "i:o:lf:U:")) != -1) {
716: switch (c) {
717: case 'i':
718: if (input != NULL)
719: errx(1, "only one -i allowed");
720: input = optarg;
721: break;
722: case 'o':
723: if (output != NULL)
724: errx(1, "only one -o allowed");
725: output = optarg;
726: break;
727: case 'f':
1.63 ! ratchov 728: farg_add(&dfiles, &aparams_none, &aparams_none,
! 729: HDR_RAW, 0, 0, optarg);
1.61 ratchov 730: break;
731: case 'l':
732: l_flag = 1;
733: break;
734: case 'U':
735: if (sscanf(optarg, "%u", &unit) != 1) {
736: fprintf(stderr, "%s: bad device number\n", optarg);
737: exit(1);
738: }
739: break;
740: default:
741: midicat_usage();
742: exit(1);
743: }
744: }
745: argc -= optind;
746: argv += optind;
747:
748: if (argc > 0 || (!input && !output && !l_flag)) {
749: midicat_usage();
750: exit(1);
751: }
752: if (!l_flag && unit >= 0)
753: errx(1, "can't use -U without -l");
754: if (l_flag) {
755: if (input || output)
756: errx(1, "can't use -i or -o with -l");
757: getbasepath(base, sizeof(path));
758: if (unit < 0)
759: unit = 0;
760: }
761: setsig();
762: filelist_init();
763:
1.63 ! ratchov 764: thrubox = thru_new("thru");
! 765: thrubox->refs++;
! 766:
! 767: if ((input || output) && SLIST_EMPTY(&dfiles)) {
! 768: farg_add(&dfiles, &aparams_none, &aparams_none,
! 769: 0, HDR_RAW, 0, NULL);
! 770: }
! 771:
! 772: while (!SLIST_EMPTY(&dfiles)) {
! 773: fa = SLIST_FIRST(&dfiles);
! 774: SLIST_REMOVE_HEAD(&dfiles, entry);
! 775: newmidi(fa, output || l_flag, input || l_flag);
! 776: free(fa);
! 777: }
! 778:
1.61 ratchov 779: if (l_flag) {
780: snprintf(path, sizeof(path), "%s/%s%u", base,
781: DEFAULT_MIDITHRU, unit);
782: listen_new(&listen_ops, path);
783: if (debug_level == 0 && daemon(0, 0) < 0)
784: err(1, "daemon");
785: }
786: if (input) {
787: if (strcmp(input, "-") == 0) {
788: fd = STDIN_FILENO;
789: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
790: warn("stdin");
791: } else {
792: fd = open(input, O_RDONLY | O_NONBLOCK, 0666);
793: if (fd < 0)
794: err(1, "%s", input);
795: }
796: stdx = (struct file *)pipe_new(&pipe_ops, fd, "stdin");
797: p = rpipe_new(stdx);
1.63 ! ratchov 798: buf = abuf_new(3125, &aparams_none);
1.61 ratchov 799: aproc_setout(p, buf);
1.63 ! ratchov 800: aproc_setin(thrubox, buf);
! 801: }
1.61 ratchov 802: if (output) {
803: if (strcmp(output, "-") == 0) {
804: fd = STDOUT_FILENO;
805: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
806: warn("stdout");
807: } else {
808: fd = open(output,
809: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
810: if (fd < 0)
811: err(1, "%s", output);
812: }
813: stdx = (struct file *)pipe_new(&pipe_ops, fd, "stdout");
814: p = wpipe_new(stdx);
1.63 ! ratchov 815: buf = abuf_new(3125, &aparams_none);
1.61 ratchov 816: aproc_setin(p, buf);
1.63 ! ratchov 817: aproc_setout(thrubox, buf);
! 818: }
1.11 jaredy 819:
1.61 ratchov 820: /*
821: * loop, start processing
822: */
823: for (;;) {
824: if (quit_flag) {
825: break;
826: }
1.63 ! ratchov 827: if (!l_flag && LIST_EMPTY(&thrubox->ibuflist))
! 828: break;
1.61 ratchov 829: if (!file_poll())
830: break;
831: }
832: if (l_flag) {
833: filelist_unlisten();
834: if (rmdir(base) < 0)
835: warn("rmdir(\"%s\")", base);
836: }
837: if (thrubox) {
838: restart_thrubox:
839: LIST_FOREACH(f, &file_list, entry) {
840: if (f->rproc && aproc_depend(thrubox, f->rproc)) {
841: file_eof(f);
842: goto restart_thrubox;
843: }
844: }
845: while (!LIST_EMPTY(&thrubox->ibuflist)) {
846: if (!file_poll())
847: break;
848: }
849: thrubox->refs--;
850: aproc_del(thrubox);
851: thrubox = NULL;
852: while (file_poll())
853: ; /* nothing */
854: }
855: filelist_done();
856: unsetsig();
1.15 ratchov 857: return 0;
1.61 ratchov 858: }
859:
860:
861: int
862: main(int argc, char **argv)
863: {
864: char *prog;
865:
866: prog = strrchr(argv[0], '/');
867: if (prog == NULL)
868: prog = argv[0];
869: else
870: prog++;
871: if (strcmp(prog, PROG_AUCAT) == 0) {
872: set_debug_level("AUCAT_DEBUG");
873: return aucat_main(argc, argv);
874: } else if (strcmp(prog, PROG_MIDICAT) == 0) {
875: set_debug_level("MIDICAT_DEBUG");
876: return midicat_main(argc, argv);
877: } else {
878: fprintf(stderr, "%s: can't determine program to run\n", prog);
879: }
880: return 1;
1.1 kstailey 881: }