mirror of https://github.com/ericonr/sndio.git
Merge branch 'master' into mixer
This commit is contained in:
commit
4453acee80
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,
|
||||
unsigned int, unsigned int, unsigned int, unsigned int);
|
||||
void dev_adjpar(struct dev *, int, int, int);
|
||||
int dev_open_do(struct dev *);
|
||||
int dev_open(struct dev *);
|
||||
void dev_exitall(struct dev *);
|
||||
void dev_close_do(struct dev *);
|
||||
void dev_close(struct dev *);
|
||||
int dev_ref(struct dev *);
|
||||
void dev_unref(struct dev *);
|
||||
|
@ -973,7 +976,8 @@ dev_new(char *path, struct aparams *par,
|
|||
return NULL;
|
||||
}
|
||||
d = xmalloc(sizeof(struct dev));
|
||||
d->path = xstrdup(path);
|
||||
d->path_list = NULL;
|
||||
namelist_add(&d->path_list, path);
|
||||
d->num = dev_sndnum++;
|
||||
d->opt_list = NULL;
|
||||
|
||||
|
@ -1043,27 +1047,14 @@ dev_adjpar(struct dev *d, int mode,
|
|||
* monitor, midi control, and any necessary conversions.
|
||||
*/
|
||||
int
|
||||
dev_open(struct dev *d)
|
||||
dev_open_do(struct dev *d)
|
||||
{
|
||||
int i, gunit;
|
||||
struct ctl *c;
|
||||
|
||||
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 (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_puts(d->path);
|
||||
log_puts(": failed to open audio device\n");
|
||||
}
|
||||
return 0;
|
||||
|
@ -1155,16 +1146,52 @@ dev_open(struct dev *d)
|
|||
}
|
||||
|
||||
/*
|
||||
* force the device to go in DEV_CFG state, the caller is supposed to
|
||||
* ensure buffers are drained
|
||||
* Reset parameters and open the device.
|
||||
*/
|
||||
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
|
||||
dev_close(struct dev *d)
|
||||
dev_exitall(struct dev *d)
|
||||
{
|
||||
int i;
|
||||
struct slot *s;
|
||||
struct ctl *c;
|
||||
|
||||
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
|
||||
if (log_level >= 3) {
|
||||
dev_log(d);
|
||||
|
@ -1176,12 +1203,6 @@ dev_close(struct dev *d)
|
|||
xfree(c);
|
||||
}
|
||||
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_siomix_close(d);
|
||||
dev_sio_close(d);
|
||||
if (d->mode & MODE_PLAY) {
|
||||
|
@ -1196,6 +1217,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
|
||||
dev_ref(struct dev *d)
|
||||
{
|
||||
|
@ -1302,7 +1421,7 @@ dev_del(struct dev *d)
|
|||
}
|
||||
midi_del(d->midi);
|
||||
*p = d->next;
|
||||
xfree(d->path);
|
||||
namelist_clear(&d->path_list);
|
||||
xfree(d);
|
||||
}
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ struct dev {
|
|||
#define DEV_INIT 1 /* stopped */
|
||||
#define DEV_RUN 2 /* playin & recording */
|
||||
unsigned int pstate; /* one of above */
|
||||
char *path; /* sio path */
|
||||
struct name *path_list;
|
||||
|
||||
/*
|
||||
* actual parameters and runtime state (i.e. once opened)
|
||||
|
@ -246,6 +246,7 @@ extern struct dev *dev_list;
|
|||
|
||||
void dev_log(struct dev *);
|
||||
void dev_close(struct dev *);
|
||||
void 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);
|
||||
|
|
|
@ -33,6 +33,7 @@ void port_imsg(void *, unsigned char *, int);
|
|||
void port_omsg(void *, unsigned char *, int);
|
||||
void port_fill(void *, int);
|
||||
void port_exit(void *);
|
||||
void port_exitall(struct port *);
|
||||
|
||||
struct midiops port_midiops = {
|
||||
port_imsg,
|
||||
|
@ -438,7 +439,8 @@ port_new(char *path, unsigned int mode, int hold)
|
|||
struct port *c;
|
||||
|
||||
c = xmalloc(sizeof(struct port));
|
||||
c->path = xstrdup(path);
|
||||
c->path_list = NULL;
|
||||
namelist_add(&c->path_list, path);
|
||||
c->state = PORT_CFG;
|
||||
c->hold = hold;
|
||||
c->midi = midi_new(&port_midiops, c, mode);
|
||||
|
@ -468,7 +470,7 @@ port_del(struct port *c)
|
|||
#endif
|
||||
}
|
||||
*p = c->next;
|
||||
xfree(c->path);
|
||||
namelist_clear(&c->path_list);
|
||||
xfree(c);
|
||||
}
|
||||
|
||||
|
@ -521,7 +523,7 @@ port_open(struct port *c)
|
|||
{
|
||||
if (!port_mio_open(c)) {
|
||||
if (log_level >= 1) {
|
||||
log_puts(c->path);
|
||||
port_log(c);
|
||||
log_puts(": failed to open midi port\n");
|
||||
}
|
||||
return 0;
|
||||
|
@ -530,11 +532,23 @@ port_open(struct port *c)
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
port_close(struct port *c)
|
||||
void
|
||||
port_exitall(struct port *c)
|
||||
{
|
||||
int i;
|
||||
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
|
||||
if (c->state == PORT_CFG) {
|
||||
port_log(c);
|
||||
|
@ -545,12 +559,7 @@ port_close(struct port *c)
|
|||
c->state = PORT_CFG;
|
||||
port_mio_close(c);
|
||||
|
||||
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);
|
||||
}
|
||||
port_exitall(c);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -586,3 +595,26 @@ port_done(struct port *c)
|
|||
if (c->state == PORT_INIT)
|
||||
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
|
||||
unsigned int state;
|
||||
unsigned int num; /* port serial number */
|
||||
char *path; /* hold the port open ? */
|
||||
int hold;
|
||||
struct name *path_list;
|
||||
int hold; /* hold the port open ? */
|
||||
struct midi *midi;
|
||||
};
|
||||
|
||||
|
@ -121,5 +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 *);
|
||||
|
||||
#endif /* !defined(MIDI_H) */
|
||||
|
|
|
@ -44,13 +44,35 @@ struct fileops port_mio_ops = {
|
|||
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
|
||||
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)
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -128,5 +150,5 @@ port_mio_hup(void *arg)
|
|||
{
|
||||
struct port *p = arg;
|
||||
|
||||
port_close(p);
|
||||
port_reopen(p);
|
||||
}
|
||||
|
|
|
@ -84,6 +84,26 @@ dev_sio_timeout(void *arg)
|
|||
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.
|
||||
*/
|
||||
|
@ -92,17 +112,18 @@ dev_sio_open(struct dev *d)
|
|||
{
|
||||
struct sio_par par;
|
||||
unsigned int mode = d->mode & (MODE_PLAY | MODE_REC);
|
||||
char *path;
|
||||
|
||||
d->sio.hdl = sio_open(d->path, mode, 1);
|
||||
if (d->sio.hdl == NULL) {
|
||||
path = dev_sio_openlist(d, mode);
|
||||
if (path == NULL) {
|
||||
if (mode != (SIO_PLAY | SIO_REC))
|
||||
return 0;
|
||||
d->sio.hdl = sio_open(d->path, SIO_PLAY, 1);
|
||||
if (d->sio.hdl != NULL)
|
||||
path = dev_sio_openlist(d, SIO_PLAY);
|
||||
if (path != NULL)
|
||||
mode = SIO_PLAY;
|
||||
else {
|
||||
d->sio.hdl = sio_open(d->path, SIO_REC, 1);
|
||||
if (d->sio.hdl != NULL)
|
||||
path = dev_sio_openlist(d, SIO_REC);
|
||||
if (path != NULL)
|
||||
mode = SIO_REC;
|
||||
else
|
||||
return 0;
|
||||
|
@ -144,35 +165,35 @@ dev_sio_open(struct dev *d)
|
|||
*/
|
||||
|
||||
if (par.bits > BITS_MAX) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.bits);
|
||||
log_puts(": unsupported number of bits\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (par.bps > SIO_BPS(BITS_MAX)) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.bps);
|
||||
log_puts(": unsupported sample size\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if ((mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.pchan);
|
||||
log_puts(": unsupported number of play channels\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.rchan);
|
||||
log_puts(": unsupported number of rec channels\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (par.bufsz == 0 || par.bufsz > RATE_MAX) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.bufsz);
|
||||
log_puts(": unsupported buffer size\n");
|
||||
|
@ -180,14 +201,14 @@ dev_sio_open(struct dev *d)
|
|||
}
|
||||
if (par.round == 0 || par.round > par.bufsz ||
|
||||
par.bufsz % par.round != 0) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.round);
|
||||
log_puts(": unsupported block size\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (par.rate == 0 || par.rate > RATE_MAX) {
|
||||
log_puts(d->path);
|
||||
dev_log(d);
|
||||
log_puts(": ");
|
||||
log_putu(par.rate);
|
||||
log_puts(": unsupported rate\n");
|
||||
|
@ -212,8 +233,14 @@ 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, 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);
|
||||
if (log_level >= 1) {
|
||||
dev_log(d);
|
||||
log_puts(": using ");
|
||||
log_puts(path);
|
||||
log_puts("\n");
|
||||
}
|
||||
return 1;
|
||||
bad_close:
|
||||
sio_close(d->sio.hdl);
|
||||
|
@ -494,5 +521,5 @@ dev_sio_hup(void *arg)
|
|||
log_puts(": disconnected\n");
|
||||
}
|
||||
#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 e Ar enc
|
||||
.Op Fl F Ar device
|
||||
.Op Fl f Ar device
|
||||
.Op Fl j Ar flag
|
||||
.Op Fl L Ar addr
|
||||
.Op Fl m Ar mode
|
||||
.Op Fl Q Ar port
|
||||
.Op Fl q Ar port
|
||||
.Op Fl r Ar rate
|
||||
.Op Fl s Ar name
|
||||
|
@ -182,6 +184,18 @@ or
|
|||
Only the signedness and the precision are mandatory.
|
||||
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
|
||||
.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
|
||||
Add this
|
||||
.Xr sndio 7
|
||||
|
@ -245,6 +259,15 @@ but the same sub-device cannot be used for both recording and monitoring.
|
|||
The default is
|
||||
.Ar play , Ns Ar rec
|
||||
(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
|
||||
Expose the given MIDI port.
|
||||
This allows multiple programs to share the port.
|
||||
|
@ -376,11 +399,15 @@ is
|
|||
If
|
||||
.Nm
|
||||
is sent
|
||||
.Dv SIGHUP ,
|
||||
.Dv SIGINT
|
||||
or
|
||||
.Dv SIGTERM ,
|
||||
it terminates.
|
||||
If
|
||||
.Nm
|
||||
is sent
|
||||
.Dv SIGHUP ,
|
||||
it reopens all audio devices and MIDI ports.
|
||||
.Pp
|
||||
By default, when the program cannot accept
|
||||
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
|
||||
*/
|
||||
#ifndef DEFAULT_ROUND
|
||||
#define DEFAULT_ROUND 960
|
||||
#define DEFAULT_ROUND 480
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -86,6 +86,7 @@
|
|||
#endif
|
||||
|
||||
void sigint(int);
|
||||
void sighup(int);
|
||||
void opt_ch(int *, int *);
|
||||
void opt_enc(struct aparams *);
|
||||
int opt_mmc(void);
|
||||
|
@ -102,12 +103,13 @@ struct opt *mkopt(char *, struct dev *,
|
|||
int, int, int, int, int, int, int, int);
|
||||
|
||||
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] "
|
||||
"[-C min:max] [-c min:max] [-e enc]\n\t"
|
||||
"[-f device] [-j flag] [-L addr] [-m mode] [-q port] [-r rate]\n\t"
|
||||
"[-s name] [-t mode] [-U unit] [-v volume] [-w flag] [-z nframes]\n";
|
||||
"[-C min:max] [-c min:max]\n\t"
|
||||
"[-e enc] [-F device] [-f device] [-j flag] [-L addr] [-m mode]\n\t"
|
||||
"[-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,
|
||||
|
@ -122,6 +124,16 @@ sigint(int s)
|
|||
quit_flag = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* SIGHUP handler, it raises the reopen flag, which requests devices
|
||||
* to be reopened.
|
||||
*/
|
||||
void
|
||||
sighup(int s)
|
||||
{
|
||||
reopen_flag = 1;
|
||||
}
|
||||
|
||||
void
|
||||
opt_ch(int *rcmin, int *rcmax)
|
||||
{
|
||||
|
@ -224,6 +236,7 @@ setsig(void)
|
|||
struct sigaction sa;
|
||||
|
||||
quit_flag = 0;
|
||||
reopen_flag = 0;
|
||||
sigfillset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = sigint;
|
||||
|
@ -231,6 +244,7 @@ setsig(void)
|
|||
err(1, "sigaction(int) failed");
|
||||
if (sigaction(SIGTERM, &sa, NULL) == -1)
|
||||
err(1, "sigaction(term) failed");
|
||||
sa.sa_handler = sighup;
|
||||
if (sigaction(SIGHUP, &sa, NULL) == -1)
|
||||
err(1, "sigaction(hup) failed");
|
||||
}
|
||||
|
@ -287,7 +301,8 @@ mkdev(char *path, struct aparams *par,
|
|||
struct dev *d;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!bufsz && !round) {
|
||||
|
@ -309,7 +324,8 @@ mkport(char *path, int hold)
|
|||
struct port *c;
|
||||
|
||||
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;
|
||||
}
|
||||
c = port_new(path, MODE_MIDIMASK, hold);
|
||||
|
@ -375,7 +391,8 @@ main(int argc, char **argv)
|
|||
mode = MODE_PLAY | MODE_REC;
|
||||
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) {
|
||||
case 'd':
|
||||
log_level++;
|
||||
|
@ -432,6 +449,11 @@ main(int argc, char **argv)
|
|||
case 'q':
|
||||
mkport(optarg, hold);
|
||||
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':
|
||||
hold = opt_onoff();
|
||||
break;
|
||||
|
@ -452,6 +474,11 @@ main(int argc, char **argv)
|
|||
mkdev(optarg, &par, 0, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
break;
|
||||
case 'F':
|
||||
if (dev_list == NULL)
|
||||
errx(1, "-F %s: no devices defined", optarg);
|
||||
namelist_add(&dev_list->path_list, optarg);
|
||||
break;
|
||||
default:
|
||||
fputs(usagestr, stderr);
|
||||
return 1;
|
||||
|
@ -519,6 +546,13 @@ main(int argc, char **argv)
|
|||
for (;;) {
|
||||
if (quit_flag)
|
||||
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())
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -188,3 +188,30 @@ xstrdup(char *s)
|
|||
memcpy(p, s, size);
|
||||
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>
|
||||
|
||||
struct name {
|
||||
struct name *next;
|
||||
char str[];
|
||||
};
|
||||
|
||||
void log_puts(char *);
|
||||
void log_putx(unsigned long);
|
||||
void log_putu(unsigned long);
|
||||
|
@ -31,6 +36,9 @@ void *xmalloc(size_t);
|
|||
char *xstrdup(char *);
|
||||
void xfree(void *);
|
||||
|
||||
void namelist_add(struct name **, char *);
|
||||
void namelist_clear(struct name **);
|
||||
|
||||
/*
|
||||
* Log levels:
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue