git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@968 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Michael Jerris 2006-03-30 01:37:57 +00:00
parent 0232f398c7
commit df1f3209d9
4 changed files with 696 additions and 696 deletions

View File

@ -1,333 +1,333 @@
/* /*
* $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $
* pablio.c * pablio.c
* Portable Audio Blocking Input/Output utility. * Portable Audio Blocking Input/Output utility.
* *
* Author: Phil Burk, http://www.softsynth.com * Author: Phil Burk, http://www.softsynth.com
* *
* This program uses the PortAudio Portable Audio Library. * This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.audiomulch.com/portaudio/ * For more information see: http://www.audiomulch.com/portaudio/
* Copyright (c) 1999-2000 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 * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*/ */
/* History: /* History:
* PLB021214 - check for valid stream in CloseAudioStream() to prevent hang. * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
* add timeOutMSec to CloseAudioStream() to prevent hang. * add timeOutMSec to CloseAudioStream() to prevent hang.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "portaudio.h" #include "portaudio.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include "pablio.h" #include "pablio.h"
#include <string.h> #include <string.h>
/************************************************************************/ /************************************************************************/
/******** Constants *****************************************************/ /******** Constants *****************************************************/
/************************************************************************/ /************************************************************************/
#define FRAMES_PER_BUFFER (256) #define FRAMES_PER_BUFFER (256)
/************************************************************************/ /************************************************************************/
/******** Prototypes ****************************************************/ /******** Prototypes ****************************************************/
/************************************************************************/ /************************************************************************/
static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
PaTimestamp outTime, void *userData); PaTimestamp outTime, void *userData);
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame); static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame);
static PaError PABLIO_TermFIFO(RingBuffer * rbuf); static PaError PABLIO_TermFIFO(RingBuffer * rbuf);
/************************************************************************/ /************************************************************************/
/******** Functions *****************************************************/ /******** Functions *****************************************************/
/************************************************************************/ /************************************************************************/
/* Called from PortAudio. /* Called from PortAudio.
* Read and write data only if there is room in FIFOs. * Read and write data only if there is room in FIFOs.
*/ */
static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, static int blockingIOCallback(void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer,
PaTimestamp outTime, void *userData) PaTimestamp outTime, void *userData)
{ {
PABLIO_Stream * data = (PABLIO_Stream *) userData; PABLIO_Stream * data = (PABLIO_Stream *) userData;
long numBytes = data->bytesPerFrame * framesPerBuffer; long numBytes = data->bytesPerFrame * framesPerBuffer;
(void) outTime; (void) outTime;
/* This may get called with NULL inputBuffer during initial setup. */ /* This may get called with NULL inputBuffer during initial setup. */
if (inputBuffer != NULL) if (inputBuffer != NULL)
{ {
RingBuffer_Write(&data->inFIFO, inputBuffer, numBytes); RingBuffer_Write(&data->inFIFO, inputBuffer, numBytes);
} }
if (outputBuffer != NULL) if (outputBuffer != NULL)
{ {
int i; int i;
int numRead = RingBuffer_Read(&data->outFIFO, outputBuffer, numBytes); int numRead = RingBuffer_Read(&data->outFIFO, outputBuffer, numBytes);
/* Zero out remainder of buffer if we run out of data. */ /* Zero out remainder of buffer if we run out of data. */
for (i = numRead; i < numBytes; i++) for (i = numRead; i < numBytes; i++)
{ {
((char *) outputBuffer)[i] = 0; ((char *) outputBuffer)[i] = 0;
} } } }
return 0; return 0;
} }
/* Allocate buffer. */ /* Allocate buffer. */
static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame) static PaError PABLIO_InitFIFO(RingBuffer * rbuf, long numFrames, long bytesPerFrame)
{ {
long numBytes = numFrames * bytesPerFrame; long numBytes = numFrames * bytesPerFrame;
char *buffer = (char *) malloc(numBytes); char *buffer = (char *) malloc(numBytes);
if (buffer == NULL) if (buffer == NULL)
return paInsufficientMemory; return paInsufficientMemory;
memset(buffer, 0, numBytes); memset(buffer, 0, numBytes);
return (PaError) RingBuffer_Init(rbuf, numBytes, buffer); return (PaError) RingBuffer_Init(rbuf, numBytes, buffer);
} }
/* Free buffer. */ /* Free buffer. */
static PaError PABLIO_TermFIFO(RingBuffer * rbuf) static PaError PABLIO_TermFIFO(RingBuffer * rbuf)
{ {
if (rbuf->buffer) if (rbuf->buffer)
free(rbuf->buffer); free(rbuf->buffer);
rbuf->buffer = NULL; rbuf->buffer = NULL;
return paNoError; return paNoError;
} }
/************************************************************ /************************************************************
* Write data to ring buffer. * Write data to ring buffer.
* Will not return until all the data has been written. * Will not return until all the data has been written.
*/ */
long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames) long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
{ {
long bytesWritten; long bytesWritten;
char *p = (char *) data; char *p = (char *) data;
long numBytes = aStream->bytesPerFrame * numFrames; long numBytes = aStream->bytesPerFrame * numFrames;
while (numBytes > 0) while (numBytes > 0)
{ {
bytesWritten = RingBuffer_Write(&aStream->outFIFO, p, numBytes); bytesWritten = RingBuffer_Write(&aStream->outFIFO, p, numBytes);
numBytes -= bytesWritten; numBytes -= bytesWritten;
p += bytesWritten; p += bytesWritten;
if (numBytes > 0) if (numBytes > 0)
Pa_Sleep(10); Pa_Sleep(10);
} }
return numFrames; return numFrames;
} }
/************************************************************ /************************************************************
* Read data from ring buffer. * Read data from ring buffer.
* Will not return until all the data has been read. * Will not return until all the data has been read.
*/ */
long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames) long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
{ {
long bytesRead; long bytesRead;
char *p = (char *) data; char *p = (char *) data;
long numBytes = aStream->bytesPerFrame * numFrames; long numBytes = aStream->bytesPerFrame * numFrames;
while (numBytes > 0) while (numBytes > 0)
{ {
bytesRead = RingBuffer_Read(&aStream->inFIFO, p, numBytes); bytesRead = RingBuffer_Read(&aStream->inFIFO, p, numBytes);
numBytes -= bytesRead; numBytes -= bytesRead;
p += bytesRead; p += bytesRead;
if (numBytes > 0) if (numBytes > 0)
Pa_Sleep(10); Pa_Sleep(10);
} }
return numFrames; return numFrames;
} }
/************************************************************
* Return the number of frames that could be written to the stream without
* having to wait.
*/
long GetAudioStreamWriteable(PABLIO_Stream * aStream)
{
int bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
return bytesEmpty / aStream->bytesPerFrame;
}
/************************************************************
/************************************************************ * Return the number of frames that could be written to the stream without
* Return the number of frames that are available to be read from the * having to wait.
* stream without having to wait. */
*/ long GetAudioStreamWriteable(PABLIO_Stream * aStream)
long GetAudioStreamReadable(PABLIO_Stream * aStream)
{ {
int bytesFull = RingBuffer_GetReadAvailable(&aStream->inFIFO); int bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
return bytesFull / aStream->bytesPerFrame; return bytesEmpty / aStream->bytesPerFrame;
} }
/************************************************************/ /************************************************************
static unsigned long RoundUpToNextPowerOf2(unsigned long n) * Return the number of frames that are available to be read from the
* stream without having to wait.
*/
long GetAudioStreamReadable(PABLIO_Stream * aStream)
{ {
long numBits = 0; int bytesFull = RingBuffer_GetReadAvailable(&aStream->inFIFO);
if (((n - 1) & n) == 0) return bytesFull / aStream->bytesPerFrame;
}
/************************************************************/
static unsigned long RoundUpToNextPowerOf2(unsigned long n)
{
long numBits = 0;
if (((n - 1) & n) == 0)
return n; /* Already Power of two. */ return n; /* Already Power of two. */
while (n > 0) while (n > 0)
{ {
n = n >> 1; n = n >> 1;
numBits++; numBits++;
} }
return (1 << numBits); return (1 << numBits);
} }
/************************************************************ /************************************************************
* Opens a PortAudio stream with default characteristics. * Opens a PortAudio stream with default characteristics.
* Allocates PABLIO_Stream structure. * Allocates PABLIO_Stream structure.
* *
* flags parameter can be an ORed combination of: * flags parameter can be an ORed combination of:
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
* and either PABLIO_MONO or PABLIO_STEREO * and either PABLIO_MONO or PABLIO_STEREO
*/ */
PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, double sampleRate, PaSampleFormat format, long flags, int indev, PaError OpenAudioStream(PABLIO_Stream ** rwblPtr, double sampleRate, PaSampleFormat format, long flags, int indev,
int outdev) int outdev)
{ {
long bytesPerSample; long bytesPerSample;
long doRead = 0; long doRead = 0;
long doWrite = 0; long doWrite = 0;
PaError err; PaError err;
PABLIO_Stream * aStream; PABLIO_Stream * aStream;
long minNumBuffers; long minNumBuffers;
long numFrames; long numFrames;
/* Allocate PABLIO_Stream structure for caller. */ /* Allocate PABLIO_Stream structure for caller. */
aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream)); aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
if (aStream == NULL) if (aStream == NULL)
return paInsufficientMemory; return paInsufficientMemory;
memset(aStream, 0, sizeof(PABLIO_Stream)); memset(aStream, 0, sizeof(PABLIO_Stream));
/* Determine size of a sample. */ /* Determine size of a sample. */
bytesPerSample = Pa_GetSampleSize(format); bytesPerSample = Pa_GetSampleSize(format);
if (bytesPerSample < 0) if (bytesPerSample < 0)
{ {
err = (PaError) bytesPerSample; err = (PaError) bytesPerSample;
goto error; goto error;
} }
aStream->samplesPerFrame = ((flags & PABLIO_MONO) != 0) ? 1 : 2; aStream->samplesPerFrame = ((flags & PABLIO_MONO) != 0) ? 1 : 2;
aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame; aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
/* Initialize PortAudio */ /* Initialize PortAudio */
err = Pa_Initialize(); err = Pa_Initialize();
if (err != paNoError) if (err != paNoError)
goto error; goto error;
/* Warning: numFrames must be larger than amount of data processed per interrupt /* Warning: numFrames must be larger than amount of data processed per interrupt
* inside PA to prevent glitches. Just to be safe, adjust size upwards. * inside PA to prevent glitches. Just to be safe, adjust size upwards.
*/ */
minNumBuffers = 2 * Pa_GetMinNumBuffers(FRAMES_PER_BUFFER, sampleRate); minNumBuffers = 2 * Pa_GetMinNumBuffers(FRAMES_PER_BUFFER, sampleRate);
numFrames = minNumBuffers * FRAMES_PER_BUFFER; numFrames = minNumBuffers * FRAMES_PER_BUFFER;
/* The PortAudio callback runs in a high priority thread. But PABLIO /* The PortAudio callback runs in a high priority thread. But PABLIO
* runs in a normal foreground thread. So we may have much worse * runs in a normal foreground thread. So we may have much worse
* latency in PABLIO. So adjust latency to a safe level. * latency in PABLIO. So adjust latency to a safe level.
*/ */
{ {
const int safeLatencyMSec = 200; const int safeLatencyMSec = 200;
int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate); int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);
if (minLatencyMSec < safeLatencyMSec) if (minLatencyMSec < safeLatencyMSec)
{ {
numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000); numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);
} }
} numFrames = RoundUpToNextPowerOf2(numFrames); } numFrames = RoundUpToNextPowerOf2(numFrames);
/* Initialize Ring Buffers */ /* Initialize Ring Buffers */
doRead = ((flags & PABLIO_READ) != 0); doRead = ((flags & PABLIO_READ) != 0);
doWrite = ((flags & PABLIO_WRITE) != 0); doWrite = ((flags & PABLIO_WRITE) != 0);
if (doRead) if (doRead)
{ {
err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame); err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
if (err != paNoError) if (err != paNoError)
goto error; goto error;
} }
if (doWrite) if (doWrite)
{ {
long numBytes; long numBytes;
err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame); err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
if (err != paNoError) if (err != paNoError)
goto error; goto error;
/* Make Write FIFO appear full initially. */ /* Make Write FIFO appear full initially. */
numBytes = RingBuffer_GetWriteAvailable(&aStream->outFIFO); numBytes = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
RingBuffer_AdvanceWriteIndex(&aStream->outFIFO, numBytes); RingBuffer_AdvanceWriteIndex(&aStream->outFIFO, numBytes);
} }
/* Open a PortAudio stream that we will use to communicate with the underlying /* Open a PortAudio stream that we will use to communicate with the underlying
* audio drivers. */ * audio drivers. */
err = Pa_OpenStream( &aStream->stream, err = Pa_OpenStream(&aStream->stream,
(doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice), (doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),
(doRead ? aStream->samplesPerFrame : 0), format, NULL, (doRead ? aStream->samplesPerFrame : 0), format, NULL,
(doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice), (doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),
(doWrite ? aStream->samplesPerFrame : 0), format, NULL, sampleRate, FRAMES_PER_BUFFER, (doWrite ? aStream->samplesPerFrame : 0), format, NULL, sampleRate, FRAMES_PER_BUFFER,
minNumBuffers, paClipOff, minNumBuffers, paClipOff,
/* we won't output out of range samples so don't bother clipping them */ /* we won't output out of range samples so don't bother clipping them */
blockingIOCallback, aStream); blockingIOCallback, aStream);
if (err != paNoError) if (err != paNoError)
goto error; goto error;
err = Pa_StartStream(aStream->stream); err = Pa_StartStream(aStream->stream);
if (err != paNoError) if (err != paNoError)
goto error; goto error;
*rwblPtr = aStream; *rwblPtr = aStream;
return paNoError; return paNoError;
error: CloseAudioStream(aStream); error:CloseAudioStream(aStream);
*rwblPtr = NULL; *rwblPtr = NULL;
return err; return err;
} }
/************************************************************/ /************************************************************/
PaError CloseAudioStream(PABLIO_Stream * aStream) PaError CloseAudioStream(PABLIO_Stream * aStream)
{ {
PaError err = paNoError; PaError err = paNoError;
int bytesEmpty; int bytesEmpty;
int byteSize = aStream->outFIFO.bufferSize; int byteSize = aStream->outFIFO.bufferSize;
if (aStream->stream != NULL) /* Make sure stream was opened. PLB021214 */ if (aStream->stream != NULL) /* Make sure stream was opened. PLB021214 */
{ {
/* If we are writing data, make sure we play everything written. */ /* If we are writing data, make sure we play everything written. */
if (byteSize > 0) if (byteSize > 0)
{ {
int timeOutMSec = 2000; int timeOutMSec = 2000;
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO); bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
while ((bytesEmpty < byteSize) && (timeOutMSec > 0)) while ((bytesEmpty < byteSize) && (timeOutMSec > 0))
{ {
Pa_Sleep(20); Pa_Sleep(20);
timeOutMSec -= 20; timeOutMSec -= 20;
bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO); bytesEmpty = RingBuffer_GetWriteAvailable(&aStream->outFIFO);
} }
} }
err = Pa_StopStream(aStream->stream); err = Pa_StopStream(aStream->stream);
if (err != paNoError) if (err != paNoError)
goto error; goto error;
err = Pa_CloseStream(aStream->stream); err = Pa_CloseStream(aStream->stream);
} }
error: Pa_Terminate(); error:Pa_Terminate();
PABLIO_TermFIFO(&aStream->inFIFO); PABLIO_TermFIFO(&aStream->inFIFO);
PABLIO_TermFIFO(&aStream->outFIFO); PABLIO_TermFIFO(&aStream->outFIFO);
free(aStream); free(aStream);
return err; return err;
} }

View File

@ -1,109 +1,109 @@
#ifndef _PABLIO_H #ifndef _PABLIO_H
#define _PABLIO_H #define _PABLIO_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* /*
* $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
* PABLIO.h * PABLIO.h
* Portable Audio Blocking read/write utility. * Portable Audio Blocking read/write utility.
* *
* Author: Phil Burk, http://www.softsynth.com/portaudio/ * Author: Phil Burk, http://www.softsynth.com/portaudio/
* *
* Include file for PABLIO, the Portable Audio Blocking I/O Library. * Include file for PABLIO, the Portable Audio Blocking I/O Library.
* PABLIO is built on top of PortAudio, the Portable Audio Library. * PABLIO is built on top of PortAudio, the Portable Audio Library.
* For more information see: http://www.audiomulch.com/portaudio/ * For more information see: http://www.audiomulch.com/portaudio/
* Copyright (c) 1999-2000 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 * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "portaudio.h" #include "portaudio.h"
#include "ringbuffer.h" #include "ringbuffer.h"
#include <string.h> #include <string.h>
typedef struct typedef struct
{ {
RingBuffer inFIFO; RingBuffer inFIFO;
RingBuffer outFIFO; RingBuffer outFIFO;
PortAudioStream *stream; PortAudioStream *stream;
int bytesPerFrame; int bytesPerFrame;
int samplesPerFrame; int samplesPerFrame;
} }
PABLIO_Stream; PABLIO_Stream;
/* Values for flags for OpenAudioStream(). */ /* Values for flags for OpenAudioStream(). */
#define PABLIO_READ (1<<0) #define PABLIO_READ (1<<0)
#define PABLIO_WRITE (1<<1) #define PABLIO_WRITE (1<<1)
#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE) #define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
#define PABLIO_MONO (1<<2) #define PABLIO_MONO (1<<2)
#define PABLIO_STEREO (1<<3) #define PABLIO_STEREO (1<<3)
/************************************************************ /************************************************************
* Write data to ring buffer. * Write data to ring buffer.
* Will not return until all the data has been written. * Will not return until all the data has been written.
*/ */
long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
/************************************************************ /************************************************************
* Read data from ring buffer. * Read data from ring buffer.
* Will not return until all the data has been read. * Will not return until all the data has been read.
*/ */
long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames ); long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
/************************************************************ /************************************************************
* Return the number of frames that could be written to the stream without * Return the number of frames that could be written to the stream without
* having to wait. * having to wait.
*/ */
long GetAudioStreamWriteable( PABLIO_Stream *aStream ); long GetAudioStreamWriteable( PABLIO_Stream *aStream );
/************************************************************ /************************************************************
* Return the number of frames that are available to be read from the * Return the number of frames that are available to be read from the
* stream without having to wait. * stream without having to wait.
*/ */
long GetAudioStreamReadable( PABLIO_Stream *aStream ); long GetAudioStreamReadable( PABLIO_Stream *aStream );
/************************************************************ /************************************************************
* Opens a PortAudio stream with default characteristics. * Opens a PortAudio stream with default characteristics.
* Allocates PABLIO_Stream structure. * Allocates PABLIO_Stream structure.
* *
* flags parameter can be an ORed combination of: * flags parameter can be an ORed combination of:
* PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE, * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
* and either PABLIO_MONO or PABLIO_STEREO * and either PABLIO_MONO or PABLIO_STEREO
*/ */
PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate, PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
PaSampleFormat format, long flags, int indev, int outdev ); PaSampleFormat format, long flags, int indev, int outdev );
PaError CloseAudioStream( PABLIO_Stream *aStream ); PaError CloseAudioStream( PABLIO_Stream *aStream );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* _PABLIO_H */ #endif /* _PABLIO_H */

View File

@ -1,219 +1,219 @@
/* /*
* $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
* ringbuffer.c * ringbuffer.c
* Ring Buffer utility.. * Ring Buffer utility..
* *
* Author: Phil Burk, http://www.softsynth.com * Author: Phil Burk, http://www.softsynth.com
* *
* This program uses the PortAudio Portable Audio Library. * This program uses the PortAudio Portable Audio Library.
* For more information see: http://www.audiomulch.com/portaudio/ * For more information see: http://www.audiomulch.com/portaudio/
* Copyright (c) 1999-2000 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 * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "ringbuffer.h" #include "ringbuffer.h"
#include <string.h> #include <string.h>
/*************************************************************************** /***************************************************************************
* Initialize FIFO. * Initialize FIFO.
* numBytes must be power of 2, returns -1 if not. * numBytes must be power of 2, returns -1 if not.
*/ */
long RingBuffer_Init(RingBuffer * rbuf, long numBytes, void *dataPtr) long RingBuffer_Init(RingBuffer * rbuf, long numBytes, void *dataPtr)
{ {
if (((numBytes - 1) & numBytes) != 0) if (((numBytes - 1) & numBytes) != 0)
return -1; /* Not Power of two. */ return -1; /* Not Power of two. */
rbuf->bufferSize = numBytes; rbuf->bufferSize = numBytes;
rbuf->buffer = (char *) dataPtr; rbuf->buffer = (char *) dataPtr;
RingBuffer_Flush(rbuf); RingBuffer_Flush(rbuf);
rbuf->bigMask = (numBytes * 2) - 1; rbuf->bigMask = (numBytes * 2) - 1;
rbuf->smallMask = (numBytes) - 1; rbuf->smallMask = (numBytes) - 1;
return 0; 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 reading. */
** Return number of bytes available for writing. */ long RingBuffer_GetReadAvailable(RingBuffer * rbuf)
long RingBuffer_GetWriteAvailable(RingBuffer * rbuf)
{ {
return (rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf)); return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask);
} }
/***************************************************************************
** 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. ** Return number of bytes available for writing. */
** If the region is contiguous, size2 will be zero. long RingBuffer_GetWriteAvailable(RingBuffer * rbuf)
** 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; return (rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
long available = RingBuffer_GetWriteAvailable(rbuf); }
if (numBytes > available)
/***************************************************************************
** 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; numBytes = available;
/* Check to see if write is not contiguous. */ /* Check to see if write is not contiguous. */
index = rbuf->writeIndex & rbuf->smallMask; index = rbuf->writeIndex & rbuf->smallMask;
if ((index + numBytes) > rbuf->bufferSize) if ((index + numBytes) > rbuf->bufferSize)
{ {
/* Write data in two blocks that wrap the buffer. */ /* Write data in two blocks that wrap the buffer. */
long firstHalf = rbuf->bufferSize - index; long firstHalf = rbuf->bufferSize - index;
*dataPtr1 = &rbuf->buffer[index]; *dataPtr1 = &rbuf->buffer[index];
*sizePtr1 = firstHalf; *sizePtr1 = firstHalf;
*dataPtr2 = &rbuf->buffer[0]; *dataPtr2 = &rbuf->buffer[0];
*sizePtr2 = numBytes - firstHalf; *sizePtr2 = numBytes - firstHalf;
} }
else else
{ {
*dataPtr1 = &rbuf->buffer[index]; *dataPtr1 = &rbuf->buffer[index];
*sizePtr1 = numBytes; *sizePtr1 = numBytes;
*dataPtr2 = NULL; *dataPtr2 = NULL;
*sizePtr2 = 0; *sizePtr2 = 0;
} }
return numBytes; 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. long RingBuffer_AdvanceWriteIndex(RingBuffer * rbuf, long numBytes)
** 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; return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
long available = RingBuffer_GetReadAvailable(rbuf); }
if (numBytes > available)
/***************************************************************************
** 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; numBytes = available;
/* Check to see if read is not contiguous. */ /* Check to see if read is not contiguous. */
index = rbuf->readIndex & rbuf->smallMask; index = rbuf->readIndex & rbuf->smallMask;
if ((index + numBytes) > rbuf->bufferSize) if ((index + numBytes) > rbuf->bufferSize)
{ {
/* Write data in two blocks that wrap the buffer. */ /* Write data in two blocks that wrap the buffer. */
long firstHalf = rbuf->bufferSize - index; long firstHalf = rbuf->bufferSize - index;
*dataPtr1 = &rbuf->buffer[index]; *dataPtr1 = &rbuf->buffer[index];
*sizePtr1 = firstHalf; *sizePtr1 = firstHalf;
*dataPtr2 = &rbuf->buffer[0]; *dataPtr2 = &rbuf->buffer[0];
*sizePtr2 = numBytes - firstHalf; *sizePtr2 = numBytes - firstHalf;
} }
else else
{ {
*dataPtr1 = &rbuf->buffer[index]; *dataPtr1 = &rbuf->buffer[index];
*sizePtr1 = numBytes; *sizePtr1 = numBytes;
*dataPtr2 = NULL; *dataPtr2 = NULL;
*sizePtr2 = 0; *sizePtr2 = 0;
} }
return numBytes; return numBytes;
} }
/***************************************************************************
*/
long RingBuffer_AdvanceReadIndex(RingBuffer * rbuf, long numBytes)
{
return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
}
/***************************************************************************
/*************************************************************************** */
** Return bytes written. */ long RingBuffer_AdvanceReadIndex(RingBuffer * rbuf, long numBytes)
long RingBuffer_Write(RingBuffer * rbuf, void *data, long numBytes)
{ {
long size1, size2, numWritten; return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
void *data1, *data2; }
numWritten = RingBuffer_GetWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
if (size2 > 0)
{ /***************************************************************************
memcpy(data1, data, size1); ** Return bytes written. */
data = ((char *) data) + size1; long RingBuffer_Write(RingBuffer * rbuf, void *data, long numBytes)
memcpy(data2, data, size2); {
} 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 else
{ {
memcpy(data1, data, size1); memcpy(data1, data, size1);
} }
RingBuffer_AdvanceWriteIndex(rbuf, numWritten); RingBuffer_AdvanceWriteIndex(rbuf, numWritten);
return numWritten; return numWritten;
} }
/*************************************************************************** /***************************************************************************
** Return bytes read. */ ** Return bytes read. */
long RingBuffer_Read(RingBuffer * rbuf, void *data, long numBytes) long RingBuffer_Read(RingBuffer * rbuf, void *data, long numBytes)
{ {
long size1, size2, numRead; long size1, size2, numRead;
void *data1, *data2; void *data1, *data2;
numRead = RingBuffer_GetReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2); numRead = RingBuffer_GetReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
if (size2 > 0) if (size2 > 0)
{ {
memcpy(data, data1, size1); memcpy(data, data1, size1);
data = ((char *) data) + size1; data = ((char *) data) + size1;
memcpy(data, data2, size2); memcpy(data, data2, size2);
} }
else else
{ {
memcpy(data, data1, size1); memcpy(data, data1, size1);
} }
RingBuffer_AdvanceReadIndex(rbuf, numRead); RingBuffer_AdvanceReadIndex(rbuf, numRead);
return numRead; return numRead;
} }

View File

@ -1,103 +1,103 @@
#ifndef _RINGBUFFER_H #ifndef _RINGBUFFER_H
#define _RINGBUFFER_H #define _RINGBUFFER_H
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {
#endif /* __cplusplus */ #endif /* __cplusplus */
/* /*
* $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $ * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $
* ringbuffer.h * ringbuffer.h
* Ring Buffer utility.. * Ring Buffer utility..
* *
* Author: Phil Burk, http://www.softsynth.com * Author: Phil Burk, http://www.softsynth.com
* *
* This program is distributed with the PortAudio Portable Audio Library. * This program is distributed with the PortAudio Portable Audio Library.
* For more information see: http://www.audiomulch.com/portaudio/ * For more information see: http://www.audiomulch.com/portaudio/
* Copyright (c) 1999-2000 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 * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files * a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, * (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, * including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software, * publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, * and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions: * subject to the following conditions:
* *
* The above copyright notice and this permission notice shall be * The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software. * included in all copies or substantial portions of the Software.
* *
* Any person wishing to distribute modifications to the Software is * Any person wishing to distribute modifications to the Software is
* requested to send the modifications to the original developer so that * requested to send the modifications to the original developer so that
* they can be incorporated into the canonical version. * they can be incorporated into the canonical version.
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* *
*/ */
#define PortAudioStream PaStream #define PortAudioStream PaStream
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include "ringbuffer.h" #include "ringbuffer.h"
#include <string.h> #include <string.h>
typedef struct typedef struct
{ {
long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */ long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
/* These are declared volatile because they are written by a different thread than the reader. */ /* These are declared volatile because they are written by a different thread than the reader. */
volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */ volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */
volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */ volatile 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 bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */
long smallMask; /* Used for fitting indices to buffer. */ long smallMask; /* Used for fitting indices to buffer. */
char *buffer; char *buffer;
} }
RingBuffer; RingBuffer;
/* /*
* Initialize Ring Buffer. * Initialize Ring Buffer.
* numBytes must be power of 2, returns -1 if not. * numBytes must be power of 2, returns -1 if not.
*/ */
long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr ); long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
/* Clear buffer. Should only be called when buffer is NOT being read. */ /* Clear buffer. Should only be called when buffer is NOT being read. */
void RingBuffer_Flush( RingBuffer *rbuf ); void RingBuffer_Flush( RingBuffer *rbuf );
/* Return number of bytes available for writing. */ /* Return number of bytes available for writing. */
long RingBuffer_GetWriteAvailable( RingBuffer *rbuf ); long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
/* Return number of bytes available for read. */ /* Return number of bytes available for read. */
long RingBuffer_GetReadAvailable( RingBuffer *rbuf ); long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
/* Return bytes written. */ /* Return bytes written. */
long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes ); long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
/* Return bytes read. */ /* Return bytes read. */
long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes ); long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
/* Get address of region(s) to which we can write data. /* Get address of region(s) to which we can write data.
** If the region is contiguous, size2 will be zero. ** If the region is contiguous, size2 will be zero.
** If non-contiguous, size2 will be the size of second region. ** If non-contiguous, size2 will be the size of second region.
** Returns room available to be written or numBytes, whichever is smaller. ** Returns room available to be written or numBytes, whichever is smaller.
*/ */
long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes, long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1, void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 ); void **dataPtr2, long *sizePtr2 );
long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes ); long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
/* Get address of region(s) from which we can read data. /* Get address of region(s) from which we can read data.
** If the region is contiguous, size2 will be zero. ** If the region is contiguous, size2 will be zero.
** If non-contiguous, size2 will be the size of second region. ** If non-contiguous, size2 will be the size of second region.
** Returns room available to be read or numBytes, whichever is smaller. ** Returns room available to be read or numBytes, whichever is smaller.
*/ */
long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes, long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
void **dataPtr1, long *sizePtr1, void **dataPtr1, long *sizePtr1,
void **dataPtr2, long *sizePtr2 ); void **dataPtr2, long *sizePtr2 );
long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes ); long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */
#endif /* _RINGBUFFER_H */ #endif /* _RINGBUFFER_H */