summaryrefslogtreecommitdiff
path: root/usr.bin/aucat/aucat.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/aucat/aucat.c')
-rw-r--r--usr.bin/aucat/aucat.c299
1 files changed, 186 insertions, 113 deletions
diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c
index 81093f42a4c..bb70afd7703 100644
--- a/usr.bin/aucat/aucat.c
+++ b/usr.bin/aucat/aucat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aucat.c,v 1.82 2010/04/03 17:59:17 ratchov Exp $ */
+/* $OpenBSD: aucat.c,v 1.83 2010/04/06 20:07:01 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -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 @@ opt_xrun(void)
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 @@ struct farg {
int hdr; /* header format */
int xrun; /* overrun/underrun policy */
int mmc; /* MMC mode */
+ unsigned mode;
};
SLIST_HEAD(farglist, farg);
@@ -194,7 +209,7 @@ SLIST_HEAD(farglist, farg);
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 @@ farg_add(struct farglist *list,
}
} 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 @@ getbasepath(char *base, size_t size)
}
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 @@ aucat_main(int argc, char **argv)
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 @@ aucat_main(int argc, char **argv)
break;
case 't':
mmc = opt_mmc();
+ if (mmc)
+ autostart = 0;
break;
case 'c':
opt_ch(&ipar);
@@ -379,18 +434,22 @@ aucat_main(int argc, char **argv)
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)
@@ -401,6 +460,7 @@ aucat_main(int argc, char **argv)
break;
case 'l':
l_flag = 1;
+ autostart = 0;
break;
case 'u':
u_flag = 1;
@@ -451,22 +511,12 @@ aucat_main(int argc, char **argv)
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 @@ aucat_main(int argc, char **argv)
*/
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 @@ aucat_main(int argc, char **argv)
* 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 : "<default>");
}
@@ -530,26 +596,33 @@ aucat_main(int argc, char **argv)
/*
* 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 @@ aucat_main(int argc, char **argv)
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 @@ aucat_main(int argc, char **argv)
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 @@ aucat_main(int argc, char **argv)
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 @@ midicat_main(int argc, char **argv)
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 @@ midicat_main(int argc, char **argv)
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 @@ midicat_main(int argc, char **argv)
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 @@ midicat_main(int argc, char **argv)
dev_midiattach(NULL, buf);
free(fa);
}
-
/*
* loop, start processing
*/
@@ -778,13 +851,13 @@ midicat_main(int argc, char **argv)
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;
}