Sync with the sndio backend I was finally able to have commited upstream.

Index: Makefile
===================================================================
RCS file: /cvs/ports/audio/portaudio-svn/Makefile,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 Makefile
--- Makefile    5 Sep 2023 16:13:41 -0000       1.24
+++ Makefile    22 Feb 2024 05:28:04 -0000
@@ -2,7 +2,7 @@ COMMENT=                portable cross-platform audio 
 
 DISTNAME =             pa_stable_v190700_20210406
 PKGNAME =              portaudio-svn-1970
-REVISION =             0
+REVISION =             1
 CATEGORIES=            audio
 SITES =                        http://files.portaudio.com/archives/
 EXTRACT_SUFX =         .tgz
Index: files/pa_sndio.c
===================================================================
RCS file: /cvs/ports/audio/portaudio-svn/files/pa_sndio.c,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 pa_sndio.c
--- files/pa_sndio.c    6 Feb 2019 14:21:15 -0000       1.6
+++ files/pa_sndio.c    22 Feb 2024 05:28:04 -0000
@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2009 Alexandre Ratchov <[email protected]>
+ * Copyright (c) 2021 Haelwenn (lanodan) Monnier <[email protected]>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -13,43 +14,39 @@
  * 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 <poll.h>
+#include <pthread.h>
 #include <sndio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
 
-#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_debugprint.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
+#include "pa_stream.h"
+#include "pa_util.h"
 
 /*
  * 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 */
+    PaUtilStreamRepresentation base;
+    PaUtilBufferProcessor bufferProcessor; /* 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;
 
 /*
@@ -57,710 +54,716 @@ typedef struct PaSndioStream
  */
 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;
+    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 deviceInfos[PA_SNDIO_AUDIODEVICES_MAX];
+    PaDeviceInfo *deviceInfoPtrs[PA_SNDIO_AUDIODEVICES_MAX];
+    char *audioDevices;
 } PaSndioHostApiRepresentation;
 
 /*
  * callback invoked when blocks are processed by the hardware
  */
-static void
-sndioOnMove(void *addr, int delta)
+static void sndioOnMove( void *addr, int delta )
 {
-       PaSndioStream *s = (PaSndioStream *)addr;
+    PaSndioStream *sndioStream = (PaSndioStream *)addr;
 
-       s->realpos += delta;
+    sndioStream->realpos += delta;
 }
 
 /*
  * convert PA encoding to sndio encoding, return true on success
  */
-static int
-sndioSetFmt(struct sio_par *sio, PaSampleFormat fmt)
+static int sndioSetFmt( struct sio_par *par, 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;
+    switch( fmt & ~paNonInterleaved )
+    {
+    case paInt32:
+    case paFloat32:
+        par->sig = 1;
+        par->bits = 32;
+        break;
+    case paInt24:
+        par->sig = 1;
+        par->bits = 24;
+        par->bps = 3; /* paInt24 is packed format */
+        break;
+    case paInt16:
+        par->sig = 1;
+        par->bits = 16;
+        break;
+    case paInt8:
+        par->sig = 1;
+        par->bits = 8;
+        break;
+    case paUInt8:
+        par->sig = 0;
+        par->bits = 8;
+        break;
+    default:
+        PA_DEBUG( ( "sndioSetFmt: %x: unsupported\n", fmt ) );
+        return 0;
+    }
+    par->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)
+static int sndioGetFmt( struct sio_par *par, 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;
+    if( ( par->bps * 8 != par->bits && !par->msb ) || ( par->bps > 1 && 
par->le != SIO_LE_NATIVE ) )
+    {
+        PA_DEBUG( ( "sndioGetFmt: bits = %u, le = %u, msb = %u, bps = %u\n", 
par->bits, par->le, par->msb, par->bps ) );
+        return 0;
+    }
+
+    switch( par->bits )
+    {
+    case 32:
+        if( !par->sig )
+            return 0;
+        *fmt = paInt32;
+        break;
+    case 24:
+        if( !par->sig )
+            return 0;
+        *fmt = ( par->bps == 3 ) ? paInt24 : paInt32;
+        break;
+    case 16:
+        if( !par->sig )
+            return 0;
+        *fmt = paInt16;
+        break;
+    case 8:
+        *fmt = par->sig ? paInt8 : paUInt8;
+        break;
+    default:
+        PA_DEBUG( ( "sndioGetFmt: %u: unsupported\n", par->bits ) );
+        return 0;
+    }
+    return 1;
 }
 
 /*
  * I/O loop for callback interface
  */
-static void *
-sndioThread(void *arg)
+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);
+    PaSndioStream *sndioStream = (PaSndioStream *)arg;
+    PaStreamCallbackTimeInfo timeInfo;
+    unsigned char *data;
+    unsigned todo, rblksz, wblksz;
+    int n, result;
+
+    rblksz = sndioStream->par.round * sndioStream->par.rchan * 
sndioStream->par.bps;
+    wblksz = sndioStream->par.round * sndioStream->par.pchan * 
sndioStream->par.bps;
+
+    PA_DEBUG( ( "sndioThread: mode = %x, round = %u, rblksz = %u, wblksz = 
%u\n", sndioStream->mode,
+                sndioStream->par.round, rblksz, wblksz ) );
+
+    while( !sndioStream->stopped )
+    {
+        if( sndioStream->mode & SIO_REC )
+        {
+            todo = rblksz;
+            data = sndioStream->rbuf;
+            while( todo > 0 )
+            {
+                n = sio_read( sndioStream->hdl, data, todo );
+                if( n == 0 )
+                {
+                    PA_DEBUG( ( "sndioThread: sio_read failed\n" ) );
+                    goto failed;
+                }
+                todo -= n;
+                data += n;
+            }
+            sndioStream->rpos += sndioStream->par.round;
+            timeInfo.inputBufferAdcTime = (double)sndioStream->realpos / 
sndioStream->par.rate;
+        }
+        if( sndioStream->mode & SIO_PLAY )
+        {
+            timeInfo.outputBufferDacTime =
+                (double)( sndioStream->realpos + sndioStream->par.bufsz ) / 
sndioStream->par.rate;
+        }
+        timeInfo.currentTime = sndioStream->realpos / 
(double)sndioStream->par.rate;
+        PaUtil_BeginBufferProcessing( &sndioStream->bufferProcessor, 
&timeInfo, 0 );
+        if( sndioStream->mode & SIO_PLAY )
+        {
+            PaUtil_SetOutputFrameCount( &sndioStream->bufferProcessor, 
sndioStream->par.round );
+            PaUtil_SetInterleavedOutputChannels( 
&sndioStream->bufferProcessor, 0, sndioStream->wbuf,
+                                                 sndioStream->par.pchan );
+        }
+        if( sndioStream->mode & SIO_REC )
+        {
+            PaUtil_SetInputFrameCount( &sndioStream->bufferProcessor, 
sndioStream->par.round );
+            PaUtil_SetInterleavedInputChannels( &sndioStream->bufferProcessor, 
0, sndioStream->rbuf,
+                                                sndioStream->par.rchan );
+        }
+        result = paContinue;
+        n = PaUtil_EndBufferProcessing( &sndioStream->bufferProcessor, &result 
);
+        if( n != sndioStream->par.round )
+        {
+            PA_DEBUG( ( "sndioThread: %d < %u frames, result = %d\n", n, 
sndioStream->par.round, result ) );
+        }
+        if( result != paContinue )
+        {
+            break;
+        }
+        if( sndioStream->mode & SIO_PLAY )
+        {
+            n = sio_write( sndioStream->hdl, sndioStream->wbuf, wblksz );
+            if( n < wblksz )
+            {
+                PA_DEBUG( ( "sndioThread: sio_write failed\n" ) );
+                goto failed;
+            }
+            sndioStream->wpos += sndioStream->par.round;
+        }
+    }
+failed:
+    sndioStream->active = 0;
+    PA_DEBUG( ( "sndioThread: done\n" ) );
+    return NULL;
+}
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi, 
PaStream **paStream,
+                           const PaStreamParameters *inputPar, const 
PaStreamParameters *outputPar, double sampleRate,
+                           unsigned long framesPerBuffer, PaStreamFlags 
streamFlags, PaStreamCallback *streamCallback,
+                           void *userData )
+{
+    PaSndioHostApiRepresentation *sndioHostApi = (PaSndioHostApiRepresentation 
*)hostApi;
+    PaSndioStream *sndioStream;
+    PaError err;
+    struct sio_hdl *hdl;
+    struct sio_par par;
+    unsigned mode;
+    int inputChannelCount, outputChannelCount;
+    PaSampleFormat inputFormat, outputFormat, sndioFormat;
+    const char *dev;
+
+    PA_DEBUG( ( "OpenStream:\n" ) );
+
+    mode = 0;
+    inputChannelCount = outputChannelCount = 0;
+    inputFormat = outputFormat = 0;
+    sio_initpar( &par );
+
+    if( outputPar && outputPar->channelCount > 0 )
+    {
+        if( outputPar->device >= sndioHostApi->base.info.deviceCount )
+        {
+            PA_DEBUG( ( "OpenStream: %d: bad output device\n", 
outputPar->device ) );
+            return paInvalidDevice;
+        }
+        if( outputPar->hostApiSpecificStreamInfo )
+        {
+            PA_DEBUG( ( "OpenStream: output specific info\n" ) );
+            return paIncompatibleHostApiSpecificStreamInfo;
+        }
+        if( !sndioSetFmt( &par, outputPar->sampleFormat ) )
+        {
+            return paSampleFormatNotSupported;
+        }
+        outputFormat = outputPar->sampleFormat;
+        outputChannelCount = par.pchan = outputPar->channelCount;
+        mode |= SIO_PLAY;
+    }
+    if( inputPar && inputPar->channelCount > 0 )
+    {
+        if( inputPar->device >= sndioHostApi->base.info.deviceCount )
+        {
+            PA_DEBUG( ( "OpenStream: %d: bad input device\n", inputPar->device 
) );
+            return paInvalidDevice;
+        }
+        if( inputPar->hostApiSpecificStreamInfo )
+        {
+            PA_DEBUG( ( "OpenStream: input specific info\n" ) );
+            return paIncompatibleHostApiSpecificStreamInfo;
+        }
+        if( !sndioSetFmt( &par, inputPar->sampleFormat ) )
+        {
+            return paSampleFormatNotSupported;
+        }
+        inputFormat = inputPar->sampleFormat;
+        inputChannelCount = par.rchan = inputPar->channelCount;
+        mode |= SIO_REC;
+    }
+    par.rate = sampleRate;
+    if( framesPerBuffer != paFramesPerBufferUnspecified )
+        par.round = framesPerBuffer;
+
+    PA_DEBUG( ( "OpenStream: mode = %x, trying rate = %u\n", mode, par.rate ) 
);
+
+    if( outputPar )
+    {
+        dev = sndioHostApi->deviceInfos[outputPar->device].name;
+    }
+    else if( inputPar )
+    {
+        dev = sndioHostApi->deviceInfos[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, &sndioFormat ) )
+    {
+        sio_close( hdl );
+        return paSampleFormatNotSupported;
+    }
+    if( ( mode & SIO_REC ) && par.rchan != inputPar->channelCount )
+    {
+        PA_DEBUG( ( "OpenStream: rchan(%u) != %d\n", par.rchan, 
inputPar->channelCount ) );
+        sio_close( hdl );
+        return paInvalidChannelCount;
+    }
+    if( ( mode & SIO_PLAY ) && par.pchan != outputPar->channelCount )
+    {
+        PA_DEBUG( ( "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 )
+    {
+        PA_DEBUG( ( "OpenStream: rate(%u) != %g\n", par.rate, sampleRate ) );
+        sio_close( hdl );
+        return paInvalidSampleRate;
+    }
+
+    sndioStream = (PaSndioStream *)PaUtil_AllocateMemory( sizeof( 
PaSndioStream ) );
+    if( sndioStream == NULL )
+    {
+        sio_close( hdl );
+        return paInsufficientMemory;
+    }
+    PaUtil_InitializeStreamRepresentation( &sndioStream->base,
+                                           streamCallback ? 
&sndioHostApi->callback : &sndioHostApi->blocking,
+                                           streamCallback, userData );
+    PA_DEBUG( ( "inputChannelCount = %d, outputChannelCount = %d, inputFormat 
= "
+                "%x, outputFormat = %x\n",
+                inputChannelCount, outputChannelCount, inputFormat, 
outputFormat ) );
+    err = PaUtil_InitializeBufferProcessor( &sndioStream->bufferProcessor, 
inputChannelCount, inputFormat, sndioFormat,
+                                            outputChannelCount, outputFormat, 
sndioFormat, sampleRate, streamFlags,
+                                            framesPerBuffer, par.round, 
paUtilFixedHostBufferSize, streamCallback,
+                                            userData );
+    if( err )
+    {
+        PA_DEBUG( ( "OpenStream: PaUtil_InitializeBufferProcessor failed\n" ) 
);
+        PaUtil_FreeMemory( sndioStream );
+        sio_close( hdl );
+        return err;
+    }
+    if( mode & SIO_REC )
+    {
+        sndioStream->rbuf = malloc( par.round * par.rchan * par.bps );
+        if( sndioStream->rbuf == NULL )
+        {
+            PA_DEBUG( ( "OpenStream: failed to allocate rbuf\n" ) );
+            PaUtil_FreeMemory( sndioStream );
+            sio_close( hdl );
+            return paInsufficientMemory;
+        }
+    }
+    if( mode & SIO_PLAY )
+    {
+        sndioStream->wbuf = malloc( par.round * par.pchan * par.bps );
+        if( sndioStream->wbuf == NULL )
+        {
+            PA_DEBUG( ( "OpenStream: failed to allocate wbuf\n" ) );
+            free( sndioStream->rbuf );
+            PaUtil_FreeMemory( sndioStream );
+            sio_close( hdl );
+            return paInsufficientMemory;
+        }
+    }
+    sndioStream->base.streamInfo.inputLatency = 0;
+    sndioStream->base.streamInfo.outputLatency =
+        ( mode & SIO_PLAY )
+            ? (double)( par.bufsz + 
PaUtil_GetBufferProcessorOutputLatencyFrames( &sndioStream->bufferProcessor ) ) 
/
+                  (double)par.rate
+            : 0;
+    sndioStream->base.streamInfo.sampleRate = par.rate;
+    sndioStream->active = 0;
+    sndioStream->stopped = 1;
+    sndioStream->mode = mode;
+    sndioStream->hdl = hdl;
+    sndioStream->par = par;
+    *paStream = sndioStream;
+    PA_DEBUG( ( "OpenStream: done\n" ) );
+    return paNoError;
+}
+
+static PaError BlockingReadStream( PaStream *paStream, void *data, unsigned 
long numFrames )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    unsigned n, res, todo;
+    void *buf;
+
+    while( numFrames > 0 )
+    {
+        n = sndioStream->par.round;
+        if( n > numFrames )
+            n = numFrames;
+        buf = sndioStream->rbuf;
+        todo = n * sndioStream->par.rchan * sndioStream->par.bps;
+        while( todo > 0 )
+        {
+            res = sio_read( sndioStream->hdl, buf, todo );
+            if( res == 0 )
+                return paUnanticipatedHostError;
+            buf = (char *)buf + res;
+            todo -= res;
+        }
+        sndioStream->rpos += n;
+        PaUtil_SetInputFrameCount( &sndioStream->bufferProcessor, n );
+        PaUtil_SetInterleavedInputChannels( &sndioStream->bufferProcessor, 0, 
sndioStream->rbuf,
+                                            sndioStream->par.rchan );
+        res = PaUtil_CopyInput( &sndioStream->bufferProcessor, &data, n );
+        if( res != n )
+        {
+            PA_DEBUG( ( "BlockingReadStream: copyInput: %u != %u\n" ) );
+            return paUnanticipatedHostError;
+        }
+        numFrames -= n;
+    }
+    return paNoError;
+}
+
+static PaError BlockingWriteStream( PaStream *paStream, const void *data, 
unsigned long numFrames )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    unsigned n, res;
+
+    while( numFrames > 0 )
+    {
+        n = sndioStream->par.round;
+        if( n > numFrames )
+            n = numFrames;
+        PaUtil_SetOutputFrameCount( &sndioStream->bufferProcessor, n );
+        PaUtil_SetInterleavedOutputChannels( &sndioStream->bufferProcessor, 0, 
sndioStream->wbuf,
+                                             sndioStream->par.pchan );
+        res = PaUtil_CopyOutput( &sndioStream->bufferProcessor, &data, n );
+        if( res != n )
+        {
+            PA_DEBUG( ( "BlockingWriteStream: copyOutput: %u != %u\n" ) );
+            return paUnanticipatedHostError;
+        }
+        res = sio_write( sndioStream->hdl, sndioStream->wbuf, n * 
sndioStream->par.pchan * sndioStream->par.bps );
+        if( res == 0 )
+            return paUnanticipatedHostError;
+        sndioStream->wpos += n;
+        numFrames -= n;
+    }
+    return paNoError;
+}
+
+static signed long BlockingGetStreamReadAvailable( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    struct pollfd pfd;
+    int n, events;
+
+    n = sio_pollfd( sndioStream->hdl, &pfd, POLLIN );
+    while( poll( &pfd, n, 0 ) < 0 )
+    {
+        if( errno == EINTR )
+            continue;
+        perror( "poll" );
+        abort();
+    }
+    events = sio_revents( sndioStream->hdl, &pfd );
+    if( !( events & POLLIN ) )
+        return 0;
+
+    return sndioStream->realpos - sndioStream->rpos;
+}
+
+static signed long BlockingGetStreamWriteAvailable( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    struct pollfd pfd;
+    int n, events;
+
+    n = sio_pollfd( sndioStream->hdl, &pfd, POLLOUT );
+    while( poll( &pfd, n, 0 ) < 0 )
+    {
+        if( errno == EINTR )
+            continue;
+        perror( "poll" );
+        abort();
+    }
+    events = sio_revents( sndioStream->hdl, &pfd );
+    if( !( events & POLLOUT ) )
+        return 0;
+
+    return sndioStream->par.bufsz - ( sndioStream->wpos - sndioStream->realpos 
);
+}
+
+static PaError BlockingWaitEmpty( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+
+    /*
+     * drain playback buffers; sndio always does it in background
+     * and there is no way to wait for completion
+     */
+    PA_DEBUG( ( "BlockingWaitEmpty: s=%d, a=%d\n", sndioStream->stopped, 
sndioStream->active ) );
+
+    return paNoError;
+}
+
+static PaError StartStream( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    unsigned primes, wblksz;
+    int err;
+
+    PA_DEBUG( ( "StartStream: s=%d, a=%d\n", sndioStream->stopped, 
sndioStream->active ) );
+
+    if( !sndioStream->stopped )
+    {
+        PA_DEBUG( ( "StartStream: already started\n" ) );
+        return paNoError;
+    }
+    sndioStream->stopped = 0;
+    sndioStream->active = 1;
+    sndioStream->realpos = 0;
+    sndioStream->wpos = 0;
+    sndioStream->rpos = 0;
+    PaUtil_ResetBufferProcessor( &sndioStream->bufferProcessor );
+    if( !sio_start( sndioStream->hdl ) )
+        return paUnanticipatedHostError;
+
+    /*
+     * send a complete buffer of silence
+     */
+    if( sndioStream->mode & SIO_PLAY )
+    {
+        wblksz = sndioStream->par.round * sndioStream->par.pchan * 
sndioStream->par.bps;
+        memset( sndioStream->wbuf, 0, wblksz );
+        for( primes = sndioStream->par.bufsz / sndioStream->par.round; primes 
> 0; primes-- )
+            sndioStream->wpos += sio_write( sndioStream->hdl, 
sndioStream->wbuf, wblksz );
+    }
+    if( sndioStream->base.streamCallback )
+    {
+        err = pthread_create( &sndioStream->thread, NULL, sndioThread, 
sndioStream );
+        if( err )
+        {
+            PA_DEBUG( ( "SndioStartStream: couldn't create thread\n" ) );
+            return paUnanticipatedHostError;
+        }
+        PA_DEBUG( ( "StartStream: started...\n" ) );
+    }
+    return paNoError;
+}
+
+static PaError StopStream( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+    void *ret;
+    int err;
+
+    PA_DEBUG( ( "StopStream: s=%d, a=%d\n", sndioStream->stopped, 
sndioStream->active ) );
+
+    if( sndioStream->stopped )
+    {
+        PA_DEBUG( ( "StartStream: already started\n" ) );
+        return paNoError;
+    }
+    sndioStream->stopped = 1;
+    if( sndioStream->base.streamCallback )
+    {
+        err = pthread_join( sndioStream->thread, &ret );
+        if( err )
+        {
+            PA_DEBUG( ( "SndioStop: couldn't join thread\n" ) );
+            return paUnanticipatedHostError;
+        }
+    }
+    if( !sio_stop( sndioStream->hdl ) )
+        return paUnanticipatedHostError;
+    return paNoError;
+}
+
+static PaError CloseStream( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+
+    PA_DEBUG( ( "CloseStream:\n" ) );
+
+    if( !sndioStream->stopped )
+        StopStream( paStream );
+
+    if( sndioStream->mode & SIO_REC )
+        free( sndioStream->rbuf );
+    if( sndioStream->mode & SIO_PLAY )
+        free( sndioStream->wbuf );
+    sio_close( sndioStream->hdl );
+    PaUtil_TerminateStreamRepresentation( &sndioStream->base );
+    PaUtil_TerminateBufferProcessor( &sndioStream->bufferProcessor );
+    PaUtil_FreeMemory( sndioStream );
+    return paNoError;
+}
+
+static PaError AbortStream( PaStream *paStream )
+{
+    PA_DEBUG( ( "AbortStream:\n" ) );
+
+    return StopStream( paStream );
+}
+
+static PaError IsStreamStopped( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+
+    // PA_DEBUG(("IsStreamStopped: s=%d, a=%d\n", sndioStream->stopped,
+    // sndioStream->active));
+
+    return sndioStream->stopped;
+}
+
+static PaError IsStreamActive( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+
+    // PA_DEBUG(("IsStreamActive: s=%d, a=%d\n", sndioStream->stopped,
+    // sndioStream->active));
+
+    return sndioStream->active;
+}
+
+static PaTime GetStreamTime( PaStream *paStream )
+{
+    PaSndioStream *sndioStream = (PaSndioStream *)paStream;
+
+    return (double)sndioStream->realpos / 
sndioStream->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;
+
+    PA_DEBUG( ( "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->deviceInfos[0];
+    InitDeviceInfo( info, hostApiIndex, SIO_DEVANY );
+    sndioHostApi->deviceInfoPtrs[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->deviceInfos[deviceCount];
+            InitDeviceInfo( info, hostApiIndex, device );
+            sndioHostApi->deviceInfoPtrs[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->deviceInfoPtrs;
+    ( *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;
+    PA_DEBUG( ( "PaSndio_Initialize: done\n" ) );
+    return paNoError;
 }
Index: patches/patch-Makefile_in
===================================================================
RCS file: /cvs/ports/audio/portaudio-svn/patches/patch-Makefile_in,v
retrieving revision 1.6
diff -u -p -u -p -r1.6 patch-Makefile_in
--- patches/patch-Makefile_in   11 Mar 2022 18:20:26 -0000      1.6
+++ patches/patch-Makefile_in   22 Feb 2024 05:28:04 -0000
@@ -1,3 +1,6 @@
+Add support for sndio (#878)
+45c12e8d18ae4434000ed1521e49d9b5ef91dedf
+
 Index: Makefile.in
 --- Makefile.in.orig
 +++ Makefile.in
Index: patches/patch-configure_in
===================================================================
RCS file: /cvs/ports/audio/portaudio-svn/patches/patch-configure_in,v
retrieving revision 1.7
diff -u -p -u -p -r1.7 patch-configure_in
--- patches/patch-configure_in  11 Mar 2022 18:20:26 -0000      1.7
+++ patches/patch-configure_in  22 Feb 2024 05:28:04 -0000
@@ -1,3 +1,6 @@
+Add support for sndio (#878)
+45c12e8d18ae4434000ed1521e49d9b5ef91dedf
+
 Index: configure.in
 --- configure.in.orig
 +++ configure.in
@@ -18,7 +21,7 @@ Index: configure.in
  fi
 +have_sndio=no
 +if test "x$with_sndio" != "xno"; then
-+    AC_CHECK_LIB(sndio, sio_open, have_sndio=yes, have_sndio=no)
++    PKG_CHECK_MODULES(SNDIO, sndio, have_sndio=yes, have_sndio=no)
 +fi
  have_asihpi=no
  if test "x$with_asihpi" != "xno"; then
@@ -28,8 +31,8 @@ Index: configure.in
          fi
  
 +        if [[ "$have_sndio" = "yes" -a "$with_sndio" != "no" ]] ; then
-+           DLL_LIBS="$DLL_LIBS -lsndio"
-+           LIBS="$LIBS -lsndio"
++           DLL_LIBS="$DLL_LIBS $SNDIO_LIBS"
++           CFLAGS="$CFLAGS $SNDIO_CFLAGS"
 +           OTHER_OBJS="$OTHER_OBJS src/hostapi/sndio/pa_sndio.o"
 +           AC_DEFINE(PA_USE_SNDIO,1)
 +        fi
@@ -37,11 +40,11 @@ Index: configure.in
          if [[ "$have_jack" = "yes" ] && [ "$with_jack" != "no" ]] ; then
             DLL_LIBS="$DLL_LIBS $JACK_LIBS"
             CFLAGS="$CFLAGS $JACK_CFLAGS"
-@@ -504,6 +519,7 @@ case "$target_os" in
-         ;;
-      *)
+@@ -506,6 +521,7 @@ case "$target_os" in
        AC_MSG_RESULT([
-+  Sndio ....................... $have_sndio
    OSS ......................... $have_oss
    JACK ........................ $have_jack
++  Sndio ....................... $have_sndio
  ])
+         ;;
+ esac
Index: patches/patch-include_portaudio_h
===================================================================
RCS file: /cvs/ports/audio/portaudio-svn/patches/patch-include_portaudio_h,v
retrieving revision 1.5
diff -u -p -u -p -r1.5 patch-include_portaudio_h
--- patches/patch-include_portaudio_h   11 Mar 2022 18:20:26 -0000      1.5
+++ patches/patch-include_portaudio_h   22 Feb 2024 05:28:04 -0000
@@ -1,3 +1,6 @@
+Add support for sndio (#878)
+45c12e8d18ae4434000ed1521e49d9b5ef91dedf
+
 Index: include/portaudio.h
 --- include/portaudio.h.orig
 +++ include/portaudio.h
Index: patches/patch-src_os_unix_pa_unix_hostapis_c
===================================================================
RCS file: 
/cvs/ports/audio/portaudio-svn/patches/patch-src_os_unix_pa_unix_hostapis_c,v
retrieving revision 1.4
diff -u -p -u -p -r1.4 patch-src_os_unix_pa_unix_hostapis_c
--- patches/patch-src_os_unix_pa_unix_hostapis_c        11 Mar 2022 18:20:26 
-0000      1.4
+++ patches/patch-src_os_unix_pa_unix_hostapis_c        22 Feb 2024 05:28:04 
-0000
@@ -1,3 +1,6 @@
+Add support for sndio (#878)
+45c12e8d18ae4434000ed1521e49d9b5ef91dedf
+
 Index: src/os/unix/pa_unix_hostapis.c
 --- src/os/unix/pa_unix_hostapis.c.orig
 +++ src/os/unix/pa_unix_hostapis.c
@@ -9,14 +12,23 @@ Index: src/os/unix/pa_unix_hostapis.c
  PaError PaOSS_Initialize( PaUtilHostApiRepresentation **hostApi, 
PaHostApiIndex index );
  /* Added for IRIX, Pieter, oct 2, 2003: */
  PaError PaSGI_Initialize( PaUtilHostApiRepresentation **hostApi, 
PaHostApiIndex index );
-@@ -78,6 +79,10 @@ PaUtilHostApiInitializer *paHostApiInitializers[] =
+@@ -63,11 +64,19 @@ PaUtilHostApiInitializer *paHostApiInitializers[] =
+         PaAlsa_Initialize,
  #endif
  
- #endif  /* __linux__ */
++#ifdef PA_USE_SNDIO
++        PaSndio_Initialize,
++#endif
++
+ #if PA_USE_OSS
+         PaOSS_Initialize,
+ #endif
+ 
+ #else   /* __linux__ */
 +
 +#ifdef PA_USE_SNDIO
-+      PaSndio_Initialize,
++        PaSndio_Initialize,
 +#endif
  
- #if PA_USE_JACK
-         PaJack_Initialize,
+ #if PA_USE_OSS
+         PaOSS_Initialize,

Reply via email to