mirror of https://github.com/ericonr/sndio.git
Merge branch 'master' into mixer
This commit is contained in:
commit
5536f474fe
228
sndiod/dev.c
228
sndiod/dev.c
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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) */
|
||||
|
|
145
sndiod/siofile.c
145
sndiod/siofile.c
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue