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..df12ac2 --- /dev/null +++ b/audio/sndio/files/patch-libsndio_mio__umidi.c @@ -0,0 +1,226 @@ +--- libsndio/mio_umidi.c.orig 2016-11-06 09:07:13 UTC ++++ libsndio/mio_umidi.c +@@ -0,0 +1,223 @@ ++/* $OpenBSD$ */ ++/* ++ * Copyright (c) 2008 Alexandre Ratchov ++ * Copyright (c) 2016 Tobias Kortkamp ++ * ++ * 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 ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#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; ++ case '\0': ++ subdevnum = 0; ++ break; ++ default: ++ DPRINTF("mio_umidi_getfd: %s: dot or end of string expected after first number\n", str); ++ return -1; ++ } ++ 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..3e1eaed 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-06 09:07:13 UTC +++ libsndio/sio_oss.c -@@ -0,0 +1,838 @@ +@@ -0,0 +1,739 @@ +/* $OpenBSD$ */ +/* + * Copyright (c) 2008 Alexandre Ratchov @@ -20,15 +20,11 @@ + */ + +#ifdef USE_OSS -+#include +#include -+#include +#include -+#include + +#include +#include -+#include +#include +#include +#include @@ -44,58 +40,77 @@ + 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; ++}; + -+/* -+ * 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]; ++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. ++ */ ++ ++ /* 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 */ ++ int idelta, odelta; ++ int iused; ++ int oused; ++ int bpf; + -+ char *devstr; ++ int fmt; ++ unsigned int rate; ++ unsigned int chan; ++ unsigned int appbufsz; ++ unsigned int round; + -+ /* 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 filling; +}; + -+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 +128,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 +165,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 +227,6 @@ + } + cap->nconf = nconf; + -+ if (sio_oss_audio_setpar(hdl, &savepar)) { -+ DPERROR("AUDIO_SETPAR"); -+ hdl->sio.eof = 1; -+ return 0; -+ } + return 1; +} + @@ -309,35 +236,27 @@ + const char *p; + char path[DEVPATH_MAX]; + unsigned int devnum; -+ int fd, flags; ++ int fd, flags, val; + -+ 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 @@ -348,11 +267,17 @@ + DPERROR(path); + return -1; + } ++ val = 1; ++ if (ioctl(fd, SNDCTL_DSP_LOW_WATER, &val) < 0) { ++ DPERROR("sio_oss_start: LOW_WATER"); ++ close(fd); ++ return -1; ++ } + 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 +287,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->filling = 0; + hdl->fd = fd; + -+ return hdl; ++ return (struct sio_hdl *)hdl; +} + +struct sio_hdl * @@ -383,11 +308,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 +325,6 @@ + + while (close(hdl->fd) < 0 && errno == EINTR) + ; /* retry */ -+ free(hdl->devstr); + free(hdl); +} + @@ -409,21 +332,32 @@ +sio_oss_start(struct sio_hdl *sh) +{ + struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh; -+ int low; ++ int trig; + -+ 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->iused = 0; ++ hdl->oused = 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. -+ */ -+ _sio_onmove_cb(&hdl->sio, 0); -+ ++ if (hdl->sio.mode & SIO_PLAY) { ++ /* ++ * keep the device paused and let sio_oss_pollfd() trigger the ++ * start later, to avoid buffer underruns ++ */ ++ hdl->filling = 1; ++ trig = 0; ++ } else { ++ /* ++ * no play buffers to fill, start now! ++ */ ++ trig = PCM_ENABLE_INPUT; ++ _sio_onmove_cb(&hdl->sio, 0); ++ } ++ if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { ++ DPERROR("sio_oss_start: SETTRIGGER"); ++ hdl->sio.eof = 1; ++ return 0; ++ } + return 1; +} + @@ -431,10 +365,18 @@ +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) ++ int trig; ++ ++ if (hdl->filling) { ++ hdl->filling = 0; ++ return 1; ++ } ++ trig = 0; ++ if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { ++ DPERROR("sio_oss_stop: SETTRIGGER"); ++ hdl->sio.eof = 1; + return 0; ++ } + return 1; +} + @@ -442,34 +384,99 @@ +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, round, bufsz; ++ int frag_max, frag_shift, frag_count, frag; ++ ++ 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 (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &hdl->fmt) < 0) { ++ DPERROR("sio_oss_setpar: SETFMT"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ ++ for (i = 0; ; i++) { ++ if (i == sizeof(formats) / sizeof(formats[0])) { ++ DPRINTF("sio_oss_setpar: unknown fmt %d\n", hdl->fmt); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ if (formats[i].fmt == hdl->fmt) ++ break; ++ } ++ ++ if (ioctl(hdl->fd, SNDCTL_DSP_SPEED, &hdl->rate) < 0) { ++ DPERROR("sio_oss_setpar: SPEED"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ ++ if (ioctl(hdl->fd, SNDCTL_DSP_CHANNELS, &hdl->chan) < 0) { ++ DPERROR("sio_oss_setpar: CHANNELS"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ ++ hdl->bpf = formats[i].bps * hdl->chan; ++ + if (par->round != ~0U && par->appbufsz != ~0U) { -+ ap.round = par->round; -+ ap.nblks = par->appbufsz / par->round; ++ round = par->round; ++ bufsz = par->appbufsz; + } else if (par->round != ~0U) { -+ ap.round = par->round; -+ ap.nblks = 2; ++ round = par->round; ++ bufsz = 2 * par->round; + } else if (par->appbufsz != ~0U) { -+ ap.round = par->appbufsz / 2; -+ ap.nblks = 2; ++ round = par->appbufsz / 2; ++ bufsz = par->appbufsz; ++ } else { ++ /* ++ * even if it's not specified, we have to set the ++ * block size to ensure that both play and record ++ * direction get the same block size. Pick an ++ * arbitrary value that would work for most players at ++ * 48kHz, stereo, 16-bit. ++ */ ++ round = 512; ++ bufsz = 1024; + } -+ if (sio_oss_audio_setpar(hdl, &ap) < 0) { -+ DPERROR("AUDIO_SETPAR"); ++ ++ frag_max = round * hdl->chan * formats[i].bps; ++ frag_shift = 8; ++ while (1 << (frag_shift + 1) <= frag_max) ++ frag_shift++; ++ ++ frag_count = bufsz / round; ++ if (frag_count < 2) ++ frag_count = 2; ++ ++ frag = frag_count << 16 | frag_shift; ++ if (ioctl(hdl->fd, SNDCTL_DSP_SETFRAGMENT, &frag) < 0) { ++ DPERROR("sio_oss_setpar: SETFRAGMENT"); + hdl->sio.eof = 1; + return 0; + } ++ + return 1; +} + @@ -477,24 +484,65 @@ +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; ++ audio_buf_info pbi, rbi; ++ ++ 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->xrun = SIO_IGNORE; ++ ++ if (hdl->sio.mode & SIO_PLAY) { ++ if (ioctl(hdl->fd, SNDCTL_DSP_GETOSPACE, &pbi) < 0) { ++ DPERROR("sio_oss_getpar: SNDCTL_DSP_GETOSPACE"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ par->round = pbi.fragsize / (par->pchan * par->bps); ++ par->bufsz = pbi.fragstotal * par->round; ++ } ++ if (hdl->sio.mode & SIO_REC) { ++ if (ioctl(hdl->fd, SNDCTL_DSP_GETISPACE, &rbi) < 0) { ++ DPERROR("sio_oss_getpar: SNDCTL_DSP_GETISPACE"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ if (!(hdl->sio.mode & SIO_PLAY)) { ++ par->round = rbi.fragsize / (par->rchan * par->bps); ++ par->bufsz = rbi.fragstotal * par->round; ++ } ++ } ++ par->appbufsz = par->bufsz; ++#ifdef DEBUG ++ if ((hdl->sio.mode & (SIO_REC | SIO_PLAY)) == (SIO_REC | SIO_PLAY)) { ++ if (pbi.fragsize != rbi.fragsize) { ++ DPRINTF("sio_oss_getpar: frag size/count mismatch\n" ++ "play: count = %d, size = %d\n" ++ "rec: count = %d, size = %d\n", ++ pbi.fragstotal, pbi.fragsize, ++ rbi.fragstotal, rbi.fragsize); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ } ++#endif + return 1; +} + @@ -519,6 +567,7 @@ + return 0; + } + ++ hdl->idelta += n; + return n; +} + @@ -540,6 +589,7 @@ + return 0; + } + ++ hdl->odelta += n; + return n; +} + @@ -553,289 +603,140 @@ +sio_oss_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events) +{ + struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh; ++ int trig; + + pfd->fd = hdl->fd; + pfd->events = events; ++ if (hdl->filling && hdl->sio.wused == hdl->sio.par.bufsz * ++ hdl->sio.par.pchan * hdl->sio.par.bps) { ++ hdl->filling = 0; ++ trig = 0; ++ if (hdl->sio.mode & SIO_PLAY) ++ trig |= PCM_ENABLE_OUTPUT; ++ if (hdl->sio.mode & SIO_REC) ++ trig |= PCM_ENABLE_INPUT; ++ if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { ++ DPERROR("sio_oss_pollfd: SETTRIGGER"); ++ hdl->sio.eof = 1; ++ return 0; ++ } ++ _sio_onmove_cb(&hdl->sio, 0); ++ } ++ return 1; ++} + ++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->bpf; ++ hdl->sio.wsil = wsil; ++ } ++ if (hdl->sio.mode & SIO_REC) { ++ hdl->idelta -= cmove * hdl->bpf; ++ 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; +} + -+int ++static int +sio_oss_revents(struct sio_hdl *sh, struct pollfd *pfd) +{ + struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh; -+ int delta; ++ audio_errinfo ei; ++ int delta, iused, oused; + int revents = pfd->revents; -+ long long play_pos, rec_pos; + oss_count_t optr, iptr; + + if ((pfd->revents & POLLHUP) || + (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; + } -+ play_pos = optr.samples - optr.fifo_samples; -+ delta = play_pos - hdl->osamples; -+ hdl->osamples = play_pos; -+ hdl->odelta += delta; ++ oused = optr.fifo_samples * hdl->bpf; ++ hdl->odelta -= oused - hdl->oused; ++ hdl->oused = oused; + if (!(hdl->sio.mode & SIO_REC)) { -+ hdl->idelta += delta; ++ hdl->idelta = hdl->odelta; + } + } + 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; + } -+ rec_pos = iptr.samples - iptr.fifo_samples; -+ delta = rec_pos - hdl->isamples; -+ hdl->isamples = rec_pos; -+ hdl->idelta += delta; ++ iused = iptr.fifo_samples * hdl->bpf; ++ hdl->idelta += iused - hdl->iused; ++ hdl->iused = iused; + if (!(hdl->sio.mode & SIO_PLAY)) { -+ hdl->odelta += delta; ++ hdl->odelta = hdl->idelta; + } + } + + delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta; + if (delta > 0) { -+ _sio_onmove_cb(&hdl->sio, delta); ++ _sio_onmove_cb(&hdl->sio, delta / hdl->bpf); + hdl->idelta -= delta; + hdl->odelta -= delta; + } + 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