mirror of https://github.com/ericonr/sndio.git
Merge branch 'master' of ssh://moule/~alex/git/sndio
This commit is contained in:
commit
e453b782d1
169
sndiod/dev.c
169
sndiod/dev.c
|
@ -58,7 +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_open(struct dev *);
|
int dev_open(struct dev *);
|
||||||
|
void dev_exitall(struct dev *);
|
||||||
|
void dev_close_do(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 *);
|
||||||
|
@ -966,7 +969,8 @@ dev_new(char *path, struct aparams *par,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
d = xmalloc(sizeof(struct dev));
|
d = xmalloc(sizeof(struct dev));
|
||||||
d->path = xstrdup(path);
|
d->path_list = NULL;
|
||||||
|
namelist_add(&d->path_list, path);
|
||||||
d->num = dev_sndnum++;
|
d->num = dev_sndnum++;
|
||||||
d->opt_list = NULL;
|
d->opt_list = NULL;
|
||||||
|
|
||||||
|
@ -1029,24 +1033,11 @@ 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(struct dev *d)
|
dev_open_do(struct dev *d)
|
||||||
{
|
{
|
||||||
d->mode = d->reqmode;
|
|
||||||
d->round = d->reqround;
|
|
||||||
d->bufsz = d->reqbufsz;
|
|
||||||
d->rate = d->reqrate;
|
|
||||||
d->pchan = d->reqpchan;
|
|
||||||
d->rchan = d->reqrchan;
|
|
||||||
d->par = d->reqpar;
|
|
||||||
if (d->pchan == 0)
|
|
||||||
d->pchan = 2;
|
|
||||||
if (d->rchan == 0)
|
|
||||||
d->rchan = 2;
|
|
||||||
if (!dev_sio_open(d)) {
|
if (!dev_sio_open(d)) {
|
||||||
if (log_level >= 1) {
|
if (log_level >= 1) {
|
||||||
dev_log(d);
|
dev_log(d);
|
||||||
log_puts(": ");
|
|
||||||
log_puts(d->path);
|
|
||||||
log_puts(": failed to open audio device\n");
|
log_puts(": failed to open audio device\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1109,15 +1100,51 @@ dev_open(struct dev *d)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* force the device to go in DEV_CFG state, the caller is supposed to
|
* Reset parameters and open the device.
|
||||||
* ensure buffers are drained
|
*/
|
||||||
|
int
|
||||||
|
dev_open(struct dev *d)
|
||||||
|
{
|
||||||
|
d->mode = d->reqmode;
|
||||||
|
d->round = d->reqround;
|
||||||
|
d->bufsz = d->reqbufsz;
|
||||||
|
d->rate = d->reqrate;
|
||||||
|
d->pchan = d->reqpchan;
|
||||||
|
d->rchan = d->reqrchan;
|
||||||
|
d->par = d->reqpar;
|
||||||
|
if (d->pchan == 0)
|
||||||
|
d->pchan = 2;
|
||||||
|
if (d->rchan == 0)
|
||||||
|
d->rchan = 2;
|
||||||
|
if (!dev_open_do(d))
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Force all slots to exit
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
dev_close(struct dev *d)
|
dev_exitall(struct dev *d)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct slot *s;
|
struct slot *s;
|
||||||
|
|
||||||
|
for (s = d->slot, i = DEV_NSLOT; i > 0; i--, s++) {
|
||||||
|
if (s->ops)
|
||||||
|
s->ops->exit(s->arg);
|
||||||
|
s->ops = NULL;
|
||||||
|
}
|
||||||
|
d->slot_list = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* force the device to go in DEV_CFG state, the caller is supposed to
|
||||||
|
* ensure buffers are drained
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dev_close_do(struct dev *d)
|
||||||
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (log_level >= 3) {
|
if (log_level >= 3) {
|
||||||
dev_log(d);
|
dev_log(d);
|
||||||
|
@ -1125,12 +1152,6 @@ dev_close(struct dev *d)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
d->pstate = DEV_CFG;
|
d->pstate = DEV_CFG;
|
||||||
for (s = d->slot, i = DEV_NSLOT; i > 0; i--, s++) {
|
|
||||||
if (s->ops)
|
|
||||||
s->ops->exit(s->arg);
|
|
||||||
s->ops = NULL;
|
|
||||||
}
|
|
||||||
d->slot_list = NULL;
|
|
||||||
dev_sio_close(d);
|
dev_sio_close(d);
|
||||||
if (d->mode & MODE_PLAY) {
|
if (d->mode & MODE_PLAY) {
|
||||||
if (d->encbuf != NULL)
|
if (d->encbuf != NULL)
|
||||||
|
@ -1144,6 +1165,104 @@ dev_close(struct dev *d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the device and exit all slots
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dev_close(struct dev *d)
|
||||||
|
{
|
||||||
|
dev_exitall(d);
|
||||||
|
dev_close_do(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Close the device, but attempt to migrate everything to a new sndio
|
||||||
|
* device.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
dev_reopen(struct dev *d)
|
||||||
|
{
|
||||||
|
struct slot *s;
|
||||||
|
long long pos;
|
||||||
|
unsigned int mode, round, bufsz, rate, pstate;
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
/* not opened */
|
||||||
|
if (d->pstate == DEV_CFG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (log_level >= 1) {
|
||||||
|
dev_log(d);
|
||||||
|
log_puts(": reopening device\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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) {
|
||||||
|
slot_log(s);
|
||||||
|
log_puts(": adjusted: delta -> ");
|
||||||
|
log_puti(s->delta);
|
||||||
|
log_puts(", delta_rem -> ");
|
||||||
|
log_puti(s->delta_rem);
|
||||||
|
log_puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d->tstate == MMC_RUN) {
|
||||||
|
d->mtc.delta -= delta * MTC_SEC;
|
||||||
|
if (log_level >= 2) {
|
||||||
|
dev_log(d);
|
||||||
|
log_puts(": adjusted mtc: delta ->");
|
||||||
|
log_puti(d->mtc.delta);
|
||||||
|
log_puts("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start the device if needed */
|
||||||
|
if (pstate == DEV_RUN)
|
||||||
|
dev_wakeup(d);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
dev_ref(struct dev *d)
|
dev_ref(struct dev *d)
|
||||||
{
|
{
|
||||||
|
@ -1250,7 +1369,7 @@ dev_del(struct dev *d)
|
||||||
}
|
}
|
||||||
midi_del(d->midi);
|
midi_del(d->midi);
|
||||||
*p = d->next;
|
*p = d->next;
|
||||||
xfree(d->path);
|
namelist_clear(&d->path_list);
|
||||||
xfree(d);
|
xfree(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ struct dev {
|
||||||
#define DEV_INIT 1 /* stopped */
|
#define DEV_INIT 1 /* stopped */
|
||||||
#define DEV_RUN 2 /* playin & recording */
|
#define DEV_RUN 2 /* playin & recording */
|
||||||
unsigned int pstate; /* one of above */
|
unsigned int pstate; /* one of above */
|
||||||
char *path; /* sio path */
|
struct name *path_list;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* actual parameters and runtime state (i.e. once opened)
|
* actual parameters and runtime state (i.e. once opened)
|
||||||
|
@ -201,6 +201,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 *);
|
||||||
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);
|
||||||
|
|
|
@ -33,6 +33,7 @@ void port_imsg(void *, unsigned char *, int);
|
||||||
void port_omsg(void *, unsigned char *, int);
|
void port_omsg(void *, unsigned char *, int);
|
||||||
void port_fill(void *, int);
|
void port_fill(void *, int);
|
||||||
void port_exit(void *);
|
void port_exit(void *);
|
||||||
|
void port_exitall(struct port *);
|
||||||
|
|
||||||
struct midiops port_midiops = {
|
struct midiops port_midiops = {
|
||||||
port_imsg,
|
port_imsg,
|
||||||
|
@ -438,7 +439,8 @@ port_new(char *path, unsigned int mode, int hold)
|
||||||
struct port *c;
|
struct port *c;
|
||||||
|
|
||||||
c = xmalloc(sizeof(struct port));
|
c = xmalloc(sizeof(struct port));
|
||||||
c->path = xstrdup(path);
|
c->path_list = NULL;
|
||||||
|
namelist_add(&c->path_list, path);
|
||||||
c->state = PORT_CFG;
|
c->state = PORT_CFG;
|
||||||
c->hold = hold;
|
c->hold = hold;
|
||||||
c->midi = midi_new(&port_midiops, c, mode);
|
c->midi = midi_new(&port_midiops, c, mode);
|
||||||
|
@ -468,7 +470,7 @@ port_del(struct port *c)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
*p = c->next;
|
*p = c->next;
|
||||||
xfree(c->path);
|
namelist_clear(&c->path_list);
|
||||||
xfree(c);
|
xfree(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +523,7 @@ port_open(struct port *c)
|
||||||
{
|
{
|
||||||
if (!port_mio_open(c)) {
|
if (!port_mio_open(c)) {
|
||||||
if (log_level >= 1) {
|
if (log_level >= 1) {
|
||||||
log_puts(c->path);
|
port_log(c);
|
||||||
log_puts(": failed to open midi port\n");
|
log_puts(": failed to open midi port\n");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -530,11 +532,23 @@ port_open(struct port *c)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
port_close(struct port *c)
|
port_exitall(struct port *c)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct midi *ep;
|
struct midi *ep;
|
||||||
|
|
||||||
|
for (i = 0; i < MIDI_NEP; i++) {
|
||||||
|
ep = midi_ep + i;
|
||||||
|
if ((ep->txmask & c->midi->self) ||
|
||||||
|
(c->midi->txmask & ep->self))
|
||||||
|
ep->ops->exit(ep->arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
port_close(struct port *c)
|
||||||
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (c->state == PORT_CFG) {
|
if (c->state == PORT_CFG) {
|
||||||
port_log(c);
|
port_log(c);
|
||||||
|
@ -545,12 +559,7 @@ port_close(struct port *c)
|
||||||
c->state = PORT_CFG;
|
c->state = PORT_CFG;
|
||||||
port_mio_close(c);
|
port_mio_close(c);
|
||||||
|
|
||||||
for (i = 0; i < MIDI_NEP; i++) {
|
port_exitall(c);
|
||||||
ep = midi_ep + i;
|
|
||||||
if ((ep->txmask & c->midi->self) ||
|
|
||||||
(c->midi->txmask & ep->self))
|
|
||||||
ep->ops->exit(ep->arg);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,3 +595,26 @@ port_done(struct port *c)
|
||||||
if (c->state == PORT_INIT)
|
if (c->state == PORT_INIT)
|
||||||
port_drain(c);
|
port_drain(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
port_reopen(struct port *p)
|
||||||
|
{
|
||||||
|
if (p->state == PORT_CFG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (log_level >= 1) {
|
||||||
|
port_log(p);
|
||||||
|
log_puts(": reopening port\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -88,8 +88,8 @@ struct port {
|
||||||
#define PORT_DRAIN 2
|
#define PORT_DRAIN 2
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
unsigned int num; /* port serial number */
|
unsigned int num; /* port serial number */
|
||||||
char *path; /* hold the port open ? */
|
struct name *path_list;
|
||||||
int hold;
|
int hold; /* hold the port open ? */
|
||||||
struct midi *midi;
|
struct midi *midi;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -121,5 +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 *);
|
||||||
|
|
||||||
#endif /* !defined(MIDI_H) */
|
#endif /* !defined(MIDI_H) */
|
||||||
|
|
|
@ -44,13 +44,35 @@ struct fileops port_mio_ops = {
|
||||||
port_mio_hup
|
port_mio_hup
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* open the port using one of the provided paths
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
port_mio_openlist(struct port *c, unsigned int mode)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
port_mio_open(struct port *p)
|
port_mio_open(struct port *p)
|
||||||
{
|
{
|
||||||
p->mio.hdl = mio_open(p->path, p->midi->mode, 1);
|
char *path;
|
||||||
|
|
||||||
|
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, p->path, mio_nfds(p->mio.hdl));
|
p->mio.file = file_new(&port_mio_ops, p, path, mio_nfds(p->mio.hdl));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,5 +150,5 @@ port_mio_hup(void *arg)
|
||||||
{
|
{
|
||||||
struct port *p = arg;
|
struct port *p = arg;
|
||||||
|
|
||||||
port_close(p);
|
port_reopen(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,6 +83,26 @@ dev_sio_timeout(void *arg)
|
||||||
dev_close(d);
|
dev_close(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* open the device using one of the provided paths
|
||||||
|
*/
|
||||||
|
static char *
|
||||||
|
dev_sio_openlist(struct dev *d, unsigned int mode)
|
||||||
|
{
|
||||||
|
struct name *n;
|
||||||
|
|
||||||
|
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;
|
||||||
|
n = n->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open the device.
|
* open the device.
|
||||||
*/
|
*/
|
||||||
|
@ -91,17 +111,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;
|
||||||
|
|
||||||
d->sio.hdl = sio_open(d->path, mode, 1);
|
path = dev_sio_openlist(d, mode);
|
||||||
if (d->sio.hdl == NULL) {
|
if (path == NULL) {
|
||||||
if (mode != (SIO_PLAY | SIO_REC))
|
if (mode != (SIO_PLAY | SIO_REC))
|
||||||
return 0;
|
return 0;
|
||||||
d->sio.hdl = sio_open(d->path, SIO_PLAY, 1);
|
path = dev_sio_openlist(d, SIO_PLAY);
|
||||||
if (d->sio.hdl != NULL)
|
if (path != NULL)
|
||||||
mode = SIO_PLAY;
|
mode = SIO_PLAY;
|
||||||
else {
|
else {
|
||||||
d->sio.hdl = sio_open(d->path, SIO_REC, 1);
|
path = dev_sio_openlist(d, SIO_REC);
|
||||||
if (d->sio.hdl != NULL)
|
if (path != NULL)
|
||||||
mode = SIO_REC;
|
mode = SIO_REC;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -143,35 +164,35 @@ dev_sio_open(struct dev *d)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (par.bits > BITS_MAX) {
|
if (par.bits > BITS_MAX) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.bits);
|
log_putu(par.bits);
|
||||||
log_puts(": unsupported number of bits\n");
|
log_puts(": unsupported number of bits\n");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
if (par.bps > SIO_BPS(BITS_MAX)) {
|
if (par.bps > SIO_BPS(BITS_MAX)) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.bps);
|
log_putu(par.bps);
|
||||||
log_puts(": unsupported sample size\n");
|
log_puts(": unsupported sample size\n");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
|
if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.pchan);
|
log_putu(par.pchan);
|
||||||
log_puts(": unsupported number of play channels\n");
|
log_puts(": unsupported number of play channels\n");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) {
|
if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.rchan);
|
log_putu(par.rchan);
|
||||||
log_puts(": unsupported number of rec channels\n");
|
log_puts(": unsupported number of rec channels\n");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
if (par.bufsz == 0 || par.bufsz > RATE_MAX) {
|
if (par.bufsz == 0 || par.bufsz > RATE_MAX) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.bufsz);
|
log_putu(par.bufsz);
|
||||||
log_puts(": unsupported buffer size\n");
|
log_puts(": unsupported buffer size\n");
|
||||||
|
@ -179,14 +200,14 @@ dev_sio_open(struct dev *d)
|
||||||
}
|
}
|
||||||
if (par.round == 0 || par.round > par.bufsz ||
|
if (par.round == 0 || par.round > par.bufsz ||
|
||||||
par.bufsz % par.round != 0) {
|
par.bufsz % par.round != 0) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.round);
|
log_putu(par.round);
|
||||||
log_puts(": unsupported block size\n");
|
log_puts(": unsupported block size\n");
|
||||||
goto bad_close;
|
goto bad_close;
|
||||||
}
|
}
|
||||||
if (par.rate == 0 || par.rate > RATE_MAX) {
|
if (par.rate == 0 || par.rate > RATE_MAX) {
|
||||||
log_puts(d->path);
|
dev_log(d);
|
||||||
log_puts(": ");
|
log_puts(": ");
|
||||||
log_putu(par.rate);
|
log_putu(par.rate);
|
||||||
log_puts(": unsupported rate\n");
|
log_puts(": unsupported rate\n");
|
||||||
|
@ -211,8 +232,14 @@ 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, d->path, sio_nfds(d->sio.hdl));
|
d->sio.file = file_new(&dev_sio_ops, d, path, 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_log(d);
|
||||||
|
log_puts(": using ");
|
||||||
|
log_puts(path);
|
||||||
|
log_puts("\n");
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
bad_close:
|
bad_close:
|
||||||
sio_close(d->sio.hdl);
|
sio_close(d->sio.hdl);
|
||||||
|
@ -493,5 +520,5 @@ dev_sio_hup(void *arg)
|
||||||
log_puts(": disconnected\n");
|
log_puts(": disconnected\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dev_close(d);
|
dev_reopen(d);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,10 +29,12 @@
|
||||||
.Op Fl C Ar min : Ns Ar max
|
.Op Fl C Ar min : Ns Ar max
|
||||||
.Op Fl c Ar min : Ns Ar max
|
.Op Fl c Ar min : Ns Ar max
|
||||||
.Op Fl e Ar enc
|
.Op Fl e Ar enc
|
||||||
|
.Op Fl F Ar device
|
||||||
.Op Fl f Ar device
|
.Op Fl f Ar device
|
||||||
.Op Fl j Ar flag
|
.Op Fl j Ar flag
|
||||||
.Op Fl L Ar addr
|
.Op Fl L Ar addr
|
||||||
.Op Fl m Ar mode
|
.Op Fl m Ar mode
|
||||||
|
.Op Fl Q Ar port
|
||||||
.Op Fl q Ar port
|
.Op Fl q Ar port
|
||||||
.Op Fl r Ar rate
|
.Op Fl r Ar rate
|
||||||
.Op Fl s Ar name
|
.Op Fl s Ar name
|
||||||
|
@ -182,6 +184,18 @@ or
|
||||||
Only the signedness and the precision are mandatory.
|
Only the signedness and the precision are mandatory.
|
||||||
Examples:
|
Examples:
|
||||||
.Va u8 , s16le , s24le3 , s24le4lsb .
|
.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
|
||||||
|
.Fl f
|
||||||
|
or
|
||||||
|
.Fl F
|
||||||
|
options will be used.
|
||||||
|
For instance, specifying a USB device following a
|
||||||
|
PCI device allows
|
||||||
|
.Nm
|
||||||
|
to use the USB one preferably when it's connected
|
||||||
|
and to fall back to the PCI one when it's disconnected.
|
||||||
.It Fl f Ar device
|
.It Fl f Ar device
|
||||||
Add this
|
Add this
|
||||||
.Xr sndio 7
|
.Xr sndio 7
|
||||||
|
@ -245,6 +259,15 @@ but the same sub-device cannot be used for both recording and monitoring.
|
||||||
The default is
|
The default is
|
||||||
.Ar play , Ns Ar rec
|
.Ar play , Ns Ar rec
|
||||||
(i.e. full-duplex).
|
(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
|
||||||
|
.Fl Q
|
||||||
|
or
|
||||||
|
.Fl q
|
||||||
|
options will be used.
|
||||||
|
For instance, this allows to replace a USB MIDI controller without
|
||||||
|
the need to restart programs using it.
|
||||||
.It Fl q Ar port
|
.It Fl q Ar port
|
||||||
Expose the given MIDI port.
|
Expose the given MIDI port.
|
||||||
This allows multiple programs to share the port.
|
This allows multiple programs to share the port.
|
||||||
|
@ -376,11 +399,15 @@ is
|
||||||
If
|
If
|
||||||
.Nm
|
.Nm
|
||||||
is sent
|
is sent
|
||||||
.Dv SIGHUP ,
|
|
||||||
.Dv SIGINT
|
.Dv SIGINT
|
||||||
or
|
or
|
||||||
.Dv SIGTERM ,
|
.Dv SIGTERM ,
|
||||||
it terminates.
|
it terminates.
|
||||||
|
If
|
||||||
|
.Nm
|
||||||
|
is sent
|
||||||
|
.Dv SIGHUP ,
|
||||||
|
it reopens all audio devices and MIDI ports.
|
||||||
.Pp
|
.Pp
|
||||||
By default, when the program cannot accept
|
By default, when the program cannot accept
|
||||||
recorded data fast enough or cannot provide data to play fast enough,
|
recorded data fast enough or cannot provide data to play fast enough,
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
* block size if neither ``-z'' nor ``-b'' is used
|
* block size if neither ``-z'' nor ``-b'' is used
|
||||||
*/
|
*/
|
||||||
#ifndef DEFAULT_ROUND
|
#ifndef DEFAULT_ROUND
|
||||||
#define DEFAULT_ROUND 960
|
#define DEFAULT_ROUND 480
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -86,6 +86,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sigint(int);
|
void sigint(int);
|
||||||
|
void sighup(int);
|
||||||
void opt_ch(int *, int *);
|
void opt_ch(int *, int *);
|
||||||
void opt_enc(struct aparams *);
|
void opt_enc(struct aparams *);
|
||||||
int opt_mmc(void);
|
int opt_mmc(void);
|
||||||
|
@ -102,12 +103,13 @@ struct opt *mkopt(char *, struct dev *,
|
||||||
int, int, int, int, int, int, int, int);
|
int, int, int, int, int, int, int, int);
|
||||||
|
|
||||||
unsigned int log_level = 0;
|
unsigned int log_level = 0;
|
||||||
volatile sig_atomic_t quit_flag = 0;
|
volatile sig_atomic_t quit_flag = 0, reopen_flag = 0;
|
||||||
|
|
||||||
char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
|
char usagestr[] = "usage: sndiod [-d] [-a flag] [-b nframes] "
|
||||||
"[-C min:max] [-c min:max] [-e enc]\n\t"
|
"[-C min:max] [-c min:max]\n\t"
|
||||||
"[-f device] [-j flag] [-L addr] [-m mode] [-q port] [-r rate]\n\t"
|
"[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
|
||||||
"[-s name] [-t mode] [-U unit] [-v volume] [-w flag] [-z nframes]\n";
|
"[-Q port] [-q port] [-r rate] [-s name] [-t mode] [-U unit]\n\t"
|
||||||
|
"[-v volume] [-w flag] [-z nframes]\n";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIGINT handler, it raises the quit flag. If the flag is already set,
|
* SIGINT handler, it raises the quit flag. If the flag is already set,
|
||||||
|
@ -122,6 +124,16 @@ sigint(int s)
|
||||||
quit_flag = 1;
|
quit_flag = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SIGHUP handler, it raises the reopen flag, which requests devices
|
||||||
|
* to be reopened.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
sighup(int s)
|
||||||
|
{
|
||||||
|
reopen_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
opt_ch(int *rcmin, int *rcmax)
|
opt_ch(int *rcmin, int *rcmax)
|
||||||
{
|
{
|
||||||
|
@ -224,6 +236,7 @@ setsig(void)
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
|
|
||||||
quit_flag = 0;
|
quit_flag = 0;
|
||||||
|
reopen_flag = 0;
|
||||||
sigfillset(&sa.sa_mask);
|
sigfillset(&sa.sa_mask);
|
||||||
sa.sa_flags = SA_RESTART;
|
sa.sa_flags = SA_RESTART;
|
||||||
sa.sa_handler = sigint;
|
sa.sa_handler = sigint;
|
||||||
|
@ -231,6 +244,7 @@ setsig(void)
|
||||||
err(1, "sigaction(int) failed");
|
err(1, "sigaction(int) failed");
|
||||||
if (sigaction(SIGTERM, &sa, NULL) == -1)
|
if (sigaction(SIGTERM, &sa, NULL) == -1)
|
||||||
err(1, "sigaction(term) failed");
|
err(1, "sigaction(term) failed");
|
||||||
|
sa.sa_handler = sighup;
|
||||||
if (sigaction(SIGHUP, &sa, NULL) == -1)
|
if (sigaction(SIGHUP, &sa, NULL) == -1)
|
||||||
err(1, "sigaction(hup) failed");
|
err(1, "sigaction(hup) failed");
|
||||||
}
|
}
|
||||||
|
@ -287,7 +301,8 @@ mkdev(char *path, struct aparams *par,
|
||||||
struct dev *d;
|
struct dev *d;
|
||||||
|
|
||||||
for (d = dev_list; d != NULL; d = d->next) {
|
for (d = dev_list; d != NULL; d = d->next) {
|
||||||
if (strcmp(d->path, path) == 0)
|
if (d->path_list->next == NULL &&
|
||||||
|
strcmp(d->path_list->str, path) == 0)
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
if (!bufsz && !round) {
|
if (!bufsz && !round) {
|
||||||
|
@ -309,7 +324,8 @@ mkport(char *path, int hold)
|
||||||
struct port *c;
|
struct port *c;
|
||||||
|
|
||||||
for (c = port_list; c != NULL; c = c->next) {
|
for (c = port_list; c != NULL; c = c->next) {
|
||||||
if (strcmp(c->path, path) == 0)
|
if (c->path_list->next == NULL &&
|
||||||
|
strcmp(c->path_list->str, path) == 0)
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
c = port_new(path, MODE_MIDIMASK, hold);
|
c = port_new(path, MODE_MIDIMASK, hold);
|
||||||
|
@ -375,7 +391,8 @@ main(int argc, char **argv)
|
||||||
mode = MODE_PLAY | MODE_REC;
|
mode = MODE_PLAY | MODE_REC;
|
||||||
tcpaddr_list = NULL;
|
tcpaddr_list = NULL;
|
||||||
|
|
||||||
while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) {
|
while ((c = getopt(argc, argv,
|
||||||
|
"a:b:c:C:de:F:f:j:L:m:Q:q:r:s:t:U:v:w:x:z:")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'd':
|
case 'd':
|
||||||
log_level++;
|
log_level++;
|
||||||
|
@ -432,6 +449,11 @@ main(int argc, char **argv)
|
||||||
case 'q':
|
case 'q':
|
||||||
mkport(optarg, hold);
|
mkport(optarg, hold);
|
||||||
break;
|
break;
|
||||||
|
case 'Q':
|
||||||
|
if (port_list == NULL)
|
||||||
|
errx(1, "-Q %s: no ports defined", optarg);
|
||||||
|
namelist_add(&port_list->path_list, optarg);
|
||||||
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
hold = opt_onoff();
|
hold = opt_onoff();
|
||||||
break;
|
break;
|
||||||
|
@ -452,6 +474,11 @@ main(int argc, char **argv)
|
||||||
mkdev(optarg, &par, 0, bufsz, round,
|
mkdev(optarg, &par, 0, bufsz, round,
|
||||||
rate, hold, autovol);
|
rate, hold, autovol);
|
||||||
break;
|
break;
|
||||||
|
case 'F':
|
||||||
|
if (dev_list == NULL)
|
||||||
|
errx(1, "-F %s: no devices defined", optarg);
|
||||||
|
namelist_add(&dev_list->path_list, optarg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
fputs(usagestr, stderr);
|
fputs(usagestr, stderr);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -519,6 +546,13 @@ main(int argc, char **argv)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (quit_flag)
|
if (quit_flag)
|
||||||
break;
|
break;
|
||||||
|
if (reopen_flag) {
|
||||||
|
reopen_flag = 0;
|
||||||
|
for (d = dev_list; d != NULL; d = d->next)
|
||||||
|
dev_reopen(d);
|
||||||
|
for (p = port_list; p != NULL; p = p->next)
|
||||||
|
port_reopen(p);
|
||||||
|
}
|
||||||
if (!file_poll())
|
if (!file_poll())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,3 +188,30 @@ xstrdup(char *s)
|
||||||
memcpy(p, s, size);
|
memcpy(p, s, size);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy and append the given string to the name list
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
namelist_add(struct name **list, char *str)
|
||||||
|
{
|
||||||
|
struct name *n;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
size = strlen(str) + 1;
|
||||||
|
n = xmalloc(sizeof(struct name) + size);
|
||||||
|
memcpy(n->str, str, size);
|
||||||
|
n->next = *list;
|
||||||
|
*list = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
namelist_clear(struct name **list)
|
||||||
|
{
|
||||||
|
struct name *n;
|
||||||
|
|
||||||
|
while ((n = *list) != NULL) {
|
||||||
|
*list = n->next;
|
||||||
|
xfree(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,11 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct name {
|
||||||
|
struct name *next;
|
||||||
|
char str[];
|
||||||
|
};
|
||||||
|
|
||||||
void log_puts(char *);
|
void log_puts(char *);
|
||||||
void log_putx(unsigned long);
|
void log_putx(unsigned long);
|
||||||
void log_putu(unsigned long);
|
void log_putu(unsigned long);
|
||||||
|
@ -31,6 +36,9 @@ void *xmalloc(size_t);
|
||||||
char *xstrdup(char *);
|
char *xstrdup(char *);
|
||||||
void xfree(void *);
|
void xfree(void *);
|
||||||
|
|
||||||
|
void namelist_add(struct name **, char *);
|
||||||
|
void namelist_clear(struct name **);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Log levels:
|
* Log levels:
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue