logo

overlay

My own overlay for experimentations, use with caution, no support is provided
commit: f606936a4991b84f8fdfd8546dd03b6fa4d4e7b9
parent: 5170336ca453b8bb3fb18a245f124bb62d736a19
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Wed, 27 May 2020 01:00:00 +0200

media-libs/portaudio: New (sndio)

Diffstat:

Amedia-libs/portaudio/Manifest2++
Amedia-libs/portaudio/files/portaudio-19.06.00-sndio.patch881+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amedia-libs/portaudio/metadata.xml8++++++++
Amedia-libs/portaudio/portaudio-19.06.00-r2.ebuild83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 974 insertions(+), 0 deletions(-)

diff --git a/media-libs/portaudio/Manifest b/media-libs/portaudio/Manifest @@ -0,0 +1,2 @@ +DIST pa_stable_v190600_20161030.tgz 1450572 BLAKE2B 3cd63cca55ff222f452d306a1ab9035739545f48dbc9bc58196052cb51e518d86568059c7528533a6932c39c68d1a5210e06470a16343b92c7e4132b71cc552e SHA512 7ec692cbd8c23878b029fad9d9fd63a021f57e60c4921f602995a2fca070c29f17a280c7f2da5966c4aad29d28434538452f4c822eacf3a60af59a6dc8e9704c +DIST portaudio-19.06.00-audacity-portmixer.patch 8722 BLAKE2B 2b69bcf26e55be46d354dc44756fd03b16031fa86a334b776eb4326a4c64a7e22abd6bf60794847526102391c8e65813b41338cf94c647e3e9b68d82ea5dc5f5 SHA512 f693aef477b516c7a03eb021260cbecb23200422a927a117e3e59a1b4e6c6c2983fbea8ee3a3714ebc55728933654bd7909327a0bab4450ccf4e6a02c86a63b5 diff --git a/media-libs/portaudio/files/portaudio-19.06.00-sndio.patch b/media-libs/portaudio/files/portaudio-19.06.00-sndio.patch @@ -0,0 +1,881 @@ +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 = \ +@@ -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 configure.in configure.in +index 13816fb..4c06d10 100644 +--- a/configure.in ++++ b/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) +@@ -406,6 +414,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" +@@ -509,6 +524,7 @@ case "$target_os" in + ;; + *) + AC_MSG_RESULT([ ++ Sndio ....................... $have_sndio + 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 +@@ -287,7 +287,8 @@ typedef enum PaHostApiTypeId + paWDMKS=11, + paJACK=12, + paWASAPI=13, +- paAudioScienceHPI=14 ++ paAudioScienceHPI=14, ++ paSndio=15 + } 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 +@@ -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 ); +@@ -79,6 +80,10 @@ PaUtilHostApiInitializer *paHostApiInitializers[] = + + #endif /* __linux__ */ + ++#ifdef PA_USE_SNDIO ++ PaSndio_Initialize, ++#endif ++ + #if PA_USE_JACK + PaJack_Initialize, + #endif diff --git a/media-libs/portaudio/metadata.xml b/media-libs/portaudio/metadata.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<pkgmetadata> +<maintainer type="project"> + <email>sound@gentoo.org</email> + <name>Gentoo Sound project</name> +</maintainer> +</pkgmetadata> diff --git a/media-libs/portaudio/portaudio-19.06.00-r2.ebuild b/media-libs/portaudio/portaudio-19.06.00-r2.ebuild @@ -0,0 +1,83 @@ +# 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 +}