commit: 049c77997adbae7ec417945e23547291f0805e06
parent: 056c5b086ae297613ffacdd019cb8e3a0aa08af2
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 30 May 2020 15:00:04 +0200
media-libs/portaudio: Bump rev and patches
Diffstat:
5 files changed, 884 insertions(+), 892 deletions(-)
diff --git a/media-libs/portaudio/files/portaudio-19.06.00-AR.patch b/media-libs/portaudio/files/portaudio-19.06.00-AR.patch
@@ -0,0 +1,14 @@
+Accept relative paths to AR as well.
+
+https://bugs.gentoo.org/720966
+--- a/configure.in
++++ b/configure.in
+@@ -105,7 +105,7 @@ AC_LIBTOOL_WIN32_DLL
+ AC_PROG_LIBTOOL
+ AC_PROG_INSTALL
+ AC_PROG_LN_S
+-AC_PATH_PROG(AR, ar, no)
++AC_CHECK_PROG(AR, ar, no)
+ if [[ $AR = "no" ]] ; then
+     AC_MSG_ERROR("Could not find ar - needed to create a library")
+ fi
diff --git a/media-libs/portaudio/files/portaudio-19.06.00-pa_sndio.c b/media-libs/portaudio/files/portaudio-19.06.00-pa_sndio.c
@@ -0,0 +1,766 @@
+/*
+ * 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 and PortAudio has
+	 * no way of accepting raw device strings from users.
+	 * Normally we just expose the default device, which can be
+	 * changed via the AUDIODEVICE environment variable, but we
+	 * also allow specifying a list of up to 16 devices via the
+	 * PA_SNDIO_AUDIODEVICES environment variable.
+	 *
+	 * Example:
+	 * PA_SNDIO_AUDIODEVICES=default:snd/0.monitor:snd@remote/0
+	 */
+#define PA_SNDIO_AUDIODEVICES_MAX	16
+	PaDeviceInfo device_info[PA_SNDIO_AUDIODEVICES_MAX];
+	PaDeviceInfo *infos[PA_SNDIO_AUDIODEVICES_MAX];
+	char *audiodevices;
+} 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");
+	return NULL;
+}
+
+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;
+	const char *dev;
+
+	DPR("OpenStream:\n");
+
+	mode = 0;
+	inch = onch = 0;
+	ifmt = ofmt = 0;
+	sio_initpar(&par);
+
+	if (outputPar && outputPar->channelCount > 0) {
+		if (outputPar->device >= sndioHostApi->base.info.deviceCount) {
+			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 >= sndioHostApi->base.info.deviceCount) {
+			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);
+
+	if (outputPar) {
+		dev = sndioHostApi->device_info[outputPar->device].name;
+	} else if (inputPar) {
+		dev = sndioHostApi->device_info[inputPar->device].name;
+	} else {
+		return paUnanticipatedHostError;
+	}
+	hdl = sio_open(dev, 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)
+{
+	PaSndioHostApiRepresentation *sndioHostApi;
+	sndioHostApi = (PaSndioHostApiRepresentation *)hostApi;
+	free(sndioHostApi->audiodevices);
+	PaUtil_FreeMemory(hostApi);
+}
+
+static void
+InitDeviceInfo(PaDeviceInfo *info, PaHostApiIndex hostApiIndex, const char *name)
+{
+	info->structVersion = 2;
+	info->name = name;
+	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;
+}
+
+PaError
+PaSndio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
+{
+	PaSndioHostApiRepresentation *sndioHostApi;
+	PaDeviceInfo *info;
+	struct sio_hdl *hdl;
+	char *audiodevices;
+	char *device;
+	size_t deviceCount;
+
+	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;
+
+	// Add default device
+	info = &sndioHostApi->device_info[0];
+	InitDeviceInfo(info, hostApiIndex, SIO_DEVANY);
+	sndioHostApi->infos[0] = info;
+	deviceCount = 1;
+
+	// Add additional devices as specified in the PA_SNDIO_AUDIODEVICES
+	// environment variable as a colon separated list
+	sndioHostApi->audiodevices = NULL;
+	audiodevices = getenv("PA_SNDIO_AUDIODEVICES");
+	if (audiodevices != NULL) {
+		sndioHostApi->audiodevices = strdup(audiodevices);
+		if (sndioHostApi->audiodevices == NULL)
+			return paNoError;
+
+		audiodevices = sndioHostApi->audiodevices;
+		while ((device = strsep(&audiodevices, ":")) != NULL &&
+			deviceCount < PA_SNDIO_AUDIODEVICES_MAX) {
+			if (*device == '\0')
+				continue;
+			info = &sndioHostApi->device_info[deviceCount];
+			InitDeviceInfo(info, hostApiIndex, device);
+			sndioHostApi->infos[deviceCount] = info;
+			deviceCount++;
+		}
+	}
+
+	*hostApi = &sndioHostApi->base;
+	(*hostApi)->info.structVersion = 1;
+	(*hostApi)->info.type = paSndio;
+	(*hostApi)->info.name = "sndio";
+	(*hostApi)->info.deviceCount = deviceCount;
+	(*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/media-libs/portaudio/files/portaudio-19.06.00-sndio.patch b/media-libs/portaudio/files/portaudio-19.06.00-sndio.patch
@@ -1,20 +1,6 @@
-Source: https://github.com/void-linux/void-packages/blob/master/srcpkgs/portaudio/patches/sndio.patch
-
-Requires an eautoreconf.
-
-diff --git Makefile.in Makefile.in
-index 5e1a764..2747f73 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -44,7 +44,7 @@ PALIB = libportaudio.la
- PAINC = include/portaudio.h
- 
- PA_LDFLAGS = $(LDFLAGS) $(SHARED_FLAGS) -rpath $(libdir) -no-undefined \
--	     -export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa|PaAsio|PaOSS)_.*" \
-+	     -export-symbols-regex "(Pa|PaMacCore|PaJack|PaAlsa|PaAsio|PaOSS|PaSndio)_.*" \
- 	     -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
- 
- COMMON_OBJS = \
+$OpenBSD: patch-Makefile_in,v 1.4 2013/03/12 00:59:50 brad Exp $
+--- portaudio/Makefile.in.orig	Thu Jul  5 23:44:34 2012
++++ portaudio/Makefile.in	Thu Jul  5 23:49:34 2012
 @@ -146,6 +146,7 @@ SRC_DIRS = \
  	src/hostapi/dsound \
  	src/hostapi/jack \
@@ -23,10 +9,10 @@ index 5e1a764..2747f73 100644
  	src/hostapi/wasapi \
  	src/hostapi/wdmks \
  	src/hostapi/wmme \
-diff --git configure.in configure.in
-index 13816fb..4c06d10 100644
---- a/configure.in
-+++ b/configure.in
+$OpenBSD: patch-configure_in,v 1.5 2019/02/06 14:21:15 jca Exp $
+Index: configure.in
+--- portaudio/configure.in.orig
++++ portaudio/configure.in
 @@ -24,6 +24,10 @@ AC_ARG_WITH(alsa,
              AS_HELP_STRING([--with-alsa], [Enable support for ALSA @<:@autodetect@:>@]),
              [with_alsa=$withval])
@@ -54,10 +40,10 @@ index 13816fb..4c06d10 100644
          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)
++           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
@@ -71,10 +57,10 @@ index 13816fb..4c06d10 100644
    OSS ......................... $have_oss
    JACK ........................ $have_jack
  ])
-diff --git include/portaudio.h include/portaudio.h
-index 8a94aaf..f94d9c4 100644
---- a/include/portaudio.h
-+++ b/include/portaudio.h
+$OpenBSD: patch-include_portaudio_h,v 1.3 2019/02/06 14:21:15 jca Exp $
+Index: include/portaudio.h
+--- portaudio/include/portaudio.h.orig
++++ portaudio/include/portaudio.h
 @@ -287,7 +287,8 @@ typedef enum PaHostApiTypeId
      paWDMKS=11,
      paJACK=12,
@@ -85,781 +71,9 @@ index 8a94aaf..f94d9c4 100644
  } PaHostApiTypeId;
  
  
-diff --git src/hostapi/sndio/pa_sndio.c src/hostapi/sndio/pa_sndio.c
-new file mode 100644
-index 0000000..725ef47
---- a//dev/null
-+++ b/src/hostapi/sndio/pa_sndio.c
-@@ -0,0 +1,765 @@
-+/*
-+ * 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 and PortAudio has
-+	 * no way of accepting raw device strings from users.
-+	 * Normally we just expose the default device, which can be
-+	 * changed via the AUDIODEVICE environment variable, but we
-+	 * also allow specifying a list of up to 16 devices via the
-+	 * PA_SNDIO_AUDIODEVICES environment variable.
-+	 *
-+	 * Example:
-+	 * PA_SNDIO_AUDIODEVICES=default:snd/0.monitor:snd@remote/0
-+	 */
-+#define PA_SNDIO_AUDIODEVICES_MAX	16
-+	PaDeviceInfo device_info[PA_SNDIO_AUDIODEVICES_MAX];
-+	PaDeviceInfo *infos[PA_SNDIO_AUDIODEVICES_MAX];
-+	char *audiodevices;
-+} 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;
-+	const char *dev;
-+
-+	DPR("OpenStream:\n");
-+
-+	mode = 0;
-+	inch = onch = 0;
-+	ifmt = ofmt = 0;
-+	sio_initpar(&par);
-+
-+	if (outputPar && outputPar->channelCount > 0) {
-+		if (outputPar->device >= sndioHostApi->base.info.deviceCount) {
-+			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 >= sndioHostApi->base.info.deviceCount) {
-+			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);
-+
-+	if (outputPar) {
-+		dev = sndioHostApi->device_info[outputPar->device].name;
-+	} else if (inputPar) {
-+		dev = sndioHostApi->device_info[inputPar->device].name;
-+	} else {
-+		return paUnanticipatedHostError;
-+	}
-+	hdl = sio_open(dev, 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)
-+{
-+	PaSndioHostApiRepresentation *sndioHostApi;
-+	sndioHostApi = (PaSndioHostApiRepresentation *)hostApi;
-+	free(sndioHostApi->audiodevices);
-+	PaUtil_FreeMemory(hostApi);
-+}
-+
-+static void
-+InitDeviceInfo(PaDeviceInfo *info, PaHostApiIndex hostApiIndex, const char *name)
-+{
-+	info->structVersion = 2;
-+	info->name = name;
-+	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;
-+}
-+
-+PaError
-+PaSndio_Initialize(PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex)
-+{
-+	PaSndioHostApiRepresentation *sndioHostApi;
-+	PaDeviceInfo *info;
-+	struct sio_hdl *hdl;
-+	char *audiodevices;
-+	char *device;
-+	size_t deviceCount;
-+
-+	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;
-+
-+	// Add default device
-+	info = &sndioHostApi->device_info[0];
-+	InitDeviceInfo(info, hostApiIndex, SIO_DEVANY);
-+	sndioHostApi->infos[0] = info;
-+	deviceCount = 1;
-+
-+	// Add additional devices as specified in the PA_SNDIO_AUDIODEVICES
-+	// environment variable as a colon separated list
-+	sndioHostApi->audiodevices = NULL;
-+	audiodevices = getenv("PA_SNDIO_AUDIODEVICES");
-+	if (audiodevices != NULL) {
-+		sndioHostApi->audiodevices = strdup(audiodevices);
-+		if (sndioHostApi->audiodevices == NULL)
-+			return paNoError;
-+
-+		audiodevices = sndioHostApi->audiodevices;
-+		while ((device = strsep(&audiodevices, ":")) != NULL &&
-+			deviceCount < PA_SNDIO_AUDIODEVICES_MAX) {
-+			if (*device == '\0')
-+				continue;
-+			info = &sndioHostApi->device_info[deviceCount];
-+			InitDeviceInfo(info, hostApiIndex, device);
-+			sndioHostApi->infos[deviceCount] = info;
-+			deviceCount++;
-+		}
-+	}
-+
-+	*hostApi = &sndioHostApi->base;
-+	(*hostApi)->info.structVersion = 1;
-+	(*hostApi)->info.type = paSndio;
-+	(*hostApi)->info.name = "sndio";
-+	(*hostApi)->info.deviceCount = deviceCount;
-+	(*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 src/os/unix/pa_unix_hostapis.c src/os/unix/pa_unix_hostapis.c
-index a9b4a05..c3fa2a3 100644
---- a/src/os/unix/pa_unix_hostapis.c
-+++ b/src/os/unix/pa_unix_hostapis.c
+$OpenBSD: patch-src_os_unix_pa_unix_hostapis_c,v 1.2 2013/03/12 00:59:50 brad Exp $
+--- portaudio/src/os/unix/pa_unix_hostapis.c.orig	Thu Jul  5 23:44:45 2012
++++ portaudio/src/os/unix/pa_unix_hostapis.c	Thu Jul  5 23:49:33 2012
 @@ -44,6 +44,7 @@
  
  PaError PaJack_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
@@ -868,14 +82,14 @@ index a9b4a05..c3fa2a3 100644
  PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
  /* Added for IRIX, Pieter, oct 2, 2003: */
  PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
-@@ -79,6 +80,10 @@ PaUtilHostApiInitializer *paHostApiInitializers[] =
+@@ -78,6 +79,10 @@ PaUtilHostApiInitializer *paHostApiInitializers[] =
+ #endif
  
  #endif  /* __linux__ */
- 
++
 +#ifdef PA_USE_SNDIO
-+	    PaSndio_Initialize,
++	PaSndio_Initialize,
 +#endif
-+
+ 
  #if PA_USE_JACK
          PaJack_Initialize,
- #endif
diff --git a/media-libs/portaudio/portaudio-19.06.00-r2.ebuild b/media-libs/portaudio/portaudio-19.06.00-r2.ebuild
@@ -1,83 +0,0 @@
-# Copyright 1999-2020 Gentoo Authors
-# Distributed under the terms of the GNU General Public License v2
-
-EAPI=7
-inherit multilib-minimal autotools
-
-DESCRIPTION="A free, cross-platform, open-source, audio I/O library"
-HOMEPAGE="http://www.portaudio.com/"
-SRC_URI="http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz
-	https://sources.debian.org/data/main/p/portaudio19/19.6.0-1/debian/patches/audacity-portmixer.patch -> ${PN}-19.06.00-audacity-portmixer.patch"
-
-LICENSE="MIT"
-SLOT="0"
-KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~sparc ~x86 ~amd64-linux ~x86-linux"
-IUSE="alsa +cxx debug doc jack oss static-libs sndio"
-
-RDEPEND="alsa? ( >=media-libs/alsa-lib-1.0.27.2[${MULTILIB_USEDEP}] )
-	jack? ( virtual/jack[${MULTILIB_USEDEP}] )
-	sndio? ( media-sound/sndio:=[${MULTILIB_USEDEP}] )
-"
-DEPEND="${RDEPEND}"
-BDEPEND="
-	doc? ( app-doc/doxygen )
-	virtual/pkgconfig
-"
-
-S="${WORKDIR}/${PN}"
-
-DOCS=( README.txt )
-
-PATCHES=(
-	"${DISTDIR}/${PN}-19.06.00-audacity-portmixer.patch"
-	"${FILESDIR}/${PN}-19.06.00-sndio.patch"
-)
-
-src_prepare() {
-	default
-
-	# depcomp is required when building the bindings/cpp extension
-	# but will be removed by autoreconf + libtool >= 2.4.6
-	# Protect it from removal
-	mv depcomp{,~} || die
-
-	eautoreconf
-
-	# Restore depcomp
-	mv depcomp{~,} || die
-}
-
-multilib_src_configure() {
-	local myeconfargs=(
-		$(use_enable debug debug-output)
-		$(use_enable cxx)
-		$(use_enable static-libs static)
-		$(use_with alsa)
-		$(use_with jack)
-		$(use_with oss)
-		$(use_with sndio)
-	)
-
-	ECONF_SOURCE="${S}" econf "${myeconfargs[@]}"
-}
-
-multilib_src_compile() {
-	# workaround parallel build issue
-	emake lib/libportaudio.la
-	emake
-}
-
-src_compile() {
-	multilib-minimal_src_compile
-
-	if use doc; then
-		doxygen -u Doxyfile || die
-		doxygen Doxyfile || die
-	fi
-}
-
-multilib_src_install_all() {
-	einstalldocs
-	use doc && dodoc -r doc/html
-	find "${ED}" -name "*.la" -delete || die
-}
diff --git a/media-libs/portaudio/portaudio-19.06.00-r3.ebuild b/media-libs/portaudio/portaudio-19.06.00-r3.ebuild
@@ -0,0 +1,81 @@
+# Copyright 1999-2020 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=7
+inherit autotools multilib-minimal
+
+DESCRIPTION="A free, cross-platform, open-source, audio I/O library"
+HOMEPAGE="http://www.portaudio.com/"
+SRC_URI="http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz
+	https://sources.debian.org/data/main/p/portaudio19/19.6.0-1/debian/patches/audacity-portmixer.patch -> ${PN}-19.06.00-audacity-portmixer.patch"
+
+LICENSE="MIT"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~mips ~ppc ~ppc64 ~sparc ~x86 ~amd64-linux ~x86-linux"
+IUSE="alsa +cxx debug doc jack oss sndio static-libs"
+
+RDEPEND="alsa? ( >=media-libs/alsa-lib-1.0.27.2[${MULTILIB_USEDEP}] )
+	jack? ( virtual/jack[${MULTILIB_USEDEP}] )
+	sndio? ( media-sound/sndio:=[${MULTILIB_USEDEP}] )
+"
+DEPEND="${RDEPEND}"
+BDEPEND="
+	doc? ( app-doc/doxygen )
+	virtual/pkgconfig
+"
+
+S="${WORKDIR}/${PN}"
+
+DOCS=( README.txt )
+
+PATCHES=(
+	"${DISTDIR}/${PN}-19.06.00-audacity-portmixer.patch"
+	"${FILESDIR}"/${PN}-19.06.00-AR.patch # bug #720966, trigger reconf
+	"${FILESDIR}/${PN}-19.06.00-sndio.patch"
+)
+
+src_prepare() {
+	default
+
+	mkdir -p "${S}/src/hostapi/sndio/" || die
+	cp "${FILESDIR}/${PN}-19.06.00-pa_sndio.c" "${S}/src/hostapi/sndio/pa_sndio.c" || die
+
+	eautoconf
+
+	multilib_copy_sources
+}
+
+multilib_src_configure() {
+	local myeconfargs=(
+		$(use_enable debug debug-output)
+		$(use_enable cxx)
+		$(use_enable static-libs static)
+		$(use_with alsa)
+		$(use_with jack)
+		$(use_with oss)
+		$(use_with sndio)
+	)
+
+	ECONF_SOURCE="${S}" econf "${myeconfargs[@]}"
+}
+
+multilib_src_compile() {
+	# workaround parallel build issue
+	emake lib/libportaudio.la
+	emake
+}
+
+src_compile() {
+	multilib-minimal_src_compile
+
+	if use doc; then
+		doxygen -u Doxyfile || die
+		doxygen Doxyfile || die
+	fi
+}
+
+multilib_src_install_all() {
+	einstalldocs
+	use doc && dodoc -r doc/html
+	find "${ED}" -name "*.la" -delete || die
+}