From 1d03551d3bdde57b6b26304c15d01e24fa830fd2 Mon Sep 17 00:00:00 2001 From: Alexandre Ratchov Date: Tue, 15 Nov 2011 08:05:23 +0000 Subject: Add a "device number" component in sndio(7) device names, allowing a single aucat instance to handle all audio and MIDI services. Since this partially breaks compatibility, this is a opportunitiy to fix few other design mistakes (eg ':' being used by inet6, type name vs api name confusion, etc..). This leads to the following names: type[@hostname][,unit]/devnum[.option] The device number is the minor device number for direct hardware access (ie the 'N' in /dev/audioN). For aucat, this is the occurence number of the -f (or -M) option. There's a compatibility hook to keep old names working if only one aucat server is running. --- usr.bin/aucat/aucat.1 | 32 ++++++++++++------------ usr.bin/aucat/aucat.c | 39 ++++++++++++++++++++--------- usr.bin/aucat/dev.c | 68 ++++++++++++++++++++++++++++----------------------- usr.bin/aucat/dev.h | 5 +++- usr.bin/aucat/opt.c | 39 +++++++++++------------------ usr.bin/aucat/opt.h | 4 +-- usr.bin/aucat/sock.c | 14 +++++++++-- 7 files changed, 113 insertions(+), 88 deletions(-) (limited to 'usr.bin/aucat') diff --git a/usr.bin/aucat/aucat.1 b/usr.bin/aucat/aucat.1 index f6f85e9da41..7de491f11a1 100644 --- a/usr.bin/aucat/aucat.1 +++ b/usr.bin/aucat/aucat.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: aucat.1,v 1.91 2011/10/24 21:46:21 ratchov Exp $ +.\" $OpenBSD: aucat.1,v 1.92 2011/11/15 08:05:22 ratchov Exp $ .\" .\" Copyright (c) 2006 Alexandre Ratchov .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 24 2011 $ +.Dd $Mdocdate: November 15 2011 $ .Dt AUCAT 1 .Os .Sh NAME @@ -383,8 +383,8 @@ of both definitions are created. The default .Xr sndio 7 device is -.Pa aucat:0 -.Pq also known as Pa aucat:0.default +.Pa snd/0 +.Pq also known as Pa snd/0.default .Pp If .Nm @@ -572,29 +572,29 @@ are recommended: .Pp For instance, the following command will create two devices: the default -.Va aucat:0 +.Va snd/0 and a MIDI-controlled -.Va aucat:0.mmc : +.Va snd/0.mmc : .Bd -literal -offset indent $ aucat -l -r 48000 -z 400 -s default -t slave -s mmc .Ed .Pp Streams connected to -.Va aucat:0 +.Va snd/0 behave normally, while streams connected to -.Va aucat:0.mmc +.Va snd/0.mmc wait for the MMC start signal and start synchronously. Regardless of which device a stream is connected to, its playback volume knob is exposed. .Pp For instance, the following command will play a file on the -.Va aucat:0.mmc +.Va snd/0.mmc audio device, and give full control to MIDI software or hardware connected to the -.Va aucat:0.thru +.Va snd/0.thru MIDI port: .Bd -literal -offset indent -$ aucat -f aucat:0.mmc -t slave -q aucat:0.thru -i file.wav +$ aucat -f snd/0.mmc -t slave -q midithru/0 -i file.wav .Ed .Pp At this stage, @@ -602,7 +602,7 @@ At this stage, will start, stop and relocate automatically following all user actions in the MIDI sequencer. Note that the sequencer must use -.Va aucat:0 +.Va snd/0 as the MTC source, i.e. the audio server, not the audio player. .Sh ENVIRONMENT .Bl -tag -width "AUCAT_COOKIE" -compact @@ -639,9 +639,9 @@ Start in server mode using default parameters, creating an additional sub-device for output to channels 2:3 only (rear speakers on most cards), exposing the -.Pa aucat:0 +.Pa snd/0 and -.Pa aucat:0.rear +.Pa snd/0.rear devices: .Bd -literal -offset indent $ aucat -l -s default -c 2:3 -s rear @@ -651,9 +651,9 @@ Start .Nm in server mode, creating the default sub-device with low volume and an additional sub-device for high volume output, exposing the -.Pa aucat:0 +.Pa snd/0 and -.Pa aucat:0.max +.Pa snd/0.max devices: .Bd -literal -offset indent $ aucat -l -v 65 -s default -v 127 -s max diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c index 4031b37d1b3..ce80ccad1b5 100644 --- a/usr.bin/aucat/aucat.c +++ b/usr.bin/aucat/aucat.c @@ -1,4 +1,4 @@ -/* $OpenBSD: aucat.c,v 1.124 2011/10/18 21:04:26 ratchov Exp $ */ +/* $OpenBSD: aucat.c,v 1.125 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -71,6 +71,13 @@ #define DEFAULT_ROUND (44100 / 15) #endif +/* + * default device in server mode + */ +#ifndef DEFAULT_DEV +#define DEFAULT_DEV "rsnd/0" +#endif + #ifdef DEBUG volatile sig_atomic_t debug_level = 1; #endif @@ -337,7 +344,10 @@ mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol) bufsz = round * 4; } else if (!round) round = bufsz / 4; - return dev_new(path, mode, bufsz, round, hold, autovol); + d = dev_new(path, mode, bufsz, round, hold, autovol); + if (d == NULL) + exit(1); + return d; } struct opt * @@ -537,20 +547,25 @@ main(int argc, char **argv) fputs(usagestr, stderr); exit(1); } - if (wav_list == NULL) { - if (opt_list == NULL) { - d = mkdev(NULL, 0, bufsz, round, 1, autovol); - mkopt("default", d, &rpar, &ppar, - mode, vol, mmc, join); - server = 1; - } - } else { - d = mkdev(NULL, 0, bufsz, round, 1, autovol); - if ((d->reqmode & MODE_THRU) && !d->ctl_list) { + if (wav_list) { + if (server) + errx(1, "-io not allowed in server mode"); + if ((d = dev_list) && d->next) + errx(1, "only one device allowed in non-server mode"); + if ((d->reqmode & MODE_THRU) && d->ctl_list == NULL) { if (!devctl_add(d, "default", MODE_MIDIMASK)) errx(1, "%s: can't open port", optarg); d->reqmode |= MODE_MIDIMASK; } + } else { + if (dev_list == NULL) + mkdev(DEFAULT_DEV, 0, bufsz, round, hold, autovol); + for (d = dev_list; d != NULL; d = d->next) { + if (opt_byname("default", d->num)) + continue; + mkopt("default", d, &rpar, &ppar, mode, vol, mmc, join); + server = 1; + } } if (server) { getbasepath(base, sizeof(base)); diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c index 449898b1078..90e0a6bd31b 100644 --- a/usr.bin/aucat/dev.c +++ b/usr.bin/aucat/dev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.c,v 1.67 2011/10/12 07:20:04 ratchov Exp $ */ +/* $OpenBSD: dev.c,v 1.68 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -62,27 +62,6 @@ * finished draining), then the device * automatically switches to INIT or CLOSED */ -/* - * TODO: - * - * priming buffer is not ok, because it will insert silence and - * break synchronization to other programs. - * - * priming buffer in server mode is required, because f->bufsz may - * be smaller than the server buffer and may cause underrun in the - * dev_bufsz part of the buffer, in turn causing apps to break. It - * doesn't hurt because we care only in synchronization between - * clients. - * - * Priming is not required in non-server mode, because streams - * actually start when they are in the READY state, and their - * buffer is large enough to never cause underruns of dev_bufsz. - * - * Fix sock.c to allocate dev_bufsz, but to use only appbufsz -- - * or whatever -- but to avoid underruns in dev_bufsz. Then remove - * this ugly hack. - * - */ #include #include #include @@ -108,6 +87,21 @@ void dev_clear(struct dev *); int devctl_open(struct dev *, struct devctl *); struct dev *dev_list = NULL; +unsigned dev_sndnum = 0, dev_thrnum = 0; + +#ifdef DEBUG +void +dev_dbg(struct dev *d) +{ + if (d->num >= DEV_NMAX) { + dbg_puts("thr"); + dbg_putu(d->num - DEV_NMAX); + } else { + dbg_puts("snd"); + dbg_putu(d->num); + } +} +#endif /* * Create a sndio device @@ -117,12 +111,24 @@ dev_new(char *path, unsigned mode, unsigned bufsz, unsigned round, unsigned hold, unsigned autovol) { struct dev *d; + unsigned *pnum; d = malloc(sizeof(struct dev)); if (d == NULL) { perror("malloc"); exit(1); } + pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum; + if (*pnum == DEV_NMAX) { +#ifdef DEBUG + if (debug_level >= 1) + dbg_puts("too many devices\n"); +#endif + return NULL; + } + d->num = (*pnum)++; + if (mode & MODE_THRU) + d->num += DEV_NMAX; d->ctl_list = NULL; d->path = path; d->reqmode = mode; @@ -135,7 +141,7 @@ dev_new(char *path, unsigned mode, d->autostart = 0; d->pstate = DEV_CLOSED; d->next = dev_list; - dev_list = d; + dev_list = d; return d; } @@ -161,7 +167,7 @@ dev_init(struct dev *d) { if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) { #ifdef DEBUG - dbg_puts(d->path); + dev_dbg(d); dbg_puts(": has no streams, skipped\n"); #endif return 1; @@ -177,7 +183,7 @@ dev_init(struct dev *d) * Add a MIDI port to the device */ int -devctl_add(struct dev *d, char *name, unsigned mode) +devctl_add(struct dev *d, char *path, unsigned mode) { struct devctl *c; @@ -186,7 +192,7 @@ devctl_add(struct dev *d, char *name, unsigned mode) perror("malloc"); exit(1); } - c->path = name; + c->path = path; c->mode = mode; c->next = d->ctl_list; d->ctl_list = c; @@ -283,6 +289,8 @@ dev_open(struct dev *d) if (f == NULL) { #ifdef DEBUG if (debug_level >= 1) { + dev_dbg(d); + dbg_puts(": "); dbg_puts(d->path); dbg_puts(": failed to open audio device\n"); } @@ -296,7 +304,7 @@ dev_open(struct dev *d) if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) { #ifdef DEBUG if (debug_level >= 1) { - dbg_puts(d->path); + dev_dbg(d); dbg_puts(": mode not supported by device\n"); } #endif @@ -356,13 +364,13 @@ dev_open(struct dev *d) #ifdef DEBUG if (debug_level >= 2) { if (d->mode & MODE_REC) { - dbg_puts(d->path); + dev_dbg(d); dbg_puts(": recording "); aparams_dbg(&d->ipar); dbg_puts("\n"); } if (d->mode & MODE_PLAY) { - dbg_puts(d->path); + dev_dbg(d); dbg_puts(": playing "); aparams_dbg(&d->opar); dbg_puts("\n"); @@ -471,7 +479,7 @@ dev_open(struct dev *d) #ifdef DEBUG if (debug_level >= 2) { if (d->mode & (MODE_PLAY | MODE_RECMASK)) { - dbg_puts(d->path); + dev_dbg(d); dbg_puts(": block size is "); dbg_putu(d->round); dbg_puts(" frames, using "); diff --git a/usr.bin/aucat/dev.h b/usr.bin/aucat/dev.h index e191a74fb57..a572401d9db 100644 --- a/usr.bin/aucat/dev.h +++ b/usr.bin/aucat/dev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dev.h,v 1.30 2011/10/12 07:20:04 ratchov Exp $ */ +/* $OpenBSD: dev.h,v 1.31 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -37,6 +37,8 @@ struct dev { unsigned autovol; /* auto adjust playvol ? */ unsigned autostart; /* don't wait for MMC start */ unsigned refcnt; /* number of openers */ +#define DEV_NMAX 16 /* max number of devices */ + unsigned num; /* serial number */ #define DEV_CLOSED 0 /* closed */ #define DEV_INIT 1 /* stopped */ #define DEV_START 2 /* ready to start */ @@ -62,6 +64,7 @@ struct dev { extern struct dev *dev_list; +void dev_dbg(struct dev *); int dev_init(struct dev *); int dev_run(struct dev *); int dev_ref(struct dev *); diff --git a/usr.bin/aucat/opt.c b/usr.bin/aucat/opt.c index d3a3e993a95..6bcf22b052c 100644 --- a/usr.bin/aucat/opt.c +++ b/usr.bin/aucat/opt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: opt.c,v 1.11 2011/10/12 07:20:04 ratchov Exp $ */ +/* $OpenBSD: opt.c,v 1.12 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -28,7 +28,8 @@ struct opt *opt_list = NULL; struct opt * -opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, +opt_new(char *name, struct dev *dev, + struct aparams *wpar, struct aparams *rpar, int maxweight, int mmc, int join, unsigned mode) { struct opt *o, **po; @@ -41,10 +42,8 @@ opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, exit(1); } c = name[len]; - if (c < 'a' && c > 'z' && - c < 'A' && c > 'Z' && - c < '0' && c > '9' && - c != '_') { + if ((c < 'a' || c > 'z') && + (c < 'A' || c > 'Z')) { fprintf(stderr, "%s: '%c' not allowed\n", name, c); exit(1); } @@ -54,7 +53,6 @@ opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, perror("opt_new: malloc"); exit(1); } - memcpy(o->name, name, len + 1); if (mode & MODE_RECMASK) o->wpar = (mode & MODE_MON) ? *rpar : *wpar; if (mode & MODE_PLAY) @@ -64,8 +62,10 @@ opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, o->join = join; o->mode = mode; o->dev = dev; + memcpy(o->name, name, len + 1); for (po = &opt_list; *po != NULL; po = &(*po)->next) { - if (strcmp(o->name, (*po)->name) == 0) { + if (o->dev->num == (*po)->dev->num && + strcmp(o->name, (*po)->name) == 0) { fprintf(stderr, "%s: already defined\n", o->name); exit(1); } @@ -74,9 +74,9 @@ opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, *po = o; #ifdef DEBUG if (debug_level >= 2) { + dev_dbg(o->dev); + dbg_puts("."); dbg_puts(o->name); - dbg_puts("@"); - dbg_puts(o->dev->path); dbg_puts(":"); if (o->mode & MODE_REC) { dbg_puts(" rec="); @@ -115,27 +115,16 @@ opt_new(char *name, struct dev *dev, struct aparams *wpar, struct aparams *rpar, } struct opt * -opt_byname(char *name) +opt_byname(char *name, unsigned num) { struct opt *o; for (o = opt_list; o != NULL; o = o->next) { - if (strcmp(name, o->name) == 0) { -#ifdef DEBUG - if (debug_level >= 3) { - dbg_puts(o->name); - dbg_puts(": option found\n"); - } -#endif + if (o->dev->num != num) + continue; + if (strcmp(name, o->name) == 0) return o; - } - } -#ifdef DEBUG - if (debug_level >= 3) { - dbg_puts(name); - dbg_puts(": option not found\n"); } -#endif return NULL; } diff --git a/usr.bin/aucat/opt.h b/usr.bin/aucat/opt.h index c904fbbb9fa..adbbba392ec 100644 --- a/usr.bin/aucat/opt.h +++ b/usr.bin/aucat/opt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: opt.h,v 1.10 2011/10/12 07:20:04 ratchov Exp $ */ +/* $OpenBSD: opt.h,v 1.11 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -40,6 +40,6 @@ extern struct opt *opt_list; struct opt *opt_new(char *, struct dev *, struct aparams *, struct aparams *, int, int, int, unsigned); int opt_bind(struct opt *); -struct opt *opt_byname(char *); +struct opt *opt_byname(char *, unsigned); #endif /* !defined(OPT_H) */ diff --git a/usr.bin/aucat/sock.c b/usr.bin/aucat/sock.c index cab30a989e3..9bef95065a2 100644 --- a/usr.bin/aucat/sock.c +++ b/usr.bin/aucat/sock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sock.c,v 1.60 2011/06/03 16:22:34 ratchov Exp $ */ +/* $OpenBSD: sock.c,v 1.61 2011/11/15 08:05:22 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -1033,9 +1033,19 @@ sock_hello(struct sock *f) #endif return 0; } - f->opt = opt_byname(p->opt); + f->opt = opt_byname(p->opt, AMSG_ISSET(p->devnum) ? p->devnum : 0); if (f->opt == NULL) return 0; +#ifdef DEBUG + if (debug_level >= 3) { + sock_dbg(f); + dbg_puts(": using "); + dev_dbg(f->opt->dev); + dbg_puts("."); + dbg_puts(f->opt->name); + dbg_puts("\n"); + } +#endif if (!dev_ref(f->opt->dev)) return 0; if ((mode & MODE_REC) && (f->opt->mode & MODE_MON)) { -- cgit v1.2.3