const struct switch_application_interface *next;
};
+struct switch_api_interface {
+ const char *interface_name;
+ const char *desc;
+ switch_status (*function)(char *in, char *out, size_t outlen);
+ const struct switch_api_interface *next;
+};
+
#endif
#define switch_copy_flags(dest, src, flags) (dest)->flags &= ~(flags); (dest)->flags |= ((src)->flags & (flags))
#define switch_strlen_zero(s) (s && *s != '\0') ? 0 : 1
#define switch_yield(ms) apr_sleep(ms * 10); apr_thread_yield();
+#define SWITCH_DECLARE_GLOBAL_STRING_FUNC(fname, vname) static void fname(char *string) { if (vname) {free(vname); vname = NULL;}vname = strdup(string);}
SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen);
SWITCH_DECLARE(switch_status) switch_socket_create_pollfd(switch_pollfd_t *poll, switch_socket_t *sock, unsigned int flags, switch_memory_pool *pool);
static switch_memory_pool *module_pool;
static int running = 1;
+#define SAMPLE_TYPE paInt16\r
+typedef short SAMPLE;\r
typedef enum {
TFLAG_IO = (1 << 0),
static struct {
int debug;
int port;
+ char *cid_name;
+ char *cid_num;
char *dialplan;
- char *soundcard;
unsigned int flags;
+ int indev;
+ int outdev;
} globals;
struct private_object {
unsigned char databuf[1024];
switch_core_session *session;
switch_caller_profile *caller_profile;
- unsigned int codec;
- unsigned int codecs;
- switch_mutex_t *mutex;
- switch_thread_cond_t *cond;
+ PaError err;\r
+ PABLIO_Stream *audio_in;\r
+ PABLIO_Stream *audio_out;
+ int indev;
+ int outdev;
};
-static void set_global_dialplan(char *dialplan)
-{
- if (globals.dialplan) {
- free(globals.dialplan);
- globals.dialplan = NULL;
- }
-
- globals.dialplan = strdup(dialplan);
-}
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_name, globals.cid_name)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_cid_num, globals.cid_num)
+
-static void set_global_soundcard(char *soundcard)
-{
- if (globals.soundcard) {
- free(globals.soundcard);
- globals.soundcard = NULL;
- }
-
- globals.soundcard = strdup(soundcard);
-}
static const switch_endpoint_interface channel_endpoint_interface;
static switch_status channel_on_init(switch_core_session *session);
switch_set_flag(tech_pvt, TFLAG_IO);
- switch_mutex_init(&tech_pvt->mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
- switch_thread_cond_create(&tech_pvt->cond, switch_core_session_get_pool(session));
- switch_mutex_lock(tech_pvt->mutex);
-
/* Move Channel's State Machine to RING */
switch_channel_set_state(channel, CS_RING);
assert(tech_pvt != NULL);
switch_clear_flag(tech_pvt, TFLAG_IO);
- switch_thread_cond_signal(tech_pvt->cond);
switch_core_codec_destroy(&tech_pvt->read_codec);
switch_core_codec_destroy(&tech_pvt->write_codec);
-
+
+ CloseAudioStream(tech_pvt->audio_in);\r
+ CloseAudioStream(tech_pvt->audio_out);\r
+
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
return SWITCH_STATUS_SUCCESS;
{
switch_channel *channel = NULL;
struct private_object *tech_pvt = NULL;
-
+ int t;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
tech_pvt = switch_core_session_get_private(session);
assert(tech_pvt != NULL);
+\r
+ if ((t = ReadAudioStream(tech_pvt->audio_in, tech_pvt->read_frame.data, tech_pvt->read_codec.implementation->samples_per_frame))) {\r
+ tech_pvt->read_frame.datalen = t * 2;\r
+ tech_pvt->read_frame.samples = t;\r
+ *frame = &tech_pvt->read_frame;\r
+ return SWITCH_STATUS_SUCCESS;\r
+ }\r
+
- for(;;) {
- if (switch_test_flag(tech_pvt, TFLAG_IO)) {
- switch_thread_cond_wait(tech_pvt->cond, tech_pvt->mutex);
- if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
- return SWITCH_STATUS_FALSE;
- }
- while (switch_test_flag(tech_pvt, TFLAG_IO) && !switch_test_flag(tech_pvt, TFLAG_VOICE)) {
- switch_yield(1000);
- }
-
- if (switch_test_flag(tech_pvt, TFLAG_IO)) {
- switch_clear_flag(tech_pvt, TFLAG_VOICE);
- if(!tech_pvt->read_frame.datalen) {
- continue;
- }
-
- *frame = &tech_pvt->read_frame;
- return SWITCH_STATUS_SUCCESS;
- }
- }
- break;
- }
return SWITCH_STATUS_FALSE;
}
switch_swap_linear(frame->data, (int)frame->datalen / 2);
}
*/
-
+
+ WriteAudioStream(tech_pvt->audio_out, (short *)frame->data, (int)(frame->datalen / sizeof(SAMPLE)));
//XXX send voice
return SWITCH_STATUS_SUCCESS;
static int dump_info(void);
static void make_call(char *dest);
+static switch_status load_config(void);
+static int get_dev_by_name(char *name, int in);
SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
return SWITCH_STATUS_TERM;
}
-\r
- Pa_Initialize();\r
+
+ Pa_Initialize();
+ load_config();
dump_info();
/* connect my internal structure to the blank pointer passed to me */
*interface = &channel_module_interface;
globals.debug = atoi(val);
} else if (!strcmp(var, "dialplan")) {
set_global_dialplan(val);
- } else if (!strcmp(var, "soundcard")) {
- set_global_soundcard(val);
+ } else if (!strcmp(var, "cid_name")) {
+ set_global_cid_name(val);
+ } else if (!strcmp(var, "cid_num")) {
+ set_global_cid_num(val);
+ } else if (!strcmp(var, "indev")) {
+ if (*val == '#') {
+ globals.indev = atoi(val+1);
+ } else {
+ globals.indev = get_dev_by_name(val, 1);
+ }
+ } else if (!strcmp(var, "outdev")) {
+ if (*val == '#') {
+ globals.outdev = atoi(val+1);
+ } else {
+ globals.outdev = get_dev_by_name(val, 1);
+ }
}
}
}
if (!globals.dialplan) {
set_global_dialplan("default");
}
-
+
switch_config_close_file(&cfg);
-
+
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
{
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-
- switch_yield(500000);
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-
- make_call("1000");
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "sleep\n");
-
+
+ switch_yield(50000);
+ make_call("8888");
return SWITCH_STATUS_TERM;
}
SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
{
- Pa_Terminate();\r
+ Pa_Terminate();
return SWITCH_STATUS_SUCCESS;
}
+static int get_dev_by_name(char *name, int in)
+{
+ int i;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ numDevices = Pa_CountDevices();
+
+ if( numDevices < 0 ) {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ return -2;
+ }
+
+ for( i=0; i<numDevices; i++ ) {
+ pdi = Pa_GetDeviceInfo( i );
+ if(strstr(pdi->name, name)) {
+ if(in && pdi->maxInputChannels) {
+ return i;
+ } else if (!in && pdi->maxOutputChannels) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
-static int dump_info(void)\r
-{\r
- int i,j;\r
- int numDevices;\r
- const PaDeviceInfo *pdi;\r
- PaError err;\r
- numDevices = Pa_CountDevices();\r
- if( numDevices < 0 )\r
- {\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );\r
- err = numDevices;\r
- goto error;\r
- }\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Number of devices = %d\n", numDevices );\r
- for( i=0; i<numDevices; i++ )\r
- {\r
- pdi = Pa_GetDeviceInfo( i );\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "---------------------------------------------- #%d", i );\r
- if( i == Pa_GetDefaultInputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultInput");\r
- if( i == Pa_GetDefaultOutputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultOutput");\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\nName = %s\n", pdi->name );\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Max Inputs = %d", pdi->maxInputChannels );\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, ", Max Outputs = %d\n", pdi->maxOutputChannels );\r
- if( pdi->numSampleRates == -1 )\r
- {\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );\r
- }\r
- else\r
- {\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rates =");\r
- for( j=0; j<pdi->numSampleRates; j++ )\r
- {\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " %8.2f,", pdi->sampleRates[j] );\r
- }\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");\r
- }\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Native Sample Formats = ");\r
- if( pdi->nativeSampleFormats & paInt8 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt8, ");\r
- if( pdi->nativeSampleFormats & paUInt8 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paUInt8, ");\r
- if( pdi->nativeSampleFormats & paInt16 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt16, ");\r
- if( pdi->nativeSampleFormats & paInt32 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt32, ");\r
- if( pdi->nativeSampleFormats & paFloat32 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paFloat32, ");\r
- if( pdi->nativeSampleFormats & paInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt24, ");\r
- if( pdi->nativeSampleFormats & paPackedInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paPackedInt24, ");\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");\r
- }\r
- \r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "----------------------------------------------\n");\r
- return 0;\r
-error:\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "An error occured while using the portaudio stream\n" );\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error number: %d\n", err );\r
- switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error message: %s\n", Pa_GetErrorText( err ) );\r
- return err;\r
-}\r
-\r
-static void make_call(char *dest)\r
-{\r
+static int dump_info(void)
+{
+ int i,j;
+ int numDevices;
+ const PaDeviceInfo *pdi;
+ PaError err;
+ numDevices = Pa_CountDevices();
+ if( numDevices < 0 )
+ {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
+ err = numDevices;
+ goto error;
+ }
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Number of devices = %d\n", numDevices );
+ for( i=0; i<numDevices; i++ )
+ {
+ pdi = Pa_GetDeviceInfo( i );
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "---------------------------------------------- #%d", i );
+ if( i == Pa_GetDefaultInputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultInput");
+ if( i == Pa_GetDefaultOutputDeviceID() ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " DefaultOutput");
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\nName = %s\n", pdi->name );
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Max Inputs = %d", pdi->maxInputChannels );
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, ", Max Outputs = %d\n", pdi->maxOutputChannels );
+ if( pdi->numSampleRates == -1 )
+ {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rate Range = %f to %f\n", pdi->sampleRates[0], pdi->sampleRates[1] );
+ }
+ else
+ {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Sample Rates =");
+ for( j=0; j<pdi->numSampleRates; j++ )
+ {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, " %8.2f,", pdi->sampleRates[j] );
+ }
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");
+ }
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Native Sample Formats = ");
+ if( pdi->nativeSampleFormats & paInt8 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt8, ");
+ if( pdi->nativeSampleFormats & paUInt8 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paUInt8, ");
+ if( pdi->nativeSampleFormats & paInt16 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt16, ");
+ if( pdi->nativeSampleFormats & paInt32 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt32, ");
+ if( pdi->nativeSampleFormats & paFloat32 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paFloat32, ");
+ if( pdi->nativeSampleFormats & paInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paInt24, ");
+ if( pdi->nativeSampleFormats & paPackedInt24 ) switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "paPackedInt24, ");
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "\n");
+ }
+
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "----------------------------------------------\n");
+ return 0;
+error:
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "An error occured while using the portaudio stream\n" );
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error number: %d\n", err );
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Error message: %s\n", Pa_GetErrorText( err ) );
+ return err;
+}
+
+static void make_call(char *dest)
+{
switch_core_session *session;
-
+ int sample_rate = 8000;
+ int codec_ms = 20;
+
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "New Inbound Channel\n");
if ((session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
struct private_object *tech_pvt;
return;
}
-
if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
globals.dialplan,
- "Test This Shit",
- "1231231234",
+ globals.cid_name,
+ globals.cid_num,
NULL,
NULL,
dest))) {
if (switch_core_codec_init(&tech_pvt->read_codec,
"L16",
- 0,
- 0,
+ sample_rate,
+ codec_ms,
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
NULL) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
} else {
if (switch_core_codec_init(&tech_pvt->write_codec,
"L16",
- 0,
- 0,
+ sample_rate,
+ codec_ms,
SWITCH_CODEC_FLAG_ENCODE |SWITCH_CODEC_FLAG_DECODE, NULL) != SWITCH_STATUS_SUCCESS) {
switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
switch_core_codec_destroy(&tech_pvt->read_codec);
}
}
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+ switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+ switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
- switch_channel_set_state(channel, CS_INIT);
- switch_core_session_thread_launch(session);
+ tech_pvt->indev = globals.indev;
+ tech_pvt->outdev = globals.outdev;
+
+ if ((tech_pvt->err = OpenAudioStream( &tech_pvt->audio_in, sample_rate, SAMPLE_TYPE, PABLIO_READ | PABLIO_MONO, tech_pvt->indev, -1)) == paNoError) {
+ if ((tech_pvt->err = OpenAudioStream(&tech_pvt->audio_out, sample_rate, SAMPLE_TYPE, PABLIO_WRITE | PABLIO_MONO, -1, tech_pvt->outdev)) != paNoError) {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open audio out!\n");
+ CloseAudioStream(tech_pvt->audio_in);
+ }
+ } else {
+ switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open audio in!\n");
+ }
+ if (tech_pvt->err == paNoError) {
+ switch_channel_set_state(channel, CS_INIT);
+ switch_core_session_thread_launch(session);
+ } else {
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ switch_core_session_destroy(&session);
+ }
}
-\r
+
}
\ No newline at end of file
--- /dev/null
+/*\r
+ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $\r
+ * pablio.c\r
+ * Portable Audio Blocking Input/Output utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+\r
+/* History:\r
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.\r
+ * add timeOutMSec to CloseAudioStream() to prevent hang.\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include "pablio.h"\r
+#include <string.h>\r
+\r
+/************************************************************************/\r
+/******** Constants *****************************************************/\r
+/************************************************************************/\r
+\r
+#define FRAMES_PER_BUFFER (256)\r
+\r
+/************************************************************************/\r
+/******** Prototypes ****************************************************/\r
+/************************************************************************/\r
+\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+ unsigned long framesPerBuffer,\r
+ PaTimestamp outTime, void *userData );\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );\r
+\r
+/************************************************************************/\r
+/******** Functions *****************************************************/\r
+/************************************************************************/\r
+\r
+/* Called from PortAudio.\r
+ * Read and write data only if there is room in FIFOs.\r
+ */\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+ unsigned long framesPerBuffer,\r
+ PaTimestamp outTime, void *userData )\r
+{\r
+ PABLIO_Stream *data = (PABLIO_Stream*)userData;\r
+ long numBytes = data->bytesPerFrame * framesPerBuffer;\r
+ (void) outTime;\r
+\r
+ /* This may get called with NULL inputBuffer during initial setup. */\r
+ if( inputBuffer != NULL )\r
+ {\r
+ RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );\r
+ }\r
+ if( outputBuffer != NULL )\r
+ {\r
+ int i;\r
+ int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );\r
+ /* Zero out remainder of buffer if we run out of data. */\r
+ for( i=numRead; i<numBytes; i++ )\r
+ {\r
+ ((char *)outputBuffer)[i] = 0;\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/* Allocate buffer. */\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )\r
+{\r
+ long numBytes = numFrames * bytesPerFrame;\r
+ char *buffer = (char *) malloc( numBytes );\r
+ if( buffer == NULL ) return paInsufficientMemory;\r
+ memset( buffer, 0, numBytes );\r
+ return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );\r
+}\r
+\r
+/* Free buffer. */\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )\r
+{\r
+ if( rbuf->buffer ) free( rbuf->buffer );\r
+ rbuf->buffer = NULL;\r
+ return paNoError;\r
+}\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+ long bytesWritten;\r
+ char *p = (char *) data;\r
+ long numBytes = aStream->bytesPerFrame * numFrames;\r
+ while( numBytes > 0)\r
+ {\r
+ bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );\r
+ numBytes -= bytesWritten;\r
+ p += bytesWritten;\r
+ if( numBytes > 0) Pa_Sleep(10);\r
+ }\r
+ return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+ long bytesRead;\r
+ char *p = (char *) data;\r
+ long numBytes = aStream->bytesPerFrame * numFrames;\r
+ while( numBytes > 0)\r
+ {\r
+ bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );\r
+ numBytes -= bytesRead;\r
+ p += bytesRead;\r
+ if( numBytes > 0) Pa_Sleep(10);\r
+ }\r
+ return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream )\r
+{\r
+ int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+ return bytesEmpty / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream )\r
+{\r
+ int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );\r
+ return bytesFull / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************/\r
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )\r
+{\r
+ long numBits = 0;\r
+ if( ((n-1) & n) == 0) return n; /* Already Power of two. */\r
+ while( n > 0 )\r
+ {\r
+ n= n>>1;\r
+ numBits++;\r
+ }\r
+ return (1<<numBits);\r
+}\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ * and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,\r
+ PaSampleFormat format, long flags, int indev, int outdev )\r
+{\r
+ long bytesPerSample;\r
+ long doRead = 0;\r
+ long doWrite = 0;\r
+ PaError err;\r
+ PABLIO_Stream *aStream;\r
+ long minNumBuffers;\r
+ long numFrames;\r
+\r
+ /* Allocate PABLIO_Stream structure for caller. */\r
+ aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );\r
+ if( aStream == NULL ) return paInsufficientMemory;\r
+ memset( aStream, 0, sizeof(PABLIO_Stream) );\r
+\r
+ /* Determine size of a sample. */\r
+ bytesPerSample = Pa_GetSampleSize( format );\r
+ if( bytesPerSample < 0 )\r
+ {\r
+ err = (PaError) bytesPerSample;\r
+ goto error;\r
+ }\r
+ aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;\r
+ aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;\r
+\r
+ /* Initialize PortAudio */\r
+ err = Pa_Initialize();\r
+ if( err != paNoError ) goto error;\r
+\r
+ /* Warning: numFrames must be larger than amount of data processed per interrupt\r
+ * inside PA to prevent glitches. Just to be safe, adjust size upwards.\r
+ */\r
+ minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );\r
+ numFrames = minNumBuffers * FRAMES_PER_BUFFER;\r
+ /* The PortAudio callback runs in a high priority thread. But PABLIO\r
+ * runs in a normal foreground thread. So we may have much worse\r
+ * latency in PABLIO. So adjust latency to a safe level.\r
+ */\r
+ {\r
+ const int safeLatencyMSec = 200;\r
+ int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);\r
+ if( minLatencyMSec < safeLatencyMSec )\r
+ {\r
+ numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);\r
+ }\r
+ }\r
+ numFrames = RoundUpToNextPowerOf2( numFrames );\r
+\r
+ /* Initialize Ring Buffers */\r
+ doRead = ((flags & PABLIO_READ) != 0);\r
+ doWrite = ((flags & PABLIO_WRITE) != 0);\r
+ if(doRead)\r
+ {\r
+ err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );\r
+ if( err != paNoError ) goto error;\r
+ }\r
+ if(doWrite)\r
+ {\r
+ long numBytes;\r
+ err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );\r
+ if( err != paNoError ) goto error;\r
+ /* Make Write FIFO appear full initially. */\r
+ numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+ RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );\r
+ }\r
+\r
+ /* Open a PortAudio stream that we will use to communicate with the underlying\r
+ * audio drivers. */\r
+ err = Pa_OpenStream(\r
+ &aStream->stream,\r
+ (doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),\r
+ (doRead ? aStream->samplesPerFrame : 0 ),\r
+ format,\r
+ NULL,\r
+ (doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),\r
+ (doWrite ? aStream->samplesPerFrame : 0 ),\r
+ format,\r
+ NULL,\r
+ sampleRate,\r
+ FRAMES_PER_BUFFER,\r
+ minNumBuffers,\r
+ paClipOff, /* we won't output out of range samples so don't bother clipping them */\r
+ blockingIOCallback,\r
+ aStream );\r
+ if( err != paNoError ) goto error;\r
+\r
+ err = Pa_StartStream( aStream->stream );\r
+ if( err != paNoError ) goto error;\r
+\r
+ *rwblPtr = aStream;\r
+ return paNoError;\r
+\r
+error:\r
+ CloseAudioStream( aStream );\r
+ *rwblPtr = NULL;\r
+ return err;\r
+}\r
+\r
+/************************************************************/\r
+PaError CloseAudioStream( PABLIO_Stream *aStream )\r
+{\r
+ PaError err = paNoError;\r
+ int bytesEmpty;\r
+ int byteSize = aStream->outFIFO.bufferSize;\r
+\r
+ if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */\r
+ {\r
+ /* If we are writing data, make sure we play everything written. */\r
+ if( byteSize > 0 )\r
+ {\r
+ int timeOutMSec = 2000;\r
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+ while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )\r
+ {\r
+ Pa_Sleep( 20 );\r
+ timeOutMSec -= 20;\r
+ bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+ }\r
+ }\r
+ err = Pa_StopStream( aStream->stream );\r
+ if( err != paNoError ) goto error;\r
+ err = Pa_CloseStream( aStream->stream );\r
+ }\r
+\r
+error:\r
+ Pa_Terminate();\r
+ PABLIO_TermFIFO( &aStream->inFIFO );\r
+ PABLIO_TermFIFO( &aStream->outFIFO );\r
+ free( aStream );\r
+ return err;\r
+}\r
--- /dev/null
+#ifndef _PABLIO_H\r
+#define _PABLIO_H\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * PABLIO.h\r
+ * Portable Audio Blocking read/write utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/\r
+ *\r
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.\r
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+ RingBuffer inFIFO;\r
+ RingBuffer outFIFO;\r
+ PortAudioStream *stream;\r
+ int bytesPerFrame;\r
+ int samplesPerFrame;\r
+}\r
+PABLIO_Stream;\r
+\r
+/* Values for flags for OpenAudioStream(). */\r
+#define PABLIO_READ (1<<0)\r
+#define PABLIO_WRITE (1<<1)\r
+#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)\r
+#define PABLIO_MONO (1<<2)\r
+#define PABLIO_STEREO (1<<3)\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ * and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,\r
+ PaSampleFormat format, long flags, int indev, int outdev );\r
+\r
+PaError CloseAudioStream( PABLIO_Stream *aStream );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _PABLIO_H */\r
--- /dev/null
+/*\r
+ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * ringbuffer.c\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+/***************************************************************************\r
+ * Initialize FIFO.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )\r
+{\r
+ if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */\r
+ rbuf->bufferSize = numBytes;\r
+ rbuf->buffer = (char *)dataPtr;\r
+ RingBuffer_Flush( rbuf );\r
+ rbuf->bigMask = (numBytes*2)-1;\r
+ rbuf->smallMask = (numBytes)-1;\r
+ return 0;\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for reading. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )\r
+{\r
+ return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )\r
+{\r
+ return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));\r
+}\r
+\r
+/***************************************************************************\r
+** Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf )\r
+{\r
+ rbuf->writeIndex = rbuf->readIndex = 0;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+ void **dataPtr1, long *sizePtr1,\r
+ void **dataPtr2, long *sizePtr2 )\r
+{\r
+ long index;\r
+ long available = RingBuffer_GetWriteAvailable( rbuf );\r
+ if( numBytes > available ) numBytes = available;\r
+ /* Check to see if write is not contiguous. */\r
+ index = rbuf->writeIndex & rbuf->smallMask;\r
+ if( (index + numBytes) > rbuf->bufferSize )\r
+ {\r
+ /* Write data in two blocks that wrap the buffer. */\r
+ long firstHalf = rbuf->bufferSize - index;\r
+ *dataPtr1 = &rbuf->buffer[index];\r
+ *sizePtr1 = firstHalf;\r
+ *dataPtr2 = &rbuf->buffer[0];\r
+ *sizePtr2 = numBytes - firstHalf;\r
+ }\r
+ else\r
+ {\r
+ *dataPtr1 = &rbuf->buffer[index];\r
+ *sizePtr1 = numBytes;\r
+ *dataPtr2 = NULL;\r
+ *sizePtr2 = 0;\r
+ }\r
+ return numBytes;\r
+}\r
+\r
+\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+ return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+ void **dataPtr1, long *sizePtr1,\r
+ void **dataPtr2, long *sizePtr2 )\r
+{\r
+ long index;\r
+ long available = RingBuffer_GetReadAvailable( rbuf );\r
+ if( numBytes > available ) numBytes = available;\r
+ /* Check to see if read is not contiguous. */\r
+ index = rbuf->readIndex & rbuf->smallMask;\r
+ if( (index + numBytes) > rbuf->bufferSize )\r
+ {\r
+ /* Write data in two blocks that wrap the buffer. */\r
+ long firstHalf = rbuf->bufferSize - index;\r
+ *dataPtr1 = &rbuf->buffer[index];\r
+ *sizePtr1 = firstHalf;\r
+ *dataPtr2 = &rbuf->buffer[0];\r
+ *sizePtr2 = numBytes - firstHalf;\r
+ }\r
+ else\r
+ {\r
+ *dataPtr1 = &rbuf->buffer[index];\r
+ *sizePtr1 = numBytes;\r
+ *dataPtr2 = NULL;\r
+ *sizePtr2 = 0;\r
+ }\r
+ return numBytes;\r
+}\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+ return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+ long size1, size2, numWritten;\r
+ void *data1, *data2;\r
+ numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+ if( size2 > 0 )\r
+ {\r
+\r
+ memcpy( data1, data, size1 );\r
+ data = ((char *)data) + size1;\r
+ memcpy( data2, data, size2 );\r
+ }\r
+ else\r
+ {\r
+ memcpy( data1, data, size1 );\r
+ }\r
+ RingBuffer_AdvanceWriteIndex( rbuf, numWritten );\r
+ return numWritten;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+ long size1, size2, numRead;\r
+ void *data1, *data2;\r
+ numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+ if( size2 > 0 )\r
+ {\r
+ memcpy( data, data1, size1 );\r
+ data = ((char *)data) + size1;\r
+ memcpy( data, data2, size2 );\r
+ }\r
+ else\r
+ {\r
+ memcpy( data, data1, size1 );\r
+ }\r
+ RingBuffer_AdvanceReadIndex( rbuf, numRead );\r
+ return numRead;\r
+}\r
--- /dev/null
+#ifndef _RINGBUFFER_H\r
+#define _RINGBUFFER_H\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $\r
+ * ringbuffer.h\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program is distributed with the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+ long bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */\r
+/* These are declared volatile because they are written by a different thread than the reader. */\r
+ volatile long writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */\r
+ volatile long readIndex; /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */\r
+ long bigMask; /* Used for wrapping indices with extra bit to distinguish full/empty. */\r
+ long smallMask; /* Used for fitting indices to buffer. */\r
+ char *buffer;\r
+}\r
+RingBuffer;\r
+/*\r
+ * Initialize Ring Buffer.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );\r
+\r
+/* Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf );\r
+\r
+/* Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );\r
+/* Return number of bytes available for read. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );\r
+/* Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );\r
+/* Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );\r
+\r
+/* Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+ void **dataPtr1, long *sizePtr1,\r
+ void **dataPtr2, long *sizePtr2 );\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+/* Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be read or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+ void **dataPtr1, long *sizePtr1,\r
+ void **dataPtr2, long *sizePtr2 );\r
+\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _RINGBUFFER_H */\r
<Tool\r
Name="VCCLCompilerTool"\r
Optimization="0"\r
- AdditionalIncludeDirectories=""$(ProjectDir)..\..\src\include";"$(ProjectDir)include";"$(ProjectDir)..\..\libs\apr\include";"$(ProjectDir)..\..\libs\portaudio\pa_common";"$(ProjectDir)..\..\libs\portaudio\pablio";"$(ProjectDir)..\..\libs\portaudio\pa_win_wmme""\r
+ AdditionalIncludeDirectories=""$(ProjectDir)..\..\src\include";"$(ProjectDir)include";"$(ProjectDir)..\..\libs\apr\include";"$(ProjectDir)..\..\libs\portaudio\pa_common";"$(ProjectDir)\..\..\..\src\mod\mod_portaudio";"$(ProjectDir)..\..\libs\portaudio\pa_win_wmme""\r
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
MinimalRebuild="true"\r
BasicRuntimeChecks="3"\r
>\r
</File>\r
<File\r
- RelativePath="..\..\libs\portaudio\pablio\pablio.c"\r
+ RelativePath="..\..\src\mod\mod_portaudio\pablio.c"\r
>\r
</File>\r
<File\r
- RelativePath="..\..\libs\portaudio\pablio\ringbuffer.c"\r
+ RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.c"\r
>\r
</File>\r
</Filter>\r
Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
>\r
+ <File\r
+ RelativePath="..\..\src\mod\mod_portaudio\pablio.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.h"\r
+ >\r
+ </File>\r
</Filter>\r
<Filter\r
Name="Resource Files"\r