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

View File

@ -254,7 +254,7 @@ extern struct dev *dev_list;
void dev_log(struct dev *); void dev_log(struct dev *);
void dev_close(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, struct dev *dev_new(char *, struct aparams *, unsigned int, unsigned int,
unsigned int, unsigned int, unsigned int, unsigned int); unsigned int, unsigned int, unsigned int, unsigned int);
struct dev *dev_bynum(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. * open the mixer device.
*/ */
void 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) if (d->siomix.hdl == NULL)
return; return;
siomix_ondesc(d->siomix.hdl, dev_siomix_ondesc, d); siomix_ondesc(d->siomix.hdl, dev_siomix_ondesc, d);
siomix_onctl(d->siomix.hdl, dev_siomix_onctl, 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)); siomix_nfds(d->siomix.hdl));
} }
@ -115,8 +114,6 @@ dev_siomix_close(struct dev *d)
if (d->siomix.hdl == NULL) if (d->siomix.hdl == NULL)
return; return;
file_del(d->siomix.file); file_del(d->siomix.file);
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
} }
int int

View File

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

View File

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

View File

@ -596,25 +596,14 @@ port_done(struct port *c)
port_drain(c); port_drain(c);
} }
void int
port_reopen(struct port *p) port_reopen(struct port *p)
{ {
if (p->state == PORT_CFG) if (p->state == PORT_CFG)
return; return 1;
if (log_level >= 1) { if (!port_mio_reopen(p))
port_log(p); return 0;
log_puts(": reopening port\n");
}
port_mio_close(p); return 1;
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);
}
} }

View File

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

View File

@ -47,18 +47,26 @@ struct fileops port_mio_ops = {
/* /*
* open the port using one of the provided paths * open the port using one of the provided paths
*/ */
static char * static struct mio_hdl *
port_mio_openlist(struct port *c, unsigned int mode) port_mio_openlist(struct port *c, unsigned int mode)
{ {
struct mio_hdl *hdl;
struct name *n; struct name *n;
n = c->path_list; n = c->path_list;
while (1) { while (1) {
if (n == NULL) if (n == NULL)
break; break;
c->mio.hdl = mio_open(n->str, mode, 1); hdl = mio_open(n->str, mode, 1);
if (c->mio.hdl != NULL) if (hdl != NULL) {
return n->str; if (log_level >= 2) {
port_log(c);
log_puts(": using ");
log_puts(n->str);
log_puts("\n");
}
return hdl;
}
n = n->next; n = n->next;
} }
return NULL; return NULL;
@ -67,12 +75,37 @@ port_mio_openlist(struct port *c, unsigned int mode)
int int
port_mio_open(struct port *p) port_mio_open(struct port *p)
{ {
char *path; p->mio.hdl = port_mio_openlist(p, p->midi->mode);
path = port_mio_openlist(p, p->midi->mode);
if (p->mio.hdl == NULL) if (p->mio.hdl == NULL)
return 0; 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; return 1;
} }
@ -150,5 +183,6 @@ port_mio_hup(void *arg)
{ {
struct port *p = 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_open(struct port *);
int port_mio_reopen(struct port *);
void port_mio_close(struct port *); void port_mio_close(struct port *);
#endif /* !defined(MIOFILE_H) */ #endif /* !defined(MIOFILE_H) */

View File

@ -87,18 +87,36 @@ dev_sio_timeout(void *arg)
/* /*
* open the device using one of the provided paths * open the device using one of the provided paths
*/ */
static char * static struct sio_hdl *
dev_sio_openlist(struct dev *d, unsigned int mode) dev_sio_openlist(struct dev *d, unsigned int mode, struct siomix_hdl **rmixhdl)
{ {
struct name *n; struct name *n;
struct sio_hdl *hdl;
struct siomix_hdl *mixhdl;
n = d->path_list; n = d->path_list;
while (1) { while (1) {
if (n == NULL) if (n == NULL)
break; break;
d->sio.hdl = sio_open(n->str, mode, 1); hdl = sio_open(n->str, mode, 1);
if (d->sio.hdl != NULL) if (hdl != NULL) {
return n->str; 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; n = n->next;
} }
return NULL; return NULL;
@ -112,18 +130,18 @@ dev_sio_open(struct dev *d)
{ {
struct sio_par par; struct sio_par par;
unsigned int mode = d->mode & (MODE_PLAY | MODE_REC); unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
char *path;
path = dev_sio_openlist(d, mode); d->sio.hdl = dev_sio_openlist(d, mode, &d->siomix.hdl);
if (path == NULL) { if (d->sio.hdl == NULL) {
if (mode != (SIO_PLAY | SIO_REC)) if (mode != (SIO_PLAY | SIO_REC))
return 0; return 0;
path = dev_sio_openlist(d, SIO_PLAY); d->sio.hdl = dev_sio_openlist(d, SIO_PLAY, &d->siomix.hdl);
if (path != NULL) if (d->sio.hdl != NULL)
mode = SIO_PLAY; mode = SIO_PLAY;
else { else {
path = dev_sio_openlist(d, SIO_REC); d->sio.hdl = dev_sio_openlist(d,
if (path != NULL) SIO_REC, &d->siomix.hdl);
if (d->sio.hdl != NULL)
mode = SIO_REC; mode = SIO_REC;
else else
return 0; return 0;
@ -233,18 +251,98 @@ dev_sio_open(struct dev *d)
if (!(mode & MODE_REC)) if (!(mode & MODE_REC))
d->mode &= ~MODE_REC; d->mode &= ~MODE_REC;
sio_onmove(d->sio.hdl, dev_sio_onmove, d); 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); timo_set(&d->sio.watchdog, dev_sio_timeout, d);
if (log_level >= 1) { dev_siomix_open(d);
dev_log(d);
log_puts(": using ");
log_puts(path);
log_puts("\n");
}
dev_siomix_open(d, path);
return 1; return 1;
bad_close: bad_close:
sio_close(d->sio.hdl); 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; return 0;
} }
@ -261,6 +359,10 @@ dev_sio_close(struct dev *d)
timo_del(&d->sio.watchdog); timo_del(&d->sio.watchdog);
file_del(d->sio.file); file_del(d->sio.file);
sio_close(d->sio.hdl); sio_close(d->sio.hdl);
if (d->siomix.hdl) {
siomix_close(d->siomix.hdl);
d->siomix.hdl = NULL;
}
} }
void void
@ -523,5 +625,6 @@ dev_sio_hup(void *arg)
log_puts(": disconnected\n"); log_puts(": disconnected\n");
} }
#endif #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_open(struct dev *);
int dev_sio_reopen(struct dev *);
void dev_sio_close(struct dev *); void dev_sio_close(struct dev *);
void dev_sio_log(struct dev *); void dev_sio_log(struct dev *);
void dev_sio_start(struct dev *); void dev_sio_start(struct dev *);

View File

@ -186,7 +186,7 @@ Examples:
.Va u8 , s16le , s24le3 , s24le4lsb . .Va u8 , s16le , s24le3 , s24le4lsb .
.It Fl F Ar device .It Fl F Ar device
Specify an alternate device to use. 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 .Fl f
or or
.Fl F .Fl F
@ -261,7 +261,7 @@ The default is
(i.e. full-duplex). (i.e. full-duplex).
.It Fl Q Ar port .It Fl Q Ar port
Specify an alternate MIDI port to use. 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 .Fl Q
or or
.Fl q .Fl q