diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h
index 378ebe3371..a005c688ab 100644
--- a/src/include/switch_module_interfaces.h
+++ b/src/include/switch_module_interfaces.h
@@ -251,4 +251,11 @@ struct switch_application_interface {
 	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
diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h
index 05a3cb8c0e..266c022575 100644
--- a/src/include/switch_utils.h
+++ b/src/include/switch_utils.h
@@ -78,6 +78,7 @@ typedef typeof(tv.tv_usec) switch_suseconds_t;
 #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);
diff --git a/src/mod/mod_portaudio/mod_portaudio.c b/src/mod/mod_portaudio/mod_portaudio.c
index 36cb1c88cb..d96c03d0cb 100644
--- a/src/mod/mod_portaudio/mod_portaudio.c
+++ b/src/mod/mod_portaudio/mod_portaudio.c
@@ -42,6 +42,8 @@ static const char modname[] = "mod_portaudio";
 static switch_memory_pool *module_pool;
 static int running = 1;
 
+#define SAMPLE_TYPE  paInt16
+typedef short SAMPLE;
 
 typedef enum {
 	TFLAG_IO = (1 << 0),
@@ -60,9 +62,12 @@ typedef enum {
 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 {
@@ -73,31 +78,18 @@ 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;
+    PABLIO_Stream *audio_in;
+    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);
@@ -131,10 +123,6 @@ 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);
 
@@ -187,11 +175,13 @@ static switch_status channel_on_hangup(switch_core_session *session)
 	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);
+	CloseAudioStream(tech_pvt->audio_out);
+
 	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
 
 	return SWITCH_STATUS_SUCCESS;
@@ -324,35 +314,21 @@ static switch_status channel_read_frame(switch_core_session *session, switch_fra
 {
 	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);
+
+	if	((t = ReadAudioStream(tech_pvt->audio_in, tech_pvt->read_frame.data, tech_pvt->read_codec.implementation->samples_per_frame))) {
+		tech_pvt->read_frame.datalen = t * 2;
+		tech_pvt->read_frame.samples = t;
+		*frame = &tech_pvt->read_frame;
+		return SWITCH_STATUS_SUCCESS;
+	}
+
 
-	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;
 }
 
@@ -376,7 +352,8 @@ static switch_status channel_write_frame(switch_core_session *session, switch_fr
 		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;
@@ -436,6 +413,8 @@ static const switch_loadable_module_interface channel_module_interface = {
 
 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) {
 
@@ -443,8 +422,9 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_modul
 		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
 		return SWITCH_STATUS_TERM;
 	}
-
-	Pa_Initialize();
+
+	Pa_Initialize();
+	load_config();
 	dump_info();
 	/* connect my internal structure to the blank pointer passed to me */
 	*interface = &channel_module_interface;
@@ -473,8 +453,22 @@ static switch_status load_config(void)
 				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);
+				}
 			}
 		}
 	}
@@ -482,96 +476,118 @@ static switch_status load_config(void)
 	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();
+   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();
 
-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)
-{
+	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)
+{
+    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;
@@ -587,11 +603,10 @@ static void make_call(char *dest)
 			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))) {
@@ -604,8 +619,8 @@ static void make_call(char *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");
@@ -613,8 +628,8 @@ static void make_call(char *dest)
 		} 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);	
@@ -622,9 +637,29 @@ static void make_call(char *dest)
 			}
 		}
 	
+		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);
+		}
 	}		
-
+
 }
\ No newline at end of file
diff --git a/src/mod/mod_portaudio/pablio.c b/src/mod/mod_portaudio/pablio.c
new file mode 100644
index 0000000000..b5735daea0
--- /dev/null
+++ b/src/mod/mod_portaudio/pablio.c
@@ -0,0 +1,327 @@
+/*
+ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $
+ * pablio.c
+ * Portable Audio Blocking Input/Output utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/* History:
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.
+ *             add timeOutMSec to CloseAudioStream() to prevent hang.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include "pablio.h"
+#include <string.h>
+
+/************************************************************************/
+/******** Constants *****************************************************/
+/************************************************************************/
+
+#define FRAMES_PER_BUFFER    (256)
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+                               unsigned long framesPerBuffer,
+                               PaTimestamp outTime, void *userData );
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data only if there is room in FIFOs.
+ */
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,
+                               unsigned long framesPerBuffer,
+                               PaTimestamp outTime, void *userData )
+{
+    PABLIO_Stream *data = (PABLIO_Stream*)userData;
+    long numBytes = data->bytesPerFrame * framesPerBuffer;
+    (void) outTime;
+
+    /* This may get called with NULL inputBuffer during initial setup. */
+    if( inputBuffer != NULL )
+    {
+        RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );
+    }
+    if( outputBuffer != NULL )
+    {
+        int i;
+        int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );
+        /* Zero out remainder of buffer if we run out of data. */
+        for( i=numRead; i<numBytes; i++ )
+        {
+            ((char *)outputBuffer)[i] = 0;
+        }
+    }
+
+    return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )
+{
+    long numBytes = numFrames * bytesPerFrame;
+    char *buffer = (char *) malloc( numBytes );
+    if( buffer == NULL ) return paInsufficientMemory;
+    memset( buffer, 0, numBytes );
+    return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )
+{
+    if( rbuf->buffer ) free( rbuf->buffer );
+    rbuf->buffer = NULL;
+    return paNoError;
+}
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+    long bytesWritten;
+    char *p = (char *) data;
+    long numBytes = aStream->bytesPerFrame * numFrames;
+    while( numBytes > 0)
+    {
+        bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );
+        numBytes -= bytesWritten;
+        p += bytesWritten;
+        if( numBytes > 0) Pa_Sleep(10);
+    }
+    return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )
+{
+    long bytesRead;
+    char *p = (char *) data;
+    long numBytes = aStream->bytesPerFrame * numFrames;
+    while( numBytes > 0)
+    {
+        bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );
+        numBytes -= bytesRead;
+        p += bytesRead;
+        if( numBytes > 0) Pa_Sleep(10);
+    }
+    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 are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream )
+{
+    int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );
+    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. */
+    while( n > 0 )
+    {
+        n= n>>1;
+        numBits++;
+    }
+    return (1<<numBits);
+}
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ *    and either PABLIO_MONO or PABLIO_STEREO
+ */
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,
+                         PaSampleFormat format, long flags, int indev, int outdev )
+{
+    long   bytesPerSample;
+    long   doRead = 0;
+    long   doWrite = 0;
+    PaError err;
+    PABLIO_Stream *aStream;
+    long   minNumBuffers;
+    long   numFrames;
+
+    /* Allocate PABLIO_Stream structure for caller. */
+    aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );
+    if( aStream == NULL ) return paInsufficientMemory;
+    memset( aStream, 0, sizeof(PABLIO_Stream) );
+
+    /* Determine size of a sample. */
+    bytesPerSample = Pa_GetSampleSize( format );
+    if( bytesPerSample < 0 )
+    {
+        err = (PaError) bytesPerSample;
+        goto error;
+    }
+    aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;
+    aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;
+
+    /* Initialize PortAudio  */
+    err = Pa_Initialize();
+    if( err != paNoError ) goto error;
+
+    /* Warning: numFrames must be larger than amount of data processed per interrupt
+     *    inside PA to prevent glitches. Just to be safe, adjust size upwards.
+     */
+    minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );
+    numFrames = minNumBuffers * FRAMES_PER_BUFFER;
+    /* The PortAudio callback runs in a high priority thread. But PABLIO
+     * runs in a normal foreground thread. So we may have much worse
+     * latency in PABLIO. So adjust latency to a safe level.
+     */
+    {
+        const int safeLatencyMSec = 200;
+        int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);
+        if( minLatencyMSec < safeLatencyMSec )
+        {
+            numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);
+        }
+    }
+    numFrames = RoundUpToNextPowerOf2( numFrames );
+
+    /* Initialize Ring Buffers */
+    doRead = ((flags & PABLIO_READ) != 0);
+    doWrite = ((flags & PABLIO_WRITE) != 0);
+    if(doRead)
+    {
+        err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );
+        if( err != paNoError ) goto error;
+    }
+    if(doWrite)
+    {
+        long numBytes;
+        err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );
+        if( err != paNoError ) goto error;
+        /* Make Write FIFO appear full initially. */
+        numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+        RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );
+    }
+
+    /* Open a PortAudio stream that we will use to communicate with the underlying
+     * audio drivers. */
+    err = Pa_OpenStream(
+              &aStream->stream,
+			  (doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),
+              (doRead ? aStream->samplesPerFrame : 0 ),
+              format,
+              NULL,
+			  (doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),
+              (doWrite ? aStream->samplesPerFrame : 0 ),
+              format,
+              NULL,
+              sampleRate,
+              FRAMES_PER_BUFFER,
+              minNumBuffers,
+              paClipOff,       /* we won't output out of range samples so don't bother clipping them */
+              blockingIOCallback,
+              aStream );
+    if( err != paNoError ) goto error;
+
+    err = Pa_StartStream( aStream->stream );
+    if( err != paNoError ) goto error;
+
+    *rwblPtr = aStream;
+    return paNoError;
+
+error:
+    CloseAudioStream( aStream );
+    *rwblPtr = NULL;
+    return err;
+}
+
+/************************************************************/
+PaError CloseAudioStream( PABLIO_Stream *aStream )
+{
+    PaError err = paNoError;
+    int bytesEmpty;
+    int byteSize = aStream->outFIFO.bufferSize;
+
+    if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */
+    {
+        /* If we are writing data, make sure we play everything written. */
+        if( byteSize > 0 )
+        {
+            int timeOutMSec = 2000;
+            bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+            while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )
+            {
+                Pa_Sleep( 20 );
+                timeOutMSec -= 20;
+                bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );
+            }
+        }
+        err = Pa_StopStream( aStream->stream );
+        if( err != paNoError ) goto error;
+        err = Pa_CloseStream( aStream->stream );
+    }
+
+error:
+    Pa_Terminate();
+    PABLIO_TermFIFO( &aStream->inFIFO );
+    PABLIO_TermFIFO( &aStream->outFIFO );
+    free( aStream );
+    return err;
+}
diff --git a/src/mod/mod_portaudio/pablio.h b/src/mod/mod_portaudio/pablio.h
new file mode 100644
index 0000000000..25bccf8998
--- /dev/null
+++ b/src/mod/mod_portaudio/pablio.h
@@ -0,0 +1,109 @@
+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
+ * PABLIO.h
+ * Portable Audio Blocking read/write utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+    RingBuffer   inFIFO;
+    RingBuffer   outFIFO;
+    PortAudioStream *stream;
+    int          bytesPerFrame;
+    int          samplesPerFrame;
+}
+PABLIO_Stream;
+
+/* Values for flags for OpenAudioStream(). */
+#define PABLIO_READ     (1<<0)
+#define PABLIO_WRITE    (1<<1)
+#define PABLIO_READ_WRITE    (PABLIO_READ|PABLIO_WRITE)
+#define PABLIO_MONO     (1<<2)
+#define PABLIO_STEREO   (1<<3)
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable( PABLIO_Stream *aStream );
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ *    and either PABLIO_MONO or PABLIO_STEREO
+ */
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,
+                         PaSampleFormat format, long flags, int indev, int outdev );
+
+PaError CloseAudioStream( PABLIO_Stream *aStream );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _PABLIO_H */
diff --git a/src/mod/mod_portaudio/ringbuffer.c b/src/mod/mod_portaudio/ringbuffer.c
new file mode 100644
index 0000000000..867b501965
--- /dev/null
+++ b/src/mod/mod_portaudio/ringbuffer.c
@@ -0,0 +1,199 @@
+/*
+ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $
+ * ringbuffer.c
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+/***************************************************************************
+ * Initialize FIFO.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )
+{
+    if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */
+    rbuf->bufferSize = numBytes;
+    rbuf->buffer = (char *)dataPtr;
+    RingBuffer_Flush( rbuf );
+    rbuf->bigMask = (numBytes*2)-1;
+    rbuf->smallMask = (numBytes)-1;
+    return 0;
+}
+/***************************************************************************
+** Return number of bytes available for reading. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )
+{
+    return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );
+}
+/***************************************************************************
+** Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )
+{
+    return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));
+}
+
+/***************************************************************************
+** Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf )
+{
+    rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/***************************************************************************
+** Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+                                 void **dataPtr1, long *sizePtr1,
+                                 void **dataPtr2, long *sizePtr2 )
+{
+    long   index;
+    long   available = RingBuffer_GetWriteAvailable( rbuf );
+    if( numBytes > available ) numBytes = available;
+    /* Check to see if write is not contiguous. */
+    index = rbuf->writeIndex & rbuf->smallMask;
+    if( (index + numBytes) > rbuf->bufferSize )
+    {
+        /* Write data in two blocks that wrap the buffer. */
+        long   firstHalf = rbuf->bufferSize - index;
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = firstHalf;
+        *dataPtr2 = &rbuf->buffer[0];
+        *sizePtr2 = numBytes - firstHalf;
+    }
+    else
+    {
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = numBytes;
+        *dataPtr2 = NULL;
+        *sizePtr2 = 0;
+    }
+    return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )
+{
+    return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+                                void **dataPtr1, long *sizePtr1,
+                                void **dataPtr2, long *sizePtr2 )
+{
+    long   index;
+    long   available = RingBuffer_GetReadAvailable( rbuf );
+    if( numBytes > available ) numBytes = available;
+    /* Check to see if read is not contiguous. */
+    index = rbuf->readIndex & rbuf->smallMask;
+    if( (index + numBytes) > rbuf->bufferSize )
+    {
+        /* Write data in two blocks that wrap the buffer. */
+        long firstHalf = rbuf->bufferSize - index;
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = firstHalf;
+        *dataPtr2 = &rbuf->buffer[0];
+        *sizePtr2 = numBytes - firstHalf;
+    }
+    else
+    {
+        *dataPtr1 = &rbuf->buffer[index];
+        *sizePtr1 = numBytes;
+        *dataPtr2 = NULL;
+        *sizePtr2 = 0;
+    }
+    return numBytes;
+}
+/***************************************************************************
+*/
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )
+{
+    return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )
+{
+    long size1, size2, numWritten;
+    void *data1, *data2;
+    numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+    if( size2 > 0 )
+    {
+
+        memcpy( data1, data, size1 );
+        data = ((char *)data) + size1;
+        memcpy( data2, data, size2 );
+    }
+    else
+    {
+        memcpy( data1, data, size1 );
+    }
+    RingBuffer_AdvanceWriteIndex( rbuf, numWritten );
+    return numWritten;
+}
+
+/***************************************************************************
+** Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )
+{
+    long size1, size2, numRead;
+    void *data1, *data2;
+    numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );
+    if( size2 > 0 )
+    {
+        memcpy( data, data1, size1 );
+        data = ((char *)data) + size1;
+        memcpy( data, data2, size2 );
+    }
+    else
+    {
+        memcpy( data, data1, size1 );
+    }
+    RingBuffer_AdvanceReadIndex( rbuf, numRead );
+    return numRead;
+}
diff --git a/src/mod/mod_portaudio/ringbuffer.h b/src/mod/mod_portaudio/ringbuffer.h
new file mode 100644
index 0000000000..6f65694471
--- /dev/null
+++ b/src/mod/mod_portaudio/ringbuffer.h
@@ -0,0 +1,102 @@
+#ifndef _RINGBUFFER_H
+#define _RINGBUFFER_H
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+/*
+ * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $
+ * ringbuffer.h
+ * Ring Buffer utility..
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program is distributed with the PortAudio Portable Audio Library.
+ * For more information see: http://www.audiomulch.com/portaudio/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "ringbuffer.h"
+#include <string.h>
+
+typedef struct
+{
+    long   bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */
+/* 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   readIndex;  /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */
+    long   bigMask;    /* Used for wrapping indices with extra bit to distinguish full/empty. */
+    long   smallMask;  /* Used for fitting indices to buffer. */
+    char *buffer;
+}
+RingBuffer;
+/*
+ * Initialize Ring Buffer.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );
+
+/* Clear buffer. Should only be called when buffer is NOT being read. */
+void RingBuffer_Flush( RingBuffer *rbuf );
+
+/* Return number of bytes available for writing. */
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );
+/* Return number of bytes available for read. */
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );
+/* Return bytes written. */
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );
+/* Return bytes read. */
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );
+
+/* Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,
+                                 void **dataPtr1, long *sizePtr1,
+                                 void **dataPtr2, long *sizePtr2 );
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );
+
+/* Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be read or numBytes, whichever is smaller.
+*/
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,
+                                void **dataPtr1, long *sizePtr1,
+                                void **dataPtr2, long *sizePtr2 );
+
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _RINGBUFFER_H */
diff --git a/w32/vsnet/mod_PortAudio.vcproj b/w32/vsnet/mod_PortAudio.vcproj
index d2da06e1d2..de624fc444 100644
--- a/w32/vsnet/mod_PortAudio.vcproj
+++ b/w32/vsnet/mod_PortAudio.vcproj
@@ -42,7 +42,7 @@
 			<Tool
 				Name="VCCLCompilerTool"
 				Optimization="0"
-				AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\src\include&quot;;&quot;$(ProjectDir)include&quot;;&quot;$(ProjectDir)..\..\libs\apr\include&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_common&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pablio&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_win_wmme&quot;"
+				AdditionalIncludeDirectories="&quot;$(ProjectDir)..\..\src\include&quot;;&quot;$(ProjectDir)include&quot;;&quot;$(ProjectDir)..\..\libs\apr\include&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_common&quot;;&quot;$(ProjectDir)\..\..\..\src\mod\mod_portaudio&quot;;&quot;$(ProjectDir)..\..\libs\portaudio\pa_win_wmme&quot;"
 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
 				MinimalRebuild="true"
 				BasicRuntimeChecks="3"
@@ -194,11 +194,11 @@
 				>
 			</File>
 			<File
-				RelativePath="..\..\libs\portaudio\pablio\pablio.c"
+				RelativePath="..\..\src\mod\mod_portaudio\pablio.c"
 				>
 			</File>
 			<File
-				RelativePath="..\..\libs\portaudio\pablio\ringbuffer.c"
+				RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.c"
 				>
 			</File>
 		</Filter>
@@ -207,6 +207,14 @@
 			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
+			<File
+				RelativePath="..\..\src\mod\mod_portaudio\pablio.h"
+				>
+			</File>
+			<File
+				RelativePath="..\..\src\mod\mod_portaudio\ringbuffer.h"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Resource Files"