=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/aucat/aucat.c,v retrieving revision 1.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- src/usr.bin/aucat/aucat.c 2008/06/02 17:09:51 1.25 +++ src/usr.bin/aucat/aucat.c 2008/08/14 09:58:55 1.26 @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.25 2008/06/02 17:09:51 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.26 2008/08/14 09:58:55 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -17,10 +17,6 @@ /* * TODO: * - * (not yet)add a silent/quiet/verbose/whatever flag, but be sure - * that by default the user is notified when one of the following - * (cpu consuming) aproc is created: mix, sub, conv - * * (hard) use parsable encoding names instead of the lookup * table. For instance, [s|u]bits[le|be][/bytes{msb|lsb}], example * s8, s16le, s24le/3msb. This would give names that correspond to @@ -34,8 +30,6 @@ * s24le/3msb,{3-6},48000 so we don't have to use three -e, -r, -c * flags, but only one -p flag that specify one or more parameters. * - * (hard) dont create mix (sub) if there's only one input (output) - * * (hard) if all inputs are over, the mixer terminates and closes * the write end of the device. It should continue writing zeros * until the recording is over (or be able to stop write end of @@ -48,8 +42,6 @@ * they provide are not used on the output). Similarly ignore * outputs that are zero filled (because channels they consume are * not provided). - * - * (easy) do we need -d flag ? */ #include @@ -72,15 +64,12 @@ #include "file.h" #include "dev.h" -/* - * Format for file headers. - */ -#define HDR_AUTO 0 /* guess by looking at the file name */ -#define HDR_RAW 1 /* no headers, ie openbsd native ;-) */ -#define HDR_WAV 2 /* microsoft riff wave */ +int debug_level = 0, quiet_flag = 0; +volatile int quit_flag = 0, pause_flag = 0; -int debug_level = 0; -volatile int quit_flag = 0; +void suspend(struct file *); +void fill(struct file *); +void flush(struct file *); /* * List of allowed encodings and their names. @@ -212,9 +201,6 @@ char *name; /* optarg pointer (no need to copy it */ int hdr; /* header format */ int xrun; /* overrun/underrun policy */ - int fd; /* file descriptor for I/O */ - struct aproc *proc; /* rpipe_xxx our wpipe_xxx */ - struct abuf *buf; }; SLIST_HEAD(farglist, farg); @@ -250,7 +236,6 @@ fa->par = *par; fa->vol = vol; fa->name = optarg; - fa->proc = NULL; SLIST_INSERT_HEAD(list, fa, entry); } @@ -258,12 +243,13 @@ * Open an input file and setup converter if necessary. */ void -newinput(struct farg *fa, struct aparams *npar, unsigned nfr, int quiet_flag) +newinput(struct farg *fa) { int fd; struct file *f; - struct aproc *p, *c; - struct abuf *buf, *nbuf; + struct aproc *proc; + struct abuf *buf; + unsigned nfr; if (strcmp(fa->name, "-") == 0) { fd = STDIN_FILENO; @@ -276,40 +262,30 @@ err(1, "%s", fa->name); } f = file_new(fd, fa->name); + f->hdr = 0; + f->hpar = fa->par; if (fa->hdr == HDR_WAV) { - if (!wav_readhdr(fd, &fa->par, &f->rbytes)) + if (!wav_readhdr(fd, &f->hpar, &f->rbytes)) exit(1); } - buf = abuf_new(nfr, aparams_bpf(&fa->par)); - p = rpipe_new(f); - aproc_setout(p, buf); - if (!aparams_eq(&fa->par, npar)) { - if (!quiet_flag) { - fprintf(stderr, "%s: ", fa->name); - aparams_print2(&fa->par, npar); - fprintf(stderr, "\n"); - } - nbuf = abuf_new(nfr, aparams_bpf(npar)); - c = conv_new(fa->name, &fa->par, npar); - aproc_setin(c, buf); - aproc_setout(c, nbuf); - fa->buf = nbuf; - } else - fa->buf = buf; - fa->proc = p; - fa->fd = fd; + nfr = dev_onfr * f->hpar.rate / dev_opar.rate; + buf = abuf_new(nfr, aparams_bpf(&f->hpar)); + proc = rpipe_new(f); + aproc_setout(proc, buf); + dev_attach(fa->name, buf, &f->hpar, fa->xrun, NULL, NULL, 0); } /* * Open an output file and setup converter if necessary. */ void -newoutput(struct farg *fa, struct aparams *npar, unsigned nfr, int quiet_flag) +newoutput(struct farg *fa) { int fd; struct file *f; - struct aproc *p, *c; - struct abuf *buf, *nbuf; + struct aproc *proc; + struct abuf *buf; + unsigned nfr; if (strcmp(fa->name, "-") == 0) { fd = STDOUT_FILENO; @@ -323,57 +299,30 @@ err(1, "%s", fa->name); } f = file_new(fd, fa->name); - if (fa->hdr == HDR_WAV) { + f->hdr = fa->hdr; + f->hpar = fa->par; + if (f->hdr == HDR_WAV) { f->wbytes = WAV_DATAMAX; - if (!wav_writehdr(fd, &fa->par)) + if (!wav_writehdr(fd, &f->hpar)) exit(1); } - buf = abuf_new(nfr, aparams_bpf(&fa->par)); - p = wpipe_new(f); - aproc_setin(p, buf); - if (!aparams_eq(&fa->par, npar)) { - if (!quiet_flag) { - fprintf(stderr, "%s: ", fa->name); - aparams_print2(npar, &fa->par); - fprintf(stderr, "\n"); - } - c = conv_new(fa->name, npar, &fa->par); - nbuf = abuf_new(nfr, aparams_bpf(npar)); - aproc_setin(c, nbuf); - aproc_setout(c, buf); - fa->buf = nbuf; - } else - fa->buf = buf; - fa->proc = p; - fa->fd = fd; + nfr = dev_infr * f->hpar.rate / dev_ipar.rate; + proc = wpipe_new(f); + buf = abuf_new(nfr, aparams_bpf(&f->hpar)); + aproc_setin(proc, buf); + dev_attach(fa->name, NULL, NULL, 0, buf, &f->hpar, fa->xrun); } -void -sighdl(int s) -{ - if (quit_flag) - _exit(1); - quit_flag = 1; -} - int main(int argc, char **argv) { - sigset_t sigset; - struct sigaction sa; - int c, u_flag, quiet_flag, ohdr, ihdr, ixrun, oxrun; + int c, u_flag, ohdr, ihdr, ixrun, oxrun; struct farg *fa; struct farglist ifiles, ofiles; - struct aparams ipar, opar, dipar, dopar, cipar, copar; + struct aparams ipar, opar, dipar, dopar; unsigned ivol, ovol; - unsigned dinfr, donfr, cinfr, confr; char *devpath, *dbgenv; - unsigned n; - struct aproc *rec, *play, *mix, *sub, *conv; - struct file *dev, *f; - struct abuf *buf, *cbuf; const char *errstr; - int fd; dbgenv = getenv("AUCAT_DEBUG"); if (dbgenv) { @@ -385,7 +334,7 @@ aparams_init(&ipar, 0, 1, 44100); aparams_init(&opar, 0, 1, 44100); - u_flag = quiet_flag = 0; + u_flag = 0; devpath = NULL; SLIST_INIT(&ifiles); SLIST_INIT(&ofiles); @@ -477,240 +426,77 @@ exit(1); } - sigfillset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sa.sa_handler = sighdl; - if (sigaction(SIGINT, &sa, NULL) < 0) - err(1, "sigaction"); - sigemptyset(&sigset); - (void)sigaddset(&sigset, SIGTSTP); - (void)sigaddset(&sigset, SIGCONT); - if (sigprocmask(SIG_BLOCK, &sigset, NULL)) - err(1, "sigprocmask"); - - file_start(); - play = rec = mix = sub = NULL; - - aparams_init(&cipar, CHAN_MAX, 0, RATE_MIN); - aparams_init(&copar, CHAN_MAX, 0, RATE_MAX); - - /* - * Iterate over all inputs and outputs and find the maximum - * sample rate and channel number. - */ - SLIST_FOREACH(fa, &ifiles, entry) { - if (cipar.cmin > fa->par.cmin) - cipar.cmin = fa->par.cmin; - if (cipar.cmax < fa->par.cmax) - cipar.cmax = fa->par.cmax; - if (cipar.rate < fa->par.rate) - cipar.rate = fa->par.rate; - } - SLIST_FOREACH(fa, &ofiles, entry) { - if (copar.cmin > fa->par.cmin) - copar.cmin = fa->par.cmin; - if (copar.cmax < fa->par.cmax) - copar.cmax = fa->par.cmax; - if (copar.rate > fa->par.rate) - copar.rate = fa->par.rate; - } - - /* - * Open the device and increase the maximum sample rate. - * channel number to include those used by the device - */ if (!u_flag) { - dipar = copar; - dopar = cipar; - } - fd = dev_init(devpath, - !SLIST_EMPTY(&ofiles) ? &dipar : NULL, - !SLIST_EMPTY(&ifiles) ? &dopar : NULL, &dinfr, &donfr); - if (fd < 0) - exit(1); - if (!SLIST_EMPTY(&ofiles)) { - if (!quiet_flag) { - fprintf(stderr, "%s: recording ", devpath); - aparams_print(&dipar); - fprintf(stderr, "\n"); + /* + * Calculate "best" device parameters. Iterate over all + * inputs and outputs and find the maximum sample rate + * and channel number. + */ + aparams_init(&dipar, CHAN_MAX, 0, RATE_MAX); + aparams_init(&dopar, CHAN_MAX, 0, RATE_MIN); + SLIST_FOREACH(fa, &ifiles, entry) { + if (dopar.cmin > fa->par.cmin) + dopar.cmin = fa->par.cmin; + if (dopar.cmax < fa->par.cmax) + dopar.cmax = fa->par.cmax; + if (dopar.rate < fa->par.rate) + dopar.rate = fa->par.rate; } - if (copar.cmin > dipar.cmin) - copar.cmin = dipar.cmin; - if (copar.cmax < dipar.cmax) - copar.cmax = dipar.cmax; - if (copar.rate > dipar.rate) - copar.rate = dipar.rate; - dinfr *= DEFAULT_NBLK; - DPRINTF("%s: using %ums rec buffer\n", devpath, - 1000 * dinfr / dipar.rate); - } - if (!SLIST_EMPTY(&ifiles)) { - if (!quiet_flag) { - fprintf(stderr, "%s: playing ", devpath); - aparams_print(&dopar); - fprintf(stderr, "\n"); + SLIST_FOREACH(fa, &ofiles, entry) { + if (dipar.cmin > fa->par.cmin) + dipar.cmin = fa->par.cmin; + if (dipar.cmax < fa->par.cmax) + dipar.cmax = fa->par.cmax; + if (dipar.rate > fa->par.rate) + dipar.rate = fa->par.rate; } - if (cipar.cmin > dopar.cmin) - cipar.cmin = dopar.cmin; - if (cipar.cmax < dopar.cmax) - cipar.cmax = dopar.cmax; - if (cipar.rate < dopar.rate) - cipar.rate = dopar.rate; - donfr *= DEFAULT_NBLK; - DPRINTF("%s: using %ums play buffer\n", devpath, - 1000 * donfr / dopar.rate); } - - /* - * Create buffers for the device. - */ - dev = file_new(fd, devpath); - if (!SLIST_EMPTY(&ofiles)) { - rec = rpipe_new(dev); - sub = sub_new(); - } - if (!SLIST_EMPTY(&ifiles)) { - play = wpipe_new(dev); - mix = mix_new(); - } + file_start(); /* - * Calculate sizes of buffers using "common" parameters, to - * have roughly the same duration as device buffers. + * Open the device, dev_init() will return new parameters + * that must be used by all inputs and outputs. */ - cinfr = donfr * cipar.rate / dopar.rate; - confr = dinfr * copar.rate / dipar.rate; + dev_init(devpath, + (!SLIST_EMPTY(&ofiles)) ? &dipar : NULL, + (!SLIST_EMPTY(&ifiles)) ? &dopar : NULL); /* * Create buffers for all input and output pipes. */ - SLIST_FOREACH(fa, &ifiles, entry) { - newinput(fa, &cipar, cinfr, quiet_flag); - if (mix) { - aproc_setin(mix, fa->buf); - fa->buf->xrun = fa->xrun; - } - if (!quiet_flag) { - fprintf(stderr, "%s: reading ", fa->name); - aparams_print(&fa->par); - fprintf(stderr, "\n"); - } + while (!SLIST_EMPTY(&ifiles)) { + fa = SLIST_FIRST(&ifiles); + SLIST_REMOVE_HEAD(&ifiles, entry); + newinput(fa); + free(fa); } - SLIST_FOREACH(fa, &ofiles, entry) { - newoutput(fa, &copar, confr, quiet_flag); - if (sub) { - aproc_setout(sub, fa->buf); - fa->buf->xrun = fa->xrun; - } - if (!quiet_flag) { - fprintf(stderr, "%s: writing ", fa->name); - aparams_print(&fa->par); - fprintf(stderr, "\n"); - } + while (!SLIST_EMPTY(&ofiles)) { + fa = SLIST_FIRST(&ofiles); + SLIST_REMOVE_HEAD(&ofiles, entry); + newoutput(fa); + free(fa); } /* - * Connect the multiplexer to the device input. + * Normalize input levels */ - if (sub) { - buf = abuf_new(dinfr, aparams_bpf(&dipar)); - aproc_setout(rec, buf); - if (!aparams_eq(&copar, &dipar)) { - if (!quiet_flag) { - fprintf(stderr, "%s: ", devpath); - aparams_print2(&dipar, &copar); - fprintf(stderr, "\n"); - } - conv = conv_new("subconv", &dipar, &copar); - cbuf = abuf_new(confr, aparams_bpf(&copar)); - aproc_setin(conv, buf); - aproc_setout(conv, cbuf); - aproc_setin(sub, cbuf); - } else - aproc_setin(sub, buf); - } + if (dev_mix) + mix_setmaster(dev_mix); /* - * Normalize input levels and connect the mixer to the device - * output. - */ - if (mix) { - n = 0; - SLIST_FOREACH(fa, &ifiles, entry) - n++; - SLIST_FOREACH(fa, &ifiles, entry) - fa->buf->mixvol /= n; - buf = abuf_new(donfr, aparams_bpf(&dopar)); - aproc_setin(play, buf); - if (!aparams_eq(&cipar, &dopar)) { - if (!quiet_flag) { - fprintf(stderr, "%s: ", devpath); - aparams_print2(&cipar, &dopar); - fprintf(stderr, "\n"); - } - conv = conv_new("mixconv", &cipar, &dopar); - cbuf = abuf_new(cinfr, aparams_bpf(&cipar)); - aproc_setout(conv, buf); - aproc_setin(conv, cbuf); - aproc_setout(mix, cbuf); - } else - aproc_setout(mix, buf); - } - - /* * start audio */ - if (play != NULL) { - if (!quiet_flag) - fprintf(stderr, "filling buffers...\n"); - buf = LIST_FIRST(&play->ibuflist); - while (!quit_flag) { - /* no more devices to poll */ - if (!file_poll()) - break; - /* eof */ - if (dev->state & FILE_EOF) - break; - /* device is blocked and play buffer is full */ - if ((dev->events & POLLOUT) && !ABUF_WOK(buf)) - break; - } - } if (!quiet_flag) fprintf(stderr, "starting device...\n"); - dev_start(dev->fd); - if (mix) - mix->u.mix.flags |= MIX_DROP; - if (sub) - sub->u.sub.flags |= SUB_DROP; - while (!quit_flag) { - if (!file_poll()) - break; - } - + dev_start(); if (!quiet_flag) - fprintf(stderr, "draining buffers...\n"); + fprintf(stderr, "process started...\n"); + dev_run(1); + if (!quiet_flag) + fprintf(stderr, "stopping device...\n"); + dev_done(); - /* - * generate EOF on all files that do input, so - * once buffers are drained, everything will be cleaned - */ - LIST_FOREACH(f, &file_list, entry) { - if ((f->events) & POLLIN || (f->state & FILE_ROK)) - file_eof(f); - } - for (;;) { - if (!file_poll()) - break; - } - SLIST_FOREACH(fa, &ofiles, entry) { - if (fa->hdr == HDR_WAV) - wav_writehdr(fa->fd, &fa->par); - close(fa->fd); - DPRINTF("%s: closed\n", fa->name); - } - dev_stop(dev->fd); file_stop(); return 0; }