aboutsummaryrefslogtreecommitdiff
path: root/audio/portaudio
diff options
context:
space:
mode:
authorTobias Kortkamp <tobik@FreeBSD.org>2017-03-21 12:05:55 +0000
committerTobias Kortkamp <tobik@FreeBSD.org>2017-03-21 12:05:55 +0000
commitfed5cabe2d35c87d5914e8e5336829addc2e83fd (patch)
treed10c9af07f3cdd4972ccc444f733145ef244e0dc /audio/portaudio
parent5c894a379ba72b3c6f907416ed7eb355aa63fd0f (diff)
downloadports-fed5cabe2d35c87d5914e8e5336829addc2e83fd.tar.gz
ports-fed5cabe2d35c87d5914e8e5336829addc2e83fd.zip
- Add SNDIO option
- Reset maintainer after 4 consecutive maintainer timeouts - Use *_CONFIGURE_WITH options helper - Do not install tests by default PR: 217385 Obtained from: OpenBSD Approved by: lme (mentor), maintainer timeout (3 weeks) Differential Revision: https://reviews.freebsd.org/D10072
Notes
Notes: svn path=/head/; revision=436589
Diffstat (limited to 'audio/portaudio')
-rw-r--r--audio/portaudio/Makefile23
-rw-r--r--audio/portaudio/files/pa_sndio.c713
-rw-r--r--audio/portaudio/files/patch-Makefile.in11
-rw-r--r--audio/portaudio/files/patch-configure.in47
-rw-r--r--audio/portaudio/files/patch-include_portaudio.h13
-rw-r--r--audio/portaudio/files/patch-src_os_unix_pa__unix__hostapis.c26
6 files changed, 823 insertions, 10 deletions
diff --git a/audio/portaudio/Makefile b/audio/portaudio/Makefile
index 57a349736e5b..436cefb23f76 100644
--- a/audio/portaudio/Makefile
+++ b/audio/portaudio/Makefile
@@ -3,26 +3,24 @@
PORTNAME= portaudio
DISTVERSION= 19_20140130
-PORTREVISION= 5
+PORTREVISION= 6
CATEGORIES= audio
MASTER_SITES= http://www.portaudio.com/archives/
DISTNAME= pa_stable_v${DISTVERSION}
-MAINTAINER= koalative@gmail.com
+MAINTAINER= ports@FreeBSD.org
COMMENT= Portable cross-platform Audio API
LICENSE= MIT
LICENSE_FILE= ${WRKSRC}/LICENSE.txt
-USES= dos2unix gmake libtool pathfix pkgconfig tar:tgz
+USES= autoreconf dos2unix gmake localbase:ldflags libtool pathfix \
+ pkgconfig tar:tgz
GNU_CONFIGURE= yes
CONFIGURE_ARGS= PKG_CONFIG_LIBDIR=${PREFIX}/libdata/pkgconfig \
--without-alsa
USE_LDCONFIG= yes
-CPPFLAGS+= -I${LOCALBASE}/include
-LDFLAGS+= -lpthread -L${LOCALBASE}/lib
-
WRKSRC= ${WRKDIR}/${PORTNAME}
PORTDOCS= *
@@ -31,8 +29,7 @@ PORTEXAMPLES= *
DOCSRCDIR1= ${WRKSRC}
DOC_FILES1= README.txt index.html
-OPTIONS_DEFINE= DOCS DOXYGEN EXAMPLES JACK PATEST
-OPTIONS_DEFAULT=PATEST
+OPTIONS_DEFINE= DOCS DOXYGEN EXAMPLES JACK PATEST SNDIO
PATEST_DESC= PortAudio Test Programs
DOXYGEN_DESC= Install API documentation (requires DOCS)
@@ -40,14 +37,20 @@ DOXYGEN_DESC= Install API documentation (requires DOCS)
OPTIONS_SUB= yes
JACK_LIB_DEPENDS= libjack.so:audio/jack
-JACK_CONFIGURE_ON= --with-jack
-JACK_CONFIGURE_OFF= --without-jack
+JACK_CONFIGURE_WITH= jack
PATEST_BIN= pa_m* paqa_* patest*
+SNDIO_LIB_DEPENDS= libsndio.so:audio/sndio
+SNDIO_CONFIGURE_WITH= sndio
+
DOXYGEN_IMPLIES= DOCS
DOXYGEN_BUILD_DEPENDS= doxygen:devel/doxygen
+post-extract:
+ @${MKDIR} ${WRKSRC}/src/hostapi/sndio
+ @${CP} ${FILESDIR}/pa_sndio.c ${WRKSRC}/src/hostapi/sndio
+
post-patch:
@${REINPLACE_CMD} -e 's|machine/soundcard.h|sys/soundcard.h|' ${WRKSRC}/configure.in \
${WRKSRC}/src/hostapi/oss/pa_unix_oss.c ${WRKSRC}/src/SConscript
diff --git a/audio/portaudio/files/pa_sndio.c b/audio/portaudio/files/pa_sndio.c
new file mode 100644
index 000000000000..dd1c145ecbb1
--- /dev/null
+++ b/audio/portaudio/files/pa_sndio.c
@@ -0,0 +1,713 @@
+/*
+ * Copyright (c) 2009 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.
+ */
+#include <sys/types.h>
+#include <pthread.h>
+#include <poll.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sndio.h>
+
+#include "pa_util.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_process.h"
+#include "pa_allocation.h"
+
+#if 0
+#define DPR(...) do { fprintf(stderr, __VA_ARGS__); } while (0)
+#else
+#define DPR(...) do {} while (0)
+#endif
+
+/*
+ * per-stream data
+ */
+typedef struct PaSndioStream
+{
+ PaUtilStreamRepresentation base;
+ PaUtilBufferProcessor bufproc; /* format conversion */
+ struct sio_hdl *hdl; /* handle for device i/o */
+ struct sio_par par; /* current device parameters */
+ unsigned mode; /* SIO_PLAY, SIO_REC or both */
+ int stopped; /* stop requested or not started */
+ int active; /* thread is running */
+ unsigned long long realpos; /* frame number h/w is processing */
+ char *rbuf, *wbuf; /* bounce buffers for conversions */
+ unsigned long long rpos, wpos; /* bytes read/written */
+ pthread_t thread; /* thread of the callback interface */
+} PaSndioStream;
+
+/*
+ * api "class" data, common to all streams
+ */
+typedef struct PaSndioHostApiRepresentation
+{
+ PaUtilHostApiRepresentation base;
+ PaUtilStreamInterface callback;
+ PaUtilStreamInterface blocking;
+ /*
+ * sndio has no device discovery mechanism, so expose only
+ * the default device, the user will have a chance to change it
+ * using the environment variable
+ */
+ PaDeviceInfo *infos[1], default_info;
+} PaSndioHostApiRepresentation;
+
+/*
+ * callback invoked when blocks are processed by the hardware
+ */
+static void
+sndioOnMove(void *addr, int delta)
+{
+ PaSndioStream *s = (PaSndioStream *)addr;
+
+ s->realpos += delta;
+}
+
+/*
+ * convert PA encoding to sndio encoding, return true on success
+ */
+static int
+sndioSetFmt(struct sio_par *sio, PaSampleFormat fmt)
+{
+ switch (fmt & ~paNonInterleaved) {
+ case paInt32:
+ sio->sig = 1;
+ sio->bits = 32;
+ break;
+ case paInt24:
+ sio->sig = 1;
+ sio->bits = 24;
+ sio->bps = 3; /* paInt24 is packed format */
+ break;
+ case paInt16:
+ case paFloat32:
+ sio->sig = 1;
+ sio->bits = 16;
+ break;
+ case paInt8:
+ sio->sig = 1;
+ sio->bits = 8;
+ break;
+ case paUInt8:
+ sio->sig = 0;
+ sio->bits = 8;
+ break;
+ default:
+ DPR("sndioSetFmt: %x: unsupported\n", fmt);
+ return 0;
+ }
+ sio->le = SIO_LE_NATIVE;
+ return 1;
+}
+
+/*
+ * convert sndio encoding to PA encoding, return true on success
+ */
+static int
+sndioGetFmt(struct sio_par *sio, PaSampleFormat *fmt)
+{
+ if ((sio->bps * 8 != sio->bits && !sio->msb) ||
+ (sio->bps > 1 && sio->le != SIO_LE_NATIVE)) {
+ DPR("sndioGetFmt: bits = %u, le = %u, msb = %u, bps = %u\n",
+ sio->bits, sio->le, sio->msb, sio->bps);
+ return 0;
+ }
+
+ switch (sio->bits) {
+ case 32:
+ if (!sio->sig)
+ return 0;
+ *fmt = paInt32;
+ break;
+ case 24:
+ if (!sio->sig)
+ return 0;
+ *fmt = (sio->bps == 3) ? paInt24 : paInt32;
+ break;
+ case 16:
+ if (!sio->sig)
+ return 0;
+ *fmt = paInt16;
+ break;
+ case 8:
+ *fmt = sio->sig ? paInt8 : paUInt8;
+ break;
+ default:
+ DPR("sndioGetFmt: %u: unsupported\n", sio->bits);
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * I/O loop for callback interface
+ */
+static void *
+sndioThread(void *arg)
+{
+ PaSndioStream *s = (PaSndioStream *)arg;
+ PaStreamCallbackTimeInfo ti;
+ unsigned char *data;
+ unsigned todo, rblksz, wblksz;
+ int n, result;
+
+ rblksz = s->par.round * s->par.rchan * s->par.bps;
+ wblksz = s->par.round * s->par.pchan * s->par.bps;
+
+ DPR("sndioThread: mode = %x, round = %u, rblksz = %u, wblksz = %u\n",
+ s->mode, s->par.round, rblksz, wblksz);
+
+ while (!s->stopped) {
+ if (s->mode & SIO_REC) {
+ todo = rblksz;
+ data = s->rbuf;
+ while (todo > 0) {
+ n = sio_read(s->hdl, data, todo);
+ if (n == 0) {
+ DPR("sndioThread: sio_read failed\n");
+ goto failed;
+ }
+ todo -= n;
+ data += n;
+ }
+ s->rpos += s->par.round;
+ ti.inputBufferAdcTime =
+ (double)s->realpos / s->par.rate;
+ }
+ if (s->mode & SIO_PLAY) {
+ ti.outputBufferDacTime =
+ (double)(s->realpos + s->par.bufsz) / s->par.rate;
+ }
+ ti.currentTime = s->realpos / (double)s->par.rate;
+ PaUtil_BeginBufferProcessing(&s->bufproc, &ti, 0);
+ if (s->mode & SIO_PLAY) {
+ PaUtil_SetOutputFrameCount(&s->bufproc, s->par.round);
+ PaUtil_SetInterleavedOutputChannels(&s->bufproc,
+ 0, s->wbuf, s->par.pchan);
+ }
+ if (s->mode & SIO_REC) {
+ PaUtil_SetInputFrameCount(&s->bufproc, s->par.round);
+ PaUtil_SetInterleavedInputChannels(&s->bufproc,
+ 0, s->rbuf, s->par.rchan);
+ }
+ result = paContinue;
+ n = PaUtil_EndBufferProcessing(&s->bufproc, &result);
+ if (n != s->par.round) {
+ DPR("sndioThread: %d < %u frames, result = %d\n",
+ n, s->par.round, result);
+ }
+ if (result != paContinue) {
+ break;
+ }
+ if (s->mode & SIO_PLAY) {
+ n = sio_write(s->hdl, s->wbuf, wblksz);
+ if (n < wblksz) {
+ DPR("sndioThread: sio_write failed\n");
+ goto failed;
+ }
+ s->wpos += s->par.round;
+ }
+ }
+ failed:
+ s->active = 0;
+ DPR("sndioThread: done\n");
+}
+
+static PaError
+OpenStream(struct PaUtilHostApiRepresentation *hostApi,
+ PaStream **stream,
+ const PaStreamParameters *inputPar,
+ const PaStreamParameters *outputPar,
+ double sampleRate,
+ unsigned long framesPerBuffer,
+ PaStreamFlags streamFlags,
+ PaStreamCallback *streamCallback,
+ void *userData)
+{
+ PaSndioHostApiRepresentation *sndioHostApi = (PaSndioHostApiRepresentation *)hostApi;
+ PaSndioStream *s;
+ PaError err;
+ struct sio_hdl *hdl;
+ struct sio_par par;
+ unsigned mode;
+ int inch, onch;
+ PaSampleFormat ifmt, ofmt, siofmt;
+
+ DPR("OpenStream:\n");
+
+ mode = 0;
+ inch = onch = 0;
+ ifmt = ofmt = 0;
+ sio_initpar(&par);
+
+ if (outputPar && outputPar->channelCount > 0) {
+ if (outputPar->device != 0) {
+ DPR("OpenStream: %d: bad output device\n", outputPar->device);
+ return paInvalidDevice;
+ }
+ if (outputPar->hostApiSpecificStreamInfo) {
+ DPR("OpenStream: output specific info\n");
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ if (!sndioSetFmt(&par, outputPar->sampleFormat)) {
+ return paSampleFormatNotSupported;
+ }
+ ofmt = outputPar->sampleFormat;
+ onch = par.pchan = outputPar->channelCount;
+ mode |= SIO_PLAY;
+ }
+ if (inputPar && inputPar->channelCount > 0) {
+ if (inputPar->device != 0) {
+ DPR("OpenStream: %d: bad input device\n", inputPar->device);
+ return paInvalidDevice;
+ }
+ if (inputPar->hostApiSpecificStreamInfo) {
+ DPR("OpenStream: input specific info\n");
+ return paIncompatibleHostApiSpecificStreamInfo;
+ }
+ if (!sndioSetFmt(&par, inputPar->sampleFormat)) {
+ return paSampleFormatNotSupported;
+ }
+ ifmt = inputPar->sampleFormat;
+ inch = par.rchan = inputPar->channelCount;
+ mode |= SIO_REC;
+ }
+ par.rate = sampleRate;
+ if (framesPerBuffer != paFramesPerBufferUnspecified)
+ par.round = framesPerBuffer;
+
+ DPR("OpenStream: mode = %x, trying rate = %u\n", mode, par.rate);
+
+ hdl = sio_open(SIO_DEVANY, mode, 0);
+ if (hdl == NULL)
+ return paUnanticipatedHostError;
+ if (!sio_setpar(hdl, &par)) {
+ sio_close(hdl);
+ return paUnanticipatedHostError;
+ }
+ if (!sio_getpar(hdl, &par)) {
+ sio_close(hdl);
+ return paUnanticipatedHostError;
+ }
+ if (!sndioGetFmt(&par, &siofmt)) {
+ sio_close(hdl);
+ return paSampleFormatNotSupported;
+ }
+ if ((mode & SIO_REC) && par.rchan != inputPar->channelCount) {
+ DPR("OpenStream: rchan(%u) != %d\n", par.rchan, inputPar->channelCount);
+ sio_close(hdl);
+ return paInvalidChannelCount;
+ }
+ if ((mode & SIO_PLAY) && par.pchan != outputPar->channelCount) {
+ DPR("OpenStream: pchan(%u) != %d\n", par.pchan, outputPar->channelCount);
+ sio_close(hdl);
+ return paInvalidChannelCount;
+ }
+ if ((double)par.rate < sampleRate * 0.995 ||
+ (double)par.rate > sampleRate * 1.005) {
+ DPR("OpenStream: rate(%u) != %g\n", par.rate, sampleRate);
+ sio_close(hdl);
+ return paInvalidSampleRate;
+ }
+
+ s = (PaSndioStream *)PaUtil_AllocateMemory(sizeof(PaSndioStream));
+ if (s == NULL) {
+ sio_close(hdl);
+ return paInsufficientMemory;
+ }
+ PaUtil_InitializeStreamRepresentation(&s->base,
+ streamCallback ? &sndioHostApi->callback : &sndioHostApi->blocking,
+ streamCallback, userData);
+ DPR("inch = %d, onch = %d, ifmt = %x, ofmt = %x\n",
+ inch, onch, ifmt, ofmt);
+ err = PaUtil_InitializeBufferProcessor(&s->bufproc,
+ inch, ifmt, siofmt,
+ onch, ofmt, siofmt,
+ sampleRate,
+ streamFlags,
+ framesPerBuffer,
+ par.round,
+ paUtilFixedHostBufferSize,
+ streamCallback, userData);
+ if (err) {
+ DPR("OpenStream: PaUtil_InitializeBufferProcessor failed\n");
+ PaUtil_FreeMemory(s);
+ sio_close(hdl);
+ return err;
+ }
+ if (mode & SIO_REC) {
+ s->rbuf = malloc(par.round * par.rchan * par.bps);
+ if (s->rbuf == NULL) {
+ DPR("OpenStream: failed to allocate rbuf\n");
+ PaUtil_FreeMemory(s);
+ sio_close(hdl);
+ return paInsufficientMemory;
+ }
+ }
+ if (mode & SIO_PLAY) {
+ s->wbuf = malloc(par.round * par.pchan * par.bps);
+ if (s->wbuf == NULL) {
+ DPR("OpenStream: failed to allocate wbuf\n");
+ free(s->rbuf);
+ PaUtil_FreeMemory(s);
+ sio_close(hdl);
+ return paInsufficientMemory;
+ }
+ }
+ s->base.streamInfo.inputLatency = 0;
+ s->base.streamInfo.outputLatency = (mode & SIO_PLAY) ?
+ (double)(par.bufsz + PaUtil_GetBufferProcessorOutputLatencyFrames(&s->bufproc)) / (double)par.rate : 0;
+ s->base.streamInfo.sampleRate = par.rate;
+ s->active = 0;
+ s->stopped = 1;
+ s->mode = mode;
+ s->hdl = hdl;
+ s->par = par;
+ *stream = s;
+ DPR("OpenStream: done\n");
+ return paNoError;
+}
+
+static PaError
+BlockingReadStream(PaStream *stream, void *data, unsigned long numFrames)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ unsigned n, res, todo;
+ void *buf;
+
+ while (numFrames > 0) {
+ n = s->par.round;
+ if (n > numFrames)
+ n = numFrames;
+ buf = s->rbuf;
+ todo = n * s->par.rchan * s->par.bps;
+ while (todo > 0) {
+ res = sio_read(s->hdl, buf, todo);
+ if (res == 0)
+ return paUnanticipatedHostError;
+ buf = (char *)buf + res;
+ todo -= res;
+ }
+ s->rpos += n;
+ PaUtil_SetInputFrameCount(&s->bufproc, n);
+ PaUtil_SetInterleavedInputChannels(&s->bufproc, 0, s->rbuf, s->par.rchan);
+ res = PaUtil_CopyInput(&s->bufproc, &data, n);
+ if (res != n) {
+ DPR("BlockingReadStream: copyInput: %u != %u\n");
+ return paUnanticipatedHostError;
+ }
+ numFrames -= n;
+ }
+ return paNoError;
+}
+
+static PaError
+BlockingWriteStream(PaStream* stream, const void *data, unsigned long numFrames)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ unsigned n, res;
+
+ while (numFrames > 0) {
+ n = s->par.round;
+ if (n > numFrames)
+ n = numFrames;
+ PaUtil_SetOutputFrameCount(&s->bufproc, n);
+ PaUtil_SetInterleavedOutputChannels(&s->bufproc, 0, s->wbuf, s->par.pchan);
+ res = PaUtil_CopyOutput(&s->bufproc, &data, n);
+ if (res != n) {
+ DPR("BlockingWriteStream: copyOutput: %u != %u\n");
+ return paUnanticipatedHostError;
+ }
+ res = sio_write(s->hdl, s->wbuf, n * s->par.pchan * s->par.bps);
+ if (res == 0)
+ return paUnanticipatedHostError;
+ s->wpos += n;
+ numFrames -= n;
+ }
+ return paNoError;
+}
+
+static signed long
+BlockingGetStreamReadAvailable(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ struct pollfd pfd;
+ int n, events;
+
+ n = sio_pollfd(s->hdl, &pfd, POLLIN);
+ while (poll(&pfd, n, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("poll");
+ abort();
+ }
+ events = sio_revents(s->hdl, &pfd);
+ if (!(events & POLLIN))
+ return 0;
+
+ return s->realpos - s->rpos;
+}
+
+static signed long
+BlockingGetStreamWriteAvailable(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ struct pollfd pfd;
+ int n, events;
+
+ n = sio_pollfd(s->hdl, &pfd, POLLOUT);
+ while (poll(&pfd, n, 0) < 0) {
+ if (errno == EINTR)
+ continue;
+ perror("poll");
+ abort();
+ }
+ events = sio_revents(s->hdl, &pfd);
+ if (!(events & POLLOUT))
+ return 0;
+
+ return s->par.bufsz - (s->wpos - s->realpos);
+}
+
+static PaError
+BlockingWaitEmpty( PaStream *stream )
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+
+ /*
+ * drain playback buffers; sndio always does it in background
+ * and there is no way to wait for completion
+ */
+ DPR("BlockingWaitEmpty: s=%d, a=%d\n", s->stopped, s->active);
+
+ return paNoError;
+}
+
+static PaError
+StartStream(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ unsigned primes, wblksz;
+ int err;
+
+ DPR("StartStream: s=%d, a=%d\n", s->stopped, s->active);
+
+ if (!s->stopped) {
+ DPR("StartStream: already started\n");
+ return paNoError;
+ }
+ s->stopped = 0;
+ s->active = 1;
+ s->realpos = 0;
+ s->wpos = 0;
+ s->rpos = 0;
+ PaUtil_ResetBufferProcessor(&s->bufproc);
+ if (!sio_start(s->hdl))
+ return paUnanticipatedHostError;
+
+ /*
+ * send a complete buffer of silence
+ */
+ if (s->mode & SIO_PLAY) {
+ wblksz = s->par.round * s->par.pchan * s->par.bps;
+ memset(s->wbuf, 0, wblksz);
+ for (primes = s->par.bufsz / s->par.round; primes > 0; primes--)
+ s->wpos += sio_write(s->hdl, s->wbuf, wblksz);
+ }
+ if (s->base.streamCallback) {
+ err = pthread_create(&s->thread, NULL, sndioThread, s);
+ if (err) {
+ DPR("SndioStartStream: couldn't create thread\n");
+ return paUnanticipatedHostError;
+ }
+ DPR("StartStream: started...\n");
+ }
+ return paNoError;
+}
+
+static PaError
+StopStream(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+ void *ret;
+ int err;
+
+ DPR("StopStream: s=%d, a=%d\n", s->stopped, s->active);
+
+ if (s->stopped) {
+ DPR("StartStream: already started\n");
+ return paNoError;
+ }
+ s->stopped = 1;
+ if (s->base.streamCallback) {
+ err = pthread_join(s->thread, &ret);
+ if (err) {
+ DPR("SndioStop: couldn't join thread\n");
+ return paUnanticipatedHostError;
+ }
+ }
+ if (!sio_stop(s->hdl))
+ return paUnanticipatedHostError;
+ return paNoError;
+}
+
+static PaError
+CloseStream(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+
+ DPR("CloseStream:\n");
+
+ if (!s->stopped)
+ StopStream(stream);
+
+ if (s->mode & SIO_REC)
+ free(s->rbuf);
+ if (s->mode & SIO_PLAY)
+ free(s->wbuf);
+ sio_close(s->hdl);
+ PaUtil_TerminateStreamRepresentation(&s->base);
+ PaUtil_TerminateBufferProcessor(&s->bufproc);
+ PaUtil_FreeMemory(s);
+ return paNoError;
+}
+
+static PaError
+AbortStream(PaStream *stream)
+{
+ DPR("AbortStream:\n");
+
+ return StopStream(stream);
+}
+
+static PaError
+IsStreamStopped(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+
+ //DPR("IsStreamStopped: s=%d, a=%d\n", s->stopped, s->active);
+
+ return s->stopped;
+}
+
+static PaError
+IsStreamActive(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+
+ //DPR("IsStreamActive: s=%d, a=%d\n", s->stopped, s->active);
+
+ return s->active;
+}
+
+static PaTime
+GetStreamTime(PaStream *stream)
+{
+ PaSndioStream *s = (PaSndioStream *)stream;
+
+ return (double)s->realpos / s->base.streamInfo.sampleRate;
+}
+
+static PaError
+IsFormatSupported(struct PaUtilHostApiRepresentation *hostApi,
+ const PaStreamParameters *inputPar,
+ const PaStreamParameters *outputPar,
+ double sampleRate)
+{
+ return paFormatIsSupported;
+}
+
+static void
+Terminate(struct PaUtilHostApiRepresentation *hostApi)
+{
+ PaUtil_FreeMemory(hostApi);
+}
+
+PaError
+PaSndio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
+{
+ PaSndioHostApiRepresentation *sndioHostApi;
+ PaDeviceInfo *info;
+ struct sio_hdl *hdl;
+
+ DPR("PaSndio_Initialize: initializing...\n");
+
+ /* unusable APIs should return paNoError and a NULL hostApi */
+ *hostApi = NULL;
+
+ sndioHostApi = PaUtil_AllocateMemory(sizeof(PaSndioHostApiRepresentation));
+ if (sndioHostApi == NULL)
+ return paNoError;
+
+ info = &sndioHostApi->default_info;
+ info->structVersion = 2;
+ info->name = "default";
+ info->hostApi = hostApiIndex;
+ info->maxInputChannels = 128;
+ info->maxOutputChannels = 128;
+ info->defaultLowInputLatency = 0.01;
+ info->defaultLowOutputLatency = 0.01;
+ info->defaultHighInputLatency = 0.5;
+ info->defaultHighOutputLatency = 0.5;
+ info->defaultSampleRate = 48000;
+ sndioHostApi->infos[0] = info;
+
+ *hostApi = &sndioHostApi->base;
+ (*hostApi)->info.structVersion = 1;
+ (*hostApi)->info.type = paSndio;
+ (*hostApi)->info.name = "sndio";
+ (*hostApi)->info.deviceCount = 1;
+ (*hostApi)->info.defaultInputDevice = 0;
+ (*hostApi)->info.defaultOutputDevice = 0;
+ (*hostApi)->deviceInfos = sndioHostApi->infos;
+ (*hostApi)->Terminate = Terminate;
+ (*hostApi)->OpenStream = OpenStream;
+ (*hostApi)->IsFormatSupported = IsFormatSupported;
+
+ PaUtil_InitializeStreamInterface(&sndioHostApi->blocking,
+ CloseStream,
+ StartStream,
+ StopStream,
+ AbortStream,
+ IsStreamStopped,
+ IsStreamActive,
+ GetStreamTime,
+ PaUtil_DummyGetCpuLoad,
+ BlockingReadStream,
+ BlockingWriteStream,
+ BlockingGetStreamReadAvailable,
+ BlockingGetStreamWriteAvailable);
+
+ PaUtil_InitializeStreamInterface(&sndioHostApi->callback,
+ CloseStream,
+ StartStream,
+ StopStream,
+ AbortStream,
+ IsStreamStopped,
+ IsStreamActive,
+ GetStreamTime,
+ PaUtil_DummyGetCpuLoad,
+ PaUtil_DummyRead,
+ PaUtil_DummyWrite,
+ PaUtil_DummyGetReadAvailable,
+ PaUtil_DummyGetWriteAvailable);
+
+ DPR("PaSndio_Initialize: done\n");
+ return paNoError;
+}
diff --git a/audio/portaudio/files/patch-Makefile.in b/audio/portaudio/files/patch-Makefile.in
new file mode 100644
index 000000000000..34b0ef54b5ef
--- /dev/null
+++ b/audio/portaudio/files/patch-Makefile.in
@@ -0,0 +1,11 @@
+$OpenBSD: patch-Makefile_in,v 1.4 2013/03/12 00:59:50 brad Exp $
+--- Makefile.in.orig 2016-06-22 08:28:31 UTC
++++ Makefile.in
+@@ -146,6 +146,7 @@ SRC_DIRS = \
+ src/hostapi/dsound \
+ src/hostapi/jack \
+ src/hostapi/oss \
++ src/hostapi/sndio \
+ src/hostapi/wasapi \
+ src/hostapi/wdmks \
+ src/hostapi/wmme \
diff --git a/audio/portaudio/files/patch-configure.in b/audio/portaudio/files/patch-configure.in
new file mode 100644
index 000000000000..27618f2ff384
--- /dev/null
+++ b/audio/portaudio/files/patch-configure.in
@@ -0,0 +1,47 @@
+$OpenBSD: patch-configure_in,v 1.4 2014/09/13 04:56:28 bentley Exp $
+--- configure.in.orig 2016-06-22 08:28:31 UTC
++++ configure.in
+@@ -24,6 +24,10 @@ AC_ARG_WITH(alsa,
+ AS_HELP_STRING([--with-alsa], [Enable support for ALSA @<:@autodetect@:>@]),
+ [with_alsa=$withval])
+
++AC_ARG_WITH(sndio,
++ AS_HELP_STRING([--with-sndio], [Enable support for sndio @<:@autodetect@:>@]),
++ [with_sndio=$withval])
++
+ AC_ARG_WITH(jack,
+ AS_HELP_STRING([--with-jack], [Enable support for JACK @<:@autodetect@:>@]),
+ [with_jack=$withval])
+@@ -120,6 +124,10 @@ have_alsa=no
+ if test "x$with_alsa" != "xno"; then
+ AC_CHECK_LIB(asound, snd_pcm_open, have_alsa=yes, have_alsa=no)
+ fi
++have_sndio=no
++if test "x$with_sndio" != "xno"; then
++ AC_CHECK_LIB(sndio, sio_open, have_sndio=yes, have_sndio=no)
++fi
+ have_asihpi=no
+ if test "x$with_asihpi" != "xno"; then
+ AC_CHECK_LIB(hpi, HPI_SubSysCreate, have_asihpi=yes, have_asihpi=no, -lm)
+@@ -397,6 +405,13 @@ case "${host_os}" in
+ AC_DEFINE(PA_USE_ALSA,1)
+ fi
+
++ if [[ "$have_sndio" = "yes" -a "$with_sndio" != "no" ]] ; then
++ DLL_LIBS="$DLL_LIBS -lsndio"
++ LIBS="$LIBS -lsndio"
++ OTHER_OBJS="$OTHER_OBJS src/hostapi/sndio/pa_sndio.o"
++ AC_DEFINE(PA_USE_SNDIO,1)
++ fi
++
+ if [[ "$have_jack" = "yes" ] && [ "$with_jack" != "no" ]] ; then
+ DLL_LIBS="$DLL_LIBS $JACK_LIBS"
+ CFLAGS="$CFLAGS $JACK_CFLAGS"
+@@ -500,6 +515,7 @@ case "$target_os" in
+ ;;
+ *)
+ AC_MSG_RESULT([
++ Sndio ....................... $have_sndio
+ OSS ......................... $have_oss
+ JACK ........................ $have_jack
+ ])
diff --git a/audio/portaudio/files/patch-include_portaudio.h b/audio/portaudio/files/patch-include_portaudio.h
new file mode 100644
index 000000000000..8c2aad7da5c2
--- /dev/null
+++ b/audio/portaudio/files/patch-include_portaudio.h
@@ -0,0 +1,13 @@
+$OpenBSD: patch-include_portaudio_h,v 1.2 2013/03/12 00:59:50 brad Exp $
+--- include/portaudio.h.orig 2016-06-22 08:28:31 UTC
++++ include/portaudio.h
+@@ -236,7 +236,8 @@ typedef enum PaHostApiTypeId
+ paWDMKS=11,
+ paJACK=12,
+ paWASAPI=13,
+- paAudioScienceHPI=14
++ paAudioScienceHPI=14,
++ paSndio=15
+ } PaHostApiTypeId;
+
+
diff --git a/audio/portaudio/files/patch-src_os_unix_pa__unix__hostapis.c b/audio/portaudio/files/patch-src_os_unix_pa__unix__hostapis.c
new file mode 100644
index 000000000000..09d9aebcdd76
--- /dev/null
+++ b/audio/portaudio/files/patch-src_os_unix_pa__unix__hostapis.c
@@ -0,0 +1,26 @@
+$OpenBSD: patch-src_os_unix_pa_unix_hostapis_c,v 1.2 2013/03/12 00:59:50 brad Exp $
+
+Difference to OpenBSD patch: PA_USE_SNDIO has been moved before
+PA_USE_OSS, so that portaudio prefers the sndio output.
+
+--- src/os/unix/pa_unix_hostapis.c.orig 2016-06-22 08:28:31 UTC
++++ src/os/unix/pa_unix_hostapis.c
+@@ -44,6 +44,7 @@
+
+ PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+ PaError PaAlsa_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
++PaError PaSndio_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+ PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+ /* Added for IRIX, Pieter, oct 2, 2003: */
+ PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+@@ -69,6 +70,10 @@ PaUtilHostApiInitializer *paHostApiIniti
+
+ #else /* __linux__ */
+
++#ifdef PA_USE_SNDIO
++ PaSndio_Initialize,
++#endif
++
+ #if PA_USE_OSS
+ PaOSS_Initialize,
+ #endif