Skip to content

Commit 25ed657

Browse files
committed
sndiod: Use per-program level controls instead of per-client
All instaces of the same program use a common level control. As a side effect, this removes the restriction on the maximum simultaneous clients sndiod can handle, which was increased to 32. Tweaks from op@ and sthen@
1 parent 389dd54 commit 25ed657

File tree

7 files changed

+191
-237
lines changed

7 files changed

+191
-237
lines changed

usr.bin/sndiod/dev.c

Lines changed: 55 additions & 187 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $OpenBSD: dev.c,v 1.122 2025/06/16 06:19:29 ratchov Exp $ */
1+
/* $OpenBSD: dev.c,v 1.123 2025/06/19 20:16:34 ratchov Exp $ */
22
/*
33
* Copyright (c) 2008-2012 Alexandre Ratchov <[email protected]>
44
*
@@ -78,7 +78,6 @@ unsigned int dev_sndnum = 0;
7878

7979
struct ctlslot ctlslot_array[DEV_NCTLSLOT];
8080
struct slot slot_array[DEV_NSLOT];
81-
unsigned int slot_serial; /* for slot allocation */
8281

8382
/*
8483
* we support/need a single MTC clock source only
@@ -87,27 +86,6 @@ struct mtc mtc_array[1] = {
8786
{.dev = NULL, .tstate = MTC_STOP}
8887
};
8988

90-
void
91-
slot_array_init(void)
92-
{
93-
unsigned int i;
94-
95-
for (i = 0; i < DEV_NSLOT; i++) {
96-
slot_array[i].unit = i;
97-
slot_array[i].ops = NULL;
98-
slot_array[i].vol = MIDI_MAXCTL;
99-
slot_array[i].opt = NULL;
100-
slot_array[i].serial = slot_serial++;
101-
memset(slot_array[i].name, 0, SLOT_NAMEMAX);
102-
}
103-
}
104-
105-
void
106-
slot_ctlname(struct slot *s, char *name, size_t size)
107-
{
108-
snprintf(name, size, "slot%zu", s - slot_array);
109-
}
110-
11189
void
11290
zomb_onmove(void *arg)
11391
{
@@ -298,16 +276,18 @@ mtc_midi_full(struct mtc *mtc)
298276

299277
/*
300278
* send a volume change MIDI message
279+
*
280+
* XXX: rename to opt_midi_vol() and move to opt.c
301281
*/
302282
void
303-
dev_midi_vol(struct dev *d, struct slot *s)
283+
dev_midi_vol(struct opt *o, struct app *a)
304284
{
305285
unsigned char msg[3];
306286

307-
msg[0] = MIDI_CTL | (s - slot_array);
287+
msg[0] = MIDI_CTL | (a - o->app_array);
308288
msg[1] = MIDI_CTL_VOL;
309-
msg[2] = s->vol;
310-
dev_midi_send(d, msg, 3);
289+
msg[2] = a->vol;
290+
midi_send(o->midi, msg, sizeof(msg));
311291
}
312292

313293
/*
@@ -352,9 +332,11 @@ dev_midi_master(struct dev *d)
352332

353333
/*
354334
* send a sndiod-specific slot description MIDI message
335+
*
336+
* XXX: rename to opt_midi_appdesc() and move to opt.c
355337
*/
356338
void
357-
dev_midi_slotdesc(struct dev *d, struct slot *s)
339+
dev_midi_slotdesc(struct opt *o, struct app *a)
358340
{
359341
struct sysex x;
360342

@@ -364,34 +346,34 @@ dev_midi_slotdesc(struct dev *d, struct slot *s)
364346
x.dev = SYSEX_DEV_ANY;
365347
x.id0 = SYSEX_AUCAT;
366348
x.id1 = SYSEX_AUCAT_SLOTDESC;
367-
if (s->opt != NULL && s->opt->dev == d)
368-
slot_ctlname(s, (char *)x.u.slotdesc.name, SYSEX_NAMELEN);
369-
x.u.slotdesc.chan = (s - slot_array);
349+
strlcpy(x.u.slotdesc.name, a->name, SYSEX_NAMELEN);
350+
x.u.slotdesc.chan = (a - o->app_array);
370351
x.u.slotdesc.end = SYSEX_END;
371-
dev_midi_send(d, (unsigned char *)&x, SYSEX_SIZE(slotdesc));
352+
midi_send(o->midi, (unsigned char *)&x, SYSEX_SIZE(slotdesc));
372353
}
373354

355+
/*
356+
* XXX: rename to opt_midi_dump() and move to opt.c
357+
*/
374358
void
375-
dev_midi_dump(struct dev *d)
359+
dev_midi_dump(struct opt *o)
376360
{
377361
struct sysex x;
378-
struct slot *s;
362+
struct app *a;
379363
int i;
380364

381-
dev_midi_master(d);
382-
for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
383-
if (s->opt != NULL && s->opt->dev != d)
384-
continue;
385-
dev_midi_slotdesc(d, s);
386-
dev_midi_vol(d, s);
365+
dev_midi_master(o->dev);
366+
for (i = 0, a = o->app_array; i < OPT_NAPP; i++, a++) {
367+
dev_midi_slotdesc(o, a);
368+
dev_midi_vol(o, a);
387369
}
388370
x.start = SYSEX_START;
389371
x.type = SYSEX_TYPE_EDU;
390372
x.dev = SYSEX_DEV_ANY;
391373
x.id0 = SYSEX_AUCAT;
392374
x.id1 = SYSEX_AUCAT_DUMPEND;
393375
x.u.dumpend.end = SYSEX_END;
394-
dev_midi_send(d, (unsigned char *)&x, SYSEX_SIZE(dumpend));
376+
midi_send(o->midi, (unsigned char *)&x, SYSEX_SIZE(dumpend));
395377
}
396378

397379
int
@@ -1523,98 +1505,30 @@ struct slot *
15231505
slot_new(struct opt *opt, unsigned int id, char *who,
15241506
struct slotops *ops, void *arg, int mode)
15251507
{
1526-
char *p;
1527-
char name[SLOT_NAMEMAX];
1528-
char ctl_name[CTL_NAMEMAX];
1529-
unsigned int i, ser, bestser, bestidx;
1530-
struct slot *unit[DEV_NSLOT];
1508+
struct app *a;
15311509
struct slot *s;
1510+
int i;
15321511

1533-
/*
1534-
* create a ``valid'' control name (lowcase, remove [^a-z], truncate)
1535-
*/
1536-
for (i = 0, p = who; ; p++) {
1537-
if (i == SLOT_NAMEMAX - 1 || *p == '\0') {
1538-
name[i] = '\0';
1539-
break;
1540-
} else if (*p >= 'A' && *p <= 'Z') {
1541-
name[i++] = *p + 'a' - 'A';
1542-
} else if (*p >= 'a' && *p <= 'z')
1543-
name[i++] = *p;
1544-
}
1545-
if (i == 0)
1546-
strlcpy(name, "noname", SLOT_NAMEMAX);
1547-
1548-
/*
1549-
* build a unit-to-slot map for this name
1550-
*/
1551-
for (i = 0; i < DEV_NSLOT; i++)
1552-
unit[i] = NULL;
1553-
for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
1554-
if (strcmp(s->name, name) == 0)
1555-
unit[s->unit] = s;
1556-
}
1557-
1558-
/*
1559-
* find the free slot with the least unit number and same id
1560-
*/
1561-
for (i = 0; i < DEV_NSLOT; i++) {
1562-
s = unit[i];
1563-
if (s != NULL && s->ops == NULL && s->id == id)
1564-
goto found;
1565-
}
1566-
1567-
/*
1568-
* find the free slot with the least unit number
1569-
*/
1570-
for (i = 0; i < DEV_NSLOT; i++) {
1571-
s = unit[i];
1572-
if (s != NULL && s->ops == NULL) {
1573-
s->id = id;
1574-
goto found;
1575-
}
1576-
}
1512+
a = opt_mkapp(opt, who);
1513+
if (a == NULL)
1514+
return NULL;
15771515

15781516
/*
1579-
* couldn't find a matching slot, pick oldest free slot
1580-
* and set its name/unit
1517+
* find a free slot and assign it the smallest possible unit number
15811518
*/
1582-
bestser = 0;
1583-
bestidx = DEV_NSLOT;
15841519
for (i = 0, s = slot_array; i < DEV_NSLOT; i++, s++) {
1585-
if (s->ops != NULL)
1586-
continue;
1587-
ser = slot_serial - s->serial;
1588-
if (ser > bestser) {
1589-
bestser = ser;
1590-
bestidx = i;
1591-
}
1520+
if (s->ops == NULL)
1521+
break;
15921522
}
1593-
1594-
if (bestidx == DEV_NSLOT) {
1595-
logx(1, "%s: out of sub-device slots", name);
1523+
if (i == DEV_NSLOT) {
1524+
logx(1, "%s: too many connections", a->name);
15961525
return NULL;
15971526
}
15981527

1599-
s = slot_array + bestidx;
1600-
ctl_del(CTL_SLOT_LEVEL, s, NULL);
1601-
s->vol = MIDI_MAXCTL;
1602-
strlcpy(s->name, name, SLOT_NAMEMAX);
1603-
s->serial = slot_serial++;
1604-
for (i = 0; unit[i] != NULL; i++)
1605-
; /* nothing */
1606-
s->unit = i;
1607-
s->id = id;
1608-
s->opt = opt;
1609-
slot_ctlname(s, ctl_name, CTL_NAMEMAX);
1610-
ctl_new(CTL_SLOT_LEVEL, s, NULL,
1611-
CTL_NUM, "", "app", ctl_name, -1, "level",
1612-
NULL, -1, 127, s->vol);
1613-
1614-
found:
1615-
/* open device, this may change opt's device */
16161528
if (!opt_ref(opt))
16171529
return NULL;
1530+
1531+
s->app = a;
16181532
s->opt = opt;
16191533
s->ops = ops;
16201534
s->arg = arg;
@@ -1629,10 +1543,8 @@ slot_new(struct opt *opt, unsigned int id, char *who,
16291543
s->appbufsz = s->opt->dev->bufsz;
16301544
s->round = s->opt->dev->round;
16311545
s->rate = s->opt->dev->rate;
1632-
dev_midi_slotdesc(s->opt->dev, s);
1633-
dev_midi_vol(s->opt->dev, s);
16341546
#ifdef DEBUG
1635-
logx(3, "slot%zu: %s/%s%u", s - slot_array, s->opt->name, s->name, s->unit);
1547+
logx(3, "slot%zu: %s/%s", s - slot_array, s->opt->name, s->app->name);
16361548
#endif
16371549
return s;
16381550
}
@@ -1660,66 +1572,21 @@ slot_del(struct slot *s)
16601572
}
16611573

16621574
/*
1663-
* change the slot play volume; called either by the slot or by MIDI
1575+
* change the slot play volume; called by the client
16641576
*/
16651577
void
16661578
slot_setvol(struct slot *s, unsigned int vol)
16671579
{
1580+
struct opt *o = s->opt;
1581+
struct app *a = s->app;
1582+
16681583
#ifdef DEBUG
16691584
logx(3, "slot%zu: setting volume %u", s - slot_array, vol);
16701585
#endif
1671-
s->vol = vol;
1672-
s->mix.vol = MIDI_TO_ADATA(s->vol);
1673-
}
1674-
1675-
/*
1676-
* set device for this slot
1677-
*/
1678-
void
1679-
slot_setopt(struct slot *s, struct opt *o)
1680-
{
1681-
struct opt *t;
1682-
struct dev *odev, *ndev;
1683-
struct ctl *c;
1684-
1685-
if (s->opt == NULL || s->opt == o)
1686-
return;
1687-
1688-
logx(2, "slot%zu: moving to opt %s", s - slot_array, o->name);
1689-
1690-
odev = s->opt->dev;
1691-
if (s->ops != NULL) {
1692-
ndev = opt_ref(o);
1693-
if (ndev == NULL)
1694-
return;
1695-
1696-
if (!dev_iscompat(odev, ndev)) {
1697-
opt_unref(o);
1698-
return;
1699-
}
1700-
}
1701-
1702-
if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
1703-
slot_detach(s);
1704-
1705-
t = s->opt;
1706-
s->opt = o;
1707-
1708-
c = ctl_find(CTL_SLOT_LEVEL, s, NULL);
1709-
ctl_update(c);
1710-
1711-
if (o->dev != t->dev) {
1712-
dev_midi_slotdesc(odev, s);
1713-
dev_midi_slotdesc(ndev, s);
1714-
dev_midi_vol(ndev, s);
1715-
}
1716-
1717-
if (s->pstate == SLOT_RUN || s->pstate == SLOT_STOP)
1718-
slot_attach(s);
1719-
1720-
if (s->ops != NULL) {
1721-
opt_unref(t);
1722-
return;
1586+
if (a->vol != vol) {
1587+
opt_appvol(o, a, vol);
1588+
dev_midi_vol(o, a);
1589+
ctl_onval(CTL_APP_LEVEL, o, a, vol);
17231590
}
17241591
}
17251592

@@ -1775,7 +1642,7 @@ slot_attach(struct slot *s)
17751642
s->next = d->slot_list;
17761643
d->slot_list = s;
17771644
if (s->mode & MODE_PLAY) {
1778-
s->mix.vol = MIDI_TO_ADATA(s->vol);
1645+
s->mix.vol = MIDI_TO_ADATA(s->app->vol);
17791646
dev_mix_adjvol(d);
17801647
}
17811648
}
@@ -2073,8 +1940,8 @@ ctlslot_visible(struct ctlslot *s, struct ctl *c)
20731940
return (s->opt->dev == c->u.any.arg0);
20741941
case CTL_OPT_DEV:
20751942
return (s->opt == c->u.any.arg0);
2076-
case CTL_SLOT_LEVEL:
2077-
return (s->opt->dev == c->u.slot_level.slot->opt->dev);
1943+
case CTL_APP_LEVEL:
1944+
return (s->opt == c->u.app_level.opt);
20781945
default:
20791946
return 0;
20801947
}
@@ -2146,9 +2013,9 @@ ctl_scope_fmt(char *buf, size_t size, struct ctl *c)
21462013
case CTL_DEV_MASTER:
21472014
return snprintf(buf, size, "dev_master:%s",
21482015
c->u.dev_master.dev->name);
2149-
case CTL_SLOT_LEVEL:
2150-
return snprintf(buf, size, "slot_level:%s%u",
2151-
c->u.slot_level.slot->name, c->u.slot_level.slot->unit);
2016+
case CTL_APP_LEVEL:
2017+
return snprintf(buf, size, "app_level:%s/%s",
2018+
c->u.app_level.opt->name, c->u.app_level.app->name);
21522019
case CTL_OPT_DEV:
21532020
return snprintf(buf, size, "opt_dev:%s/%s",
21542021
c->u.opt_dev.opt->name, c->u.opt_dev.dev->name);
@@ -2208,10 +2075,9 @@ ctl_setval(struct ctl *c, int val)
22082075
c->val_mask = ~0U;
22092076
c->curval = val;
22102077
return 1;
2211-
case CTL_SLOT_LEVEL:
2212-
slot_setvol(c->u.slot_level.slot, val);
2213-
// XXX change dev_midi_vol() into slot_midi_vol()
2214-
dev_midi_vol(c->u.slot_level.slot->opt->dev, c->u.slot_level.slot);
2078+
case CTL_APP_LEVEL:
2079+
opt_appvol(c->u.app_level.opt, c->u.app_level.app, val);
2080+
dev_midi_vol(c->u.app_level.opt, c->u.app_level.app);
22152081
c->val_mask = ~0U;
22162082
c->curval = val;
22172083
return 1;
@@ -2272,6 +2138,7 @@ ctl_new(int scope, void *arg0, void *arg1,
22722138
c->u.hw.addr = *(unsigned int *)arg1;
22732139
break;
22742140
case CTL_OPT_DEV:
2141+
case CTL_APP_LEVEL:
22752142
c->u.any.arg1 = arg1;
22762143
break;
22772144
default:
@@ -2337,6 +2204,7 @@ ctl_match(struct ctl *c, int scope, void *arg0, void *arg1)
23372204
return 0;
23382205
break;
23392206
case CTL_OPT_DEV:
2207+
case CTL_APP_LEVEL:
23402208
if (arg1 != NULL && c->u.any.arg1 != arg1)
23412209
return 0;
23422210
break;

0 commit comments

Comments
 (0)