merge head

This commit is contained in:
Alexandre Ratchov 2016-01-26 10:23:38 +01:00
parent 7b062cf12f
commit 5dc67b663e
44 changed files with 544 additions and 948 deletions

View File

@ -14,7 +14,7 @@ LDADD = -lsndio @ldadd@
@vars@ @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}, ${MAN1_DIR}
# #
BIN_DIR = @bindir@ BIN_DIR = @bindir@
@ -45,7 +45,7 @@ clean:
OBJS = abuf.o afile.o aucat.o dsp.o utils.o OBJS = abuf.o afile.o aucat.o dsp.o utils.o
aucat: ${OBJS} aucat: ${OBJS}
${CC} ${LDFLAGS} ${LIB} -o aucat ${OBJS} ${LDADD} ${CC} ${LDFLAGS} ${LIB} -o aucat ${OBJS} ${LDADD}
.c.o: .c.o:
${CC} ${CFLAGS} ${INCLUDE} ${DEFS} -c $< ${CC} ${CFLAGS} ${INCLUDE} ${DEFS} -c $<

View File

@ -53,7 +53,7 @@ abuf_init(struct abuf *buf, unsigned int len)
void void
abuf_done(struct abuf *buf) abuf_done(struct abuf *buf)
{ {
#ifdef DEBUG #ifdef DEBUG
if (buf->used > 0) { if (buf->used > 0) {
if (log_level >= 3) { if (log_level >= 3) {
log_puts("deleting non-empty buffer, used = "); log_puts("deleting non-empty buffer, used = ");

View File

@ -563,7 +563,7 @@ afile_aiff_readhdr(struct afile *f)
log_puts(f->path); log_puts(f->path);
log_puts(": failed to read chunk header\n"); log_puts(": failed to read chunk header\n");
return 0; return 0;
} }
csize = be32_get(&chunk.size); csize = be32_get(&chunk.size);
if (memcmp(chunk.id, aiff_id_comm, 4) == 0) { if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
if (!afile_aiff_readcomm(f, csize, comp, &nfr)) 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) { } else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
if (!afile_aiff_readdata(f, csize, &offs)) if (!afile_aiff_readdata(f, csize, &offs))
return 0; return 0;
f->startpos = sizeof(form) + pos + sizeof(chunk) + offs; f->startpos = sizeof(form) + pos +
sizeof(chunk) + offs;
break; break;
} else { } else {
#ifdef DEBUG #ifdef DEBUG
@ -927,7 +928,8 @@ afile_open(struct afile *f, char *path, int hdr, int flags,
f->fd = STDOUT_FILENO; f->fd = STDOUT_FILENO;
} else { } else {
f->path = path; 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) { if (f->fd < 0) {
log_puts(f->path); log_puts(f->path);
log_puts(": failed to create file\n"); 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->par.msb = 1;
f->endpos = f->startpos = sizeof(struct aiff_hdr); f->endpos = f->startpos = sizeof(struct aiff_hdr);
f->maxpos = 0x7fffffff; f->maxpos = 0x7fffffff;
if (!afile_writehdr(f, &dummy, sizeof(struct aiff_hdr))) if (!afile_writehdr(f, &dummy,
sizeof(struct aiff_hdr)))
goto bad_close; goto bad_close;
} else if (f->hdr == AFILE_HDR_AU) { } else if (f->hdr == AFILE_HDR_AU) {
f->par.bits = (f->par.bits + 7) & ~7; f->par.bits = (f->par.bits + 7) & ~7;

View File

@ -87,7 +87,7 @@ Increase log verbosity.
Encoding of the audio file. Encoding of the audio file.
The default is The default is
.Va s16 . .Va s16 .
Encoding names use the follwing scheme: signedness Encoding names use the following scheme: signedness
.Po .Po
.Va s .Va s
or or
@ -223,7 +223,7 @@ back to the starting position.
.El .El
.Pp .Pp
MIDI control is intended to be used together with MIDI control is intended to be used together with
.Xr sndiod 1 . .Xr sndiod 8 .
For instance, the following command will create two devices: For instance, the following command will create two devices:
the default the default
.Va snd/0 .Va snd/0
@ -280,9 +280,9 @@ $ aucat -n -i stereo.wav -c 0:0 -o left.wav \e
.Xr audioctl 1 , .Xr audioctl 1 ,
.Xr cdio 1 , .Xr cdio 1 ,
.Xr mixerctl 1 , .Xr mixerctl 1 ,
.Xr sndiod 1 ,
.Xr audio 4 , .Xr audio 4 ,
.Xr sndio 7 .Xr sndio 7 ,
.Xr sndiod 8
.Sh BUGS .Sh BUGS
Resampling is low quality. Resampling is low quality.
.Pp .Pp

View File

@ -308,7 +308,8 @@ slot_init(struct slot *s)
s->cmin, s->cmax, s->cmin, s->cmax,
0, dev_pchan - 1, 0, dev_pchan - 1,
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); dec_init(&s->conv, &s->afile.par, slot_nch);
s->convbuf = s->convbuf =
xmalloc(s->round * slot_nch * sizeof(adata_t)); xmalloc(s->round * slot_nch * sizeof(adata_t));
@ -425,7 +426,7 @@ slot_del(struct slot *s)
xfree(s); xfree(s);
} }
static int static int
play_filt_resamp(struct slot *s, void *res_in, void *out, int todo) play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
{ {
int i, offs, vol, nch; int i, offs, vol, nch;
@ -455,7 +456,7 @@ play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
return todo; return todo;
} }
static int static int
play_filt_dec(struct slot *s, void *in, void *out, int todo) play_filt_dec(struct slot *s, void *in, void *out, int todo)
{ {
void *tmp; void *tmp;
@ -506,7 +507,7 @@ slot_mix_badd(struct slot *s, adata_t *odata)
return done; return done;
} }
static int static int
rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo) rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
{ {
int i, vol, offs, nch; int i, vol, offs, nch;
@ -535,7 +536,7 @@ rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
return todo; return todo;
} }
static int static int
rec_filt_enc(struct slot *s, void *in, void *out, int todo) rec_filt_enc(struct slot *s, void *in, void *out, int todo)
{ {
void *tmp; void *tmp;
@ -1032,7 +1033,8 @@ playrec_cycle(void)
n = sio_read(dev_sh, p, todo); n = sio_read(dev_sh, p, todo);
if (n == 0) { if (n == 0) {
log_puts(dev_name); log_puts(dev_name);
log_puts(": failed to read from device\n"); log_puts(": failed to read "
"from device\n");
return 0; return 0;
} }
p += n; p += n;
@ -1114,7 +1116,7 @@ playrec(char *dev, int mode, int bufsz, char *port)
continue; continue;
log_puts("poll failed\n"); log_puts("poll failed\n");
panic(); panic();
} }
if (dev_pstate == DEV_START) { if (dev_pstate == DEV_START) {
ev = sio_revents(dev_sh, pfds); ev = sio_revents(dev_sh, pfds);
if (ev & POLLHUP) { if (ev & POLLHUP) {
@ -1276,7 +1278,7 @@ main(int argc, char **argv)
port = NULL; port = NULL;
dev = NULL; dev = NULL;
mode = 0; mode = 0;
while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) { while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
@ -1359,7 +1361,7 @@ main(int argc, char **argv)
if (mode == 0) { if (mode == 0) {
log_puts("at least -i or -o required\n"); log_puts("at least -i or -o required\n");
return 1; return 1;
} }
if (!playrec(dev, mode, bufsz, port)) if (!playrec(dev, mode, bufsz, port))
return 1; return 1;
} }

View File

@ -222,7 +222,7 @@ aparams_strtoenc(struct aparams *par, char *istr)
return 0; return 0;
done: done:
par->msb = msb; par->msb = msb;
par->sig = sig; par->sig = sig;
par->bits = bits; par->bits = bits;
par->bps = bps; 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 * initialize resampler with ibufsz/obufsz factor and "nch" channels
*/ */
void 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; unsigned int i;
@ -516,7 +517,7 @@ enc_init(struct conv *p, struct aparams *par, int nch)
p->bias = (1U << 31) >> p->shift; p->bias = (1U << 31) >> p->shift;
} else { } else {
p->bias = 0; p->bias = 0;
} }
if (!par->le) { if (!par->le) {
p->bfirst = par->bps - 1; p->bfirst = par->bps - 1;
p->bnext = -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 * convert samples from ulaw/alaw to adata_t
*/ */
void 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 int f;
unsigned char *idata; unsigned char *idata;
@ -711,7 +713,7 @@ dec_init(struct conv *p, struct aparams *par, int nch)
p->bias = (1U << 31) >> p->shift; p->bias = (1U << 31) >> p->shift;
} else { } else {
p->bias = 0; p->bias = 0;
} }
if (par->le) { if (par->le) {
p->bfirst = par->bps - 1; p->bfirst = par->bps - 1;
p->bnext = -1; p->bnext = -1;

View File

@ -91,7 +91,7 @@ log_putx(unsigned long num)
c += (c < 10) ? '0' : 'a' - 10; c += (c < 10) ? '0' : 'a' - 10;
LOG_PUTC(c); LOG_PUTC(c);
} }
} else } else
LOG_PUTC('0'); LOG_PUTC('0');
} }

8
configure vendored
View File

@ -59,6 +59,14 @@ case `uname` in
so="$so libsndio.so" so="$so libsndio.so"
defs='-D_GNU_SOURCE -DDEV_RANDOM=\\"/dev/urandom\\"' 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) OpenBSD)
sun=yes sun=yes
rmidi=yes rmidi=yes

View File

@ -19,7 +19,7 @@
#include <stdint.h> #include <stdint.h>
/* /*
* unix-domain socket name is: * unix-domain socket name is:
* *
* DIR [ '-' UID ] '/' FILE UNIT * DIR [ '-' UID ] '/' FILE UNIT

View File

@ -468,15 +468,24 @@ parsestr(const char *str, char *rstr, unsigned int max)
} }
int int
_aucat_open(struct aucat *hdl, const char *str, unsigned int mode, _aucat_open(struct aucat *hdl, const char *str, unsigned int mode)
unsigned int type)
{ {
extern char *__progname; extern char *__progname;
int eof; int eof;
char host[NI_MAXHOST], opt[AMSG_OPTMAX]; char host[NI_MAXHOST], opt[AMSG_OPTMAX];
const char *p = str; const char *p;
unsigned int unit, devnum; 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 == '@') { if (*p == '@') {
p = parsestr(++p, host, NI_MAXHOST); p = parsestr(++p, host, NI_MAXHOST);
if (p == NULL) if (p == NULL)
@ -489,7 +498,7 @@ _aucat_open(struct aucat *hdl, const char *str, unsigned int mode,
return 0; return 0;
} else } else
unit = 0; unit = 0;
if (*p != '/' && *p != ':') { if (*p != '/') {
DPRINTF("%s: '/' expected\n", str); DPRINTF("%s: '/' expected\n", str);
return 0; return 0;
} }

View File

@ -21,7 +21,7 @@ int _aucat_rmsg(struct aucat *, int *);
int _aucat_wmsg(struct aucat *, int *); int _aucat_wmsg(struct aucat *, int *);
size_t _aucat_rdata(struct aucat *, void *, size_t, int *); size_t _aucat_rdata(struct aucat *, void *, size_t, int *);
size_t _aucat_wdata(struct aucat *, const void *, size_t, unsigned, 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); void _aucat_close(struct aucat *, int);
int _aucat_pollfd(struct aucat *, struct pollfd *, int); int _aucat_pollfd(struct aucat *, struct pollfd *, int);
int _aucat_revents(struct aucat *, struct pollfd *); int _aucat_revents(struct aucat *, struct pollfd *);

View File

@ -36,7 +36,6 @@ mio_open(const char *str, unsigned int mode, int nbio)
{ {
static char portany[] = MIO_PORTANY; static char portany[] = MIO_PORTANY;
struct mio_hdl *hdl; struct mio_hdl *hdl;
const char *p;
#ifdef DEBUG #ifdef DEBUG
_sndio_debug_init(); _sndio_debug_init();
@ -51,32 +50,28 @@ mio_open(const char *str, unsigned int mode, int nbio)
str = portany; str = portany;
} }
if (strcmp(str, portany) == 0) { if (strcmp(str, portany) == 0) {
hdl = _mio_aucat_open("/0", mode, nbio, 1); hdl = _mio_aucat_open("midithru/0", mode, nbio);
if (hdl != NULL) if (hdl != NULL)
return hdl; return hdl;
#if defined(USE_RMIDI) #if defined(USE_RMIDI)
return _mio_rmidi_open("/0", mode, nbio); return _mio_rmidi_open("rmidi/0", mode, nbio);
#elif defined(USE_ALSA) #elif defined(USE_ALSA)
return mio_alsa_open("/0", mode, nbio); return _mio_alsa_open("rmidi/0", mode, nbio);
#else #else
return NULL; return NULL;
#endif #endif
} }
if ((p = _sndio_parsetype(str, "snd")) != NULL || if (_sndio_parsetype(str, "snd") ||
(p = _sndio_parsetype(str, "aucat")) != NULL) _sndio_parsetype(str, "midithru") ||
return _mio_aucat_open(p, mode, nbio, 0); _sndio_parsetype(str, "midi"))
if ((p = _sndio_parsetype(str, "midithru")) != NULL) return _mio_aucat_open(str, mode, nbio);
return _mio_aucat_open(p, mode, nbio, 1); if (_sndio_parsetype(str, "rmidi"))
if ((p = _sndio_parsetype(str, "midi")) != NULL) #if defined(USE_RMIDI)
return _mio_aucat_open(p, mode, nbio, 2); return _mio_rmidi_open(str, mode, nbio);
#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);
#elif defined(USE_ALSA) #elif defined(USE_ALSA)
return mio_alsa_open(p, mode, nbio); return _mio_alsa_open(str, mode, nbio);
#endif #else
} return NULL;
#endif #endif
DPRINTF("mio_open: %s: unknown device type\n", str); DPRINTF("mio_open: %s: unknown device type\n", str);
return NULL; return NULL;

View File

@ -35,7 +35,7 @@
#ifdef DEBUG #ifdef DEBUG
static snd_output_t *output = NULL; 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 #else
#define DALSA(str, err) do {} while (0) #define DALSA(str, err) do {} while (0)
#endif #endif
@ -64,18 +64,24 @@ static struct mio_ops mio_alsa_ops = {
}; };
struct mio_hdl * 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; struct mio_alsa_hdl *hdl;
size_t len; size_t len;
int rc; 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 '/': case '/':
str++; p++;
break; break;
default: default:
DPRINTF("mio_alsa_open: %s: '/<devnum>' expected\n", str); DPRINTF("_mio_alsa_open: %s: '/' expected\n", _str);
return NULL; return NULL;
} }
hdl = malloc(sizeof(struct mio_alsa_hdl)); 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) if (rc < 0)
DALSA("couldn't attach to stderr", rc); DALSA("couldn't attach to stderr", rc);
#endif #endif
len = strlen(str); len = strlen(p);
hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX)); hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
if (hdl->devname == NULL) { if (hdl->devname == NULL) {
free(hdl); free(hdl);
return NULL; return NULL;
} }
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1); 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; hdl->in = hdl->out = NULL;
rc = snd_rawmidi_open(&hdl->in, &hdl->out, rc = snd_rawmidi_open(&hdl->in, &hdl->out,
hdl->devname, SND_RAWMIDI_NONBLOCK); hdl->devname, SND_RAWMIDI_NONBLOCK);

View File

@ -75,7 +75,8 @@ mio_aucat_runmsg(struct mio_aucat_hdl *hdl)
delta, hdl->aucat.maxwrite); delta, hdl->aucat.maxwrite);
break; break;
default: 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; hdl->mio.eof = 1;
return 0; return 0;
} }
@ -85,15 +86,14 @@ mio_aucat_runmsg(struct mio_aucat_hdl *hdl)
} }
struct mio_hdl * struct mio_hdl *
_mio_aucat_open(const char *str, unsigned int mode, _mio_aucat_open(const char *str, unsigned int mode, int nbio)
int nbio, unsigned int type)
{ {
struct mio_aucat_hdl *hdl; struct mio_aucat_hdl *hdl;
hdl = malloc(sizeof(struct mio_aucat_hdl)); hdl = malloc(sizeof(struct mio_aucat_hdl));
if (hdl == NULL) if (hdl == NULL)
return NULL; return NULL;
if (!_aucat_open(&hdl->aucat, str, mode, type)) if (!_aucat_open(&hdl->aucat, str, mode))
goto bad; goto bad;
_mio_create(&hdl->mio, &mio_aucat_ops, mode, nbio); _mio_create(&hdl->mio, &mio_aucat_ops, mode, nbio);
if (!_aucat_setfl(&hdl->aucat, 1, &hdl->mio.eof)) if (!_aucat_setfl(&hdl->aucat, 1, &hdl->mio.eof))

View File

@ -51,7 +51,7 @@ The
library allows user processes to access library allows user processes to access
.Xr midi 4 .Xr midi 4
hardware and hardware and
.Xr sndiod 1 .Xr sndiod 8
MIDI thru boxes and control ports in a uniform way. MIDI thru boxes and control ports in a uniform way.
.Ss Opening and closing an MIDI stream .Ss Opening and closing an MIDI stream
First the application must call the First the application must call the
@ -243,7 +243,7 @@ The debug level:
may be a value between 0 and 2. may be a value between 0 and 2.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sndiod 1 ,
.Xr poll 2 , .Xr poll 2 ,
.Xr midi 4 , .Xr midi 4 ,
.Xr sndio 7 .Xr sndio 7 ,
.Xr sndiod 8

View File

@ -45,9 +45,9 @@ struct mio_ops {
struct mio_hdl *_mio_rmidi_open(const char *, unsigned, int); struct mio_hdl *_mio_rmidi_open(const char *, unsigned, int);
#ifdef USE_ALSA #ifdef USE_ALSA
struct mio_hdl *mio_alsa_open(const char *, unsigned, int); struct mio_hdl *_mio_alsa_open(const char *, unsigned, int);
#endif #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_create(struct mio_hdl *, struct mio_ops *, unsigned, int);
void _mio_destroy(struct mio_hdl *); void _mio_destroy(struct mio_hdl *);

View File

@ -15,6 +15,7 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#ifdef USE_RMIDI
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -56,33 +57,34 @@ static struct mio_ops mio_rmidi_ops = {
mio_rmidi_revents mio_rmidi_revents
}; };
struct mio_hdl * static int
_mio_rmidi_open(const char *str, unsigned int mode, int nbio) mio_rmidi_getfd(const char *str, unsigned int mode, int nbio)
{ {
int fd, flags; const char *p;
struct mio_rmidi_hdl *hdl;
char path[DEVPATH_MAX]; char path[DEVPATH_MAX];
unsigned int devnum; 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 '/': case '/':
str++; p++;
break; break;
default: default:
DPRINTF("_mio_rmidi_open: %s: '/<devnum>' expected\n", str); DPRINTF("mio_rmidi_getfd: %s: '/' expected\n", str);
return NULL; return -1;
} }
str = _sndio_parsenum(str, &devnum, 255); p = _sndio_parsenum(p, &devnum, 255);
if (str == NULL || *str != '\0') { if (p == NULL || *p != '\0') {
DPRINTF("_mio_rmidi_open: can't determine device number\n"); DPRINTF("mio_rmidi_getfd: %s: number expected after '/'\n", str);
return NULL; 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); snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
if (mode == (MIO_OUT | MIO_IN)) if (mode == (MIO_IN | MIO_OUT))
flags = O_RDWR; flags = O_RDWR;
else else
flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY; 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) if (errno == EINTR)
continue; continue;
DPERROR(path); 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; hdl->fd = fd;
return (struct mio_hdl *)hdl; 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; return NULL;
} }
@ -147,7 +175,7 @@ mio_rmidi_write(struct mio_hdl *sh, const void *buf, size_t len)
DPERROR("mio_rmidi_write: write"); DPERROR("mio_rmidi_write: write");
hdl->mio.eof = 1; hdl->mio.eof = 1;
} }
return 0; return 0;
} }
return n; return n;
} }
@ -173,3 +201,4 @@ mio_rmidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
{ {
return pfd->revents; return pfd->revents;
} }
#endif /* defined USE_RMIDI */

View File

@ -45,7 +45,6 @@ sio_open(const char *str, unsigned int mode, int nbio)
{ {
static char devany[] = SIO_DEVANY; static char devany[] = SIO_DEVANY;
struct sio_hdl *hdl; struct sio_hdl *hdl;
const char *p;
#ifdef DEBUG #ifdef DEBUG
_sndio_debug_init(); _sndio_debug_init();
@ -60,29 +59,26 @@ sio_open(const char *str, unsigned int mode, int nbio)
str = devany; str = devany;
} }
if (strcmp(str, devany) == 0) { if (strcmp(str, devany) == 0) {
hdl = _sio_aucat_open("/0", mode, nbio); hdl = _sio_aucat_open("snd/0", mode, nbio);
if (hdl != NULL) if (hdl != NULL)
return hdl; return hdl;
#if defined(USE_SUN) #if defined(USE_SUN)
return _sio_sun_open("/0", mode, nbio); return _sio_sun_open("rsnd/0", mode, nbio);
#elif defined(USE_ALSA) #elif defined(USE_ALSA)
return _sio_alsa_open("/0", mode, nbio); return _sio_alsa_open("rsnd/0", mode, nbio);
#else #else
return NULL; return NULL;
#endif #endif
} }
if ((p = _sndio_parsetype(str, "snd")) != NULL || if (_sndio_parsetype(str, "snd"))
(p = _sndio_parsetype(str, "aucat")) != NULL) return _sio_aucat_open(str, mode, nbio);
return _sio_aucat_open(p, mode, nbio); if (_sndio_parsetype(str, "rsnd"))
#if defined(USE_ALSA) || defined(USE_SUN)
if ((p = _sndio_parsetype(str, "rsnd")) != NULL ||
(p = _sndio_parsetype(str, "sun")) != NULL) {
#if defined(USE_SUN) #if defined(USE_SUN)
return _sio_sun_open(p, mode, nbio); return _sio_sun_open(str, mode, nbio);
#elif defined(USE_ALSA) #elif defined(USE_ALSA)
return _sio_alsa_open(p, mode, nbio); return _sio_alsa_open(str, mode, nbio);
#endif #else
} return NULL;
#endif #endif
DPRINTF("sio_open: %s: unknown device type\n", str); DPRINTF("sio_open: %s: unknown device type\n", str);
return NULL; return NULL;
@ -169,7 +165,7 @@ sio_setpar(struct sio_hdl *hdl, struct sio_par *par)
return 0; return 0;
} }
if (par->__magic != SIO_PAR_MAGIC) { 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; hdl->eof = 1;
return 0; return 0;
} }
@ -452,7 +448,7 @@ sio_onmove(struct sio_hdl *hdl, void (*cb)(void *, int), void *addr)
#ifdef DEBUG #ifdef DEBUG
void void
_sio_printpos(struct sio_hdl *hdl) _sio_printpos(struct sio_hdl *hdl)
{ {
struct timespec ts; struct timespec ts;
long long rpos, rdiff; long long rpos, rdiff;
long long cpos, cdiff; long long cpos, cdiff;
@ -465,7 +461,7 @@ _sio_printpos(struct sio_hdl *hdl)
rround = hdl->par.round * rbpf; rround = hdl->par.round * rbpf;
wround = hdl->par.round * wbpf; wround = hdl->par.round * wbpf;
rpos = (hdl->mode & SIO_REC) ? rpos = (hdl->mode & SIO_REC) ?
hdl->cpos * rbpf - hdl->rused : 0; hdl->cpos * rbpf - hdl->rused : 0;
wpos = (hdl->mode & SIO_PLAY) ? wpos = (hdl->mode & SIO_PLAY) ?
hdl->cpos * wbpf + hdl->wused : 0; hdl->cpos * wbpf + hdl->wused : 0;

View File

@ -39,7 +39,7 @@
#ifdef DEBUG #ifdef DEBUG
static snd_output_t *output = NULL; 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 #else
#define DALSA(str, err) do {} while (0) #define DALSA(str, err) do {} while (0)
#endif #endif
@ -103,9 +103,9 @@ static unsigned int cap_rates[] = {
}; };
static snd_pcm_format_t cap_fmts[] = { static snd_pcm_format_t cap_fmts[] = {
/* XXX add s24le3 and s24be3 */ /* XXX add s24le3 and s24be3 */
SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE, SND_PCM_FORMAT_S32_LE, SND_PCM_FORMAT_S32_BE,
SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE, SND_PCM_FORMAT_S24_LE, SND_PCM_FORMAT_S24_BE,
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
SND_PCM_FORMAT_U8 SND_PCM_FORMAT_U8
}; };
@ -275,17 +275,23 @@ sio_alsa_enctofmt(struct sio_alsa_hdl *hdl, snd_pcm_format_t *rfmt,
struct sio_hdl * struct sio_hdl *
_sio_alsa_open(const char *str, unsigned mode, int nbio) _sio_alsa_open(const char *str, unsigned mode, int nbio)
{ {
const char *p;
struct sio_alsa_hdl *hdl; struct sio_alsa_hdl *hdl;
struct sio_par par; struct sio_par par;
size_t len; size_t len;
int err; 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 '/': case '/':
str++; p++;
break; break;
default: default:
DPRINTF("_sio_alsa_open: %s: '/<devnum>' expected\n", str); DPRINTF("_sio_alsa_open: %s: '/' expected\n", str);
return NULL; return NULL;
} }
hdl = malloc(sizeof(struct sio_alsa_hdl)); hdl = malloc(sizeof(struct sio_alsa_hdl));
@ -298,12 +304,12 @@ _sio_alsa_open(const char *str, unsigned mode, int nbio)
if (err < 0) if (err < 0)
DALSA("couldn't attach to stderr", err); DALSA("couldn't attach to stderr", err);
#endif #endif
len = strlen(str); len = strlen(p);
hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX)); hdl->devname = malloc(len + sizeof(DEVNAME_PREFIX));
if (hdl->devname == NULL) if (hdl->devname == NULL)
goto bad_free_hdl; goto bad_free_hdl;
memcpy(hdl->devname, DEVNAME_PREFIX, sizeof(DEVNAME_PREFIX) - 1); 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) { if (mode & SIO_PLAY) {
err = snd_pcm_open(&hdl->opcm, hdl->devname, err = snd_pcm_open(&hdl->opcm, hdl->devname,
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); 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 :) * 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; hdl->sio.par.bps * hdl->sio.par.rchan : 1;
wbpf = (hdl->sio.mode & SIO_PLAY) ? wbpf = (hdl->sio.mode & SIO_PLAY) ?
hdl->sio.par.bps * hdl->sio.par.pchan : 1; 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; clk = hdl->sio.cpos % hdl->sio.par.round;
rdrop = (clk * rbpf - hdl->sio.rused) % rround; 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) snd_pcm_uframes_t *round, unsigned int *periods)
{ {
static snd_pcm_format_t fmts[] = { 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_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_U24_LE, SND_PCM_FORMAT_U24_BE,
SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE, SND_PCM_FORMAT_S16_LE, SND_PCM_FORMAT_S16_BE,
SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE, SND_PCM_FORMAT_U16_LE, SND_PCM_FORMAT_U16_BE,
SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S8 SND_PCM_FORMAT_U8, SND_PCM_FORMAT_S8
}; };
int i, err, dir = 0; 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], sio_alsa_fmttopar(hdl, cap_fmts[i],
&cap->enc[i].bits, &cap->enc[i].bits,
&cap->enc[i].sig, &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].bps = SIO_BPS(cap->enc[0].bits);
cap->enc[i].msb = 1; 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); ofmt, orate, (unsigned int)oround, operiods);
DPRINTFN(2, "ifmt = %u, irate = %u, iround = %u, iperiods = %u\n", DPRINTFN(2, "ifmt = %u, irate = %u, iround = %u, iperiods = %u\n",
ifmt, irate, (unsigned int)iround, iperiods); ifmt, irate, (unsigned int)iround, iperiods);
if (ifmt != ofmt) { if (ifmt != ofmt) {
DPRINTF("play and rec formats differ\n"); DPRINTF("play and rec formats differ\n");
hdl->sio.eof = 1; hdl->sio.eof = 1;
@ -1116,7 +1122,7 @@ sio_alsa_revents(struct sio_hdl *sh, struct pollfd *pfd)
if (hdl->sio.eof) if (hdl->sio.eof)
return POLLHUP; return POLLHUP;
for (i = 0; i < hdl->onfds + hdl->infds; i++) { for (i = 0; i < hdl->onfds + hdl->infds; i++) {
DPRINTFN(4, "sio_alsa_revents: pfds[%d].revents = %x\n", DPRINTFN(4, "sio_alsa_revents: pfds[%d].revents = %x\n",
i, pfd[i].revents); i, pfd[i].revents);

View File

@ -125,7 +125,8 @@ sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
hdl->pstate = PSTATE_INIT; hdl->pstate = PSTATE_INIT;
break; break;
default: 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; hdl->sio.eof = 1;
return 0; return 0;
} }
@ -156,7 +157,7 @@ _sio_aucat_open(const char *str, unsigned int mode, int nbio)
hdl = malloc(sizeof(struct sio_aucat_hdl)); hdl = malloc(sizeof(struct sio_aucat_hdl));
if (hdl == NULL) if (hdl == NULL)
return NULL; return NULL;
if (!_aucat_open(&hdl->aucat, str, mode, 0)) { if (!_aucat_open(&hdl->aucat, str, mode)) {
free(hdl); free(hdl);
return NULL; return NULL;
} }

View File

@ -80,7 +80,7 @@ The
library allows user processes to access library allows user processes to access
.Xr audio 4 .Xr audio 4
hardware and the hardware and the
.Xr sndiod 1 .Xr sndiod 8
audio server in a uniform way. audio server in a uniform way.
.Ss Opening and closing an audio device .Ss Opening and closing an audio device
First the application must call the First the application must call the
@ -255,7 +255,7 @@ has been called,
must be called before parameters can be changed. must be called before parameters can be changed.
.Pp .Pp
If the device is exposed by the If the device is exposed by the
.Xr sndiod 1 .Xr sndiod 8
server, which is the default configuration, server, which is the default configuration,
a transparent emulation layer will a transparent emulation layer will
automatically be set up, and in this case any combination of 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. may be a value between 0 and 2.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sndiod 1 ,
.Xr audio 4 , .Xr audio 4 ,
.Xr sndio 7 , .Xr sndio 7 ,
.Xr sndiod 8 ,
.Xr audio 9 .Xr audio 9
.Sh BUGS .Sh BUGS
The The
@ -727,7 +727,7 @@ function will stop playback immediately.
If the application doesn't consume recorded data fast enough then If the application doesn't consume recorded data fast enough then
.Dq "control messages" .Dq "control messages"
from the from the
.Xr sndiod 1 .Xr sndiod 8
server are delayed and consequently server are delayed and consequently
.Fn sio_onmove .Fn sio_onmove
callback or volume changes may be delayed. callback or volume changes may be delayed.

View File

@ -330,46 +330,57 @@ sio_sun_getcap(struct sio_hdl *sh, struct sio_cap *cap)
#undef NRATES #undef NRATES
} }
struct sio_hdl * static int
_sio_sun_open(const char *str, unsigned int mode, int nbio) sio_sun_getfd(const char *str, unsigned int mode, int nbio)
{ {
int fd, flags, fullduplex; const char *p;
struct audio_info aui;
struct sio_sun_hdl *hdl;
struct sio_par par;
char path[DEVPATH_MAX]; char path[DEVPATH_MAX];
unsigned int devnum; 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 '/': case '/':
str++; p++;
break; break;
default: default:
DPRINTF("_sio_sun_open: %s: '/<devnum>' expected\n", str); DPRINTF("sio_sun_getfd: %s: '/' expected\n", str);
return NULL; return -1;
} }
str = _sndio_parsenum(str, &devnum, 255); p = _sndio_parsenum(p, &devnum, 255);
if (str == NULL || *str != '\0') { if (p == NULL || *p != '\0') {
DPRINTF("_sio_sun_open: can't determine device number\n"); DPRINTF("sio_sun_getfd: %s: number expected after '/'\n", str);
return NULL; 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); snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
if (mode == (SIO_PLAY | SIO_REC)) if (mode == (SIO_PLAY | SIO_REC))
flags = O_RDWR; flags = O_RDWR;
else else
flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY; flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY;
while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) { while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
if (errno == EINTR) if (errno == EINTR)
continue; continue;
DPERROR(path); 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 * pause the device
@ -381,18 +392,7 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
aui.record.pause = 1; aui.record.pause = 1;
if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) { if (ioctl(fd, AUDIO_SETINFO, &aui) < 0) {
DPERROR("sio_open_sun: setinfo"); DPERROR("sio_open_sun: setinfo");
goto bad_close; goto bad_free;
}
/*
* 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;
}
} }
hdl->fd = fd; hdl->fd = fd;
@ -410,16 +410,30 @@ _sio_sun_open(const char *str, unsigned int mode, int nbio)
par.bits = 16; par.bits = 16;
par.appbufsz = 1200; par.appbufsz = 1200;
if (!sio_setpar(&hdl->sio, &par)) if (!sio_setpar(&hdl->sio, &par))
goto bad_close; goto bad_free;
return (struct sio_hdl *)hdl; return (struct sio_hdl *)hdl;
bad_close:
while (close(fd) < 0 && errno == EINTR)
; /* retry */
bad_free: bad_free:
free(hdl); free(hdl);
return NULL; 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 static void
sio_sun_close(struct sio_hdl *sh) 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", DPRINTFN(2, "sio_sun_setpar: %i: trying pars = %u/%u/%u\n",
i, rate, prec, enc); 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)"); DPERROR("sio_sun_setpar: setinfo(pars)");
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
@ -567,7 +582,7 @@ sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
case AUDIO_ENCODING_ULINEAR: case AUDIO_ENCODING_ULINEAR:
break; break;
default: default:
DPRINTF("sio_sun_setpar: couldn't set linear encoding\n"); DPRINTF("sio_sun_setpar: couldn't find encoding\n");
hdl->sio.eof = 1; hdl->sio.eof = 1;
return 0; return 0;
} }
@ -658,7 +673,7 @@ sio_sun_setpar(struct sio_hdl *sh, struct sio_par *par)
} }
infr = aui.record.block_size / ibpf; infr = aui.record.block_size / ibpf;
onfr = aui.play.block_size / obpf; 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); 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"); DPERROR("sio_sun_write: write");
hdl->sio.eof = 1; hdl->sio.eof = 1;
} }
return 0; return 0;
} }
if (hdl->filling) { if (hdl->filling) {
if (!sio_sun_autostart(hdl)) 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; doerr = (ap.play_xrun - hdl->oerr) / hdl->obpf;
hdl->obytes = ap.play_pos; hdl->obytes = ap.play_pos;
hdl->oerr = ap.play_xrun; hdl->oerr = ap.play_xrun;
hdl->odelta += delta; hdl->odelta += delta;
if (!(hdl->sio.mode & SIO_REC)) { if (!(hdl->sio.mode & SIO_REC)) {
hdl->idelta += delta; hdl->idelta += delta;
dierr = doerr; dierr = doerr;

View File

@ -36,7 +36,6 @@ siomix_open(const char *str, unsigned int mode, int nbio)
{ {
static char devany[] = SIOMIX_DEVANY; static char devany[] = SIOMIX_DEVANY;
struct siomix_hdl *hdl; struct siomix_hdl *hdl;
const char *p;
#ifdef DEBUG #ifdef DEBUG
_sndio_debug_init(); _sndio_debug_init();
@ -49,27 +48,26 @@ siomix_open(const char *str, unsigned int mode, int nbio)
str = devany; str = devany;
} }
if (strcmp(str, devany) == 0) { if (strcmp(str, devany) == 0) {
hdl = _siomix_aucat_open("/0", mode, nbio); hdl = _siomix_aucat_open("snd/0", mode, nbio);
if (hdl != NULL) if (hdl != NULL)
return hdl; return hdl;
#if defined(USE_SUN_MIXER) #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) #elif defined(USE_ALSA_MIXER)
return _siomix_alsa_open("/0", mode, nbio); return _siomix_alsa_open("rsnd/0", mode, nbio);
#else #else
return NULL; return NULL;
#endif #endif
} }
if ((p = _sndio_parsetype(str, "snd")) != NULL) if (_sndio_parsetype(str, "snd"))
return _siomix_aucat_open(p, mode, nbio); return _siomix_aucat_open(str, mode, nbio);
#if defined(USE_ALSA_MIXER) || defined(USE_SUN_MIXER) if (_sndio_parsetype(str, "rsnd"))
if ((p = _sndio_parsetype(str, "rsnd")) != NULL) {
#if defined(USE_SUN_MIXER) #if defined(USE_SUN_MIXER)
return _siomix_sun_open(p, mode, nbio); return _siomix_sun_open(str, mode, nbio);
#elif defined(USE_ALSA_MIXER) #elif defined(USE_ALSA_MIXER)
return _siomix_alsa_open(p, mode, nbio); return _siomix_alsa_open(str, mode, nbio);
#endif #else
} return NULL;
#endif #endif
DPRINTF("siomix_open: %s: unknown device type\n", str); DPRINTF("siomix_open: %s: unknown device type\n", str);
return NULL; return NULL;

View File

@ -143,7 +143,7 @@ _siomix_aucat_open(const char *str, unsigned int mode, int nbio)
hdl = malloc(sizeof(struct siomix_aucat_hdl)); hdl = malloc(sizeof(struct siomix_aucat_hdl));
if (hdl == NULL) if (hdl == NULL)
return NULL; return NULL;
if (!_aucat_open(&hdl->aucat, str, mode, 0)) { if (!_aucat_open(&hdl->aucat, str, mode)) {
free(hdl); free(hdl);
return NULL; return NULL;
} }

View File

@ -32,8 +32,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include "debug.h" #include "debug.h"
#include "siomix_priv.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 SUN_TO_SIOMIX(v) (((v) * 127 + 127) / 255)
#define SIOMIX_TO_SUN(v) (((v) * 255 + 63) / 127) #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; return 1;
} }
struct siomix_hdl * static int
_siomix_sun_open(const char *str, unsigned int mode, int nbio) siomix_sun_getfd(const char *str, unsigned int mode, int nbio)
{ {
struct siomix_sun_hdl *hdl; const char *p;
char path[PATH_MAX]; char path[DEVPATH_MAX];
int flags; unsigned int devnum;
int fd, flags;
if (*str != '/') { p = _sndio_parsetype(str, "rsnd");
DPRINTF("siomix_sun_open: %s: '/<devnum>' expected\n", str); if (p == NULL) {
return NULL; DPRINTF("siomix_sun_getfd: %s: \"rsnd\" expected\n", str);
return -1;
} }
str++; switch (*p) {
hdl = malloc(sizeof(struct siomix_sun_hdl)); case '/':
if (hdl == NULL) p++;
return NULL; break;
_siomix_create(&hdl->siomix, &siomix_sun_ops, mode, nbio); default:
snprintf(path, sizeof(path), "/dev/mixer%s", str); 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)) if (mode == (SIOMIX_READ | SIOMIX_WRITE))
flags = O_RDWR; flags = O_RDWR;
else else
flags = (mode & SIOMIX_WRITE) ? O_WRONLY : O_RDONLY; 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) if (errno == EINTR)
continue; continue;
DPERROR(path); DPERROR(path);
free(hdl); return -1;
return NULL;
} }
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); init(hdl);
return (struct siomix_hdl *)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 static void
siomix_sun_close(struct siomix_hdl *addr) siomix_sun_close(struct siomix_hdl *addr)
{ {

View File

@ -25,7 +25,7 @@ The
.Nm sndio .Nm sndio
audio and MIDI system provides access to audio and MIDI hardware and audio and MIDI system provides access to audio and MIDI hardware and
to services provided by to services provided by
.Xr sndiod 1 , .Xr sndiod 8 ,
summarized below. summarized below.
.Pp .Pp
Hardware Hardware
@ -38,7 +38,7 @@ audio programs.
.Pp .Pp
To overcome hardware limitations and to allow multiple applications To overcome hardware limitations and to allow multiple applications
to share the hardware, to share the hardware,
.Xr sndiod 1 .Xr sndiod 8
can be used. can be used.
It exposes one or more software sub-devices backed by the underlying hardware, It exposes one or more software sub-devices backed by the underlying hardware,
while doing all necessary conversions on the fly. 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 applications connected to the thru box (for instance a software sequencer
can send events to multiple software synthesizers). can send events to multiple software synthesizers).
There's no hardware involved: thru boxes are created by There's no hardware involved: thru boxes are created by
.Xr sndiod 1 . .Xr sndiod 8 .
.Pp .Pp
Additionally, Additionally,
.Xr sndiod 1 .Xr sndiod 8
exposes a MIDI port used to control and monitor audio streams exposes a MIDI port used to control and monitor audio streams
in real time using MIDI. in real time using MIDI.
.Sh DEVICE NAMES .Sh DEVICE NAMES
From the user's perspective every audio interface, MIDI port, and From the user's perspective every audio interface, MIDI port, and
.Xr sndiod 1 .Xr sndiod 8
service has a name of the form: service has a name of the form:
.Bd -literal -offset center .Bd -literal -offset center
type[@hostname][,unit]/devnum[.option] type[@hostname][,unit]/devnum[.option]
@ -89,36 +89,36 @@ Raw
port. port.
.It Pa snd .It Pa snd
Audio device exposed by Audio device exposed by
.Xr sndiod 1 . .Xr sndiod 8 .
.It Pa midithru .It Pa midithru
MIDI thru box created with MIDI thru box created with
.Xr sndiod 1 . .Xr sndiod 8 .
.It Pa midi .It Pa midi
MIDI port exposed by MIDI port exposed by
.Xr sndiod 1 . .Xr sndiod 8 .
.It Pa default .It Pa default
Default audio device or MIDI port (see below). Default audio device or MIDI port (see below).
.El .El
.It Pa hostname .It Pa hostname
The hostname or address where the remote The hostname or address where the remote
.Xr sndiod 1 .Xr sndiod 8
server to connect to is running. server to connect to is running.
.It Pa unit .It Pa unit
The number of the The number of the
.Xr sndiod 1 .Xr sndiod 8
server to connect to, corresponding to the integer specified using the server to connect to, corresponding to the integer specified using the
.Fl U .Fl U
option of option of
.Xr sndiod 1 . .Xr sndiod 8 .
Useful only if multiple Useful only if multiple
.Xr sndiod 1 .Xr sndiod 8
servers are running on the same system. servers are running on the same system.
.It Pa devnum .It Pa devnum
Device number. Device number.
For hardware audio or MIDI ports, this corresponds to For hardware audio or MIDI ports, this corresponds to
the character device minor number. the character device minor number.
For audio devices or MIDI ports created with For audio devices or MIDI ports created with
.Xr sndiod 1 .Xr sndiod 8
it corresponds to the number of the corresponding it corresponds to the number of the corresponding
.Fl fq .Fl fq
option on the command line. option on the command line.
@ -126,7 +126,7 @@ option on the command line.
Corresponds to the sub-device string registered using the Corresponds to the sub-device string registered using the
.Fl s .Fl s
option of option of
.Xr sndiod 1 . .Xr sndiod 8 .
.El .El
.Pp .Pp
For example: For example:
@ -138,13 +138,13 @@ First hardware audio device.
Hardware MIDI port number 5. Hardware MIDI port number 5.
.It Pa snd/0 .It Pa snd/0
First audio device exposed by First audio device exposed by
.Xr sndiod 1 . .Xr sndiod 8 .
.It Pa snd/0.rear .It Pa snd/0.rear
Sub-device registered with Sub-device registered with
.Fl s Fa rear . .Fl s Fa rear .
.It Pa midithru/0 .It Pa midithru/0
First MIDI thru box created with First MIDI thru box created with
.Xr sndiod 1 . .Xr sndiod 8 .
.El .El
.Sh DEFAULTS .Sh DEFAULTS
If 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 If that fails, it then tries to use
.Pa rsnd/0 . .Pa rsnd/0 .
This allows the This allows the
.Xr sndiod 1 .Xr sndiod 8
audio server to be used by default and the bare hardware as fallback; audio server to be used by default and the bare hardware as fallback;
programs don't have to be reconfigured when programs don't have to be reconfigured when
.Xr sndiod 1 .Xr sndiod 8
is started or stopped. is started or stopped.
.Pp .Pp
If 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 If that fails, it then tries to use
.Pa rmidi/0 . .Pa rmidi/0 .
As long as As long as
.Xr sndiod 1 .Xr sndiod 8
is running, this allows programs to exchange MIDI data on is running, this allows programs to exchange MIDI data on
machines with no MIDI hardware by default, e.g. a MIDI player machines with no MIDI hardware by default, e.g. a MIDI player
could use a software synthesizer with no manual configuration could use a software synthesizer with no manual configuration
required. required.
.Sh AUTHENTICATION .Sh AUTHENTICATION
If a shared If a shared
.Xr sndiod 1 .Xr sndiod 8
server is running, for privacy reasons only one user may have server is running, for privacy reasons only one user may have
connections to it at a given time connections to it at a given time
(though the same user could have multiple connections to it). (though the same user could have multiple connections to it).
@ -216,8 +216,8 @@ Audio devices.
MIDI ports. MIDI ports.
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr sndiod 1 ,
.Xr mio_open 3 , .Xr mio_open 3 ,
.Xr sio_open 3 , .Xr sio_open 3 ,
.Xr audio 4 , .Xr audio 4 ,
.Xr midi 4 .Xr midi 4 ,
.Xr sndiod 8

View File

@ -14,29 +14,29 @@ LDADD = -lsndio @ldadd@
@vars@ @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}, ${MAN8_DIR}
# #
BIN_DIR = @bindir@ BIN_DIR = @bindir@
MAN1_DIR = @mandir@/man1 MAN8_DIR = @mandir@/man8
# #
# programs to build # programs to build
# #
PROG = sndiod PROG = sndiod
MAN1 = sndiod.1 MAN8 = sndiod.8
all: ${PROG} ${MAN1} all: ${PROG}
install: install:
mkdir -p ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN1_DIR} mkdir -p ${DESTDIR}${BIN_DIR} ${DESTDIR}${MAN8_DIR}
rm -f ${DESTDIR}${BIN_DIR}/${PROG} ${DESTDIR}${MAN1_DIR}/${MAN1} rm -f ${DESTDIR}${BIN_DIR}/${PROG} ${DESTDIR}${MAN8_DIR}/${MAN8}
cp ${PROG} ${DESTDIR}${BIN_DIR} cp ${PROG} ${DESTDIR}${BIN_DIR}
cp ${MAN1} ${DESTDIR}${MAN1_DIR} cp ${MAN8} ${DESTDIR}${MAN8_DIR}
uninstall: uninstall:
cd ${DESTDIR}${BIN_DIR} && rm -f ${PROG} cd ${DESTDIR}${BIN_DIR} && rm -f ${PROG}
cd ${DESTDIR}${MAN1_DIR} && rm -f ${MAN1} cd ${DESTDIR}${MAN8_DIR} && rm -f ${MAN8}
clean: clean:
rm -f -- *.o ${PROG} rm -f -- *.o ${PROG}

View File

@ -53,7 +53,7 @@ abuf_init(struct abuf *buf, unsigned int len)
void void
abuf_done(struct abuf *buf) abuf_done(struct abuf *buf)
{ {
#ifdef DEBUG #ifdef DEBUG
if (buf->used > 0) { if (buf->used > 0) {
if (log_level >= 3) { if (log_level >= 3) {
log_puts("deleting non-empty buffer, used = "); log_puts("deleting non-empty buffer, used = ");

View File

@ -557,12 +557,12 @@ slot_skip(struct slot *s)
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY) {
abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf); abuf_rdiscard(&s->mix.buf, s->round * s->mix.bpf);
} }
s->skip--; s->skip--;
} }
return max - s->skip; return max - s->skip;
} }
int int
play_filt_resamp(struct slot *s, void *res_in, void *out, int todo) play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
{ {
int i, offs, vol, nch; int i, offs, vol, nch;
@ -592,7 +592,7 @@ play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
return todo; return todo;
} }
int int
play_filt_dec(struct slot *s, void *in, void *out, int todo) play_filt_dec(struct slot *s, void *in, void *out, int todo)
{ {
void *tmp; 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) rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
{ {
int i, vol, offs, nch; int i, vol, offs, nch;
@ -702,7 +702,7 @@ rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
return todo; return todo;
} }
int int
rec_filt_enc(struct slot *s, void *in, void *out, int todo) rec_filt_enc(struct slot *s, void *in, void *out, int todo)
{ {
void *tmp; void *tmp;
@ -857,11 +857,11 @@ dev_cycle(struct dev *d)
dev_mix_adjvol(d); dev_mix_adjvol(d);
continue; continue;
} }
/* /*
* check for xruns * check for xruns
*/ */
if (((s->mode & MODE_PLAY) && if (((s->mode & MODE_PLAY) &&
s->mix.buf.used < s->round * s->mix.bpf) || s->mix.buf.used < s->round * s->mix.bpf) ||
((s->mode & MODE_RECMASK) && ((s->mode & MODE_RECMASK) &&
s->sub.buf.len - s->sub.buf.used < s->sub.buf.len - s->sub.buf.used <
@ -927,7 +927,7 @@ void
dev_onmove(struct dev *d, int delta) dev_onmove(struct dev *d, int delta)
{ {
long long pos; long long pos;
struct slot *s, *snext; struct slot *s, *snext;
d->delta += delta; d->delta += delta;
@ -1256,6 +1256,8 @@ dev_done(struct dev *d)
log_puts(": draining\n"); log_puts(": draining\n");
} }
#endif #endif
if (d->tstate != MMC_STOP)
dev_mmcstop(d);
if (d->hold) if (d->hold)
dev_unref(d); dev_unref(d);
} }
@ -1266,7 +1268,7 @@ dev_bynum(int num)
struct dev *d; struct dev *d;
for (d = dev_list; d != NULL; d = d->next) { for (d = dev_list; d != NULL; d = d->next) {
if (num-- == 0) if (d->num == num)
return d; return d;
} }
return NULL; return NULL;
@ -1327,11 +1329,11 @@ dev_wakeup(struct dev *d)
} }
d->poffs = 0; d->poffs = 0;
/* /*
* empty cycles don't increment delta, so it's ok to * empty cycles don't increment delta, so it's ok to
* start at 0 * start at 0
**/ **/
d->delta = 0; d->delta = 0;
d->pstate = DEV_RUN; d->pstate = DEV_RUN;
dev_sio_start(d); dev_sio_start(d);
@ -1650,7 +1652,7 @@ slot_attach(struct slot *s)
* start the device if not started * start the device if not started
*/ */
dev_wakeup(d); dev_wakeup(d);
/* /*
* get the current position, the origin is when the first sample * get the current position, the origin is when the first sample
* played and/or recorded * played and/or recorded
@ -1684,7 +1686,7 @@ slot_attach(struct slot *s)
#ifdef DEBUG #ifdef DEBUG
if ((s->mode & d->mode) != s->mode) { if ((s->mode & d->mode) != s->mode) {
slot_log(s); slot_log(s);
log_puts(": mode beyond device mode, not attaching\n"); log_puts(": mode beyond device mode, not attaching\n");
panic(); panic();
} }
#endif #endif
@ -1752,7 +1754,7 @@ slot_attach(struct slot *s)
s->sub.encbuf = s->sub.encbuf =
xmalloc(s->round * slot_nch * sizeof(adata_t)); xmalloc(s->round * slot_nch * sizeof(adata_t));
} }
/* /*
* N-th recorded block is the N-th played block * 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 * device may be disconnected, and if so we're called from
* slot->ops->exit() on a closed device * slot->ops->exit() on a closed device
*/ */
if (s->dev->pstate == DEV_CFG) if (s->dev->pstate == DEV_CFG)
return; return;
if (s->tstate == MMC_OFF) if (s->tstate == MMC_OFF)
@ -1811,7 +1813,7 @@ slot_start(struct slot *s)
log_puts("\n"); log_puts("\n");
} }
#endif #endif
s->mix.bpf = s->par.bps * s->mix.bpf = s->par.bps *
(s->mix.slot_cmax - s->mix.slot_cmin + 1); (s->mix.slot_cmax - s->mix.slot_cmin + 1);
abuf_init(&s->mix.buf, bufsz * s->mix.bpf); abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
} }
@ -1826,7 +1828,7 @@ slot_start(struct slot *s)
log_puts("\n"); log_puts("\n");
} }
#endif #endif
s->sub.bpf = s->par.bps * s->sub.bpf = s->par.bps *
(s->sub.slot_cmax - s->sub.slot_cmin + 1); (s->sub.slot_cmax - s->sub.slot_cmin + 1);
abuf_init(&s->sub.buf, bufsz * s->sub.bpf); abuf_init(&s->sub.buf, bufsz * s->sub.bpf);
} }
@ -1871,7 +1873,7 @@ slot_detach(struct slot *s)
panic(); panic();
} }
#endif #endif
} }
*ps = s->next; *ps = s->next;
if (s->mode & MODE_RECMASK) { if (s->mode & MODE_RECMASK) {
if (s->sub.encbuf) if (s->sub.encbuf)

View File

@ -46,7 +46,7 @@ struct slot {
void *arg; /* user data for callbacks */ void *arg; /* user data for callbacks */
struct aparams par; /* socket side params */ struct aparams par; /* socket side params */
struct { struct {
int weight; /* dynamic range */ int weight; /* dynamic range */
int maxweight; /* max dynamic range allowed */ int maxweight; /* max dynamic range allowed */
unsigned int vol; /* volume within the vol */ unsigned int vol; /* volume within the vol */
struct abuf buf; /* socket side buffer */ struct abuf buf; /* socket side buffer */
@ -140,7 +140,7 @@ struct dev {
/* /*
* audio device (while opened) * audio device (while opened)
*/ */
struct dev_sio sio; struct dev_sio sio;
struct dev_siomix siomix; struct dev_siomix siomix;
struct aparams par; /* encoding */ struct aparams par; /* encoding */

View File

@ -152,7 +152,7 @@ aparams_strtoenc(struct aparams *par, char *istr)
return 0; return 0;
done: done:
par->msb = msb; par->msb = msb;
par->sig = sig; par->sig = sig;
par->bits = bits; par->bits = bits;
par->bps = bps; 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 * initialize resampler with ibufsz/obufsz factor and "nch" channels
*/ */
void 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; unsigned int i;
@ -446,7 +447,7 @@ enc_init(struct conv *p, struct aparams *par, int nch)
p->bias = (1U << 31) >> p->shift; p->bias = (1U << 31) >> p->shift;
} else { } else {
p->bias = 0; p->bias = 0;
} }
if (!par->le) { if (!par->le) {
p->bfirst = par->bps - 1; p->bfirst = par->bps - 1;
p->bnext = -1; p->bnext = -1;
@ -539,7 +540,7 @@ dec_init(struct conv *p, struct aparams *par, int nch)
p->bias = (1U << 31) >> p->shift; p->bias = (1U << 31) >> p->shift;
} else { } else {
p->bias = 0; p->bias = 0;
} }
if (par->le) { if (par->le) {
p->bfirst = par->bps - 1; p->bfirst = par->bps - 1;
p->bnext = -1; p->bnext = -1;

View File

@ -105,9 +105,9 @@ typedef int adata_t;
struct aparams { struct aparams {
unsigned int bps; /* bytes per sample */ unsigned int bps; /* bytes per sample */
unsigned int bits; /* actually used bits */ 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 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 { struct resamp {
@ -124,7 +124,7 @@ struct conv {
int bfirst; /* bytes to skip at startup */ int bfirst; /* bytes to skip at startup */
unsigned int bps; /* bytes per sample */ unsigned int bps; /* bytes per sample */
unsigned int shift; /* shift to get 32bit MSB */ 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 bnext; /* to reach the next byte */
int snext; /* to reach the next sample */ int snext; /* to reach the next sample */
int nch; int nch;

View File

@ -46,7 +46,6 @@
#include <sys/types.h> #include <sys/types.h>
#include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
@ -259,7 +258,7 @@ file_del(struct file *f)
log_puts("bad state in file_del()\n"); log_puts("bad state in file_del()\n");
panic(); panic();
} }
#endif #endif
file_nfds -= f->max_nfds; file_nfds -= f->max_nfds;
f->state = FILE_ZOMB; f->state = FILE_ZOMB;
#ifdef DEBUG #ifdef DEBUG
@ -283,7 +282,7 @@ file_process(struct file *f, struct pollfd *pfd)
if (log_level >= 3) if (log_level >= 3)
clock_gettime(CLOCK_MONOTONIC, &ts0); clock_gettime(CLOCK_MONOTONIC, &ts0);
#endif #endif
revents = (f->state != FILE_ZOMB) ? revents = (f->state != FILE_ZOMB) ?
f->ops->revents(f->arg, pfd) : 0; f->ops->revents(f->arg, pfd) : 0;
if ((revents & POLLHUP) && (f->state != FILE_ZOMB)) if ((revents & POLLHUP) && (f->state != FILE_ZOMB))
f->ops->hup(f->arg); f->ops->hup(f->arg);
@ -399,8 +398,10 @@ file_poll(void)
timo = -1; timo = -1;
res = poll(pfds, nfds, timo); res = poll(pfds, nfds, timo);
if (res < 0) { if (res < 0) {
if (errno != EINTR) if (errno != EINTR) {
err(1, "poll"); log_puts("poll failed");
panic();
}
return 1; return 1;
} }
@ -412,19 +413,17 @@ file_poll(void)
file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec); file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
file_wtime += ts.tv_nsec - sleepts.tv_nsec; file_wtime += ts.tv_nsec - sleepts.tv_nsec;
#endif #endif
delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec); if (timo_queue) {
delta_nsec += ts.tv_nsec - file_ts.tv_nsec; delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
#ifdef DEBUG delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
if (delta_nsec < 0) if (delta_nsec >= 0 && delta_nsec < 60000000000LL)
log_puts("file_poll: negative time interval\n"); timo_update(delta_nsec / 1000);
#endif else {
file_ts = ts; if (log_level >= 2)
if (delta_nsec >= 0 && delta_nsec < 1000000000LL) log_puts("out-of-bounds clock delta\n");
timo_update(delta_nsec / 1000); }
else {
if (log_level >= 2)
log_puts("ignored huge clock delta\n");
} }
file_ts = ts;
/* /*
* process files that rely on poll * process files that rely on poll
@ -444,15 +443,14 @@ filelist_init(void)
{ {
sigset_t set; 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) { if (clock_gettime(CLOCK_MONOTONIC, &file_ts) < 0) {
perror("clock_gettime"); log_puts("filelist_init: CLOCK_MONOTONIC unsupported\n");
exit(1); panic();
} }
sigemptyset(&set);
sigaddset(&set, SIGPIPE);
sigprocmask(SIG_BLOCK, &set, NULL);
file_list = NULL;
log_sync = 0; log_sync = 0;
timo_init(); timo_init();
} }

View File

@ -34,7 +34,7 @@ struct fileops {
char *name; char *name;
int (*pollfd)(void *, struct pollfd *); int (*pollfd)(void *, struct pollfd *);
int (*revents)(void *, struct pollfd *); int (*revents)(void *, struct pollfd *);
/* /*
* we have to handle POLLIN and POLLOUT events * we have to handle POLLIN and POLLOUT events
* in separate handles, since handling POLLIN can * in separate handles, since handling POLLIN can
* close the file, and continuing (to handle POLLOUT) * close the file, and continuing (to handle POLLOUT)
@ -52,7 +52,7 @@ struct file {
#define FILE_INIT 0 /* ready */ #define FILE_INIT 0 /* ready */
#define FILE_ZOMB 1 /* closed, but not free()d yet */ #define FILE_ZOMB 1 /* closed, but not free()d yet */
unsigned int state; /* one of above */ 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 */ unsigned int nfds; /* number of descriptors polled */
char *name; /* for debug purposes */ char *name; /* for debug purposes */
}; };

View File

@ -24,12 +24,10 @@
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <netdb.h> #include <netdb.h>
#include <err.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <poll.h> #include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -80,7 +78,7 @@ listen_close(struct listen *f)
xfree(f); xfree(f);
} }
void int
listen_new_un(char *path) listen_new_un(char *path)
{ {
int sock, oldumask; int sock, oldumask;
@ -89,11 +87,13 @@ listen_new_un(char *path)
sock = socket(AF_UNIX, SOCK_STREAM, 0); sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) { if (sock < 0) {
perror("socket"); log_puts(path);
exit(1); log_puts(": failed to create socket\n");
return 0;
} }
if (unlink(path) < 0 && errno != ENOENT) { if (unlink(path) < 0 && errno != ENOENT) {
perror("unlink"); log_puts(path);
log_puts(": failed to unlink socket\n");
goto bad_close; goto bad_close;
} }
sockname.sun_family = AF_UNIX; sockname.sun_family = AF_UNIX;
@ -101,11 +101,13 @@ listen_new_un(char *path)
oldumask = umask(0111); oldumask = umask(0111);
if (bind(sock, (struct sockaddr *)&sockname, if (bind(sock, (struct sockaddr *)&sockname,
sizeof(struct sockaddr_un)) < 0) { sizeof(struct sockaddr_un)) < 0) {
perror("bind"); log_puts(path);
log_puts(": failed to bind socket\n");
goto bad_close; goto bad_close;
} }
if (listen(sock, 1) < 0) { if (listen(sock, 1) < 0) {
perror("listen"); log_puts(path);
log_puts(": failed to listen\n");
goto bad_close; goto bad_close;
} }
umask(oldumask); umask(oldumask);
@ -114,29 +116,25 @@ listen_new_un(char *path)
if (f->file == NULL) if (f->file == NULL)
goto bad_close; goto bad_close;
f->path = xstrdup(path); f->path = xstrdup(path);
if (f->path == NULL) {
perror("strdup");
exit(1);
}
f->fd = sock; f->fd = sock;
f->next = listen_list; f->next = listen_list;
listen_list = f; listen_list = f;
return; return 1;
bad_close: bad_close:
close(sock); close(sock);
exit(1); return 0;
} }
void int
listen_new_tcp(char *addr, unsigned int port) listen_new_tcp(char *addr, unsigned int port)
{ {
char *host, serv[sizeof(unsigned int) * 3 + 1]; char *host, serv[sizeof(unsigned int) * 3 + 1];
struct addrinfo *ailist, *ai, aihints; struct addrinfo *ailist, *ai, aihints;
struct listen *f; struct listen *f;
int s, error, opt = 1, n = 0; 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)); memset(&aihints, 0, sizeof(struct addrinfo));
snprintf(serv, sizeof(serv), "%u", port); snprintf(serv, sizeof(serv), "%u", port);
@ -146,24 +144,27 @@ listen_new_tcp(char *addr, unsigned int port)
aihints.ai_protocol = IPPROTO_TCP; aihints.ai_protocol = IPPROTO_TCP;
error = getaddrinfo(host, serv, &aihints, &ailist); error = getaddrinfo(host, serv, &aihints, &ailist);
if (error) { if (error) {
fprintf(stderr, "%s: %s\n", addr, gai_strerror(error)); log_puts(addr);
exit(1); log_puts(": failed to resolve address\n");
return 0;
} }
/* /*
* for each address, try create a listening socket bound on * for each address, try create a listening socket bound on
* that address * that address
*/ */
for (ai = ailist; ai != NULL; ai = ai->ai_next) { for (ai = ailist; ai != NULL; ai = ai->ai_next) {
s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (s < 0) { if (s < 0) {
perror("socket"); log_puts(addr);
log_puts(": failed to create socket\n");
continue; continue;
} }
opt = 1; opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
&opt, sizeof(int)) < 0) { &opt, sizeof(int)) < 0) {
perror("setsockopt"); log_puts(addr);
log_puts(": failed to set SO_REUSEADDR\n");
goto bad_close; goto bad_close;
} }
if (ai->ai_family == AF_INET6) { if (ai->ai_family == AF_INET6) {
@ -175,17 +176,20 @@ listen_new_tcp(char *addr, unsigned int port)
opt = 1; opt = 1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
&opt, sizeof(int)) < 0) { &opt, sizeof(int)) < 0) {
perror("setsockopt"); log_puts(addr);
log_puts(": failed to set IPV6_V6ONLY\n");
goto bad_close; goto bad_close;
} }
} }
if (bind(s, ai->ai_addr, ai->ai_addrlen) < 0) { 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; goto bad_close;
} }
if (listen(s, 1) < 0) { if (listen(s, 1) < 0) {
perror("listen"); log_puts(addr);
log_puts(": failed to listen\n");
goto bad_close; goto bad_close;
} }
f = xmalloc(sizeof(struct listen)); f = xmalloc(sizeof(struct listen));
@ -202,8 +206,7 @@ listen_new_tcp(char *addr, unsigned int port)
n++; n++;
} }
freeaddrinfo(ailist); freeaddrinfo(ailist);
if (n == 0) return n;
exit(1);
} }
int int
@ -217,7 +220,8 @@ listen_pollfd(void *arg, struct pollfd *pfd)
{ {
struct listen *f = arg; struct listen *f = arg;
if (file_slowaccept) f->slowaccept = file_slowaccept;
if (f->slowaccept)
return 0; return 0;
pfd->fd = f->fd; pfd->fd = f->fd;
pfd->events = POLLIN; pfd->events = POLLIN;
@ -227,6 +231,10 @@ listen_pollfd(void *arg, struct pollfd *pfd)
int int
listen_revents(void *arg, struct pollfd *pfd) listen_revents(void *arg, struct pollfd *pfd)
{ {
struct listen *f = arg;
if (f->slowaccept)
return 0;
return pfd->revents; return pfd->revents;
} }
@ -244,12 +252,11 @@ listen_in(void *arg)
continue; continue;
if (errno == ENFILE || errno == EMFILE) if (errno == ENFILE || errno == EMFILE)
file_slowaccept = 1; file_slowaccept = 1;
else if (errno != ECONNABORTED && errno != EWOULDBLOCK)
perror("accept");
return; return;
} }
if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { 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); close(sock);
return; return;
} }
@ -257,7 +264,8 @@ listen_in(void *arg)
opt = 1; opt = 1;
if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
&opt, sizeof(int)) < 0) { &opt, sizeof(int)) < 0) {
perror("setsockopt"); file_log(f->file);
log_puts(": failed to set TCP_NODELAY flag\n");
close(sock); close(sock);
return; return;
} }

View File

@ -24,12 +24,13 @@ struct listen {
struct file *file; struct file *file;
char *path; char *path;
int fd; int fd;
int slowaccept;
}; };
extern struct listen *listen_list; extern struct listen *listen_list;
void listen_new_un(char *); int listen_new_un(char *);
void listen_new_tcp(char *, unsigned int); int listen_new_tcp(char *, unsigned int);
int listen_init(struct listen *); int listen_init(struct listen *);
void listen_close(struct listen *); void listen_close(struct listen *);

View File

@ -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) * input message (2-byte messages with running status)
*/ */
tickets = maxavail / 2 - iep->tickets; 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 * store the given message in the output buffer
*/ */
void void
midi_out(struct midi *oep, unsigned char *idata, int icount) midi_out(struct midi *oep, unsigned char *idata, int icount)
{ {
unsigned char *odata; unsigned char *odata;
int ocount; int ocount;
#ifdef DEBUG #ifdef DEBUG
int i; int i;
#endif #endif
while (icount > 0) { while (icount > 0) {
if (oep->obuf.used == oep->obuf.len) { if (oep->obuf.used == oep->obuf.len) {
#ifdef DEBUG #ifdef DEBUG
@ -376,13 +376,11 @@ midi_out(struct midi *oep, unsigned char *idata, int icount)
} }
} }
#ifdef DEBUG
void void
port_log(struct port *p) port_log(struct port *p)
{ {
midi_log(p->midi); midi_log(p->midi);
} }
#endif
void void
port_imsg(void *arg, unsigned char *msg, int size) port_imsg(void *arg, unsigned char *msg, int size)
@ -427,18 +425,16 @@ port_exit(void *arg)
struct port * struct port *
port_new(char *path, unsigned int mode, int hold) port_new(char *path, unsigned int mode, int hold)
{ {
struct port *c, **pc; struct port *c;
c = xmalloc(sizeof(struct port)); c = xmalloc(sizeof(struct port));
c->path = xstrdup(path); c->path = xstrdup(path);
c->state = PORT_CFG; c->state = PORT_CFG;
c->hold = hold; c->hold = hold;
c->midi = midi_new(&port_midiops, c, mode); c->midi = midi_new(&port_midiops, c, mode);
midi_portnum++; c->num = midi_portnum++;
for (pc = &port_list; *pc != NULL; pc = &(*pc)->next) c->next = port_list;
; /* nothing */ port_list = c;
c->next = NULL;
*pc = c;
return c; return c;
} }
@ -504,7 +500,7 @@ port_bynum(int num)
struct port *p; struct port *p;
for (p = port_list; p != NULL; p = p->next) { for (p = port_list; p != NULL; p = p->next) {
if (num-- == 0) if (p->num == num)
return p; return p;
} }
return NULL; return NULL;
@ -536,9 +532,9 @@ port_close(struct port *c)
panic(); panic();
} }
#endif #endif
c->state = PORT_CFG; c->state = PORT_CFG;
port_mio_close(c); port_mio_close(c);
for (i = 0; i < MIDI_NEP; i++) { for (i = 0; i < MIDI_NEP; i++) {
ep = midi_ep + i; ep = midi_ep + i;
if ((ep->txmask & c->midi->self) || if ((ep->txmask & c->midi->self) ||

View File

@ -73,7 +73,7 @@ struct midi {
unsigned int len; /* expected ``msg'' length */ unsigned int len; /* expected ``msg'' length */
unsigned int txmask; /* list of ep we send to */ unsigned int txmask; /* list of ep we send to */
unsigned int self; /* equal (1 << index) */ 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 */ struct abuf obuf; /* output buffer */
}; };
@ -87,6 +87,7 @@ struct port {
#define PORT_INIT 1 #define PORT_INIT 1
#define PORT_DRAIN 2 #define PORT_DRAIN 2
unsigned int state; unsigned int state;
unsigned int num; /* port serial number */
char *path; /* hold the port open ? */ char *path; /* hold the port open ? */
int hold; int hold;
struct midi *midi; struct midi *midi;

View File

@ -14,8 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "dev.h" #include "dev.h"
@ -32,20 +30,27 @@ opt_new(char *name, struct dev *dev,
int pmin, int pmax, int rmin, int rmax, int pmin, int pmax, int rmin, int rmax,
int maxweight, int mmc, int dup, unsigned int mode) int maxweight, int mmc, int dup, unsigned int mode)
{ {
struct opt *o, **po; struct opt *o;
unsigned int len; unsigned int len;
char c; 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++) { for (len = 0; name[len] != '\0'; len++) {
if (len == OPT_NAMEMAX) { if (len == OPT_NAMEMAX) {
fprintf(stderr, "%s: name too long\n", name); log_puts(name);
exit(1); log_puts(": too long\n");
return NULL;
} }
c = name[len]; c = name[len];
if ((c < 'a' || c > 'z') && if ((c < 'a' || c > 'z') &&
(c < 'A' || c > 'Z')) { (c < 'A' || c > 'Z')) {
fprintf(stderr, "%s: '%c' not allowed\n", name, c); log_puts(name);
exit(1); log_puts(": only alphabetic chars allowed\n");
return NULL;
} }
} }
o = xmalloc(sizeof(struct opt)); o = xmalloc(sizeof(struct opt));
@ -63,15 +68,8 @@ opt_new(char *name, struct dev *dev,
o->mode = mode; o->mode = mode;
o->dev = dev; o->dev = dev;
memcpy(o->name, name, len + 1); memcpy(o->name, name, len + 1);
for (po = &opt_list; *po != NULL; po = &(*po)->next) { o->next = opt_list;
if (o->dev->num == (*po)->dev->num && opt_list = o;
strcmp(o->name, (*po)->name) == 0) {
fprintf(stderr, "%s: already defined\n", o->name);
exit(1);
}
}
o->next = NULL;
*po = o;
if (log_level >= 2) { if (log_level >= 2) {
dev_log(o->dev); dev_log(o->dev);
log_puts("."); log_puts(".");

View File

@ -163,7 +163,7 @@ dev_sio_open(struct dev *d)
log_putu(par.pchan); log_putu(par.pchan);
log_puts(": unsupported number of play channels\n"); log_puts(": unsupported number of play channels\n");
goto bad_close; goto bad_close;
} }
if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) { if ((mode & SIO_REC) && par.rchan > NCHAN_MAX) {
log_puts(d->path); log_puts(d->path);
log_puts(": "); log_puts(": ");
@ -296,7 +296,7 @@ dev_sio_pollfd(void *arg, struct pollfd *pfd)
{ {
struct dev *d = arg; struct dev *d = arg;
int events; int events;
events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT; events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT;
return sio_pollfd(d->sio.hdl, pfd, events); return sio_pollfd(d->sio.hdl, pfd, events);
} }

View File

@ -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.

View File

@ -14,7 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <sys/queue.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/resource.h> #include <sys/resource.h>
@ -95,9 +94,9 @@ unsigned int opt_mode(void);
void getbasepath(char *, size_t); void getbasepath(char *, size_t);
void setsig(void); void setsig(void);
void unsetsig(void); void unsetsig(void);
void privdrop(void);
struct dev *mkdev(char *, struct aparams *, struct dev *mkdev(char *, struct aparams *,
int, int, int, int, int, int); int, int, int, int, int, int);
struct port *mkport(char *, int);
struct opt *mkopt(char *, struct dev *, struct opt *mkopt(char *, struct dev *,
int, int, int, int, int, int, int, int); int, int, int, int, int, int, int, int);
@ -244,11 +243,11 @@ unsetsig(void)
sa.sa_flags = SA_RESTART; sa.sa_flags = SA_RESTART;
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
if (sigaction(SIGHUP, &sa, NULL) < 0) 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) 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) if (sigaction(SIGINT, &sa, NULL) < 0)
err(1, "unsetsig(int): sigaction failed\n"); err(1, "unsetsig(int): sigaction failed");
} }
void void
@ -256,7 +255,7 @@ getbasepath(char *base, size_t size)
{ {
uid_t uid; uid_t uid;
struct stat sb; struct stat sb;
mode_t mask; mode_t mask, omask;
uid = geteuid(); uid = geteuid();
if (uid == 0) { if (uid == 0) {
@ -266,31 +265,20 @@ getbasepath(char *base, size_t size)
mask = 077; mask = 077;
snprintf(base, SOCKPATH_MAX, SOCKPATH_DIR "-%u", uid); 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) if (errno != EEXIST)
err(1, "mkdir(\"%s\")", base); err(1, "mkdir(\"%s\")", base);
} }
umask(omask);
if (stat(base, &sb) < 0) if (stat(base, &sb) < 0)
err(1, "stat(\"%s\")", base); 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) if (sb.st_uid != uid || (sb.st_mode & mask) != 0)
errx(1, "%s has wrong permissions", base); 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 * struct dev *
mkdev(char *path, struct aparams *par, mkdev(char *path, struct aparams *par,
int mode, int bufsz, int round, int rate, int hold, int autovol) 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, o = opt_new(path, d, pmin, pmax, rmin, rmax,
MIDI_TO_ADATA(vol), mmc, dup, mode); MIDI_TO_ADATA(vol), mmc, dup, mode);
if (o == NULL) 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); dev_adjpar(d, o->mode, o->pmin, o->pmax, o->rmin, o->rmax);
return o; return o;
} }
@ -350,14 +338,18 @@ main(int argc, char **argv)
int c, background, unit; int c, background, unit;
int pmin, pmax, rmin, rmax; int pmin, pmax, rmin, rmax;
char base[SOCKPATH_MAX], path[SOCKPATH_MAX]; char base[SOCKPATH_MAX], path[SOCKPATH_MAX];
char loc[32]; unsigned int mode, dup, mmc, vol;
unsigned int mode, dup, mmc, vol, i;
unsigned int hold, autovol, bufsz, round, rate; unsigned int hold, autovol, bufsz, round, rate;
const char *str; const char *str;
struct aparams par; struct aparams par;
struct dev *d; struct dev *d;
struct port *p; struct port *p;
struct listen *l; struct listen *l;
struct passwd *pw;
struct tcpaddr {
char *host;
struct tcpaddr *next;
} *tcpaddr_list, *ta;
atexit(log_flush); atexit(log_flush);
@ -380,25 +372,27 @@ main(int argc, char **argv)
rmax = 1; rmax = 1;
aparams_init(&par); aparams_init(&par);
mode = MODE_PLAY | MODE_REC; mode = MODE_PLAY | MODE_REC;
tcpaddr_list = NULL;
setsig(); setsig();
filelist_init(); 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) { switch (c) {
case 'd': case 'd':
log_level++; log_level++;
background = 0; background = 0;
break; break;
case 'U': case 'U':
if (listen_list)
errx(1, "-U must come before -L");
unit = strtonum(optarg, 0, 15, &str); unit = strtonum(optarg, 0, 15, &str);
if (str) if (str)
errx(1, "%s: unit number is %s", optarg, str); errx(1, "%s: unit number is %s", optarg, str);
break; break;
case 'L': 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; break;
case 'm': case 'm':
mode = opt_mode(); mode = opt_mode();
@ -433,8 +427,9 @@ main(int argc, char **argv)
d = mkdev(DEFAULT_DEV, &par, 0, bufsz, round, d = mkdev(DEFAULT_DEV, &par, 0, bufsz, round,
rate, hold, autovol); rate, hold, autovol);
} }
mkopt(optarg, d, pmin, pmax, rmin, rmax, if (mkopt(optarg, d, pmin, pmax, rmin, rmax,
mode, vol, mmc, dup); mode, vol, mmc, dup) == NULL)
return 1;
break; break;
case 'q': case 'q':
mkport(optarg, hold); mkport(optarg, hold);
@ -470,29 +465,33 @@ main(int argc, char **argv)
fputs(usagestr, stderr); fputs(usagestr, stderr);
return 1; return 1;
} }
if (dev_list == NULL) { if (dev_list == NULL)
for (i = 0; i < 4; i++) { mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol);
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);
}
}
for (d = dev_list; d != NULL; d = d->next) { for (d = dev_list; d != NULL; d = d->next) {
if (opt_byname("default", d->num)) if (opt_byname("default", d->num))
continue; continue;
mkopt("default", d, pmin, pmax, rmin, rmax, if (mkopt("default", d, pmin, pmax, rmin, rmax,
mode, vol, mmc, dup); mode, vol, mmc, dup) == NULL)
return 1;
} }
getbasepath(base, sizeof(base)); getbasepath(base, sizeof(base));
snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit); snprintf(path, SOCKPATH_MAX, "%s/" SOCKPATH_FILE "%u", base, unit);
listen_new_un(path); if (!listen_new_un(path))
if (geteuid() == 0) return 1;
privdrop(); 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(); midi_init();
for (p = port_list; p != NULL; p = p->next) { for (p = port_list; p != NULL; p = p->next) {
if (!port_init(p)) if (!port_init(p))
@ -512,10 +511,6 @@ main(int argc, char **argv)
if (daemon(0, 0) < 0) if (daemon(0, 0) < 0)
err(1, "daemon"); err(1, "daemon");
} }
/*
* Loop, start audio.
*/
for (;;) { for (;;) {
if (quit_flag) if (quit_flag)
break; break;
@ -539,8 +534,13 @@ main(int argc, char **argv)
dev_del(dev_list); dev_del(dev_list);
while (port_list) while (port_list)
port_del(port_list); port_del(port_list);
filelist_done(); while (tcpaddr_list) {
ta = tcpaddr_list;
tcpaddr_list = ta->next;
xfree(ta);
}
rmdir(base); rmdir(base);
filelist_done();
unsetsig(); unsetsig();
return 0; return 0;
} }

View File

@ -163,6 +163,7 @@ sock_close(struct sock *f)
} }
file_del(f->file); file_del(f->file);
close(f->fd); close(f->fd);
file_slowaccept = 0;
xfree(f); xfree(f);
} }
@ -350,7 +351,7 @@ sock_fdwrite(struct sock *f, void *data, int count)
} }
sock_close(f); sock_close(f);
} else { } else {
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 4) { if (log_level >= 4) {
sock_log(f); sock_log(f);
log_puts(": write blocked\n"); log_puts(": write blocked\n");
@ -391,7 +392,7 @@ sock_fdread(struct sock *f, void *data, int count)
} }
sock_close(f); sock_close(f);
} else { } else {
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 4) { if (log_level >= 4) {
sock_log(f); sock_log(f);
log_puts(": read blocked\n"); log_puts(": read blocked\n");
@ -1143,7 +1144,7 @@ sock_execmsg(struct sock *f)
f->ralign = s->round * s->mix.bpf; f->ralign = s->round * s->mix.bpf;
} }
} }
slot_stop(s); slot_stop(s);
break; break;
case AMSG_SETPAR: case AMSG_SETPAR:
#ifdef DEBUG #ifdef DEBUG
@ -1241,7 +1242,7 @@ sock_execmsg(struct sock *f)
f->rtodo = sizeof(struct amsg); f->rtodo = sizeof(struct amsg);
f->rstate = SOCK_RMSG; f->rstate = SOCK_RMSG;
f->lastvol = ctl; /* dont trigger feedback message */ f->lastvol = ctl; /* dont trigger feedback message */
slot_setvol(f->slot, ctl); slot_setvol(s, ctl);
dev_midi_vol(s->dev, s); dev_midi_vol(s->dev, s);
dev_onctl(s->dev, s->dev->ctl_addr + dev_onctl(s->dev, s->dev->ctl_addr +
CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl); CTLADDR_SLOT_LEVEL(f->slot - s->dev->slot), ctl);
@ -1439,7 +1440,7 @@ sock_buildmsg(struct sock *f)
if (f->fillpending > 0) { if (f->fillpending > 0) {
AMSG_INIT(&f->wmsg); AMSG_INIT(&f->wmsg);
f->wmsg.cmd = htonl(AMSG_FLOWCTL); f->wmsg.cmd = htonl(AMSG_FLOWCTL);
f->wmsg.u.ts.delta = htonl(f->fillpending); f->wmsg.u.ts.delta = htonl(f->fillpending);
size = f->fillpending; size = f->fillpending;
if (f->slot) if (f->slot)
@ -1483,7 +1484,7 @@ sock_buildmsg(struct sock *f)
} }
if (f->midi != NULL && f->midi->obuf.used > 0) { if (f->midi != NULL && f->midi->obuf.used > 0) {
size = f->midi->obuf.used; size = f->midi->obuf.used;
if (size > AMSG_DATAMAX) if (size > AMSG_DATAMAX)
size = AMSG_DATAMAX; size = AMSG_DATAMAX;
AMSG_INIT(&f->wmsg); AMSG_INIT(&f->wmsg);

View File

@ -91,7 +91,7 @@ log_putx(unsigned long num)
c += (c < 10) ? '0' : 'a' - 10; c += (c < 10) ? '0' : 'a' - 10;
LOG_PUTC(c); LOG_PUTC(c);
} }
} else } else
LOG_PUTC('0'); LOG_PUTC('0');
} }
@ -146,7 +146,7 @@ void *
xmalloc(size_t size) xmalloc(size_t size)
{ {
void *p; void *p;
p = malloc(size); p = malloc(size);
if (p == NULL) { if (p == NULL) {
log_puts("failed to allocate "); log_puts("failed to allocate ");
@ -163,6 +163,12 @@ xmalloc(size_t size)
void void
xfree(void *p) xfree(void *p)
{ {
#ifdef DEBUG
if (p == NULL) {
log_puts("xfree with NULL arg\n");
panic();
}
#endif
free(p); free(p);
} }