Merge branch 'master' into mixer

This commit is contained in:
Alexandre Ratchov 2019-09-21 08:31:44 +02:00
commit 5536f474fe
12 changed files with 298 additions and 168 deletions

View File

@ -58,10 +58,10 @@ int dev_getpos(struct dev *);
struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int);
void dev_adjpar(struct dev *, int, int, int);
int dev_open_do(struct dev *);
int dev_allocbufs(struct dev *);
int dev_open(struct dev *);
void dev_exitall(struct dev *);
void dev_close_do(struct dev *);
void dev_freebufs(struct dev *);
void dev_close(struct dev *);
int dev_ref(struct dev *);
void dev_unref(struct dev *);
@ -83,6 +83,7 @@ void slot_attach(struct slot *);
void slot_ready(struct slot *);
void slot_allocbufs(struct slot *);
void slot_freebufs(struct slot *);
void slot_initconv(struct slot *);
void slot_start(struct slot *);
void slot_detach(struct slot *);
void slot_stop(struct slot *);
@ -1047,15 +1048,8 @@ dev_adjpar(struct dev *d, int mode,
* monitor, midi control, and any necessary conversions.
*/
int
dev_open_do(struct dev *d)
dev_allocbufs(struct dev *d)
{
if (!dev_sio_open(d)) {
if (log_level >= 1) {
dev_log(d);
log_puts(": failed to open audio device\n");
}
return 0;
}
if (d->mode & MODE_REC) {
/*
* Create device <-> demuxer buffer
@ -1089,7 +1083,6 @@ dev_open_do(struct dev *d)
} else
d->encbuf = NULL;
}
d->pstate = DEV_INIT;
if (log_level >= 2) {
dev_log(d);
log_puts(": ");
@ -1133,9 +1126,15 @@ dev_open(struct dev *d)
d->pchan = 2;
if (d->rchan == 0)
d->rchan = 2;
if (!dev_open_do(d))
if (!dev_sio_open(d)) {
if (log_level >= 1) {
dev_log(d);
log_puts(": failed to open audio device\n");
}
return 0;
}
if (!dev_allocbufs(d))
return 0;
/*
* we use the "sndiod" group name. find a unused
@ -1163,6 +1162,8 @@ dev_open(struct dev *d)
}
dev_addctl(d, "sndiod", gunit, CTL_NUM,
CTLADDR_MASTER, "master", -1, "level", NULL, -1, d->master);
d->pstate = DEV_INIT;
return 1;
}
@ -1195,31 +1196,14 @@ dev_exitall(struct dev *d)
* ensure buffers are drained
*/
void
dev_close_do(struct dev *d)
dev_freebufs(struct dev *d)
{
struct ctl *c, **pc;
#ifdef DEBUG
if (log_level >= 3) {
dev_log(d);
log_puts(": closing\n");
}
#endif
pc = &d->ctl_list;
while ((c = *pc) != NULL) {
if (c->addr >= CTLADDR_END) {
if (c->refs_mask == 0) {
*pc = c->next;
xfree(c);
continue;
}
c->type = CTL_NONE;
c->desc_mask = ~0;
}
pc = &c->next;
}
d->pstate = DEV_CFG;
dev_sio_close(d);
if (d->mode & MODE_PLAY) {
if (d->encbuf != NULL)
xfree(d->encbuf);
@ -1241,7 +1225,9 @@ dev_close(struct dev *d)
struct ctl *c;
dev_exitall(d);
dev_close_do(d);
d->pstate = DEV_CFG;
dev_sio_close(d);
dev_freebufs(d);
/* there are no clients, just free remaining local controls */
while ((c = d->ctl_list) != NULL) {
@ -1254,67 +1240,43 @@ dev_close(struct dev *d)
* Close the device, but attempt to migrate everything to a new sndio
* device.
*/
void
int
dev_reopen(struct dev *d)
{
struct slot *s;
struct ctl *c, **pc;
long long pos;
unsigned int mode, round, bufsz, rate, pstate;
unsigned int pstate;
int delta;
/* not opened */
if (d->pstate == DEV_CFG)
return;
if (log_level >= 1) {
dev_log(d);
log_puts(": reopening device\n");
}
return 1;
/* save state */
mode = d->mode;
round = d->round;
bufsz = d->bufsz;
rate = d->rate;
delta = d->delta;
pstate = d->pstate;
/* close device */
dev_close_do(d);
if (!dev_sio_reopen(d))
return 0;
/* open device */
if (!dev_open_do(d)) {
if (log_level >= 1) {
dev_log(d);
log_puts(": found no working alternate device\n");
}
dev_exitall(d);
return;
}
/* reopen returns a stopped device */
d->pstate = DEV_INIT;
/* check if new parameters are compatible with old ones */
if (d->mode != mode ||
d->round != round ||
d->bufsz != bufsz ||
d->rate != rate) {
if (log_level >= 1) {
dev_log(d);
log_puts(": alternate device not compatible\n");
}
dev_close(d);
return;
}
/* reallocate new buffers, with new parameters */
dev_freebufs(d);
dev_allocbufs(d);
/*
* adjust time positions, make anything go back delta ticks, so
* that the new device can start at zero
*/
for (s = d->slot_list; s != NULL; s = s->next) {
pos = (long long)(d->round - delta) * s->round + s->delta_rem;
s->delta_rem = pos % d->round;
s->delta += pos / (int)d->round;
s->delta -= s->round;
if (log_level >= 2) {
pos = (long long)s->delta * d->round + s->delta_rem;
pos -= (long long)delta * s->round;
s->delta_rem = pos % (int)d->round;
s->delta = pos / (int)d->round;
if (log_level >= 3) {
slot_log(s);
log_puts(": adjusted: delta -> ");
log_puti(s->delta);
@ -1322,6 +1284,9 @@ dev_reopen(struct dev *d)
log_puti(s->delta_rem);
log_puts("\n");
}
/* reinitilize the format conversion chain */
slot_initconv(s);
}
if (d->tstate == MMC_RUN) {
d->mtc.delta -= delta * MTC_SEC;
@ -1333,9 +1298,29 @@ dev_reopen(struct dev *d)
}
}
/* remove controls of old device */
pc = &d->ctl_list;
while ((c = *pc) != NULL) {
if (c->addr >= CTLADDR_END) {
if (c->refs_mask == 0) {
*pc = c->next;
xfree(c);
continue;
}
c->type = CTL_NONE;
c->desc_mask = ~0;
}
pc = &c->next;
}
/* add new device controls */
dev_siomix_open(d);
/* start the device if needed */
if (pstate == DEV_RUN)
dev_wakeup(d);
return 1;
}
int
@ -1591,31 +1576,15 @@ dev_mmcloc(struct dev *d, unsigned int origin)
dev_mmcstart(d);
}
/*
* allocate buffers & conversion chain
*/
void
slot_allocbufs(struct slot *s)
slot_initconv(struct slot *s)
{
unsigned int dev_nch;
struct dev *d = s->dev;
if (s->mode & MODE_PLAY) {
s->mix.bpf = s->par.bps * s->mix.nch;
abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf);
dev_nch = s->opt->pmax - s->opt->pmin + 1;
s->mix.decbuf = NULL;
s->mix.resampbuf = NULL;
s->mix.join = 1;
s->mix.expand = 1;
if (s->opt->dup) {
if (dev_nch > s->mix.nch)
s->mix.expand = dev_nch / s->mix.nch;
else if (dev_nch < s->mix.nch)
s->mix.join = s->mix.nch / dev_nch;
}
cmap_init(&s->mix.cmap,
s->opt->pmin, s->opt->pmin + s->mix.nch - 1,
s->opt->pmin, s->opt->pmin + s->mix.nch - 1,
@ -1623,32 +1592,22 @@ slot_allocbufs(struct slot *s)
s->opt->pmin, s->opt->pmax);
if (!aparams_native(&s->par)) {
dec_init(&s->mix.dec, &s->par, s->mix.nch);
s->mix.decbuf =
xmalloc(s->round * s->mix.nch * sizeof(adata_t));
}
if (s->rate != d->rate) {
resamp_init(&s->mix.resamp, s->round, d->round,
s->mix.nch);
s->mix.resampbuf =
xmalloc(d->round * s->mix.nch * sizeof(adata_t));
}
s->mix.join = 1;
s->mix.expand = 1;
if (s->opt->dup) {
if (s->mix.cmap.nch > s->mix.nch)
s->mix.expand = s->mix.cmap.nch / s->mix.nch;
else if (s->mix.cmap.nch > 0)
s->mix.join = s->mix.nch / s->mix.cmap.nch;
}
}
if (s->mode & MODE_RECMASK) {
s->sub.bpf = s->par.bps * s->sub.nch;
abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf);
dev_nch = s->opt->rmax - s->opt->rmin + 1;
s->sub.encbuf = NULL;
s->sub.resampbuf = NULL;
s->sub.join = 1;
s->sub.expand = 1;
if (s->opt->dup) {
if (dev_nch > s->sub.nch)
s->sub.join = dev_nch / s->sub.nch;
else if (dev_nch < s->sub.nch)
s->sub.expand = s->sub.nch / dev_nch;
}
cmap_init(&s->sub.cmap,
0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
s->opt->rmin, s->opt->rmax,
@ -1657,13 +1616,17 @@ slot_allocbufs(struct slot *s)
if (s->rate != d->rate) {
resamp_init(&s->sub.resamp, d->round, s->round,
s->sub.nch);
s->sub.resampbuf =
xmalloc(d->round * s->sub.nch * sizeof(adata_t));
}
if (!aparams_native(&s->par)) {
enc_init(&s->sub.enc, &s->par, s->sub.nch);
s->sub.encbuf =
xmalloc(s->round * s->sub.nch * sizeof(adata_t));
}
s->sub.join = 1;
s->sub.expand = 1;
if (s->opt->dup) {
if (s->sub.cmap.nch > s->sub.nch)
s->sub.join = s->sub.cmap.nch / s->sub.nch;
else if (s->sub.cmap.nch > 0)
s->sub.expand = s->sub.nch / s->sub.cmap.nch;
}
/*
@ -1683,6 +1646,49 @@ slot_allocbufs(struct slot *s)
s->appbufsz * s->sub.nch * sizeof(adata_t));
}
}
}
/*
* allocate buffers & conversion chain
*/
void
slot_allocbufs(struct slot *s)
{
struct dev *d = s->dev;
if (s->mode & MODE_PLAY) {
s->mix.bpf = s->par.bps * s->mix.nch;
abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf);
s->mix.decbuf = NULL;
s->mix.resampbuf = NULL;
if (!aparams_native(&s->par)) {
s->mix.decbuf =
xmalloc(s->round * s->mix.nch * sizeof(adata_t));
}
if (s->rate != d->rate) {
s->mix.resampbuf =
xmalloc(d->round * s->mix.nch * sizeof(adata_t));
}
}
if (s->mode & MODE_RECMASK) {
s->sub.bpf = s->par.bps * s->sub.nch;
abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf);
s->sub.encbuf = NULL;
s->sub.resampbuf = NULL;
if (s->rate != d->rate) {
s->sub.resampbuf =
xmalloc(d->round * s->sub.nch * sizeof(adata_t));
}
if (!aparams_native(&s->par)) {
s->sub.encbuf =
xmalloc(s->round * s->sub.nch * sizeof(adata_t));
}
}
slot_initconv(s);
#ifdef DEBUG
if (log_level >= 3) {

View File

@ -254,7 +254,7 @@ extern struct dev *dev_list;
void dev_log(struct dev *);
void dev_close(struct dev *);
void dev_reopen(struct dev *);
int dev_reopen(struct dev *);
struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int);
struct dev *dev_bynum(int);

View File

@ -95,14 +95,13 @@ dev_siomix_onctl(void *arg, unsigned int addr, unsigned int val)
* open the mixer device.
*/
void
dev_siomix_open(struct dev *d, char *path)
dev_siomix_open(struct dev *d)
{
d->siomix.hdl = siomix_open(path, SIOMIX_READ | SIOMIX_WRITE, 0);
if (d->siomix.hdl == NULL)
return;
siomix_ondesc(d->siomix.hdl, dev_siomix_ondesc, d);
siomix_onctl(d->siomix.hdl, dev_siomix_onctl, d);
d->siomix.file = file_new(&dev_siomix_ops, d, path,
d->siomix.file = file_new(&dev_siomix_ops, d, "mix",
siomix_nfds(d->siomix.hdl));
}
@ -115,8 +114,6 @@ dev_siomix_close(struct dev *d)
if (d->siomix.hdl == NULL)
return;
file_del(d->siomix.file);
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
}
int

View File

@ -26,7 +26,7 @@ struct dev_siomix {
struct file *file;
};
void dev_siomix_open(struct dev *, char *);
void dev_siomix_open(struct dev *);
void dev_siomix_close(struct dev *);
#endif /* !defined(DEV_SIOMIX_H) */

View File

@ -16,7 +16,6 @@
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <sys/un.h>

View File

@ -596,25 +596,14 @@ port_done(struct port *c)
port_drain(c);
}
void
int
port_reopen(struct port *p)
{
if (p->state == PORT_CFG)
return;
return 1;
if (log_level >= 1) {
port_log(p);
log_puts(": reopening port\n");
}
if (!port_mio_reopen(p))
return 0;
port_mio_close(p);
if (!port_mio_open(p)) {
if (log_level >= 1) {
port_log(p);
log_puts(": found no working alternate port\n");
}
p->state = PORT_CFG;
port_exitall(p);
}
return 1;
}

View File

@ -121,6 +121,6 @@ int port_init(struct port *);
void port_done(struct port *);
void port_drain(struct port *);
int port_close(struct port *);
void port_reopen(struct port *);
int port_reopen(struct port *);
#endif /* !defined(MIDI_H) */

View File

@ -47,18 +47,26 @@ struct fileops port_mio_ops = {
/*
* open the port using one of the provided paths
*/
static char *
static struct mio_hdl *
port_mio_openlist(struct port *c, unsigned int mode)
{
struct mio_hdl *hdl;
struct name *n;
n = c->path_list;
while (1) {
if (n == NULL)
break;
c->mio.hdl = mio_open(n->str, mode, 1);
if (c->mio.hdl != NULL)
return n->str;
hdl = mio_open(n->str, mode, 1);
if (hdl != NULL) {
if (log_level >= 2) {
port_log(c);
log_puts(": using ");
log_puts(n->str);
log_puts("\n");
}
return hdl;
}
n = n->next;
}
return NULL;
@ -67,12 +75,37 @@ port_mio_openlist(struct port *c, unsigned int mode)
int
port_mio_open(struct port *p)
{
char *path;
path = port_mio_openlist(p, p->midi->mode);
p->mio.hdl = port_mio_openlist(p, p->midi->mode);
if (p->mio.hdl == NULL)
return 0;
p->mio.file = file_new(&port_mio_ops, p, path, mio_nfds(p->mio.hdl));
p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(p->mio.hdl));
return 1;
}
/*
* Open an alternate port. Upon success, close the old port
* and continue using the new one.
*/
int
port_mio_reopen(struct port *p)
{
struct mio_hdl *hdl;
hdl = port_mio_openlist(p, p->midi->mode);
if (hdl == NULL) {
if (log_level >= 1) {
port_log(p);
log_puts(": couldn't open an alternate port\n");
}
return 0;
}
/* close unused device */
file_del(p->mio.file);
mio_close(p->mio.hdl);
p->mio.hdl = hdl;
p->mio.file = file_new(&port_mio_ops, p, "port", mio_nfds(hdl));
return 1;
}
@ -150,5 +183,6 @@ port_mio_hup(void *arg)
{
struct port *p = arg;
port_reopen(p);
if (!port_reopen(p))
port_close(p);
}

View File

@ -25,6 +25,7 @@ struct port_mio {
};
int port_mio_open(struct port *);
int port_mio_reopen(struct port *);
void port_mio_close(struct port *);
#endif /* !defined(MIOFILE_H) */

View File

@ -87,18 +87,36 @@ dev_sio_timeout(void *arg)
/*
* open the device using one of the provided paths
*/
static char *
dev_sio_openlist(struct dev *d, unsigned int mode)
static struct sio_hdl *
dev_sio_openlist(struct dev *d, unsigned int mode, struct siomix_hdl **rmixhdl)
{
struct name *n;
struct sio_hdl *hdl;
struct siomix_hdl *mixhdl;
n = d->path_list;
while (1) {
if (n == NULL)
break;
d->sio.hdl = sio_open(n->str, mode, 1);
if (d->sio.hdl != NULL)
return n->str;
hdl = sio_open(n->str, mode, 1);
if (hdl != NULL) {
if (log_level >= 2) {
dev_log(d);
log_puts(": using ");
log_puts(n->str);
log_puts("\n");
}
mixhdl = siomix_open(n->str,
SIOMIX_READ | SIOMIX_WRITE, 0);
if (mixhdl == NULL) {
if (log_level >= 1) {
dev_log(d);
log_puts(": no mixer\n");
}
}
*rmixhdl = mixhdl;
return hdl;
}
n = n->next;
}
return NULL;
@ -112,18 +130,18 @@ dev_sio_open(struct dev *d)
{
struct sio_par par;
unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
char *path;
path = dev_sio_openlist(d, mode);
if (path == NULL) {
d->sio.hdl = dev_sio_openlist(d, mode, &d->siomix.hdl);
if (d->sio.hdl == NULL) {
if (mode != (SIO_PLAY | SIO_REC))
return 0;
path = dev_sio_openlist(d, SIO_PLAY);
if (path != NULL)
d->sio.hdl = dev_sio_openlist(d, SIO_PLAY, &d->siomix.hdl);
if (d->sio.hdl != NULL)
mode = SIO_PLAY;
else {
path = dev_sio_openlist(d, SIO_REC);
if (path != NULL)
d->sio.hdl = dev_sio_openlist(d,
SIO_REC, &d->siomix.hdl);
if (d->sio.hdl != NULL)
mode = SIO_REC;
else
return 0;
@ -233,18 +251,98 @@ dev_sio_open(struct dev *d)
if (!(mode & MODE_REC))
d->mode &= ~MODE_REC;
sio_onmove(d->sio.hdl, dev_sio_onmove, d);
d->sio.file = file_new(&dev_sio_ops, d, path, sio_nfds(d->sio.hdl));
d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl));
timo_set(&d->sio.watchdog, dev_sio_timeout, d);
if (log_level >= 1) {
dev_log(d);
log_puts(": using ");
log_puts(path);
log_puts("\n");
}
dev_siomix_open(d, path);
dev_siomix_open(d);
return 1;
bad_close:
sio_close(d->sio.hdl);
if (d->siomix.hdl) {
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
}
return 0;
}
/*
* Open an alternate device. Upon success and if the new device is
* compatible with the old one, close the old device and continue
* using the new one. The new device is not started.
*/
int
dev_sio_reopen(struct dev *d)
{
struct siomix_hdl *mixhdl;
struct sio_par par;
struct sio_hdl *hdl;
hdl = dev_sio_openlist(d, d->mode & (MODE_PLAY | MODE_REC), &mixhdl);
if (hdl == NULL) {
if (log_level >= 1) {
dev_log(d);
log_puts(": couldn't open an alternate device\n");
}
return 0;
}
sio_initpar(&par);
par.bits = d->par.bits;
par.bps = d->par.bps;
par.sig = d->par.sig;
par.le = d->par.le;
par.msb = d->par.msb;
if (d->mode & SIO_PLAY)
par.pchan = d->pchan;
if (d->mode & SIO_REC)
par.rchan = d->rchan;
par.appbufsz = d->bufsz;
par.round = d->round;
par.rate = d->rate;
if (!sio_setpar(hdl, &par))
goto bad_close;
if (!sio_getpar(hdl, &par))
goto bad_close;
/* check if new parameters are compatible with old ones */
if (par.round != d->round || par.bufsz != d->bufsz ||
par.rate != d->rate) {
if (log_level >= 1) {
dev_log(d);
log_puts(": alternate device not compatible\n");
}
goto bad_close;
}
/* close unused device */
timo_del(&d->sio.watchdog);
file_del(d->sio.file);
sio_close(d->sio.hdl);
dev_siomix_close(d);
if (d->siomix.hdl) {
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
}
/* update parameters */
d->par.bits = par.bits;
d->par.bps = par.bps;
d->par.sig = par.sig;
d->par.le = par.le;
d->par.msb = par.msb;
if (d->mode & SIO_PLAY)
d->pchan = par.pchan;
if (d->mode & SIO_REC)
d->rchan = par.rchan;
d->sio.hdl = hdl;
d->siomix.hdl = mixhdl;
d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(hdl));
sio_onmove(hdl, dev_sio_onmove, d);
return 1;
bad_close:
sio_close(hdl);
if (mixhdl)
siomix_close(mixhdl);
return 0;
}
@ -261,6 +359,10 @@ dev_sio_close(struct dev *d)
timo_del(&d->sio.watchdog);
file_del(d->sio.file);
sio_close(d->sio.hdl);
if (d->siomix.hdl) {
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
}
}
void
@ -523,5 +625,6 @@ dev_sio_hup(void *arg)
log_puts(": disconnected\n");
}
#endif
dev_reopen(d);
if (!dev_reopen(d))
dev_close(d);
}

View File

@ -38,6 +38,7 @@ struct dev_sio {
};
int dev_sio_open(struct dev *);
int dev_sio_reopen(struct dev *);
void dev_sio_close(struct dev *);
void dev_sio_log(struct dev *);
void dev_sio_start(struct dev *);

View File

@ -186,7 +186,7 @@ Examples:
.Va u8 , s16le , s24le3 , s24le4lsb .
.It Fl F Ar device
Specify an alternate device to use.
If doesn't work, the one given with the last
If it doesn't work, the one given with the last
.Fl f
or
.Fl F
@ -261,7 +261,7 @@ The default is
(i.e. full-duplex).
.It Fl Q Ar port
Specify an alternate MIDI port to use.
If doesn't work, the one given with the last
If it doesn't work, the one given with the last
.Fl Q
or
.Fl q