mirror of
https://github.com/openbsd/src.git
synced 2026-06-18 07:13:36 +02:00
sndiod: Add the server.mode control making the setting dynamic
The default mode remains "-m play,rec" but now it can be changed with sndioctl(1). If the server is switched to play-only mode, then existing clients will start recording silence. Similarly if it's switched to rec-only mode, clients are muted. ok armani, deraadt, rsadowski
This commit is contained in:
+24
-29
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dev.c,v 1.132 2026/03/15 14:24:43 ratchov Exp $ */
|
||||
/* $OpenBSD: dev.c,v 1.133 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -42,7 +42,6 @@ void dev_sub_bcopy(struct dev *, struct slot *);
|
||||
void dev_onmove(struct dev *, int);
|
||||
void dev_master(struct dev *, unsigned int);
|
||||
void dev_cycle(struct dev *);
|
||||
void dev_adjpar(struct dev *, int, int, int);
|
||||
int dev_allocbufs(struct dev *);
|
||||
void dev_freebufs(struct dev *);
|
||||
int dev_ref(struct dev *);
|
||||
@@ -747,8 +746,7 @@ dev_master(struct dev *d, unsigned int master)
|
||||
* Create a sndio device
|
||||
*/
|
||||
struct dev *
|
||||
dev_new(char *path, struct aparams *par,
|
||||
unsigned int mode, unsigned int bufsz, unsigned int round,
|
||||
dev_new(char *path, struct aparams *par, unsigned int bufsz, unsigned int round,
|
||||
unsigned int rate, unsigned int hold, unsigned int autovol)
|
||||
{
|
||||
struct dev *d, **pd;
|
||||
@@ -762,7 +760,6 @@ dev_new(char *path, struct aparams *par,
|
||||
d->num = dev_sndnum++;
|
||||
|
||||
d->reqpar = *par;
|
||||
d->reqmode = mode;
|
||||
d->reqpchan = d->reqrchan = 0;
|
||||
d->reqbufsz = bufsz;
|
||||
d->reqround = round;
|
||||
@@ -786,18 +783,12 @@ dev_new(char *path, struct aparams *par,
|
||||
* adjust device parameters and mode
|
||||
*/
|
||||
void
|
||||
dev_adjpar(struct dev *d, int mode,
|
||||
int pmax, int rmax)
|
||||
dev_adjpar(struct dev *d, int pmax, int rmax)
|
||||
{
|
||||
d->reqmode |= mode & MODE_AUDIOMASK;
|
||||
if (mode & MODE_PLAY) {
|
||||
if (d->reqpchan < pmax + 1)
|
||||
d->reqpchan = pmax + 1;
|
||||
}
|
||||
if (mode & MODE_REC) {
|
||||
if (d->reqrchan < rmax + 1)
|
||||
d->reqrchan = rmax + 1;
|
||||
}
|
||||
if (d->reqpchan < pmax + 1)
|
||||
d->reqpchan = pmax + 1;
|
||||
if (d->reqrchan < rmax + 1)
|
||||
d->reqrchan = rmax + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -867,7 +858,7 @@ dev_allocbufs(struct dev *d)
|
||||
int
|
||||
dev_open(struct dev *d)
|
||||
{
|
||||
d->mode = d->reqmode;
|
||||
d->mode = MODE_AUDIOMASK;
|
||||
d->round = d->reqround;
|
||||
d->bufsz = d->reqbufsz;
|
||||
d->rate = d->reqrate;
|
||||
@@ -996,12 +987,6 @@ dev_unref(struct dev *d)
|
||||
int
|
||||
dev_init(struct dev *d)
|
||||
{
|
||||
if ((d->reqmode & MODE_AUDIOMASK) == 0) {
|
||||
#ifdef DEBUG
|
||||
logx(1, "%s: has no streams", d->path);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if (d->hold && !dev_ref(d))
|
||||
return 0;
|
||||
return 1;
|
||||
@@ -1473,12 +1458,6 @@ slot_attach(struct slot *s)
|
||||
struct dev *d = s->opt->dev;
|
||||
long long pos;
|
||||
|
||||
if (((s->mode & MODE_PLAY) && !(s->opt->mode & MODE_PLAY)) ||
|
||||
((s->mode & MODE_RECMASK) && !(s->opt->mode & MODE_RECMASK))) {
|
||||
logx(1, "slot%zu at %s: mode not allowed", s - slot_array, s->opt->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* setup conversions layer
|
||||
*/
|
||||
@@ -1814,6 +1793,7 @@ ctlslot_visible(struct ctlslot *s, struct ctl *c)
|
||||
case CTL_DEV_MASTER:
|
||||
return (s->opt->dev == c->u.any.arg0);
|
||||
case CTL_OPT_DEV:
|
||||
case CTL_OPT_MODE:
|
||||
return (s->opt == c->u.any.arg0);
|
||||
case CTL_APP_LEVEL:
|
||||
return (s->opt == c->u.app_level.opt);
|
||||
@@ -1894,6 +1874,9 @@ ctl_scope_fmt(char *buf, size_t size, struct ctl *c)
|
||||
case CTL_OPT_DEV:
|
||||
return snprintf(buf, size, "opt_dev:%s/%s",
|
||||
c->u.opt_dev.opt->name, c->u.opt_dev.dev->name);
|
||||
case CTL_OPT_MODE:
|
||||
return snprintf(buf, size, "opt_mode:%s/%s",
|
||||
c->u.opt_mode.opt->name, opt_modes[c->u.opt_mode.idx].name);
|
||||
default:
|
||||
return snprintf(buf, size, "unknown");
|
||||
}
|
||||
@@ -1962,6 +1945,11 @@ ctl_setval(struct ctl *c, int val)
|
||||
opt_setalt(c->u.opt_dev.opt, c->u.opt_dev.dev);
|
||||
}
|
||||
return 1;
|
||||
case CTL_OPT_MODE:
|
||||
opt_setmode(c->u.opt_mode.opt, c->u.opt_mode.idx, val);
|
||||
c->val_mask = ~0U;
|
||||
c->curval = val;
|
||||
return 1;
|
||||
default:
|
||||
logx(2, "ctl%u: not writable", c->addr);
|
||||
return 1;
|
||||
@@ -2018,6 +2006,9 @@ ctl_new(int scope, void *arg0, void *arg1,
|
||||
case CTL_APP_LEVEL:
|
||||
c->u.any.arg1 = arg1;
|
||||
break;
|
||||
case CTL_OPT_MODE:
|
||||
c->u.opt_mode.idx = *(int *)arg1;
|
||||
break;
|
||||
default:
|
||||
c->u.any.arg1 = NULL;
|
||||
}
|
||||
@@ -2085,6 +2076,10 @@ ctl_match(struct ctl *c, int scope, void *arg0, void *arg1)
|
||||
if (arg1 != NULL && c->u.any.arg1 != arg1)
|
||||
return 0;
|
||||
break;
|
||||
case CTL_OPT_MODE:
|
||||
if (arg1 != NULL && c->u.opt_mode.idx != *(int *)arg1)
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: dev.h,v 1.53 2026/03/15 14:24:43 ratchov Exp $ */
|
||||
/* $OpenBSD: dev.h,v 1.54 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -124,6 +124,7 @@ struct ctl {
|
||||
#define CTL_DEV_MASTER 1
|
||||
#define CTL_OPT_DEV 2
|
||||
#define CTL_APP_LEVEL 3
|
||||
#define CTL_OPT_MODE 4
|
||||
unsigned int scope;
|
||||
union {
|
||||
struct {
|
||||
@@ -145,6 +146,10 @@ struct ctl {
|
||||
struct opt *opt;
|
||||
struct dev *dev;
|
||||
} opt_dev;
|
||||
struct {
|
||||
struct opt *opt;
|
||||
int idx;
|
||||
} opt_mode;
|
||||
} u;
|
||||
|
||||
unsigned int addr; /* slot side control address */
|
||||
@@ -240,7 +245,6 @@ struct dev {
|
||||
/*
|
||||
* desired parameters
|
||||
*/
|
||||
unsigned int reqmode; /* mode */
|
||||
struct aparams reqpar; /* parameters */
|
||||
int reqpchan, reqrchan; /* play & rec chans */
|
||||
unsigned int reqbufsz; /* buffer size */
|
||||
@@ -280,11 +284,11 @@ int dev_open(struct dev *);
|
||||
void dev_close(struct dev *);
|
||||
void dev_abort(struct dev *);
|
||||
void dev_migrate(struct dev *);
|
||||
struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
|
||||
struct dev *dev_new(char *, struct aparams *, unsigned int,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int);
|
||||
struct dev *dev_bynum(int);
|
||||
void dev_del(struct dev *);
|
||||
void dev_adjpar(struct dev *, int, int, int);
|
||||
void dev_adjpar(struct dev *, int, int);
|
||||
int dev_init(struct dev *);
|
||||
void dev_done(struct dev *);
|
||||
int dev_ref(struct dev *);
|
||||
|
||||
+44
-9
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: opt.c,v 1.16 2025/11/26 08:40:16 ratchov Exp $ */
|
||||
/* $OpenBSD: opt.c,v 1.17 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2011 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -37,6 +37,12 @@ struct midiops opt_midiops = {
|
||||
opt_midi_exit
|
||||
};
|
||||
|
||||
const struct opt_mode opt_modes[] = {
|
||||
{MODE_PLAY, "play"},
|
||||
{MODE_REC, "rec"},
|
||||
{MODE_MON, "mon"},
|
||||
};
|
||||
|
||||
struct app *
|
||||
opt_mkapp(struct opt *o, char *who)
|
||||
{
|
||||
@@ -378,14 +384,10 @@ opt_new(struct dev *d, char *name,
|
||||
o->midi = midi_new(&opt_midiops, o, MODE_MIDIIN | MODE_MIDIOUT);
|
||||
midi_tag(o->midi, o->num);
|
||||
|
||||
if (mode & MODE_PLAY) {
|
||||
o->pmin = pmin;
|
||||
o->pmax = pmax;
|
||||
}
|
||||
if (mode & MODE_RECMASK) {
|
||||
o->rmin = rmin;
|
||||
o->rmax = rmax;
|
||||
}
|
||||
o->pmin = pmin;
|
||||
o->pmax = pmax;
|
||||
o->rmin = rmin;
|
||||
o->rmax = rmax;
|
||||
o->maxweight = maxweight;
|
||||
o->mtc = mmc ? &mtc_array[0] : NULL;
|
||||
o->dup = dup;
|
||||
@@ -486,21 +488,54 @@ opt_del(struct opt *o)
|
||||
void
|
||||
opt_init(struct opt *o)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sizeof(opt_modes) / sizeof(opt_modes[0]); i++) {
|
||||
ctl_new(CTL_OPT_MODE, o, &i, CTL_VEC, "",
|
||||
o->name, "server", -1, "mode", opt_modes[i].name, -1,
|
||||
1, (o->mode & opt_modes[i].bit) ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
opt_done(struct opt *o)
|
||||
{
|
||||
struct dev *d;
|
||||
int i;
|
||||
|
||||
if (o->refcnt != 0) {
|
||||
// XXX: all clients are already kicked, so this never happens
|
||||
logx(0, "%s: still has refs", o->name);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(opt_modes) / sizeof(opt_modes[0]); i++)
|
||||
ctl_del(CTL_OPT_MODE, o, &i);
|
||||
|
||||
for (d = dev_list; d != NULL; d = d->next)
|
||||
ctl_del(CTL_OPT_DEV, o, d);
|
||||
}
|
||||
|
||||
/*
|
||||
* Flip a bit of opt's mode
|
||||
*/
|
||||
void
|
||||
opt_setmode(struct opt *o, int idx, int val)
|
||||
{
|
||||
int mode;
|
||||
|
||||
/*
|
||||
* The o->mode field is directly used by the device,
|
||||
* so just flipping the bit is OK.
|
||||
*/
|
||||
mode = opt_modes[idx].bit;
|
||||
if (val)
|
||||
o->mode |= mode;
|
||||
else
|
||||
o->mode &= ~mode;
|
||||
|
||||
logx(2, "%s: %s -> %d", __func__, opt_modes[idx].name, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set opt's device, and (if necessary) move clients to
|
||||
* to the new device
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: opt.h,v 1.11 2025/11/26 08:40:16 ratchov Exp $ */
|
||||
/* $OpenBSD: opt.h,v 1.12 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -55,8 +55,15 @@ struct opt {
|
||||
int refcnt;
|
||||
};
|
||||
|
||||
struct opt_mode {
|
||||
int bit;
|
||||
char *name;
|
||||
};
|
||||
|
||||
extern struct opt *opt_list;
|
||||
|
||||
extern const struct opt_mode opt_modes[];
|
||||
|
||||
struct app *opt_mkapp(struct opt *o, char *who);
|
||||
void opt_appvol(struct opt *o, struct app *a, int vol);
|
||||
void opt_midi_vol(struct opt *, struct app *);
|
||||
@@ -70,6 +77,7 @@ struct opt *opt_byname(char *);
|
||||
struct opt *opt_bynum(int);
|
||||
void opt_init(struct opt *);
|
||||
void opt_done(struct opt *);
|
||||
void opt_setmode(struct opt *, int, int);
|
||||
int opt_setdev(struct opt *, struct dev *);
|
||||
void opt_migrate(struct opt *, struct dev *);
|
||||
struct dev *opt_ref(struct opt *);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: siofile.c,v 1.30 2026/01/22 09:24:26 ratchov Exp $ */
|
||||
/* $OpenBSD: siofile.c,v 1.31 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -104,7 +104,7 @@ int
|
||||
dev_sio_open(struct dev *d)
|
||||
{
|
||||
struct sio_par par;
|
||||
unsigned int rate, mode = d->reqmode & (SIO_PLAY | SIO_REC);
|
||||
unsigned int rate, mode = SIO_PLAY | SIO_REC;
|
||||
|
||||
d->sio.hdl = fdpass_sio_open(d->num, mode);
|
||||
if (d->sio.hdl == NULL) {
|
||||
|
||||
+10
-11
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sndiod.c,v 1.53 2026/03/15 10:05:09 ratchov Exp $ */
|
||||
/* $OpenBSD: sndiod.c,v 1.54 2026/05/20 13:02:04 ratchov Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
@@ -103,8 +103,7 @@ unsigned int opt_mode(void);
|
||||
void getbasepath(char *);
|
||||
void setsig(void);
|
||||
void unsetsig(void);
|
||||
struct dev *mkdev(char *, struct aparams *,
|
||||
int, int, int, int, int, int);
|
||||
struct dev *mkdev(char *, struct aparams *, int, int, int, int, int);
|
||||
struct port *mkport(char *, int);
|
||||
struct opt *mkopt(char *, struct dev *, struct opt_alt *,
|
||||
int, int, int, int, int, int, int, int);
|
||||
@@ -366,7 +365,7 @@ unsetsig(void)
|
||||
|
||||
struct dev *
|
||||
mkdev(char *path, struct aparams *par,
|
||||
int mode, int bufsz, int round, int rate, int hold, int autovol)
|
||||
int bufsz, int round, int rate, int hold, int autovol)
|
||||
{
|
||||
struct dev *d;
|
||||
|
||||
@@ -381,7 +380,7 @@ mkdev(char *path, struct aparams *par,
|
||||
bufsz = round * 2;
|
||||
} else if (!round)
|
||||
round = bufsz / 2;
|
||||
d = dev_new(path, par, mode, bufsz, round, rate, hold, autovol);
|
||||
d = dev_new(path, par, bufsz, round, rate, hold, autovol);
|
||||
if (d == NULL)
|
||||
exit(1);
|
||||
return d;
|
||||
@@ -414,7 +413,7 @@ mkopt(char *path, struct dev *d, struct opt_alt *alt_list,
|
||||
MIDI_TO_ADATA(vol), mmc, dup, mode);
|
||||
if (o == NULL)
|
||||
return NULL;
|
||||
dev_adjpar(d, o->mode, o->pmax, o->rmax);
|
||||
dev_adjpar(d, o->pmax, o->rmax);
|
||||
for (a = alt_list; a != NULL; a = a->next)
|
||||
opt_setalt(o, a->dev);
|
||||
return o;
|
||||
@@ -602,7 +601,7 @@ main(int argc, char **argv)
|
||||
case 's':
|
||||
if (d == NULL) {
|
||||
for (i = 0; default_devs[i] != NULL; i++) {
|
||||
mkdev(default_devs[i], &par, 0,
|
||||
mkdev(default_devs[i], &par,
|
||||
bufsz, round, rate, 0, autovol);
|
||||
}
|
||||
d = dev_list;
|
||||
@@ -642,7 +641,7 @@ main(int argc, char **argv)
|
||||
errx(1, "%s: block size is %s", optarg, str);
|
||||
break;
|
||||
case 'f':
|
||||
d = mkdev(optarg, &par, 0, bufsz, round,
|
||||
d = mkdev(optarg, &par, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
while ((a = alt_list) != NULL) {
|
||||
alt_list = a->next;
|
||||
@@ -653,7 +652,7 @@ main(int argc, char **argv)
|
||||
if (d == NULL)
|
||||
errx(1, "-F %s: no devices defined", optarg);
|
||||
a = xmalloc(sizeof(struct opt_alt));
|
||||
a->dev = mkdev(optarg, &par, 0, bufsz, round,
|
||||
a->dev = mkdev(optarg, &par, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
for (pa = &alt_list; *pa != NULL; pa = &(*pa)->next)
|
||||
;
|
||||
@@ -677,7 +676,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
if (dev_list == NULL) {
|
||||
for (i = 0; default_devs[i] != NULL; i++) {
|
||||
mkdev(default_devs[i], &par, 0,
|
||||
mkdev(default_devs[i], &par,
|
||||
bufsz, round, rate, 0, autovol);
|
||||
}
|
||||
}
|
||||
@@ -701,7 +700,7 @@ main(int argc, char **argv)
|
||||
if (opt_new(d, NULL, o->pmin, o->pmax, o->rmin, o->rmax,
|
||||
o->maxweight, o->mtc != NULL, o->dup, o->mode) == NULL)
|
||||
return 1;
|
||||
dev_adjpar(d, o->mode, o->pmax, o->rmax);
|
||||
dev_adjpar(d, o->pmax, o->rmax);
|
||||
}
|
||||
|
||||
while ((a = alt_list) != NULL) {
|
||||
|
||||
Reference in New Issue
Block a user