Index: pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_lib.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_lib.c	(revision 339)
+++ pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_lib.c	(revision 339)
@@ -0,0 +1,827 @@
+/*
+ * Portable Audio I/O Library
+ * Host Independant Layer
+ *
+ * Based on the Open Source API proposed by Ross Bencina
+ * Copyright (c) 1999-2000 Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* Modification History:
+ PLB20010422 - apply Mike Berry's changes for CodeWarrior on PC
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+/* PLB20010422 - "memory.h" doesn't work on CodeWarrior for PC. Thanks Mike Berry for the mod. */
+#ifdef _WIN32
+#ifndef __MWERKS__
+#include <memory.h>
+#endif  /* __MWERKS__ */
+#else   /* !_WIN32 */
+#include <memory.h>
+#endif  /* _WIN32 */
+
+#include "portaudio.h"
+#include "pa_host.h"
+#include "pa_trace.h"
+
+/* The reason we might NOT want to validate the rate before opening the stream
+ * is because many DirectSound drivers lie about the rates they actually support.
+ */
+#define PA_VALIDATE_RATE    (0)   /* If true validate sample rate against driver info. */
+
+/*
+O- maybe not allocate past_InputBuffer and past_OutputBuffer if not needed for conversion
+*/
+
+#ifndef FALSE
+ #define FALSE  (0)
+ #define TRUE   (!FALSE)
+#endif
+
+#define PRINT(x) { printf x; fflush(stdout); }
+#define ERR_RPT(x) PRINT(x)
+#define DBUG(x)  /* PRINT(x) */
+#define DBUGX(x) /* PRINT(x) */
+
+static int gInitCount = 0; /* Count number of times Pa_Initialize() called to allow nesting and overlapping. */
+
+static PaError Pa_KillStream(  PortAudioStream *stream, int abort );
+
+/***********************************************************************/
+int PaHost_FindClosestTableEntry( double allowableError,  const double *rateTable, int numRates, double frameRate )
+{
+    double err, minErr = allowableError;
+    int i, bestFit = -1;
+
+    for( i=0; i<numRates; i++ )
+    {
+        err = fabs( frameRate - rateTable[i] );
+        if( err < minErr )
+        {
+            minErr = err;
+            bestFit = i;
+        }
+    }
+    return bestFit;
+}
+
+/**************************************************************************
+** Make sure sample rate is legal and also convert to enumeration for driver.
+*/
+PaError PaHost_ValidateSampleRate( PaDeviceID id, double requestedFrameRate,
+                                   double *closestFrameRatePtr )
+{
+    long bestRateIndex;
+    const PaDeviceInfo *pdi;
+    pdi = Pa_GetDeviceInfo( id );
+    if( pdi == NULL ) return paInvalidDeviceId;
+
+    if( pdi->numSampleRates == -1 )
+    {
+        /* Is it out of range? */
+        if( (requestedFrameRate < pdi->sampleRates[0]) ||
+                (requestedFrameRate > pdi->sampleRates[1]) )
+        {
+            return paInvalidSampleRate;
+        }
+
+        *closestFrameRatePtr = requestedFrameRate;
+    }
+    else
+    {
+        bestRateIndex = PaHost_FindClosestTableEntry( 1.0, pdi->sampleRates, pdi->numSampleRates, requestedFrameRate );
+        if( bestRateIndex < 0 ) return paInvalidSampleRate;
+        *closestFrameRatePtr = pdi->sampleRates[bestRateIndex];
+    }
+    return paNoError;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenStream(
+    PortAudioStream** streamPtrPtr,
+    PaDeviceID inputDeviceID,
+    int numInputChannels,
+    PaSampleFormat inputSampleFormat,
+    void *inputDriverInfo,
+    PaDeviceID outputDeviceID,
+    int numOutputChannels,
+    PaSampleFormat outputSampleFormat,
+    void *outputDriverInfo,
+    double sampleRate,
+    unsigned long framesPerBuffer,
+    unsigned long numberOfBuffers,
+    unsigned long streamFlags,
+    PortAudioCallback *callback,
+    void *userData )
+{
+    internalPortAudioStream   *past = NULL;
+    PaError                    result = paNoError;
+    int                        bitsPerInputSample;
+    int                        bitsPerOutputSample;
+    /* Print passed parameters. */
+    DBUG(("Pa_OpenStream( %p, %d, %d, %d, %p, /* input */ \n",
+          streamPtrPtr, inputDeviceID, numInputChannels,
+          inputSampleFormat, inputDriverInfo ));
+    DBUG(("               %d, %d, %d, %p, /* output */\n",
+          outputDeviceID, numOutputChannels,
+          outputSampleFormat, outputDriverInfo ));
+    DBUG(("               %g, %d, %d, 0x%x, , %p )\n",
+          sampleRate, framesPerBuffer, numberOfBuffers,
+          streamFlags, userData ));
+
+    /* Check for parameter errors. */
+    if( (streamFlags & ~(paClipOff | paDitherOff)) != 0 ) return paInvalidFlag;
+    if( streamPtrPtr == NULL ) return paBadStreamPtr;
+    if( inputDriverInfo != NULL ) return paHostError; /* REVIEW */
+    if( outputDriverInfo != NULL ) return paHostError; /* REVIEW */
+    if( (inputDeviceID < 0) && ( outputDeviceID < 0) ) return paInvalidDeviceId;
+    if( (outputDeviceID >= Pa_CountDevices()) || (inputDeviceID >= Pa_CountDevices()) ) return paInvalidDeviceId;
+    if( (numInputChannels <= 0) && ( numOutputChannels <= 0) ) return paInvalidChannelCount;
+
+#if SUPPORT_AUDIO_CAPTURE
+    if( inputDeviceID >= 0 )
+    {
+        PaError size = Pa_GetSampleSize( inputSampleFormat );
+        if( size < 0 ) return size;
+        bitsPerInputSample = 8 * size;
+        if( (numInputChannels <= 0) ) return paInvalidChannelCount;
+    }
+#else
+    if( inputDeviceID >= 0 )
+    {
+        return paInvalidChannelCount;
+    }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+    else
+    {
+        if( numInputChannels > 0 ) return paInvalidChannelCount;
+        bitsPerInputSample = 0;
+    }
+
+    if( outputDeviceID >= 0 )
+    {
+        PaError size = Pa_GetSampleSize( outputSampleFormat );
+        if( size < 0 ) return size;
+        bitsPerOutputSample = 8 * size;
+        if( (numOutputChannels <= 0) ) return paInvalidChannelCount;
+    }
+    else
+    {
+        if( numOutputChannels > 0 ) return paInvalidChannelCount;
+        bitsPerOutputSample = 0;
+    }
+
+    if( callback == NULL ) return paNullCallback;
+
+    /* Allocate and clear stream structure. */
+    past = (internalPortAudioStream *) PaHost_AllocateFastMemory( sizeof(internalPortAudioStream) );
+    if( past == NULL ) return paInsufficientMemory;
+    memset( past, 0, sizeof(internalPortAudioStream) );
+    AddTraceMessage("Pa_OpenStream: past", (long) past );
+
+    past->past_Magic = PA_MAGIC;  /* Set ID to catch bugs. */
+    past->past_FramesPerUserBuffer = framesPerBuffer;
+    past->past_NumUserBuffers = numberOfBuffers; /* NOTE - PaHost_OpenStream() NMUST CHECK FOR ZERO! */
+    past->past_Callback = callback;
+    past->past_UserData = userData;
+    past->past_OutputSampleFormat = outputSampleFormat;
+    past->past_InputSampleFormat = inputSampleFormat;
+    past->past_OutputDeviceID = outputDeviceID;
+    past->past_InputDeviceID = inputDeviceID;
+    past->past_NumInputChannels = numInputChannels;
+    past->past_NumOutputChannels = numOutputChannels;
+    past->past_Flags = streamFlags;
+
+    /* Check for absurd sample rates. */
+    if( (sampleRate < 1000.0) || (sampleRate > 200000.0) )
+    {
+        result = paInvalidSampleRate;
+        goto cleanup;
+    }
+
+    /* Allocate buffers that may be used for format conversion from user to native buffers. */
+    if( numInputChannels > 0 )
+    {
+
+#if PA_VALIDATE_RATE
+        result = PaHost_ValidateSampleRate( inputDeviceID, sampleRate, &past->past_SampleRate );
+        if( result < 0 )
+        {
+            goto cleanup;
+        }
+#else
+        past->past_SampleRate = sampleRate;
+#endif
+        /* Allocate single Input buffer. */
+        past->past_InputBufferSize = framesPerBuffer * numInputChannels * ((bitsPerInputSample+7) / 8);
+        past->past_InputBuffer = PaHost_AllocateFastMemory(past->past_InputBufferSize);
+        if( past->past_InputBuffer == NULL )
+        {
+            result = paInsufficientMemory;
+            goto cleanup;
+        }
+    }
+    else
+    {
+        past->past_InputBuffer = NULL;
+    }
+
+    /* Allocate single Output buffer. */
+    if( numOutputChannels > 0 )
+    {
+#if PA_VALIDATE_RATE
+        result = PaHost_ValidateSampleRate( outputDeviceID, sampleRate, &past->past_SampleRate );
+        if( result < 0 )
+        {
+            goto cleanup;
+        }
+#else
+        past->past_SampleRate = sampleRate;
+#endif
+        past->past_OutputBufferSize = framesPerBuffer * numOutputChannels * ((bitsPerOutputSample+7) / 8);
+        past->past_OutputBuffer = PaHost_AllocateFastMemory(past->past_OutputBufferSize);
+        if( past->past_OutputBuffer == NULL )
+        {
+            result = paInsufficientMemory;
+            goto cleanup;
+        }
+    }
+    else
+    {
+        past->past_OutputBuffer = NULL;
+    }
+
+    result = PaHost_OpenStream( past );
+    if( result < 0 ) goto cleanup;
+
+    *streamPtrPtr = (void *) past;
+
+    return result;
+
+cleanup:
+    if( past != NULL ) Pa_CloseStream( past );
+    *streamPtrPtr = NULL;
+    return result;
+}
+
+
+/*************************************************************************/
+DLL_API PaError Pa_OpenDefaultStream( PortAudioStream** stream,
+                                      int numInputChannels,
+                                      int numOutputChannels,
+                                      PaSampleFormat sampleFormat,
+                                      double sampleRate,
+                                      unsigned long framesPerBuffer,
+                                      unsigned long numberOfBuffers,
+                                      PortAudioCallback *callback,
+                                      void *userData )
+{
+    return Pa_OpenStream(
+               stream,
+               ((numInputChannels > 0) ? Pa_GetDefaultInputDeviceID() : paNoDevice),
+               numInputChannels, sampleFormat, NULL,
+               ((numOutputChannels > 0) ? Pa_GetDefaultOutputDeviceID() : paNoDevice),
+               numOutputChannels, sampleFormat, NULL,
+               sampleRate, framesPerBuffer, numberOfBuffers, paNoFlag, callback, userData );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_CloseStream( PortAudioStream* stream)
+{
+    PaError   result;
+    internalPortAudioStream   *past;
+
+    DBUG(("Pa_CloseStream()\n"));
+    if( stream == NULL ) return paBadStreamPtr;
+    past = (internalPortAudioStream *) stream;
+
+    Pa_AbortStream( past );
+    result = PaHost_CloseStream( past );
+
+    if( past->past_InputBuffer ) PaHost_FreeFastMemory( past->past_InputBuffer, past->past_InputBufferSize );
+    if( past->past_OutputBuffer ) PaHost_FreeFastMemory( past->past_OutputBuffer, past->past_OutputBufferSize );
+    PaHost_FreeFastMemory( past, sizeof(internalPortAudioStream) );
+
+    return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StartStream( PortAudioStream *stream )
+{
+    PaError result = paHostError;
+    internalPortAudioStream   *past;
+
+    if( stream == NULL ) return paBadStreamPtr;
+    past = (internalPortAudioStream *) stream;
+
+    past->past_FrameCount = 0.0;
+
+    if( past->past_NumInputChannels > 0 )
+    {
+        result = PaHost_StartInput( past );
+        DBUG(("Pa_StartStream: PaHost_StartInput returned = 0x%X.\n", result));
+        if( result < 0 ) goto error;
+    }
+
+    if( past->past_NumOutputChannels > 0 )
+    {
+        result = PaHost_StartOutput( past );
+        DBUG(("Pa_StartStream: PaHost_StartOutput returned = 0x%X.\n", result));
+        if( result < 0 ) goto error;
+    }
+
+    result = PaHost_StartEngine( past );
+    DBUG(("Pa_StartStream: PaHost_StartEngine returned = 0x%X.\n", result));
+    if( result < 0 ) goto error;
+
+    return paNoError;
+
+error:
+    return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StopStream(  PortAudioStream *stream )
+{
+    return Pa_KillStream( stream, 0 );
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_AbortStream(  PortAudioStream *stream )
+{
+    return Pa_KillStream( stream, 1 );
+}
+
+/*************************************************************************/
+static PaError Pa_KillStream(  PortAudioStream *stream, int abort )
+{
+    PaError result = paNoError;
+    internalPortAudioStream   *past;
+
+    DBUG(("Pa_StopStream().\n"));
+    if( stream == NULL ) return paBadStreamPtr;
+    past = (internalPortAudioStream *) stream;
+
+    if( (past->past_NumInputChannels > 0) || (past->past_NumOutputChannels > 0) )
+    {
+        result = PaHost_StopEngine( past, abort );
+        DBUG(("Pa_StopStream: PaHost_StopEngine returned = 0x%X.\n", result));
+        if( result < 0 ) goto error;
+    }
+
+    if( past->past_NumInputChannels > 0 )
+    {
+        result = PaHost_StopInput( past, abort );
+        DBUG(("Pa_StopStream: PaHost_StopInput returned = 0x%X.\n", result));
+        if( result != paNoError ) goto error;
+    }
+
+    if( past->past_NumOutputChannels > 0 )
+    {
+        result = PaHost_StopOutput( past, abort );
+        DBUG(("Pa_StopStream: PaHost_StopOutput returned = 0x%X.\n", result));
+        if( result != paNoError ) goto error;
+    }
+
+error:
+    past->past_Usage = 0;
+    past->past_IfLastExitValid = 0;
+
+    return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_StreamActive( PortAudioStream *stream )
+{
+    internalPortAudioStream   *past;
+    if( stream == NULL ) return paBadStreamPtr;
+    past = (internalPortAudioStream *) stream;
+    return PaHost_StreamActive( past );
+}
+
+/*************************************************************************/
+DLL_API const char *Pa_GetErrorText( PaError errnum )
+{
+    const char *msg;
+
+    switch(errnum)
+    {
+    case paNoError:                  msg = "Success"; break;
+    case paHostError:                msg = "Host error."; break;
+    case paInvalidChannelCount:      msg = "Invalid number of channels."; break;
+    case paInvalidSampleRate:        msg = "Invalid sample rate."; break;
+    case paInvalidDeviceId:          msg = "Invalid device ID."; break;
+    case paInvalidFlag:              msg = "Invalid flag."; break;
+    case paSampleFormatNotSupported: msg = "Sample format not supported"; break;
+    case paBadIODeviceCombination:   msg = "Illegal combination of I/O devices."; break;
+    case paInsufficientMemory:       msg = "Insufficient memory."; break;
+    case paBufferTooBig:             msg = "Buffer too big."; break;
+    case paBufferTooSmall:           msg = "Buffer too small."; break;
+    case paNullCallback:             msg = "No callback routine specified."; break;
+    case paBadStreamPtr:             msg = "Invalid stream pointer."; break;
+    case paTimedOut    :             msg = "Wait Timed Out."; break;
+    case paInternalError:            msg = "Internal PortAudio Error."; break;
+    default:                         msg = "Illegal error number."; break;
+    }
+    return msg;
+}
+
+/*
+ Get CPU Load as a fraction of total CPU time.
+ A value of 0.5 would imply that PortAudio and the sound generating
+ callback was consuming roughly 50% of the available CPU time.
+ The amount may vary depending on CPU load.
+ This function may be called from the callback function.
+*/
+DLL_API double Pa_GetCPULoad(  PortAudioStream* stream)
+{
+    internalPortAudioStream   *past;
+    if( stream == NULL ) return (double) paBadStreamPtr;
+    past = (internalPortAudioStream *) stream;
+    return past->past_Usage;
+}
+
+/*************************************************************
+** Calculate 2 LSB dither signal with a triangular distribution.
+** Ranged properly for adding to a 32 bit integer prior to >>15.
+*/
+#define DITHER_BITS   (15)
+#define DITHER_SCALE  (1.0f / ((1<<DITHER_BITS)-1))
+static long Pa_TriangularDither( void )
+{
+    static unsigned long previous = 0;
+    static unsigned long randSeed1 = 22222;
+    static unsigned long randSeed2 = 5555555;
+    long current, highPass;
+    /* Generate two random numbers. */
+    randSeed1 = (randSeed1 * 196314165) + 907633515;
+    randSeed2 = (randSeed2 * 196314165) + 907633515;
+    /* Generate triangular distribution about 0. */
+    current = (((long)randSeed1)>>(32-DITHER_BITS)) + (((long)randSeed2)>>(32-DITHER_BITS));
+    /* High pass filter to reduce audibility. */
+    highPass = current - previous;
+    previous = current;
+    return highPass;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Int16, call user code, then convert output
+** to Int16 format for native use.
+** Assumes host native format is paInt16.
+** Returns result from user callback.
+*/
+long Pa_CallConvertInt16( internalPortAudioStream   *past,
+                          short *nativeInputBuffer,
+                          short *nativeOutputBuffer )
+{
+    long              temp;
+    long              bytesEmpty = 0;
+    long              bytesFilled = 0;
+    int               userResult;
+    unsigned int      i;
+    void             *inputBuffer = NULL;
+    void             *outputBuffer = NULL;
+
+#if SUPPORT_AUDIO_CAPTURE
+    /* Get native data from DirectSound. */
+    if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+    {
+        /* Convert from native format to PA format. */
+        unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumInputChannels;
+        switch(past->past_InputSampleFormat)
+        {
+
+        case paFloat32:
+            {
+                float *inBufPtr = (float *) past->past_InputBuffer;
+                inputBuffer = past->past_InputBuffer;
+                for( i=0; i<samplesPerBuffer; i++ )
+                {
+                    inBufPtr[i] = nativeInputBuffer[i] * (1.0f / 32767.0f);
+                }
+                break;
+            }
+
+        case paInt32:
+            {
+                /* Convert 16 bit data to 32 bit integers */
+                int *inBufPtr = (int *) past->past_InputBuffer;
+                inputBuffer = past->past_InputBuffer;
+                for( i=0; i<samplesPerBuffer; i++ )
+                {
+                    inBufPtr[i] = nativeInputBuffer[i] << 16;
+                }
+                break;
+            }
+
+        case paInt16:
+            {
+                /* Already in correct format so don't copy. */
+                inputBuffer = nativeInputBuffer;
+                break;
+            }
+
+        case paInt8:
+            {
+                /* Convert 16 bit data to 8 bit chars */
+                char *inBufPtr = (char *) past->past_InputBuffer;
+                inputBuffer = past->past_InputBuffer;
+                if( past->past_Flags & paDitherOff )
+                {
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        inBufPtr[i] = (char)(nativeInputBuffer[i] >> 8);
+                    }
+                }
+                else
+                {
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        temp = nativeInputBuffer[i];
+                        temp += Pa_TriangularDither() >> 7;
+                        temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+                        inBufPtr[i] = (char)(temp >> 8);
+                    }
+                }
+                break;
+            }
+
+        case paUInt8:
+            {
+                /* Convert 16 bit data to 8 bit unsigned chars */
+                unsigned char *inBufPtr = (unsigned char *) past->past_InputBuffer;
+                inputBuffer = past->past_InputBuffer;
+                if( past->past_Flags & paDitherOff )
+                {
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        inBufPtr[i] = ((unsigned char)(nativeInputBuffer[i] >> 8)) + 0x80;
+                    }
+                }
+                else
+                {
+                    /* If you dither then you have to clip because dithering could push the signal out of range! */
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        temp = nativeInputBuffer[i];
+                        temp += Pa_TriangularDither() >> 7;
+                        temp = ((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+                        inBufPtr[i] = (unsigned char)(temp + 0x80);
+                    }
+                }
+                break;
+            }
+
+        default:
+            break;
+        }
+    }
+#endif /* SUPPORT_AUDIO_CAPTURE */
+
+    /* Are we doing output time? */
+    if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+    {
+        /* May already be in native format so just write directly to native buffer. */
+        outputBuffer = (past->past_OutputSampleFormat == paInt16) ?
+                       nativeOutputBuffer : past->past_OutputBuffer;
+    }
+    /*
+     AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+     AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+    */
+    /* Call user callback routine. */
+    userResult = past->past_Callback(
+                     inputBuffer,
+                     outputBuffer,
+                     past->past_FramesPerUserBuffer,
+                     past->past_FrameCount,
+                     past->past_UserData );
+
+    past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+    /* Convert to native format if necessary. */
+    if( outputBuffer != NULL )
+    {
+        unsigned int samplesPerBuffer = past->past_FramesPerUserBuffer * past->past_NumOutputChannels;
+        switch(past->past_OutputSampleFormat)
+        {
+        case paFloat32:
+            {
+                float *outBufPtr = (float *) past->past_OutputBuffer;
+                if( past->past_Flags & paDitherOff )
+                {
+                    if( past->past_Flags & paClipOff ) /* NOTHING */
+                    {
+                        for( i=0; i<samplesPerBuffer; i++ )
+                        {
+                            *nativeOutputBuffer++ = (short) (outBufPtr[i] * (32767.0f));
+                        }
+                    }
+                    else /* CLIP */
+                    {
+                        for( i=0; i<samplesPerBuffer; i++ )
+                        {
+                            temp = (long)(outBufPtr[i] * 32767.0f);
+                            *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+                        }
+                    }
+                }
+                else
+                {
+                    /* If you dither then you have to clip because dithering could push the signal out of range! */
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        float dither  = Pa_TriangularDither()*DITHER_SCALE;
+                        float dithered = (outBufPtr[i] * (32767.0f)) + dither;
+                        temp = (long) (dithered);
+                        *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+                    }
+                }
+                break;
+            }
+
+        case paInt32:
+            {
+                int *outBufPtr = (int *) past->past_OutputBuffer;
+                if( past->past_Flags & paDitherOff )
+                {
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        *nativeOutputBuffer++ = (short) (outBufPtr[i] >> 16 );
+                    }
+                }
+                else
+                {
+                    for( i=0; i<samplesPerBuffer; i++ )
+                    {
+                        /* Shift one bit down before dithering so that we have room for overflow from add. */
+                        temp = (outBufPtr[i] >> 1) + Pa_TriangularDither();
+                        temp = temp >> 15;
+                        *nativeOutputBuffer++ = (short)((temp < -0x8000) ? -0x8000 : ((temp > 0x7FFF) ? 0x7FFF : temp));
+                    }
+                }
+                break;
+            }
+
+        case paInt8:
+            {
+                char *outBufPtr = (char *) past->past_OutputBuffer;
+                for( i=0; i<samplesPerBuffer; i++ )
+                {
+                    *nativeOutputBuffer++ = ((short)outBufPtr[i]) << 8;
+                }
+                break;
+            }
+
+        case paUInt8:
+            {
+                unsigned char *outBufPtr = (unsigned char *) past->past_OutputBuffer;
+                for( i=0; i<samplesPerBuffer; i++ )
+                {
+                    *nativeOutputBuffer++ = ((short)(outBufPtr[i] - 0x80)) << 8;
+                }
+                break;
+            }
+
+        default:
+            break;
+        }
+
+    }
+
+    return userResult;
+}
+
+/*************************************************************************
+** Called by host code.
+** Convert input from Float32, call user code, then convert output
+** to Float32 format for native use.
+** Assumes host native format is Float32.
+** Returns result from user callback.
+** FIXME - Unimplemented for formats other than paFloat32!!!!
+*/
+long Pa_CallConvertFloat32( internalPortAudioStream   *past,
+                            float *nativeInputBuffer,
+                            float *nativeOutputBuffer )
+{
+    long              bytesEmpty = 0;
+    long              bytesFilled = 0;
+    int               userResult;
+    void             *inputBuffer = NULL;
+    void             *outputBuffer = NULL;
+
+    /* Get native data from DirectSound. */
+    if( (past->past_NumInputChannels > 0) && (nativeInputBuffer != NULL) )
+    {
+        inputBuffer = nativeInputBuffer;  // FIXME
+    }
+
+    /* Are we doing output time? */
+    if( (past->past_NumOutputChannels > 0) && (nativeOutputBuffer != NULL) )
+    {
+        /* May already be in native format so just write directly to native buffer. */
+        outputBuffer = (past->past_OutputSampleFormat == paFloat32) ?
+                       nativeOutputBuffer : past->past_OutputBuffer;
+    }
+    /*
+     AddTraceMessage("Pa_CallConvertInt16: inputBuffer = ", (int) inputBuffer );
+     AddTraceMessage("Pa_CallConvertInt16: outputBuffer = ", (int) outputBuffer );
+    */
+    /* Call user callback routine. */
+    userResult = past->past_Callback(
+                     inputBuffer,
+                     outputBuffer,
+                     past->past_FramesPerUserBuffer,
+                     past->past_FrameCount,
+                     past->past_UserData );
+
+    past->past_FrameCount += (PaTimestamp) past->past_FramesPerUserBuffer;
+
+    /* Convert to native format if necessary. */ // FIXME
+    return userResult;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_Initialize( void )
+{
+    if( gInitCount++ > 0 ) return paNoError;
+    ResetTraceMessages();
+    return PaHost_Init();
+}
+
+DLL_API PaError Pa_Terminate( void )
+{
+    PaError result = paNoError;
+
+    if( gInitCount == 0 ) return paNoError;
+    else if( --gInitCount == 0 )
+    {
+        result = PaHost_Term();
+        DumpTraceMessages();
+    }
+    return result;
+}
+
+/*************************************************************************/
+DLL_API PaError Pa_GetSampleSize( PaSampleFormat format )
+{
+    int size;
+    switch(format )
+    {
+
+    case paUInt8:
+    case paInt8:
+        size = 1;
+        break;
+
+    case paInt16:
+        size = 2;
+        break;
+
+    case paPackedInt24:
+        size = 3;
+        break;
+
+    case paFloat32:
+    case paInt32:
+    case paInt24:
+        size = 4;
+        break;
+
+    default:
+        size = paSampleFormatNotSupported;
+        break;
+    }
+    return (PaError) size;
+}
+
+
Index: pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_mac_core.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_mac_core.c	(revision 339)
+++ pjproject/trunk/pjmedia/src/pjmedia/portaudio/pa_mac_core.c	(revision 339)
@@ -0,0 +1,896 @@
+/*
+ * $Id$
+ * pa_mac_core.c
+ * Implementation of PortAudio for Mac OS X CoreAudio       
+ *                                                                                         
+ * PortAudio Portable Real-Time Audio Library
+ * Latest Version at: http://www.portaudio.com
+ *
+ * Authors: Ross Bencina and Phil Burk
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <CoreAudio/CoreAudio.h>
+#include <AudioToolbox/AudioToolbox.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+#include "portaudio.h"
+#include "pa_trace.h"
+#include "pa_util.h"
+#include "pa_allocation.h"
+#include "pa_hostapi.h"
+#include "pa_stream.h"
+#include "pa_cpuload.h"
+#include "pa_process.h"
+
+// =====  constants  =====
+
+// =====  structs  =====
+#pragma mark structs
+
+// PaMacCoreHostApiRepresentation - host api datastructure specific to this implementation
+typedef struct PaMacCore_HAR
+{
+    PaUtilHostApiRepresentation inheritedHostApiRep;
+    PaUtilStreamInterface callbackStreamInterface;
+    PaUtilStreamInterface blockingStreamInterface;
+    
+    PaUtilAllocationGroup *allocations;
+    AudioDeviceID *macCoreDeviceIds;
+}
+PaMacCoreHostApiRepresentation;
+
+typedef struct PaMacCore_DI
+{
+    PaDeviceInfo inheritedDeviceInfo;
+}
+PaMacCoreDeviceInfo;
+
+// PaMacCoreStream - a stream data structure specifically for this implementation
+typedef struct PaMacCore_S
+{
+    PaUtilStreamRepresentation streamRepresentation;
+    PaUtilCpuLoadMeasurer cpuLoadMeasurer;
+    PaUtilBufferProcessor bufferProcessor;
+    
+    int primeStreamUsingCallback;
+    
+    AudioDeviceID inputDevice;
+    AudioDeviceID outputDevice;
+    
+    // Processing thread management --------------
+//    HANDLE abortEvent;
+//    HANDLE processingThread;
+//    DWORD processingThreadId;
+    
+    char throttleProcessingThreadOnOverload; // 0 -> don't throtte, non-0 -> throttle
+    int processingThreadPriority;
+    int highThreadPriority;
+    int throttledThreadPriority;
+    unsigned long throttledSleepMsecs;
+    
+    int isStopped;
+    volatile int isActive;
+    volatile int stopProcessing; // stop thread once existing buffers have been returned
+    volatile int abortProcessing; // stop thread immediately
+    
+//    DWORD allBuffersDurationMs; // used to calculate timeouts
+}
+PaMacCoreStream;
+
+// Data needed by the CoreAudio callback functions
+typedef struct PaMacCore_CD
+{
+    PaMacCoreStream *stream;
+    PaStreamCallback *callback;
+    void *userData;
+    PaUtilConverter *inputConverter;
+    PaUtilConverter *outputConverter;
+    void *inputBuffer;
+    void *outputBuffer;
+    int inputChannelCount;
+    int outputChannelCount;
+    PaSampleFormat inputSampleFormat;
+    PaSampleFormat outputSampleFormat;
+    PaUtilTriangularDitherGenerator *ditherGenerator;
+}
+PaMacClientData;
+
+// =====  CoreAudio-PortAudio bridge functions =====
+#pragma mark CoreAudio-PortAudio bridge functions
+
+// Maps CoreAudio OSStatus codes to PortAudio PaError codes
+static PaError conv_err(OSStatus error)
+{
+    PaError result;
+    
+    switch (error) {
+        case kAudioHardwareNoError:
+            result = paNoError; break;
+        case kAudioHardwareNotRunningError:
+            result = paInternalError; break;
+        case kAudioHardwareUnspecifiedError:
+            result = paInternalError; break;
+        case kAudioHardwareUnknownPropertyError:
+            result = paInternalError; break;
+        case kAudioHardwareBadPropertySizeError:
+            result = paInternalError; break;
+        case kAudioHardwareIllegalOperationError:
+            result = paInternalError; break;
+        case kAudioHardwareBadDeviceError:
+            result = paInvalidDevice; break;
+        case kAudioHardwareBadStreamError:
+            result = paBadStreamPtr; break;
+        case kAudioHardwareUnsupportedOperationError:
+            result = paInternalError; break;
+        case kAudioDeviceUnsupportedFormatError:
+            result = paSampleFormatNotSupported; break;
+        case kAudioDevicePermissionsError:
+            result = paDeviceUnavailable; break;
+        default:
+            result = paInternalError;
+    }
+    
+    return result;
+}
+
+static AudioStreamBasicDescription *InitializeStreamDescription(const PaStreamParameters *parameters, double sampleRate)
+{
+    struct AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(sizeof(AudioStreamBasicDescription));
+    streamDescription->mSampleRate = sampleRate;
+    streamDescription->mFormatID = kAudioFormatLinearPCM;
+    streamDescription->mFormatFlags = 0;
+    streamDescription->mFramesPerPacket = 1;
+    
+    if (parameters->sampleFormat & paNonInterleaved) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsNonInterleaved;
+        streamDescription->mChannelsPerFrame = 1;
+        streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat);
+        streamDescription->mBytesPerPacket = Pa_GetSampleSize(parameters->sampleFormat);
+    }
+    else {
+        streamDescription->mChannelsPerFrame = parameters->channelCount;
+    }
+    
+    streamDescription->mBytesPerFrame = Pa_GetSampleSize(parameters->sampleFormat) * streamDescription->mChannelsPerFrame;
+    streamDescription->mBytesPerPacket = streamDescription->mBytesPerFrame * streamDescription->mFramesPerPacket;
+    
+    if (parameters->sampleFormat & paFloat32) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsFloat;
+        streamDescription->mBitsPerChannel = 32;
+    }
+    else if (parameters->sampleFormat & paInt32) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+        streamDescription->mBitsPerChannel = 32;
+    }
+    else if (parameters->sampleFormat & paInt24) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+        streamDescription->mBitsPerChannel = 24;
+    }
+    else if (parameters->sampleFormat & paInt16) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+        streamDescription->mBitsPerChannel = 16;
+    }
+    else if (parameters->sampleFormat & paInt8) {
+        streamDescription->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
+        streamDescription->mBitsPerChannel = 8;
+    }    
+    else if (parameters->sampleFormat & paInt32) {
+        streamDescription->mBitsPerChannel = 8;
+    }
+    
+    return streamDescription;
+}
+
+static PaStreamCallbackTimeInfo *InitializeTimeInfo(const AudioTimeStamp* now, const AudioTimeStamp* inputTime, const AudioTimeStamp* outputTime)
+{
+    PaStreamCallbackTimeInfo *timeInfo = PaUtil_AllocateMemory(sizeof(PaStreamCallbackTimeInfo));
+    
+    timeInfo->inputBufferAdcTime = inputTime->mSampleTime;
+    timeInfo->currentTime = now->mSampleTime;
+    timeInfo->outputBufferDacTime = outputTime->mSampleTime;
+    
+    return timeInfo;
+}
+
+// =====  support functions  =====
+#pragma mark support functions
+
+static void CleanUp(PaMacCoreHostApiRepresentation *macCoreHostApi)
+{
+    if( macCoreHostApi->allocations )
+    {
+        PaUtil_FreeAllAllocations( macCoreHostApi->allocations );
+        PaUtil_DestroyAllocationGroup( macCoreHostApi->allocations );
+    }
+    
+    PaUtil_FreeMemory( macCoreHostApi );    
+}
+
+static PaError GetChannelInfo(PaDeviceInfo *deviceInfo, AudioDeviceID macCoreDeviceId, int isInput)
+{
+    UInt32 propSize;
+    PaError err = paNoError;
+    UInt32 i;
+    int numChannels = 0;
+    AudioBufferList *buflist;
+
+    err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, NULL));
+    buflist = PaUtil_AllocateMemory(propSize);
+    err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamConfiguration, &propSize, buflist));
+    if (!err) {
+        for (i = 0; i < buflist->mNumberBuffers; ++i) {
+            numChannels += buflist->mBuffers[i].mNumberChannels;
+        }
+		
+		if (isInput)
+			deviceInfo->maxInputChannels = numChannels;
+		else
+			deviceInfo->maxOutputChannels = numChannels;
+		
+        int frameLatency;
+        propSize = sizeof(UInt32);
+        err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyLatency, &propSize, &frameLatency));
+        if (!err) {
+            double secondLatency = frameLatency / deviceInfo->defaultSampleRate;
+            if (isInput) {
+                deviceInfo->defaultLowInputLatency = secondLatency;
+                deviceInfo->defaultHighInputLatency = secondLatency;
+            }
+            else {
+                deviceInfo->defaultLowOutputLatency = secondLatency;
+                deviceInfo->defaultHighOutputLatency = secondLatency;
+            }
+        }
+    }
+    PaUtil_FreeMemory(buflist);
+    
+    return err;
+}
+
+static PaError InitializeDeviceInfo(PaMacCoreDeviceInfo *macCoreDeviceInfo,  AudioDeviceID macCoreDeviceId, PaHostApiIndex hostApiIndex )
+{
+    PaDeviceInfo *deviceInfo = &macCoreDeviceInfo->inheritedDeviceInfo;
+    deviceInfo->structVersion = 2;
+    deviceInfo->hostApi = hostApiIndex;
+    
+    PaError err = paNoError;
+    UInt32 propSize;
+
+    err = conv_err(AudioDeviceGetPropertyInfo(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, NULL));
+    // FIXME: this allocation should be part of the allocations group
+    char *name = PaUtil_AllocateMemory(propSize);
+    err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyDeviceName, &propSize, name));
+    if (!err) {
+        deviceInfo->name = name;
+    }
+    
+    Float64 sampleRate;
+    propSize = sizeof(Float64);
+    err = conv_err(AudioDeviceGetProperty(macCoreDeviceId, 0, 0, kAudioDevicePropertyNominalSampleRate, &propSize, &sampleRate));
+    if (!err) {
+        deviceInfo->defaultSampleRate = sampleRate;
+    }
+
+
+    // Get channel info
+    err = GetChannelInfo(deviceInfo, macCoreDeviceId, 1);
+    err = GetChannelInfo(deviceInfo, macCoreDeviceId, 0);
+
+    return err;
+}
+
+static PaError InitializeDeviceInfos( PaMacCoreHostApiRepresentation *macCoreHostApi, PaHostApiIndex hostApiIndex )
+{
+    PaError result = paNoError;
+    PaUtilHostApiRepresentation *hostApi;
+    PaMacCoreDeviceInfo *deviceInfoArray;
+
+    // initialise device counts and default devices under the assumption that there are no devices. These values are incremented below if and when devices are successfully initialized.
+    hostApi = &macCoreHostApi->inheritedHostApiRep;
+    hostApi->info.deviceCount = 0;
+    hostApi->info.defaultInputDevice = paNoDevice;
+    hostApi->info.defaultOutputDevice = paNoDevice;
+    
+    UInt32 propsize;
+    AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propsize, NULL);
+    int numDevices = propsize / sizeof(AudioDeviceID);
+    hostApi->info.deviceCount = numDevices;
+    if (numDevices > 0) {
+        hostApi->deviceInfos = (PaDeviceInfo**)PaUtil_GroupAllocateMemory(
+                                            macCoreHostApi->allocations, sizeof(PaDeviceInfo*) * numDevices );
+        if( !hostApi->deviceInfos )
+        {
+            return paInsufficientMemory;
+        }
+
+        // allocate all device info structs in a contiguous block
+        deviceInfoArray = (PaMacCoreDeviceInfo*)PaUtil_GroupAllocateMemory(
+                                macCoreHostApi->allocations, sizeof(PaMacCoreDeviceInfo) * numDevices );
+        if( !deviceInfoArray )
+        {
+            return paInsufficientMemory;
+        }
+        
+        macCoreHostApi->macCoreDeviceIds = PaUtil_GroupAllocateMemory(macCoreHostApi->allocations, propsize);
+        AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propsize, macCoreHostApi->macCoreDeviceIds);
+
+        AudioDeviceID defaultInputDevice, defaultOutputDevice;
+        propsize = sizeof(AudioDeviceID);
+        AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &propsize, &defaultInputDevice);
+        AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &propsize, &defaultOutputDevice);
+        
+        UInt32 i;
+        for (i = 0; i < numDevices; ++i) {
+            if (macCoreHostApi->macCoreDeviceIds[i] == defaultInputDevice) {
+                hostApi->info.defaultInputDevice = i;
+            }
+            if (macCoreHostApi->macCoreDeviceIds[i] == defaultOutputDevice) {
+                hostApi->info.defaultOutputDevice = i;
+            }
+            InitializeDeviceInfo(&deviceInfoArray[i], macCoreHostApi->macCoreDeviceIds[i], hostApiIndex);
+            hostApi->deviceInfos[i] = &(deviceInfoArray[i].inheritedDeviceInfo);      
+        }
+    }
+
+    return result;
+}
+
+static OSStatus CheckFormat(AudioDeviceID macCoreDeviceId, const PaStreamParameters *parameters, double sampleRate, int isInput)
+{
+    UInt32 propSize = sizeof(AudioStreamBasicDescription);
+    AudioStreamBasicDescription *streamDescription = PaUtil_AllocateMemory(propSize);
+
+    streamDescription->mSampleRate = sampleRate;
+    streamDescription->mFormatID = 0;
+    streamDescription->mFormatFlags = 0;
+    streamDescription->mBytesPerPacket = 0;
+    streamDescription->mFramesPerPacket = 0;
+    streamDescription->mBytesPerFrame = 0;
+    streamDescription->mChannelsPerFrame = 0;
+    streamDescription->mBitsPerChannel = 0;
+    streamDescription->mReserved = 0;
+
+    OSStatus result = AudioDeviceGetProperty(macCoreDeviceId, 0, isInput, kAudioDevicePropertyStreamFormatSupported, &propSize, streamDescription);
+    PaUtil_FreeMemory(streamDescription);
+    return result;
+}
+
+static OSStatus CopyInputData(PaMacClientData* destination, const AudioBufferList *source, unsigned long frameCount)
+{
+    int frameSpacing, channelSpacing;
+    if (destination->inputSampleFormat & paNonInterleaved) {
+        frameSpacing = 1;
+        channelSpacing = destination->inputChannelCount;
+    }
+    else {
+        frameSpacing = destination->inputChannelCount;
+        channelSpacing = 1;
+    }
+    
+    AudioBuffer const *inputBuffer = &source->mBuffers[0];
+    void *coreAudioBuffer = inputBuffer->mData;
+    void *portAudioBuffer = destination->inputBuffer;
+    UInt32 i, streamNumber, streamChannel;
+    for (i = streamNumber = streamChannel = 0; i < destination->inputChannelCount; ++i, ++streamChannel) {
+        if (streamChannel >= inputBuffer->mNumberChannels) {
+            ++streamNumber;
+            inputBuffer = &source->mBuffers[streamNumber];
+            coreAudioBuffer = inputBuffer->mData;
+            streamChannel = 0;
+        }
+        destination->inputConverter(portAudioBuffer, frameSpacing, coreAudioBuffer, inputBuffer->mNumberChannels, frameCount, destination->ditherGenerator);
+        coreAudioBuffer += sizeof(Float32);
+        portAudioBuffer += Pa_GetSampleSize(destination->inputSampleFormat) * channelSpacing;
+    }
+}
+
+static OSStatus CopyOutputData(AudioBufferList* destination, PaMacClientData *source, unsigned long frameCount)
+{
+    int frameSpacing, channelSpacing;
+    if (source->outputSampleFormat & paNonInterleaved) {
+        frameSpacing = 1;
+        channelSpacing = source->outputChannelCount;
+    }
+    else {
+        frameSpacing = source->outputChannelCount;
+        channelSpacing = 1;
+    }
+    
+    AudioBuffer *outputBuffer = &destination->mBuffers[0];
+    void *coreAudioBuffer = outputBuffer->mData;
+    void *portAudioBuffer = source->outputBuffer;
+    UInt32 i, streamNumber, streamChannel;
+    for (i = streamNumber = streamChannel = 0; i < source->outputChannelCount; ++i, ++streamChannel) {
+        if (streamChannel >= outputBuffer->mNumberChannels) {
+            ++streamNumber;
+            outputBuffer = &destination->mBuffers[streamNumber];
+            coreAudioBuffer = outputBuffer->mData;
+            streamChannel = 0;
+        }
+        source->outputConverter(coreAudioBuffer, outputBuffer->mNumberChannels, portAudioBuffer, frameSpacing, frameCount, NULL);
+        coreAudioBuffer += sizeof(Float32);
+        portAudioBuffer += Pa_GetSampleSize(source->outputSampleFormat) * channelSpacing;
+    }    
+}
+
+static OSStatus AudioIOProc( AudioDeviceID inDevice,
+                      const AudioTimeStamp* inNow,
+                      const AudioBufferList* inInputData,
+                      const AudioTimeStamp* inInputTime,
+                      AudioBufferList* outOutputData, 
+                      const AudioTimeStamp* inOutputTime,
+                      void* inClientData)
+{
+    PaMacClientData *clientData = (PaMacClientData *)inClientData;
+    PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
+    
+    PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
+    
+    AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
+    unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
+
+    if (clientData->inputBuffer) {
+        CopyInputData(clientData, inInputData, frameCount);
+    }
+    PaStreamCallbackResult result = clientData->callback(clientData->inputBuffer, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
+    if (clientData->outputBuffer) {
+        CopyOutputData(outOutputData, clientData, frameCount);
+    }
+
+    PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
+    
+    if (result == paComplete || result == paAbort) {
+        Pa_StopStream(clientData->stream);
+    }
+}
+
+// This is not for input-only streams, this is for streams where the input device is different from the output device
+// TODO: This needs to store the output data in a buffer, to be written to the device the next time AudioOutputProc is called
+static OSStatus AudioInputProc( AudioDeviceID inDevice,
+                         const AudioTimeStamp* inNow,
+                         const AudioBufferList* inInputData,
+                         const AudioTimeStamp* inInputTime,
+                         AudioBufferList* outOutputData, 
+                         const AudioTimeStamp* inOutputTime,
+                         void* inClientData)
+{
+    PaMacClientData *clientData = (PaMacClientData *)inClientData;
+    PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
+
+    PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
+
+    AudioBuffer const *inputBuffer = &inInputData->mBuffers[0];
+    unsigned long frameCount = inputBuffer->mDataByteSize / (inputBuffer->mNumberChannels * sizeof(Float32));
+
+    CopyInputData(clientData, inInputData, frameCount);
+    clientData->callback(clientData->inputBuffer, NULL, frameCount, timeInfo, paNoFlag, clientData->userData);
+    
+    PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
+}
+
+// This is not for output-only streams, this is for streams where the input device is different from the output device
+static OSStatus AudioOutputProc( AudioDeviceID inDevice,
+                          const AudioTimeStamp* inNow,
+                          const AudioBufferList* inInputData,
+                          const AudioTimeStamp* inInputTime,
+                          AudioBufferList* outOutputData, 
+                          const AudioTimeStamp* inOutputTime,
+                          void* inClientData)
+{
+    PaMacClientData *clientData = (PaMacClientData *)inClientData;
+    PaStreamCallbackTimeInfo *timeInfo = InitializeTimeInfo(inNow, inInputTime, inOutputTime);
+
+    PaUtil_BeginCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer );
+
+    AudioBuffer *outputBuffer = &outOutputData->mBuffers[0];
+    unsigned long frameCount = outputBuffer->mDataByteSize / (outputBuffer->mNumberChannels * sizeof(Float32));
+
+    clientData->callback(NULL, clientData->outputBuffer, frameCount, timeInfo, paNoFlag, clientData->userData);
+
+    CopyOutputData(outOutputData, clientData, frameCount);
+
+    PaUtil_EndCpuLoadMeasurement( &clientData->stream->cpuLoadMeasurer, frameCount );
+}
+
+static PaError SetSampleRate(AudioDeviceID device, double sampleRate, int isInput)
+{
+    PaError result = paNoError;
+    
+    double actualSampleRate;
+    UInt32 propSize = sizeof(double);
+    result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyNominalSampleRate, propSize, &sampleRate));
+    
+    result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyNominalSampleRate, &propSize, &actualSampleRate));
+    
+    if (result == paNoError && actualSampleRate != sampleRate) {
+        result = paInvalidSampleRate;
+    }
+    
+    return result;    
+}
+
+static PaError SetFramesPerBuffer(AudioDeviceID device, unsigned long framesPerBuffer, int isInput)
+{
+    PaError result = paNoError;
+    UInt32 preferredFramesPerBuffer = framesPerBuffer;
+    //    while (preferredFramesPerBuffer > UINT32_MAX) {
+    //        preferredFramesPerBuffer /= 2;
+    //    }
+    
+    UInt32 actualFramesPerBuffer;
+    UInt32 propSize = sizeof(UInt32);
+    result = conv_err(AudioDeviceSetProperty(device, NULL, 0, isInput, kAudioDevicePropertyBufferFrameSize, propSize, &preferredFramesPerBuffer));
+    
+    result = conv_err(AudioDeviceGetProperty(device, 0, isInput, kAudioDevicePropertyBufferFrameSize, &propSize, &actualFramesPerBuffer));
+    
+    if (result != paNoError) {
+        // do nothing
+    }
+    else if (actualFramesPerBuffer > framesPerBuffer) {
+        result = paBufferTooSmall;
+    }
+    else if (actualFramesPerBuffer < framesPerBuffer) {
+        result = paBufferTooBig;
+    }
+    
+    return result;    
+}
+    
+static PaError SetUpUnidirectionalStream(AudioDeviceID device, double sampleRate, unsigned long framesPerBuffer, int isInput)
+{
+    PaError err = paNoError;
+    err = SetSampleRate(device, sampleRate, isInput);
+    if( err == paNoError )
+        err = SetFramesPerBuffer(device, framesPerBuffer, isInput);
+    return err;
+}
+
+// =====  PortAudio functions  =====
+#pragma mark PortAudio functions
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+    
+    PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex index );
+    
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+static void Terminate( struct PaUtilHostApiRepresentation *hostApi )
+{
+    PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
+    
+    CleanUp(macCoreHostApi);
+}
+
+static PaError IsFormatSupported( struct PaUtilHostApiRepresentation *hostApi,
+                                  const PaStreamParameters *inputParameters,
+                                  const PaStreamParameters *outputParameters,
+                                  double sampleRate )
+{
+    PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation*)hostApi;
+    PaDeviceInfo *deviceInfo;
+    
+    PaError result = paNoError;
+    if (inputParameters) {
+        deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[inputParameters->device];
+        if (inputParameters->channelCount > deviceInfo->maxInputChannels)
+            result = paInvalidChannelCount;
+        else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[inputParameters->device], inputParameters, sampleRate, 1) != kAudioHardwareNoError) {
+            result = paInvalidSampleRate;
+        }
+    }
+    if (outputParameters && result == paNoError) {
+        deviceInfo = macCoreHostApi->inheritedHostApiRep.deviceInfos[outputParameters->device];
+        if (outputParameters->channelCount > deviceInfo->maxOutputChannels)
+            result = paInvalidChannelCount;
+        else if (CheckFormat(macCoreHostApi->macCoreDeviceIds[outputParameters->device], outputParameters, sampleRate, 0) != kAudioHardwareNoError) {
+            result = paInvalidSampleRate;
+        }
+    }
+
+    return result;
+}
+
+static PaError OpenStream( struct PaUtilHostApiRepresentation *hostApi,
+                           PaStream** s,
+                           const PaStreamParameters *inputParameters,
+                           const PaStreamParameters *outputParameters,
+                           double sampleRate,
+                           unsigned long framesPerBuffer,
+                           PaStreamFlags streamFlags,
+                           PaStreamCallback *streamCallback,
+                           void *userData )
+{
+    PaError err = paNoError;
+    PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)hostApi;
+    PaMacCoreStream *stream = PaUtil_AllocateMemory(sizeof(PaMacCoreStream));
+    stream->isActive = 0;
+    stream->isStopped = 1;
+    stream->inputDevice = kAudioDeviceUnknown;
+    stream->outputDevice = kAudioDeviceUnknown;
+    
+    PaUtil_InitializeStreamRepresentation( &stream->streamRepresentation,
+                                           ( (streamCallback)
+                                             ? &macCoreHostApi->callbackStreamInterface
+                                             : &macCoreHostApi->blockingStreamInterface ),
+                                           streamCallback, userData );
+    PaUtil_InitializeCpuLoadMeasurer( &stream->cpuLoadMeasurer, sampleRate );
+    
+    *s = (PaStream*)stream;
+    PaMacClientData *clientData = PaUtil_AllocateMemory(sizeof(PaMacClientData));
+    clientData->stream = stream;
+    clientData->callback = streamCallback;
+    clientData->userData = userData;
+    clientData->inputBuffer = 0;
+    clientData->outputBuffer = 0;
+    clientData->ditherGenerator = PaUtil_AllocateMemory(sizeof(PaUtilTriangularDitherGenerator));
+    PaUtil_InitializeTriangularDitherState(clientData->ditherGenerator);
+    
+    if (inputParameters != NULL) {
+        stream->inputDevice = macCoreHostApi->macCoreDeviceIds[inputParameters->device];
+        clientData->inputConverter = PaUtil_SelectConverter(paFloat32, inputParameters->sampleFormat, streamFlags);
+        clientData->inputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(inputParameters->sampleFormat) * framesPerBuffer * inputParameters->channelCount);
+        clientData->inputChannelCount = inputParameters->channelCount;
+        clientData->inputSampleFormat = inputParameters->sampleFormat;
+        err = SetUpUnidirectionalStream(stream->inputDevice, sampleRate, framesPerBuffer, 1);
+    }
+    
+    if (err == paNoError && outputParameters != NULL) {
+        stream->outputDevice = macCoreHostApi->macCoreDeviceIds[outputParameters->device];
+        clientData->outputConverter = PaUtil_SelectConverter(outputParameters->sampleFormat, paFloat32, streamFlags);
+        clientData->outputBuffer = PaUtil_AllocateMemory(Pa_GetSampleSize(outputParameters->sampleFormat) * framesPerBuffer * outputParameters->channelCount);
+        clientData->outputChannelCount = outputParameters->channelCount;
+        clientData->outputSampleFormat = outputParameters->sampleFormat;
+        err = SetUpUnidirectionalStream(stream->outputDevice, sampleRate, framesPerBuffer, 0);
+    }
+
+    if (inputParameters == NULL || outputParameters == NULL || stream->inputDevice == stream->outputDevice) {
+        AudioDeviceID device = (inputParameters == NULL) ? stream->outputDevice : stream->inputDevice;
+
+        AudioDeviceAddIOProc(device, AudioIOProc, clientData);
+    }
+    else {
+        // using different devices for input and output
+        AudioDeviceAddIOProc(stream->inputDevice, AudioInputProc, clientData);
+        AudioDeviceAddIOProc(stream->outputDevice, AudioOutputProc, clientData);
+    }
+    
+    return err;
+}
+
+// Note: When CloseStream() is called, the multi-api layer ensures that the stream has already been stopped or aborted.
+static PaError CloseStream( PaStream* s )
+{
+    PaError err = paNoError;
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+
+    PaUtil_ResetCpuLoadMeasurer( &stream->cpuLoadMeasurer );
+
+    if (stream->inputDevice != kAudioDeviceUnknown) {
+        if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
+            err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioIOProc));
+        }
+        else {
+            err = conv_err(AudioDeviceRemoveIOProc(stream->inputDevice, AudioInputProc));
+            err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioOutputProc));
+        }
+    }
+    else {
+        err = conv_err(AudioDeviceRemoveIOProc(stream->outputDevice, AudioIOProc));
+    }
+    
+    return err;
+}
+
+
+static PaError StartStream( PaStream *s )
+{
+    PaError err = paNoError;
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+
+    if (stream->inputDevice != kAudioDeviceUnknown) {
+        if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
+            err = conv_err(AudioDeviceStart(stream->inputDevice, AudioIOProc));
+        }
+        else {
+            err = conv_err(AudioDeviceStart(stream->inputDevice, AudioInputProc));
+            err = conv_err(AudioDeviceStart(stream->outputDevice, AudioOutputProc));
+        }
+    }
+    else {
+        err = conv_err(AudioDeviceStart(stream->outputDevice, AudioIOProc));
+    }
+    
+    stream->isActive = 1;
+    stream->isStopped = 0;
+    return err;
+}
+
+static PaError AbortStream( PaStream *s )
+{
+    PaError err = paNoError;
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+    
+    if (stream->inputDevice != kAudioDeviceUnknown) {
+        if (stream->outputDevice == kAudioDeviceUnknown || stream->outputDevice == stream->inputDevice) {
+            err = conv_err(AudioDeviceStop(stream->inputDevice, AudioIOProc));
+        }
+        else {
+            err = conv_err(AudioDeviceStop(stream->inputDevice, AudioInputProc));
+            err = conv_err(AudioDeviceStop(stream->outputDevice, AudioOutputProc));
+        }
+    }
+    else {
+        err = conv_err(AudioDeviceStop(stream->outputDevice, AudioIOProc));
+    }
+    
+    stream->isActive = 0;
+    stream->isStopped = 1;
+    return err;
+}    
+
+static PaError StopStream( PaStream *s )
+{
+    // TODO: this should be nicer than abort
+    return AbortStream(s);
+}
+
+static PaError IsStreamStopped( PaStream *s )
+{
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+    
+    return stream->isStopped;
+}
+
+
+static PaError IsStreamActive( PaStream *s )
+{
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+
+    return stream->isActive;
+}
+
+
+static PaTime GetStreamTime( PaStream *s )
+{
+    OSStatus err;
+    PaTime result;
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+
+    AudioTimeStamp *timeStamp = PaUtil_AllocateMemory(sizeof(AudioTimeStamp));
+    if (stream->inputDevice != kAudioDeviceUnknown) {
+        err = AudioDeviceGetCurrentTime(stream->inputDevice, timeStamp);
+    }
+    else {
+        err = AudioDeviceGetCurrentTime(stream->outputDevice, timeStamp);
+    }
+    
+    result = err ? 0 : timeStamp->mSampleTime;
+    PaUtil_FreeMemory(timeStamp);
+
+    return result;
+}
+
+
+static double GetStreamCpuLoad( PaStream* s )
+{
+    PaMacCoreStream *stream = (PaMacCoreStream*)s;
+    
+    return PaUtil_GetCpuLoad( &stream->cpuLoadMeasurer );
+}
+
+
+// As separate stream interfaces are used for blocking and callback streams, the following functions can be guaranteed to only be called for blocking streams.
+
+static PaError ReadStream( PaStream* s,
+                           void *buffer,
+                           unsigned long frames )
+{
+    return paInternalError;
+}
+
+
+static PaError WriteStream( PaStream* s,
+                            const void *buffer,
+                            unsigned long frames )
+{
+    return paInternalError;
+}
+
+
+static signed long GetStreamReadAvailable( PaStream* s )
+{
+    return paInternalError;
+}
+
+
+static signed long GetStreamWriteAvailable( PaStream* s )
+{
+    return paInternalError;
+}
+
+// HostAPI-specific initialization function
+PaError PaMacCore_Initialize( PaUtilHostApiRepresentation **hostApi, PaHostApiIndex hostApiIndex )
+{
+    PaError result = paNoError;
+    PaMacCoreHostApiRepresentation *macCoreHostApi = (PaMacCoreHostApiRepresentation *)PaUtil_AllocateMemory( sizeof(PaMacCoreHostApiRepresentation) );
+    if( !macCoreHostApi )
+    {
+        result = paInsufficientMemory;
+        goto error;
+    }
+    
+    macCoreHostApi->allocations = PaUtil_CreateAllocationGroup();
+    if( !macCoreHostApi->allocations )
+    {
+        result = paInsufficientMemory;
+        goto error;
+    }
+    
+    *hostApi = &macCoreHostApi->inheritedHostApiRep;
+    (*hostApi)->info.structVersion = 1;
+    (*hostApi)->info.type = paCoreAudio;
+    (*hostApi)->info.name = "CoreAudio";
+
+    result = InitializeDeviceInfos(macCoreHostApi, hostApiIndex);
+    if (result != paNoError) {
+        goto error;
+    }
+    
+    // Set up the proper callbacks to this HostApi's functions
+    (*hostApi)->Terminate = Terminate;
+    (*hostApi)->OpenStream = OpenStream;
+    (*hostApi)->IsFormatSupported = IsFormatSupported;
+    
+    PaUtil_InitializeStreamInterface( &macCoreHostApi->callbackStreamInterface, CloseStream, StartStream,
+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+                                      GetStreamTime, GetStreamCpuLoad,
+                                      PaUtil_DummyRead, PaUtil_DummyWrite,
+                                      PaUtil_DummyGetReadAvailable, PaUtil_DummyGetWriteAvailable );
+    
+    PaUtil_InitializeStreamInterface( &macCoreHostApi->blockingStreamInterface, CloseStream, StartStream,
+                                      StopStream, AbortStream, IsStreamStopped, IsStreamActive,
+                                      GetStreamTime, PaUtil_DummyGetCpuLoad,
+                                      ReadStream, WriteStream, GetStreamReadAvailable, GetStreamWriteAvailable );
+    
+    return result;
+    
+error:
+        if( macCoreHostApi ) {
+            CleanUp(macCoreHostApi);
+        }
+    
+    return result;
+}
Index: pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.c	(revision 339)
+++ pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.c	(revision 339)
@@ -0,0 +1,199 @@
+/*
+ * $Id$
+ * ringbuffer.c
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * Initialize FIFO.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+{
+    if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */
+    rbuf->bufferSize = numBytes;
+    rbuf->buffer = (char *)dataPtr;
+    RingBuffer_Flush( rbuf );
+    rbuf->bigMask = (numBytes*2)-1;
+    rbuf->smallMask = (numBytes)-1;
+    return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+{
+    return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
+}
+/***************************************************************************
+** Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
+{
+    return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
+}
+
+/***************************************************************************
+** Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf )
+{
+    rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/***************************************************************************
+** Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+                                 void **dataPtr1, long *sizePtr1,
+                                 void **dataPtr2, long *sizePtr2 )
+{
+    long   index;
+    long   available = RingBuffer_GetWriteAvailable( rbuf );
+    if( numBytes > available ) numBytes = available;
+    /* Check to see if write is not contiguous. */
+    index = rbuf->writeIndex & rbuf->smallMask;
+    if( (index + numBytes) > rbuf->bufferSize )
+    {
+        /* Write data in two blocks that wrap the buffer. */
+        long   firstHalf = rbuf->bufferSize - index;
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = firstHalf;
+        *dataPtr2 = &rbuf->buffer[0];
+        *sizePtr2 = numBytes - firstHalf;
+    }
+    else
+    {
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = numBytes;
+        *dataPtr2 = NULL;
+        *sizePtr2 = 0;
+    }
+    return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
+{
+    return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+                                void **dataPtr1, long *sizePtr1,
+                                void **dataPtr2, long *sizePtr2 )
+{
+    long   index;
+    long   available = RingBuffer_GetReadAvailable( rbuf );
+    if( numBytes > available ) numBytes = available;
+    /* Check to see if read is not contiguous. */
+    index = rbuf->readIndex & rbuf->smallMask;
+    if( (index + numBytes) > rbuf->bufferSize )
+    {
+        /* Write data in two blocks that wrap the buffer. */
+        long firstHalf = rbuf->bufferSize - index;
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = firstHalf;
+        *dataPtr2 = &rbuf->buffer[0];
+        *sizePtr2 = numBytes - firstHalf;
+    }
+    else
+    {
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = numBytes;
+        *dataPtr2 = NULL;
+        *sizePtr2 = 0;
+    }
+    return numBytes;
+}
+/***************************************************************************
+*/
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
+{
+    return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )
+{
+    long size1, size2, numWritten;
+    void *data1, *data2;
+    numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+    if( size2 > 0 )
+    {
+
+        memcpy( data1, data, size1 );
+        data = ((char *)data) + size1;
+        memcpy( data2, data, size2 );
+    }
+    else
+    {
+        memcpy( data1, data, size1 );
+    }
+    RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+    return numWritten;
+}
+
+/***************************************************************************
+** Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
+{
+    long size1, size2, numRead;
+    void *data1, *data2;
+    numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+    if( size2 > 0 )
+    {
+        memcpy( data, data1, size1 );
+        data = ((char *)data) + size1;
+        memcpy( data, data2, size2 );
+    }
+    else
+    {
+        memcpy( data, data1, size1 );
+    }
+    RingBuffer_AdvanceReadIndex( rbuf, numRead );
+    return numRead;
+}
Index: pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.h
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.h	(revision 339)
+++ pjproject/trunk/pjmedia/src/pjmedia/portaudio/ringbuffer.h	(revision 339)
@@ -0,0 +1,101 @@
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id$
+ * ringbuffer.h
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program is distributed with the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+    long   bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
+    long   writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
+    long   readIndex;  /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
+    long   bigMask;    /* Used for wrapping indices with extra bit to distinguish full/empty. */
+    long   smallMask;  /* Used for fitting indices to buffer. */
+    char *buffer;
+}
+RingBuffer;
+/*
+ * Initialize Ring Buffer.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf );
+
+/* Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+/* Return number of bytes available for read. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+/* Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
+/* Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
+
+/* Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+                                 void **dataPtr1, long *sizePtr1,
+                                 void **dataPtr2, long *sizePtr2 );
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
+
+/* Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+                                void **dataPtr1, long *sizePtr1,
+                                void **dataPtr2, long *sizePtr2 );
+
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _RINGBUFFER_H */
