Annotation of src/usr.bin/aucat/aucat.c, Revision 1.55
1.55 ! ratchov 1: /* $OpenBSD: aucat.c,v 1.54 2009/01/25 17:07:39 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: /*
18: * TODO:
19: *
20: * (hard) use parsable encoding names instead of the lookup
21: * table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example
22: * s8, s16le, s24le/3msb. This would give names that correspond to
23: * what use most linux-centric apps, but for which we have an
24: * algorithm to convert the name to a aparams structure.
25: *
26: * (easy) uses {chmin-chmax} instead of chmin:chmax notation for
27: * channels specification to match the notation used in rmix.
28: *
29: * (easy) use comma-separated parameters syntax, example:
30: * s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c
31: * flags, but only one -p flag that specify one or more parameters.
32: *
33: * (hard) if all inputs are over, the mixer terminates and closes
34: * the write end of the device. It should continue writing zeros
35: * until the recording is over (or be able to stop write end of
36: * the device)
37: *
38: * (hard) implement -n flag (no device) to connect all inputs to
39: * the outputs.
40: *
41: * (hard) ignore input files that are not audible (because channels
42: * they provide are not used on the output). Similarly ignore
43: * outputs that are zero filled (because channels they consume are
44: * not provided).
1.1 kstailey 45: */
46:
1.15 ratchov 47: #include <sys/param.h>
1.1 kstailey 48: #include <sys/types.h>
1.15 ratchov 49: #include <sys/queue.h>
1.55 ! ratchov 50: #include <sys/stat.h>
1.13 uwe 51:
1.15 ratchov 52: #include <err.h>
1.55 ! ratchov 53: #include <errno.h>
1.1 kstailey 54: #include <fcntl.h>
1.55 ! ratchov 55: #include <limits.h>
1.15 ratchov 56: #include <signal.h>
1.1 kstailey 57: #include <stdio.h>
1.4 millert 58: #include <stdlib.h>
1.8 david 59: #include <string.h>
1.1 kstailey 60: #include <unistd.h>
1.15 ratchov 61: #include <varargs.h>
1.1 kstailey 62:
1.15 ratchov 63: #include "conf.h"
64: #include "aparams.h"
65: #include "aproc.h"
66: #include "abuf.h"
1.28 ratchov 67: #include "wav.h"
68: #include "listen.h"
1.15 ratchov 69: #include "dev.h"
1.11 jaredy 70:
1.43 ratchov 71: #define MODE_PLAY 1
72: #define MODE_REC 2
73:
1.28 ratchov 74: int debug_level = 0;
75: volatile int quit_flag = 0;
1.7 deraadt 76:
1.28 ratchov 77: /*
78: * SIGINT handler, it raises the quit flag. If the flag is already set,
79: * that means that the last SIGINT was not handled, because the process
80: * is blocked somewhere, so exit
81: */
82: void
83: sigint(int s)
84: {
85: if (quit_flag)
86: _exit(1);
87: quit_flag = 1;
88: }
1.22 ratchov 89:
1.15 ratchov 90: /*
1.28 ratchov 91: * increase debug level on SIGUSR1
1.15 ratchov 92: */
1.28 ratchov 93: void
94: sigusr1(int s)
95: {
96: if (debug_level < 4)
97: debug_level++;
98: }
1.13 uwe 99:
1.11 jaredy 100: /*
1.28 ratchov 101: * decrease debug level on SIGUSR2
1.1 kstailey 102: */
1.28 ratchov 103: void
104: sigusr2(int s)
1.15 ratchov 105: {
1.28 ratchov 106: if (debug_level > 0)
107: debug_level--;
1.15 ratchov 108: }
109:
110: void
111: usage(void)
1.1 kstailey 112: {
1.15 ratchov 113: extern char *__progname;
1.4 millert 114:
1.15 ratchov 115: fprintf(stderr,
1.51 ratchov 116: "usage: %s [-lnu] [-b nsamples] [-C min:max] [-c min:max] [-e enc] "
1.29 jmc 117: "[-f device]\n"
1.45 jmc 118: "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s socket]\n"
1.44 jmc 119: "\t[-v volume] [-x policy]\n",
1.15 ratchov 120: __progname);
121: }
122:
123: void
124: opt_ch(struct aparams *par)
125: {
126: if (sscanf(optarg, "%u:%u", &par->cmin, &par->cmax) != 2 ||
1.28 ratchov 127: par->cmax < par->cmin || par->cmax > NCHAN_MAX - 1)
1.35 ratchov 128: errx(1, "%s: bad channel range", optarg);
1.15 ratchov 129: }
1.13 uwe 130:
1.15 ratchov 131: void
132: opt_rate(struct aparams *par)
133: {
134: if (sscanf(optarg, "%u", &par->rate) != 1 ||
135: par->rate < RATE_MIN || par->rate > RATE_MAX)
1.35 ratchov 136: errx(1, "%s: bad sample rate", optarg);
137: }
138:
139: void
140: opt_vol(unsigned *vol)
141: {
142: if (sscanf(optarg, "%u", vol) != 1 ||
143: *vol > MIDI_MAXCTL)
144: errx(1, "%s: bad volume", optarg);
1.15 ratchov 145: }
1.13 uwe 146:
1.15 ratchov 147: void
148: opt_enc(struct aparams *par)
149: {
1.28 ratchov 150: int len;
151:
152: len = aparams_strtoenc(par, optarg);
153: if (len == 0 || optarg[len] != '\0')
154: errx(1, "%s: bad encoding", optarg);
1.15 ratchov 155: }
1.4 millert 156:
1.15 ratchov 157: int
158: opt_hdr(void)
159: {
160: if (strcmp("auto", optarg) == 0)
161: return HDR_AUTO;
162: if (strcmp("raw", optarg) == 0)
163: return HDR_RAW;
164: if (strcmp("wav", optarg) == 0)
165: return HDR_WAV;
1.35 ratchov 166: errx(1, "%s: bad header specification", optarg);
1.1 kstailey 167: }
168:
1.22 ratchov 169: int
170: opt_xrun(void)
171: {
172: if (strcmp("ignore", optarg) == 0)
173: return XRUN_IGNORE;
174: if (strcmp("sync", optarg) == 0)
175: return XRUN_SYNC;
176: if (strcmp("error", optarg) == 0)
177: return XRUN_ERROR;
178: errx(1, "%s: onderrun/overrun policy", optarg);
179: }
180:
1.43 ratchov 181: int
182: opt_mode(void)
183: {
184: if (strcmp("play", optarg) == 0)
185: return MODE_PLAY;
186: if (strcmp("rec", optarg) == 0)
187: return MODE_REC;
188: if (strcmp("duplex", optarg) == 0)
189: return MODE_PLAY | MODE_REC;
190: errx(1, "%s: bad mode", optarg);
191: }
192:
1.13 uwe 193: /*
1.42 ratchov 194: * Arguments of -i, -o and -s options are stored in a list.
1.13 uwe 195: */
1.15 ratchov 196: struct farg {
197: SLIST_ENTRY(farg) entry;
1.42 ratchov 198: struct aparams ipar; /* input (read) parameters */
199: struct aparams opar; /* output (write) parameters */
1.15 ratchov 200: unsigned vol; /* last requested volume */
201: char *name; /* optarg pointer (no need to copy it */
202: int hdr; /* header format */
1.22 ratchov 203: int xrun; /* overrun/underrun policy */
1.15 ratchov 204: };
1.13 uwe 205:
1.15 ratchov 206: SLIST_HEAD(farglist, farg);
1.13 uwe 207:
1.15 ratchov 208: /*
209: * Add a farg entry to the given list, corresponding
210: * to the given file name.
211: */
212: void
1.52 ratchov 213: farg_add(struct farglist *list,
1.42 ratchov 214: struct aparams *ipar, struct aparams *opar, unsigned vol,
215: int hdr, int xrun, char *optarg)
1.15 ratchov 216: {
217: struct farg *fa;
218: size_t namelen;
1.52 ratchov 219:
1.15 ratchov 220: fa = malloc(sizeof(struct farg));
221: if (fa == NULL)
222: err(1, "%s", optarg);
223:
224: if (hdr == HDR_AUTO) {
225: namelen = strlen(optarg);
1.52 ratchov 226: if (namelen >= 4 &&
1.15 ratchov 227: strcasecmp(optarg + namelen - 4, ".wav") == 0) {
228: fa->hdr = HDR_WAV;
229: DPRINTF("%s: assuming wav file format\n", optarg);
230: } else {
231: fa->hdr = HDR_RAW;
232: DPRINTF("%s: assuming headerless file\n", optarg);
1.13 uwe 233: }
1.52 ratchov 234: } else
1.15 ratchov 235: fa->hdr = hdr;
1.22 ratchov 236: fa->xrun = xrun;
1.42 ratchov 237: fa->ipar = *ipar;
238: fa->opar = *opar;
1.15 ratchov 239: fa->vol = vol;
240: fa->name = optarg;
241: SLIST_INSERT_HEAD(list, fa, entry);
242: }
1.13 uwe 243:
1.15 ratchov 244: /*
245: * Open an input file and setup converter if necessary.
246: */
247: void
1.26 ratchov 248: newinput(struct farg *fa)
1.15 ratchov 249: {
250: int fd;
1.28 ratchov 251: struct wav *f;
1.26 ratchov 252: struct aproc *proc;
253: struct abuf *buf;
254: unsigned nfr;
1.15 ratchov 255:
256: if (strcmp(fa->name, "-") == 0) {
257: fd = STDIN_FILENO;
258: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
259: warn("stdin");
260: fa->name = "stdin";
261: } else {
262: fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
263: if (fd < 0)
264: err(1, "%s", fa->name);
1.13 uwe 265: }
1.28 ratchov 266: /*
267: * XXX : we should round rate, right ?
268: */
1.42 ratchov 269: f = wav_new_in(&wav_ops, fd, fa->name, &fa->ipar, fa->hdr);
270: nfr = dev_bufsz * fa->ipar.rate / dev_rate;
271: buf = abuf_new(nfr, &fa->ipar);
1.28 ratchov 272: proc = rpipe_new((struct file *)f);
1.26 ratchov 273: aproc_setout(proc, buf);
1.28 ratchov 274: abuf_fill(buf); /* XXX: move this in dev_attach() ? */
1.42 ratchov 275: dev_attach(fa->name, buf, &fa->ipar, fa->xrun,
1.40 ratchov 276: NULL, NULL, 0, ADATA_UNIT);
1.35 ratchov 277: dev_setvol(buf, MIDI_TO_ADATA(fa->vol));
1.15 ratchov 278: }
1.13 uwe 279:
1.15 ratchov 280: /*
281: * Open an output file and setup converter if necessary.
282: */
283: void
1.26 ratchov 284: newoutput(struct farg *fa)
1.15 ratchov 285: {
286: int fd;
1.28 ratchov 287: struct wav *f;
1.26 ratchov 288: struct aproc *proc;
289: struct abuf *buf;
290: unsigned nfr;
1.15 ratchov 291:
292: if (strcmp(fa->name, "-") == 0) {
293: fd = STDOUT_FILENO;
294: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
295: warn("stdout");
296: fa->name = "stdout";
297: } else {
298: fd = open(fa->name,
299: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
300: if (fd < 0)
301: err(1, "%s", fa->name);
302: }
1.28 ratchov 303: /*
304: * XXX : we should round rate, right ?
305: */
1.42 ratchov 306: f = wav_new_out(&wav_ops, fd, fa->name, &fa->opar, fa->hdr);
307: nfr = dev_bufsz * fa->opar.rate / dev_rate;
1.28 ratchov 308: proc = wpipe_new((struct file *)f);
1.42 ratchov 309: buf = abuf_new(nfr, &fa->opar);
1.26 ratchov 310: aproc_setin(proc, buf);
1.42 ratchov 311: dev_attach(fa->name, NULL, NULL, 0, buf, &fa->opar, fa->xrun, 0);
1.13 uwe 312: }
313:
1.1 kstailey 314: int
1.15 ratchov 315: main(int argc, char **argv)
1.1 kstailey 316: {
1.51 ratchov 317: int c, u_flag, l_flag, n_flag, hdr, xrun, suspend = 0;
1.15 ratchov 318: struct farg *fa;
1.42 ratchov 319: struct farglist ifiles, ofiles, sfiles;
1.26 ratchov 320: struct aparams ipar, opar, dipar, dopar;
1.28 ratchov 321: struct sigaction sa;
1.55 ! ratchov 322: struct stat sb;
! 323: char base[PATH_MAX], path[PATH_MAX];
1.43 ratchov 324: unsigned bufsz, mode;
1.42 ratchov 325: char *devpath, *dbgenv;
1.21 ratchov 326: const char *errstr;
1.40 ratchov 327: unsigned volctl;
1.55 ! ratchov 328: uid_t uid;
1.15 ratchov 329:
1.19 ratchov 330: dbgenv = getenv("AUCAT_DEBUG");
331: if (dbgenv) {
1.21 ratchov 332: debug_level = strtonum(dbgenv, 0, 4, &errstr);
333: if (errstr)
334: errx(1, "AUCAT_DEBUG is %s: %s", errstr, dbgenv);
1.19 ratchov 335: }
336:
1.15 ratchov 337: aparams_init(&ipar, 0, 1, 44100);
338: aparams_init(&opar, 0, 1, 44100);
1.26 ratchov 339: u_flag = 0;
1.28 ratchov 340: l_flag = 0;
1.51 ratchov 341: n_flag = 0;
1.15 ratchov 342: devpath = NULL;
343: SLIST_INIT(&ifiles);
344: SLIST_INIT(&ofiles);
1.42 ratchov 345: SLIST_INIT(&sfiles);
1.28 ratchov 346: hdr = HDR_AUTO;
347: xrun = XRUN_IGNORE;
1.40 ratchov 348: volctl = MIDI_MAXCTL;
1.32 ratchov 349: bufsz = 44100 * 4 / 15; /* XXX: use milliseconds, not frames */
1.43 ratchov 350: mode = 0;
1.15 ratchov 351:
1.51 ratchov 352: while ((c = getopt(argc, argv, "nb:c:C:e:r:h:x:v:i:o:f:m:lus:")) != -1) {
1.15 ratchov 353: switch (c) {
1.51 ratchov 354: case 'n':
355: n_flag = 1;
356: break;
1.43 ratchov 357: case 'm':
358: mode = opt_mode();
359: break;
1.15 ratchov 360: case 'h':
1.28 ratchov 361: hdr = opt_hdr();
1.15 ratchov 362: break;
1.22 ratchov 363: case 'x':
1.28 ratchov 364: xrun = opt_xrun();
1.22 ratchov 365: break;
1.15 ratchov 366: case 'c':
367: opt_ch(&ipar);
368: break;
369: case 'C':
370: opt_ch(&opar);
371: break;
372: case 'e':
373: opt_enc(&ipar);
1.28 ratchov 374: aparams_copyenc(&opar, &ipar);
1.15 ratchov 375: break;
376: case 'r':
377: opt_rate(&ipar);
1.28 ratchov 378: opar.rate = ipar.rate;
1.15 ratchov 379: break;
1.35 ratchov 380: case 'v':
1.40 ratchov 381: opt_vol(&volctl);
1.35 ratchov 382: break;
1.15 ratchov 383: case 'i':
1.42 ratchov 384: farg_add(&ifiles, &ipar, &opar, volctl,
385: hdr, xrun, optarg);
1.15 ratchov 386: break;
387: case 'o':
1.42 ratchov 388: farg_add(&ofiles, &ipar, &opar, volctl,
389: hdr, xrun, optarg);
390: break;
391: case 's':
392: farg_add(&sfiles, &ipar, &opar, volctl,
393: hdr, xrun, 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.32 ratchov 409: if (sscanf(optarg, "%u", &bufsz) != 1 || bufsz == 0) {
1.28 ratchov 410: fprintf(stderr, "%s: bad buf size\n", optarg);
411: exit(1);
412: }
413: break;
1.11 jaredy 414: default:
415: usage();
1.15 ratchov 416: exit(1);
1.4 millert 417: }
418: }
419: argc -= optind;
420: argv += optind;
421:
1.15 ratchov 422: if (!devpath) {
1.47 ratchov 423: dopar = ipar;
424: dipar = opar;
1.15 ratchov 425: }
426:
1.28 ratchov 427: if (!l_flag && SLIST_EMPTY(&ifiles) &&
428: SLIST_EMPTY(&ofiles) && argc > 0) {
1.15 ratchov 429: /*
430: * Legacy mode: if no -i or -o options are provided, and
431: * there are arguments then assume the arguments are files
432: * to play.
433: */
434: for (c = 0; c < argc; c++)
435: if (legacy_play(devpath, argv[c]) != 0) {
1.17 jakemsr 436: errx(1, "%s: could not play\n", argv[c]);
1.15 ratchov 437: }
438: exit(0);
439: } else if (argc > 0) {
1.11 jaredy 440: usage();
1.15 ratchov 441: exit(1);
442: }
443:
1.42 ratchov 444: if (!l_flag && !SLIST_EMPTY(&sfiles))
445: errx(1, "can't use -s without -l");
1.43 ratchov 446: if ((l_flag || mode != 0) &&
447: (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
448: errx(1, "can't use -l, -m and -s with -o or -i");
449: if (!mode) {
450: if (l_flag || !SLIST_EMPTY(&ifiles))
451: mode |= MODE_PLAY;
452: if (l_flag || !SLIST_EMPTY(&ofiles))
453: mode |= MODE_REC;
454: }
1.51 ratchov 455: if (n_flag) {
456: if (devpath != NULL || l_flag)
457: errx(1, "can't use -n with -f or -l");
458: if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
459: errx(1, "both -i and -o are required with -n");
460: }
1.15 ratchov 461:
1.46 ratchov 462: /*
463: * if there are no sockets paths provided use the default
464: */
465: if (l_flag && SLIST_EMPTY(&sfiles)) {
466: farg_add(&sfiles, &dopar, &dipar,
467: MIDI_MAXCTL, HDR_RAW, XRUN_IGNORE, DEFAULT_SOCKET);
468: }
469:
470: if (!u_flag) {
1.26 ratchov 471: /*
472: * Calculate "best" device parameters. Iterate over all
473: * inputs and outputs and find the maximum sample rate
474: * and channel number.
475: */
1.49 ratchov 476: aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
477: aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
1.26 ratchov 478: SLIST_FOREACH(fa, &ifiles, entry) {
1.46 ratchov 479: aparams_grow(&dopar, &fa->ipar);
1.26 ratchov 480: }
481: SLIST_FOREACH(fa, &ofiles, entry) {
1.46 ratchov 482: aparams_grow(&dipar, &fa->opar);
483: }
484: SLIST_FOREACH(fa, &sfiles, entry) {
485: aparams_grow(&dopar, &fa->ipar);
486: aparams_grow(&dipar, &fa->opar);
1.17 jakemsr 487: }
1.42 ratchov 488: }
489:
1.55 ! ratchov 490: if (l_flag) {
! 491: uid = geteuid();
! 492: snprintf(base, PATH_MAX, "/tmp/aucat-%u", uid);
! 493: if (mkdir(base, 0700) < 0) {
! 494: if (errno != EEXIST)
! 495: err(1, "mkdir(\"%s\")", base);
! 496: }
! 497: if (stat(base, &sb) < 0)
! 498: err(1, "stat(\"%s\")", base);
! 499: if (sb.st_uid != uid || (sb.st_mode & 077) != 0)
! 500: errx(1, "%s has wrong permissions", base);
! 501: }
1.28 ratchov 502: quit_flag = 0;
503: sigfillset(&sa.sa_mask);
504: sa.sa_flags = SA_RESTART;
505: sa.sa_handler = sigint;
506: if (sigaction(SIGINT, &sa, NULL) < 0)
507: DPRINTF("sigaction(int) failed\n");
1.53 ratchov 508: if (sigaction(SIGTERM, &sa, NULL) < 0)
509: DPRINTF("sigaction(term) failed\n");
510: if (sigaction(SIGHUP, &sa, NULL) < 0)
511: DPRINTF("sigaction(hup) failed\n");
1.28 ratchov 512: #ifdef DEBUG
513: sa.sa_handler = sigusr1;
514: if (sigaction(SIGUSR1, &sa, NULL) < 0)
515: DPRINTF("sigaction(usr1) failed\n");
516: sa.sa_handler = sigusr2;
517: if (sigaction(SIGUSR2, &sa, NULL) < 0)
518: DPRINTF("sigaction(usr2) failed1n");
519: #endif
520: filelist_init();
1.51 ratchov 521:
1.15 ratchov 522: /*
1.32 ratchov 523: * Open the device. Give half of the buffer to the device,
524: * the other half is for the socket/files
1.15 ratchov 525: */
1.51 ratchov 526: if (n_flag) {
527: dev_loopinit(&dipar, &dopar, bufsz);
528: } else {
1.52 ratchov 529: dev_init(devpath,
1.51 ratchov 530: (mode & MODE_REC) ? &dipar : NULL,
531: (mode & MODE_PLAY) ? &dopar : NULL,
532: bufsz);
533: }
1.52 ratchov 534:
1.15 ratchov 535: /*
536: * Create buffers for all input and output pipes.
537: */
1.26 ratchov 538: while (!SLIST_EMPTY(&ifiles)) {
539: fa = SLIST_FIRST(&ifiles);
540: SLIST_REMOVE_HEAD(&ifiles, entry);
541: newinput(fa);
542: free(fa);
543: }
544: while (!SLIST_EMPTY(&ofiles)) {
545: fa = SLIST_FIRST(&ofiles);
546: SLIST_REMOVE_HEAD(&ofiles, entry);
547: newoutput(fa);
1.42 ratchov 548: free(fa);
549: }
550: while (!SLIST_EMPTY(&sfiles)) {
551: fa = SLIST_FIRST(&sfiles);
552: SLIST_REMOVE_HEAD(&sfiles, entry);
1.55 ! ratchov 553: if (strchr(fa->name, '/') != NULL)
! 554: errx(1, "socket names must not contain '/'");
! 555: snprintf(path, PATH_MAX, "%s/%s", base, fa->name);
! 556: listen_new(&listen_ops, path, &fa->opar, &fa->ipar,
! 557: MIDI_TO_ADATA(fa->vol));
1.26 ratchov 558: free(fa);
1.15 ratchov 559: }
1.13 uwe 560:
1.15 ratchov 561: /*
1.28 ratchov 562: * loop, start audio
1.15 ratchov 563: */
1.28 ratchov 564: for (;;) {
565: if (quit_flag) {
566: break;
567: }
1.50 ratchov 568: if ((!dev_rec || dev_rec->u.io.file == NULL) &&
1.51 ratchov 569: (!dev_play || dev_play->u.io.file == NULL) && !n_flag) {
1.50 ratchov 570: fprintf(stderr, "device desappeared, terminating\n");
571: break;
1.38 ratchov 572: }
1.50 ratchov 573: if (!file_poll())
574: break;
1.34 ratchov 575: if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
576: (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz)) {
1.37 ratchov 577: if (!l_flag)
578: break;
1.34 ratchov 579: if (!suspend) {
580: DPRINTF("suspending\n");
581: suspend = 1;
582: dev_stop();
583: dev_clear();
584: }
585: }
586: if ((dev_mix && dev_mix->u.mix.idle == 0) ||
587: (dev_sub && dev_sub->u.sub.idle == 0)) {
588: if (suspend) {
589: DPRINTF("resuming\n");
590: suspend = 0;
591: dev_start();
592: }
593: }
594: }
1.55 ! ratchov 595: if (l_flag) {
1.50 ratchov 596: filelist_unlisten();
1.55 ! ratchov 597: if (rmdir(base) < 0)
! 598: warn("rmdir(\"%s\")", base);
! 599: }
1.34 ratchov 600: if (suspend) {
601: DPRINTF("resuming to drain\n");
602: suspend = 0;
603: dev_start();
1.28 ratchov 604: }
1.51 ratchov 605: if (n_flag) {
606: dev_loopdone();
607: } else
608: dev_done();
1.28 ratchov 609: filelist_done();
1.11 jaredy 610:
1.28 ratchov 611: sigfillset(&sa.sa_mask);
612: sa.sa_flags = SA_RESTART;
613: sa.sa_handler = SIG_DFL;
614: if (sigaction(SIGINT, &sa, NULL) < 0)
615: DPRINTF("dev_done: sigaction failed\n");
1.15 ratchov 616: return 0;
1.1 kstailey 617: }