diff --git a/audio/sndio/Makefile b/audio/sndio/Makefile
index 12dff7b..1d140d5 100644
--- a/audio/sndio/Makefile
+++ b/audio/sndio/Makefile
@@ -3,7 +3,7 @@
 
 PORTNAME=	sndio
 PORTVERSION=	1.1.0
-PORTREVISION=	1
+PORTREVISION=	2
 CATEGORIES=	audio
 MASTER_SITES=	http://www.sndio.org/
 
diff --git a/audio/sndio/files/patch-configure b/audio/sndio/files/patch-configure
index b4980dd..0620b2e 100644
--- a/audio/sndio/files/patch-configure
+++ b/audio/sndio/files/patch-configure
@@ -1,30 +1,41 @@
 --- configure.orig	2015-12-15 05:28:04 UTC
 +++ configure
-@@ -32,6 +32,7 @@ prefix=/usr/local			# where to install s
+@@ -20,6 +20,8 @@ Usage: configure [options]
+ --disable-sun			disable sun audio backend
+ --enable-rmidi			enable character device midi backend [$rmidi]
+ --disable-rmidi			disable character device midi backend
++--enable-umidi			enable character device midi backend [$umidi]
++--disable-umidi			disable character device midi backend
+ --with-libbsd			use the libbsd rather than bsd-compat/*
+ --without-libbsd		don't use libbsd
+ END
+@@ -32,7 +34,9 @@ prefix=/usr/local			# where to install s
  so="libsndio.so.\${MAJ}.\${MIN}"	# shared libs to build
  alsa=no					# do we want alsa support ?
  sun=no					# do we want sun support ?
 +oss=no					# do we want oss support ?
  rmidi=no				# do we want support for raw char dev ?
++umidi=no				# do we want support for raw char dev ?
  precision=16				# aucat/sndiod arithmetic precision
  user=_sndio				# non-privileged user for sndio daemon
-@@ -71,6 +72,15 @@ case `uname` in
+ libbsd=no				# use libbsd?
+@@ -71,6 +75,15 @@ case `uname` in
  		defs='-DHAVE_ARC4RANDOM -DHAVE_ISSETUGID \\\
  		-DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRTONUM'
  		;;
-+	FreeBSD)
++	DragonFly|FreeBSD)
 +		user=_sndio
 +		so="$so libsndio.so"
 +		defs='-DHAVE_ARC4RANDOM -DHAVE_ISSETUGID \\\
-+		-DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRTONUM \\\
-+		-DDEFAULT_DEV=\\"fallback\\"'
++		-DHAVE_STRLCAT -DHAVE_STRLCPY -DHAVE_STRTONUM'
 +		oss=yes
++		umidi=yes
 +		mandir=${prefix}/man
 +		;;
  esac
  
  # shell word separator (none)
-@@ -106,6 +116,12 @@ for i; do
+@@ -106,6 +119,12 @@ for i; do
  	--disable-alsa)
  		alsa=no
  		shift;;
@@ -37,7 +48,20 @@
  	--enable-sun)
  		sun=yes
  		shift;;
-@@ -162,6 +178,13 @@ if [ $alsa = yes ]; then
+@@ -118,6 +137,12 @@ for i; do
+ 	--disable-rmidi)
+ 		rmidi=no
+ 		shift;;
++	--enable-umidi)
++		umidi=yes
++		shift;;
++	--disable-umidi)
++		umidi=no
++		shift;;
+ 	--privsep-user=*)
+ 		user="${i#--privsep-user=}"
+ 		shift;;
+@@ -162,6 +187,13 @@ if [ $alsa = yes ]; then
  fi
  
  #
@@ -51,11 +75,28 @@
  # if using Sun API, add corresponding parameters
  #
  if [ $sun = yes ]; then
-@@ -215,6 +238,7 @@ user..................... $user
+@@ -176,6 +208,13 @@ if [ $rmidi = yes ]; then
+ fi
+ 
+ #
++# if using raw character devices for midi, add corresponding parameters
++#
++if [ $umidi = yes ]; then
++	defs="$defs -DUSE_UMIDI"
++fi
++
++#
+ # if using libbsd, add corresponding parameters
+ #
+ if [ $libbsd = yes ]; then
+@@ -215,8 +254,10 @@ user..................... $user
  libbsd................... $libbsd
  precision................ $precision
  alsa..................... $alsa
 +oss...................... $oss
  sun...................... $sun
  rmidi.................... $rmidi
++umidi.................... $umidi
+ 
+ Do "make && make install" to compile and install sndio
  
diff --git a/audio/sndio/files/patch-libsndio_Makefile.in b/audio/sndio/files/patch-libsndio_Makefile.in
index e199ca7..407b8bb 100644
--- a/audio/sndio/files/patch-libsndio_Makefile.in
+++ b/audio/sndio/files/patch-libsndio_Makefile.in
@@ -1,15 +1,25 @@
 --- libsndio/Makefile.in.orig	2015-12-30 11:54:40 UTC
 +++ libsndio/Makefile.in
-@@ -99,7 +99,7 @@ clean:
+@@ -98,8 +98,8 @@ clean:
+ # loader to determine dependencies in a single pass
  #
  OBJS = debug.o aucat.o \
- mio.o mio_rmidi.o mio_alsa.o mio_aucat.o \
+-mio.o mio_rmidi.o mio_alsa.o mio_aucat.o \
 -sio.o sio_alsa.o sio_aucat.o sio_sun.o \
++mio.o mio_rmidi.o mio_umidi.o mio_alsa.o mio_aucat.o \
 +sio.o sio_alsa.o sio_aucat.o sio_oss.o sio_sun.o \
  issetugid.o strlcat.o strlcpy.o strtonum.o
  
  .c.o:
-@@ -140,3 +140,5 @@ sio_aucat.o:	sio_aucat.c aucat.h amsg.h 
+@@ -132,6 +132,7 @@ mio_alsa.o:	mio_alsa.c debug.h mio_priv.
+ mio_aucat.o:	mio_aucat.c aucat.h amsg.h debug.h mio_priv.h sndio.h \
+ 		../bsd-compat/bsd-compat.h
+ mio_rmidi.o:	mio_rmidi.c debug.h mio_priv.h sndio.h
++mio_umidi.o:	mio_umidi.c debug.h mio_priv.h sndio.h
+ sio.o:		sio.c debug.h sio_priv.h sndio.h \
+ 		../bsd-compat/bsd-compat.h
+ sio_alsa.o:	sio_alsa.c debug.h sio_priv.h sndio.h \
+@@ -140,3 +141,5 @@ sio_aucat.o:	sio_aucat.c aucat.h amsg.h 
  		../bsd-compat/bsd-compat.h
  sio_sun.o:	sio_sun.c debug.h sio_priv.h sndio.h \
  		../bsd-compat/bsd-compat.h
diff --git a/audio/sndio/files/patch-libsndio_mio.c b/audio/sndio/files/patch-libsndio_mio.c
new file mode 100644
index 0000000..f605b0e
--- /dev/null
+++ b/audio/sndio/files/patch-libsndio_mio.c
@@ -0,0 +1,20 @@
+--- libsndio/mio.c.orig	2015-12-09 10:13:10 UTC
++++ libsndio/mio.c
+@@ -55,6 +55,8 @@ mio_open(const char *str, unsigned int m
+ 			return hdl;
+ #if defined(USE_RMIDI)
+ 		return _mio_rmidi_open("rmidi/0", mode, nbio);
++#elif defined(USE_UMIDI)
++		return _mio_umidi_open("rmidi/0", mode, nbio);
+ #elif defined(USE_ALSA)
+ 		return _mio_alsa_open("rmidi/0", mode, nbio);
+ #else
+@@ -68,6 +70,8 @@ mio_open(const char *str, unsigned int m
+ 	if (_sndio_parsetype(str, "rmidi"))
+ #if defined(USE_RMIDI)
+ 		return _mio_rmidi_open(str, mode, nbio);
++#elif defined(USE_UMIDI)
++		return _mio_umidi_open(str, mode, nbio);
+ #elif defined(USE_ALSA)
+ 		return _mio_alsa_open(str, mode, nbio);
+ #else
diff --git a/audio/sndio/files/patch-libsndio_mio__priv.h b/audio/sndio/files/patch-libsndio_mio__priv.h
new file mode 100644
index 0000000..a5c5b7e
--- /dev/null
+++ b/audio/sndio/files/patch-libsndio_mio__priv.h
@@ -0,0 +1,12 @@
+--- libsndio/mio_priv.h.orig	2015-12-09 10:13:10 UTC
++++ libsndio/mio_priv.h
+@@ -44,6 +44,9 @@ struct mio_ops {
+ };
+ 
+ struct mio_hdl *_mio_rmidi_open(const char *, unsigned, int);
++#ifdef USE_UMIDI
++struct mio_hdl *_mio_umidi_open(const char *, unsigned, int);
++#endif
+ #ifdef USE_ALSA
+ struct mio_hdl *_mio_alsa_open(const char *, unsigned, int);
+ #endif
diff --git a/audio/sndio/files/patch-libsndio_mio__umidi.c b/audio/sndio/files/patch-libsndio_mio__umidi.c
new file mode 100644
index 0000000..78bf9f7
--- /dev/null
+++ b/audio/sndio/files/patch-libsndio_mio__umidi.c
@@ -0,0 +1,222 @@
+--- libsndio/mio_umidi.c.orig	2016-11-04 12:06:45 UTC
++++ libsndio/mio_umidi.c
+@@ -0,0 +1,219 @@
++/*	$OpenBSD$	*/
++/*
++ * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
++ * Copyright (c) 2016 Tobias Kortkamp <t@tobik.me>
++ *
++ * 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.
++ */
++
++#ifdef USE_UMIDI
++#include <sys/types.h>
++#include <sys/stat.h>
++
++#include <errno.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <poll.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++#include "debug.h"
++#include "mio_priv.h"
++
++#define DEVPATH_PREFIX	"/dev/umidi"
++#define DEVPATH_MAX 	(1 +		\
++	sizeof(DEVPATH_PREFIX) - 1 +	\
++	sizeof(int) * 3)
++
++struct mio_umidi_hdl {
++	struct mio_hdl mio;
++	int fd;
++};
++
++static void mio_umidi_close(struct mio_hdl *);
++static size_t mio_umidi_read(struct mio_hdl *, void *, size_t);
++static size_t mio_umidi_write(struct mio_hdl *, const void *, size_t);
++static int mio_umidi_nfds(struct mio_hdl *);
++static int mio_umidi_pollfd(struct mio_hdl *, struct pollfd *, int);
++static int mio_umidi_revents(struct mio_hdl *, struct pollfd *);
++
++static struct mio_ops mio_umidi_ops = {
++	mio_umidi_close,
++	mio_umidi_write,
++	mio_umidi_read,
++	mio_umidi_nfds,
++	mio_umidi_pollfd,
++	mio_umidi_revents
++};
++
++static int
++mio_umidi_getfd(const char *str, unsigned int mode, int nbio)
++{
++	const char *p;
++	char path[DEVPATH_MAX];
++	unsigned int devnum;
++	unsigned int subdevnum;
++	int fd, flags;
++
++	p = _sndio_parsetype(str, "rmidi");
++	if (p == NULL) {
++		DPRINTF("mio_umidi_getfd: %s: \"rsnd\" expected\n", str);
++		return -1;
++	}
++	switch (*p) {
++	case '/':
++		p++;
++		break;
++	default:
++		DPRINTF("mio_umidi_getfd: %s: '/' expected\n", str);
++		return -1;
++	}
++	p = _sndio_parsenum(p, &devnum, 255);
++	if (p == NULL) {
++		DPRINTF("mio_umidi_getfd: %s: number expected after '/'\n", str);
++		return -1;
++	}
++	switch (*p) {
++	case '.':
++		p++;
++		p = _sndio_parsenum(p, &subdevnum, 255);
++		if (p == NULL || *p != '\0') {
++			DPRINTF("mio_umidi_getfd: %s: number expected after '.'\n",
++				str);
++			return -1;
++		}
++		break;
++	default:
++		subdevnum = 0;
++	}
++	snprintf(path, sizeof(path), DEVPATH_PREFIX "%u.%u", devnum, subdevnum);
++	if (mode == (MIO_IN | MIO_OUT))
++		flags = O_RDWR;
++	else
++		flags = (mode & MIO_OUT) ? O_WRONLY : O_RDONLY;
++	while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) < 0) {
++		if (errno == EINTR)
++			continue;
++		DPERROR(path);
++		return -1;
++	}
++	return fd;
++}
++
++static struct mio_hdl *
++mio_umidi_fdopen(int fd, unsigned int mode, int nbio)
++{
++	struct mio_umidi_hdl *hdl;
++
++	hdl = malloc(sizeof(struct mio_umidi_hdl));
++	if (hdl == NULL)
++		return NULL;
++	_mio_create(&hdl->mio, &mio_umidi_ops, mode, nbio);
++	hdl->fd = fd;
++	return (struct mio_hdl *)hdl;
++}
++
++struct mio_hdl *
++_mio_umidi_open(const char *str, unsigned int mode, int nbio)
++{
++	struct mio_hdl *hdl;
++	int fd;
++
++	fd = mio_umidi_getfd(str, mode, nbio);
++	if (fd < 0)
++		return NULL;
++	hdl = mio_umidi_fdopen(fd, mode, nbio);
++	if (hdl != NULL)
++		return hdl;
++	while (close(fd) < 0 && errno == EINTR)
++		; /* retry */
++	return NULL;
++}
++
++static void
++mio_umidi_close(struct mio_hdl *sh)
++{
++	struct mio_umidi_hdl *hdl = (struct mio_umidi_hdl *)sh;
++	int rc;
++
++	do {
++		rc = close(hdl->fd);
++	} while (rc < 0 && errno == EINTR);
++	free(hdl);
++}
++
++static size_t
++mio_umidi_read(struct mio_hdl *sh, void *buf, size_t len)
++{
++	struct mio_umidi_hdl *hdl = (struct mio_umidi_hdl *)sh;
++	ssize_t n;
++
++	while ((n = read(hdl->fd, buf, len)) < 0) {
++		if (errno == EINTR)
++			continue;
++		if (errno != EAGAIN) {
++			DPERROR("mio_umidi_read: read");
++			hdl->mio.eof = 1;
++		}
++		return 0;
++	}
++	if (n == 0) {
++		DPRINTF("mio_umidi_read: eof\n");
++		hdl->mio.eof = 1;
++		return 0;
++	}
++	return n;
++}
++
++static size_t
++mio_umidi_write(struct mio_hdl *sh, const void *buf, size_t len)
++{
++	struct mio_umidi_hdl *hdl = (struct mio_umidi_hdl *)sh;
++	ssize_t n;
++
++	while ((n = write(hdl->fd, buf, len)) < 0) {
++		if (errno == EINTR)
++			continue;
++		if (errno != EAGAIN) {
++			DPERROR("mio_umidi_write: write");
++			hdl->mio.eof = 1;
++		}
++		return 0;
++	}
++	return n;
++}
++
++static int
++mio_umidi_nfds(struct mio_hdl *sh)
++{
++	return 1;
++}
++
++static int
++mio_umidi_pollfd(struct mio_hdl *sh, struct pollfd *pfd, int events)
++{
++	struct mio_umidi_hdl *hdl = (struct mio_umidi_hdl *)sh;
++
++	pfd->fd = hdl->fd;
++	pfd->events = events;
++	return 1;
++}
++
++static int
++mio_umidi_revents(struct mio_hdl *sh, struct pollfd *pfd)
++{
++	return pfd->revents;
++}
++#endif /* defined USE_UMIDI */
diff --git a/audio/sndio/files/patch-libsndio_sio.c b/audio/sndio/files/patch-libsndio_sio.c
index 1226d84..44de62a 100644
--- a/audio/sndio/files/patch-libsndio_sio.c
+++ b/audio/sndio/files/patch-libsndio_sio.c
@@ -1,23 +1,15 @@
 --- libsndio/sio.c.orig	2016-01-08 20:51:12 UTC
 +++ libsndio/sio.c
-@@ -64,17 +64,25 @@ sio_open(const char *str, unsigned int m
+@@ -64,6 +64,8 @@ sio_open(const char *str, unsigned int m
  			return hdl;
  #if defined(USE_SUN)
  		return _sio_sun_open("rsnd/0", mode, nbio);
 +#elif defined(USE_OSS)
-+		return _sio_oss_open("fallback", mode, nbio);
++		return _sio_oss_open("rsnd/0", mode, nbio);
  #elif defined(USE_ALSA)
  		return _sio_alsa_open("rsnd/0", mode, nbio);
  #else
- 		return NULL;
- #endif
- 	}
-+#if defined(USE_OSS)
-+	if (strcmp(str, "fallback") == 0)
-+		return _sio_oss_open(str, mode, nbio);
-+#endif
- 	if (_sndio_parsetype(str, "snd"))
- 		return _sio_aucat_open(str, mode, nbio);
+@@ -75,6 +77,8 @@ sio_open(const char *str, unsigned int m
  	if (_sndio_parsetype(str, "rsnd"))
  #if defined(USE_SUN)
  		return _sio_sun_open(str, mode, nbio);
diff --git a/audio/sndio/files/patch-libsndio_sio__oss.c b/audio/sndio/files/patch-libsndio_sio__oss.c
index 90cde18..ba812d7 100644
--- a/audio/sndio/files/patch-libsndio_sio__oss.c
+++ b/audio/sndio/files/patch-libsndio_sio__oss.c
@@ -1,6 +1,6 @@
---- libsndio/sio_oss.c.orig	2016-08-20 02:30:22 UTC
+--- libsndio/sio_oss.c.orig	2016-11-04 12:06:45 UTC
 +++ libsndio/sio_oss.c
-@@ -0,0 +1,838 @@
+@@ -0,0 +1,644 @@
 +/*	$OpenBSD$	*/
 +/*
 + * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
@@ -20,15 +20,11 @@
 + */
 +
 +#ifdef USE_OSS
-+#include <sys/types.h>
 +#include <sys/ioctl.h>
-+#include <sys/param.h>
 +#include <sys/soundcard.h>
-+#include <sys/stat.h>
 +
 +#include <errno.h>
 +#include <fcntl.h>
-+#include <limits.h>
 +#include <poll.h>
 +#include <stdio.h>
 +#include <stdlib.h>
@@ -44,58 +40,73 @@
 +	sizeof(DEVPATH_PREFIX) - 1 +	\
 +	sizeof(int) * 3)
 +
-+#define AUDIO_INITPAR(p)						\
-+	(void)memset((void *)(p), 0xff, sizeof(struct audio_swpar))
++struct sio_oss_fmt {
++	int fmt;
++	unsigned int bits;
++	unsigned int bps;
++	unsigned int sig;
++	unsigned int le;
++	unsigned int msb;
++};
++static struct sio_oss_fmt formats[] = {
++	/* See http://manuals.opensound.com/developer/formats.html.
++	 * AFMT_{S8,U16}_* are marked as obsolete so are missing here.
++	 */
 +
-+/*
-+ * argument to AUDIO_SETPAR and AUDIO_GETPAR ioctls
-+ */
-+struct audio_swpar {
-+	unsigned int sig;		/* if 1, encoding is signed */
-+	unsigned int le;		/* if 1, encoding is little-endian */
-+	unsigned int bits;		/* bits per sample */
-+	unsigned int bps;		/* bytes per sample */
-+	unsigned int msb;		/* if 1, bits are msb-aligned */
-+	unsigned int rate;		/* common play & rec sample rate */
-+	unsigned int pchan;		/* play channels */
-+	unsigned int rchan;		/* rec channels */
-+	unsigned int nblks;		/* number of blocks in play buffer */
-+	unsigned int round;		/* common frames per block */
-+	unsigned int _spare[6];
++	/* le+msb not important */
++	{ AFMT_U8,      8, 1, 0, 0, 0 },
++	{ AFMT_U8,      8, 1, 0, 1, 0 },
++	{ AFMT_U8,      8, 1, 0, 0, 1 },
++	{ AFMT_U8,      8, 1, 0, 1, 1 },
++
++	/* msb not important */
++	{ AFMT_S16_BE, 16, 2, 1, 0, 0 },
++	{ AFMT_S16_BE, 16, 2, 1, 0, 1 },
++	{ AFMT_S16_LE, 16, 2, 1, 1, 0 },
++	{ AFMT_S16_LE, 16, 2, 1, 1, 1 },
++	{ AFMT_S24_BE, 24, 3, 1, 0, 0 },
++	{ AFMT_S24_BE, 24, 3, 1, 0, 1 },
++	{ AFMT_S24_LE, 24, 3, 1, 1, 0 },
++	{ AFMT_S24_LE, 24, 3, 1, 1, 1 },
++	{ AFMT_U24_BE, 24, 3, 0, 0, 0 },
++	{ AFMT_U24_BE, 24, 3, 0, 0, 1 },
++	{ AFMT_U24_LE, 24, 3, 0, 1, 0 },
++	{ AFMT_U24_LE, 24, 3, 0, 1, 1 },
++
++	{ AFMT_S32_BE, 32, 4, 1, 0, 1 },
++	{ AFMT_S32_LE, 32, 4, 1, 1, 1 },
++	{ AFMT_U32_BE, 32, 4, 0, 0, 1 },
++	{ AFMT_U32_LE, 32, 4, 0, 1, 1 },
 +};
 +
 +struct sio_oss_hdl {
 +	struct sio_hdl sio;
 +	int fd;
-+	unsigned int ibpf, obpf;	/* bytes per frame */
 +	unsigned int isamples;
 +	unsigned int osamples;
-+	int idelta, odelta;		/* position reported to client */
-+
-+	char *devstr;
++	int idelta, odelta;
 +
-+	/* OSS doesn't have an API to ask for device parameters
-+	 * without setting them, so we keep track of them ourselves.
-+	 */
-+	struct audio_swpar swpar;
++	int fmt;
++	unsigned int rate;
++	unsigned int chan;
++	unsigned int appbufsz;
++	unsigned int round;
 +};
 +
-+static void sio_oss_close(struct sio_hdl *);
-+static int sio_oss_start(struct sio_hdl *);
-+static int sio_oss_stop(struct sio_hdl *);
-+static int sio_oss_setpar(struct sio_hdl *, struct sio_par *);
-+static int sio_oss_getpar(struct sio_hdl *, struct sio_par *);
++static struct sio_hdl *sio_oss_fdopen(const char *, int, unsigned int, int);
 +static int sio_oss_getcap(struct sio_hdl *, struct sio_cap *);
-+static size_t sio_oss_read(struct sio_hdl *, void *, size_t);
-+static size_t sio_oss_write(struct sio_hdl *, const void *, size_t);
++static int sio_oss_getfd(const char *, unsigned int, int);
++static int sio_oss_getpar(struct sio_hdl *, struct sio_par *);
 +static int sio_oss_nfds(struct sio_hdl *);
 +static int sio_oss_pollfd(struct sio_hdl *, struct pollfd *, int);
 +static int sio_oss_revents(struct sio_hdl *, struct pollfd *);
-+
-+static void sio_oss_fmt_to_swpar(int, struct audio_swpar *);
-+static int sio_oss_audio_getpar(struct sio_oss_hdl *, struct audio_swpar *);
-+static int sio_oss_audio_setpar(struct sio_oss_hdl *, struct audio_swpar *);
-+static int sio_oss_reopen(struct sio_oss_hdl *);
++static int sio_oss_setpar(struct sio_hdl *, struct sio_par *);
++static int sio_oss_start(struct sio_hdl *);
++static int sio_oss_stop(struct sio_hdl *);
++static int sio_oss_xrun(struct sio_oss_hdl *);
++static size_t sio_oss_read(struct sio_hdl *, void *, size_t);
++static size_t sio_oss_write(struct sio_hdl *, const void *, size_t);
++static void sio_oss_close(struct sio_hdl *);
 +
 +static struct sio_ops sio_oss_ops = {
 +	sio_oss_close,
@@ -113,97 +124,36 @@
 +	NULL, /* getvol */
 +};
 +
-+static int
-+sio_oss_adjpar(struct sio_oss_hdl *hdl, struct audio_swpar *ap)
-+{
-+	if (hdl->sio.eof)
-+		return 0;
-+	if (sio_oss_audio_setpar(hdl, ap)) {
-+		DPERROR("AUDIO_SETPAR");
-+		hdl->sio.eof = 1;
-+		return 0;
-+	}
-+	if (sio_oss_audio_getpar(hdl, ap)) {
-+		DPERROR("AUDIO_GETPAR");
-+		hdl->sio.eof = 1;
-+		return 0;
-+	}
-+	return 1;
-+}
-+
-+/*
-+ * try to set the device to the given parameters and check that the
-+ * device can use them; return 1 on success, 0 on failure or error
-+ */
-+static int
-+sio_oss_testpar(struct sio_oss_hdl *hdl, struct sio_enc *enc,
-+    unsigned int pchan, unsigned int rchan, unsigned int rate)
-+{
-+	struct audio_swpar ap;
-+
-+	AUDIO_INITPAR(&ap);
-+	if (enc != NULL) {
-+		ap.sig = enc->sig;
-+		ap.bits = enc->bits;
-+		ap.bps = enc->bps;
-+		if (ap.bps > 1)
-+			ap.le = enc->le;
-+		if (ap.bps * 8 > ap.bits)
-+			ap.msb = enc->msb;
-+	}
-+	if (rate)
-+		ap.rate = rate;
-+	if (pchan && (hdl->sio.mode & SIO_PLAY))
-+		ap.pchan = pchan;
-+	if (rchan && (hdl->sio.mode & SIO_REC))
-+		ap.rchan = rchan;
-+	if (!sio_oss_adjpar(hdl, &ap))
-+		return 0;
-+	if (pchan && ap.pchan != pchan)
-+		return 0;
-+	if (rchan && ap.rchan != rchan)
-+		return 0;
-+	if (rate && ap.rate != rate)
-+		return 0;
-+	if (enc) {
-+		if (ap.sig != enc->sig)
-+			return 0;
-+		if (ap.bits != enc->bits)
-+			return 0;
-+		if (ap.bps != enc->bps)
-+			return 0;
-+		if (ap.bps > 1 && ap.le != enc->le)
-+			return 0;
-+		if (ap.bits < ap.bps * 8 && ap.msb != enc->msb)
-+			return 0;
-+	}
-+	return 1;
-+}
-+
 +/*
 + * guess device capabilities
 + */
 +static int
 +sio_oss_getcap(struct sio_hdl *sh, struct sio_cap *cap)
 +{
++	/* From sound(4):
++	 * The FreeBSD multichannel matrix processor supports up to 18
++	 * interleaved channels, but the limit is currently set to 8
++	 * channels (as commonly used for 7.1 surround sound).
++	 */
 +	static unsigned int chans[] = {
-+		1, 2, 4, 6, 8, 10, 12
++		1, 2, 4, 6, 8
 +	};
 +	static unsigned int rates[] = {
-+		8000, 11025, 12000, 16000, 22050, 24000,
-+		32000, 44100, 48000, 64000, 88200, 96000
++		8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
++		48000, 64000, 88200, 96000, 192000
 +	};
-+	static unsigned int encs[] = {
-+		8, 16, 24, 32
++	static int afmts[] = {
++		AFMT_U8, AFMT_S16_LE, AFMT_S16_BE, AFMT_S24_LE, AFMT_U24_LE,
++		AFMT_S32_LE, AFMT_U32_LE
 +	};
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
-+	struct audio_swpar savepar, ap;
 +	unsigned int nconf = 0;
 +	unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
-+	unsigned int i, j, conf;
++	unsigned int i, j, k, conf;
++	int fmts;
 +
-+	if (sio_oss_audio_getpar(hdl, &savepar)) {
-+		DPERROR("AUDIO_GETPAR");
++	if (ioctl(hdl->fd, SNDCTL_DSP_GETFMTS, &fmts) < 0) {
++		DPERROR("sio_oss_getcap: GETFMTS");
 +		hdl->sio.eof = 1;
 +		return 0;
 +	}
@@ -211,71 +161,49 @@
 +	/*
 +	 * get a subset of supported encodings
 +	 */
-+	for (i = 0; i < sizeof(encs) / sizeof(encs[0]); i++) {
-+		AUDIO_INITPAR(&ap);
-+		ap.bits = encs[i];
-+		ap.sig = (ap.bits > 8) ? 1 : 0;
-+		if (!sio_oss_adjpar(hdl, &ap))
-+			return 0;
-+		if (ap.bits == encs[i]) {
-+			cap->enc[i].sig = ap.sig;
-+			cap->enc[i].bits = ap.bits;
-+			cap->enc[i].le = ap.le;
-+			cap->enc[i].bps = ap.bps;
-+			cap->enc[i].msb = ap.msb;
-+			enc_map |= 1 << i;
++	for (j = 0, i = 0; i < sizeof(afmts) / sizeof(afmts[0]); i++) {
++		if (fmts & afmts[i]) {
++			for (k = 0; k < sizeof(formats) / sizeof(formats[0]); k++) {
++				if (formats[k].fmt == afmts[i]) {
++					cap->enc[j].sig = formats[k].sig;
++					cap->enc[j].bits = formats[k].bits;
++					cap->enc[j].bps = formats[k].bps;
++					cap->enc[j].le = formats[k].le;
++					cap->enc[j].msb = formats[k].msb;
++					enc_map |= 1 << j;
++					j++;
++					break;
++				}
++			}
 +		}
 +	}
 +
 +	/*
 +	 * fill channels
-+	 *
-+	 * for now we're lucky: all kernel devices assume that the
-+	 * number of channels and the encoding are independent so we can
-+	 * use the current encoding and try various channels.
 +	 */
 +	if (hdl->sio.mode & SIO_PLAY) {
 +		for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
-+			AUDIO_INITPAR(&ap);
-+			ap.pchan = chans[i];
-+			if (!sio_oss_adjpar(hdl, &ap))
-+				return 0;
-+			if (ap.pchan == chans[i]) {
-+				cap->pchan[i] = chans[i];
-+				pchan_map |= (1 << i);
-+			}
++			cap->pchan[i] = chans[i];
++			pchan_map |= (1 << i);
 +		}
 +	}
 +	if (hdl->sio.mode & SIO_REC) {
 +		for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
-+			AUDIO_INITPAR(&ap);
-+			ap.pchan = chans[i];
-+			if (!sio_oss_adjpar(hdl, &ap))
-+				return 0;
-+			if (ap.rchan == chans[i]) {
-+				cap->rchan[i] = chans[i];
-+				rchan_map |= (1 << i);
-+			}
++			cap->rchan[i] = chans[i];
++			rchan_map |= (1 << i);
 +		}
 +	}
 +
 +	/*
 +	 * fill rates
-+	 *
-+	 * rates are not independent from other parameters (eg. on
-+	 * uaudio devices), so certain rates may not be allowed with
-+	 * certain encodings. We have to check rates for all encodings
 +	 */
-+	for (j = 0; j < sizeof(encs) / sizeof(encs[0]); j++) {
++	for (j = 0; j < sizeof(formats) / sizeof(formats[0]); j++) {
 +		rate_map = 0;
 +		if ((enc_map & (1 << j)) == 0)
 +			continue;
 +		for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
-+			if (sio_oss_testpar(hdl,
-+				&cap->enc[j], 0, 0, rates[i])) {
-+				cap->rate[i] = rates[i];
-+				rate_map |= (1 << i);
-+			}
++			cap->rate[i] = rates[i];
++			rate_map |= (1 << i);
 +		}
 +		for (conf = 0; conf < nconf; conf++) {
 +			if (cap->confs[conf].rate == rate_map) {
@@ -295,11 +223,6 @@
 +	}
 +	cap->nconf = nconf;
 +
-+	if (sio_oss_audio_setpar(hdl, &savepar)) {
-+		DPERROR("AUDIO_SETPAR");
-+		hdl->sio.eof = 1;
-+		return 0;
-+	}
 +	return 1;
 +}
 +
@@ -311,33 +234,25 @@
 +	unsigned int devnum;
 +	int fd, flags;
 +
-+	if (strcmp(str, "fallback") == 0) {
-+		/* On FreeBSD /dev/dsp points to the default unit
-+		 * selectable with the hw.snd.default_unit sysctl.
-+		 * Use it as fallback device.
-+		 */
-+		snprintf(path, sizeof(path), DEVPATH_PREFIX);
-+	} else {
-+		p = _sndio_parsetype(str, "rsnd");
-+		if (p == NULL) {
-+			DPRINTF("sio_oss_getfd: %s: \"rsnd\" expected\n", str);
-+			return -1;
-+		}
-+		switch (*p) {
-+		case '/':
-+			p++;
-+			break;
-+		default:
-+			DPRINTF("sio_oss_getfd: %s: '/' expected\n", str);
-+			return -1;
-+		}
-+		p = _sndio_parsenum(p, &devnum, 255);
-+		if (p == NULL || *p != '\0') {
-+			DPRINTF("sio_oss_getfd: %s: number expected after '/'\n", str);
-+			return -1;
-+		}
-+		snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
++	p = _sndio_parsetype(str, "rsnd");
++	if (p == NULL) {
++		DPRINTF("sio_oss_getfd: %s: \"rsnd\" expected\n", str);
++		return -1;
++	}
++	switch (*p) {
++	case '/':
++		p++;
++		break;
++	default:
++		DPRINTF("sio_oss_getfd: %s: '/' expected\n", str);
++		return -1;
++	}
++	p = _sndio_parsenum(p, &devnum, 255);
++	if (p == NULL || *p != '\0') {
++		DPRINTF("sio_oss_getfd: %s: number expected after '/'\n", str);
++		return -1;
 +	}
++	snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
 +	if (mode == (SIO_PLAY | SIO_REC))
 +		flags = O_RDWR;
 +	else
@@ -351,8 +266,8 @@
 +	return fd;
 +}
 +
-+static struct sio_oss_hdl *
-+sio_oss_fdopen(int fd, unsigned int mode, int nbio)
++static struct sio_hdl *
++sio_oss_fdopen(const char *str, int fd, unsigned int mode, int nbio)
 +{
 +	struct sio_oss_hdl *hdl;
 +
@@ -362,15 +277,15 @@
 +	_sio_create(&hdl->sio, &sio_oss_ops, mode, nbio);
 +
 +	/* Set default device parameters */
-+	sio_oss_fmt_to_swpar(AFMT_S16_LE, &hdl->swpar);
-+	hdl->swpar.msb = 1;
-+	hdl->swpar.rate = 48000;
-+	hdl->swpar.bps = SIO_BPS(hdl->swpar.bits);
-+	hdl->swpar.pchan = hdl->swpar.rchan = 2;
++	hdl->fmt = AFMT_S16_LE;
++	hdl->rate = 48000;
++	hdl->chan = 2;
++	hdl->round = 960;
++	hdl->appbufsz = 8 * 960;
 +
 +	hdl->fd = fd;
 +
-+	return hdl;
++	return (struct sio_hdl *)hdl;
 +}
 +
 +struct sio_hdl *
@@ -383,11 +298,10 @@
 +	if (fd < 0)
 +		return NULL;
 +
-+	hdl = sio_oss_fdopen(fd, mode, nbio);
-+	if (hdl != NULL) {
-+		hdl->devstr = strdup(str);
++	hdl = (struct sio_oss_hdl *)sio_oss_fdopen(str, fd, mode, nbio);
++	if (hdl != NULL)
 +		return (struct sio_hdl*)hdl;
-+        }
++
 +	while (close(fd) < 0 && errno == EINTR)
 +		; /* retry */
 +
@@ -401,7 +315,6 @@
 +
 +	while (close(hdl->fd) < 0 && errno == EINTR)
 +		; /* retry */
-+	free(hdl->devstr);
 +	free(hdl);
 +}
 +
@@ -409,18 +322,14 @@
 +sio_oss_start(struct sio_hdl *sh)
 +{
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
-+	int low;
 +
-+	hdl->obpf = hdl->sio.par.pchan * hdl->sio.par.bps;
-+	hdl->ibpf = hdl->sio.par.rchan * hdl->sio.par.bps;
 +	hdl->isamples = 0;
 +	hdl->osamples = 0;
 +	hdl->idelta = 0;
 +	hdl->odelta = 0;
 +
-+	/* Nothing else to do here, device was just (re-)opened in
-+	 * sio_setpar and OSS starts playing/recording on first
-+	 * write/read.
++	/* Nothing else to do here.  OSS starts playing/recording
++	 * on first write/read.
 +	 */
 +	_sio_onmove_cb(&hdl->sio, 0);
 +
@@ -431,45 +340,95 @@
 +sio_oss_stop(struct sio_hdl *sh)
 +{
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl*)sh;
-+	/* Close and reopen device.  This resets CURRENT_IPTR which
-+	 * allows us to get a semi-accurate recording position */
-+        if (sio_oss_audio_setpar(hdl, &hdl->swpar) < 0)
-+		return 0;
-+	return 1;
++
++        if (ioctl(hdl->fd, SNDCTL_DSP_SYNC, NULL) < 0) {
++            DPERROR("sio_oss_stop: SYNC");
++            hdl->sio.eof = 1;
++            return 0;
++        }
++        if (ioctl(hdl->fd, SNDCTL_DSP_HALT, NULL) < 0) {
++            DPERROR("sio_oss_stop: HALT");
++            hdl->sio.eof = 1;
++            return 0;
++        }
++
++        /* Reset device parameters.  When we do not do this, resuming
++         * playback/recording will trigger poll with revents=POLLIN
++         * too often, which leads to sndiod using 100 % CPU.
++         */
++        return sio_oss_setpar(sh, &hdl->sio.par);
 +}
 +
 +static int
 +sio_oss_setpar(struct sio_hdl *sh, struct sio_par *par)
 +{
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
-+	struct audio_swpar ap;
-+
-+	AUDIO_INITPAR(&ap);
-+	ap.sig = par->sig;
-+	ap.le = par->le;
-+	ap.bits = par->bits;
-+	ap.bps = par->bps;
-+	ap.msb = par->msb;
-+	ap.rate = par->rate;
++	unsigned int i;
++	int policy;
++
++	hdl->fmt = AFMT_S16_LE;
++	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
++		if (formats[i].bits == par->bits
++		    && formats[i].le == par->le
++		    && formats[i].sig == par->sig
++		    && formats[i].msb == par->msb) {
++			hdl->fmt = formats[i].fmt;
++			break;
++		}
++	}
++
++	if (par->rate != ~0U)
++		hdl->rate = par->rate;
++	if (hdl->rate < 8000)
++		hdl->rate = 8000;
++	if (hdl->rate > 192000)
++		hdl->rate = 192000;
++
 +	if (hdl->sio.mode & SIO_PLAY)
-+		ap.pchan = par->pchan;
-+	if (hdl->sio.mode & SIO_REC)
-+		ap.rchan = par->rchan;
++		hdl->chan = par->pchan;
++	else if (hdl->sio.mode & SIO_REC)
++		hdl->chan = par->rchan;
++
 +	if (par->round != ~0U && par->appbufsz != ~0U) {
-+		ap.round = par->round;
-+		ap.nblks = par->appbufsz / par->round;
++		hdl->round = par->round;
++		hdl->appbufsz = par->appbufsz;
 +	} else if (par->round != ~0U) {
-+		ap.round = par->round;
-+		ap.nblks = 2;
++		hdl->round = par->round;
++		hdl->appbufsz = 2 * par->round;
 +	} else if (par->appbufsz != ~0U) {
-+		ap.round = par->appbufsz / 2;
-+		ap.nblks = 2;
++		hdl->round = par->appbufsz / 2;
++		hdl->appbufsz = par->appbufsz;
++	}
++
++	/* Set timing policy to 5 which is OSS' default.  The
++	 * user-settable hw.snd.latency sysctl influences the default
++	 * policy.
++	 */
++	policy = 5;
++	if (ioctl(hdl->fd, SNDCTL_DSP_POLICY, &policy) < 0) {
++		DPERROR("sio_oss_setpar: POLICY");
++		hdl->sio.eof = 1;
++		return 0;
++	}
++
++	if (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &hdl->fmt) < 0) {
++		DPERROR("sio_oss_setpar: SETFMT");
++		hdl->sio.eof = 1;
++		return 0;
++	}
++
++	if (ioctl(hdl->fd, SNDCTL_DSP_SPEED, &hdl->rate) < 0) {
++		DPERROR("sio_oss_setpar: SPEED");
++		hdl->sio.eof = 1;
++		return 0;
 +	}
-+	if (sio_oss_audio_setpar(hdl, &ap) < 0) {
-+		DPERROR("AUDIO_SETPAR");
++
++	if (ioctl(hdl->fd, SNDCTL_DSP_CHANNELS, &hdl->chan) < 0) {
++		DPERROR("sio_oss_setpar: CHANNELS");
 +		hdl->sio.eof = 1;
 +		return 0;
 +	}
++
 +	return 1;
 +}
 +
@@ -477,24 +436,32 @@
 +sio_oss_getpar(struct sio_hdl *sh, struct sio_par *par)
 +{
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
-+	struct audio_swpar ap;
-+
-+	if (sio_oss_audio_getpar(hdl, &ap) < 0) {
-+		DPERROR("AUDIO_GETPAR");
++	unsigned int i, found = 0;
++
++	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
++		if (formats[i].fmt == hdl->fmt) {
++			par->sig = formats[i].sig;
++			par->le = formats[i].le;
++			par->bits = formats[i].bits;
++			par->bps = formats[i].bps;
++			par->msb = formats[i].msb;
++			found = 1;
++			break;
++		}
++	}
++	if (!found) {
++		DPRINTF("sio_oss_getpar: unknown format %d\n", hdl->fmt);
 +		hdl->sio.eof = 1;
 +		return 0;
 +	}
-+	par->sig = ap.sig;
-+	par->le = ap.le;
-+	par->bits = ap.bits;
-+	par->bps = ap.bps;
-+	par->msb = ap.msb;
-+	par->rate = ap.rate;
-+	par->pchan = ap.pchan;
-+	par->rchan = ap.rchan;
-+	par->round = ap.round;
-+	par->appbufsz = par->bufsz = ap.round * ap.nblks;
++
++	par->rate = hdl->rate;
++	par->pchan = hdl->chan;
++	par->rchan = hdl->chan;
++	par->round = hdl->round;
++	par->appbufsz = par->bufsz = hdl->appbufsz;
 +	par->xrun = SIO_IGNORE;
++
 +	return 1;
 +}
 +
@@ -560,10 +527,64 @@
 +	return 1;
 +}
 +
-+int
++static int
++sio_oss_xrun(struct sio_oss_hdl *hdl)
++{
++	int clk;
++	int wsil, rdrop, cmove;
++	int rbpf, rround;
++	int wbpf;
++
++	DPRINTFN(2, "sio_oss_xrun:\n");
++	if (_sndio_debug >= 2)
++		_sio_printpos(&hdl->sio);
++
++	/*
++	 * we assume rused/wused are zero if rec/play modes are not
++	 * selected. This allows us to keep the same formula for all
++	 * modes, provided we set rbpf/wbpf to 1 to avoid division by
++	 * zero.
++	 *
++	 * to understand the formula, draw a picture :)
++	 */
++	rbpf = (hdl->sio.mode & SIO_REC) ?
++	    hdl->sio.par.bps * hdl->sio.par.rchan : 1;
++	wbpf = (hdl->sio.mode & SIO_PLAY) ?
++	    hdl->sio.par.bps * hdl->sio.par.pchan : 1;
++	rround = hdl->sio.par.round * rbpf;
++
++	clk = hdl->sio.cpos % hdl->sio.par.round;
++	rdrop = (clk * rbpf - hdl->sio.rused) % rround;
++	if (rdrop < 0)
++		rdrop += rround;
++	cmove = (rdrop + hdl->sio.rused) / rbpf;
++	wsil = cmove * wbpf + hdl->sio.wused;
++
++	DPRINTFN(2, "wsil = %d, cmove = %d, rdrop = %d\n", wsil, cmove, rdrop);
++
++	if (!sio_oss_stop(&hdl->sio))
++		return 0;
++	if (!sio_oss_start(&hdl->sio))
++		return 0;
++	if (hdl->sio.mode & SIO_PLAY) {
++		hdl->odelta -= cmove;
++		hdl->sio.wsil = wsil;
++	}
++	if (hdl->sio.mode & SIO_REC) {
++		hdl->idelta -= cmove;
++		hdl->sio.rdrop = rdrop;
++	}
++	DPRINTFN(2, "xrun: corrected\n");
++	DPRINTFN(2, "wsil = %d, rdrop = %d, odelta = %d, idelta = %d\n",
++	    wsil, rdrop, hdl->odelta, hdl->idelta);
++	return 1;
++}
++
++static int
 +sio_oss_revents(struct sio_hdl *sh, struct pollfd *pfd)
 +{
 +	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
++	audio_errinfo ei;
 +	int delta;
 +	int revents = pfd->revents;
 +	long long play_pos, rec_pos;
@@ -573,9 +594,21 @@
 +	    (pfd->revents & (POLLIN | POLLOUT)) == 0)
 +		return pfd->revents;
 +
++	/* Hide xruns from clients */
++	if (ioctl(hdl->fd, SNDCTL_DSP_GETERROR, &ei) < 0) {
++		DPERROR("sio_oss_revents: GETERROR");
++		hdl->sio.eof = 1;
++		return POLLHUP;
++	}
++	if (ei.play_underruns > 0 || ei.rec_overruns > 0) {
++		if (!sio_oss_xrun(hdl))
++			return POLLHUP;
++		return 0;
++	}
++
 +	if (hdl->sio.mode & SIO_PLAY) {
 +		if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_OPTR, &optr) < 0) {
-+			DPERROR("sio_oss_revents: ");
++			DPERROR("sio_oss_revents: CURRENT_OPTR");
 +			hdl->sio.eof = 1;
 +			return POLLHUP;
 +		}
@@ -589,7 +622,7 @@
 +	}
 +	if (hdl->sio.mode & SIO_REC) {
 +		if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_IPTR, &iptr) < 0) {
-+			DPERROR("sio_oss_revents: ");
++			DPERROR("sio_oss_revents: CURRENT_IPTR");
 +			hdl->sio.eof = 1;
 +			return POLLHUP;
 +		}
@@ -611,231 +644,4 @@
 +	return revents;
 +}
 +
-+static void
-+sio_oss_fmt_to_swpar(int fmt, struct audio_swpar *ap) {
-+	switch(fmt) {
-+	case AFMT_S8:
-+		ap->le = 1;
-+		ap->sig = 1;
-+		ap->bits = 8;
-+		break;
-+	case AFMT_U8:
-+		ap->le = 1;
-+		ap->sig = 0;
-+		ap->bits = 8;
-+		break;
-+	case AFMT_S16_LE:
-+		ap->le = 1;
-+		ap->sig = 1;
-+		ap->bits = 16;
-+		break;
-+	case AFMT_S16_BE:
-+		ap->le = 0;
-+		ap->sig = 1;
-+		ap->bits = 16;
-+		break;
-+	case AFMT_U16_LE:
-+		ap->le = 1;
-+		ap->sig = 0;
-+		ap->bits = 16;
-+		break;
-+	case AFMT_U16_BE:
-+		ap->le = 0;
-+		ap->sig = 0;
-+		ap->bits = 16;
-+		break;
-+	case AFMT_S24_LE:
-+		ap->le = 1;
-+		ap->sig = 1;
-+		ap->bits = 24;
-+		break;
-+	case AFMT_S24_BE:
-+		ap->le = 0;
-+		ap->sig = 1;
-+		ap->bits = 24;
-+		break;
-+	case AFMT_U24_LE:
-+		ap->le = 1;
-+		ap->sig = 0;
-+		ap->bits = 24;
-+		break;
-+	case AFMT_U24_BE:
-+		ap->le = 0;
-+		ap->sig = 0;
-+		ap->bits = 24;
-+		break;
-+	case AFMT_S32_LE:
-+		ap->le = 1;
-+		ap->sig = 1;
-+		ap->bits = 32;
-+		break;
-+	case AFMT_S32_BE:
-+		ap->le = 0;
-+		ap->sig = 1;
-+		ap->bits = 32;
-+		break;
-+	case AFMT_U32_LE:
-+		ap->le = 1;
-+		ap->sig = 0;
-+		ap->bits = 32;
-+		break;
-+	case AFMT_U32_BE:
-+		ap->le = 0;
-+		ap->sig = 0;
-+		ap->bits = 32;
-+		break;
-+	}
-+}
-+
-+static int
-+sio_oss_swpar_to_fmt(struct audio_swpar *ap)
-+{
-+	unsigned int bits = ap->bits;
-+	unsigned int sig = ap->sig;
-+	unsigned int le = ap->le;
-+
-+	switch(bits) {
-+	case 8:
-+		if (sig)
-+			return AFMT_S8;
-+		else
-+			return AFMT_U8;
-+		break;
-+	case 16:
-+		if (sig)
-+			if (le)
-+				return AFMT_S16_LE;
-+			else
-+				return AFMT_S16_BE;
-+		else
-+			if (le)
-+				return AFMT_U16_LE;
-+			else
-+				return AFMT_U16_BE;
-+		break;
-+		break;
-+	case 24:
-+		if (sig)
-+			if (le)
-+				return AFMT_S24_LE;
-+			else
-+				return AFMT_S24_BE;
-+		else
-+			if (le)
-+				return AFMT_U24_LE;
-+			else
-+				return AFMT_U24_BE;
-+		break;
-+		break;
-+	case 32:
-+		if (sig)
-+			if (le)
-+				return AFMT_S32_LE;
-+			else
-+				return AFMT_S32_BE;
-+		else
-+			if (le)
-+				return AFMT_U32_LE;
-+			else
-+				return AFMT_U32_BE;
-+		break;
-+	default:
-+		if (sig)
-+			if (SIO_LE_NATIVE)
-+				return AFMT_S16_LE;
-+			else
-+				return AFMT_S16_BE;
-+		else
-+			if (SIO_LE_NATIVE)
-+				return AFMT_U16_LE;
-+			else
-+				return AFMT_U16_BE;
-+	}
-+}
-+
-+static int sio_oss_audio_getpar(struct sio_oss_hdl *hdl, struct audio_swpar *ap)
-+{
-+	audio_buf_info bi;
-+
-+	*ap = hdl->swpar;
-+
-+	return 0;
-+}
-+
-+static int sio_oss_audio_setpar(struct sio_oss_hdl *hdl, struct audio_swpar *ap)
-+{
-+	audio_buf_info bi;
-+	int bufsz;
-+	int chan;
-+	int fmt;
-+	int rate;
-+
-+	if (sio_oss_reopen(hdl) < 0) {
-+		DPERROR("sio_oss_audio_setpar: reopen");
-+		return -1;
-+	}
-+
-+	ap->msb = ap->msb == -1 ? 0 : ap->msb;
-+	ap->sig = ap->sig == -1 ? 1 : ap->sig;
-+	ap->bits = ap->bits == -1 ? ap->bps == -1 ? 16 : ap->bps*8 : ap->bits;
-+	ap->le = ap->le == -1 ? SIO_LE_NATIVE : ap->le;
-+	ap->bps = ap->bps == -1 ? SIO_BPS(ap->bits) : ap->bps;
-+	ap->msb = 0;
-+	ap->rate = ap->rate == -1 ? 48000 : ap->rate;
-+
-+	if (ap->bits < 8)
-+		ap->bits = 8;
-+	if (ap->bits > 32)
-+		ap->bits = 32;
-+	if (ap->bps < 1)
-+		ap->bps = 1;
-+	if (ap->bps > 4)
-+		ap->bps = 4;
-+	if (ap->rate < 4000)
-+		ap->rate = 4000;
-+	if (ap->rate > 192000)
-+		ap->rate = 192000;
-+
-+	fmt = sio_oss_swpar_to_fmt(ap);
-+	if (fmt < 0)
-+		return -1;
-+	if (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &fmt) < 0) {
-+		DPERROR("sio_oss_audio_setpar: SETFMT");
-+		return -1;
-+	}
-+	sio_oss_fmt_to_swpar(fmt, ap);
-+
-+	if (ioctl(hdl->fd, SNDCTL_DSP_SPEED, &ap->rate) < 0) {
-+		DPERROR("sio_oss_audio_setpar: SPEED");
-+		return -1;
-+	}
-+
-+	chan = ap->pchan == ~0U ? ap->pchan : ap->rchan;
-+	chan = chan == -1 ? 2 : chan;
-+	if (ioctl(hdl->fd, SNDCTL_DSP_CHANNELS, &chan) < 0) {
-+		DPERROR("sio_oss_audio_setpar: CHANNELS");
-+		return -1;
-+	}
-+	ap->pchan = ap->rchan = chan;
-+
-+	ap->nblks = ap->nblks <= 0 ? 8 : ap->nblks;
-+	ap->round = ap->round <= 0 ? 960 : ap->round;
-+
-+	hdl->swpar = *ap;
-+
-+	return 0;
-+}
-+
-+static int sio_oss_reopen(struct sio_oss_hdl *hdl) {
-+	/* Reopen device */
-+	while (close(hdl->fd) < 0 && errno == EINTR)
-+		; /* retry */
-+	hdl->fd = sio_oss_getfd(hdl->devstr, hdl->sio.mode, 1);
-+	if (hdl->fd < 0) {
-+		DPERROR("sio_oss_audio_setpar: reopen");
-+		return -1;
-+	}
-+	return 0;
-+}
-+
 +#endif /* defined USE_OSS */
diff --git a/audio/sndio/files/sndiod.in b/audio/sndio/files/sndiod.in
old mode 100644
new mode 100755
index 87d1087..2300f2b
--- a/audio/sndio/files/sndiod.in
+++ b/audio/sndio/files/sndiod.in
@@ -3,19 +3,10 @@
 # $FreeBSD$
 #
 # PROVIDE: sndiod
-# REQUIRE: NETWORKING
+# REQUIRE: NETWORKING sysctl
 # BEFORE:  DAEMON
 # KEYWORD: shutdown
 
-# By default sndiod will use the audio device from
-# hw.snd.default_unit.  You can override this by setting sndiod_flags.
-#
-# To connect to a remote sndiod use e.g.
-# sndiod_flags="-f snd@remotehost/0"
-#
-# To use /dev/dsp5
-# sndiod_flags="-f rsnd/5"
-
 . /etc/rc.subr
 
 name=sndiod
@@ -23,8 +14,9 @@ rcvar=sndiod_enable
 
 load_rc_config $name
 
+: ${sndiod_dev="rsnd/$($SYSCTL -n hw.snd.default_unit)"}
 : ${sndiod_enable="NO"}
-: ${sndiod_flags="-s default -m mon -s monitor"}
+: ${sndiod_flags="-f ${sndiod_dev} -c 0:7 -j off -s default -m mon -s monitor"}
 
 command="%%PREFIX%%/bin/sndiod"
 
diff --git a/audio/sndio/pkg-message b/audio/sndio/pkg-message
index 7b4572d..de3663c 100644
--- a/audio/sndio/pkg-message
+++ b/audio/sndio/pkg-message
@@ -1,7 +1,3 @@
-Sndio's OSS support (i.e. local playback/recording support) is highly
-experimental.  If you run into problems please file a bug at
-https://github.com/t6/sndio or send an email to t+sndio@tobik.me.
-
 Enable the sndiod server with:
 
     sysrc sndiod_enable=YES
@@ -13,19 +9,12 @@ plays through sndiod:
 
     aucat -f snd/0.monitor -o recording.wav
 
-Make sure you override sndiod_flags if this is not wanted:
-
-    sysrc sndiod_flags=""
-
-If you want clients to auto-play to your remote sndio server set
-sndiod_flags accordingly:
-
-    sysrc sndiod_flags="-f snd@remotehost/0"
-
-Alternatively you can always set the AUDIODEVICE environment variable
-so clients know where to stream to:
+Make sure you override sndiod_flags if this is not wanted.
 
-    export AUDIODEVICE=snd@remotehost/0
+By default the rc.d script passes '-c 0:7 -j off' to sndiod, so that
+it uses all 8 virtual channels provided by OSS.  If you override
+sndiod_flags consider keeping these options, so that multi-channel
+audio works as you'd expect.
 
 There is little sndio support in the FreeBSD ports tree right now.  If
 your favourite port is missing support please take a look at the fork