mirror of https://github.com/ericonr/sndio.git
merge head
This commit is contained in:
parent
7b062cf12f
commit
5dc67b663e
|
@ -14,7 +14,7 @@ LDADD = -lsndio @ldadd@
|
|||
@vars@
|
||||
|
||||
#
|
||||
# binaries, documentation, man pages and examples will be installed in
|
||||
# binaries, documentation, man pages and examples will be installed in
|
||||
# ${BIN_DIR}, ${MAN1_DIR}
|
||||
#
|
||||
BIN_DIR = @bindir@
|
||||
|
@ -45,7 +45,7 @@ clean:
|
|||
OBJS = abuf.o afile.o aucat.o dsp.o utils.o
|
||||
|
||||
aucat: ${OBJS}
|
||||
${CC} ${LDFLAGS} ${LIB} -o aucat ${OBJS} ${LDADD}
|
||||
${CC} ${LDFLAGS} ${LIB} -o aucat ${OBJS} ${LDADD}
|
||||
|
||||
.c.o:
|
||||
${CC} ${CFLAGS} ${INCLUDE} ${DEFS} -c $<
|
||||
|
|
|
@ -53,7 +53,7 @@ abuf_init(struct abuf *buf, unsigned int len)
|
|||
void
|
||||
abuf_done(struct abuf *buf)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
if (buf->used > 0) {
|
||||
if (log_level >= 3) {
|
||||
log_puts("deleting non-empty buffer, used = ");
|
||||
|
|
|
@ -563,7 +563,7 @@ afile_aiff_readhdr(struct afile *f)
|
|||
log_puts(f->path);
|
||||
log_puts(": failed to read chunk header\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
csize = be32_get(&chunk.size);
|
||||
if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
|
||||
if (!afile_aiff_readcomm(f, csize, comp, &nfr))
|
||||
|
@ -572,7 +572,8 @@ afile_aiff_readhdr(struct afile *f)
|
|||
} else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
|
||||
if (!afile_aiff_readdata(f, csize, &offs))
|
||||
return 0;
|
||||
f->startpos = sizeof(form) + pos + sizeof(chunk) + offs;
|
||||
f->startpos = sizeof(form) + pos +
|
||||
sizeof(chunk) + offs;
|
||||
break;
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
|
@ -927,7 +928,8 @@ afile_open(struct afile *f, char *path, int hdr, int flags,
|
|||
f->fd = STDOUT_FILENO;
|
||||
} else {
|
||||
f->path = path;
|
||||
f->fd = open(f->path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
f->fd = open(f->path,
|
||||
O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
if (f->fd < 0) {
|
||||
log_puts(f->path);
|
||||
log_puts(": failed to create file\n");
|
||||
|
@ -956,7 +958,8 @@ afile_open(struct afile *f, char *path, int hdr, int flags,
|
|||
f->par.msb = 1;
|
||||
f->endpos = f->startpos = sizeof(struct aiff_hdr);
|
||||
f->maxpos = 0x7fffffff;
|
||||
if (!afile_writehdr(f, &dummy, sizeof(struct aiff_hdr)))
|
||||
if (!afile_writehdr(f, &dummy,
|
||||
sizeof(struct aiff_hdr)))
|
||||
goto bad_close;
|
||||
} else if (f->hdr == AFILE_HDR_AU) {
|
||||
f->par.bits = (f->par.bits + 7) & ~7;
|
||||
|
|
|
@ -87,7 +87,7 @@ Increase log verbosity.
|
|||
Encoding of the audio file.
|
||||
The default is
|
||||
.Va s16 .
|
||||
Encoding names use the follwing scheme: signedness
|
||||
Encoding names use the following scheme: signedness
|
||||
.Po
|
||||
.Va s
|
||||
or
|
||||
|
@ -223,7 +223,7 @@ back to the starting position.
|
|||
.El
|
||||
.Pp
|
||||
MIDI control is intended to be used together with
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
For instance, the following command will create two devices:
|
||||
the default
|
||||
.Va snd/0
|
||||
|
@ -280,9 +280,9 @@ $ aucat -n -i stereo.wav -c 0:0 -o left.wav \e
|
|||
.Xr audioctl 1 ,
|
||||
.Xr cdio 1 ,
|
||||
.Xr mixerctl 1 ,
|
||||
.Xr sndiod 1 ,
|
||||
.Xr audio 4 ,
|
||||
.Xr sndio 7
|
||||
.Xr sndio 7 ,
|
||||
.Xr sndiod 8
|
||||
.Sh BUGS
|
||||
Resampling is low quality.
|
||||
.Pp
|
||||
|
|
|
@ -308,7 +308,8 @@ slot_init(struct slot *s)
|
|||
s->cmin, s->cmax,
|
||||
0, dev_pchan - 1,
|
||||
0, dev_pchan - 1);
|
||||
if (s->afile.fmt != AFILE_FMT_PCM || !aparams_native(&s->afile.par)) {
|
||||
if (s->afile.fmt != AFILE_FMT_PCM ||
|
||||
!aparams_native(&s->afile.par)) {
|
||||
dec_init(&s->conv, &s->afile.par, slot_nch);
|
||||
s->convbuf =
|
||||
xmalloc(s->round * slot_nch * sizeof(adata_t));
|
||||
|
@ -425,7 +426,7 @@ slot_del(struct slot *s)
|
|||
xfree(s);
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
|
||||
{
|
||||
int i, offs, vol, nch;
|
||||
|
@ -455,7 +456,7 @@ play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
|
|||
return todo;
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
play_filt_dec(struct slot *s, void *in, void *out, int todo)
|
||||
{
|
||||
void *tmp;
|
||||
|
@ -506,7 +507,7 @@ slot_mix_badd(struct slot *s, adata_t *odata)
|
|||
return done;
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
|
||||
{
|
||||
int i, vol, offs, nch;
|
||||
|
@ -535,7 +536,7 @@ rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
|
|||
return todo;
|
||||
}
|
||||
|
||||
static int
|
||||
static int
|
||||
rec_filt_enc(struct slot *s, void *in, void *out, int todo)
|
||||
{
|
||||
void *tmp;
|
||||
|
@ -1032,7 +1033,8 @@ playrec_cycle(void)
|
|||
n = sio_read(dev_sh, p, todo);
|
||||
if (n == 0) {
|
||||
log_puts(dev_name);
|
||||
log_puts(": failed to read from device\n");
|
||||
log_puts(": failed to read "
|
||||
"from device\n");
|
||||
return 0;
|
||||
}
|
||||
p += n;
|
||||
|
@ -1114,7 +1116,7 @@ playrec(char *dev, int mode, int bufsz, char *port)
|
|||
continue;
|
||||
log_puts("poll failed\n");
|
||||
panic();
|
||||
}
|
||||
}
|
||||
if (dev_pstate == DEV_START) {
|
||||
ev = sio_revents(dev_sh, pfds);
|
||||
if (ev & POLLHUP) {
|
||||
|
@ -1276,7 +1278,7 @@ main(int argc, char **argv)
|
|||
port = NULL;
|
||||
dev = NULL;
|
||||
mode = 0;
|
||||
|
||||
|
||||
while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) {
|
||||
switch (c) {
|
||||
case 'b':
|
||||
|
@ -1359,7 +1361,7 @@ main(int argc, char **argv)
|
|||
if (mode == 0) {
|
||||
log_puts("at least -i or -o required\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (!playrec(dev, mode, bufsz, port))
|
||||
return 1;
|
||||
}
|
||||
|
|
12
aucat/dsp.c
12
aucat/dsp.c
|
@ -222,7 +222,7 @@ aparams_strtoenc(struct aparams *par, char *istr)
|
|||
return 0;
|
||||
|
||||
done:
|
||||
par->msb = msb;
|
||||
par->msb = msb;
|
||||
par->sig = sig;
|
||||
par->bits = bits;
|
||||
par->bps = bps;
|
||||
|
@ -366,7 +366,8 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
|
|||
* initialize resampler with ibufsz/obufsz factor and "nch" channels
|
||||
*/
|
||||
void
|
||||
resamp_init(struct resamp *p, unsigned int iblksz, unsigned int oblksz, int nch)
|
||||
resamp_init(struct resamp *p, unsigned int iblksz,
|
||||
unsigned int oblksz, int nch)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -516,7 +517,7 @@ enc_init(struct conv *p, struct aparams *par, int nch)
|
|||
p->bias = (1U << 31) >> p->shift;
|
||||
} else {
|
||||
p->bias = 0;
|
||||
}
|
||||
}
|
||||
if (!par->le) {
|
||||
p->bfirst = par->bps - 1;
|
||||
p->bnext = -1;
|
||||
|
@ -673,7 +674,8 @@ dec_do_float(struct conv *p, unsigned char *in, unsigned char *out, int todo)
|
|||
* convert samples from ulaw/alaw to adata_t
|
||||
*/
|
||||
void
|
||||
dec_do_ulaw(struct conv *p, unsigned char *in, unsigned char *out, int todo, int is_alaw)
|
||||
dec_do_ulaw(struct conv *p, unsigned char *in,
|
||||
unsigned char *out, int todo, int is_alaw)
|
||||
{
|
||||
unsigned int f;
|
||||
unsigned char *idata;
|
||||
|
@ -711,7 +713,7 @@ dec_init(struct conv *p, struct aparams *par, int nch)
|
|||
p->bias = (1U << 31) >> p->shift;
|
||||
} else {
|
||||
p->bias = 0;
|
||||
}
|
||||
}
|
||||
if (par->le) {
|
||||
p->bfirst = par->bps - 1;
|
||||
p->bnext = -1;
|
||||
|
|
|
@ -91,7 +91,7 @@ log_putx(unsigned long num)
|
|||
c += (c < 10) ? '0' : 'a' - 10;
|
||||
LOG_PUTC(c);
|
||||
}
|
||||
} else
|
||||
} else
|
||||
LOG_PUTC('0');
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,14 @@ case `uname` in
|
|||
so="$so libsndio.so"
|
||||
defs='-D_GNU_SOURCE -DDEV_RANDOM=\\"/dev/urandom\\"'
|
||||
;;
|
||||
NetBSD)
|
||||
sun=no
|
||||
rmidi=yes
|
||||
user=_sndio
|
||||
so="$so libsndio.so"
|
||||
defs='-DHAVE_ARC4RANDOM -DHAVE_ISSETUGID \\\
|
||||
-DHAVE_STRLCAT -DHAVE_STRLCPY'
|
||||
;;
|
||||
OpenBSD)
|
||||
sun=yes
|
||||
rmidi=yes
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
/*
|
||||
* unix-domain socket name is:
|
||||
*
|
||||
* DIR [ '-' UID ] '/' FILE UNIT
|
||||
|
|
|
@ -468,15 +468,24 @@ parsestr(const char *str, char *rstr, unsigned int max)
|
|||
}
|
||||
|
||||
int
|
||||
_aucat_open(struct aucat *hdl, const char *str, unsigned int mode,
|
||||
unsigned int type)
|
||||
_aucat_open(struct aucat *hdl, const char *str, unsigned int mode)
|
||||
{
|
||||
extern char *__progname;
|
||||
int eof;
|
||||
char host[NI_MAXHOST], opt[AMSG_OPTMAX];
|
||||
const char *p = str;
|
||||
unsigned int unit, devnum;
|
||||
const char *p;
|
||||
unsigned int unit, devnum, type;
|
||||
|
||||
if ((p = _sndio_parsetype(str, "snd")) != NULL)
|
||||
type = 0;
|
||||
else if ((p = _sndio_parsetype(str, "midithru")) != NULL)
|
||||
type = 1;
|
||||
else if ((p = _sndio_parsetype(str, "midi")) != NULL)
|
||||
type = 2;
|
||||
else {
|
||||
DPRINTF("%s: unsupported device type\n", str);
|
||||
return -1;
|
||||
}
|
||||
if (*p == '@') {
|
||||
p = parsestr(++p, host, NI_MAXHOST);
|
||||
if (p == NULL)
|
||||
|
@ -489,7 +498,7 @@ _aucat_open(struct aucat *hdl, const char *str, unsigned int mode,
|
|||
return 0;
|
||||
} else
|
||||
unit = 0;
|
||||
if (*p != '/' && *p != ':') {
|
||||
if (*p != '/') {
|
||||
DPRINTF("%s: '/' expected\n", str);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ int _aucat_rmsg(struct aucat *, int *);
|
|||
int _aucat_wmsg(struct aucat *, int *);
|
||||
size_t _aucat_rdata(struct aucat *, void *, size_t, int *);
|
||||
size_t _aucat_wdata(struct aucat *, const void *, size_t, unsigned, int *);
|
||||
int _aucat_open(struct aucat *, const char *, unsigned, unsigned);
|
||||
int _aucat_open(struct aucat *, const char *, unsigned);
|
||||
void _aucat_close(struct aucat *, int);
|
||||
int _aucat_pollfd(struct aucat *, struct pollfd *, int);
|
||||
int _aucat_revents(struct aucat *, struct pollfd *);
|
||||
|
|
|
@ -36,7 +36,6 @@ mio_open(const char *str, unsigned int mode, int nbio)
|
|||
{
|
||||
static char portany[] = MIO_PORTANY;
|
||||
struct mio_hdl *hdl;
|
||||
const char *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
_sndio_debug_init();
|
||||
|
@ -51,32 +50,28 @@ mio_open(const char *str, unsigned int mode, int nbio)
|
|||
str = portany;
|
||||
}
|
||||
if (strcmp(str, portany) == 0) {
|
||||
hdl = _mio_aucat_open("/0", mode, nbio, 1);
|
||||
hdl = _mio_aucat_open("midithru/0", mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
#if defined(USE_RMIDI)
|
||||
return _mio_rmidi_open("/0", mode, nbio);
|
||||
return _mio_rmidi_open("rmidi/0", mode, nbio);
|
||||
#elif defined(USE_ALSA)
|
||||
return mio_alsa_open("/0", mode, nbio);
|
||||
return _mio_alsa_open("rmidi/0", mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if ((p = _sndio_parsetype(str, "snd")) != NULL ||
|
||||
(p = _sndio_parsetype(str, "aucat")) != NULL)
|
||||
return _mio_aucat_open(p, mode, nbio, 0);
|
||||
if ((p = _sndio_parsetype(str, "midithru")) != NULL)
|
||||
return _mio_aucat_open(p, mode, nbio, 1);
|
||||
if ((p = _sndio_parsetype(str, "midi")) != NULL)
|
||||
return _mio_aucat_open(p, mode, nbio, 2);
|
||||
#if defined(USE_RMIDI) || defined(USE_ALSA)
|
||||
if ((p = _sndio_parsetype(str, "rmidi")) != NULL) {
|
||||
#if defined(USE_SUN)
|
||||
return _mio_rmidi_open(p, mode, nbio);
|
||||
if (_sndio_parsetype(str, "snd") ||
|
||||
_sndio_parsetype(str, "midithru") ||
|
||||
_sndio_parsetype(str, "midi"))
|
||||
return _mio_aucat_open(str, mode, nbio);
|
||||
if (_sndio_parsetype(str, "rmidi"))
|
||||
#if defined(USE_RMIDI)
|
||||
return _mio_rmidi_open(str, mode, nbio);
|
||||
#elif defined(USE_ALSA)
|
||||
return mio_alsa_open(p, mode, nbio);
|
||||
#endif
|
||||
}
|
||||
return _mio_alsa_open(str, mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
DPRINTF("mio_open: %s: unknown device type\n", str);
|
||||
return NULL;
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
#ifdef DEBUG
|
||||
static snd_output_t *output = NULL;
|
||||
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
|
||||
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
|
||||
#else
|
||||
#define DALSA(str, err) do {} while (0)
|
||||
#endif
|
||||
|
@ -64,18 +64,24 @@ static struct mio_ops mio_alsa_ops = {
|
|||
};
|
||||
|
||||
struct mio_hdl *
|
||||
mio_alsa_open(const char *str, unsigned int mode, int nbio)
|
||||
_mio_alsa_open(const char *_str, unsigned int mode, int nbio)
|
||||
{
|
||||
const char *p;
|
||||
struct mio_alsa_hdl *hdl;
|
||||
size_t len;
|
||||
int rc;
|
||||
|
||||
switch (*str) {
|
||||
p = _sndio_parsetype(_str, "rmidi");
|
||||
if (p == NULL) {
|
||||
DPRINTF("_mio_alsa_open: %s: \"rsnd\" expected\n", _str);
|
||||
return NULL;
|
||||
}
|
||||
switch (*p) {
|
||||
case '/':
|
||||
str++;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("mio_alsa_open: %s: '/<devnum>' expected\n", str);
|
||||
DPRINTF("_mio_alsa_open: %s: '/' expected\n", _str);
|
||||
return NULL;
|
||||
}
|
||||
hdl = malloc(sizeof(struct mio_alsa_hdl));
|
||||
|
@ -87,14 +93,14 @@ mio_alsa_open(const char *str, unsigned int mode, int nbio)
|
|||
if (rc < 0)
|
||||
DALSA("couldn't attach to stderr", rc);
|
||||
#endif
|
||||
len = strlen(str);
|
||||
len = strlen(p);
|
||||
hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
|
||||
if (hdl->devname == NULL) {
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1);
|
||||
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, str, len + 1);
|
||||
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, p, len + 1);
|
||||
hdl->in = hdl->out = NULL;
|
||||
rc = snd_rawmidi_open(&hdl->in, &hdl->out,
|
||||
hdl->devname, SND_RAWMIDI_NONBLOCK);
|
||||
|
|
|
@ -75,7 +75,8 @@ mio_aucat_runmsg(struct mio_aucat_hdl *hdl)
|
|||
delta, hdl->aucat.maxwrite);
|
||||
break;
|
||||
default:
|
||||
DPRINTF("mio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd);
|
||||
DPRINTF("mio_aucat_runmsg: unhandled message %u\n",
|
||||
hdl->aucat.rmsg.cmd);
|
||||
hdl->mio.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -85,15 +86,14 @@ mio_aucat_runmsg(struct mio_aucat_hdl *hdl)
|
|||
}
|
||||
|
||||
struct mio_hdl *
|
||||
_mio_aucat_open(const char *str, unsigned int mode,
|
||||
int nbio, unsigned int type)
|
||||
_mio_aucat_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct mio_aucat_hdl *hdl;
|
||||
|
||||
hdl = malloc(sizeof(struct mio_aucat_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
if (!_aucat_open(&hdl->aucat, str, mode, type))
|
||||
if (!_aucat_open(&hdl->aucat, str, mode))
|
||||
goto bad;
|
||||
_mio_create(&hdl->mio, &mio_aucat_ops, mode, nbio);
|
||||
if (!_aucat_setfl(&hdl->aucat, 1, &hdl->mio.eof))
|
||||
|
|
|
@ -51,7 +51,7 @@ The
|
|||
library allows user processes to access
|
||||
.Xr midi 4
|
||||
hardware and
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
MIDI thru boxes and control ports in a uniform way.
|
||||
.Ss Opening and closing an MIDI stream
|
||||
First the application must call the
|
||||
|
@ -243,7 +243,7 @@ The debug level:
|
|||
may be a value between 0 and 2.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr sndiod 1 ,
|
||||
.Xr poll 2 ,
|
||||
.Xr midi 4 ,
|
||||
.Xr sndio 7
|
||||
.Xr sndio 7 ,
|
||||
.Xr sndiod 8
|
||||
|
|
|
@ -45,9 +45,9 @@ struct mio_ops {
|
|||
|
||||
struct mio_hdl *_mio_rmidi_open(const char *, unsigned, int);
|
||||
#ifdef USE_ALSA
|
||||
struct mio_hdl *mio_alsa_open(const char *, unsigned, int);
|
||||
struct mio_hdl *_mio_alsa_open(const char *, unsigned, int);
|
||||
#endif
|
||||
struct mio_hdl *_mio_aucat_open(const char *, unsigned, int, unsigned);
|
||||
struct mio_hdl *_mio_aucat_open(const char *, unsigned, int);
|
||||
void _mio_create(struct mio_hdl *, struct mio_ops *, unsigned, int);
|
||||
void _mio_destroy(struct mio_hdl *);
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifdef USE_RMIDI
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
@ -56,33 +57,34 @@ static struct mio_ops mio_rmidi_ops = {
|
|||
mio_rmidi_revents
|
||||
};
|
||||
|
||||
struct mio_hdl *
|
||||
_mio_rmidi_open(const char *str, unsigned int mode, int nbio)
|
||||
static int
|
||||
mio_rmidi_getfd(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
int fd, flags;
|
||||
struct mio_rmidi_hdl *hdl;
|
||||
const char *p;
|
||||
char path[DEVPATH_MAX];
|
||||
unsigned int devnum;
|
||||
int fd, flags;
|
||||
|
||||
switch (*str) {
|
||||
p = _sndio_parsetype(str, "rmidi");
|
||||
if (p == NULL) {
|
||||
DPRINTF("mio_rmidi_getfd: %s: \"rsnd\" expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
switch (*p) {
|
||||
case '/':
|
||||
str++;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("_mio_rmidi_open: %s: '/<devnum>' expected\n", str);
|
||||
return NULL;
|
||||
DPRINTF("mio_rmidi_getfd: %s: '/' expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
str = _sndio_parsenum(str, &devnum, 255);
|
||||
if (str == NULL || *str != '\0') {
|
||||
DPRINTF("_mio_rmidi_open: can't determine device number\n");
|
||||
return NULL;
|
||||
p = _sndio_parsenum(p, &devnum, 255);
|
||||
if (p == NULL || *p != '\0') {
|
||||
DPRINTF("mio_rmidi_getfd: %s: number expected after '/'\n", str);
|
||||
return -1;
|
||||
}
|
||||
hdl = malloc(sizeof(struct mio_rmidi_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
|
||||
snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
|
||||
if (mode == (MIO_OUT | MIO_IN))
|
||||
if (mode == (MIO_IN | MIO_OUT))
|
||||
flags = O_RDWR;
|
||||
else
|
||||
flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
|
||||
|
@ -90,12 +92,38 @@ _mio_rmidi_open(const char *str, unsigned int mode, int nbio)
|
|||
if (errno == EINTR)
|
||||
continue;
|
||||
DPERROR(path);
|
||||
goto bad_free;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct mio_hdl *
|
||||
mio_rmidi_fdopen(int fd, unsigned int mode, int nbio)
|
||||
{
|
||||
struct mio_rmidi_hdl *hdl;
|
||||
|
||||
hdl = malloc(sizeof(struct mio_rmidi_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_mio_create(&hdl->mio, &mio_rmidi_ops, mode, nbio);
|
||||
hdl->fd = fd;
|
||||
return (struct mio_hdl *)hdl;
|
||||
bad_free:
|
||||
free(hdl);
|
||||
}
|
||||
|
||||
struct mio_hdl *
|
||||
_mio_rmidi_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct mio_hdl *hdl;
|
||||
int fd;
|
||||
|
||||
fd = mio_rmidi_getfd(str, mode, nbio);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
hdl = mio_rmidi_fdopen(fd, mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
while (close(fd) < 0 && errno == EINTR)
|
||||
; /* retry */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -147,7 +175,7 @@ mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
|
|||
DPERROR("mio_rmidi_write: write");
|
||||
hdl->mio.eof = 1;
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
@ -173,3 +201,4 @@ mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
|
|||
{
|
||||
return pfd->revents;
|
||||
}
|
||||
#endif /* defined USE_RMIDI */
|
||||
|
|
|
@ -45,7 +45,6 @@ sio_open(const char *str, unsigned int mode, int nbio)
|
|||
{
|
||||
static char devany[] = SIO_DEVANY;
|
||||
struct sio_hdl *hdl;
|
||||
const char *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
_sndio_debug_init();
|
||||
|
@ -60,29 +59,26 @@ sio_open(const char *str, unsigned int mode, int nbio)
|
|||
str = devany;
|
||||
}
|
||||
if (strcmp(str, devany) == 0) {
|
||||
hdl = _sio_aucat_open("/0", mode, nbio);
|
||||
hdl = _sio_aucat_open("snd/0", mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
#if defined(USE_SUN)
|
||||
return _sio_sun_open("/0", mode, nbio);
|
||||
return _sio_sun_open("rsnd/0", mode, nbio);
|
||||
#elif defined(USE_ALSA)
|
||||
return _sio_alsa_open("/0", mode, nbio);
|
||||
return _sio_alsa_open("rsnd/0", mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if ((p = _sndio_parsetype(str, "snd")) != NULL ||
|
||||
(p = _sndio_parsetype(str, "aucat")) != NULL)
|
||||
return _sio_aucat_open(p, mode, nbio);
|
||||
#if defined(USE_ALSA) || defined(USE_SUN)
|
||||
if ((p = _sndio_parsetype(str, "rsnd")) != NULL ||
|
||||
(p = _sndio_parsetype(str, "sun")) != NULL) {
|
||||
if (_sndio_parsetype(str, "snd"))
|
||||
return _sio_aucat_open(str, mode, nbio);
|
||||
if (_sndio_parsetype(str, "rsnd"))
|
||||
#if defined(USE_SUN)
|
||||
return _sio_sun_open(p, mode, nbio);
|
||||
return _sio_sun_open(str, mode, nbio);
|
||||
#elif defined(USE_ALSA)
|
||||
return _sio_alsa_open(p, mode, nbio);
|
||||
#endif
|
||||
}
|
||||
return _sio_alsa_open(str, mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
DPRINTF("sio_open: %s: unknown device type\n", str);
|
||||
return NULL;
|
||||
|
@ -169,7 +165,7 @@ sio_setpar(struct sio_hdl *hdl, struct sio_par *par)
|
|||
return 0;
|
||||
}
|
||||
if (par->__magic != SIO_PAR_MAGIC) {
|
||||
DPRINTF("sio_setpar: use of uninitialized sio_par structure\n");
|
||||
DPRINTF("sio_setpar: uninitialized sio_par structure\n");
|
||||
hdl->eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -452,7 +448,7 @@ sio_onmove(struct sio_hdl *hdl, void (*cb)(void *, int), void *addr)
|
|||
#ifdef DEBUG
|
||||
void
|
||||
_sio_printpos(struct sio_hdl *hdl)
|
||||
{
|
||||
{
|
||||
struct timespec ts;
|
||||
long long rpos, rdiff;
|
||||
long long cpos, cdiff;
|
||||
|
@ -465,7 +461,7 @@ _sio_printpos(struct sio_hdl *hdl)
|
|||
rround = hdl->par.round * rbpf;
|
||||
wround = hdl->par.round * wbpf;
|
||||
|
||||
rpos = (hdl->mode & SIO_REC) ?
|
||||
rpos = (hdl->mode & SIO_REC) ?
|
||||
hdl->cpos * rbpf - hdl->rused : 0;
|
||||
wpos = (hdl->mode & SIO_PLAY) ?
|
||||
hdl->cpos * wbpf + hdl->wused : 0;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#ifdef DEBUG
|
||||
static snd_output_t *output = NULL;
|
||||
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
|
||||
#define DALSA(str, err) fprintf(stderr, "%s: %s\n", str, snd_strerror(err))
|
||||
#else
|
||||
#define DALSA(str, err) do {} while (0)
|
||||
#endif
|
||||
|
@ -103,9 +103,9 @@ static unsigned int cap_rates[] = {
|
|||
};
|
||||
static snd_pcm_format_t cap_fmts[] = {
|
||||
/* XXX add s24le3 and s24be3 */
|
||||
SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_U8
|
||||
};
|
||||
|
||||
|
@ -275,17 +275,23 @@ sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, snd_pcm_format_t *rfmt,
|
|||
struct sio_hdl *
|
||||
_sio_alsa_open(const char *str, unsigned mode, int nbio)
|
||||
{
|
||||
const char *p;
|
||||
struct sio_alsa_hdl *hdl;
|
||||
struct sio_par par;
|
||||
size_t len;
|
||||
int err;
|
||||
|
||||
switch (*str) {
|
||||
p = _sndio_parsetype(str, "rsnd");
|
||||
if (p == NULL) {
|
||||
DPRINTF("_sio_alsa_open: %s: \"rsnd\" expected\n", str);
|
||||
return NULL;
|
||||
}
|
||||
switch (*p) {
|
||||
case '/':
|
||||
str++;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("_sio_alsa_open: %s: '/<devnum>' expected\n", str);
|
||||
DPRINTF("_sio_alsa_open: %s: '/' expected\n", str);
|
||||
return NULL;
|
||||
}
|
||||
hdl = malloc(sizeof(struct sio_alsa_hdl));
|
||||
|
@ -298,12 +304,12 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
|
|||
if (err < 0)
|
||||
DALSA("couldn't attach to stderr", err);
|
||||
#endif
|
||||
len = strlen(str);
|
||||
len = strlen(p);
|
||||
hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
|
||||
if (hdl->devname == NULL)
|
||||
goto bad_free_hdl;
|
||||
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1);
|
||||
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, str, len + 1);
|
||||
memcpy(hdl->devname + sizeof(DEVNAME_PREFIX) - 1, p, len + 1);
|
||||
if (mode & SIO_PLAY) {
|
||||
err = snd_pcm_open(&hdl->opcm, hdl->devname,
|
||||
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||
|
@ -492,11 +498,11 @@ sio_alsa_xrun(struct sio_alsa_hdl *hdl)
|
|||
*
|
||||
* to understand the formula, draw a picture :)
|
||||
*/
|
||||
rbpf = (hdl->sio.mode & SIO_REC) ?
|
||||
rbpf = (hdl->sio.mode & SIO_REC) ?
|
||||
hdl->sio.par.bps * hdl->sio.par.rchan : 1;
|
||||
wbpf = (hdl->sio.mode & SIO_PLAY) ?
|
||||
hdl->sio.par.bps * hdl->sio.par.pchan : 1;
|
||||
rround = hdl->sio.par.round * rbpf;
|
||||
rround = hdl->sio.par.round * rbpf;
|
||||
|
||||
clk = hdl->sio.cpos % hdl->sio.par.round;
|
||||
rdrop = (clk * rbpf - hdl->sio.rused) % rround;
|
||||
|
@ -531,12 +537,12 @@ sio_alsa_setpar_hw(snd_pcm_t *pcm, snd_pcm_hw_params_t *hwp,
|
|||
snd_pcm_uframes_t *round, unsigned int *periods)
|
||||
{
|
||||
static snd_pcm_format_t fmts[] = {
|
||||
SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE,
|
||||
SND_PCM_FORMAT_U32_LE, SND_PCM_FORMAT_U32_BE,
|
||||
SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE,
|
||||
SND_PCM_FORMAT_U24_LE, SND_PCM_FORMAT_U24_BE,
|
||||
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE,
|
||||
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
|
||||
SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE,
|
||||
SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S8
|
||||
};
|
||||
int i, err, dir = 0;
|
||||
|
@ -693,7 +699,7 @@ sio_alsa_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
|||
sio_alsa_fmttopar(hdl, cap_fmts[i],
|
||||
&cap->enc[i].bits,
|
||||
&cap->enc[i].sig,
|
||||
&cap->enc[i].le);
|
||||
&cap->enc[i].le);
|
||||
cap->enc[i].bps = SIO_BPS(cap->enc[0].bits);
|
||||
cap->enc[i].msb = 1;
|
||||
}
|
||||
|
@ -790,7 +796,7 @@ sio_alsa_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||
ofmt, orate, (unsigned int)oround, operiods);
|
||||
DPRINTFN(2, "ifmt = %u, irate = %u, iround = %u, iperiods = %u\n",
|
||||
ifmt, irate, (unsigned int)iround, iperiods);
|
||||
|
||||
|
||||
if (ifmt != ofmt) {
|
||||
DPRINTF("play and rec formats differ\n");
|
||||
hdl->sio.eof = 1;
|
||||
|
@ -1116,7 +1122,7 @@ sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
|||
|
||||
if (hdl->sio.eof)
|
||||
return POLLHUP;
|
||||
|
||||
|
||||
for (i = 0; i < hdl->onfds + hdl->infds; i++) {
|
||||
DPRINTFN(4, "sio_alsa_revents: pfds[%d].revents = %x\n",
|
||||
i, pfd[i].revents);
|
||||
|
|
|
@ -125,7 +125,8 @@ sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
|
|||
hdl->pstate = PSTATE_INIT;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("sio_aucat_runmsg: unhandled message %u\n", hdl->aucat.rmsg.cmd);
|
||||
DPRINTF("sio_aucat_runmsg: unhandled message %u\n",
|
||||
hdl->aucat.rmsg.cmd);
|
||||
hdl->sio.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -156,7 +157,7 @@ _sio_aucat_open(const char *str, unsigned int mode, int nbio)
|
|||
hdl = malloc(sizeof(struct sio_aucat_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
if (!_aucat_open(&hdl->aucat, str, mode, 0)) {
|
||||
if (!_aucat_open(&hdl->aucat, str, mode)) {
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ The
|
|||
library allows user processes to access
|
||||
.Xr audio 4
|
||||
hardware and the
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
audio server in a uniform way.
|
||||
.Ss Opening and closing an audio device
|
||||
First the application must call the
|
||||
|
@ -255,7 +255,7 @@ has been called,
|
|||
must be called before parameters can be changed.
|
||||
.Pp
|
||||
If the device is exposed by the
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
server, which is the default configuration,
|
||||
a transparent emulation layer will
|
||||
automatically be set up, and in this case any combination of
|
||||
|
@ -709,9 +709,9 @@ The debug level:
|
|||
may be a value between 0 and 2.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr sndiod 1 ,
|
||||
.Xr audio 4 ,
|
||||
.Xr sndio 7 ,
|
||||
.Xr sndiod 8 ,
|
||||
.Xr audio 9
|
||||
.Sh BUGS
|
||||
The
|
||||
|
@ -727,7 +727,7 @@ function will stop playback immediately.
|
|||
If the application doesn't consume recorded data fast enough then
|
||||
.Dq "control messages"
|
||||
from the
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
server are delayed and consequently
|
||||
.Fn sio_onmove
|
||||
callback or volume changes may be delayed.
|
||||
|
|
|
@ -330,46 +330,57 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
|
|||
#undef NRATES
|
||||
}
|
||||
|
||||
struct sio_hdl *
|
||||
_sio_sun_open(const char *str, unsigned int mode, int nbio)
|
||||
static int
|
||||
sio_sun_getfd(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
int fd, flags, fullduplex;
|
||||
struct audio_info aui;
|
||||
struct sio_sun_hdl *hdl;
|
||||
struct sio_par par;
|
||||
const char *p;
|
||||
char path[DEVPATH_MAX];
|
||||
unsigned int devnum;
|
||||
int fd, flags;
|
||||
|
||||
switch (*str) {
|
||||
p = _sndio_parsetype(str, "rsnd");
|
||||
if (p == NULL) {
|
||||
DPRINTF("sio_sun_getfd: %s: \"rsnd\" expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
switch (*p) {
|
||||
case '/':
|
||||
str++;
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str);
|
||||
return NULL;
|
||||
DPRINTF("sio_sun_getfd: %s: '/' expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
str = _sndio_parsenum(str, &devnum, 255);
|
||||
if (str == NULL || *str != '\0') {
|
||||
DPRINTF("_sio_sun_open: can't determine device number\n");
|
||||
return NULL;
|
||||
p = _sndio_parsenum(p, &devnum, 255);
|
||||
if (p == NULL || *p != '\0') {
|
||||
DPRINTF("sio_sun_getfd: %s: number expected after '/'\n", str);
|
||||
return -1;
|
||||
}
|
||||
hdl = malloc(sizeof(struct sio_sun_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_sio_create(&hdl->sio, &sio_sun_ops, mode, nbio);
|
||||
|
||||
snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
|
||||
if (mode == (SIO_PLAY | SIO_REC))
|
||||
flags = O_RDWR;
|
||||
else
|
||||
flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY;
|
||||
|
||||
while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
DPERROR(path);
|
||||
goto bad_free;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct sio_hdl *
|
||||
sio_sun_fdopen(int fd, unsigned int mode, int nbio)
|
||||
{
|
||||
struct audio_info aui;
|
||||
struct sio_sun_hdl *hdl;
|
||||
struct sio_par par;
|
||||
|
||||
hdl = malloc(sizeof(struct sio_sun_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_sio_create(&hdl->sio, &sio_sun_ops, mode, nbio);
|
||||
|
||||
/*
|
||||
* pause the device
|
||||
|
@ -381,18 +392,7 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
|
|||
aui.record.pause = 1;
|
||||
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) {
|
||||
DPERROR("sio_open_sun: setinfo");
|
||||
goto bad_close;
|
||||
}
|
||||
/*
|
||||
* If both play and record are requested then
|
||||
* set full duplex mode.
|
||||
*/
|
||||
if (mode == (SIO_PLAY | SIO_REC)) {
|
||||
fullduplex = 1;
|
||||
if (ioctl(fd, AUDIO_SETFD, &fullduplex) < 0) {
|
||||
DPRINTF("sio_open_sun: %s: can't set full-duplex\n", path);
|
||||
goto bad_close;
|
||||
}
|
||||
goto bad_free;
|
||||
}
|
||||
hdl->fd = fd;
|
||||
|
||||
|
@ -410,16 +410,30 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
|
|||
par.bits = 16;
|
||||
par.appbufsz = 1200;
|
||||
if (!sio_setpar(&hdl->sio, &par))
|
||||
goto bad_close;
|
||||
goto bad_free;
|
||||
return (struct sio_hdl *)hdl;
|
||||
bad_close:
|
||||
while (close(fd) < 0 && errno == EINTR)
|
||||
; /* retry */
|
||||
bad_free:
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sio_hdl *
|
||||
_sio_sun_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct sio_hdl *hdl;
|
||||
int fd;
|
||||
|
||||
fd = sio_sun_getfd(str, mode, nbio);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
hdl = sio_sun_fdopen(fd, mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
while (close(fd) < 0 && errno == EINTR)
|
||||
; /* retry */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
sio_sun_close(struct sio_hdl *sh)
|
||||
{
|
||||
|
@ -546,7 +560,8 @@ sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||
}
|
||||
DPRINTFN(2, "sio_sun_setpar: %i: trying pars = %u/%u/%u\n",
|
||||
i, rate, prec, enc);
|
||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 && errno != EINVAL) {
|
||||
if (ioctl(hdl->fd, AUDIO_SETINFO, &aui) < 0 &&
|
||||
errno != EINVAL) {
|
||||
DPERROR("sio_sun_setpar: setinfo(pars)");
|
||||
hdl->sio.eof = 1;
|
||||
return 0;
|
||||
|
@ -567,7 +582,7 @@ sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||
case AUDIO_ENCODING_ULINEAR:
|
||||
break;
|
||||
default:
|
||||
DPRINTF("sio_sun_setpar: couldn't set linear encoding\n");
|
||||
DPRINTF("sio_sun_setpar: couldn't find encoding\n");
|
||||
hdl->sio.eof = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -658,7 +673,7 @@ sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
|
|||
}
|
||||
infr = aui.record.block_size / ibpf;
|
||||
onfr = aui.play.block_size / obpf;
|
||||
DPRINTFN(2, "sio_sun_setpar: %i: trying round = %u -> (%u, %u)\n",
|
||||
DPRINTFN(2, "sio_sun_setpar: %i: round = %u -> (%u, %u)\n",
|
||||
i, round, infr, onfr);
|
||||
|
||||
/*
|
||||
|
@ -788,7 +803,7 @@ sio_sun_write(struct sio_hdl *sh, const void *buf, size_t len)
|
|||
DPERROR("sio_sun_write: write");
|
||||
hdl->sio.eof = 1;
|
||||
}
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
if (hdl->filling) {
|
||||
if (!sio_sun_autostart(hdl))
|
||||
|
@ -833,7 +848,7 @@ sio_sun_revents(struct sio_hdl *sh, struct pollfd *pfd)
|
|||
doerr = (ap.play_xrun - hdl->oerr) / hdl->obpf;
|
||||
hdl->obytes = ap.play_pos;
|
||||
hdl->oerr = ap.play_xrun;
|
||||
hdl->odelta += delta;
|
||||
hdl->odelta += delta;
|
||||
if (!(hdl->sio.mode & SIO_REC)) {
|
||||
hdl->idelta += delta;
|
||||
dierr = doerr;
|
||||
|
|
|
@ -36,7 +36,6 @@ siomix_open(const char *str, unsigned int mode, int nbio)
|
|||
{
|
||||
static char devany[] = SIOMIX_DEVANY;
|
||||
struct siomix_hdl *hdl;
|
||||
const char *p;
|
||||
|
||||
#ifdef DEBUG
|
||||
_sndio_debug_init();
|
||||
|
@ -49,27 +48,26 @@ siomix_open(const char *str, unsigned int mode, int nbio)
|
|||
str = devany;
|
||||
}
|
||||
if (strcmp(str, devany) == 0) {
|
||||
hdl = _siomix_aucat_open("/0", mode, nbio);
|
||||
hdl = _siomix_aucat_open("snd/0", mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
#if defined(USE_SUN_MIXER)
|
||||
return _siomix_sun_open("/0", mode, nbio);
|
||||
return _siomix_sun_open("rsnd/0", mode, nbio);
|
||||
#elif defined(USE_ALSA_MIXER)
|
||||
return _siomix_alsa_open("/0", mode, nbio);
|
||||
return _siomix_alsa_open("rsnd/0", mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
if ((p = _sndio_parsetype(str, "snd")) != NULL)
|
||||
return _siomix_aucat_open(p, mode, nbio);
|
||||
#if defined(USE_ALSA_MIXER) || defined(USE_SUN_MIXER)
|
||||
if ((p = _sndio_parsetype(str, "rsnd")) != NULL) {
|
||||
if (_sndio_parsetype(str, "snd"))
|
||||
return _siomix_aucat_open(str, mode, nbio);
|
||||
if (_sndio_parsetype(str, "rsnd"))
|
||||
#if defined(USE_SUN_MIXER)
|
||||
return _siomix_sun_open(p, mode, nbio);
|
||||
return _siomix_sun_open(str, mode, nbio);
|
||||
#elif defined(USE_ALSA_MIXER)
|
||||
return _siomix_alsa_open(p, mode, nbio);
|
||||
#endif
|
||||
}
|
||||
return _siomix_alsa_open(str, mode, nbio);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
DPRINTF("siomix_open: %s: unknown device type\n", str);
|
||||
return NULL;
|
||||
|
|
|
@ -143,7 +143,7 @@ _siomix_aucat_open(const char *str, unsigned int mode, int nbio)
|
|||
hdl = malloc(sizeof(struct siomix_aucat_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
if (!_aucat_open(&hdl->aucat, str, mode, 0)) {
|
||||
if (!_aucat_open(&hdl->aucat, str, mode)) {
|
||||
free(hdl);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -32,8 +32,15 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "siomix_priv.h"
|
||||
#include "bsd-compat.h"
|
||||
|
||||
#define DEVPATH_PREFIX "/dev/mixer"
|
||||
#define DEVPATH_MAX (1 + \
|
||||
sizeof(DEVPATH_PREFIX) - 1 + \
|
||||
sizeof(int) * 3)
|
||||
|
||||
#define SUN_TO_SIOMIX(v) (((v) * 127 + 127) / 255)
|
||||
#define SIOMIX_TO_SUN(v) (((v) * 255 + 63) / 127)
|
||||
|
@ -261,38 +268,77 @@ scanvol(struct siomix_sun_hdl *hdl, struct wskbd_vol *vol)
|
|||
return 1;
|
||||
}
|
||||
|
||||
struct siomix_hdl *
|
||||
_siomix_sun_open(const char *str, unsigned int mode, int nbio)
|
||||
static int
|
||||
siomix_sun_getfd(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl;
|
||||
char path[PATH_MAX];
|
||||
int flags;
|
||||
const char *p;
|
||||
char path[DEVPATH_MAX];
|
||||
unsigned int devnum;
|
||||
int fd, flags;
|
||||
|
||||
if (*str != '/') {
|
||||
DPRINTF("siomix_sun_open: %s: '/<devnum>' expected\n", str);
|
||||
return NULL;
|
||||
p = _sndio_parsetype(str, "rsnd");
|
||||
if (p == NULL) {
|
||||
DPRINTF("siomix_sun_getfd: %s: \"rsnd\" expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
str++;
|
||||
hdl = malloc(sizeof(struct siomix_sun_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_siomix_create(&hdl->siomix, &siomix_sun_ops, mode, nbio);
|
||||
snprintf(path, sizeof(path), "/dev/mixer%s", str);
|
||||
switch (*p) {
|
||||
case '/':
|
||||
p++;
|
||||
break;
|
||||
default:
|
||||
DPRINTF("siomix_sun_getfd: %s: '/' expected\n", str);
|
||||
return -1;
|
||||
}
|
||||
p = _sndio_parsenum(p, &devnum, 255);
|
||||
if (p == NULL || *p != '\0') {
|
||||
DPRINTF("siomix_sun_getfd: %s: number expected after '/'\n", str);
|
||||
return -1;
|
||||
}
|
||||
snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
|
||||
if (mode == (SIOMIX_READ | SIOMIX_WRITE))
|
||||
flags = O_RDWR;
|
||||
else
|
||||
flags = (mode & SIOMIX_WRITE) ? O_WRONLY : O_RDONLY;
|
||||
while ((hdl->fd = open(path, flags | O_CLOEXEC)) < 0) {
|
||||
while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
DPERROR(path);
|
||||
free(hdl);
|
||||
return NULL;
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static struct siomix_hdl *
|
||||
siomix_sun_fdopen(int fd, unsigned int mode, int nbio)
|
||||
{
|
||||
struct siomix_sun_hdl *hdl;
|
||||
|
||||
hdl = malloc(sizeof(struct siomix_sun_hdl));
|
||||
if (hdl == NULL)
|
||||
return NULL;
|
||||
_siomix_create(&hdl->siomix, &siomix_sun_ops, mode, nbio);
|
||||
hdl->fd = fd;
|
||||
init(hdl);
|
||||
return (struct siomix_hdl *)hdl;
|
||||
}
|
||||
|
||||
struct siomix_hdl *
|
||||
_siomix_sun_open(const char *str, unsigned int mode, int nbio)
|
||||
{
|
||||
struct siomix_hdl *hdl;
|
||||
int fd;
|
||||
|
||||
fd = siomix_sun_getfd(str, mode, nbio);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
hdl = siomix_sun_fdopen(fd, mode, nbio);
|
||||
if (hdl != NULL)
|
||||
return hdl;
|
||||
while (close(fd) < 0 && errno == EINTR)
|
||||
; /* retry */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
siomix_sun_close(struct siomix_hdl *addr)
|
||||
{
|
||||
|
|
|
@ -25,7 +25,7 @@ The
|
|||
.Nm sndio
|
||||
audio and MIDI system provides access to audio and MIDI hardware and
|
||||
to services provided by
|
||||
.Xr sndiod 1 ,
|
||||
.Xr sndiod 8 ,
|
||||
summarized below.
|
||||
.Pp
|
||||
Hardware
|
||||
|
@ -38,7 +38,7 @@ audio programs.
|
|||
.Pp
|
||||
To overcome hardware limitations and to allow multiple applications
|
||||
to share the hardware,
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
can be used.
|
||||
It exposes one or more software sub-devices backed by the underlying hardware,
|
||||
while doing all necessary conversions on the fly.
|
||||
|
@ -57,15 +57,15 @@ Software MIDI thru boxes allow one application to send MIDI data to other
|
|||
applications connected to the thru box (for instance a software sequencer
|
||||
can send events to multiple software synthesizers).
|
||||
There's no hardware involved: thru boxes are created by
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.Pp
|
||||
Additionally,
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
exposes a MIDI port used to control and monitor audio streams
|
||||
in real time using MIDI.
|
||||
.Sh DEVICE NAMES
|
||||
From the user's perspective every audio interface, MIDI port, and
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
service has a name of the form:
|
||||
.Bd -literal -offset center
|
||||
type[@hostname][,unit]/devnum[.option]
|
||||
|
@ -89,36 +89,36 @@ Raw
|
|||
port.
|
||||
.It Pa snd
|
||||
Audio device exposed by
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.It Pa midithru
|
||||
MIDI thru box created with
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.It Pa midi
|
||||
MIDI port exposed by
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.It Pa default
|
||||
Default audio device or MIDI port (see below).
|
||||
.El
|
||||
.It Pa hostname
|
||||
The hostname or address where the remote
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
server to connect to is running.
|
||||
.It Pa unit
|
||||
The number of the
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
server to connect to, corresponding to the integer specified using the
|
||||
.Fl U
|
||||
option of
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
Useful only if multiple
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
servers are running on the same system.
|
||||
.It Pa devnum
|
||||
Device number.
|
||||
For hardware audio or MIDI ports, this corresponds to
|
||||
the character device minor number.
|
||||
For audio devices or MIDI ports created with
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
it corresponds to the number of the corresponding
|
||||
.Fl fq
|
||||
option on the command line.
|
||||
|
@ -126,7 +126,7 @@ option on the command line.
|
|||
Corresponds to the sub-device string registered using the
|
||||
.Fl s
|
||||
option of
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.El
|
||||
.Pp
|
||||
For example:
|
||||
|
@ -138,13 +138,13 @@ First hardware audio device.
|
|||
Hardware MIDI port number 5.
|
||||
.It Pa snd/0
|
||||
First audio device exposed by
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.It Pa snd/0.rear
|
||||
Sub-device registered with
|
||||
.Fl s Fa rear .
|
||||
.It Pa midithru/0
|
||||
First MIDI thru box created with
|
||||
.Xr sndiod 1 .
|
||||
.Xr sndiod 8 .
|
||||
.El
|
||||
.Sh DEFAULTS
|
||||
If
|
||||
|
@ -158,10 +158,10 @@ If it is not set, the program first tries to connect to
|
|||
If that fails, it then tries to use
|
||||
.Pa rsnd/0 .
|
||||
This allows the
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
audio server to be used by default and the bare hardware as fallback;
|
||||
programs don't have to be reconfigured when
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
is started or stopped.
|
||||
.Pp
|
||||
If
|
||||
|
@ -175,14 +175,14 @@ If it is not set, the program first tries to connect to
|
|||
If that fails, it then tries to use
|
||||
.Pa rmidi/0 .
|
||||
As long as
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
is running, this allows programs to exchange MIDI data on
|
||||
machines with no MIDI hardware by default, e.g. a MIDI player
|
||||
could use a software synthesizer with no manual configuration
|
||||
required.
|
||||
.Sh AUTHENTICATION
|
||||
If a shared
|
||||
.Xr sndiod 1
|
||||
.Xr sndiod 8
|
||||
server is running, for privacy reasons only one user may have
|
||||
connections to it at a given time
|
||||
(though the same user could have multiple connections to it).
|
||||
|
@ -216,8 +216,8 @@ Audio devices.
|
|||
MIDI ports.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr sndiod 1 ,
|
||||
.Xr mio_open 3 ,
|
||||
.Xr sio_open 3 ,
|
||||
.Xr audio 4 ,
|
||||
.Xr midi 4
|
||||
.Xr midi 4 ,
|
||||
.Xr sndiod 8
|
||||
|
|
|
@ -14,29 +14,29 @@ LDADD = -lsndio @ldadd@
|
|||
@vars@
|
||||
|
||||
#
|
||||
# binaries, documentation, man pages and examples will be installed in
|
||||
# ${BIN_DIR}, ${MAN1_DIR}
|
||||
# binaries, documentation, man pages and examples will be installed in
|
||||
# ${BIN_DIR}, ${MAN8_DIR}
|
||||
#
|
||||
BIN_DIR = @bindir@
|
||||
MAN1_DIR = @mandir@/man1
|
||||
MAN8_DIR = @mandir@/man8
|
||||
|
||||
#
|
||||
# programs to build
|
||||
#
|
||||
PROG = sndiod
|
||||
MAN1 = sndiod.1
|
||||
MAN8 = sndiod.8
|
||||
|
||||
all: ${PROG} ${MAN1}
|
||||
all: ${PROG}
|
||||
|
||||
install:
|
||||
mkdir -p ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN1_DIR}
|
||||
rm -f ${DESTDIR}${BIN_DIR}/${PROG} ${DESTDIR}${MAN1_DIR}/${MAN1}
|
||||
mkdir -p ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN8_DIR}
|
||||
rm -f ${DESTDIR}${BIN_DIR}/${PROG} ${DESTDIR}${MAN8_DIR}/${MAN8}
|
||||
cp ${PROG} ${DESTDIR}${BIN_DIR}
|
||||
cp ${MAN1} ${DESTDIR}${MAN1_DIR}
|
||||
cp ${MAN8} ${DESTDIR}${MAN8_DIR}
|
||||
|
||||
uninstall:
|
||||
cd ${DESTDIR}${BIN_DIR} && rm -f ${PROG}
|
||||
cd ${DESTDIR}${MAN1_DIR} && rm -f ${MAN1}
|
||||
cd ${DESTDIR}${MAN8_DIR} && rm -f ${MAN8}
|
||||
|
||||
clean:
|
||||
rm -f -- *.o ${PROG}
|
||||
|
|
|
@ -53,7 +53,7 @@ abuf_init(struct abuf *buf, unsigned int len)
|
|||
void
|
||||
abuf_done(struct abuf *buf)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
if (buf->used > 0) {
|
||||
if (log_level >= 3) {
|
||||
log_puts("deleting non-empty buffer, used = ");
|
||||
|
|
38
sndiod/dev.c
38
sndiod/dev.c
|
@ -557,12 +557,12 @@ slot_skip(struct slot *s)
|
|||
if (s->mode & MODE_PLAY) {
|
||||
abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
|
||||
}
|
||||
s->skip--;
|
||||
s->skip--;
|
||||
}
|
||||
return max - s->skip;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
|
||||
{
|
||||
int i, offs, vol, nch;
|
||||
|
@ -592,7 +592,7 @@ play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
|
|||
return todo;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
play_filt_dec(struct slot *s, void *in, void *out, int todo)
|
||||
{
|
||||
void *tmp;
|
||||
|
@ -673,7 +673,7 @@ dev_mix_adjvol(struct dev *d)
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
|
||||
{
|
||||
int i, vol, offs, nch;
|
||||
|
@ -702,7 +702,7 @@ rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
|
|||
return todo;
|
||||
}
|
||||
|
||||
int
|
||||
int
|
||||
rec_filt_enc(struct slot *s, void *in, void *out, int todo)
|
||||
{
|
||||
void *tmp;
|
||||
|
@ -857,11 +857,11 @@ dev_cycle(struct dev *d)
|
|||
dev_mix_adjvol(d);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* check for xruns
|
||||
*/
|
||||
if (((s->mode & MODE_PLAY) &&
|
||||
if (((s->mode & MODE_PLAY) &&
|
||||
s->mix.buf.used < s->round * s->mix.bpf) ||
|
||||
((s->mode & MODE_RECMASK) &&
|
||||
s->sub.buf.len - s->sub.buf.used <
|
||||
|
@ -927,7 +927,7 @@ void
|
|||
dev_onmove(struct dev *d, int delta)
|
||||
{
|
||||
long long pos;
|
||||
struct slot *s, *snext;
|
||||
struct slot *s, *snext;
|
||||
|
||||
d->delta += delta;
|
||||
|
||||
|
@ -1256,6 +1256,8 @@ dev_done(struct dev *d)
|
|||
log_puts(": draining\n");
|
||||
}
|
||||
#endif
|
||||
if (d->tstate != MMC_STOP)
|
||||
dev_mmcstop(d);
|
||||
if (d->hold)
|
||||
dev_unref(d);
|
||||
}
|
||||
|
@ -1266,7 +1268,7 @@ dev_bynum(int num)
|
|||
struct dev *d;
|
||||
|
||||
for (d = dev_list; d != NULL; d = d->next) {
|
||||
if (num-- == 0)
|
||||
if (d->num == num)
|
||||
return d;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -1327,11 +1329,11 @@ dev_wakeup(struct dev *d)
|
|||
}
|
||||
d->poffs = 0;
|
||||
|
||||
/*
|
||||
/*
|
||||
* empty cycles don't increment delta, so it's ok to
|
||||
* start at 0
|
||||
**/
|
||||
d->delta = 0;
|
||||
d->delta = 0;
|
||||
|
||||
d->pstate = DEV_RUN;
|
||||
dev_sio_start(d);
|
||||
|
@ -1650,7 +1652,7 @@ slot_attach(struct slot *s)
|
|||
* start the device if not started
|
||||
*/
|
||||
dev_wakeup(d);
|
||||
|
||||
|
||||
/*
|
||||
* get the current position, the origin is when the first sample
|
||||
* played and/or recorded
|
||||
|
@ -1684,7 +1686,7 @@ slot_attach(struct slot *s)
|
|||
#ifdef DEBUG
|
||||
if ((s->mode & d->mode) != s->mode) {
|
||||
slot_log(s);
|
||||
log_puts(": mode beyond device mode, not attaching\n");
|
||||
log_puts(": mode beyond device mode, not attaching\n");
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
|
@ -1752,7 +1754,7 @@ slot_attach(struct slot *s)
|
|||
s->sub.encbuf =
|
||||
xmalloc(s->round * slot_nch * sizeof(adata_t));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* N-th recorded block is the N-th played block
|
||||
*/
|
||||
|
@ -1770,7 +1772,7 @@ slot_ready(struct slot *s)
|
|||
/*
|
||||
* device may be disconnected, and if so we're called from
|
||||
* slot->ops->exit() on a closed device
|
||||
*/
|
||||
*/
|
||||
if (s->dev->pstate == DEV_CFG)
|
||||
return;
|
||||
if (s->tstate == MMC_OFF)
|
||||
|
@ -1811,7 +1813,7 @@ slot_start(struct slot *s)
|
|||
log_puts("\n");
|
||||
}
|
||||
#endif
|
||||
s->mix.bpf = s->par.bps *
|
||||
s->mix.bpf = s->par.bps *
|
||||
(s->mix.slot_cmax - s->mix.slot_cmin + 1);
|
||||
abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
|
||||
}
|
||||
|
@ -1826,7 +1828,7 @@ slot_start(struct slot *s)
|
|||
log_puts("\n");
|
||||
}
|
||||
#endif
|
||||
s->sub.bpf = s->par.bps *
|
||||
s->sub.bpf = s->par.bps *
|
||||
(s->sub.slot_cmax - s->sub.slot_cmin + 1);
|
||||
abuf_init(&s->sub.buf, bufsz * s->sub.bpf);
|
||||
}
|
||||
|
@ -1871,7 +1873,7 @@ slot_detach(struct slot *s)
|
|||
panic();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
*ps = s->next;
|
||||
if (s->mode & MODE_RECMASK) {
|
||||
if (s->sub.encbuf)
|
||||
|
|
|
@ -46,7 +46,7 @@ struct slot {
|
|||
void *arg; /* user data for callbacks */
|
||||
struct aparams par; /* socket side params */
|
||||
struct {
|
||||
int weight; /* dynamic range */
|
||||
int weight; /* dynamic range */
|
||||
int maxweight; /* max dynamic range allowed */
|
||||
unsigned int vol; /* volume within the vol */
|
||||
struct abuf buf; /* socket side buffer */
|
||||
|
@ -140,7 +140,7 @@ struct dev {
|
|||
|
||||
/*
|
||||
* audio device (while opened)
|
||||
*/
|
||||
*/
|
||||
struct dev_sio sio;
|
||||
struct dev_siomix siomix;
|
||||
struct aparams par; /* encoding */
|
||||
|
|
|
@ -152,7 +152,7 @@ aparams_strtoenc(struct aparams *par, char *istr)
|
|||
return 0;
|
||||
|
||||
done:
|
||||
par->msb = msb;
|
||||
par->msb = msb;
|
||||
par->sig = sig;
|
||||
par->bits = bits;
|
||||
par->bps = bps;
|
||||
|
@ -296,7 +296,8 @@ resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
|
|||
* initialize resampler with ibufsz/obufsz factor and "nch" channels
|
||||
*/
|
||||
void
|
||||
resamp_init(struct resamp *p, unsigned int iblksz, unsigned int oblksz, int nch)
|
||||
resamp_init(struct resamp *p, unsigned int iblksz,
|
||||
unsigned int oblksz, int nch)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -446,7 +447,7 @@ enc_init(struct conv *p, struct aparams *par, int nch)
|
|||
p->bias = (1U << 31) >> p->shift;
|
||||
} else {
|
||||
p->bias = 0;
|
||||
}
|
||||
}
|
||||
if (!par->le) {
|
||||
p->bfirst = par->bps - 1;
|
||||
p->bnext = -1;
|
||||
|
@ -539,7 +540,7 @@ dec_init(struct conv *p, struct aparams *par, int nch)
|
|||
p->bias = (1U << 31) >> p->shift;
|
||||
} else {
|
||||
p->bias = 0;
|
||||
}
|
||||
}
|
||||
if (par->le) {
|
||||
p->bfirst = par->bps - 1;
|
||||
p->bnext = -1;
|
||||
|
|
|
@ -105,9 +105,9 @@ typedef int adata_t;
|
|||
struct aparams {
|
||||
unsigned int bps; /* bytes per sample */
|
||||
unsigned int bits; /* actually used bits */
|
||||
unsigned int le; /* 1 if little endian, 0 if big endian */
|
||||
unsigned int le; /* 1 if little endian, else be */
|
||||
unsigned int sig; /* 1 if signed, 0 if unsigned */
|
||||
unsigned int msb; /* 1 if msb justified, 0 if lsb justified */
|
||||
unsigned int msb; /* 1 if msb justified, else lsb */
|
||||
};
|
||||
|
||||
struct resamp {
|
||||
|
@ -124,7 +124,7 @@ struct conv {
|
|||
int bfirst; /* bytes to skip at startup */
|
||||
unsigned int bps; /* bytes per sample */
|
||||
unsigned int shift; /* shift to get 32bit MSB */
|
||||
unsigned int bias; /* bias of unsigned samples */
|
||||
unsigned int bias; /* bias of unsigned samples */
|
||||
int bnext; /* to reach the next byte */
|
||||
int snext; /* to reach the next sample */
|
||||
int nch;
|
||||
|
|
|
@ -46,7 +46,6 @@
|
|||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
|
@ -259,7 +258,7 @@ file_del(struct file *f)
|
|||
log_puts("bad state in file_del()\n");
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
file_nfds -= f->max_nfds;
|
||||
f->state = FILE_ZOMB;
|
||||
#ifdef DEBUG
|
||||
|
@ -283,7 +282,7 @@ file_process(struct file *f, struct pollfd *pfd)
|
|||
if (log_level >= 3)
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts0);
|
||||
#endif
|
||||
revents = (f->state != FILE_ZOMB) ?
|
||||
revents = (f->state != FILE_ZOMB) ?
|
||||
f->ops->revents(f->arg, pfd) : 0;
|
||||
if ((revents & POLLHUP) && (f->state != FILE_ZOMB))
|
||||
f->ops->hup(f->arg);
|
||||
|
@ -399,8 +398,10 @@ file_poll(void)
|
|||
timo = -1;
|
||||
res = poll(pfds, nfds, timo);
|
||||
if (res < 0) {
|
||||
if (errno != EINTR)
|
||||
err(1, "poll");
|
||||
if (errno != EINTR) {
|
||||
log_puts("poll failed");
|
||||
panic();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -412,19 +413,17 @@ file_poll(void)
|
|||
file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
|
||||
file_wtime += ts.tv_nsec - sleepts.tv_nsec;
|
||||
#endif
|
||||
delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
|
||||
delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
|
||||
#ifdef DEBUG
|
||||
if (delta_nsec < 0)
|
||||
log_puts("file_poll: negative time interval\n");
|
||||
#endif
|
||||
file_ts = ts;
|
||||
if (delta_nsec >= 0 && delta_nsec < 1000000000LL)
|
||||
timo_update(delta_nsec / 1000);
|
||||
else {
|
||||
if (log_level >= 2)
|
||||
log_puts("ignored huge clock delta\n");
|
||||
if (timo_queue) {
|
||||
delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
|
||||
delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
|
||||
if (delta_nsec >= 0 && delta_nsec < 60000000000LL)
|
||||
timo_update(delta_nsec / 1000);
|
||||
else {
|
||||
if (log_level >= 2)
|
||||
log_puts("out-of-bounds clock delta\n");
|
||||
}
|
||||
}
|
||||
file_ts = ts;
|
||||
|
||||
/*
|
||||
* process files that rely on poll
|
||||
|
@ -444,15 +443,14 @@ filelist_init(void)
|
|||
{
|
||||
sigset_t set;
|
||||
|
||||
sigemptyset(&set);
|
||||
(void)sigaddset(&set, SIGPIPE);
|
||||
if (sigprocmask(SIG_BLOCK, &set, NULL))
|
||||
err(1, "sigprocmask");
|
||||
file_list = NULL;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &file_ts) < 0) {
|
||||
perror("clock_gettime");
|
||||
exit(1);
|
||||
log_puts("filelist_init: CLOCK_MONOTONIC unsupported\n");
|
||||
panic();
|
||||
}
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set, SIGPIPE);
|
||||
sigprocmask(SIG_BLOCK, &set, NULL);
|
||||
file_list = NULL;
|
||||
log_sync = 0;
|
||||
timo_init();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ struct fileops {
|
|||
char *name;
|
||||
int (*pollfd)(void *, struct pollfd *);
|
||||
int (*revents)(void *, struct pollfd *);
|
||||
/*
|
||||
/*
|
||||
* we have to handle POLLIN and POLLOUT events
|
||||
* in separate handles, since handling POLLIN can
|
||||
* close the file, and continuing (to handle POLLOUT)
|
||||
|
@ -52,7 +52,7 @@ struct file {
|
|||
#define FILE_INIT 0 /* ready */
|
||||
#define FILE_ZOMB 1 /* closed, but not free()d yet */
|
||||
unsigned int state; /* one of above */
|
||||
unsigned int max_nfds; /* max number of descriptors */
|
||||
unsigned int max_nfds; /* max number of descriptors */
|
||||
unsigned int nfds; /* number of descriptors polled */
|
||||
char *name; /* for debug purposes */
|
||||
};
|
||||
|
|
|
@ -24,12 +24,10 @@
|
|||
#include <netinet/tcp.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
@ -80,7 +78,7 @@ listen_close(struct listen *f)
|
|||
xfree(f);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
listen_new_un(char *path)
|
||||
{
|
||||
int sock, oldumask;
|
||||
|
@ -89,11 +87,13 @@ listen_new_un(char *path)
|
|||
|
||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("socket");
|
||||
exit(1);
|
||||
log_puts(path);
|
||||
log_puts(": failed to create socket\n");
|
||||
return 0;
|
||||
}
|
||||
if (unlink(path) < 0 && errno != ENOENT) {
|
||||
perror("unlink");
|
||||
log_puts(path);
|
||||
log_puts(": failed to unlink socket\n");
|
||||
goto bad_close;
|
||||
}
|
||||
sockname.sun_family = AF_UNIX;
|
||||
|
@ -101,11 +101,13 @@ listen_new_un(char *path)
|
|||
oldumask = umask(0111);
|
||||
if (bind(sock, (struct sockaddr *)&sockname,
|
||||
sizeof(struct sockaddr_un)) < 0) {
|
||||
perror("bind");
|
||||
log_puts(path);
|
||||
log_puts(": failed to bind socket\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (listen(sock, 1) < 0) {
|
||||
perror("listen");
|
||||
log_puts(path);
|
||||
log_puts(": failed to listen\n");
|
||||
goto bad_close;
|
||||
}
|
||||
umask(oldumask);
|
||||
|
@ -114,29 +116,25 @@ listen_new_un(char *path)
|
|||
if (f->file == NULL)
|
||||
goto bad_close;
|
||||
f->path = xstrdup(path);
|
||||
if (f->path == NULL) {
|
||||
perror("strdup");
|
||||
exit(1);
|
||||
}
|
||||
f->fd = sock;
|
||||
f->next = listen_list;
|
||||
listen_list = f;
|
||||
return;
|
||||
return 1;
|
||||
bad_close:
|
||||
close(sock);
|
||||
exit(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
listen_new_tcp(char *addr, unsigned int port)
|
||||
{
|
||||
char *host, serv[sizeof(unsigned int) * 3 + 1];
|
||||
struct addrinfo *ailist, *ai, aihints;
|
||||
struct listen *f;
|
||||
int s, error, opt = 1, n = 0;
|
||||
|
||||
/*
|
||||
* obtain a list of possible addresses for the host/port
|
||||
|
||||
/*
|
||||
* obtain a list of possible addresses for the host/port
|
||||
*/
|
||||
memset(&aihints, 0, sizeof(struct addrinfo));
|
||||
snprintf(serv, sizeof(serv), "%u", port);
|
||||
|
@ -146,24 +144,27 @@ listen_new_tcp(char *addr, unsigned int port)
|
|||
aihints.ai_protocol = IPPROTO_TCP;
|
||||
error = getaddrinfo(host, serv, &aihints, &ailist);
|
||||
if (error) {
|
||||
fprintf(stderr, "%s: %s\n", addr, gai_strerror(error));
|
||||
exit(1);
|
||||
log_puts(addr);
|
||||
log_puts(": failed to resolve address\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
* for each address, try create a listening socket bound on
|
||||
* that address
|
||||
*/
|
||||
for (ai = ailist; ai != NULL; ai = ai->ai_next) {
|
||||
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
|
||||
if (s < 0) {
|
||||
perror("socket");
|
||||
log_puts(addr);
|
||||
log_puts(": failed to create socket\n");
|
||||
continue;
|
||||
}
|
||||
opt = 1;
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
|
||||
&opt, sizeof(int)) < 0) {
|
||||
perror("setsockopt");
|
||||
log_puts(addr);
|
||||
log_puts(": failed to set SO_REUSEADDR\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (ai->ai_family == AF_INET6) {
|
||||
|
@ -175,17 +176,20 @@ listen_new_tcp(char *addr, unsigned int port)
|
|||
opt = 1;
|
||||
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
&opt, sizeof(int)) < 0) {
|
||||
perror("setsockopt");
|
||||
log_puts(addr);
|
||||
log_puts(": failed to set IPV6_V6ONLY\n");
|
||||
goto bad_close;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
|
||||
perror("bind");
|
||||
log_puts(addr);
|
||||
log_puts(": failed to bind socket\n");
|
||||
goto bad_close;
|
||||
}
|
||||
if (listen(s, 1) < 0) {
|
||||
perror("listen");
|
||||
log_puts(addr);
|
||||
log_puts(": failed to listen\n");
|
||||
goto bad_close;
|
||||
}
|
||||
f = xmalloc(sizeof(struct listen));
|
||||
|
@ -202,8 +206,7 @@ listen_new_tcp(char *addr, unsigned int port)
|
|||
n++;
|
||||
}
|
||||
freeaddrinfo(ailist);
|
||||
if (n == 0)
|
||||
exit(1);
|
||||
return n;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -217,7 +220,8 @@ listen_pollfd(void *arg, struct pollfd *pfd)
|
|||
{
|
||||
struct listen *f = arg;
|
||||
|
||||
if (file_slowaccept)
|
||||
f->slowaccept = file_slowaccept;
|
||||
if (f->slowaccept)
|
||||
return 0;
|
||||
pfd->fd = f->fd;
|
||||
pfd->events = POLLIN;
|
||||
|
@ -227,6 +231,10 @@ listen_pollfd(void *arg, struct pollfd *pfd)
|
|||
int
|
||||
listen_revents(void *arg, struct pollfd *pfd)
|
||||
{
|
||||
struct listen *f = arg;
|
||||
|
||||
if (f->slowaccept)
|
||||
return 0;
|
||||
return pfd->revents;
|
||||
}
|
||||
|
||||
|
@ -244,12 +252,11 @@ listen_in(void *arg)
|
|||
continue;
|
||||
if (errno == ENFILE || errno == EMFILE)
|
||||
file_slowaccept = 1;
|
||||
else if (errno != ECONNABORTED && errno != EWOULDBLOCK)
|
||||
perror("accept");
|
||||
return;
|
||||
}
|
||||
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
|
||||
perror("fcntl(sock, O_NONBLOCK)");
|
||||
file_log(f->file);
|
||||
log_puts(": failed to set non-blocking mode\n");
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
|
@ -257,7 +264,8 @@ listen_in(void *arg)
|
|||
opt = 1;
|
||||
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
||||
&opt, sizeof(int)) < 0) {
|
||||
perror("setsockopt");
|
||||
file_log(f->file);
|
||||
log_puts(": failed to set TCP_NODELAY flag\n");
|
||||
close(sock);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,13 @@ struct listen {
|
|||
struct file *file;
|
||||
char *path;
|
||||
int fd;
|
||||
int slowaccept;
|
||||
};
|
||||
|
||||
extern struct listen *listen_list;
|
||||
|
||||
void listen_new_un(char *);
|
||||
void listen_new_tcp(char *, unsigned int);
|
||||
int listen_new_un(char *);
|
||||
int listen_new_tcp(char *, unsigned int);
|
||||
int listen_init(struct listen *);
|
||||
void listen_close(struct listen *);
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ midi_tickets(struct midi *iep)
|
|||
}
|
||||
|
||||
/*
|
||||
* in the worst case output message is twice the
|
||||
* in the worst case output message is twice the
|
||||
* input message (2-byte messages with running status)
|
||||
*/
|
||||
tickets = maxavail / 2 - iep->tickets;
|
||||
|
@ -333,14 +333,14 @@ midi_in(struct midi *iep, unsigned char *idata, int icount)
|
|||
* store the given message in the output buffer
|
||||
*/
|
||||
void
|
||||
midi_out(struct midi *oep, unsigned char *idata, int icount)
|
||||
midi_out(struct midi *oep, unsigned char *idata, int icount)
|
||||
{
|
||||
unsigned char *odata;
|
||||
int ocount;
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
#endif
|
||||
|
||||
|
||||
while (icount > 0) {
|
||||
if (oep->obuf.used == oep->obuf.len) {
|
||||
#ifdef DEBUG
|
||||
|
@ -376,13 +376,11 @@ midi_out(struct midi *oep, unsigned char *idata, int icount)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
port_log(struct port *p)
|
||||
{
|
||||
midi_log(p->midi);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
port_imsg(void *arg, unsigned char *msg, int size)
|
||||
|
@ -427,18 +425,16 @@ port_exit(void *arg)
|
|||
struct port *
|
||||
port_new(char *path, unsigned int mode, int hold)
|
||||
{
|
||||
struct port *c, **pc;
|
||||
struct port *c;
|
||||
|
||||
c = xmalloc(sizeof(struct port));
|
||||
c->path = xstrdup(path);
|
||||
c->state = PORT_CFG;
|
||||
c->hold = hold;
|
||||
c->midi = midi_new(&port_midiops, c, mode);
|
||||
midi_portnum++;
|
||||
for (pc = &port_list; *pc != NULL; pc = &(*pc)->next)
|
||||
; /* nothing */
|
||||
c->next = NULL;
|
||||
*pc = c;
|
||||
c->num = midi_portnum++;
|
||||
c->next = port_list;
|
||||
port_list = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -504,7 +500,7 @@ port_bynum(int num)
|
|||
struct port *p;
|
||||
|
||||
for (p = port_list; p != NULL; p = p->next) {
|
||||
if (num-- == 0)
|
||||
if (p->num == num)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -536,9 +532,9 @@ port_close(struct port *c)
|
|||
panic();
|
||||
}
|
||||
#endif
|
||||
c->state = PORT_CFG;
|
||||
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) ||
|
||||
|
|
|
@ -73,7 +73,7 @@ struct midi {
|
|||
unsigned int len; /* expected ``msg'' length */
|
||||
unsigned int txmask; /* list of ep we send to */
|
||||
unsigned int self; /* equal (1 << index) */
|
||||
unsigned int tickets; /* max bytes we can process */
|
||||
int tickets; /* max bytes we can process */
|
||||
struct abuf obuf; /* output buffer */
|
||||
};
|
||||
|
||||
|
@ -87,6 +87,7 @@ struct port {
|
|||
#define PORT_INIT 1
|
||||
#define PORT_DRAIN 2
|
||||
unsigned int state;
|
||||
unsigned int num; /* port serial number */
|
||||
char *path; /* hold the port open ? */
|
||||
int hold;
|
||||
struct midi *midi;
|
||||
|
|
30
sndiod/opt.c
30
sndiod/opt.c
|
@ -14,8 +14,6 @@
|
|||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dev.h"
|
||||
|
@ -32,20 +30,27 @@ opt_new(char *name, struct dev *dev,
|
|||
int pmin, int pmax, int rmin, int rmax,
|
||||
int maxweight, int mmc, int dup, unsigned int mode)
|
||||
{
|
||||
struct opt *o, **po;
|
||||
struct opt *o;
|
||||
unsigned int len;
|
||||
char c;
|
||||
|
||||
if (opt_byname(name, dev->num)) {
|
||||
log_puts(name);
|
||||
log_puts(": already defined\n");
|
||||
return NULL;
|
||||
}
|
||||
for (len = 0; name[len] != '\0'; len++) {
|
||||
if (len == OPT_NAMEMAX) {
|
||||
fprintf(stderr, "%s: name too long\n", name);
|
||||
exit(1);
|
||||
log_puts(name);
|
||||
log_puts(": too long\n");
|
||||
return NULL;
|
||||
}
|
||||
c = name[len];
|
||||
if ((c < 'a' || c > 'z') &&
|
||||
(c < 'A' || c > 'Z')) {
|
||||
fprintf(stderr, "%s: '%c' not allowed\n", name, c);
|
||||
exit(1);
|
||||
log_puts(name);
|
||||
log_puts(": only alphabetic chars allowed\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
o = xmalloc(sizeof(struct opt));
|
||||
|
@ -63,15 +68,8 @@ opt_new(char *name, struct dev *dev,
|
|||
o->mode = mode;
|
||||
o->dev = dev;
|
||||
memcpy(o->name, name, len + 1);
|
||||
for (po = &opt_list; *po != NULL; po = &(*po)->next) {
|
||||
if (o->dev->num == (*po)->dev->num &&
|
||||
strcmp(o->name, (*po)->name) == 0) {
|
||||
fprintf(stderr, "%s: already defined\n", o->name);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
o->next = NULL;
|
||||
*po = o;
|
||||
o->next = opt_list;
|
||||
opt_list = o;
|
||||
if (log_level >= 2) {
|
||||
dev_log(o->dev);
|
||||
log_puts(".");
|
||||
|
|
|
@ -163,7 +163,7 @@ dev_sio_open(struct dev *d)
|
|||
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);
|
||||
log_puts(": ");
|
||||
|
@ -296,7 +296,7 @@ dev_sio_pollfd(void *arg, struct pollfd *pfd)
|
|||
{
|
||||
struct dev *d = arg;
|
||||
int events;
|
||||
|
||||
|
||||
events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT;
|
||||
return sio_pollfd(d->sio.hdl, pfd, events);
|
||||
}
|
||||
|
|
532
sndiod/sndiod.1
532
sndiod/sndiod.1
|
@ -1,532 +0,0 @@
|
|||
.\" $OpenBSD$
|
||||
.\"
|
||||
.\" Copyright (c) 2006-2012 Alexandre Ratchov <alex@caoua.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
.\" copyright notice and this permission notice appear in all copies.
|
||||
.\"
|
||||
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate$
|
||||
.Dt SNDIOD 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm sndiod
|
||||
.Nd audio/MIDI server
|
||||
.Sh SYNOPSIS
|
||||
.Nm sndiod
|
||||
.Bk -words
|
||||
.Op Fl d
|
||||
.Op Fl a Ar flag
|
||||
.Op Fl b Ar nframes
|
||||
.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 j Ar flag
|
||||
.Op Fl L Ar addr
|
||||
.Op Fl m Ar mode
|
||||
.Op Fl q Ar port
|
||||
.Op Fl r Ar rate
|
||||
.Op Fl s Ar name
|
||||
.Op Fl t Ar mode
|
||||
.Op Fl U Ar unit
|
||||
.Op Fl v Ar volume
|
||||
.Op Fl w Ar flag
|
||||
.Op Fl z Ar nframes
|
||||
.Ek
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
daemon is an intermediate layer between
|
||||
audio or MIDI programs and the hardware.
|
||||
It performs the necessary audio processing to
|
||||
allow any program to work on any supported hardware.
|
||||
By default,
|
||||
.Nm
|
||||
accepts connections from programs
|
||||
running on the same system only;
|
||||
it initializes only when programs are using its services,
|
||||
allowing
|
||||
.Nm
|
||||
to consume a negligible amount of system resources the rest of the time.
|
||||
Systems with no audio hardware can use
|
||||
.Nm
|
||||
to keep hot-pluggable devices usable by default at
|
||||
virtually no cost.
|
||||
.Pp
|
||||
.Nm
|
||||
operates as follows: it exposes at least one
|
||||
.Em sub-device
|
||||
that any number of audio programs can connect to and use as if it was
|
||||
audio hardware.
|
||||
During playback,
|
||||
.Nm
|
||||
receives audio data concurrently from all programs, mixes it and sends
|
||||
the result to the hardware device.
|
||||
Similarly, during recording it duplicates audio data recorded
|
||||
from the device and sends it to all programs.
|
||||
Since audio data flows through the
|
||||
.Nm
|
||||
process, it has the opportunity to process audio data on the fly:
|
||||
.Pp
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
Change the sound encoding to overcome incompatibilities between
|
||||
software and hardware.
|
||||
.It
|
||||
Route the sound from one channel to another,
|
||||
join stereo or split mono.
|
||||
.It
|
||||
Control the per-application playback volume as well as the
|
||||
master volume.
|
||||
.It
|
||||
Monitor the sound being played, allowing one program to record
|
||||
what other programs play.
|
||||
.El
|
||||
.Pp
|
||||
Processing is configured on a per sub-device basis, meaning that
|
||||
the sound of all programs connected to the same sub-device will be
|
||||
processed according to the same configuration.
|
||||
Multiple sub-devices can be defined, allowing multiple configurations
|
||||
to coexist.
|
||||
The user selects the configuration a given program will use
|
||||
by selecting the sub-device the program uses.
|
||||
.Pp
|
||||
.Nm
|
||||
exposes MIDI thru boxes (hubs),
|
||||
allowing programs to send MIDI messages to each other
|
||||
or to hardware MIDI ports in a uniform way.
|
||||
.Pp
|
||||
Finally,
|
||||
.Nm
|
||||
exposes a control MIDI port usable for:
|
||||
.Pp
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
Volume control.
|
||||
.It
|
||||
Common clock source for audio and MIDI programs.
|
||||
.It
|
||||
Start, stop and relocate groups of audio programs.
|
||||
.El
|
||||
.Pp
|
||||
The options are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl a Ar flag
|
||||
Control whether
|
||||
.Nm
|
||||
opens the audio device or the MIDI port only when needed or keeps
|
||||
it open all the time.
|
||||
If the flag is
|
||||
.Va on
|
||||
then the audio device or MIDI port is kept open all the time, ensuring
|
||||
no other program can steal it.
|
||||
If the flag is
|
||||
.Va off ,
|
||||
then it's automatically closed, allowing other programs to have direct
|
||||
access to the audio device, or the device to be disconnected.
|
||||
The default is
|
||||
.Va off .
|
||||
.It Fl b Ar nframes
|
||||
The buffer size of the audio device in frames.
|
||||
A frame consists of one sample for each channel in the stream.
|
||||
This is the number of frames that will be buffered before being played
|
||||
and thus controls the playback latency.
|
||||
The default is 7680 or twice the block size
|
||||
.Pq Fl z ,
|
||||
if the block size is set.
|
||||
.It Xo
|
||||
.Fl C Ar min : Ns Ar max ,
|
||||
.Fl c Ar min : Ns Ar max
|
||||
.Xc
|
||||
The range of channel numbers for recording and playback directions,
|
||||
respectively any client is allowed to use.
|
||||
This is a subset of the audio device channels.
|
||||
The default is 0:1, i.e. stereo.
|
||||
.It Fl d
|
||||
Increase log verbosity.
|
||||
.Nm
|
||||
logs on
|
||||
.Em stderr .
|
||||
.It Fl e Ar enc
|
||||
Attempt to configure the device to use this encoding.
|
||||
The default is
|
||||
.Va s16 .
|
||||
Encoding names use the follwing scheme: signedness
|
||||
.Po
|
||||
.Va s
|
||||
or
|
||||
.Va u
|
||||
.Pc
|
||||
followed
|
||||
by the precision in bits, the byte-order
|
||||
.Po
|
||||
.Va le
|
||||
or
|
||||
.Va be
|
||||
.Pc ,
|
||||
the number of
|
||||
bytes per sample, and the alignment
|
||||
.Po
|
||||
.Va msb
|
||||
or
|
||||
.Va lsb
|
||||
.Pc .
|
||||
Only the signedness and the precision are mandatory.
|
||||
Examples:
|
||||
.Va u8 , s16le , s24le3 , s24le4lsb .
|
||||
.It Fl f Ar device
|
||||
Add this
|
||||
.Xr sndio 7
|
||||
audio device to devices used for playing and/or recording.
|
||||
Preceding per-device options
|
||||
.Pq Fl aberwz
|
||||
apply to this device.
|
||||
Sub-devices
|
||||
.Pq Fl s
|
||||
that are applied after will be attached to this device.
|
||||
Device mode and parameters are determined from sub-devices
|
||||
attached to it.
|
||||
.It Fl j Ar flag
|
||||
Control whether program channels are joined or expanded if
|
||||
the number of channels requested by a program is not equal
|
||||
to the device number of channels.
|
||||
If the flag is
|
||||
.Va off
|
||||
then client channels are routed to the corresponding
|
||||
device channel, possibly discarding channels not present in the device.
|
||||
If the flag is
|
||||
.Va on ,
|
||||
then a single client channel may be sent on multiple device channels,
|
||||
or multiple client channels may be sent to a single device channel.
|
||||
For instance, this feature could be used for mono to stereo conversions.
|
||||
The default is
|
||||
.Ar on .
|
||||
.It Fl L Ar addr
|
||||
Specify a local network address
|
||||
.Nm
|
||||
should listen;
|
||||
.Nm
|
||||
will listen on TCP port 11025+n, where n is the unit number
|
||||
specified with
|
||||
.Fl U .
|
||||
Without this option,
|
||||
.Nm
|
||||
listens on the
|
||||
.Ux Ns -domain
|
||||
socket only, and is not reachable from any network.
|
||||
If the option argument is
|
||||
.Sq -
|
||||
then
|
||||
.Nm
|
||||
will accept connections from any address.
|
||||
.It Fl m Ar mode
|
||||
Set the sub-device mode.
|
||||
Valid modes are
|
||||
.Ar play ,
|
||||
.Ar rec ,
|
||||
and
|
||||
.Ar mon ,
|
||||
corresponding to playback, recording and monitoring.
|
||||
A monitoring stream is a fake recording stream corresponding to
|
||||
the mix of all playback streams.
|
||||
Multiple modes can be specified, separated by commas,
|
||||
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
|
||||
Expose the given MIDI port.
|
||||
This allows multiple programs to share the port.
|
||||
.It Fl r Ar rate
|
||||
Attempt to force the device to use this sample rate in Hertz.
|
||||
The default is 48000.
|
||||
.It Fl s Ar name
|
||||
Add
|
||||
.Ar name
|
||||
to the list of sub-devices to expose.
|
||||
This allows clients to use
|
||||
.Nm
|
||||
instead of the physical audio device for audio input and output
|
||||
in order to share the physical device with other clients.
|
||||
Defining multiple sub-devices allows splitting a physical audio device
|
||||
into sub-devices having different properties (e.g. channel ranges).
|
||||
The given
|
||||
.Ar name
|
||||
corresponds to the
|
||||
.Dq option
|
||||
part of the
|
||||
.Xr sndio 7
|
||||
device name string.
|
||||
.It Fl t Ar mode
|
||||
Select the way clients are controlled by MIDI Machine Control (MMC)
|
||||
messages received by
|
||||
.Nm .
|
||||
If the mode is
|
||||
.Va off
|
||||
(the default), then programs are not affected by MMC messages.
|
||||
If the mode is
|
||||
.Va slave ,
|
||||
then programs are started synchronously by MMC start messages;
|
||||
additionally, the server clock is exposed as MIDI Time Code (MTC)
|
||||
messages allowing MTC-capable software or hardware to be synchronized
|
||||
to audio programs.
|
||||
.It Fl U Ar unit
|
||||
Unit number.
|
||||
Each
|
||||
.Nm
|
||||
server instance has an unique unit number,
|
||||
used in
|
||||
.Xr sndio 7
|
||||
device names.
|
||||
The default is 0.
|
||||
The unit number must be set before any
|
||||
.Fl L
|
||||
is used.
|
||||
.It Fl v Ar volume
|
||||
Software volume attenuation of playback.
|
||||
The value must be between 1 and 127,
|
||||
corresponding to \-42dB and \-0dB attenuation in 1/3dB steps.
|
||||
Clients inherit this parameter.
|
||||
Reducing the volume in advance allows a client's volume to stay independent
|
||||
from the number of clients as long as their number is small enough.
|
||||
18 volume units (i.e. \-6dB attenuation) allows the number
|
||||
of playback programs to be doubled.
|
||||
The default is 118 i.e. \-3dB.
|
||||
.It Fl w Ar flag
|
||||
Control
|
||||
.Nm
|
||||
behaviour when the maximum volume of the hardware is reached
|
||||
and a new program starts playing.
|
||||
This happens only when volumes are not properly set using the
|
||||
.Fl v
|
||||
option.
|
||||
If the flag is
|
||||
.Va on ,
|
||||
then the master volume is automatically adjusted to avoid clipping.
|
||||
Using
|
||||
.Va off
|
||||
makes sense in the rare situation where all programs lower their volumes.
|
||||
The default is
|
||||
.Va on .
|
||||
.It Fl z Ar nframes
|
||||
The audio device block size in frames.
|
||||
This is the number of frames between audio clock ticks,
|
||||
i.e. the clock resolution.
|
||||
If a sub-device is created with the
|
||||
.Fl t
|
||||
option, and MTC is used for synchronization, the clock
|
||||
resolution must be 96, 100 or 120 ticks per second for maximum
|
||||
accuracy.
|
||||
For instance, 100 ticks per second at 48000Hz corresponds
|
||||
to a 480 frame block size.
|
||||
The default is 960 or half of the buffer size
|
||||
.Pq Fl b ,
|
||||
if the buffer size is set.
|
||||
.El
|
||||
.Pp
|
||||
On the command line,
|
||||
per-device parameters
|
||||
.Pq Fl aberwz
|
||||
must precede the device definition
|
||||
.Pq Fl f ,
|
||||
and per-sub-device parameters
|
||||
.Pq Fl Ccjmtvx
|
||||
must precede the sub-device definition
|
||||
.Pq Fl s .
|
||||
Sub-device definitions
|
||||
.Pq Fl s
|
||||
must follow the definition of the device
|
||||
.Pq Fl f
|
||||
to which they are attached.
|
||||
.Pp
|
||||
If no audio devices
|
||||
.Pq Fl f
|
||||
are specified, first 4 audio devices are added and
|
||||
settings are applied to all of them.
|
||||
Similarly, if no MIDI ports
|
||||
.Pq Fl q
|
||||
are specified, first 8 MIDI ports are added and
|
||||
settings are applied to all of them.
|
||||
If no sub-devices
|
||||
.Pq Fl s
|
||||
are specified for a device, a default sub-device is
|
||||
created attached to it.
|
||||
If a device or MIDI port
|
||||
.Pq Fl fq
|
||||
is defined twice, both definitions are merged:
|
||||
parameters of the first one are used but sub-devices
|
||||
.Pq Fl s
|
||||
of both definitions are created.
|
||||
.Pp
|
||||
If
|
||||
.Nm
|
||||
is sent
|
||||
.Dv SIGHUP ,
|
||||
.Dv SIGINT
|
||||
or
|
||||
.Dv SIGTERM ,
|
||||
it terminates.
|
||||
.Pp
|
||||
By default, when the program cannot accept
|
||||
recorded data fast enough or cannot provide data to play fast enough,
|
||||
the program is paused, i.e. samples that cannot be written are discarded
|
||||
and samples that cannot be read are replaced by silence.
|
||||
If a sub-device is created with the
|
||||
.Fl t
|
||||
option, then recorded samples are discarded,
|
||||
but the same amount of silence will be written
|
||||
once the program is unblocked, in order to reach the right position in time.
|
||||
Similarly silence is played, but the same amount of samples will be discarded
|
||||
once the program is unblocked.
|
||||
This ensures proper synchronization between programs.
|
||||
.Sh MIDI CONTROL
|
||||
.Nm
|
||||
creates a MIDI port with the same name as the exposed audio
|
||||
sub-device to which MIDI programs can connect.
|
||||
.Nm
|
||||
exposes the audio device clock
|
||||
and allows audio device properties to be controlled
|
||||
through MIDI.
|
||||
.Pp
|
||||
A MIDI channel is assigned to each stream, and the volume
|
||||
is changed using the standard volume controller (number 7).
|
||||
Similarly, when the audio client changes its volume,
|
||||
the same MIDI controller message is sent out; it can be used
|
||||
for instance for monitoring or as feedback for motorized
|
||||
faders.
|
||||
.Pp
|
||||
The master volume can be changed using the standard master volume
|
||||
system exclusive message.
|
||||
.Pp
|
||||
Streams created with the
|
||||
.Fl t
|
||||
option are controlled by the following MMC messages:
|
||||
.Bl -tag -width relocateXXX -offset indent
|
||||
.It relocate
|
||||
This message is ignored by audio
|
||||
.Nm
|
||||
clients, but the given time position is sent to MIDI ports as an MTC
|
||||
.Dq "full frame"
|
||||
message forcing all MTC-slaves to relocate to the given
|
||||
position (see below).
|
||||
.It start
|
||||
Put all streams in starting mode.
|
||||
In this mode,
|
||||
.Nm
|
||||
waits for all streams to become ready
|
||||
to start, and then starts them synchronously.
|
||||
Once started, new streams can be created
|
||||
.Pq Nm sndiod
|
||||
but they will be blocked
|
||||
until the next stop-to-start transition.
|
||||
.It stop
|
||||
Put all streams in stopped mode (the default).
|
||||
In this mode, any stream attempting to start playback or recording
|
||||
is paused.
|
||||
Client streams that are already
|
||||
started are not affected until they stop and try to start again.
|
||||
.El
|
||||
.Pp
|
||||
Streams created with the
|
||||
.Fl t
|
||||
option export the
|
||||
.Nm
|
||||
device clock using MTC, allowing non-audio
|
||||
software or hardware to be synchronized to the audio stream.
|
||||
Maximum accuracy is achieved when the number of blocks per
|
||||
second is equal to one of the standard MTC clock rates (96, 100 and 120Hz).
|
||||
The following sample rates
|
||||
.Pq Fl r
|
||||
and block sizes
|
||||
.Pq Fl z
|
||||
are recommended:
|
||||
.Pp
|
||||
.Bl -bullet -offset indent -compact
|
||||
.It
|
||||
44100Hz, 441 frames (MTC rate is 100Hz)
|
||||
.It
|
||||
48000Hz, 400 frames (MTC rate is 120Hz)
|
||||
.It
|
||||
48000Hz, 480 frames (MTC rate is 100Hz)
|
||||
.It
|
||||
48000Hz, 500 frames (MTC rate is 96Hz)
|
||||
.El
|
||||
.Pp
|
||||
For instance, the following command will create two devices:
|
||||
the default
|
||||
.Va snd/0
|
||||
and a MIDI-controlled
|
||||
.Va snd/0.mmc :
|
||||
.Bd -literal -offset indent
|
||||
$ sndiod -r 48000 -z 400 -s default -t slave -s mmc
|
||||
.Ed
|
||||
.Pp
|
||||
Streams connected to
|
||||
.Va snd/0
|
||||
behave normally, while streams connected to
|
||||
.Va snd/0.mmc
|
||||
wait for the MMC start signal and start synchronously.
|
||||
Regardless of which device a stream is connected to,
|
||||
its playback volume knob is exposed.
|
||||
.Sh EXAMPLES
|
||||
Start server using default parameters, creating an
|
||||
additional sub-device for output to channels 2:3 only (rear speakers
|
||||
on most cards), exposing the
|
||||
.Pa snd/0
|
||||
and
|
||||
.Pa snd/0.rear
|
||||
devices:
|
||||
.Bd -literal -offset indent
|
||||
$ sndiod -s default -c 2:3 -s rear
|
||||
.Ed
|
||||
.Pp
|
||||
Start server creating the default sub-device with low volume and
|
||||
an additional sub-device for high volume output, exposing the
|
||||
.Pa snd/0
|
||||
and
|
||||
.Pa snd/0.max
|
||||
devices:
|
||||
.Bd -literal -offset indent
|
||||
$ sndiod -v 65 -s default -v 127 -s max
|
||||
.Ed
|
||||
.Pp
|
||||
Start server configuring the audio device to use
|
||||
a 48kHz sample frequency, 240-frame block size,
|
||||
and 2-block buffers.
|
||||
The corresponding latency is 10ms, which is
|
||||
the time it takes the sound to propagate 3.5 meters.
|
||||
.Bd -literal -offset indent
|
||||
$ sndiod -r 48000 -b 480 -z 240
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr sndio 7
|
||||
.Sh BUGS
|
||||
Resampling is low quality; down-sampling especially should be avoided
|
||||
when recording.
|
||||
.Pp
|
||||
Processing is done using 16-bit arithmetic,
|
||||
thus samples with more than 16 bits are rounded.
|
||||
16 bits (i.e. 97dB dynamic) are largely enough for most applications though.
|
||||
Processing precision can be increased to 24-bit at compilation time though.
|
||||
.Pp
|
||||
If
|
||||
.Fl a Ar off
|
||||
is used,
|
||||
.Nm
|
||||
creates sub-devices to expose first
|
||||
and then opens the audio hardware on demand.
|
||||
Technically, this allows
|
||||
.Nm
|
||||
to attempt to use one of the sub-devices it exposes as an audio device,
|
||||
creating a deadlock.
|
||||
There's nothing to prevent the user
|
||||
from shooting himself in the foot by creating such a deadlock.
|
106
sndiod/sndiod.c
106
sndiod/sndiod.c
|
@ -14,7 +14,6 @@
|
|||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/queue.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/resource.h>
|
||||
|
@ -95,9 +94,9 @@ unsigned int opt_mode(void);
|
|||
void getbasepath(char *, size_t);
|
||||
void setsig(void);
|
||||
void unsetsig(void);
|
||||
void privdrop(void);
|
||||
struct dev *mkdev(char *, struct aparams *,
|
||||
int, int, int, int, int, int);
|
||||
struct port *mkport(char *, int);
|
||||
struct opt *mkopt(char *, struct dev *,
|
||||
int, int, int, int, int, int, int, int);
|
||||
|
||||
|
@ -244,11 +243,11 @@ unsetsig(void)
|
|||
sa.sa_flags = SA_RESTART;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
if (sigaction(SIGHUP, &sa, NULL) < 0)
|
||||
err(1, "unsetsig(hup): sigaction failed\n");
|
||||
err(1, "unsetsig(hup): sigaction failed");
|
||||
if (sigaction(SIGTERM, &sa, NULL) < 0)
|
||||
err(1, "unsetsig(term): sigaction failed\n");
|
||||
err(1, "unsetsig(term): sigaction failed");
|
||||
if (sigaction(SIGINT, &sa, NULL) < 0)
|
||||
err(1, "unsetsig(int): sigaction failed\n");
|
||||
err(1, "unsetsig(int): sigaction failed");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -256,7 +255,7 @@ getbasepath(char *base, size_t size)
|
|||
{
|
||||
uid_t uid;
|
||||
struct stat sb;
|
||||
mode_t mask;
|
||||
mode_t mask, omask;
|
||||
|
||||
uid = geteuid();
|
||||
if (uid == 0) {
|
||||
|
@ -266,31 +265,20 @@ getbasepath(char *base, size_t size)
|
|||
mask = 077;
|
||||
snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid);
|
||||
}
|
||||
if (mkdir(base, 0777 & ~mask) < 0) {
|
||||
omask = umask(mask);
|
||||
if (mkdir(base, 0777) < 0) {
|
||||
if (errno != EEXIST)
|
||||
err(1, "mkdir(\"%s\")", base);
|
||||
}
|
||||
umask(omask);
|
||||
if (stat(base, &sb) < 0)
|
||||
err(1, "stat(\"%s\")", base);
|
||||
if (!S_ISDIR(sb.st_mode))
|
||||
errx(1, "%s is not a directory", base);
|
||||
if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
|
||||
errx(1, "%s has wrong permissions", base);
|
||||
}
|
||||
|
||||
void
|
||||
privdrop(void)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
if ((pw = getpwnam(SNDIO_USER)) == NULL)
|
||||
errx(1, "unknown user %s", SNDIO_USER);
|
||||
if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0)
|
||||
err(1, "setpriority");
|
||||
if (setgroups(1, &pw->pw_gid) ||
|
||||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
|
||||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
|
||||
err(1, "cannot drop privileges");
|
||||
}
|
||||
|
||||
struct dev *
|
||||
mkdev(char *path, struct aparams *par,
|
||||
int mode, int bufsz, int round, int rate, int hold, int autovol)
|
||||
|
@ -339,7 +327,7 @@ mkopt(char *path, struct dev *d,
|
|||
o = opt_new(path, d, pmin, pmax, rmin, rmax,
|
||||
MIDI_TO_ADATA(vol), mmc, dup, mode);
|
||||
if (o == NULL)
|
||||
errx(1, "%s: couldn't create subdev", path);
|
||||
return NULL;
|
||||
dev_adjpar(d, o->mode, o->pmin, o->pmax, o->rmin, o->rmax);
|
||||
return o;
|
||||
}
|
||||
|
@ -350,14 +338,18 @@ main(int argc, char **argv)
|
|||
int c, background, unit;
|
||||
int pmin, pmax, rmin, rmax;
|
||||
char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
|
||||
char loc[32];
|
||||
unsigned int mode, dup, mmc, vol, i;
|
||||
unsigned int mode, dup, mmc, vol;
|
||||
unsigned int hold, autovol, bufsz, round, rate;
|
||||
const char *str;
|
||||
struct aparams par;
|
||||
struct dev *d;
|
||||
struct port *p;
|
||||
struct listen *l;
|
||||
struct passwd *pw;
|
||||
struct tcpaddr {
|
||||
char *host;
|
||||
struct tcpaddr *next;
|
||||
} *tcpaddr_list, *ta;
|
||||
|
||||
atexit(log_flush);
|
||||
|
||||
|
@ -380,25 +372,27 @@ main(int argc, char **argv)
|
|||
rmax = 1;
|
||||
aparams_init(&par);
|
||||
mode = MODE_PLAY | MODE_REC;
|
||||
tcpaddr_list = NULL;
|
||||
|
||||
setsig();
|
||||
filelist_init();
|
||||
|
||||
while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:Mq:r:s:t:U:v:w:x:z:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "a:b:c:C:de:f:j:L:m:q:r:s:t:U:v:w:x:z:")) != -1) {
|
||||
switch (c) {
|
||||
case 'd':
|
||||
log_level++;
|
||||
background = 0;
|
||||
break;
|
||||
case 'U':
|
||||
if (listen_list)
|
||||
errx(1, "-U must come before -L");
|
||||
unit = strtonum(optarg, 0, 15, &str);
|
||||
if (str)
|
||||
errx(1, "%s: unit number is %s", optarg, str);
|
||||
break;
|
||||
case 'L':
|
||||
listen_new_tcp(optarg, AUCAT_PORT + unit);
|
||||
ta = xmalloc(sizeof(struct tcpaddr));
|
||||
ta->host = optarg;
|
||||
ta->next = tcpaddr_list;
|
||||
tcpaddr_list = ta;
|
||||
break;
|
||||
case 'm':
|
||||
mode = opt_mode();
|
||||
|
@ -433,8 +427,9 @@ main(int argc, char **argv)
|
|||
d = mkdev(DEFAULT_DEV, &par, 0, bufsz, round,
|
||||
rate, hold, autovol);
|
||||
}
|
||||
mkopt(optarg, d, pmin, pmax, rmin, rmax,
|
||||
mode, vol, mmc, dup);
|
||||
if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
|
||||
mode, vol, mmc, dup) == NULL)
|
||||
return 1;
|
||||
break;
|
||||
case 'q':
|
||||
mkport(optarg, hold);
|
||||
|
@ -470,29 +465,33 @@ main(int argc, char **argv)
|
|||
fputs(usagestr, stderr);
|
||||
return 1;
|
||||
}
|
||||
if (dev_list == NULL) {
|
||||
for (i = 0; i < 4; i++) {
|
||||
snprintf(loc, sizeof(loc), "rsnd/%u", i);
|
||||
mkdev(loc, &par, 0, bufsz, round, rate, hold, autovol);
|
||||
}
|
||||
}
|
||||
if (port_list == NULL) {
|
||||
for (i = 0; i < 8; i++) {
|
||||
snprintf(loc, sizeof(loc), "rmidi/%u", i);
|
||||
mkport(loc, hold);
|
||||
}
|
||||
}
|
||||
if (dev_list == NULL)
|
||||
mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol);
|
||||
for (d = dev_list; d != NULL; d = d->next) {
|
||||
if (opt_byname("default", d->num))
|
||||
continue;
|
||||
mkopt("default", d, pmin, pmax, rmin, rmax,
|
||||
mode, vol, mmc, dup);
|
||||
if (mkopt("default", d, pmin, pmax, rmin, rmax,
|
||||
mode, vol, mmc, dup) == NULL)
|
||||
return 1;
|
||||
}
|
||||
getbasepath(base, sizeof(base));
|
||||
snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
|
||||
listen_new_un(path);
|
||||
if (geteuid() == 0)
|
||||
privdrop();
|
||||
if (!listen_new_un(path))
|
||||
return 1;
|
||||
for (ta = tcpaddr_list; ta != NULL; ta = ta->next) {
|
||||
if (!listen_new_tcp(ta->host, AUCAT_PORT + unit))
|
||||
return 1;
|
||||
}
|
||||
if (geteuid() == 0) {
|
||||
if ((pw = getpwnam(SNDIO_USER)) == NULL)
|
||||
errx(1, "unknown user %s", SNDIO_USER);
|
||||
if (setpriority(PRIO_PROCESS, 0, SNDIO_PRIO) < 0)
|
||||
err(1, "setpriority");
|
||||
if (setgroups(1, &pw->pw_gid) ||
|
||||
setgid(pw->pw_gid) ||
|
||||
setuid(pw->pw_uid))
|
||||
err(1, "cannot drop privileges");
|
||||
}
|
||||
midi_init();
|
||||
for (p = port_list; p != NULL; p = p->next) {
|
||||
if (!port_init(p))
|
||||
|
@ -512,10 +511,6 @@ main(int argc, char **argv)
|
|||
if (daemon(0, 0) < 0)
|
||||
err(1, "daemon");
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop, start audio.
|
||||
*/
|
||||
for (;;) {
|
||||
if (quit_flag)
|
||||
break;
|
||||
|
@ -539,8 +534,13 @@ main(int argc, char **argv)
|
|||
dev_del(dev_list);
|
||||
while (port_list)
|
||||
port_del(port_list);
|
||||
filelist_done();
|
||||
while (tcpaddr_list) {
|
||||
ta = tcpaddr_list;
|
||||
tcpaddr_list = ta->next;
|
||||
xfree(ta);
|
||||
}
|
||||
rmdir(base);
|
||||
filelist_done();
|
||||
unsetsig();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ sock_close(struct sock *f)
|
|||
}
|
||||
file_del(f->file);
|
||||
close(f->fd);
|
||||
file_slowaccept = 0;
|
||||
xfree(f);
|
||||
}
|
||||
|
||||
|
@ -350,7 +351,7 @@ sock_fdwrite(struct sock *f, void *data, int count)
|
|||
}
|
||||
sock_close(f);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
sock_log(f);
|
||||
log_puts(": write blocked\n");
|
||||
|
@ -391,7 +392,7 @@ sock_fdread(struct sock *f, void *data, int count)
|
|||
}
|
||||
sock_close(f);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
sock_log(f);
|
||||
log_puts(": read blocked\n");
|
||||
|
@ -1143,7 +1144,7 @@ sock_execmsg(struct sock *f)
|
|||
f->ralign = s->round * s->mix.bpf;
|
||||
}
|
||||
}
|
||||
slot_stop(s);
|
||||
slot_stop(s);
|
||||
break;
|
||||
case AMSG_SETPAR:
|
||||
#ifdef DEBUG
|
||||
|
@ -1241,7 +1242,7 @@ sock_execmsg(struct sock *f)
|
|||
f->rtodo = sizeof(struct amsg);
|
||||
f->rstate = SOCK_RMSG;
|
||||
f->lastvol = ctl; /* dont trigger feedback message */
|
||||
slot_setvol(f->slot, ctl);
|
||||
slot_setvol(s, ctl);
|
||||
dev_midi_vol(s->dev, s);
|
||||
dev_onctl(s->dev, s->dev->ctl_addr +
|
||||
CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl);
|
||||
|
@ -1439,7 +1440,7 @@ sock_buildmsg(struct sock *f)
|
|||
|
||||
if (f->fillpending > 0) {
|
||||
AMSG_INIT(&f->wmsg);
|
||||
f->wmsg.cmd = htonl(AMSG_FLOWCTL);
|
||||
f->wmsg.cmd = htonl(AMSG_FLOWCTL);
|
||||
f->wmsg.u.ts.delta = htonl(f->fillpending);
|
||||
size = f->fillpending;
|
||||
if (f->slot)
|
||||
|
@ -1483,7 +1484,7 @@ sock_buildmsg(struct sock *f)
|
|||
}
|
||||
|
||||
if (f->midi != NULL && f->midi->obuf.used > 0) {
|
||||
size = f->midi->obuf.used;
|
||||
size = f->midi->obuf.used;
|
||||
if (size > AMSG_DATAMAX)
|
||||
size = AMSG_DATAMAX;
|
||||
AMSG_INIT(&f->wmsg);
|
||||
|
|
|
@ -91,7 +91,7 @@ log_putx(unsigned long num)
|
|||
c += (c < 10) ? '0' : 'a' - 10;
|
||||
LOG_PUTC(c);
|
||||
}
|
||||
} else
|
||||
} else
|
||||
LOG_PUTC('0');
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ void *
|
|||
xmalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
|
||||
|
||||
p = malloc(size);
|
||||
if (p == NULL) {
|
||||
log_puts("failed to allocate ");
|
||||
|
@ -163,6 +163,12 @@ xmalloc(size_t size)
|
|||
void
|
||||
xfree(void *p)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (p == NULL) {
|
||||
log_puts("xfree with NULL arg\n");
|
||||
panic();
|
||||
}
|
||||
#endif
|
||||
free(p);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue