=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/aucat/aucat.c,v retrieving revision 1.80 retrieving revision 1.81 diff -u -r1.80 -r1.81 --- src/usr.bin/aucat/aucat.c 2010/01/14 17:43:55 1.80 +++ src/usr.bin/aucat/aucat.c 2010/04/03 17:40:33 1.81 @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.80 2010/01/14 17:43:55 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.81 2010/04/03 17:40:33 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -43,9 +43,6 @@ #include "dbg.h" #endif -#define MODE_PLAY 1 -#define MODE_REC 2 - #define PROG_AUCAT "aucat" #define PROG_MIDICAT "midicat" @@ -159,16 +156,33 @@ errx(1, "%s: bad underrun/overrun policy", optarg); } -int +unsigned opt_mode(void) { - if (strcmp("play", optarg) == 0) - return MODE_PLAY; - if (strcmp("rec", optarg) == 0) - return MODE_REC; - if (strcmp("duplex", optarg) == 0) - return MODE_PLAY | MODE_REC; - errx(1, "%s: bad mode", optarg); + unsigned mode = 0; + char *p = optarg; + size_t len; + + for (p = optarg; *p != NULL; p++) { + len = strcspn(p, ","); + if (strncmp("play", p, len) == 0) { + mode |= MODE_PLAY; + } else if (strncmp("rec", p, len) == 0) { + mode |= MODE_REC; + } else if (strncmp("mon", p, len) == 0) { + mode |= MODE_MON; + } else if (strncmp("duplex", p, len) == 0) { + /* XXX: backward compat, remove this */ + mode |= MODE_REC | MODE_PLAY; + } else + errx(1, "%s: bad mode", optarg); + p += len; + if (*p == '\0') + break; + } + if (mode == 0) + errx(1, "empty mode"); + return mode; } /* @@ -183,6 +197,7 @@ int hdr; /* header format */ int xrun; /* overrun/underrun policy */ int mmc; /* MMC mode */ + unsigned mode; }; SLIST_HEAD(farglist, farg); @@ -194,7 +209,7 @@ void farg_add(struct farglist *list, struct aparams *ipar, struct aparams *opar, unsigned vol, - int hdr, int xrun, int mmc, char *name) + int hdr, int xrun, int mmc, unsigned mode, char *name) { struct farg *fa; size_t namelen; @@ -212,12 +227,15 @@ } } else fa->hdr = hdr; + if (mmc && xrun == XRUN_IGNORE) + xrun = XRUN_SYNC; fa->xrun = xrun; fa->ipar = *ipar; fa->opar = *opar; fa->vol = vol; fa->name = name; fa->mmc = mmc; + fa->mode = mode; SLIST_INSERT_HEAD(list, fa, entry); } @@ -287,28 +305,61 @@ } void +stopall(char *base) +{ + struct file *f; + + restart: + LIST_FOREACH(f, &file_list, entry) { + /* + * skip connected streams (handled by dev_done()) + */ + if (APROC_OK(dev_mix) && f->rproc && + aproc_depend(dev_mix, f->rproc)) + continue; + if (APROC_OK(dev_sub) && f->wproc && + aproc_depend(f->wproc, dev_sub)) + continue; + if (APROC_OK(dev_midi)) { + if (f->rproc && aproc_depend(dev_midi, f->rproc)) + continue; + if (f->wproc && aproc_depend(f->wproc, dev_midi)) + continue; + } + /* + * kill anything else + */ + file_close(f); + goto restart; + } +} + +void aucat_usage(void) { (void)fputs("usage: " PROG_AUCAT " [-dlnu] [-b nframes] " - "[-C min:max] [-c min:max] [-e enc] [-f device]\n" - "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s name]\n" - "\t[-t mode] [-U unit] [-v volume] [-x policy] [-z nframes]\n", + "[-C min:max] [-c min:max] [-e enc]\n\t" + "[-f device] [-h fmt] [-i file] [-m mode]" + "[-o file] [-q device]\n\t" + "[-r rate] [-s name] [-t mode] [-U unit] " + "[-v volume] [-x policy]\n\t" + "[-z nframes]\n", stderr); } int aucat_main(int argc, char **argv) { - int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, suspend = 0, unit; + int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, unit; struct farg *fa; - struct farglist ifiles, ofiles, sfiles; + struct farglist ifiles, ofiles, sfiles, qfiles; struct aparams ipar, opar, dipar, dopar; char base[PATH_MAX], path[PATH_MAX], *file; unsigned bufsz, round, mode; char *devpath; const char *str; unsigned volctl; - int mmc; + int mmc, autostart; aparams_init(&ipar, 0, 1, 44100); aparams_init(&opar, 0, 1, 44100); @@ -322,14 +373,16 @@ SLIST_INIT(&ifiles); SLIST_INIT(&ofiles); SLIST_INIT(&sfiles); + SLIST_INIT(&qfiles); hdr = HDR_AUTO; xrun = XRUN_IGNORE; volctl = MIDI_MAXCTL; - mode = 0; + mode = MODE_PLAY | MODE_REC; bufsz = 0; round = 0; + autostart = 1; - while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:lus:U:t:z:")) != -1) { + while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:z:")) != -1) { switch (c) { case 'd': #ifdef DEBUG @@ -352,6 +405,8 @@ break; case 't': mmc = opt_mmc(); + if (mmc) + autostart = 0; break; case 'c': opt_ch(&ipar); @@ -379,19 +434,23 @@ if (strcmp(file, "-") == 0) file = NULL; farg_add(&ifiles, &ipar, &opar, volctl, - hdr, xrun, 0, file); + hdr, xrun, mmc, mode & MODE_PLAY, file); break; case 'o': file = optarg; if (strcmp(file, "-") == 0) file = NULL; farg_add(&ofiles, &ipar, &opar, volctl, - hdr, xrun, 0, file); + hdr, xrun, mmc, mode & MODE_RECMASK, file); break; case 's': farg_add(&sfiles, &ipar, &opar, volctl, - hdr, xrun, mmc, optarg); + hdr, xrun, mmc, mode, optarg); break; + case 'q': + farg_add(&qfiles, &aparams_none, &aparams_none, + 0, HDR_RAW, 0, 0, 0, optarg); + break; case 'f': if (devpath) err(1, "only one -f allowed"); @@ -401,6 +460,7 @@ break; case 'l': l_flag = 1; + autostart = 0; break; case 'u': u_flag = 1; @@ -451,22 +511,12 @@ if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0)) errx(1, "can't use -s or -U without -l"); - if ((l_flag || mode != 0) && - (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles))) - errx(1, "can't use -l, -m and -s with -o or -i"); - if (!mode) { - if (l_flag || !SLIST_EMPTY(&ifiles)) - mode |= MODE_PLAY; - if (l_flag || !SLIST_EMPTY(&ofiles)) - mode |= MODE_REC; - if (!mode) { - aucat_usage(); - exit(1); - } - } + if (l_flag && (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles))) + errx(1, "can't use -l, and -s with -o or -i"); if (n_flag) { - if (devpath != NULL || l_flag) - errx(1, "can't use -n with -f or -l"); + if (devpath != NULL || !SLIST_EMPTY(&qfiles) || + l_flag || !autostart) + errx(1, "can't use -n with -f, -q, -t or -l"); if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles)) errx(1, "both -i and -o are required with -n"); } @@ -476,28 +526,43 @@ */ if (l_flag && SLIST_EMPTY(&sfiles)) { farg_add(&sfiles, &dopar, &dipar, - volctl, HDR_RAW, XRUN_IGNORE, mmc, DEFAULT_OPT); + volctl, HDR_RAW, XRUN_IGNORE, mmc, mode, DEFAULT_OPT); } - if (!u_flag) { - /* - * Calculate "best" device parameters. Iterate over all - * inputs and outputs and find the maximum sample rate - * and channel number. - */ - aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate); - aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate); - SLIST_FOREACH(fa, &ifiles, entry) { + /* + * Check modes and calculate "best" device parameters. Iterate over all + * inputs and outputs and find the maximum sample rate and channel + * number. + */ + mode = 0; + aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate); + aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate); + SLIST_FOREACH(fa, &ifiles, entry) { + if (fa->mode == 0) + errx(1, "%s: not in play mode", fa->name); + mode |= fa->mode; + if (!u_flag) aparams_grow(&dopar, &fa->ipar); - } - SLIST_FOREACH(fa, &ofiles, entry) { + } + SLIST_FOREACH(fa, &ofiles, entry) { + if (fa->mode == 0) + errx(1, "%s: not in rec/mon mode", fa->name); + if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON)) + errx(1, "%s: can't record and monitor", fa->name); + mode |= fa->mode; + if (!u_flag) aparams_grow(&dipar, &fa->opar); - } - SLIST_FOREACH(fa, &sfiles, entry) { + } + SLIST_FOREACH(fa, &sfiles, entry) { + if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON)) + errx(1, "%s: can't record and monitor", fa->name); + mode |= fa->mode; + if (!u_flag) { aparams_grow(&dopar, &fa->ipar); aparams_grow(&dipar, &fa->opar); } } + if (!round) round = ((mode & MODE_REC) ? dipar.rate : dopar.rate) / 15; if (!bufsz) @@ -516,12 +581,13 @@ * the other half is for the socket/files. */ if (n_flag) { + if (mode & MODE_MON) + errx(1, "monitoring not allowed in loopback mode"); dev_loopinit(&dipar, &dopar, bufsz); } else { - if (!dev_init(devpath, - (mode & MODE_REC) ? &dipar : NULL, - (mode & MODE_PLAY) ? &dopar : NULL, - bufsz, round)) { + if ((mode & MODE_MON) && !(mode & MODE_PLAY)) + errx(1, "no playback stream to monitor"); + if (!dev_init(devpath, mode, &dipar, &dopar, bufsz, round)) { errx(1, "%s: can't open device", devpath ? devpath : ""); } @@ -530,26 +596,33 @@ /* * Create buffers for all input and output pipes. */ + while (!SLIST_EMPTY(&qfiles)) { + fa = SLIST_FIRST(&qfiles); + SLIST_REMOVE_HEAD(&qfiles, entry); + if (!dev_thruadd(fa->name, 1, 1)) + errx(1, "%s: can't open device", fa->name); + free(fa); + } while (!SLIST_EMPTY(&ifiles)) { fa = SLIST_FIRST(&ifiles); SLIST_REMOVE_HEAD(&ifiles, entry); - if (!wav_new_in(&wav_ops, fa->name, - fa->hdr, &fa->ipar, fa->xrun, fa->vol)) + if (!wav_new_in(&wav_ops, fa->mode, fa->name, + fa->hdr, &fa->ipar, fa->xrun, fa->vol, fa->mmc)) exit(1); free(fa); } while (!SLIST_EMPTY(&ofiles)) { fa = SLIST_FIRST(&ofiles); SLIST_REMOVE_HEAD(&ofiles, entry); - if (!wav_new_out(&wav_ops, fa->name, - fa->hdr, &fa->opar, fa->xrun)) + if (!wav_new_out(&wav_ops, fa->mode, fa->name, + fa->hdr, &fa->opar, fa->xrun, fa->mmc)) free(fa); } while (!SLIST_EMPTY(&sfiles)) { fa = SLIST_FIRST(&sfiles); SLIST_REMOVE_HEAD(&sfiles, entry); opt_new(fa->name, &fa->opar, &fa->ipar, - MIDI_TO_ADATA(fa->vol), fa->mmc); + MIDI_TO_ADATA(fa->vol), fa->mmc, fa->mode); free(fa); } if (l_flag) { @@ -559,6 +632,14 @@ if (!d_flag && daemon(0, 0) < 0) err(1, "daemon"); } + if (autostart) { + /* + * inject artificial mmc start + */ + ctl_start(dev_midi); + } + if (l_flag) + dev_prime(); /* * Loop, start audio. @@ -567,57 +648,48 @@ if (quit_flag) { break; } - if ((dev_mix && LIST_EMPTY(&dev_mix->obuflist)) || - (dev_sub && LIST_EMPTY(&dev_sub->ibuflist))) { + if ((APROC_OK(dev_mix) && LIST_EMPTY(&dev_mix->obuflist)) || + (APROC_OK(dev_sub) && LIST_EMPTY(&dev_sub->ibuflist))) { fprintf(stderr, "device disappeared, terminating\n"); break; } + if (!l_flag && ctl_idle(dev_midi)) + break; if (!file_poll()) break; - if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) && - (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz) && - ((dev_mix || dev_sub) && dev_midi->u.ctl.tstate != CTL_RUN)) { - if (!l_flag) - break; - if (!suspend) { -#ifdef DEBUG - if (debug_level >= 2) - dbg_puts("suspending\n"); -#endif - suspend = 1; + if ((!APROC_OK(dev_mix) || dev_mix->u.mix.idle > 2 * dev_bufsz) && + (!APROC_OK(dev_sub) || dev_sub->u.sub.idle > 2 * dev_bufsz) && + (!APROC_OK(dev_submon) || dev_submon->u.sub.idle > 2 * dev_bufsz) && + (!APROC_OK(dev_midi) || dev_midi->u.ctl.tstate != CTL_RUN)) { + if (dev_pstate == DEV_RUN) { + dev_pstate = DEV_INIT; dev_stop(); dev_clear(); - dev_prime(); + /* + * priming buffer in non-server mode is not + * ok, because it will insert silence and + * break synchronization + */ + if (l_flag) + dev_prime(); } } - if ((dev_mix && dev_mix->u.mix.idle == 0) || - (dev_sub && dev_sub->u.sub.idle == 0) || - ((dev_mix || dev_sub) && dev_midi->u.ctl.tstate == CTL_RUN)) { - if (suspend) { -#ifdef DEBUG - if (debug_level >= 2) - dbg_puts("resuming\n"); -#endif - suspend = 0; - dev_start(); - } + /* + * move device state machine + * XXX: move this to dev.c + */ + if (dev_pstate == DEV_START) { + dev_pstate = DEV_RUN; + dev_start(); } } + stopall(base); + dev_done(); + filelist_done(); if (l_flag) { - filelist_unlisten(); - if (rmdir(base) < 0) + if (rmdir(base) < 0 && errno != ENOTEMPTY) warn("rmdir(\"%s\")", base); } - if (suspend) { -#ifdef DEBUG - if (debug_level >= 2) - dbg_puts("resuming to drain\n"); -#endif - suspend = 0; - dev_start(); - } - dev_done(); - filelist_done(); unsetsig(); return 0; } @@ -625,8 +697,8 @@ void midicat_usage(void) { - (void)fputs("usage: " PROG_MIDICAT " [-dl] [-f device] " - "[-i file] [-o file] [-U unit]\n", + (void)fputs("usage: " PROG_MIDICAT " [-dl] " + "[-i file] [-o file] [-q device] [-U unit]\n", stderr); } int @@ -648,7 +720,7 @@ SLIST_INIT(&ifiles); SLIST_INIT(&ofiles); - while ((c = getopt(argc, argv, "di:o:lf:U:")) != -1) { + while ((c = getopt(argc, argv, "di:o:lf:q:U:")) != -1) { switch (c) { case 'd': #ifdef DEBUG @@ -659,15 +731,17 @@ break; case 'i': farg_add(&ifiles, &aparams_none, &aparams_none, - 0, HDR_RAW, 0, 0, optarg); + 0, HDR_RAW, 0, 0, 0, optarg); break; case 'o': farg_add(&ofiles, &aparams_none, &aparams_none, - 0, HDR_RAW, 0, 0, optarg); + 0, HDR_RAW, 0, 0, 0, optarg); break; - case 'f': + /* XXX: backward compat, remove this */ + case 'f': + case 'q': farg_add(&dfiles, &aparams_none, &aparams_none, - 0, HDR_RAW, 0, 0, optarg); + 0, HDR_RAW, 0, 0, 0, optarg); break; case 'l': l_flag = 1; @@ -703,12 +777,12 @@ filelist_init(); dev_thruinit(); - if (!l_flag) + if (!l_flag && APROC_OK(dev_midi)) dev_midi->flags |= APROC_QUIT; if ((!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles)) && SLIST_EMPTY(&dfiles)) { farg_add(&dfiles, &aparams_none, &aparams_none, - 0, HDR_RAW, 0, 0, NULL); + 0, HDR_RAW, 0, 0, 0, NULL); } while (!SLIST_EMPTY(&dfiles)) { fa = SLIST_FIRST(&dfiles); @@ -767,7 +841,6 @@ dev_midiattach(NULL, buf); free(fa); } - /* * loop, start processing */ @@ -778,13 +851,13 @@ if (!file_poll()) break; } + stopall(base); + dev_done(); + filelist_done(); if (l_flag) { - filelist_unlisten(); - if (rmdir(base) < 0) + if (rmdir(base) < 0 && errno != ENOTEMPTY) warn("rmdir(\"%s\")", base); } - dev_done(); - filelist_done(); unsetsig(); return 0; }