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