Annotation of src/usr.bin/aucat/aucat.c, Revision 1.18
1.18 ! jmc 1: /* $OpenBSD: aucat.c,v 1.17 2008/05/26 07:56:17 jakemsr 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: * (not yet)add a silent/quiet/verbose/whatever flag, but be sure
21: * that by default the user is notified when one of the following
22: * (cpu consuming) aproc is created: mix, sub, conv
23: *
24: * (hard) use parsable encoding names instead of the lookup
25: * table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example
26: * s8, s16le, s24le/3msb. This would give names that correspond to
27: * what use most linux-centric apps, but for which we have an
28: * algorithm to convert the name to a aparams structure.
29: *
30: * (easy) uses {chmin-chmax} instead of chmin:chmax notation for
31: * channels specification to match the notation used in rmix.
32: *
33: * (easy) use comma-separated parameters syntax, example:
34: * s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c
35: * flags, but only one -p flag that specify one or more parameters.
36: *
37: * (hard) dont create mix (sub) if there's only one input (output)
38: *
39: * (hard) if all inputs are over, the mixer terminates and closes
40: * the write end of the device. It should continue writing zeros
41: * until the recording is over (or be able to stop write end of
42: * the device)
43: *
44: * (hard) implement -n flag (no device) to connect all inputs to
45: * the outputs.
46: *
47: * (hard) ignore input files that are not audible (because channels
48: * they provide are not used on the output). Similarly ignore
49: * outputs that are zero filled (because channels they consume are
50: * not provided).
51: *
52: * (easy) do we need -d flag ?
1.1 kstailey 53: */
54:
1.15 ratchov 55: #include <sys/param.h>
1.1 kstailey 56: #include <sys/types.h>
1.15 ratchov 57: #include <sys/queue.h>
1.13 uwe 58:
1.15 ratchov 59: #include <err.h>
1.1 kstailey 60: #include <fcntl.h>
1.15 ratchov 61: #include <signal.h>
1.1 kstailey 62: #include <stdio.h>
1.4 millert 63: #include <stdlib.h>
1.8 david 64: #include <string.h>
1.1 kstailey 65: #include <unistd.h>
1.15 ratchov 66: #include <varargs.h>
1.1 kstailey 67:
1.15 ratchov 68: #include "conf.h"
69: #include "aparams.h"
70: #include "aproc.h"
71: #include "abuf.h"
72: #include "file.h"
73: #include "dev.h"
1.11 jaredy 74:
1.13 uwe 75: /*
1.15 ratchov 76: * Format for file headers.
1.1 kstailey 77: */
1.15 ratchov 78: #define HDR_AUTO 0 /* guess by looking at the file name */
79: #define HDR_RAW 1 /* no headers, ie openbsd native ;-) */
80: #define HDR_WAV 2 /* microsoft riff wave */
1.7 deraadt 81:
1.15 ratchov 82: int debug_level = 0;
83: volatile int quit_flag = 0;
84: /*
85: * List of allowed encodings and their names.
86: */
87: struct enc {
88: char *name;
89: struct aparams par;
90: } enc_list[] = {
91: /* name bps, bits, le, sign, msb, unused */
92: { "s8", { 1, 8, 1, 1, 1, 0, 0, 0 } },
93: { "u8", { 1, 8, 1, 0, 1, 0, 0, 0 } },
94: { "s16le", { 2, 16, 1, 1, 1, 0, 0, 0 } },
95: { "u16le", { 2, 16, 1, 0, 1, 0, 0, 0 } },
96: { "s16be", { 2, 16, 0, 1, 1, 0, 0, 0 } },
97: { "u16be", { 2, 16, 0, 0, 1, 0, 0, 0 } },
98: { "s24le", { 4, 24, 1, 1, 1, 0, 0, 0 } },
99: { "u24le", { 4, 24, 1, 0, 1, 0, 0, 0 } },
100: { "s24be", { 4, 24, 0, 1, 1, 0, 0, 0 } },
101: { "u24be", { 4, 24, 0, 0, 1, 0, 0, 0 } },
102: { "s32le", { 4, 32, 1, 1, 1, 0, 0, 0 } },
103: { "u32le", { 4, 32, 1, 0, 1, 0, 0, 0 } },
104: { "s32be", { 4, 32, 0, 1, 1, 0, 0, 0 } },
105: { "u32be", { 4, 32, 0, 0, 1, 0, 0, 0 } },
106: { "s24le3", { 3, 24, 1, 1, 1, 0, 0, 0 } },
107: { "u24le3", { 3, 24, 1, 0, 1, 0, 0, 0 } },
108: { "s24be3", { 3, 24, 0, 1, 1, 0, 0, 0 } },
109: { "u24be3", { 3, 24, 0, 0, 1, 0, 0, 0 } },
110: { "s20le3", { 3, 20, 1, 1, 1, 0, 0, 0 } },
111: { "u20le3", { 3, 20, 1, 0, 1, 0, 0, 0 } },
112: { "s20be3", { 3, 20, 0, 1, 1, 0, 0, 0 } },
113: { "u20be3", { 3, 20, 0, 0, 1, 0, 0, 0 } },
114: { "s18le3", { 3, 18, 1, 1, 1, 0, 0, 0 } },
115: { "u18le3", { 3, 18, 1, 0, 1, 0, 0, 0 } },
116: { "s18be3", { 3, 18, 0, 1, 1, 0, 0, 0 } },
117: { "u18be3", { 3, 18, 0, 0, 1, 0, 0, 0 } },
118: { NULL, { 0, 0, 0, 0, 0, 0, 0, 0 } }
119: };
1.13 uwe 120:
1.11 jaredy 121: /*
1.15 ratchov 122: * Search an encoding in the above table. On success fill encoding
123: * part of "par" and return 1, otherwise return 0.
1.1 kstailey 124: */
1.15 ratchov 125: unsigned
126: enc_lookup(char *name, struct aparams *par)
127: {
128: struct enc *e;
129:
130: for (e = enc_list; e->name != NULL; e++) {
131: if (strcmp(e->name, name) == 0) {
132: par->bps = e->par.bps;
133: par->bits = e->par.bits;
134: par->sig = e->par.sig;
135: par->le = e->par.le;
136: par->msb = e->par.msb;
137: return 1;
138: }
139: }
140: return 0;
141: }
142:
143: void
144: usage(void)
1.1 kstailey 145: {
1.15 ratchov 146: extern char *__progname;
1.4 millert 147:
1.15 ratchov 148: fprintf(stderr,
1.18 ! jmc 149: "usage: %s [-qu] [-C min:max] [-c min:max] [-d level] "
1.16 jmc 150: "[-E enc] [-e enc]\n"
151: "\t[-f device] [-H fmt] [-h fmt] [-i file] [-o file] [-R rate]\n"
152: "\t[-r rate]\n",
1.15 ratchov 153: __progname);
154: }
155:
156: void
157: opt_ch(struct aparams *par)
158: {
159: if (sscanf(optarg, "%u:%u", &par->cmin, &par->cmax) != 2 ||
160: par->cmin > CHAN_MAX || par->cmax > CHAN_MAX ||
161: par->cmin > par->cmax)
162: err(1, "%s: bad channel range", optarg);
163: }
1.13 uwe 164:
1.15 ratchov 165: void
166: opt_rate(struct aparams *par)
167: {
168: if (sscanf(optarg, "%u", &par->rate) != 1 ||
169: par->rate < RATE_MIN || par->rate > RATE_MAX)
170: err(1, "%s: bad sample rate", optarg);
171: }
1.13 uwe 172:
1.15 ratchov 173: void
174: opt_enc(struct aparams *par)
175: {
176: if (!enc_lookup(optarg, par))
177: err(1, "%s: bad encoding", optarg);
178: }
1.4 millert 179:
1.15 ratchov 180: int
181: opt_hdr(void)
182: {
183: if (strcmp("auto", optarg) == 0)
184: return HDR_AUTO;
185: if (strcmp("raw", optarg) == 0)
186: return HDR_RAW;
187: if (strcmp("wav", optarg) == 0)
188: return HDR_WAV;
189: err(1, "%s: bad header specification", optarg);
1.1 kstailey 190: }
191:
1.13 uwe 192: /*
1.15 ratchov 193: * Arguments of -i and -o opations are stored in a list.
1.13 uwe 194: */
1.15 ratchov 195: struct farg {
196: SLIST_ENTRY(farg) entry;
197: struct aparams par; /* last requested format */
198: unsigned vol; /* last requested volume */
199: char *name; /* optarg pointer (no need to copy it */
200: int hdr; /* header format */
201: int fd; /* file descriptor for I/O */
202: struct aproc *proc; /* rpipe_xxx our wpipe_xxx */
203: struct abuf *buf;
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
213: opt_file(struct farglist *list,
214: struct aparams *par, unsigned vol, int hdr, char *optarg)
215: {
216: struct farg *fa;
217: size_t namelen;
218:
219: fa = malloc(sizeof(struct farg));
220: if (fa == NULL)
221: err(1, "%s", optarg);
222:
223: if (hdr == HDR_AUTO) {
224: namelen = strlen(optarg);
225: if (namelen >= 4 &&
226: strcasecmp(optarg + namelen - 4, ".wav") == 0) {
227: fa->hdr = HDR_WAV;
228: DPRINTF("%s: assuming wav file format\n", optarg);
229: } else {
230: fa->hdr = HDR_RAW;
231: DPRINTF("%s: assuming headerless file\n", optarg);
1.13 uwe 232: }
1.15 ratchov 233: } else
234: fa->hdr = hdr;
235: fa->par = *par;
236: fa->vol = vol;
237: fa->name = optarg;
238: fa->proc = NULL;
239: SLIST_INSERT_HEAD(list, fa, entry);
240: }
1.13 uwe 241:
1.15 ratchov 242: /*
243: * Open an input file and setup converter if necessary.
244: */
245: void
1.17 jakemsr 246: newinput(struct farg *fa, struct aparams *npar, unsigned nfr, int quiet_flag)
1.15 ratchov 247: {
248: int fd;
249: struct file *f;
250: struct aproc *p, *c;
251: struct abuf *buf, *nbuf;
252:
253: if (strcmp(fa->name, "-") == 0) {
254: fd = STDIN_FILENO;
255: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
256: warn("stdin");
257: fa->name = "stdin";
258: } else {
259: fd = open(fa->name, O_RDONLY | O_NONBLOCK, 0666);
260: if (fd < 0)
261: err(1, "%s", fa->name);
1.13 uwe 262: }
1.15 ratchov 263: f = file_new(fd, fa->name);
264: if (fa->hdr == HDR_WAV) {
265: if (!wav_readhdr(fd, &fa->par, &f->rbytes))
266: exit(1);
1.13 uwe 267: }
1.15 ratchov 268: buf = abuf_new(nfr, aparams_bpf(&fa->par));
269: p = rpipe_new(f);
270: aproc_setout(p, buf);
271: if (!aparams_eq(&fa->par, npar)) {
1.17 jakemsr 272: if (!quiet_flag) {
273: fprintf(stderr, "%s: ", fa->name);
274: aparams_print2(&fa->par, npar);
275: fprintf(stderr, "\n");
276: }
1.15 ratchov 277: nbuf = abuf_new(nfr, aparams_bpf(npar));
278: c = conv_new(fa->name, &fa->par, npar);
279: aproc_setin(c, buf);
280: aproc_setout(c, nbuf);
281: fa->buf = nbuf;
282: } else
283: fa->buf = buf;
284: fa->proc = p;
285: fa->fd = fd;
286: }
1.13 uwe 287:
1.15 ratchov 288: /*
289: * Open an output file and setup converter if necessary.
290: */
291: void
1.17 jakemsr 292: newoutput(struct farg *fa, struct aparams *npar, unsigned nfr, int quiet_flag)
1.15 ratchov 293: {
294: int fd;
295: struct file *f;
296: struct aproc *p, *c;
297: struct abuf *buf, *nbuf;
298:
299: if (strcmp(fa->name, "-") == 0) {
300: fd = STDOUT_FILENO;
301: if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
302: warn("stdout");
303: fa->name = "stdout";
304: } else {
305: fd = open(fa->name,
306: O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
307: if (fd < 0)
308: err(1, "%s", fa->name);
309: }
310: f = file_new(fd, fa->name);
311: if (fa->hdr == HDR_WAV) {
312: f->wbytes = WAV_DATAMAX;
313: if (!wav_writehdr(fd, &fa->par))
314: exit(1);
1.13 uwe 315: }
1.15 ratchov 316: buf = abuf_new(nfr, aparams_bpf(&fa->par));
317: p = wpipe_new(f);
318: aproc_setin(p, buf);
319: if (!aparams_eq(&fa->par, npar)) {
1.17 jakemsr 320: if (!quiet_flag) {
321: fprintf(stderr, "%s: ", fa->name);
322: aparams_print2(npar, &fa->par);
323: fprintf(stderr, "\n");
324: }
1.15 ratchov 325: c = conv_new(fa->name, npar, &fa->par);
326: nbuf = abuf_new(nfr, aparams_bpf(npar));
327: aproc_setin(c, nbuf);
328: aproc_setout(c, buf);
329: fa->buf = nbuf;
330: } else
331: fa->buf = buf;
332: fa->proc = p;
333: fa->fd = fd;
334: }
1.13 uwe 335:
1.15 ratchov 336: void
337: sighdl(int s)
338: {
339: if (quit_flag)
340: _exit(1);
341: quit_flag = 1;
1.13 uwe 342: }
343:
1.1 kstailey 344: int
1.15 ratchov 345: main(int argc, char **argv)
1.1 kstailey 346: {
1.15 ratchov 347: struct sigaction sa;
1.17 jakemsr 348: int c, u_flag, quiet_flag, ohdr, ihdr;
1.15 ratchov 349: struct farg *fa;
350: struct farglist ifiles, ofiles;
351: struct aparams ipar, opar, dipar, dopar, cipar, copar;
352: unsigned ivol, ovol;
353: unsigned dinfr, donfr, cinfr, confr;
354: char *devpath;
355: unsigned n;
356: struct aproc *rec, *play, *mix, *sub, *conv;
357: struct file *dev, *f;
358: struct abuf *buf, *cbuf;
359: int fd;
360:
361: aparams_init(&ipar, 0, 1, 44100);
362: aparams_init(&opar, 0, 1, 44100);
363:
1.17 jakemsr 364: u_flag = quiet_flag = 0;
1.15 ratchov 365: devpath = NULL;
366: SLIST_INIT(&ifiles);
367: SLIST_INIT(&ofiles);
368: ihdr = ohdr = HDR_AUTO;
369: ivol = ovol = MIDI_TO_ADATA(127);
370:
1.17 jakemsr 371: while ((c = getopt(argc, argv, "d:c:C:e:E:r:R:h:H:i:o:f:qu")) != -1) {
1.15 ratchov 372: switch (c) {
373: case 'd':
374: if (sscanf(optarg, "%u", &debug_level) != 1 ||
375: debug_level > 4)
376: err(1, "%s: not an integer in the 0..4 range",
377: optarg);
378: break;
379: case 'h':
380: ihdr = opt_hdr();
381: break;
382: case 'H':
383: ohdr = opt_hdr();
384: break;
385: case 'c':
386: opt_ch(&ipar);
387: break;
388: case 'C':
389: opt_ch(&opar);
390: break;
391: case 'e':
392: opt_enc(&ipar);
393: break;
394: case 'E':
395: opt_enc(&opar);
396: break;
397: case 'r':
398: opt_rate(&ipar);
399: break;
400: case 'R':
401: opt_rate(&opar);
402: break;
403: case 'i':
404: opt_file(&ifiles, &ipar, 127, ihdr, optarg);
405: break;
406: case 'o':
407: opt_file(&ofiles, &opar, 127, ohdr, optarg);
408: break;
1.4 millert 409: case 'f':
1.15 ratchov 410: if (devpath)
411: err(1, "only one -f allowed");
412: devpath = optarg;
413: dipar = ipar;
414: dopar = opar;
415: break;
1.17 jakemsr 416: case 'q':
417: quiet_flag = 1;
418: break;
1.15 ratchov 419: case 'u':
420: u_flag = 1;
1.4 millert 421: break;
1.11 jaredy 422: default:
423: usage();
1.15 ratchov 424: exit(1);
1.4 millert 425: }
426: }
427: argc -= optind;
428: argv += optind;
429:
1.15 ratchov 430: if (!devpath) {
431: devpath = getenv("AUDIODEVICE");
432: if (devpath == NULL)
433: devpath = DEFAULT_DEVICE;
434: dipar = ipar;
435: dopar = opar;
436: }
437:
438: if (SLIST_EMPTY(&ifiles) && SLIST_EMPTY(&ofiles) && argc > 0) {
439: /*
440: * Legacy mode: if no -i or -o options are provided, and
441: * there are arguments then assume the arguments are files
442: * to play.
443: */
444: for (c = 0; c < argc; c++)
445: if (legacy_play(devpath, argv[c]) != 0) {
1.17 jakemsr 446: errx(1, "%s: could not play\n", argv[c]);
1.15 ratchov 447: }
448: exit(0);
449: } else if (argc > 0) {
1.11 jaredy 450: usage();
1.15 ratchov 451: exit(1);
452: }
453:
454: sigfillset(&sa.sa_mask);
455: sa.sa_flags = SA_RESTART;
456: sa.sa_handler = sighdl;
457: if (sigaction(SIGINT, &sa, NULL) < 0)
458: err(1, "sigaction");
459:
460: file_start();
461: play = rec = mix = sub = NULL;
462:
463: aparams_init(&cipar, CHAN_MAX, 0, RATE_MIN);
464: aparams_init(&copar, CHAN_MAX, 0, RATE_MAX);
465:
466: /*
467: * Iterate over all inputs and outputs and find the maximum
468: * sample rate and channel number.
469: */
470: SLIST_FOREACH(fa, &ifiles, entry) {
471: if (cipar.cmin > fa->par.cmin)
472: cipar.cmin = fa->par.cmin;
473: if (cipar.cmax < fa->par.cmax)
474: cipar.cmax = fa->par.cmax;
475: if (cipar.rate < fa->par.rate)
476: cipar.rate = fa->par.rate;
477: }
478: SLIST_FOREACH(fa, &ofiles, entry) {
479: if (copar.cmin > fa->par.cmin)
480: copar.cmin = fa->par.cmin;
481: if (copar.cmax < fa->par.cmax)
482: copar.cmax = fa->par.cmax;
483: if (copar.rate > fa->par.rate)
484: copar.rate = fa->par.rate;
485: }
486:
487: /*
488: * Open the device and increase the maximum sample rate.
489: * channel number to include those used by the device
490: */
491: if (!u_flag) {
492: dipar = copar;
493: dopar = cipar;
494: }
495: fd = dev_init(devpath,
496: !SLIST_EMPTY(&ofiles) ? &dipar : NULL,
497: !SLIST_EMPTY(&ifiles) ? &dopar : NULL, &dinfr, &donfr);
498: if (fd < 0)
499: exit(1);
500: if (!SLIST_EMPTY(&ofiles)) {
1.17 jakemsr 501: if (!quiet_flag) {
502: fprintf(stderr, "%s: recording ", devpath);
503: aparams_print(&dipar);
504: fprintf(stderr, "\n");
505: }
1.15 ratchov 506: if (copar.cmin > dipar.cmin)
507: copar.cmin = dipar.cmin;
508: if (copar.cmax < dipar.cmax)
509: copar.cmax = dipar.cmax;
510: if (copar.rate > dipar.rate)
511: copar.rate = dipar.rate;
512: dinfr *= DEFAULT_NBLK;
513: DPRINTF("%s: using %ums rec buffer\n", devpath,
514: 1000 * dinfr / dipar.rate);
515: }
516: if (!SLIST_EMPTY(&ifiles)) {
1.17 jakemsr 517: if (!quiet_flag) {
518: fprintf(stderr, "%s: playing ", devpath);
519: aparams_print(&dopar);
520: fprintf(stderr, "\n");
521: }
1.15 ratchov 522: if (cipar.cmin > dopar.cmin)
523: cipar.cmin = dopar.cmin;
524: if (cipar.cmax < dopar.cmax)
525: cipar.cmax = dopar.cmax;
526: if (cipar.rate < dopar.rate)
527: cipar.rate = dopar.rate;
528: donfr *= DEFAULT_NBLK;
529: DPRINTF("%s: using %ums play buffer\n", devpath,
530: 1000 * donfr / dopar.rate);
531: }
532:
533: /*
534: * Create buffers for the device.
535: */
536: dev = file_new(fd, devpath);
537: if (!SLIST_EMPTY(&ofiles)) {
538: rec = rpipe_new(dev);
539: sub = sub_new();
540: }
541: if (!SLIST_EMPTY(&ifiles)) {
542: play = wpipe_new(dev);
543: mix = mix_new();
544: }
545:
546: /*
547: * Calculate sizes of buffers using "common" parameters, to
548: * have roughly the same duration as device buffers.
549: */
550: cinfr = donfr * cipar.rate / dopar.rate;
551: confr = dinfr * copar.rate / dipar.rate;
552:
553: /*
554: * Create buffers for all input and output pipes.
555: */
556: SLIST_FOREACH(fa, &ifiles, entry) {
1.17 jakemsr 557: newinput(fa, &cipar, cinfr, quiet_flag);
1.15 ratchov 558: if (mix)
559: aproc_setin(mix, fa->buf);
1.17 jakemsr 560: if (!quiet_flag) {
561: fprintf(stderr, "%s: reading ", fa->name);
562: aparams_print(&fa->par);
563: fprintf(stderr, "\n");
564: }
1.15 ratchov 565: }
566: SLIST_FOREACH(fa, &ofiles, entry) {
1.17 jakemsr 567: newoutput(fa, &copar, confr, quiet_flag);
1.15 ratchov 568: if (sub)
569: aproc_setout(sub, fa->buf);
1.17 jakemsr 570: if (!quiet_flag) {
571: fprintf(stderr, "%s: writing ", fa->name);
572: aparams_print(&fa->par);
573: fprintf(stderr, "\n");
574: }
1.15 ratchov 575: }
1.13 uwe 576:
1.15 ratchov 577: /*
578: * Connect the multiplexer to the device input.
579: */
580: if (sub) {
581: buf = abuf_new(dinfr, aparams_bpf(&dipar));
582: aproc_setout(rec, buf);
583: if (!aparams_eq(&copar, &dipar)) {
1.17 jakemsr 584: if (!quiet_flag) {
585: fprintf(stderr, "%s: ", devpath);
586: aparams_print2(&dipar, &copar);
587: fprintf(stderr, "\n");
588: }
1.15 ratchov 589: conv = conv_new("subconv", &dipar, &copar);
590: cbuf = abuf_new(confr, aparams_bpf(&copar));
591: aproc_setin(conv, buf);
592: aproc_setout(conv, cbuf);
593: aproc_setin(sub, cbuf);
594: } else
595: aproc_setin(sub, buf);
596: }
1.13 uwe 597:
1.15 ratchov 598: /*
599: * Normalize input levels and connect the mixer to the device
600: * output.
601: */
602: if (mix) {
603: n = 0;
604: SLIST_FOREACH(fa, &ifiles, entry)
605: n++;
606: SLIST_FOREACH(fa, &ifiles, entry)
607: fa->buf->mixvol /= n;
608: buf = abuf_new(donfr, aparams_bpf(&dopar));
609: aproc_setin(play, buf);
610: if (!aparams_eq(&cipar, &dopar)) {
1.17 jakemsr 611: if (!quiet_flag) {
612: fprintf(stderr, "%s: ", devpath);
613: aparams_print2(&cipar, &dopar);
614: fprintf(stderr, "\n");
615: }
1.15 ratchov 616: conv = conv_new("mixconv", &cipar, &dopar);
617: cbuf = abuf_new(cinfr, aparams_bpf(&cipar));
618: aproc_setout(conv, buf);
619: aproc_setin(conv, cbuf);
620: aproc_setout(mix, cbuf);
621: } else
622: aproc_setout(mix, buf);
623: }
1.13 uwe 624:
1.15 ratchov 625: /*
626: * start audio
627: */
628: if (play != NULL) {
1.17 jakemsr 629: if (!quiet_flag)
630: fprintf(stderr, "filling buffers...\n");
1.15 ratchov 631: while (!quit_flag) {
632: /* no more devices to poll */
633: if (!file_poll())
634: break;
635: /* device is blocked */
636: if (dev->events & POLLOUT)
637: break;
638: /* eof */
639: if (dev->state & FILE_EOF)
640: break;
1.4 millert 641: }
642: }
1.17 jakemsr 643: if (!quiet_flag)
644: fprintf(stderr, "starting device...\n");
1.15 ratchov 645: dev_start(dev->fd);
646: dev->state &= ~(FILE_RFLOW | FILE_WFLOW);
647: while (!quit_flag) {
648: if (!file_poll())
649: break;
650: }
1.11 jaredy 651:
1.17 jakemsr 652: if (!quiet_flag)
653: fprintf(stderr, "draining buffers...\n");
1.11 jaredy 654:
1.15 ratchov 655: /*
656: * generate EOF on all files that do input, so
657: * once buffers are drained, everything will be cleaned
658: */
659: LIST_FOREACH(f, &file_list, entry) {
660: if ((f->events) & POLLIN || (f->state & FILE_ROK))
661: file_eof(f);
662: }
663: for (;;) {
664: if (!file_poll())
665: break;
666: }
667: SLIST_FOREACH(fa, &ofiles, entry) {
668: if (fa->hdr == HDR_WAV)
669: wav_writehdr(fa->fd, &fa->par);
670: close(fa->fd);
671: DPRINTF("%s: closed\n", fa->name);
672: }
673: dev_stop(dev->fd);
674: file_stop();
675: return 0;
1.1 kstailey 676: }