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