Annotation of src/usr.bin/aucat/aucat.c, Revision 1.142
1.140 ratchov 1: /* $OpenBSD$ */
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.86 ratchov 21: #include <sys/resource.h>
1.13 uwe 22:
1.15 ratchov 23: #include <err.h>
1.55 ratchov 24: #include <errno.h>
1.1 kstailey 25: #include <fcntl.h>
1.138 ratchov 26: #include <grp.h>
1.55 ratchov 27: #include <limits.h>
1.86 ratchov 28: #include <pwd.h>
1.15 ratchov 29: #include <signal.h>
1.135 ratchov 30: #include <sndio.h>
1.1 kstailey 31: #include <stdio.h>
1.4 millert 32: #include <stdlib.h>
1.8 david 33: #include <string.h>
1.1 kstailey 34: #include <unistd.h>
35:
1.62 ratchov 36: #include "abuf.h"
1.112 ratchov 37: #include "amsg.h"
1.15 ratchov 38: #include "aparams.h"
39: #include "aproc.h"
1.62 ratchov 40: #include "conf.h"
41: #include "dev.h"
1.61 ratchov 42: #include "midi.h"
1.62 ratchov 43: #include "wav.h"
1.78 ratchov 44: #ifdef DEBUG
45: #include "dbg.h"
46: #endif
1.11 jaredy 47:
1.61 ratchov 48: #define PROG_AUCAT "aucat"
49:
1.108 ratchov 50: /*
51: * sample rate if no ``-r'' is used
52: */
53: #ifndef DEFAULT_RATE
1.132 ratchov 54: #define DEFAULT_RATE 48000
1.108 ratchov 55: #endif
56:
1.120 ratchov 57: /*
1.133 ratchov 58: * block size if neither ``-z'' nor ``-b'' is used
1.120 ratchov 59: */
60: #ifndef DEFAULT_ROUND
1.133 ratchov 61: #define DEFAULT_ROUND 960
62: #endif
63:
64: /*
65: * buffer size if neither ``-z'' nor ``-b'' is used
66: */
67: #ifndef DEFAULT_BUFSZ
68: #define DEFAULT_BUFSZ 7860
1.120 ratchov 69: #endif
70:
1.78 ratchov 71: #ifdef DEBUG
1.120 ratchov 72: volatile sig_atomic_t debug_level = 1;
1.78 ratchov 73: #endif
1.111 deraadt 74: volatile sig_atomic_t quit_flag = 0;
1.7 deraadt 75:
1.142 ! ratchov 76: char aucat_usage[] = "usage: " PROG_AUCAT " [-dMn]\n\t"
1.141 ratchov 77: "[-C min:max] [-c min:max] [-e enc] [-f device]\n\t"
1.142 ! ratchov 78: "[-h fmt] [-i file] [-j flag] [-o file] [-q port]\n\t"
1.141 ratchov 79: "[-r rate] [-t mode] [-v volume] [-w flag] [-x policy]\n";
1.129 ratchov 80:
1.28 ratchov 81: /*
82: * SIGINT handler, it raises the quit flag. If the flag is already set,
83: * that means that the last SIGINT was not handled, because the process
1.62 ratchov 84: * is blocked somewhere, so exit.
1.28 ratchov 85: */
86: void
87: sigint(int s)
88: {
89: if (quit_flag)
90: _exit(1);
91: quit_flag = 1;
92: }
1.22 ratchov 93:
1.78 ratchov 94: #ifdef DEBUG
95: /*
96: * Increase debug level on SIGUSR1.
97: */
98: void
99: sigusr1(int s)
100: {
101: if (debug_level < 4)
102: debug_level++;
103: }
104:
105: /*
106: * Decrease debug level on SIGUSR2.
107: */
108: void
109: sigusr2(int s)
110: {
111: if (debug_level > 0)
112: debug_level--;
113: }
114: #endif
1.15 ratchov 115:
116: void
117: opt_ch(struct aparams *par)
118: {
1.76 ratchov 119: char *next, *end;
120: long cmin, cmax;
1.13 uwe 121:
1.76 ratchov 122: errno = 0;
123: cmin = strtol(optarg, &next, 10);
124: if (next == optarg || *next != ':')
125: goto failed;
126: cmax = strtol(++next, &end, 10);
127: if (end == next || *end != '\0')
128: goto failed;
129: if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
130: goto failed;
131: par->cmin = cmin;
132: par->cmax = cmax;
133: return;
134: failed:
135: errx(1, "%s: bad channel range", optarg);
1.15 ratchov 136: }
1.13 uwe 137:
1.15 ratchov 138: void
139: opt_enc(struct aparams *par)
140: {
1.28 ratchov 141: int len;
142:
143: len = aparams_strtoenc(par, optarg);
144: if (len == 0 || optarg[len] != '\0')
145: errx(1, "%s: bad encoding", optarg);
1.15 ratchov 146: }
1.4 millert 147:
1.15 ratchov 148: int
149: opt_hdr(void)
150: {
151: if (strcmp("auto", optarg) == 0)
152: return HDR_AUTO;
153: if (strcmp("raw", optarg) == 0)
154: return HDR_RAW;
155: if (strcmp("wav", optarg) == 0)
156: return HDR_WAV;
1.35 ratchov 157: errx(1, "%s: bad header specification", optarg);
1.1 kstailey 158: }
159:
1.22 ratchov 160: int
1.74 ratchov 161: opt_mmc(void)
162: {
163: if (strcmp("off", optarg) == 0)
164: return 0;
165: if (strcmp("slave", optarg) == 0)
166: return 1;
167: errx(1, "%s: bad MMC mode", optarg);
168: }
169:
170: int
1.90 ratchov 171: opt_onoff(void)
1.84 ratchov 172: {
173: if (strcmp("off", optarg) == 0)
174: return 0;
175: if (strcmp("on", optarg) == 0)
176: return 1;
177: errx(1, "%s: bad join/expand setting", optarg);
178: }
179:
180: int
1.22 ratchov 181: opt_xrun(void)
182: {
183: if (strcmp("ignore", optarg) == 0)
184: return XRUN_IGNORE;
185: if (strcmp("sync", optarg) == 0)
186: return XRUN_SYNC;
187: if (strcmp("error", optarg) == 0)
188: return XRUN_ERROR;
1.73 ratchov 189: errx(1, "%s: bad underrun/overrun policy", optarg);
1.22 ratchov 190: }
191:
1.113 ratchov 192: void
1.61 ratchov 193: setsig(void)
194: {
195: struct sigaction sa;
196:
197: quit_flag = 0;
198: sigfillset(&sa.sa_mask);
199: sa.sa_flags = SA_RESTART;
200: sa.sa_handler = sigint;
201: if (sigaction(SIGINT, &sa, NULL) < 0)
1.68 ratchov 202: err(1, "sigaction(int) failed");
1.61 ratchov 203: if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68 ratchov 204: err(1, "sigaction(term) failed");
1.61 ratchov 205: if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68 ratchov 206: err(1, "sigaction(hup) failed");
1.78 ratchov 207: #ifdef DEBUG
208: sa.sa_handler = sigusr1;
209: if (sigaction(SIGUSR1, &sa, NULL) < 0)
210: err(1, "sigaction(usr1) failed");
211: sa.sa_handler = sigusr2;
212: if (sigaction(SIGUSR2, &sa, NULL) < 0)
213: err(1, "sigaction(usr2) failed1n");
214: #endif
1.61 ratchov 215: }
216:
217: void
218: unsetsig(void)
219: {
220: struct sigaction sa;
221:
222: sigfillset(&sa.sa_mask);
223: sa.sa_flags = SA_RESTART;
224: sa.sa_handler = SIG_DFL;
1.78 ratchov 225: #ifdef DEBUG
226: if (sigaction(SIGUSR2, &sa, NULL) < 0)
227: err(1, "unsetsig(usr2): sigaction failed");
228: if (sigaction(SIGUSR1, &sa, NULL) < 0)
229: err(1, "unsetsig(usr1): sigaction failed");
230: #endif
1.61 ratchov 231: if (sigaction(SIGHUP, &sa, NULL) < 0)
1.68 ratchov 232: err(1, "unsetsig(hup): sigaction failed\n");
1.61 ratchov 233: if (sigaction(SIGTERM, &sa, NULL) < 0)
1.68 ratchov 234: err(1, "unsetsig(term): sigaction failed\n");
1.61 ratchov 235: if (sigaction(SIGINT, &sa, NULL) < 0)
1.68 ratchov 236: err(1, "unsetsig(int): sigaction failed\n");
1.61 ratchov 237: }
238:
1.120 ratchov 239: struct dev *
240: mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol)
1.61 ratchov 241: {
1.120 ratchov 242: struct dev *d;
243:
244: if (path) {
245: for (d = dev_list; d != NULL; d = d->next) {
246: if (d->reqmode & (MODE_LOOP | MODE_THRU))
247: continue;
248: if (strcmp(d->path, path) == 0)
249: return d;
250: }
251: } else {
252: if (dev_list)
253: return dev_list;
1.135 ratchov 254: path = SIO_DEVANY;
1.120 ratchov 255: }
1.133 ratchov 256: if (!bufsz && !round) {
257: round = DEFAULT_ROUND;
258: bufsz = DEFAULT_BUFSZ;
259: } else if (!bufsz) {
1.132 ratchov 260: bufsz = round * 2;
1.120 ratchov 261: } else if (!round)
1.132 ratchov 262: round = bufsz / 2;
1.125 ratchov 263: d = dev_new(path, mode, bufsz, round, hold, autovol);
264: if (d == NULL)
265: exit(1);
266: return d;
1.120 ratchov 267: }
268:
1.1 kstailey 269: int
1.120 ratchov 270: main(int argc, char **argv)
1.1 kstailey 271: {
1.128 ratchov 272: int c, background, unit, active;
1.134 ratchov 273: unsigned int mode, hdr, xrun, rate, join, mmc, vol;
274: unsigned int hold, autovol, bufsz, round;
1.76 ratchov 275: const char *str;
1.120 ratchov 276: struct aparams ppar, rpar;
1.92 ratchov 277: struct dev *d, *dnext;
1.120 ratchov 278: struct wav *w;
1.19 ratchov 279:
1.92 ratchov 280: /*
281: * global options defaults
282: */
1.120 ratchov 283: hdr = HDR_AUTO;
284: xrun = XRUN_IGNORE;
285: vol = MIDI_MAXCTL;
1.124 ratchov 286: join = 1;
1.120 ratchov 287: mmc = 0;
1.124 ratchov 288: hold = 0;
289: autovol = 1;
1.120 ratchov 290: bufsz = 0;
291: round = 0;
292: unit = 0;
293: background = 0;
294: aparams_init(&ppar, 0, 1, DEFAULT_RATE);
295: aparams_init(&rpar, 0, 1, DEFAULT_RATE);
1.123 ratchov 296: mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC;
1.120 ratchov 297:
298: #ifdef DEBUG
299: atexit(dbg_flush);
300: #endif
301: setsig();
302: filelist_init();
303:
1.142 ! ratchov 304: while ((c = getopt(argc, argv,
! 305: "a:b:c:C:de:f:h:i:j:Mno:q:r:t:v:w:x:z:")) != -1) {
1.15 ratchov 306: switch (c) {
1.69 ratchov 307: case 'd':
1.78 ratchov 308: #ifdef DEBUG
1.120 ratchov 309: if (debug_level < 4)
1.78 ratchov 310: debug_level++;
311: #endif
1.129 ratchov 312: background = 0;
1.51 ratchov 313: break;
1.15 ratchov 314: case 'h':
1.120 ratchov 315: hdr = opt_hdr();
1.15 ratchov 316: break;
1.22 ratchov 317: case 'x':
1.120 ratchov 318: xrun = opt_xrun();
1.22 ratchov 319: break;
1.84 ratchov 320: case 'j':
1.120 ratchov 321: join = opt_onoff();
1.84 ratchov 322: break;
1.74 ratchov 323: case 't':
1.120 ratchov 324: mmc = opt_mmc();
1.74 ratchov 325: break;
1.15 ratchov 326: case 'c':
1.120 ratchov 327: opt_ch(&ppar);
1.15 ratchov 328: break;
329: case 'C':
1.120 ratchov 330: opt_ch(&rpar);
1.15 ratchov 331: break;
332: case 'e':
1.120 ratchov 333: opt_enc(&ppar);
334: aparams_copyenc(&rpar, &ppar);
1.15 ratchov 335: break;
336: case 'r':
1.92 ratchov 337: rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
1.76 ratchov 338: if (str)
339: errx(1, "%s: rate is %s", optarg, str);
1.120 ratchov 340: ppar.rate = rpar.rate = rate;
1.15 ratchov 341: break;
1.35 ratchov 342: case 'v':
1.120 ratchov 343: vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
1.76 ratchov 344: if (str)
345: errx(1, "%s: volume is %s", optarg, str);
1.35 ratchov 346: break;
1.15 ratchov 347: case 'i':
1.120 ratchov 348: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
349: w = wav_new_in(&wav_ops, d,
350: mode & (MODE_PLAY | MODE_MIDIOUT), optarg,
351: hdr, &ppar, xrun, vol, mmc, join);
352: if (w == NULL)
353: errx(1, "%s: couldn't create stream", optarg);
354: dev_adjpar(d, w->mode, NULL, &w->hpar);
355: break;
356: case 'o':
357: d = mkdev(NULL, 0, bufsz, round, 1, autovol);
358: w = wav_new_out(&wav_ops, d,
359: mode & (MODE_RECMASK | MODE_MIDIIN), optarg,
360: hdr, &rpar, xrun, mmc, join);
361: if (w == NULL)
362: errx(1, "%s: couldn't create stream", optarg);
363: dev_adjpar(d, w->mode, &w->hpar, NULL);
1.15 ratchov 364: break;
1.120 ratchov 365: case 'q':
366: d = mkdev(NULL, mode, bufsz, round, 1, autovol);
367: if (!devctl_add(d, optarg, MODE_MIDIMASK))
368: errx(1, "%s: can't open port", optarg);
369: d->reqmode |= MODE_MIDIMASK;
1.92 ratchov 370: break;
1.115 ratchov 371: case 'w':
1.120 ratchov 372: autovol = opt_onoff();
1.4 millert 373: break;
1.28 ratchov 374: case 'b':
1.120 ratchov 375: bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
1.76 ratchov 376: if (str)
377: errx(1, "%s: buffer size is %s", optarg, str);
1.28 ratchov 378: break;
1.74 ratchov 379: case 'z':
1.120 ratchov 380: round = strtonum(optarg, 1, SHRT_MAX, &str);
1.76 ratchov 381: if (str)
382: errx(1, "%s: block size is %s", optarg, str);
1.74 ratchov 383: break;
1.92 ratchov 384: case 'f':
1.120 ratchov 385: mkdev(optarg, 0, bufsz, round, hold, autovol);
386: break;
387: case 'n':
388: mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
389: break;
390: case 'M':
1.127 ratchov 391: mkdev("midithru", MODE_THRU, 0, 0, hold, 0);
1.92 ratchov 392: break;
1.11 jaredy 393: default:
1.142 ! ratchov 394: fputs(aucat_usage, stderr);
1.15 ratchov 395: exit(1);
1.4 millert 396: }
397: }
398: argc -= optind;
399: argv += optind;
1.92 ratchov 400: if (argc > 0) {
1.142 ! ratchov 401: fputs(aucat_usage, stderr);
1.102 ratchov 402: exit(1);
1.15 ratchov 403: }
1.125 ratchov 404: if (wav_list) {
405: if ((d = dev_list) && d->next)
1.142 ! ratchov 406: errx(1, "only one device allowed");
1.125 ratchov 407: if ((d->reqmode & MODE_THRU) && d->ctl_list == NULL) {
1.120 ratchov 408: if (!devctl_add(d, "default", MODE_MIDIMASK))
409: errx(1, "%s: can't open port", optarg);
410: d->reqmode |= MODE_MIDIMASK;
1.125 ratchov 411: }
412: } else {
1.142 ! ratchov 413: fputs(aucat_usage, stderr);
! 414: exit(1);
1.120 ratchov 415: }
416: for (w = wav_list; w != NULL; w = w->next) {
417: if (!wav_init(w))
418: exit(1);
1.55 ratchov 419: }
1.120 ratchov 420: for (d = dev_list; d != NULL; d = d->next) {
421: if (!dev_init(d))
422: exit(1);
423: if (d->autostart && (d->mode & MODE_AUDIOMASK))
1.126 ratchov 424: dev_mmcstart(d);
1.56 ratchov 425: }
1.13 uwe 426:
1.15 ratchov 427: /*
1.62 ratchov 428: * Loop, start audio.
1.15 ratchov 429: */
1.28 ratchov 430: for (;;) {
1.90 ratchov 431: if (quit_flag)
1.28 ratchov 432: break;
1.92 ratchov 433: active = 0;
434: for (d = dev_list; d != NULL; d = dnext) {
435: dnext = d->next;
436: if (!dev_run(d))
437: goto fatal;
1.127 ratchov 438: if (d->refcnt > 0)
1.92 ratchov 439: active = 1;
440: }
441: if (dev_list == NULL)
1.50 ratchov 442: break;
1.142 ! ratchov 443: if (!active)
1.83 ratchov 444: break;
1.50 ratchov 445: if (!file_poll())
446: break;
1.34 ratchov 447: }
1.92 ratchov 448: fatal:
1.110 ratchov 449:
1.90 ratchov 450: /*
451: * give a chance to drain
452: */
1.96 ratchov 453: for (d = dev_list; d != NULL; d = d->next)
454: dev_drain(d);
1.90 ratchov 455: while (file_poll())
456: ; /* nothing */
1.96 ratchov 457:
458: while (dev_list)
459: dev_del(dev_list);
1.83 ratchov 460: filelist_done();
1.61 ratchov 461: unsetsig();
462: return 0;
1.1 kstailey 463: }