Annotation of src/usr.bin/aucat/aucat.c, Revision 1.19
1.19 ! ratchov 1: /* $OpenBSD: aucat.c,v 1.18 2008/05/26 08:32:11 jmc 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;
1.19 ! ratchov 354: char *devpath, *dbgenv;
1.15 ratchov 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:
1.19 ! ratchov 361: dbgenv = getenv("AUCAT_DEBUG");
! 362: if (dbgenv) {
! 363: if (sscanf(dbgenv, "%u", &debug_level) != 1 ||
! 364: debug_level > 4)
! 365: err(1, "%s: not an integer in the 0..4 range", dbgenv);
! 366: }
! 367:
1.15 ratchov 368: aparams_init(&ipar, 0, 1, 44100);
369: aparams_init(&opar, 0, 1, 44100);
370:
1.17 jakemsr 371: u_flag = quiet_flag = 0;
1.15 ratchov 372: devpath = NULL;
373: SLIST_INIT(&ifiles);
374: SLIST_INIT(&ofiles);
375: ihdr = ohdr = HDR_AUTO;
376: ivol = ovol = MIDI_TO_ADATA(127);
377:
1.19 ! ratchov 378: while ((c = getopt(argc, argv, "c:C:e:E:r:R:h:H:i:o:f:qu")) != -1) {
1.15 ratchov 379: switch (c) {
380: case 'h':
381: ihdr = opt_hdr();
382: break;
383: case 'H':
384: ohdr = opt_hdr();
385: break;
386: case 'c':
387: opt_ch(&ipar);
388: break;
389: case 'C':
390: opt_ch(&opar);
391: break;
392: case 'e':
393: opt_enc(&ipar);
394: break;
395: case 'E':
396: opt_enc(&opar);
397: break;
398: case 'r':
399: opt_rate(&ipar);
400: break;
401: case 'R':
402: opt_rate(&opar);
403: break;
404: case 'i':
405: opt_file(&ifiles, &ipar, 127, ihdr, optarg);
406: break;
407: case 'o':
408: opt_file(&ofiles, &opar, 127, ohdr, optarg);
409: break;
1.4 millert 410: case 'f':
1.15 ratchov 411: if (devpath)
412: err(1, "only one -f allowed");
413: devpath = optarg;
414: dipar = ipar;
415: dopar = opar;
416: break;
1.17 jakemsr 417: case 'q':
418: quiet_flag = 1;
419: break;
1.15 ratchov 420: case 'u':
421: u_flag = 1;
1.4 millert 422: break;
1.11 jaredy 423: default:
424: usage();
1.15 ratchov 425: exit(1);
1.4 millert 426: }
427: }
428: argc -= optind;
429: argv += optind;
430:
1.15 ratchov 431: if (!devpath) {
432: devpath = getenv("AUDIODEVICE");
433: if (devpath == NULL)
434: devpath = DEFAULT_DEVICE;
435: dipar = ipar;
436: dopar = opar;
437: }
438:
439: if (SLIST_EMPTY(&ifiles) && SLIST_EMPTY(&ofiles) && argc > 0) {
440: /*
441: * Legacy mode: if no -i or -o options are provided, and
442: * there are arguments then assume the arguments are files
443: * to play.
444: */
445: for (c = 0; c < argc; c++)
446: if (legacy_play(devpath, argv[c]) != 0) {
1.17 jakemsr 447: errx(1, "%s: could not play\n", argv[c]);
1.15 ratchov 448: }
449: exit(0);
450: } else if (argc > 0) {
1.11 jaredy 451: usage();
1.15 ratchov 452: exit(1);
453: }
454:
455: sigfillset(&sa.sa_mask);
456: sa.sa_flags = SA_RESTART;
457: sa.sa_handler = sighdl;
458: if (sigaction(SIGINT, &sa, NULL) < 0)
459: err(1, "sigaction");
460:
461: file_start();
462: play = rec = mix = sub = NULL;
463:
464: aparams_init(&cipar, CHAN_MAX, 0, RATE_MIN);
465: aparams_init(&copar, CHAN_MAX, 0, RATE_MAX);
466:
467: /*
468: * Iterate over all inputs and outputs and find the maximum
469: * sample rate and channel number.
470: */
471: SLIST_FOREACH(fa, &ifiles, entry) {
472: if (cipar.cmin > fa->par.cmin)
473: cipar.cmin = fa->par.cmin;
474: if (cipar.cmax < fa->par.cmax)
475: cipar.cmax = fa->par.cmax;
476: if (cipar.rate < fa->par.rate)
477: cipar.rate = fa->par.rate;
478: }
479: SLIST_FOREACH(fa, &ofiles, entry) {
480: if (copar.cmin > fa->par.cmin)
481: copar.cmin = fa->par.cmin;
482: if (copar.cmax < fa->par.cmax)
483: copar.cmax = fa->par.cmax;
484: if (copar.rate > fa->par.rate)
485: copar.rate = fa->par.rate;
486: }
487:
488: /*
489: * Open the device and increase the maximum sample rate.
490: * channel number to include those used by the device
491: */
492: if (!u_flag) {
493: dipar = copar;
494: dopar = cipar;
495: }
496: fd = dev_init(devpath,
497: !SLIST_EMPTY(&ofiles) ? &dipar : NULL,
498: !SLIST_EMPTY(&ifiles) ? &dopar : NULL, &dinfr, &donfr);
499: if (fd < 0)
500: exit(1);
501: if (!SLIST_EMPTY(&ofiles)) {
1.17 jakemsr 502: if (!quiet_flag) {
503: fprintf(stderr, "%s: recording ", devpath);
504: aparams_print(&dipar);
505: fprintf(stderr, "\n");
506: }
1.15 ratchov 507: if (copar.cmin > dipar.cmin)
508: copar.cmin = dipar.cmin;
509: if (copar.cmax < dipar.cmax)
510: copar.cmax = dipar.cmax;
511: if (copar.rate > dipar.rate)
512: copar.rate = dipar.rate;
513: dinfr *= DEFAULT_NBLK;
514: DPRINTF("%s: using %ums rec buffer\n", devpath,
515: 1000 * dinfr / dipar.rate);
516: }
517: if (!SLIST_EMPTY(&ifiles)) {
1.17 jakemsr 518: if (!quiet_flag) {
519: fprintf(stderr, "%s: playing ", devpath);
520: aparams_print(&dopar);
521: fprintf(stderr, "\n");
522: }
1.15 ratchov 523: if (cipar.cmin > dopar.cmin)
524: cipar.cmin = dopar.cmin;
525: if (cipar.cmax < dopar.cmax)
526: cipar.cmax = dopar.cmax;
527: if (cipar.rate < dopar.rate)
528: cipar.rate = dopar.rate;
529: donfr *= DEFAULT_NBLK;
530: DPRINTF("%s: using %ums play buffer\n", devpath,
531: 1000 * donfr / dopar.rate);
532: }
533:
534: /*
535: * Create buffers for the device.
536: */
537: dev = file_new(fd, devpath);
538: if (!SLIST_EMPTY(&ofiles)) {
539: rec = rpipe_new(dev);
540: sub = sub_new();
541: }
542: if (!SLIST_EMPTY(&ifiles)) {
543: play = wpipe_new(dev);
544: mix = mix_new();
545: }
546:
547: /*
548: * Calculate sizes of buffers using "common" parameters, to
549: * have roughly the same duration as device buffers.
550: */
551: cinfr = donfr * cipar.rate / dopar.rate;
552: confr = dinfr * copar.rate / dipar.rate;
553:
554: /*
555: * Create buffers for all input and output pipes.
556: */
557: SLIST_FOREACH(fa, &ifiles, entry) {
1.17 jakemsr 558: newinput(fa, &cipar, cinfr, quiet_flag);
1.15 ratchov 559: if (mix)
560: aproc_setin(mix, fa->buf);
1.17 jakemsr 561: if (!quiet_flag) {
562: fprintf(stderr, "%s: reading ", fa->name);
563: aparams_print(&fa->par);
564: fprintf(stderr, "\n");
565: }
1.15 ratchov 566: }
567: SLIST_FOREACH(fa, &ofiles, entry) {
1.17 jakemsr 568: newoutput(fa, &copar, confr, quiet_flag);
1.15 ratchov 569: if (sub)
570: aproc_setout(sub, fa->buf);
1.17 jakemsr 571: if (!quiet_flag) {
572: fprintf(stderr, "%s: writing ", fa->name);
573: aparams_print(&fa->par);
574: fprintf(stderr, "\n");
575: }
1.15 ratchov 576: }
1.13 uwe 577:
1.15 ratchov 578: /*
579: * Connect the multiplexer to the device input.
580: */
581: if (sub) {
582: buf = abuf_new(dinfr, aparams_bpf(&dipar));
583: aproc_setout(rec, buf);
584: if (!aparams_eq(&copar, &dipar)) {
1.17 jakemsr 585: if (!quiet_flag) {
586: fprintf(stderr, "%s: ", devpath);
587: aparams_print2(&dipar, &copar);
588: fprintf(stderr, "\n");
589: }
1.15 ratchov 590: conv = conv_new("subconv", &dipar, &copar);
591: cbuf = abuf_new(confr, aparams_bpf(&copar));
592: aproc_setin(conv, buf);
593: aproc_setout(conv, cbuf);
594: aproc_setin(sub, cbuf);
595: } else
596: aproc_setin(sub, buf);
597: }
1.13 uwe 598:
1.15 ratchov 599: /*
600: * Normalize input levels and connect the mixer to the device
601: * output.
602: */
603: if (mix) {
604: n = 0;
605: SLIST_FOREACH(fa, &ifiles, entry)
606: n++;
607: SLIST_FOREACH(fa, &ifiles, entry)
608: fa->buf->mixvol /= n;
609: buf = abuf_new(donfr, aparams_bpf(&dopar));
610: aproc_setin(play, buf);
611: if (!aparams_eq(&cipar, &dopar)) {
1.17 jakemsr 612: if (!quiet_flag) {
613: fprintf(stderr, "%s: ", devpath);
614: aparams_print2(&cipar, &dopar);
615: fprintf(stderr, "\n");
616: }
1.15 ratchov 617: conv = conv_new("mixconv", &cipar, &dopar);
618: cbuf = abuf_new(cinfr, aparams_bpf(&cipar));
619: aproc_setout(conv, buf);
620: aproc_setin(conv, cbuf);
621: aproc_setout(mix, cbuf);
622: } else
623: aproc_setout(mix, buf);
624: }
1.13 uwe 625:
1.15 ratchov 626: /*
627: * start audio
628: */
629: if (play != NULL) {
1.17 jakemsr 630: if (!quiet_flag)
631: fprintf(stderr, "filling buffers...\n");
1.15 ratchov 632: while (!quit_flag) {
633: /* no more devices to poll */
634: if (!file_poll())
635: break;
636: /* device is blocked */
637: if (dev->events & POLLOUT)
638: break;
639: /* eof */
640: if (dev->state & FILE_EOF)
641: break;
1.4 millert 642: }
643: }
1.17 jakemsr 644: if (!quiet_flag)
645: fprintf(stderr, "starting device...\n");
1.15 ratchov 646: dev_start(dev->fd);
647: dev->state &= ~(FILE_RFLOW | FILE_WFLOW);
648: while (!quit_flag) {
649: if (!file_poll())
650: break;
651: }
1.11 jaredy 652:
1.17 jakemsr 653: if (!quiet_flag)
654: fprintf(stderr, "draining buffers...\n");
1.11 jaredy 655:
1.15 ratchov 656: /*
657: * generate EOF on all files that do input, so
658: * once buffers are drained, everything will be cleaned
659: */
660: LIST_FOREACH(f, &file_list, entry) {
661: if ((f->events) & POLLIN || (f->state & FILE_ROK))
662: file_eof(f);
663: }
664: for (;;) {
665: if (!file_poll())
666: break;
667: }
668: SLIST_FOREACH(fa, &ofiles, entry) {
669: if (fa->hdr == HDR_WAV)
670: wav_writehdr(fa->fd, &fa->par);
671: close(fa->fd);
672: DPRINTF("%s: closed\n", fa->name);
673: }
674: dev_stop(dev->fd);
675: file_stop();
676: return 0;
1.1 kstailey 677: }