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