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