From 6668d0282f5c0df9bcaa3fbca6f02fc65e586487 Mon Sep 17 00:00:00 2001
From: Anthony Minessale <anthony.minessale@gmail.com>
Date: Tue, 3 Jan 2006 22:13:59 +0000
Subject: [PATCH] update

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@263 d0543943-73ff-0310-b7d9-9358b9ac24b2
---
 src/mod/aplications/mod_bridgecall.c          |  271 ++++
 src/mod/aplications/mod_bridgecall.vcproj     |  207 +++
 .../aplications/mod_playback/mod_playback.c   |  199 +++
 .../mod_playback/mod_playback.vcproj          |  207 +++
 src/mod/aplications/mod_skel/mod_skel.c       |   54 +
 src/mod/codec/mod_codec_g729/Makefile         |   12 +
 src/mod/codec/mod_codec_g729/mod_codec_g729.c |  203 +++
 .../mod_codec_g729/mod_codec_g729.vcproj      |  211 +++
 src/mod/codec/mod_g711codec/Makefile          |   15 +
 src/mod/codec/mod_g711codec/g711.c            |  312 ++++
 src/mod/codec/mod_g711codec/g711.h            |   60 +
 src/mod/codec/mod_g711codec/mod_g711codec.c   |  303 ++++
 .../codec/mod_g711codec/mod_g711codec.vcproj  |  215 +++
 src/mod/codec/mod_rawaudio/mod_rawaudio.c     |  215 +++
 .../codec/mod_rawaudio/mod_rawaudio.vcproj    |  211 +++
 src/mod/codec/mod_speexcodec/Makefile         |   12 +
 src/mod/codec/mod_speexcodec/mod_speexcodec.c |  342 ++++
 .../mod_speexcodec/mod_speexcodec.vcproj      |  211 +++
 .../mod_dialplan_demo/mod_dialplan_demo.c     |  124 ++
 .../mod_dialplan_demo.vcproj                  |  207 +++
 src/mod/endpoints/mod_exosip/Makefile         |   26 +
 src/mod/endpoints/mod_exosip/mod_exosip.c     | 1409 ++++++++++++++++
 .../endpoints/mod_exosip/mod_exosip.vcproj    |  229 +++
 .../endpoints/mod_exosip/mod_exosip_ccrtp.c   | 1373 ++++++++++++++++
 src/mod/endpoints/mod_exosip/mod_exosip_ucl.c | 1438 +++++++++++++++++
 src/mod/endpoints/mod_iaxchan/Makefile        |   15 +
 .../endpoints/mod_iaxchan/mod_IaxChan.vcproj  |  212 +++
 src/mod/endpoints/mod_iaxchan/mod_iaxchan.c   |  986 +++++++++++
 src/mod/endpoints/mod_opalchan/Makefile       |   12 +
 src/mod/endpoints/mod_opalchan/mod_opalchan.c |  385 +++++
 src/mod/endpoints/mod_portaudio/Makefile      |   19 +
 .../mod_portaudio/mod_PortAudio.vcproj        |  228 +++
 .../endpoints/mod_portaudio/mod_portaudio.c   |  934 +++++++++++
 src/mod/endpoints/mod_portaudio/pablio.c      |  327 ++++
 src/mod/endpoints/mod_portaudio/pablio.h      |  109 ++
 src/mod/endpoints/mod_portaudio/ringbuffer.c  |  199 +++
 src/mod/endpoints/mod_portaudio/ringbuffer.h  |  103 ++
 src/mod/endpoints/mod_wanchan/mod_wanchan.c   |  634 ++++++++
 .../mod_woomerachan/mod_woomerachan.c         | 1387 ++++++++++++++++
 .../mod_woomerachan/mod_woomerachan.vcproj    |  207 +++
 .../mod_event_test/mod_event_test.c           |  133 ++
 .../mod_event_test/mod_event_test.vcproj      |  207 +++
 .../event_handlers/mod_xmpp_event/Makefile    |   14 +
 .../mod_xmpp_event/mod_xmpp_event.c           |  386 +++++
 .../mod_xmpp_event/mod_xmpp_event.vcproj      |  212 +++
 src/mod/formats/mod_sndfile/Makefile          |   15 +
 src/mod/formats/mod_sndfile/mod_sndfile.c     |  294 ++++
 .../formats/mod_sndfile/mod_sndfilel.vcproj   |  212 +++
 src/mod/timers/mod_softtimer/mod_softtimer.c  |  128 ++
 .../timers/mod_softtimer/mod_softtimer.vcproj |  207 +++
 50 files changed, 15631 insertions(+)
 create mode 100644 src/mod/aplications/mod_bridgecall.c
 create mode 100644 src/mod/aplications/mod_bridgecall.vcproj
 create mode 100644 src/mod/aplications/mod_playback/mod_playback.c
 create mode 100644 src/mod/aplications/mod_playback/mod_playback.vcproj
 create mode 100644 src/mod/aplications/mod_skel/mod_skel.c
 create mode 100644 src/mod/codec/mod_codec_g729/Makefile
 create mode 100644 src/mod/codec/mod_codec_g729/mod_codec_g729.c
 create mode 100644 src/mod/codec/mod_codec_g729/mod_codec_g729.vcproj
 create mode 100644 src/mod/codec/mod_g711codec/Makefile
 create mode 100644 src/mod/codec/mod_g711codec/g711.c
 create mode 100644 src/mod/codec/mod_g711codec/g711.h
 create mode 100644 src/mod/codec/mod_g711codec/mod_g711codec.c
 create mode 100644 src/mod/codec/mod_g711codec/mod_g711codec.vcproj
 create mode 100644 src/mod/codec/mod_rawaudio/mod_rawaudio.c
 create mode 100644 src/mod/codec/mod_rawaudio/mod_rawaudio.vcproj
 create mode 100644 src/mod/codec/mod_speexcodec/Makefile
 create mode 100644 src/mod/codec/mod_speexcodec/mod_speexcodec.c
 create mode 100644 src/mod/codec/mod_speexcodec/mod_speexcodec.vcproj
 create mode 100644 src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.c
 create mode 100644 src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.vcproj
 create mode 100644 src/mod/endpoints/mod_exosip/Makefile
 create mode 100644 src/mod/endpoints/mod_exosip/mod_exosip.c
 create mode 100644 src/mod/endpoints/mod_exosip/mod_exosip.vcproj
 create mode 100644 src/mod/endpoints/mod_exosip/mod_exosip_ccrtp.c
 create mode 100644 src/mod/endpoints/mod_exosip/mod_exosip_ucl.c
 create mode 100644 src/mod/endpoints/mod_iaxchan/Makefile
 create mode 100644 src/mod/endpoints/mod_iaxchan/mod_IaxChan.vcproj
 create mode 100644 src/mod/endpoints/mod_iaxchan/mod_iaxchan.c
 create mode 100644 src/mod/endpoints/mod_opalchan/Makefile
 create mode 100644 src/mod/endpoints/mod_opalchan/mod_opalchan.c
 create mode 100644 src/mod/endpoints/mod_portaudio/Makefile
 create mode 100644 src/mod/endpoints/mod_portaudio/mod_PortAudio.vcproj
 create mode 100644 src/mod/endpoints/mod_portaudio/mod_portaudio.c
 create mode 100644 src/mod/endpoints/mod_portaudio/pablio.c
 create mode 100644 src/mod/endpoints/mod_portaudio/pablio.h
 create mode 100644 src/mod/endpoints/mod_portaudio/ringbuffer.c
 create mode 100644 src/mod/endpoints/mod_portaudio/ringbuffer.h
 create mode 100644 src/mod/endpoints/mod_wanchan/mod_wanchan.c
 create mode 100644 src/mod/endpoints/mod_woomerachan/mod_woomerachan.c
 create mode 100644 src/mod/endpoints/mod_woomerachan/mod_woomerachan.vcproj
 create mode 100644 src/mod/event_handlers/mod_event_test/mod_event_test.c
 create mode 100644 src/mod/event_handlers/mod_event_test/mod_event_test.vcproj
 create mode 100644 src/mod/event_handlers/mod_xmpp_event/Makefile
 create mode 100644 src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.c
 create mode 100644 src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.vcproj
 create mode 100644 src/mod/formats/mod_sndfile/Makefile
 create mode 100644 src/mod/formats/mod_sndfile/mod_sndfile.c
 create mode 100644 src/mod/formats/mod_sndfile/mod_sndfilel.vcproj
 create mode 100644 src/mod/timers/mod_softtimer/mod_softtimer.c
 create mode 100644 src/mod/timers/mod_softtimer/mod_softtimer.vcproj

diff --git a/src/mod/aplications/mod_bridgecall.c b/src/mod/aplications/mod_bridgecall.c
new file mode 100644
index 0000000000..facdca0734
--- /dev/null
+++ b/src/mod/aplications/mod_bridgecall.c
@@ -0,0 +1,271 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_bridgecall.c -- Channel Bridge Application Module
+ *
+ */
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+static const char modname[] = "mod_bridgecall";
+
+struct audio_bridge_data {
+	switch_core_session *session_a;
+	switch_core_session *session_b;
+	int running;
+};
+
+static void *audio_bridge_thread(switch_thread *thread, void *obj)
+{
+	struct switch_core_thread_session *data = obj;
+
+	switch_channel *chan_a, *chan_b;
+	switch_frame *read_frame;
+	switch_core_session *session_a, *session_b;
+
+	session_a = data->objs[0];
+	session_b = data->objs[1];
+
+	chan_a = switch_core_session_get_channel(session_a);
+	chan_b = switch_core_session_get_channel(session_b);
+
+	while(data->running > 0) {
+		switch_channel_state b_state = switch_channel_get_state(chan_b);
+
+		switch (b_state) {
+case CS_HANGUP:
+	data->running = -1;
+	continue;
+	break;
+default:
+	break;
+		}
+
+		if (switch_channel_has_dtmf(chan_a)) {
+			char dtmf[128];
+			switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
+			switch_core_session_send_dtmf(session_b, dtmf);
+		}
+		if (switch_core_session_read_frame(session_a, &read_frame, -1) == SWITCH_STATUS_SUCCESS && read_frame->datalen) {
+			if (switch_core_session_write_frame(session_b, read_frame, -1) != SWITCH_STATUS_SUCCESS) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: Bad Frame.... %d Bubye!\n", read_frame->datalen);
+				data->running = -1;
+			}
+		} else {			
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: Bad Frame.... %d Bubye!\n", read_frame->datalen);
+			data->running = -1;
+		}  
+	}
+
+	switch_channel_hangup(chan_b);
+	data->running = 0;
+
+	return NULL;
+}
+
+
+static switch_status audio_bridge_on_hangup(switch_core_session *session)
+{
+	switch_core_session *other_session;
+	switch_channel *channel = NULL, *other_channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	other_session = switch_channel_get_private(channel);
+	assert(other_session != NULL);
+
+	other_channel = switch_core_session_get_channel(other_session);
+	assert(other_channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel), switch_channel_get_name(other_channel));
+
+	switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
+	switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status audio_bridge_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
+
+	/* put the channel in a passive state so we can loop audio to it */
+	if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+		switch_channel_set_state(channel, CS_TRANSMIT);
+		return SWITCH_STATUS_FALSE;
+	}
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_event_handler_table audio_bridge_peer_event_handlers = {
+	/*.on_init*/		NULL,
+	/*.on_ring*/		audio_bridge_on_ring,
+	/*.on_execute*/		NULL,
+	/*.on_hangup*/		audio_bridge_on_hangup,
+	/*.on_loopback*/	NULL,
+	/*.on_transmit*/	NULL
+};
+
+static const switch_event_handler_table audio_bridge_caller_event_handlers = {
+	/*.on_init*/		NULL,
+	/*.on_ring*/		NULL,
+	/*.on_execute*/		NULL,
+	/*.on_hangup*/		audio_bridge_on_hangup,
+	/*.on_loopback*/	NULL,
+	/*.on_transmit*/	NULL
+};
+
+static void audio_bridge_function(switch_core_session *session, char *data)
+{
+	switch_channel *caller_channel, *peer_channel;
+	switch_core_session *peer_session;
+	switch_caller_profile *caller_profile, *caller_caller_profile;
+	char chan_type[128]= {'\0'}, *chan_data;
+	int timelimit = 60; /* probably a useful option to pass in when there's time */
+	caller_channel = switch_core_session_get_channel(session);
+	assert(caller_channel != NULL);
+
+
+	strncpy(chan_type, data, sizeof(chan_type));
+
+	if ((chan_data = strchr(chan_type, '/'))) {
+		*chan_data = '\0';
+		chan_data++;
+	}
+
+	caller_caller_profile = switch_channel_get_caller_profile(caller_channel);
+	caller_profile = switch_caller_profile_new(session,
+		caller_caller_profile->dialplan,
+		caller_caller_profile->caller_id_name,
+		caller_caller_profile->caller_id_number,
+		caller_caller_profile->network_addr,
+		NULL,
+		NULL,
+		chan_data);
+
+
+
+	if (switch_core_session_outgoing_channel(session, chan_type, caller_profile, &peer_session) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DOH!\n");
+		switch_channel_hangup(caller_channel);
+		return;
+	} else {
+		struct switch_core_thread_session this_audio_thread, other_audio_thread;
+		time_t start;
+
+		peer_channel = switch_core_session_get_channel(peer_session);
+		memset(&other_audio_thread, 0, sizeof(other_audio_thread));
+		memset(&this_audio_thread, 0, sizeof(this_audio_thread));
+		other_audio_thread.objs[0] = session;
+		other_audio_thread.objs[1] = peer_session;
+		other_audio_thread.running = 5;
+
+		this_audio_thread.objs[0] = peer_session;
+		this_audio_thread.objs[1] = session;
+		this_audio_thread.running = 2;
+
+
+		switch_channel_set_private(caller_channel, peer_session);
+		switch_channel_set_private(peer_channel, session);
+		switch_channel_set_event_handlers(caller_channel, &audio_bridge_caller_event_handlers);		
+		switch_channel_set_event_handlers(peer_channel, &audio_bridge_peer_event_handlers);
+		switch_core_session_thread_launch(peer_session);
+
+		for(;;) {
+			int state = switch_channel_get_state(peer_channel);
+			if (state > CS_RING) {
+				break;
+			}
+			switch_yield(1000);
+		}
+
+		time(&start);
+		while(switch_channel_get_state(caller_channel) == CS_EXECUTE && 
+			switch_channel_get_state(peer_channel) == CS_TRANSMIT && 
+			!switch_channel_test_flag(peer_channel, CF_ANSWERED) && 
+			((time(NULL) - start) < timelimit)) {
+				switch_yield(20000);
+		}
+
+		if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
+			switch_channel_answer(caller_channel);
+
+			switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
+			audio_bridge_thread(NULL, (void *) &this_audio_thread);
+			switch_channel_hangup(peer_channel);
+			if (other_audio_thread.running > 0) {
+				other_audio_thread.running = -1;
+				/* wait for the other audio thread */
+				while (other_audio_thread.running) {
+					switch_yield(1000);
+				}
+			}
+
+
+		}
+	}
+
+	switch_channel_hangup(caller_channel);
+	switch_channel_hangup(peer_channel);
+}
+
+
+static const switch_application_interface bridge_application_interface = {
+	/*.interface_name*/			"bridge",
+	/*.application_function*/	audio_bridge_function
+};
+
+
+static const switch_loadable_module_interface mod_bridgecall_module_interface = {
+	/*.module_name = */			modname,
+	/*.endpoint_interface = */	NULL,
+	/*.timer_interface = */		NULL,
+	/*.dialplan_interface = */	NULL,
+	/*.codec_interface = */		NULL,
+	/*.application_interface*/	&bridge_application_interface
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &mod_bridgecall_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
diff --git a/src/mod/aplications/mod_bridgecall.vcproj b/src/mod/aplications/mod_bridgecall.vcproj
new file mode 100644
index 0000000000..86366d09e7
--- /dev/null
+++ b/src/mod/aplications/mod_bridgecall.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_bridgecall"
+	ProjectGUID="{E1794405-29D4-466D-9BE3-DD2344C2A663}"
+	RootNamespace="mod_bridgecall"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_bridgecall.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_bridgecall.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_bridgecall.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_bridgecall.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_bridgecall.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_bridgecall.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/aplications/mod_playback/mod_playback.c b/src/mod/aplications/mod_playback/mod_playback.c
new file mode 100644
index 0000000000..757f7e7906
--- /dev/null
+++ b/src/mod/aplications/mod_playback/mod_playback.c
@@ -0,0 +1,199 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_playback.c -- Raw Audio File Streaming Application Module
+ *
+ */
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+static const char modname[] = "mod_playback";
+
+
+void playback_function(switch_core_session *session, char *data)
+{
+	switch_channel *channel;
+	short buf[960];
+	char dtmf[128];
+	int interval = 0, samples = 0;
+	size_t len = 0, ilen = 0;
+	switch_frame write_frame;
+	switch_timer timer;
+	switch_core_thread_session thread_session;
+	switch_codec codec;
+	switch_memory_pool *pool = switch_core_session_get_pool(session);
+	switch_file_handle fh;
+	char *codec_name;
+	int x;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	if (switch_core_file_open(&fh,
+		data,
+		SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
+		switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+			switch_channel_hangup(channel);
+			return;
+	}
+
+	switch_channel_answer(channel);
+
+	write_frame.data = buf;
+	write_frame.buflen = sizeof(buf);
+
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OPEN FILE %s %dhz %d channels\n", data, fh.samplerate, fh.channels);
+
+	interval = 20;
+	samples = (fh.samplerate / 50) * fh.channels;
+	len = samples * 2;
+
+	codec_name = "L16";
+
+	if (switch_core_codec_init(&codec,
+		codec_name,
+		fh.samplerate,
+		interval,
+		fh.channels,
+		SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+		NULL,
+		pool) == SWITCH_STATUS_SUCCESS) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activated\n");
+			write_frame.codec = &codec;
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Raw Codec Activation Failed %s@%dhz %d channels %dms\n", codec_name, fh.samplerate, fh.channels, interval);
+		switch_core_file_close(&fh);
+		switch_channel_hangup(channel);
+		return;
+	}
+
+	if (switch_core_timer_init(&timer, "soft", interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer failed!\n");
+		switch_core_codec_destroy(&codec);
+		switch_core_file_close(&fh);
+		switch_channel_hangup(channel);
+		return;
+	}
+	write_frame.rate = fh.samplerate;
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "setup timer success %d bytes per %d ms!\n", len, interval);
+
+	/* start a thread to absorb incoming audio */
+	switch_core_service_session(session, &thread_session);
+	ilen = samples;
+	while(switch_channel_get_state(channel) == CS_EXECUTE) {
+		int done = 0;
+
+		if (switch_channel_has_dtmf(channel)) {
+			switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DTMF [%s]\n", dtmf);
+
+			switch (*dtmf) {
+			case '*':
+				done = 1;
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (done) {
+			break;
+		}
+
+		switch_core_file_read(&fh, buf, &ilen);
+
+		if (ilen <= 0) {
+			break;
+		}
+
+		write_frame.datalen = ilen * 2;
+		write_frame.samples = (int)ilen;
+#ifdef SWAP_LINEAR
+		switch_swap_linear(write_frame.data, (int)write_frame.datalen / 2);
+#endif
+		if (switch_core_session_write_frame(session, &write_frame, -1) != SWITCH_STATUS_SUCCESS) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n");
+			break;
+		}
+
+		if ((x = switch_core_timer_next(&timer)) < 0) {
+			break;
+		}
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
+	switch_core_file_close(&fh);
+
+	/* End the audio absorbing thread */
+	switch_core_thread_session_end(&thread_session);
+
+	switch_core_timer_destroy(&timer);
+
+	switch_core_codec_destroy(&codec);
+
+	switch_channel_hangup(channel);
+}
+
+static const switch_application_interface playback_application_interface = {
+	/*.interface_name*/ "playback",
+	/*.application_function*/ playback_function
+};
+
+static const switch_loadable_module_interface mod_playback_module_interface = {
+	/*.module_name = */			modname,
+	/*.endpoint_interface = */	NULL,
+	/*.timer_interface = */		NULL,
+	/*.dialplan_interface = */	NULL,
+	/*.codec_interface = */		NULL,
+	/*.application_interface*/	&playback_application_interface
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &mod_playback_module_interface;
+
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* 'switch_module_runtime' will start up in a thread by itself just by having it exist 
+if it returns anything but SWITCH_STATUS_TERM it will be called again automaticly
+*/
+
+
+//switch_status switch_module_runtime(void)
+
+
+
+
diff --git a/src/mod/aplications/mod_playback/mod_playback.vcproj b/src/mod/aplications/mod_playback/mod_playback.vcproj
new file mode 100644
index 0000000000..a63395a01c
--- /dev/null
+++ b/src/mod/aplications/mod_playback/mod_playback.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_playback"
+	ProjectGUID="{78100236-7CEA-4948-96CC-E8ED3160329C}"
+	RootNamespace="mod_playback"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_playback.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_playback.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_playback.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_playback.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_playback.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_playback.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/aplications/mod_skel/mod_skel.c b/src/mod/aplications/mod_skel/mod_skel.c
new file mode 100644
index 0000000000..21126d1f3e
--- /dev/null
+++ b/src/mod/aplications/mod_skel/mod_skel.c
@@ -0,0 +1,54 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_skel.c -- Framework Demo Module
+ *
+ */
+#include <switch.h>
+
+static const char modname[] = "mod_skel";
+
+static switch_loadable_module_interface skel_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+switch_status switch_module_load(switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &skel_module_interface;
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hello World!\n");
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
diff --git a/src/mod/codec/mod_codec_g729/Makefile b/src/mod/codec/mod_codec_g729/Makefile
new file mode 100644
index 0000000000..6657b4c1fa
--- /dev/null
+++ b/src/mod/codec/mod_codec_g729/Makefile
@@ -0,0 +1,12 @@
+CFLAGS += -I/usr/local/include/libg729
+LDFLAGS +=-lg729
+
+all:	$(MOD).so
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o
+	$(CC) $(SOLINK) $(MOD).o -o $(MOD).so $(LDFLAGS) -lspeex
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/codec/mod_codec_g729/mod_codec_g729.c b/src/mod/codec/mod_codec_g729/mod_codec_g729.c
new file mode 100644
index 0000000000..e85d461ea1
--- /dev/null
+++ b/src/mod/codec/mod_codec_g729/mod_codec_g729.c
@@ -0,0 +1,203 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Michael Jerris <mike@jerris.com>
+ *
+ * mod_codec_g729.c -- G729 Codec Module
+ *
+ */
+#include "switch.h"
+#include "g729.h"
+
+static const char modname[] = "mod_codec_g729";
+
+struct g729_context {
+	struct dec_state decoder_object;
+	struct cod_state encoder_object;
+};
+
+static switch_status switch_g729_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)
+{
+	struct g729_context *context = NULL;
+	int encoding, decoding;
+
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(struct g729_context))))) {
+		return SWITCH_STATUS_FALSE;
+	} else {
+		if (encoding) {
+			g729_init_coder(&context->encoder_object, 0);
+		}
+		if (decoding) {
+			g729_init_decoder(&context->decoder_object);
+		}
+
+		codec->private = context;
+
+		return SWITCH_STATUS_SUCCESS;
+	}
+}
+
+static switch_status switch_g729_destroy(switch_codec *codec)
+{
+	codec->private = NULL;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status switch_g729_encode(switch_codec *codec,
+										switch_codec *other_codec,
+										void *decoded_data,
+										size_t decoded_data_len,
+										int decoded_rate,
+										void *encoded_data,
+										size_t *encoded_data_len,
+										int *encoded_rate,
+										unsigned int *flag)
+{
+	struct g729_context *context = codec->private;
+	int cbret = 0;
+
+	if (!context) {
+		return SWITCH_STATUS_FALSE;
+	}
+	if (decoded_data_len % 160 == 0) {
+		unsigned int new_len = 0;
+		INT16 *ddp = decoded_data;
+		char *edp = encoded_data;
+		int x;
+		int loops = (int) decoded_data_len / 160;
+
+		for(x = 0; x < loops && new_len < *encoded_data_len; x++) {
+			g729_coder(&context->encoder_object, ddp, edp, &cbret);
+			edp += 10;
+			ddp += 80;
+			new_len += 10;
+		}
+		if( new_len <= *encoded_data_len ) {
+			*encoded_data_len = new_len;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "buffer overflow!!! %u >= %u\n", new_len, *encoded_data_len);
+			return SWITCH_STATUS_FALSE;			
+		}
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status switch_g729_decode(switch_codec *codec,
+										switch_codec *other_codec,
+										void *encoded_data,
+										size_t encoded_data_len,
+										int encoded_rate,
+										void *decoded_data,
+										size_t *decoded_data_len,
+										int *decoded_rate,
+										unsigned int *flag) 
+{
+	struct g729_context *context = codec->private;
+
+	if (!context) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+
+	if (encoded_data_len % 10 == 0) {
+		int loops = (int) encoded_data_len / 10;
+		char *edp = encoded_data;
+		short *ddp = decoded_data;
+		int x;
+		unsigned int new_len = 0;
+		for(x = 0; x < loops && new_len < *decoded_data_len; x++) {
+			g729_decoder(&context->decoder_object, ddp, edp, 10);
+			ddp += 80;
+			edp += 10;
+			new_len += 160;
+		}
+		if (new_len <= *decoded_data_len) {
+			*decoded_data_len = new_len;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "buffer overflow!!!\n");
+			return SWITCH_STATUS_FALSE;
+		}
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "yo this frame is an odd size [%d]\n", encoded_data_len);
+	}
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* Registration */
+
+static const switch_codec_implementation g729_8k_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				64000,
+	/*.microseconds_per_frame*/			20000,
+	/*.samples_per_frame*/				160,
+	/*.bytes_per_frame*/				320,
+	/*.encoded_bytes_per_frame*/		20,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			24,
+	/*.init*/							switch_g729_init,
+	/*.encode*/							switch_g729_encode,
+	/*.decode*/							switch_g729_decode,
+	/*.destroy*/						switch_g729_destroy,
+};
+
+static const switch_codec_interface g729_codec_interface = {
+	/*.interface_name*/					"g729",
+	/*.codec_type*/						SWITCH_CODEC_TYPE_AUDIO,
+	/*.ianacode*/						18,
+	/*.iananame*/						"G729",
+	/*.implementations*/				&g729_8k_implementation,
+};
+
+static switch_loadable_module_interface g729_module_interface = {
+	/*.module_name*/					modname,
+	/*.endpoint_interface*/				NULL,
+	/*.timer_interface*/				NULL,
+	/*.dialplan_interface*/				NULL,
+	/*.codec_interface*/				&g729_codec_interface,
+	/*.application_interface*/			NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &g729_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
diff --git a/src/mod/codec/mod_codec_g729/mod_codec_g729.vcproj b/src/mod/codec/mod_codec_g729/mod_codec_g729.vcproj
new file mode 100644
index 0000000000..9b7ecdaa62
--- /dev/null
+++ b/src/mod/codec/mod_codec_g729/mod_codec_g729.vcproj
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_codec_g729"
+	ProjectGUID="{1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}"
+	RootNamespace="mod_codec_g729"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_CodecG729 Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libg729.lib FreeSwitchCore.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_codec_g729.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Debug&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729\Debug&quot;;..\..\..\w32\vsnet\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_codec_g729.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_codec_g729.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_CodecG729 Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libg729.lib FreeSwitchCore.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_codec_g729.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Release&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729\Release&quot;;..\..\..\w32\vsnet\Release"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_codec_g729.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="mod_codec_g729.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/codec/mod_g711codec/Makefile b/src/mod/codec/mod_g711codec/Makefile
new file mode 100644
index 0000000000..60ab1c465c
--- /dev/null
+++ b/src/mod/codec/mod_g711codec/Makefile
@@ -0,0 +1,15 @@
+
+all:	$(MOD).so
+
+g711.o: g711.c g711.h
+	$(CC) -c -O2 -pthread -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE g711.c -o g711.o
+
+$(MOD).so: $(MOD).c g711.o
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o
+	$(CC) $(SOLINK) g711.o $(MOD).o -o $(MOD).so $(LDFLAGS)
+
+
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/codec/mod_g711codec/g711.c b/src/mod/codec/mod_g711codec/g711.c
new file mode 100644
index 0000000000..b69eb4f912
--- /dev/null
+++ b/src/mod/codec/mod_g711codec/g711.c
@@ -0,0 +1,312 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * December 30, 1994:
+ * Functions linear2alaw, linear2ulaw have been updated to correctly
+ * convert unquantized 16 bit values.
+ * Tables for direct u- to A-law and A- to u-law conversions have been
+ * corrected.
+ * Borge Lindberg, Center for PersonKommunikation, Aalborg University.
+ * bli@cpk.auc.dk
+ *
+ */
+/*
+ * Downloaded from comp.speech site in Cambridge.
+ *
+ */
+
+#include "g711.h"
+
+/*
+ * g711.c
+ *
+ * u-law, A-law and linear PCM conversions.
+ */
+#define	SIGN_BIT	(0x80)		/* Sign bit for a A-law byte. */
+#define	QUANT_MASK	(0xf)		/* Quantization field mask. */
+#define	NSEGS		(8)		/* Number of A-law segments. */
+#define	SEG_SHIFT	(4)		/* Left shift for segment number. */
+#define	SEG_MASK	(0x70)		/* Segment field mask. */
+
+static short seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF,
+				0x1FF, 0x3FF, 0x7FF, 0xFFF};
+static short seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF,
+				0x3FF, 0x7FF, 0xFFF, 0x1FFF};
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = {			/* u- to A-law conversions */
+	1,	1,	2,	2,	3,	3,	4,	4,
+	5,	5,	6,	6,	7,	7,	8,	8,
+	9,	10,	11,	12,	13,	14,	15,	16,
+	17,	18,	19,	20,	21,	22,	23,	24,
+	25,	27,	29,	31,	33,	34,	35,	36,
+	37,	38,	39,	40,	41,	42,	43,	44,
+	46,	48,	49,	50,	51,	52,	53,	54,
+	55,	56,	57,	58,	59,	60,	61,	62,
+	64,	65,	66,	67,	68,	69,	70,	71,
+	72,	73,	74,	75,	76,	77,	78,	79,
+/* corrected:
+	81,	82,	83,	84,	85,	86,	87,	88, 
+   should be: */
+	80,	82,	83,	84,	85,	86,	87,	88,
+	89,	90,	91,	92,	93,	94,	95,	96,
+	97,	98,	99,	100,	101,	102,	103,	104,
+	105,	106,	107,	108,	109,	110,	111,	112,
+	113,	114,	115,	116,	117,	118,	119,	120,
+	121,	122,	123,	124,	125,	126,	127,	128};
+
+unsigned char _a2u[128] = {			/* A- to u-law conversions */
+	1,	3,	5,	7,	9,	11,	13,	15,
+	16,	17,	18,	19,	20,	21,	22,	23,
+	24,	25,	26,	27,	28,	29,	30,	31,
+	32,	32,	33,	33,	34,	34,	35,	35,
+	36,	37,	38,	39,	40,	41,	42,	43,
+	44,	45,	46,	47,	48,	48,	49,	49,
+	50,	51,	52,	53,	54,	55,	56,	57,
+	58,	59,	60,	61,	62,	63,	64,	64,
+	65,	66,	67,	68,	69,	70,	71,	72,
+/* corrected:
+	73,	74,	75,	76,	77,	78,	79,	79,
+   should be: */
+	73,	74,	75,	76,	77,	78,	79,	80,
+	80,	81,	82,	83,	84,	85,	86,	87,
+	88,	89,	90,	91,	92,	93,	94,	95,
+	96,	97,	98,	99,	100,	101,	102,	103,
+	104,	105,	106,	107,	108,	109,	110,	111,
+	112,	113,	114,	115,	116,	117,	118,	119,
+	120,	121,	122,	123,	124,	125,	126,	127};
+
+static short search(
+   short val,
+   short *table,
+   short size)
+{
+   short i;
+   
+   for (i = 0; i < size; i++) {
+	  if (val <= *table++)
+	 return (i);
+   }
+   return (size);
+}
+
+/*
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ *		Linear Input Code	Compressed Code
+ *	------------------------	---------------
+ *	0000000wxyza			000wxyz
+ *	0000001wxyza			001wxyz
+ *	000001wxyzab			010wxyz
+ *	00001wxyzabc			011wxyz
+ *	0001wxyzabcd			100wxyz
+ *	001wxyzabcde			101wxyz
+ *	01wxyzabcdef			110wxyz
+ *	1wxyzabcdefg			111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char
+linear2alaw(short pcm_val)	/* 2's complement (16-bit range) */
+{
+   short	 mask;
+   short	 seg;
+   unsigned char aval;
+   
+   pcm_val = pcm_val >> 3;
+
+   if (pcm_val >= 0) {
+	  mask = 0xD5;		/* sign (7th) bit = 1 */
+   } else {
+	  mask = 0x55;		/* sign bit = 0 */
+	  pcm_val = -pcm_val - 1;
+   }
+   
+   /* Convert the scaled magnitude to segment number. */
+   seg = search(pcm_val, seg_aend, 8);
+   
+   /* Combine the sign, segment, and quantization bits. */
+   
+   if (seg >= 8)		/* out of range, return maximum value. */
+	  return (unsigned char) (0x7F ^ mask);
+   else {
+	  aval = (unsigned char) seg << SEG_SHIFT;
+	  if (seg < 2)
+	 aval |= (pcm_val >> 1) & QUANT_MASK;
+	  else
+	 aval |= (pcm_val >> seg) & QUANT_MASK;
+	  return (aval ^ mask);
+   }
+}
+
+/*
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM
+ *
+ */
+short
+alaw2linear(
+   unsigned char	a_val)
+{
+   short t;
+   short seg;
+   
+   a_val ^= 0x55;
+   
+   t = (a_val & QUANT_MASK) << 4;
+   seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+   switch (seg) {
+   case 0:
+	  t += 8;
+	  break;
+   case 1:
+	  t += 0x108;
+	  break;
+   default:
+	  t += 0x108;
+	  t <<= seg - 1;
+   }
+   return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+#define	BIAS		(0x84)		/* Bias for linear code. */
+#define CLIP			8159
+
+/*
+* linear2ulaw() - Convert a linear PCM value to u-law
+*
+* In order to simplify the encoding process, the original linear magnitude
+* is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+* (33 - 8191). The result can be seen in the following encoding table:
+*
+*	Biased Linear Input Code	Compressed Code
+*	------------------------	---------------
+*	00000001wxyza			000wxyz
+*	0000001wxyzab			001wxyz
+*	000001wxyzabc			010wxyz
+*	00001wxyzabcd			011wxyz
+*	0001wxyzabcde			100wxyz
+*	001wxyzabcdef			101wxyz
+*	01wxyzabcdefg			110wxyz
+*	1wxyzabcdefgh			111wxyz
+*
+* Each biased linear code has a leading 1 which identifies the segment
+* number. The value of the segment number is equal to 7 minus the number
+* of leading 0's. The quantization interval is directly available as the
+* four bits wxyz.  * The trailing bits (a - h) are ignored.
+*
+* Ordinarily the complement of the resulting code word is used for
+* transmission, and so the code word is complemented before it is returned.
+*
+* For further information see John C. Bellamy's Digital Telephony, 1982,
+* John Wiley & Sons, pps 98-111 and 472-476.
+*/
+unsigned char
+linear2ulaw(
+   short pcm_val)	/* 2's complement (16-bit range) */
+{
+   short		 mask;
+   short	 seg;
+   unsigned char uval;
+   
+   /* Get the sign and the magnitude of the value. */
+   pcm_val = pcm_val >> 2;
+   if (pcm_val < 0) {
+	  pcm_val = -pcm_val;
+	  mask = 0x7F;
+   } else {
+	  mask = 0xFF;
+   }
+   if ( pcm_val > CLIP ) pcm_val = CLIP;		/* clip the magnitude */
+   pcm_val += (BIAS >> 2);
+   
+   /* Convert the scaled magnitude to segment number. */
+   seg = search(pcm_val, seg_uend, 8);
+   
+   /*
+   * Combine the sign, segment, quantization bits;
+   * and complement the code word.
+   */
+   if (seg >= 8)		/* out of range, return maximum value. */
+	  return (unsigned char) (0x7F ^ mask);
+   else {
+	  uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
+	  return (uval ^ mask);
+   }
+   
+}
+
+/*
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+short
+ulaw2linear(
+   unsigned char	u_val)
+{
+   short t;
+   
+   /* Complement to obtain normal u-law value. */
+   u_val = ~u_val;
+   
+   /*
+	* Extract and bias the quantization bits. Then
+	* shift up by the segment number and subtract out the bias.
+	*/
+   t = ((u_val & QUANT_MASK) << 3) + BIAS;
+   t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+   
+   return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/* A-law to u-law conversion */
+unsigned char
+alaw2ulaw(
+   unsigned char	aval)
+{
+   aval &= 0xff;
+   return (unsigned char) ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+	   (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/* u-law to A-law conversion */
+unsigned char
+ulaw2alaw(
+   unsigned char	uval)
+{
+   uval &= 0xff;
+   return (unsigned char) ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+			   (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
+
+/* ---------- end of g711.c ----------------------------------------------------- */
diff --git a/src/mod/codec/mod_g711codec/g711.h b/src/mod/codec/mod_g711codec/g711.h
new file mode 100644
index 0000000000..015c23267c
--- /dev/null
+++ b/src/mod/codec/mod_g711codec/g711.h
@@ -0,0 +1,60 @@
+/*
+ * This source code is a product of Sun Microsystems, Inc. and is provided
+ * for unrestricted use.  Users may copy or modify this source code without
+ * charge.
+ *
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun source code is provided with no support and without any obligation on
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * December 30, 1994:
+ * Functions linear2alaw, linear2ulaw have been updated to correctly
+ * convert unquantized 16 bit values.
+ * Tables for direct u- to A-law and A- to u-law conversions have been
+ * corrected.
+ * Borge Lindberg, Center for PersonKommunikation, Aalborg University.
+ * bli@cpk.auc.dk
+ *
+ */
+/*
+ * Downloaded from comp.speech site in Cambridge.
+ *
+ */
+
+#ifndef _G711_H_
+#define _G711_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+unsigned char	linear2alaw(short pcm_val);
+short		alaw2linear(unsigned char a_val);
+unsigned char	linear2ulaw(short pcm_val);
+short		ulaw2linear(unsigned char u_val);
+unsigned char	alaw2ulaw(unsigned char aval);
+unsigned char	ulaw2alaw(unsigned char uval);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _G711_H_ */
diff --git a/src/mod/codec/mod_g711codec/mod_g711codec.c b/src/mod/codec/mod_g711codec/mod_g711codec.c
new file mode 100644
index 0000000000..e1cd6fce69
--- /dev/null
+++ b/src/mod/codec/mod_g711codec/mod_g711codec.c
@@ -0,0 +1,303 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_g711codec.c -- G711 Ulaw/Alaw Codec Module
+ *
+ */
+#include <switch.h>
+#include "g711.h"
+
+
+static const char modname[] = "mod_g711codec";
+
+
+static switch_status switch_g711u_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)
+{
+	int encoding, decoding;
+
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!(encoding || decoding)) {
+		return SWITCH_STATUS_FALSE;
+	} else {
+		return SWITCH_STATUS_SUCCESS;
+	}
+}
+
+
+static switch_status switch_g711u_encode(switch_codec *codec,
+										 switch_codec *other_codec,
+										 void *decoded_data,
+										 size_t decoded_data_len,
+										 int decoded_rate,
+										 void *encoded_data,
+										 size_t *encoded_data_len,
+										 int *encoded_rate,
+										 unsigned int *flag)
+{
+	short *dbuf;
+	unsigned char *ebuf;
+	size_t i;
+
+	dbuf = decoded_data;
+	ebuf = encoded_data;
+
+	for (i = 0; i < decoded_data_len / sizeof(short); i++) {
+		ebuf[i] = linear2ulaw(dbuf[i]);
+	}
+
+	*encoded_data_len = i;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status switch_g711u_decode(switch_codec *codec,
+										 switch_codec *other_codec,
+										 void *encoded_data,
+										 size_t encoded_data_len,
+										 int encoded_rate,
+										 void *decoded_data,
+										 size_t *decoded_data_len,
+										 int *decoded_rate,
+										 unsigned int *flag) 
+{
+	short *dbuf;
+	unsigned char *ebuf;
+	size_t i;
+
+	dbuf = decoded_data;
+	ebuf = encoded_data;
+
+	if (*flag & SWITCH_CODEC_FLAG_SILENCE) {
+		memset(dbuf, 0, codec->implementation->bytes_per_frame);
+		*decoded_data_len = codec->implementation->bytes_per_frame;
+	} else {
+		for (i = 0; i < encoded_data_len; i++) {
+			dbuf[i] = ulaw2linear(ebuf[i]);
+		}
+
+		*decoded_data_len = i * 2;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status switch_g711u_destroy(switch_codec *codec)
+{
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status switch_g711a_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)
+{
+	int encoding, decoding;
+
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!(encoding || decoding)) {
+		return SWITCH_STATUS_FALSE;
+	} else {
+		return SWITCH_STATUS_SUCCESS;
+	}
+}
+
+
+static switch_status switch_g711a_encode(switch_codec *codec,
+										 switch_codec *other_codec,
+										 void *decoded_data,
+										 size_t decoded_data_len,
+										 int decoded_rate,
+										 void *encoded_data,
+										 size_t *encoded_data_len,
+										 int *encoded_rate,
+										 unsigned int *flag)
+{
+	short *dbuf;
+	unsigned char *ebuf;
+	size_t i;
+
+	dbuf = decoded_data;
+	ebuf = encoded_data;
+
+	for (i = 0; i < decoded_data_len / sizeof(short); i++) {
+		ebuf[i] = linear2alaw(dbuf[i]);
+	}
+
+	*encoded_data_len = i;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status switch_g711a_decode(switch_codec *codec,
+										 switch_codec *other_codec,
+										 void *encoded_data,
+										 size_t encoded_data_len,
+										 int encoded_rate,
+										 void *decoded_data,
+										 size_t *decoded_data_len,
+										 int *decoded_rate,
+										 unsigned int *flag) 
+{
+	short *dbuf;
+	unsigned char *ebuf;
+	size_t i;
+
+	dbuf = decoded_data;
+	ebuf = encoded_data;
+
+	if (*flag & SWITCH_CODEC_FLAG_SILENCE) {
+		memset(dbuf, 0, codec->implementation->bytes_per_frame);
+		*decoded_data_len = codec->implementation->bytes_per_frame;
+	} else {
+		for (i = 0; i < encoded_data_len; i++) {
+			dbuf[i] = alaw2linear(ebuf[i]);
+		}
+
+		*decoded_data_len = i * 2;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status switch_g711a_destroy(switch_codec *codec)
+{
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* Registration */
+
+
+static const switch_codec_implementation g711u_8k_60ms_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				19200,
+	/*.microseconds_per_frame*/			60000,
+	/*.samples_per_frame*/				480,
+	/*.bytes_per_frame*/				960,
+	/*.encoded_bytes_per_frame*/		480,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			1,
+	/*.init*/							switch_g711u_init,
+	/*.encode*/							switch_g711u_encode,
+	/*.decode*/							switch_g711u_decode,
+	/*.destroy*/						switch_g711u_destroy
+};
+
+static const switch_codec_implementation g711u_8k_30ms_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				96000,
+	/*.microseconds_per_frame*/			30000,
+	/*.samples_per_frame*/				240,
+	/*.bytes_per_frame*/				480,
+	/*.encoded_bytes_per_frame*/		240,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			1,
+	/*.init*/							switch_g711u_init,
+	/*.encode*/							switch_g711u_encode,
+	/*.decode*/							switch_g711u_decode,
+	/*.destroy*/						switch_g711u_destroy,
+	/*.next*/							&g711u_8k_60ms_implementation
+};
+
+static const switch_codec_implementation g711u_8k_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				64000,
+	/*.microseconds_per_frame*/			20000,
+	/*.samples_per_frame*/				160,
+	/*.bytes_per_frame*/				320,
+	/*.encoded_bytes_per_frame*/		160,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			1,
+	/*.init*/							switch_g711u_init,
+	/*.encode*/							switch_g711u_encode,
+	/*.decode*/							switch_g711u_decode,
+	/*.destroy*/						switch_g711u_destroy,
+	///*.next*/							&g711u_8k_30ms_implementation
+};
+
+
+static const switch_codec_implementation g711a_8k_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				64000,
+	/*.microseconds_per_frame*/			20000,
+	/*.samples_per_frame*/				160,
+	/*.bytes_per_frame*/				320,
+	/*.encoded_bytes_per_frame*/		160,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			1,
+	/*.init*/							switch_g711a_init,
+	/*.encode*/							switch_g711a_encode,
+	/*.decode*/							switch_g711a_decode,
+	/*.destroy*/						switch_g711a_destroy
+};
+
+
+static const switch_codec_interface g711a_codec_interface = {
+	/*.interface_name*/					"g711 alaw",
+	/*.codec_type*/						SWITCH_CODEC_TYPE_AUDIO,
+	/*.ianacode*/						8,
+	/*.iananame*/						"PCMA",
+	/*.implementations*/				&g711a_8k_implementation
+};
+
+static const switch_codec_interface g711u_codec_interface = {
+	/*.interface_name*/					"g711 ulaw",
+	/*.codec_type*/						SWITCH_CODEC_TYPE_AUDIO,
+	/*.ianacode*/						0,
+	/*.iananame*/						"PCMU",
+	/*.implementations*/				&g711u_8k_implementation,
+	/*.next*/							&g711a_codec_interface
+};
+
+static switch_loadable_module_interface g711_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		&g711u_codec_interface,
+	/*.application_interface*/	NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &g711_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
diff --git a/src/mod/codec/mod_g711codec/mod_g711codec.vcproj b/src/mod/codec/mod_g711codec/mod_g711codec.vcproj
new file mode 100644
index 0000000000..2d79448078
--- /dev/null
+++ b/src/mod/codec/mod_g711codec/mod_g711codec.vcproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_g711codec"
+	ProjectGUID="{B1FE4613-3F4B-4DAF-9714-2472BF8F56AE}"
+	RootNamespace="mod_g711codec"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_g711codec.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_g711codec.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_g711codec.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_g711codec.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_g711codec.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\g711.c"
+				>
+			</File>
+			<File
+				RelativePath=".\mod_g711codec.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\g711.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/codec/mod_rawaudio/mod_rawaudio.c b/src/mod/codec/mod_rawaudio/mod_rawaudio.c
new file mode 100644
index 0000000000..7dca8096a4
--- /dev/null
+++ b/src/mod/codec/mod_rawaudio/mod_rawaudio.c
@@ -0,0 +1,215 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_rawaudio.c -- Raw Signed Linear Codec
+ *
+ */
+#include <switch.h>
+#include <libresample.h>
+
+static const char modname[] = "mod_rawaudio";
+
+
+static switch_status switch_raw_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)
+{
+	int encoding, decoding;
+	struct raw_context *context = NULL;
+
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!(encoding || decoding)) {
+		return SWITCH_STATUS_FALSE;
+	} else {
+		return SWITCH_STATUS_SUCCESS;
+	}
+}
+
+static switch_status switch_raw_encode(switch_codec *codec,
+								 switch_codec *other_codec,
+								 void *decoded_data,
+								 size_t decoded_data_len,
+								 int decoded_rate,
+								 void *encoded_data,
+								 size_t *encoded_data_len,
+								 int *encoded_rate,
+								 unsigned int *flag)
+{
+
+	/* NOOP indicates that the audio in is already the same as the audio out, so no conversion was necessary.*/
+	if (decoded_rate != codec->implementation->samples_per_second) {
+		memcpy(encoded_data, decoded_data, decoded_data_len);
+		*encoded_data_len = decoded_data_len;
+		return SWITCH_STATUS_RESAMPLE;
+	}
+	return SWITCH_STATUS_NOOP;
+}
+
+static switch_status switch_raw_decode(switch_codec *codec,
+								 switch_codec *other_codec,
+								 void *encoded_data,
+								 size_t encoded_data_len,
+								 int encoded_rate,
+								 void *decoded_data,
+								 size_t *decoded_data_len,
+								 int *decoded_rate,
+								 unsigned int *flag) 
+{
+	if (encoded_rate != other_codec->implementation->samples_per_second) {
+		memcpy(decoded_data, encoded_data, encoded_data_len);
+		*decoded_data_len = encoded_data_len;
+		return SWITCH_STATUS_RESAMPLE;
+	}
+	return SWITCH_STATUS_NOOP;
+}
+
+
+static switch_status switch_raw_destroy(switch_codec *codec)
+{
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_codec_implementation raw_32k_implementation = {
+	/*.samples_per_second = */  32000,
+	/*.bits_per_second = */ 512000,
+	/*.microseconds_per_frame = */ 20000,
+	/*.samples_per_frame = */ 640,
+	/*.bytes_per_frame = */ 1280,
+	/*.encoded_bytes_per_frame = */ 1280,
+	/*.number_of_channels = */ 1,
+	/*.pref_frames_per_packet = */ 1,
+	/*.max_frames_per_packet = */ 1,
+	/*.init = */ switch_raw_init,
+	/*.encode = */ switch_raw_encode,
+	/*.decode = */ switch_raw_decode,
+	/*.destroy = */ switch_raw_destroy
+};
+
+static const switch_codec_implementation raw_22k_implementation = {
+	/*.samples_per_second = */ 22050,
+	/*.bits_per_second = */ 352800,
+	/*.microseconds_per_frame = */ 20000,
+	/*.samples_per_frame = */ 441,
+	/*.bytes_per_frame = */ 882,
+	/*.encoded_bytes_per_frame = */ 882,
+	/*.number_of_channels = */ 1,
+	/*.pref_frames_per_packet = */ 1,
+	/*.max_frames_per_packet = */ 1,
+	/*.init = */ switch_raw_init,
+	/*.encode = */ switch_raw_encode,
+	/*.decode = */ switch_raw_decode,
+	/*.destroy = */ switch_raw_destroy,
+	/*.next = */ &raw_32k_implementation
+};
+
+static const switch_codec_implementation raw_16k_implementation = {
+	/*.samples_per_second = */ 16000,
+	/*.bits_per_second = */ 256000,
+	/*.microseconds_per_frame = */ 20000,
+	/*.samples_per_frame = */ 320,
+	/*.bytes_per_frame = */ 640,
+	/*.encoded_bytes_per_frame = */ 640,
+	/*.number_of_channels = */ 1,
+	/*.pref_frames_per_packet = */ 1,
+	/*.max_frames_per_packet = */ 1,
+	/*.init = */ switch_raw_init,
+	/*.encode = */ switch_raw_encode,
+	/*.decode = */ switch_raw_decode,
+	/*.destroy = */ switch_raw_destroy,
+	/*.next = */ &raw_22k_implementation
+};
+
+static const switch_codec_implementation raw_8k_implementation = {
+	/*.samples_per_second = */ 8000,
+	/*.bits_per_second = */ 128000,
+	/*.microseconds_per_frame = */ 20000,
+	/*.samples_per_frame = */ 160,
+	/*.bytes_per_frame = */ 320,
+	/*.encoded_bytes_per_frame = */ 320,
+	/*.number_of_channels = */ 1,
+	/*.pref_frames_per_packet = */ 1,
+	/*.max_frames_per_packet = */ 1,
+	/*.init = */ switch_raw_init,
+	/*.encode = */ switch_raw_encode,
+	/*.decode = */ switch_raw_decode,
+	/*.destroy = */ switch_raw_destroy,
+	/*.next = */ &raw_16k_implementation
+};
+
+
+static const switch_codec_implementation raw_8k_30ms_implementation = {
+	/*.samples_per_second*/				8000,
+	/*.bits_per_second*/				128000,
+	/*.microseconds_per_frame*/			30000,
+	/*.samples_per_frame*/				240,
+	/*.bytes_per_frame*/				480,
+	/*.encoded_bytes_per_frame*/		480,
+	/*.number_of_channels*/				1,
+	/*.pref_frames_per_packet*/			1,
+	/*.max_frames_per_packet*/			1,
+	/*.init*/							switch_raw_init,
+	/*.encode*/							switch_raw_encode,
+	/*.decode*/							switch_raw_decode,
+	/*.destroy*/						switch_raw_destroy,
+	/*.next*/							&raw_8k_implementation
+};
+
+
+static const switch_codec_interface raw_codec_interface = {
+	/*.interface_name*/					"raw signed linear (16 bit)",
+	/*.codec_type*/						SWITCH_CODEC_TYPE_AUDIO,
+	/*.ianacode*/						10,
+	/*.iananame*/						"L16",
+	/*.implementations*/				&raw_8k_30ms_implementation
+};
+
+static switch_loadable_module_interface raw_module_interface = {
+	/*.module_name*/					modname,
+	/*.endpoint_interface*/				NULL,
+	/*.timer_interface*/				NULL,
+	/*.dialplan_interface*/				NULL,
+	/*.codec_interface*/				&raw_codec_interface,
+	/*.application_interface*/			NULL,
+	/*.api_interface*/					NULL,
+	///*.file_interface*/					&raw_file_interface
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */ 
+	*interface = &raw_module_interface;
+
+	/* indicate that the module should continue to be loaded */ 
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
diff --git a/src/mod/codec/mod_rawaudio/mod_rawaudio.vcproj b/src/mod/codec/mod_rawaudio/mod_rawaudio.vcproj
new file mode 100644
index 0000000000..2fb53179c8
--- /dev/null
+++ b/src/mod/codec/mod_rawaudio/mod_rawaudio.vcproj
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_rawaudio"
+	ProjectGUID="{5844AFE1-AA3E-4BDB-A9EF-119AEF19DF88}"
+	RootNamespace="mod_rawaudio"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_rawaudio Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libresample\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libresampled.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_rawaudio.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\libresample\win&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_rawaudio.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_rawaudio.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_rawaudio Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libresample\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libresample.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_rawaudio.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\libresample\win&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_rawaudio.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_rawaudio.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/codec/mod_speexcodec/Makefile b/src/mod/codec/mod_speexcodec/Makefile
new file mode 100644
index 0000000000..396db30128
--- /dev/null
+++ b/src/mod/codec/mod_speexcodec/Makefile
@@ -0,0 +1,12 @@
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install speex-1.1.11.1.tar.gz --prefix=$(PREFIX)
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o
+	$(CC) $(SOLINK) $(MOD).o -o $(MOD).so $(LDFLAGS) -lspeex
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/codec/mod_speexcodec/mod_speexcodec.c b/src/mod/codec/mod_speexcodec/mod_speexcodec.c
new file mode 100644
index 0000000000..d20d646cab
--- /dev/null
+++ b/src/mod/codec/mod_speexcodec/mod_speexcodec.c
@@ -0,0 +1,342 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_speexcodec.c -- Speex Codec Module
+ *
+ */
+#include <switch.h>
+#include <speex/speex.h>
+#include <speex/speex_preprocess.h>
+
+static const char modname[] = "mod_speexcodec";
+
+const struct switch_codec_settings default_codec_settings = {
+	/*.quality*/				5,
+	/*.complexity*/				5,
+	/*.enhancement*/			1,
+	/*.vad*/					0,
+	/*.vbr*/					0,
+	/*.vbr_quality*/			4,
+	/*.abr*/					0,
+	/*.dtx*/					0,
+	/*.preproc*/				0,
+	/*.pp_vad*/					0,
+	/*.pp_agc*/					0,
+	/*.pp_agc_level*/			8000,
+	/*.pp_denoise*/				0,
+	/*.pp_dereverb*/			0,
+	/*.pp_dereverb_decay*/		0.4f,
+	/*.pp_dereverb_level*/		0.3f,
+};
+
+struct speex_context {
+	switch_codec *codec;
+	unsigned int flags;
+
+	/* Encoder */
+	void *encoder_state;
+	struct SpeexBits encoder_bits;
+	unsigned int encoder_frame_size;
+	int encoder_mode;
+	SpeexPreprocessState *pp;
+
+	/* Decoder */
+	void *decoder_state;
+	struct SpeexBits decoder_bits;
+	unsigned int decoder_frame_size;
+	int decoder_mode;
+};
+
+static switch_status switch_speex_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)
+{
+	struct speex_context *context = NULL;
+	int encoding, decoding;
+	
+	encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (!codec_settings) {
+		codec_settings = &default_codec_settings;
+	}
+
+	memcpy(&codec->codec_settings, codec_settings, sizeof(codec->codec_settings));
+
+	if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(*context))))) {
+		return SWITCH_STATUS_FALSE;
+	} else {
+		const SpeexMode *mode = NULL;
+		
+		context->codec = codec;
+		if (codec->implementation->samples_per_second == 8000) {
+			mode = &speex_nb_mode;
+		} else if (codec->implementation->samples_per_second == 16000) {
+			mode = &speex_wb_mode;
+		} else if (codec->implementation->samples_per_second == 32000) {
+			mode = &speex_uwb_mode;
+		}
+
+		if (!mode) {
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if (encoding) {
+			speex_bits_init(&context->encoder_bits);
+			context->encoder_state = speex_encoder_init(mode);
+			speex_encoder_ctl(context->encoder_state, SPEEX_GET_FRAME_SIZE, &context->encoder_frame_size);
+			speex_encoder_ctl(context->encoder_state, SPEEX_SET_COMPLEXITY, &codec->codec_settings.complexity);
+			if (codec->codec_settings.preproc) {
+				context->pp = speex_preprocess_state_init(context->encoder_frame_size, codec->implementation->samples_per_second);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_VAD, &codec->codec_settings.pp_vad);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC, &codec->codec_settings.pp_agc);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &codec->codec_settings.pp_agc_level);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DENOISE, &codec->codec_settings.pp_denoise);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB, &codec->codec_settings.pp_dereverb);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &codec->codec_settings.pp_dereverb_decay);
+				speex_preprocess_ctl(context->pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &codec->codec_settings.pp_dereverb_level);
+			}
+
+			if (!codec->codec_settings.abr && !codec->codec_settings.vbr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_QUALITY, &codec->codec_settings.quality);
+				if (codec->codec_settings.vad) {
+					speex_encoder_ctl(context->encoder_state, SPEEX_SET_VAD, &codec->codec_settings.vad);
+				}
+			}
+			if (codec->codec_settings.vbr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR, &codec->codec_settings.vbr);
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_VBR_QUALITY, &codec->codec_settings.vbr_quality);
+			}
+			if (codec->codec_settings.abr) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_ABR, &codec->codec_settings.abr);
+			}
+			if (codec->codec_settings.dtx) {
+				speex_encoder_ctl(context->encoder_state, SPEEX_SET_DTX, &codec->codec_settings.dtx); 
+			}	
+		}
+
+		if (decoding) {
+			speex_bits_init(&context->decoder_bits);
+			context->decoder_state = speex_decoder_init(mode);
+			if (codec->codec_settings.enhancement) {
+				speex_decoder_ctl(context->decoder_state, SPEEX_SET_ENH, &codec->codec_settings.enhancement);
+			}
+		}
+
+
+
+		codec->private = context;
+		return SWITCH_STATUS_SUCCESS;
+	}
+}
+
+static switch_status switch_speex_encode(switch_codec *codec,
+								   switch_codec *other_codec,
+								   void *decoded_data,
+								   size_t decoded_data_len,
+								   int decoded_rate,
+								   void *encoded_data,
+								   size_t *encoded_data_len,
+								   int *encoded_rate,
+								   unsigned int *flag)
+{
+	struct speex_context *context = codec->private;
+	short *buf;
+	int is_speech = 1;
+
+	if (!context) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	buf = decoded_data;
+
+	if (context->pp) {
+		is_speech = speex_preprocess(context->pp, buf, NULL);
+	}
+
+	if (is_speech) {
+		is_speech = speex_encode_int(context->encoder_state, buf, &context->encoder_bits) || ! context->codec->codec_settings.dtx;
+	} else {
+		speex_bits_pack(&context->encoder_bits, 0, 5);
+	}
+
+
+	if (is_speech) {
+		switch_clear_flag(context, SWITCH_CODEC_FLAG_SILENCE);
+		*flag |= SWITCH_CODEC_FLAG_SILENCE_STOP;
+	} else {
+		if (switch_test_flag(context, SWITCH_CODEC_FLAG_SILENCE)) {
+			*encoded_data_len = 0;
+			*flag |= SWITCH_CODEC_FLAG_SILENCE;
+			return SWITCH_STATUS_SUCCESS;
+		}
+
+		switch_set_flag(context, SWITCH_CODEC_FLAG_SILENCE);
+		*flag |= SWITCH_CODEC_FLAG_SILENCE_START;
+	}
+
+
+
+
+	speex_bits_pack(&context->encoder_bits, 15, 5);
+	*encoded_data_len = speex_bits_write(&context->encoder_bits, (char *)encoded_data, context->encoder_frame_size);
+	speex_bits_reset(&context->encoder_bits);
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status switch_speex_decode(switch_codec *codec,
+								   switch_codec *other_codec,
+								   void *encoded_data,
+								   size_t encoded_data_len,
+								   int encoded_rate,
+								   void *decoded_data,
+								   size_t *decoded_data_len,
+								   int *decoded_rate,
+								   unsigned int *flag) 
+{
+	struct speex_context *context = codec->private;
+	short *buf;
+
+	if (!context) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	buf = decoded_data;
+	if (*flag & SWITCH_CODEC_FLAG_SILENCE) {
+		speex_decode_int(context->decoder_state, NULL, buf);
+	} else {
+		speex_bits_read_from(&context->decoder_bits, (char *)encoded_data, (int)*decoded_data_len);
+		speex_decode_int(context->decoder_state, &context->decoder_bits, buf);
+	}
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status switch_speex_destroy(switch_codec *codec)
+{
+	int encoding, decoding;
+	struct speex_context *context = codec->private;
+
+	if (!context) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	encoding = (codec->flags & SWITCH_CODEC_FLAG_ENCODE);
+	decoding = (codec->flags & SWITCH_CODEC_FLAG_DECODE);
+
+	if (encoding) {
+		speex_bits_destroy(&context->encoder_bits);
+		speex_encoder_destroy(context->encoder_state);
+	}
+
+	if (decoding) {
+		speex_bits_destroy(&context->decoder_bits);
+		speex_decoder_destroy(context->decoder_state);
+	}
+
+	codec->private = NULL;
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* Registration */
+static const switch_codec_implementation speex_32k_implementation = {
+	/*.samples_per_second*/					32000,
+	/*.bits_per_second*/					512000,
+	/*.nanoseconds_per_frame*/				20000,
+	/*.samples_per_frame*/					640,
+	/*.bytes_per_frame*/					1280,
+	/*.encoded_bytes_per_frame*/			1280,
+	/*.number_of_channels*/					1,
+	/*.pref_frames_per_packet*/				1,
+	/*.max_frames_per_packet*/				1,
+	/*.init*/								switch_speex_init,
+	/*.encode*/								switch_speex_encode,
+	/*.decode*/								switch_speex_decode,
+	/*.destroy*/							switch_speex_destroy
+};
+
+static const switch_codec_implementation speex_16k_implementation = {
+	/*.samples_per_second*/					16000,
+	/*.bits_per_second*/					256000,
+	/*.nanoseconds_per_frame*/				20000,
+	/*.samples_per_frame*/					320,
+	/*.bytes_per_frame*/					640,
+	/*.encoded_bytes_per_frame*/			640,
+	/*.number_of_channels*/					1,
+	/*.pref_frames_per_packet*/				1,
+	/*.max_frames_per_packet*/				1,
+	/*.init*/								switch_speex_init,
+	/*.encode*/								switch_speex_encode,
+	/*.decode*/								switch_speex_decode,
+	/*.destroy*/							switch_speex_destroy,
+	/*.next*/								&speex_32k_implementation
+};
+
+static const switch_codec_implementation speex_8k_implementation = {
+	/*.samples_per_second*/					8000,
+	/*.bits_per_second*/					128000,
+	/*.nanoseconds_per_frame*/				20000,
+	/*.samples_per_frame*/					160,
+	/*.bytes_per_frame*/					320,
+	/*.encoded_bytes_per_frame*/			320,
+	/*.number_of_channels*/					1,
+	/*.pref_frames_per_packet*/				1,
+	/*.max_frames_per_packet*/				1,
+	/*.init*/								switch_speex_init,
+	/*.encode*/								switch_speex_encode,
+	/*.decode*/								switch_speex_decode,
+	/*.destroy*/							switch_speex_destroy,
+	/*.next*/								&speex_16k_implementation
+};
+
+static const switch_codec_interface speex_codec_interface = {
+	/*.interface_name*/						"speex",
+	/*.codec_type*/							SWITCH_CODEC_TYPE_AUDIO,
+	/*.ianacode*/							98,
+	/*.iananame*/							"speex",
+	/*.implementations*/					&speex_8k_implementation
+};
+
+static switch_loadable_module_interface speex_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		&speex_codec_interface,
+	/*.application_interface*/	NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &speex_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
diff --git a/src/mod/codec/mod_speexcodec/mod_speexcodec.vcproj b/src/mod/codec/mod_speexcodec/mod_speexcodec.vcproj
new file mode 100644
index 0000000000..0abb26ac7c
--- /dev/null
+++ b/src/mod/codec/mod_speexcodec/mod_speexcodec.vcproj
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_speexcodec"
+	ProjectGUID="{5580D60E-0F77-4716-9CD4-B8E5986FA375}"
+	RootNamespace="mod_speexcodec"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_SpeexCodec Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\speex\include&quot;;&quot;$(InputDir)..\..\..\libs\speex\include\speex&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libspeex.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_speexcodec.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\speex\win32\libspeex\Debug&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_speexcodec.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_speexcodec.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_SpeexCodec Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\speex\include&quot;;&quot;$(InputDir)..\..\..\libs\speex\include\speex&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libspeex.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_speexcodec.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\speex\win32\libspeex\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_speexcodec.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_speexcodec.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.c b/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.c
new file mode 100644
index 0000000000..c071f613bb
--- /dev/null
+++ b/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.c
@@ -0,0 +1,124 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_dialplan_demo.c -- Example Dialplan Module
+ *
+ */
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+
+static const char modname[] = "mod_dialplan_demo";
+
+
+switch_caller_extension *demo_dialplan_hunt(switch_core_session *session)
+{
+	switch_caller_profile *caller_profile;
+	switch_caller_extension *extension = NULL;
+	switch_channel *channel;
+	char *cf = "extensions.conf";
+	switch_config cfg;
+	char *var, *val;
+	char app[1024];
+
+	channel = switch_core_session_get_channel(session);
+	caller_profile = switch_channel_get_caller_profile(channel);
+	//switch_channel_set_variable(channel, "pleasework", "yay");
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hello %s You Dialed %s!\n", caller_profile->caller_id_name, caller_profile->destination_number);	
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		switch_channel_hangup(channel);
+		return NULL;
+	}
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "extensions")) {
+			if (!strcmp(var, caller_profile->destination_number) && val) {
+				char *data;
+
+				memset(app, 0, sizeof(app));
+				strncpy(app, val, sizeof(app));
+
+				if ((data = strchr(app, ' '))) {
+					*data = '\0';
+					data++;
+				} else {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "invalid extension on line %d\n", cfg.lineno);
+					continue;
+				}
+				if (!extension) {
+					if (!(extension = switch_caller_extension_new(session, caller_profile->destination_number, caller_profile->destination_number))) {
+						switch_console_printf(SWITCH_CHANNEL_CONSOLE, "memory error!\n");
+						break;
+					}
+				}
+
+				switch_caller_extension_add_application(session, extension, app, data);
+			} 
+		}
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (extension) {
+		switch_channel_set_state(channel, CS_EXECUTE);
+	} else {
+		switch_channel_hangup(channel);
+	}
+
+	return extension;
+}
+
+
+static const switch_dialplan_interface demo_dialplan_interface = {
+	/*.interface_name =*/ "demo",
+	/*.hunt_function = */ demo_dialplan_hunt
+	/*.next = NULL */
+};
+
+static const switch_loadable_module_interface demo_dialplan_module_interface = {
+	/*.module_name = */ modname,
+	/*.endpoint_interface = */ NULL,
+	/*.timer_interface = */ NULL,
+	/*.dialplan_interface = */ &demo_dialplan_interface,
+	/*.codec_interface = */ NULL,
+	/*.application_interface =*/ NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &demo_dialplan_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
diff --git a/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.vcproj b/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.vcproj
new file mode 100644
index 0000000000..ecf5b98985
--- /dev/null
+++ b/src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_dialplan_demo"
+	ProjectGUID="{2988EB83-785F-45D4-8731-8E1E4345177E}"
+	RootNamespace="mod_dialplan_demo"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_dialplan_demo.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_dialplan_demo.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_dialplan_demo.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_dialplan_demo.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_dialplan_demo.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_dialplan_demo.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/endpoints/mod_exosip/Makefile b/src/mod/endpoints/mod_exosip/Makefile
new file mode 100644
index 0000000000..5e8906382f
--- /dev/null
+++ b/src/mod/endpoints/mod_exosip/Makefile
@@ -0,0 +1,26 @@
+#CFLAGS += -I/usr/src/common/src
+LDFLAGS += -leXosip2  -ljrtp4c
+
+ifeq ($(OSARCH),Darwin)
+	LINKER=g++
+else
+	LINKER=$(CC)
+endif
+
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install jthread-1.1.2.tar.gz --prefix=$(PREFIX)
+	$(BASE)/buildlib.sh $(BASE) install jrtplib-3.3.0.tar.gz --prefix=$(PREFIX)
+	$(BASE)/buildlib.sh $(BASE) install jrtp4c --prefix=$(PREFIX)
+	$(BASE)/buildlib.sh $(BASE) install libosip2-2.2.2.tar.gz --prefix=$(PREFIX)
+	$(BASE)/buildlib.sh $(BASE) install libeXosip2-2.2.2.tar.gz --disable-josua --prefix=$(PREFIX)
+
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(LINKER) $(SOLINK) -o $(MOD).so  $(MOD).o $(LDFLAGS)
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/endpoints/mod_exosip/mod_exosip.c b/src/mod/endpoints/mod_exosip/mod_exosip.c
new file mode 100644
index 0000000000..972797c379
--- /dev/null
+++ b/src/mod/endpoints/mod_exosip/mod_exosip.c
@@ -0,0 +1,1409 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_exosip.c -- eXoSIP SIP Endpoint
+ *
+ */
+
+#define HAVE_APR
+#include <switch.h>
+#include <jrtp4c.h>
+#include <eXosip2/eXosip.h>
+#include <osip2/osip_mt.h>
+#include <osipparser2/osip_rfc3264.h>
+#include <osipparser2/osip_port.h>
+
+
+static const char modname[] = "mod_exosip";
+#define STRLEN 15
+
+static switch_memory_pool *module_pool;
+
+typedef enum {
+	PFLAG_ANSWER = (1 << 0),
+	PFLAG_HANGUP = (1 << 1),
+} PFLAGS;
+
+
+typedef enum {
+	PPFLAG_RING = (1 << 0),
+} PPFLAGS;
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_READING = (1 << 4),
+	TFLAG_WRITING = (1 << 5),
+	TFLAG_USING_CODEC = (1 << 6),	
+	TFLAG_RTP = (1 << 7),
+	TFLAG_BYE = (1 << 8)
+} TFLAGS;
+
+
+#define PACKET_LEN 160
+#define DEFAULT_BYTES_PER_FRAME 160
+
+
+static const switch_endpoint_interface exosip_endpoint_interface;
+
+static struct {
+	int debug;
+	int bytes_per_frame;
+	char *dialplan;
+	int port;
+	int rtp_start;
+	int rtp_end;
+	switch_hash *call_hash;
+	switch_mutex_t *port_lock;
+	int running;
+	int codec_ms;
+} globals;
+
+struct private_object {
+	unsigned int flags;		
+	switch_core_session *session;
+	switch_frame read_frame;
+	switch_codec read_codec;
+	switch_codec write_codec;
+	unsigned char read_buf[1024];
+	switch_caller_profile *caller_profile;
+	int cid;
+	int did;
+	int tid;
+	int32_t timestamp_send;
+	int32_t timestamp_recv;
+	int payload_num;
+	struct jrtp4c *rtp_session;
+	struct osip_rfc3264 *sdp_config;
+	sdp_message_t *remote_sdp;
+	sdp_message_t *local_sdp;
+	char remote_sdp_audio_ip[50];
+	int remote_sdp_audio_port;
+	char local_sdp_audio_ip[50];
+	int local_sdp_audio_port;
+	char call_id[50];
+	int ssrc;
+	switch_mutex_t *rtp_lock;
+};
+
+
+static int next_rtp_port(void)
+{
+	int port;
+
+	switch_mutex_lock(globals.port_lock);
+	port = globals.rtp_start;
+	globals.rtp_start += 2;
+	if (port >= globals.rtp_end) {
+		port = globals.rtp_start;
+	}
+	switch_mutex_unlock(globals.port_lock);
+	return port;
+}
+
+
+static void set_global_dialplan(char *dialplan)
+{
+	if (globals.dialplan) {
+		free(globals.dialplan);
+		globals.dialplan = NULL;
+	}
+
+	globals.dialplan = strdup(dialplan);
+}
+
+static void set_global_dialplan(char *dialplan);
+static switch_status exosip_on_init(switch_core_session *session);
+static switch_status exosip_on_hangup(switch_core_session *session);
+static switch_status exosip_on_loopback(switch_core_session *session);
+static switch_status exosip_on_transmit(switch_core_session *session);
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static int config_exosip(int reload);
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload);
+static switch_status exosip_kill_channel(switch_core_session *session, int sig);
+static void activate_rtp(struct private_object *tech_pvt);
+static void deactivate_rtp(struct private_object *tech_pvt);
+
+static struct private_object *get_pvt_by_call_id(int id)
+{
+	char name[50];
+	snprintf(name, sizeof(name), "%d", id);
+	return (struct private_object *) switch_core_hash_find(globals.call_hash, name);
+}
+
+static switch_status exosip_on_execute(switch_core_session *session)
+{
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static int sdp_add_codec(struct osip_rfc3264 *cnf, int codec_type, int payload, char *attribute, int rate, int index)
+{
+	char tmp[4] = "", string[32] = "";
+	sdp_media_t *med = NULL;
+	sdp_attribute_t *attr = NULL;
+
+	sdp_media_init(&med);
+	if (med == NULL)
+		return -1;
+
+	if (!index) {
+		snprintf(tmp, sizeof(tmp), "%i", payload);
+		med->m_proto = osip_strdup("RTP/AVP");
+		osip_list_add(med->m_payloads, osip_strdup(tmp), -1);
+	}
+	if (attribute) {
+		sdp_attribute_init(&attr);
+		attr->a_att_field = osip_strdup("rtpmap");
+		snprintf(string, sizeof(string), "%i %s/%i", payload, attribute, rate);
+		attr->a_att_value = osip_strdup(string);
+		osip_list_add(med->a_attributes, attr, -1);
+	}
+
+	switch (codec_type) {
+case SWITCH_CODEC_TYPE_AUDIO:
+	med->m_media = osip_strdup("audio");
+	osip_rfc3264_add_audio_media(cnf, med, -1);
+	break;
+case SWITCH_CODEC_TYPE_VIDEO:
+	med->m_media = osip_strdup("video");
+	osip_rfc3264_add_video_media(cnf, med, -1);
+	break;
+default:
+	break;
+	}
+	return 0;
+}
+
+
+/* 
+State methods they get called when the state changes to the specific state 
+returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status exosip_on_init(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	char from_uri[512] = "", localip[128] = "", port[7] = "", *buf = NULL, tmp[512] = "";
+	osip_message_t *invite = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.data = tech_pvt->read_buf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->read_buf);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP INIT\n");
+
+	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+		char *dest_uri;
+		switch_codec_interface *codecs[SWITCH_MAX_CODECS];
+		int num_codecs = 0;
+		/* do SIP Goodies...*/
+
+		/* Generate callerid URI */
+		eXosip_guess_localip(AF_INET, localip, 128);
+		snprintf(from_uri, sizeof(from_uri), "<sip:%s@%s>", tech_pvt->caller_profile->caller_id_number, localip);
+		/* Setup codec negotiation stuffs */
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Decide on local IP and rtp port */
+		strncpy(tech_pvt->local_sdp_audio_ip, localip, sizeof(tech_pvt->local_sdp_audio_ip));
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		/* Initialize SDP */
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_v_version_set(tech_pvt->local_sdp, "0");
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		sdp_message_t_time_descr_add(tech_pvt->local_sdp, "0", "0");
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_media_add(tech_pvt->local_sdp, "audio", port, NULL, "RTP/AVP");
+		/* Add in every codec we support on this outbound call */
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+
+				snprintf(tmp, sizeof(tmp), "%i", codecs[i]->ianacode);
+				sdp_message_m_payload_add(tech_pvt->local_sdp, 0, osip_strdup(tmp));
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					/* Add to SDP config */
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+					/* Add to SDP message */
+
+					snprintf(tmp, sizeof(tmp), "%i %s/%i", codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second);
+					sdp_message_a_attribute_add(tech_pvt->local_sdp, 0, "rtpmap", osip_strdup(tmp));
+					memset(tmp, 0, sizeof(tmp));
+				}
+			}
+		}
+		/* Setup our INVITE */
+		eXosip_lock();
+		if (!(dest_uri = (char *) switch_core_session_alloc(session, strlen(tech_pvt->caller_profile->destination_number) + 10))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "AIEEEE!\n");
+			assert(dest_uri != NULL);
+		}
+		sprintf(dest_uri, "sip:%s", tech_pvt->caller_profile->destination_number);
+		eXosip_call_build_initial_invite(&invite, dest_uri, from_uri, NULL, NULL);
+		osip_message_set_supported(invite, "100rel, replaces");
+		/* Add SDP to the INVITE */
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(invite, buf, strlen(buf));
+		osip_message_set_content_type(invite, "application/sdp");
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OUTBOUND SDP:\n%s\n", buf);
+		free(buf);
+		/* Send the INVITE */
+		tech_pvt->cid = eXosip_call_send_initial_invite(invite);
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", tech_pvt->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);
+		tech_pvt->did = -1;
+		eXosip_unlock();
+	} 
+
+	/* Let Media Work */
+	switch_set_flag(tech_pvt, TFLAG_IO);
+
+	/* Move Channel's State Machine to RING */
+	switch_channel_set_state(channel, CS_RING);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP RING\n");
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_hangup(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	int i;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_core_hash_delete(globals.call_hash, tech_pvt->call_id);	
+
+
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+
+	deactivate_rtp(tech_pvt);
+
+	i = eXosip_call_terminate(tech_pvt->cid, tech_pvt->did);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		switch_core_codec_destroy(&tech_pvt->read_codec);
+		switch_core_codec_destroy(&tech_pvt->write_codec);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP HANGUP %s %d/%d=%d\n", switch_channel_get_name(channel), tech_pvt->cid, tech_pvt->did, i);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session)
+{
+	if ((*new_session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(*new_session));
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			switch_caller_profile *caller_profile;
+
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "Exosip/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+}
+
+
+static void deactivate_rtp(struct private_object *tech_pvt)
+{
+	int loops = 0;
+	if (tech_pvt->rtp_session) {
+		switch_mutex_lock(tech_pvt->rtp_lock);
+
+		while(loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
+			switch_yield(10000);
+			loops++;
+		}
+
+		jrtp4c_destroy(&tech_pvt->rtp_session);
+		tech_pvt->rtp_session = NULL;
+		switch_mutex_unlock(tech_pvt->rtp_lock);
+	}
+}
+
+static void activate_rtp(struct private_object *tech_pvt)
+{
+	int bw, ms;
+	switch_channel *channel;
+	const char *err;
+
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (tech_pvt->rtp_session) {
+		return;
+	}
+
+	switch_mutex_lock(tech_pvt->rtp_lock);
+
+	if (tech_pvt->rtp_session) {
+		switch_mutex_unlock(tech_pvt->rtp_lock);
+		return;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bw = tech_pvt->read_codec.implementation->bits_per_second;
+		ms = tech_pvt->read_codec.implementation->microseconds_per_frame;
+	} else {
+		switch_channel_get_raw_mode(channel, NULL, NULL, NULL, &ms, &bw);
+		bw *= 8;
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activating RTP %s:%d->%s:%d codec: %d ms: %d\n",
+		tech_pvt->local_sdp_audio_ip,
+		tech_pvt->local_sdp_audio_port,
+		tech_pvt->remote_sdp_audio_ip,
+		tech_pvt->remote_sdp_audio_port,
+		tech_pvt->read_codec.codec_interface->ianacode,
+		ms
+		);
+
+
+
+
+	tech_pvt->rtp_session = jrtp4c_new(
+		tech_pvt->local_sdp_audio_ip,
+		tech_pvt->local_sdp_audio_port,
+		tech_pvt->remote_sdp_audio_ip,
+		tech_pvt->remote_sdp_audio_port,
+		tech_pvt->read_codec.codec_interface->ianacode,
+		tech_pvt->read_codec.implementation->samples_per_second,
+		&err);
+
+	if (tech_pvt->rtp_session) {
+		tech_pvt->ssrc = jrtp4c_get_ssrc(tech_pvt->rtp_session);
+		jrtp4c_start(tech_pvt->rtp_session);
+		switch_set_flag(tech_pvt, TFLAG_RTP);
+	} else {
+		switch_channel *channel = switch_core_session_get_channel(tech_pvt->session);
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Oh oh? [%s]\n", err);
+		switch_channel_hangup(channel);
+		switch_set_flag(tech_pvt, TFLAG_BYE);
+		switch_clear_flag(tech_pvt, TFLAG_IO);
+	}
+
+	switch_mutex_unlock(tech_pvt->rtp_lock);
+}
+
+static switch_status exosip_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+		char *buf = NULL;
+		osip_message_t *answer = NULL;
+
+
+		/* Transmit 200 OK with SDP */
+		eXosip_lock();
+		eXosip_call_build_answer(tech_pvt->tid, 200, &answer);
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(answer, buf, strlen(buf));
+		osip_message_set_content_type(answer, "application/sdp");
+		free(buf); 
+		eXosip_call_send_answer(tech_pvt->tid, 200, answer);
+		eXosip_unlock();
+	} 
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	struct private_object *tech_pvt = NULL;
+	size_t bytes = 0, samples = 0, frames=0, ms=0;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.datalen = 0;
+	switch_set_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		samples = tech_pvt->read_codec.implementation->samples_per_frame;
+		ms = tech_pvt->read_codec.implementation->microseconds_per_frame;
+	} else {
+		assert(0);
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
+		if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+			return SWITCH_STATUS_GENERR;
+		}
+
+
+		assert(tech_pvt->rtp_session != NULL);
+		tech_pvt->read_frame.datalen = 0;
+
+		while(!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
+			tech_pvt->read_frame.datalen = jrtp4c_read(tech_pvt->rtp_session,
+				tech_pvt->read_frame.data,
+				sizeof(tech_pvt->read_buf));
+
+			if (tech_pvt->read_frame.datalen > 0) {
+				bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+				frames = (tech_pvt->read_frame.datalen / bytes);
+				samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+				ms = frames * tech_pvt->read_codec.implementation->microseconds_per_frame;
+				tech_pvt->timestamp_recv += (int32_t)samples;
+				tech_pvt->read_frame.samples = (int)samples;
+				break;
+			}
+
+			switch_yield(100);
+		}
+
+		//tech_pvt->timestamp_recv += samples;
+
+
+		//printf("%s %s->%s recv %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_audio_ip, tech_pvt->read_frame.datalen, samples, frames, ms, tech_pvt->timestamp_recv);
+
+
+		//switch_mutex_unlock(tech_pvt->rtp_lock);
+
+	} else {
+		memset(tech_pvt->read_buf, 0, 160);
+		tech_pvt->read_frame.datalen = 160;
+	}
+
+	switch_clear_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	*frame = &tech_pvt->read_frame;
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	switch_status status = SWITCH_STATUS_SUCCESS;
+	int bytes=0, samples=0, ms=0, frames=0;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+		return SWITCH_STATUS_GENERR;
+	}
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch_set_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_lock(tech_pvt->rtp_lock);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		frames = ((int)frame->datalen / bytes);
+		samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+		ms = frames * tech_pvt->read_codec.implementation->microseconds_per_frame / 1000;
+	} else {
+		assert(0);
+	}
+
+
+	//printf("%s %s->%s send %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, ms, tech_pvt->timestamp_send);
+
+
+	jrtp4c_write(tech_pvt->rtp_session, frame->data, (int)frame->datalen, samples);
+	tech_pvt->timestamp_send += (int)samples;
+
+	switch_clear_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_unlock(tech_pvt->rtp_lock);
+	return status;
+}
+
+
+
+static switch_status exosip_kill_channel(switch_core_session *session, int sig)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status exosip_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static const switch_io_routines exosip_io_routines = {
+	/*.outgoing_channel*/	exosip_outgoing_channel,
+	/*.answer_channel*/		exosip_answer_channel,
+	/*.read_frame*/			exosip_read_frame,
+	/*.write_frame*/		exosip_write_frame,
+	/*.kill_channel*/		exosip_kill_channel,
+	/*.waitfor_read*/		exosip_waitfor_read,
+	/*.waitfor_read*/		exosip_waitfor_write
+};
+
+static const switch_event_handler_table  exosip_event_handlers = {
+	/*.on_init*/			exosip_on_init,
+	/*.on_ring*/			exosip_on_ring,
+	/*.on_execute*/			exosip_on_execute,
+	/*.on_hangup*/			exosip_on_hangup,
+	/*.on_loopback*/		exosip_on_loopback,
+	/*.on_transmit*/		exosip_on_transmit
+};
+
+static const switch_endpoint_interface exosip_endpoint_interface = {
+	/*.interface_name*/		"exosip",
+	/*.io_routines*/		&exosip_io_routines,
+	/*.event_handlers*/		&exosip_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface exosip_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&exosip_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	if (globals.running) {
+		globals.running = -1;
+		while(globals.running) {
+			switch_yield(1000);
+		}
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	/* NOTE:  **interface is **_interface because the common lib redefines interface to struct in some situations */
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &exosip_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_create_call(eXosip_event_t *event)
+{
+	switch_core_session *session;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL, *audio_tab[10], *video_tab[10], *t38_tab[10], *app_tab[10];
+	char local_sdp_str[8192] = "", port[8] = "";
+	int mline = 0, pos = 0;
+	switch_channel *channel = NULL;
+	char name[128];
+	char *dpayload, *dname, *drate;
+	char *remote_sdp_str = NULL;
+
+	if ((session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_codec_interface *codecs[SWITCH_MAX_CODECS];
+		int num_codecs = 0;
+
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(session);
+			switch_core_session_set_private(session, tech_pvt);
+			tech_pvt->session = session;
+			switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_MEMERR;
+		}
+
+		if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+			globals.dialplan,
+			event->request->from->displayname,
+			event->request->from->url->username,
+			event->request->from->url->host,
+			NULL,
+			NULL,
+			event->request->req_uri->username))) {
+				switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+
+		switch_set_flag(tech_pvt, TFLAG_INBOUND);
+		tech_pvt->did = event->did;
+		tech_pvt->cid = event->cid;
+		tech_pvt->tid = event->tid;
+
+		snprintf(name, sizeof(name), "Exosip/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
+		switch_channel_set_name(channel, name);
+
+		if (!(remote_sdp = eXosip_get_sdp_info(event->request))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Find Remote SDP!\n");
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		eXosip_guess_localip(AF_INET, tech_pvt->local_sdp_audio_ip, 50);
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Add in what codecs we support locally */
+
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+				}
+			}
+		}
+		osip_rfc3264_prepare_answer(tech_pvt->sdp_config, remote_sdp, local_sdp_str, 8192);
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_parse(tech_pvt->local_sdp, local_sdp_str);
+
+		sdp_message_to_str(remote_sdp, &remote_sdp_str);
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "LOCAL SDP:\n%s\nREMOTE SDP:\n%s", local_sdp_str,remote_sdp_str);
+
+		mline = 0;
+		while (0==osip_rfc3264_match(tech_pvt->sdp_config, remote_sdp, audio_tab, video_tab, t38_tab, app_tab, mline)) {
+			if (audio_tab[0] == NULL && video_tab[0] == NULL && t38_tab[0] == NULL && app_tab[0] == NULL) {
+
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got no compatible codecs!\n");
+				break;
+			}
+			for (pos=0; audio_tab[pos]!=NULL; pos++) {
+				osip_rfc3264_complete_answer(tech_pvt->sdp_config, remote_sdp, tech_pvt->local_sdp, audio_tab[pos], mline);
+				if (parse_sdp_media(audio_tab[pos], &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+					tech_pvt->payload_num = atoi(dpayload);
+					break;
+				}
+			}
+			mline++;
+		}
+		free(remote_sdp_str);
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_port_set(tech_pvt->local_sdp, 0, osip_strdup(port));
+
+		conn = eXosip_get_audio_connection(remote_sdp);
+		remote_med = eXosip_get_audio_media(remote_sdp);
+		snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+		tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", event->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);	
+
+		if (!dname) {
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_state(channel, CS_INIT);
+
+
+		if (1) {
+			int rate = atoi(drate);
+
+			if (switch_core_codec_init(&tech_pvt->read_codec,
+				dname,
+				rate,
+				globals.codec_ms,
+				1,
+				SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+				NULL,
+				switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+					switch_channel_hangup(channel);
+					return SWITCH_STATUS_FALSE;
+			} else {
+				if (switch_core_codec_init(&tech_pvt->write_codec,
+					dname,
+					rate,
+					globals.codec_ms,
+					1,
+					SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+					NULL,
+					switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+						switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+						switch_channel_hangup(channel);
+						return SWITCH_STATUS_FALSE;
+				} else {
+					int ms;
+					tech_pvt->read_frame.rate = rate;
+					switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+					ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Inbound Codec %s/%d %d ms\n", dname, rate, ms);
+					tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+					switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+					switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+				}
+			}
+		}
+
+		activate_rtp(tech_pvt);
+
+		if (switch_test_flag(tech_pvt, TFLAG_RTP)) {
+			switch_core_session_thread_launch(session);
+		} else {
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_FALSE;
+		}
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create new Inbound Channel!\n");
+	}
+
+
+	return 0;
+
+}
+
+static void destroy_call_by_event(eXosip_event_t *event)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt [%d]!\n", event->cid);
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "destroy %s\n", switch_channel_get_name(channel));
+	exosip_kill_channel(tech_pvt->session, SWITCH_SIG_KILL);
+	switch_channel_hangup(channel);
+
+}
+
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload)
+{
+	int pos = 0;
+	sdp_attribute_t *attr = NULL;
+	char *name, *rate, *payload;
+	switch_status status = SWITCH_STATUS_GENERR;
+
+	while (osip_list_eol(media->a_attributes, pos) == 0) {
+		attr = (sdp_attribute_t *)osip_list_get(media->a_attributes, pos);
+		if (attr != NULL && strcasecmp(attr->a_att_field, "rtpmap") == 0) {
+			payload = attr->a_att_value;
+			if ((name = strchr(payload, ' '))) {
+				*(name++) = '\0';
+				/* Name and payload are required */
+				*dpayload = strdup(payload);
+				status = SWITCH_STATUS_SUCCESS;
+				if ((rate = strchr(name, '/'))) {
+					*(rate++) = '\0';
+					*drate = strdup(rate);
+					*dname = strdup(name);
+				} else {
+					*dname = strdup(name);
+					*drate = strdup("8000");
+				}
+			} else {
+				*dpayload = strdup("10");
+				*dname = strdup("L16");
+				*drate = strdup("8000");
+			}
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Found negotiated codec Payload: %s Name: %s Rate: %s\n", *dpayload, *dname, *drate);
+			break;
+		}
+		attr = NULL;
+		pos++;
+	}
+
+	return status;
+}
+
+static void handle_answer(eXosip_event_t *event)
+{
+	osip_message_t *ack = NULL;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL;
+	struct private_object *tech_pvt;
+	char *dpayload = NULL, *dname = NULL, *drate = NULL;
+	switch_channel *channel;
+
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt!\n");
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (!event->response) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Someone answered... with no SDP information - WTF?!?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+	/* Get all of the remote SDP elements... stuff */
+	if (!(remote_sdp = eXosip_get_sdp_info(event->response))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cant Find SDP?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+
+	conn = eXosip_get_audio_connection(remote_sdp);
+	remote_med = eXosip_get_audio_media(remote_sdp);
+
+	/* Grab IP/port */
+	tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+	snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+	/* Grab codec elements */
+	if (parse_sdp_media(remote_med, &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+		tech_pvt->payload_num = atoi(dpayload);
+	}
+
+	/* Assign them thar IDs */
+	tech_pvt->did = event->did;
+	tech_pvt->tid = event->tid;
+
+
+	if (1) {
+		int rate = atoi(drate);
+
+
+		if (switch_core_codec_init(&tech_pvt->read_codec,
+			dname,
+			rate,
+			globals.codec_ms,
+			1,
+			SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+			NULL,
+			switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+				switch_channel_hangup(channel);
+				return;
+		} else {
+			if (switch_core_codec_init(&tech_pvt->write_codec,
+				dname,
+				rate,
+				globals.codec_ms,
+				1,
+				SWITCH_CODEC_FLAG_ENCODE |SWITCH_CODEC_FLAG_DECODE,
+				NULL,
+				switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+					switch_channel_hangup(channel);
+					return;
+			} else {
+				int ms;
+				tech_pvt->read_frame.rate = rate;
+				switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+				ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Outbound Codec %s/%d %d ms\n", dname, rate, ms);
+				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);
+			}
+		}
+	}
+
+
+	eXosip_lock();
+	eXosip_call_build_ack(event->did, &ack);
+	eXosip_call_send_ack(event->did, ack);
+	eXosip_unlock();
+
+	free(dname);
+	free(drate);
+	free(dpayload);
+
+
+	activate_rtp(tech_pvt);
+
+	if (switch_test_flag(tech_pvt, TFLAG_RTP)) {
+		channel = switch_core_session_get_channel(tech_pvt->session);
+		assert(channel != NULL);
+		switch_channel_answer(channel);
+	}
+}
+
+static void log_event(eXosip_event_t *je)
+{
+	char buf[100];
+
+	buf[0] = '\0';
+	if (je->type == EXOSIP_CALL_NOANSWER) {
+		snprintf (buf, 99, "<- (%i %i) No answer", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_CLOSED) {
+		snprintf (buf, 99, "<- (%i %i) Call Closed", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_RELEASED) {
+		snprintf (buf, 99, "<- (%i %i) Call released", je->cid, je->did);
+	} else if (je->type == EXOSIP_MESSAGE_NEW
+		&& je->request!=NULL && MSG_IS_MESSAGE(je->request)) {
+			char *tmp = NULL;
+
+			if (je->request != NULL) {
+				osip_body_t *body;
+				osip_from_to_str (je->request->from, &tmp);
+
+				osip_message_get_body (je->request, 0, &body);
+				if (body != NULL && body->body != NULL) {
+					snprintf (buf, 99, "<- (%i) from: %s TEXT: %s",
+						je->tid, tmp, body->body);
+				}
+				osip_free (tmp);
+			} else {
+				snprintf (buf, 99, "<- (%i) New event for unknown request?", je->tid);
+			}
+	} else if (je->type == EXOSIP_MESSAGE_NEW) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+			je->tid, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->type == EXOSIP_MESSAGE_PROCEEDING
+		|| je->type == EXOSIP_MESSAGE_ANSWERED
+		|| je->type == EXOSIP_MESSAGE_REDIRECTED
+		|| je->type == EXOSIP_MESSAGE_REQUESTFAILURE
+		|| je->type == EXOSIP_MESSAGE_SERVERFAILURE
+		|| je->type == EXOSIP_MESSAGE_GLOBALFAILURE) {
+			if (je->response != NULL && je->request != NULL) {
+				char *tmp = NULL;
+
+				osip_to_to_str (je->request->to, &tmp);
+				snprintf (buf, 99, "<- (%i) [%i %s for %s] to: %s",
+					je->tid, je->response->status_code,
+					je->response->reason_phrase, je->request->sip_method, tmp);
+				osip_free (tmp);
+			} else if (je->request != NULL) {
+				snprintf (buf, 99, "<- (%i) Error for %s request",
+					je->tid, je->request->sip_method);
+			} else {
+				snprintf (buf, 99, "<- (%i) Error for unknown request", je->tid);
+			}
+	} else if (je->response == NULL && je->request != NULL && je->cid > 0) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i %i) %s from: %s",
+			je->cid, je->did, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->cid > 0) {
+		char *tmp = NULL;
+
+		osip_to_to_str (je->request->to, &tmp);
+		snprintf (buf, 99, "<- (%i %i) [%i %s] for %s to: %s",
+			je->cid, je->did, je->response->status_code,
+			je->response->reason_phrase, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->rid > 0) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+			je->rid, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->rid > 0) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+			je->rid, je->response->status_code,
+			je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->sid > 0) {
+		char *tmp = NULL;
+		char *stat = NULL;
+		osip_header_t *sub_state;
+
+		osip_message_header_get_byname (je->request, "subscription-state",
+			0, &sub_state);
+		if (sub_state != NULL && sub_state->hvalue != NULL)
+			stat = sub_state->hvalue;
+
+		osip_uri_to_str (je->request->from->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%s] %s from: %s",
+			je->sid, stat, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->sid > 0) {
+		char *tmp = NULL;
+
+		osip_uri_to_str (je->request->to->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+			je->sid, je->response->status_code,
+			je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) %s from: %s",
+			je->cid, je->did, je->sid, je->nid,
+			je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL) {
+		char *tmp = NULL;
+
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) [%i %s] for %s from: %s",
+			je->cid, je->did, je->sid, je->nid,
+			je->response->status_code, je->response->reason_phrase,
+			je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else {
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i|t=%i) %s",
+			je->cid, je->did, je->sid, je->nid, je->tid, je->textinfo);
+	}
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\n%s\n", buf);
+	/* Print it out */
+}
+
+
+
+static void *monitor_thread_run(void)
+{
+	eXosip_event_t *event = NULL;
+
+	globals.running = 1;
+	while (globals.running > 0) {
+		if (!(event = eXosip_event_wait(0,100))) {
+			switch_yield(100);
+			continue;
+		}
+
+		eXosip_lock();
+		eXosip_automatic_action ();
+		eXosip_unlock();
+
+		log_event(event);
+
+		switch(event->type) {
+			case EXOSIP_CALL_INVITE:
+				exosip_create_call(event);
+				break;
+			case EXOSIP_CALL_REINVITE:
+				/* See what the reinvite is about - on hold or whatever */
+				//handle_reinvite(event);
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got a reinvite.\n");
+				break;
+			case EXOSIP_CALL_MESSAGE_NEW:
+				if (event->request != NULL && MSG_IS_REFER(event->request)) {
+					//handle_call_transfer(event);
+				}
+				break;
+			case EXOSIP_CALL_ACK:
+				/* If audio is not flowing and this has SDP - fire it up! */
+				break;
+			case EXOSIP_CALL_ANSWERED:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was answered.\n");
+				handle_answer(event);
+				break;
+			case EXOSIP_CALL_PROCEEDING:
+				/* This is like a 100 Trying... yeah */
+				break;
+			case EXOSIP_CALL_RINGING:
+				//handle_ringing(event);
+				break;
+			case EXOSIP_CALL_REDIRECTED:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Call was redirect\n");
+				break;
+			case EXOSIP_CALL_CLOSED:
+				destroy_call_by_event(event);
+				break;
+			case EXOSIP_CALL_RELEASED:
+				destroy_call_by_event(event);
+				break;
+			case EXOSIP_CALL_NOANSWER:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was not answered.\n");
+				destroy_call_by_event(event);
+				break;
+			case EXOSIP_CALL_REQUESTFAILURE:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Request failure\n");
+				destroy_call_by_event(event);
+				break;
+			case EXOSIP_CALL_SERVERFAILURE:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Server failure\n");
+				destroy_call_by_event(event);
+				break;
+			case EXOSIP_CALL_GLOBALFAILURE:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Global failure\n");
+				destroy_call_by_event(event);
+				break;
+				/* Registration related stuff */
+			case EXOSIP_REGISTRATION_NEW:
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Received registration attempt\n");
+				break;
+			default:
+				/* Unknown event... casually absorb it for now */
+				break;
+		}
+
+		//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "There was an event (%d) [%s]\n", event->type, event->textinfo);
+		/* Free the event */
+		eXosip_event_free(event);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Monitor Thread Exiting\n");
+	globals.running = 0;
+	return NULL;
+}
+
+
+static int config_exosip(int reload) 
+{
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "exosip.conf";
+
+	globals.bytes_per_frame = DEFAULT_BYTES_PER_FRAME;
+	switch_core_hash_init(&globals.call_hash, module_pool);
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+
+	globals.rtp_start = 16384;
+	globals.rtp_end = 32768;
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+			} else if (!strcmp(var, "rtp_min_port")) {
+				globals.rtp_start = atoi(val);
+			} else if (!strcmp(var, "rtp_max_port")) {
+				globals.rtp_end = atoi(val);
+			} else if (!strcmp(var, "codec_ms")) {
+				globals.codec_ms = atoi(val);
+			}
+		}
+	}
+
+	if (!globals.codec_ms) {
+		globals.codec_ms = 20;
+	}
+
+	if (!globals.port) {
+		globals.port = 5060;
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+
+	if (eXosip_init ()) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_init initialization failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+	if (eXosip_listen_addr (IPPROTO_UDP, NULL, globals.port, AF_INET, 0)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_listen_addr failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch_mutex_init(&globals.port_lock, SWITCH_MUTEX_NESTED, module_pool);
+
+	/* Setup the user agent */
+	eXosip_set_user_agent("FreeSWITCH");
+
+	monitor_thread_run();
+
+	eXosip_quit();
+
+	return 0;
+
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+	config_exosip(0);
+	return SWITCH_STATUS_TERM;
+}
+
diff --git a/src/mod/endpoints/mod_exosip/mod_exosip.vcproj b/src/mod/endpoints/mod_exosip/mod_exosip.vcproj
new file mode 100644
index 0000000000..014a0e56fb
--- /dev/null
+++ b/src/mod/endpoints/mod_exosip/mod_exosip.vcproj
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_exosip"
+	ProjectGUID="{45DF84ED-D24A-4FF6-B5B0-0A9A5FDB9552}"
+	RootNamespace="mod_exosip"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_Exosip Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalOptions="/D _CRT_SECURE_NO_DEPRECATE"
+				Optimization="0"
+				AdditionalIncludeDirectories="..\..\include;..\..\..\libs\include;..\..\..\libs\libeXosip2\include;..\..\..\libs\osip\include;..\..\..\libs\jrtp4c\src;..\..\..\libs\osip\src\osipparser2;..\..\..\libs\jrtplib\src;&quot;..\..\..\libs\jthread-1.1.2\src&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				GeneratePreprocessedFile="0"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/NODEFAULTLIB:LIBCMT"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libcpmt.lib eXosip.lib jrtplib.lib jthread.lib osipparser2.lib osip2.lib"
+				ShowProgress="0"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_exosip.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Debug&quot;;&quot;$(InputDir)..\..\..\libs\jrtp4c\w32\Debug&quot;;&quot;$(InputDir)..\..\..\libs\jrtplib\Debug&quot;;&quot;$(InputDir)..\..\..\libs\jthread-1.1.2\Debug&quot;;&quot;$(InputDir)..\..\..\libs\libeXosip2\platform\vsnet\Debug&quot;;&quot;$(InputDir)..\..\..\libs\osip\platform\vsnet\Debug&quot;"
+				IgnoreAllDefaultLibraries="false"
+				IgnoreDefaultLibraryNames=""
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_exosip.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_exosip.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_Exosip Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="..\..\include;..\..\..\libs\include;..\..\..\libs\libeXosip2\include;..\..\..\libs\osip\include;..\..\..\libs\jrtp4c\src;..\..\..\libs\osip\src\osipparser2;..\..\..\libs\jrtplib\src;&quot;..\..\..\libs\jthread-1.1.2\src&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libcpmt.lib eXosip.lib jrtplib.lib jthread.lib osipparser2.lib osip2.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_exosip.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Release&quot;;&quot;$(InputDir)..\..\..\libs\jrtp4c\w32\Release&quot;;&quot;$(InputDir)..\..\..\libs\jrtplib\Release&quot;;&quot;$(InputDir)..\..\..\libs\jthread-1.1.2\Release&quot;;&quot;$(InputDir)..\..\..\libs\libeXosip2\platform\vsnet\Release&quot;;&quot;$(InputDir)..\..\..\libs\osip\platform\vsnet\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_exosip.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\..\..\libs\jrtp4c\src\jrtp4c.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\mod_exosip.c"
+				>
+			</File>
+			<File
+				RelativePath="..\..\..\libs\osip\src\osipparser2\osip_rfc3264.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\..\..\libs\osip\src\osipparser2\osip_rfc3264i.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/endpoints/mod_exosip/mod_exosip_ccrtp.c b/src/mod/endpoints/mod_exosip/mod_exosip_ccrtp.c
new file mode 100644
index 0000000000..4d895ca0fc
--- /dev/null
+++ b/src/mod/endpoints/mod_exosip/mod_exosip_ccrtp.c
@@ -0,0 +1,1373 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_exosip.c -- eXoSIP SIP Endpoint
+ *
+ */
+
+
+#define HAVE_APR
+#include <switch.h>
+#include <ccrtp4c.h>
+#include <eXosip2/eXosip.h>
+#include <osip2/osip_mt.h>
+#include <osipparser2/osip_rfc3264.h>
+#include <osipparser2/osip_port.h>
+
+
+static const char modname[] = "mod_exosip";
+#define STRLEN 15
+
+static switch_memory_pool *module_pool;
+
+typedef enum {
+	PFLAG_ANSWER = (1 << 0),
+	PFLAG_HANGUP = (1 << 1),
+} PFLAGS;
+
+
+typedef enum {
+	PPFLAG_RING = (1 << 0),
+} PPFLAGS;
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_READING = (1 << 4),
+	TFLAG_WRITING = (1 << 5),
+	TFLAG_USING_CODEC = (1 << 6),	
+	TFLAG_RTP = (1 << 7),
+	TFLAG_BYE = (1 << 8)
+} TFLAGS;
+
+
+#define PACKET_LEN 160
+#define DEFAULT_BYTES_PER_FRAME 160
+
+
+static const switch_endpoint_interface exosip_endpoint_interface;
+
+static struct {
+	int debug;
+	int bytes_per_frame;
+	char *dialplan;
+	int port;
+	int rtp_start;
+	int rtp_end;
+	switch_hash *call_hash;
+	switch_mutex_t *port_lock;
+	int running;
+	int codec_ms;
+} globals;
+
+struct private_object {
+	unsigned int flags;		
+	switch_core_session *session;
+	switch_frame read_frame;
+	switch_codec read_codec;
+	switch_codec write_codec;
+	unsigned char read_buf[1024];
+	switch_caller_profile *caller_profile;
+	int cid;
+	int did;
+	int tid;
+	int32_t timestamp_send;
+	int32_t timestamp_recv;
+	int payload_num;
+	struct ccrtp4c *rtp_session;
+	struct osip_rfc3264 *sdp_config;
+	sdp_message_t *remote_sdp;
+	sdp_message_t *local_sdp;
+	char remote_sdp_audio_ip[50];
+	int remote_sdp_audio_port;
+	char local_sdp_audio_ip[50];
+	int local_sdp_audio_port;
+	char call_id[50];
+	int ssrc;
+	//switch_mutex_t *rtp_lock;
+};
+
+
+static int next_rtp_port(void)
+{
+	int port;
+
+	switch_mutex_lock(globals.port_lock);
+	port = globals.rtp_start;
+	globals.rtp_start += 2;
+	if (port >= globals.rtp_end) {
+		port = globals.rtp_start;
+	}
+	switch_mutex_unlock(globals.port_lock);
+	return port;
+}
+
+
+static void set_global_dialplan(char *dialplan)
+{
+	if (globals.dialplan) {
+		free(globals.dialplan);
+		globals.dialplan = NULL;
+	}
+	
+	globals.dialplan = strdup(dialplan);
+}
+
+static void set_global_dialplan(char *dialplan);
+static switch_status exosip_on_init(switch_core_session *session);
+static switch_status exosip_on_hangup(switch_core_session *session);
+static switch_status exosip_on_loopback(switch_core_session *session);
+static switch_status exosip_on_transmit(switch_core_session *session);
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static int config_exosip(int reload);
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload);
+static switch_status exosip_kill_channel(switch_core_session *session, int sig);
+static void activate_rtp(struct private_object *tech_pvt);
+static void deactivate_rtp(struct private_object *tech_pvt);
+
+static struct private_object *get_pvt_by_call_id(int id)
+{
+	char name[50];
+	snprintf(name, sizeof(name), "%d", id);
+	return (struct private_object *) switch_core_hash_find(globals.call_hash, name);
+}
+
+static switch_status exosip_on_execute(switch_core_session *session)
+{
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static int sdp_add_codec(struct osip_rfc3264 *cnf, int codec_type, int payload, char *attribute, int rate, int index)
+{
+	char tmp[4] = "", string[32] = "";
+	sdp_media_t *med = NULL;
+	sdp_attribute_t *attr = NULL;
+
+	sdp_media_init(&med);
+	if (med == NULL)
+		return -1;
+
+	if (!index) {
+		snprintf(tmp, sizeof(tmp), "%i", payload);
+		med->m_proto = osip_strdup("RTP/AVP");
+		osip_list_add(med->m_payloads, osip_strdup(tmp), -1);
+	}
+	if (attribute) {
+		sdp_attribute_init(&attr);
+		attr->a_att_field = osip_strdup("rtpmap");
+		snprintf(string, sizeof(string), "%i %s/%i", payload, attribute, rate);
+		attr->a_att_value = osip_strdup(string);
+		osip_list_add(med->a_attributes, attr, -1);
+	}
+
+	switch (codec_type) {
+	case SWITCH_CODEC_TYPE_AUDIO:
+		med->m_media = osip_strdup("audio");
+		osip_rfc3264_add_audio_media(cnf, med, -1);
+		break;
+	case SWITCH_CODEC_TYPE_VIDEO:
+		med->m_media = osip_strdup("video");
+		osip_rfc3264_add_video_media(cnf, med, -1);
+		break;
+	default:
+		break;
+	}
+	 return 0;
+}
+
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status exosip_on_init(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	char from_uri[512] = "", localip[128] = "", port[7] = "", *buf = NULL, tmp[512] = "";
+	osip_message_t *invite = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.data = tech_pvt->read_buf;
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP INIT\n");
+
+	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+		char *dest_uri;
+		switch_codec_interface *codecs[512];
+		int num_codecs = 0;
+		/* do SIP Goodies...*/
+
+		/* Generate callerid URI */
+		eXosip_guess_localip(AF_INET, localip, 128);
+		snprintf(from_uri, sizeof(from_uri), "<sip:%s@%s>", tech_pvt->caller_profile->caller_id_number, localip);
+		/* Setup codec negotiation stuffs */
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Decide on local IP and rtp port */
+		strncpy(tech_pvt->local_sdp_audio_ip, localip, sizeof(tech_pvt->local_sdp_audio_ip));
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		/* Initialize SDP */
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_v_version_set(tech_pvt->local_sdp, "0");
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		sdp_message_t_time_descr_add(tech_pvt->local_sdp, "0", "0");
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_media_add(tech_pvt->local_sdp, "audio", port, NULL, "RTP/AVP");
+		/* Add in every codec we support on this outbound call */
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+
+				snprintf(tmp, sizeof(tmp), "%i", codecs[i]->ianacode);
+				sdp_message_m_payload_add(tech_pvt->local_sdp, 0, osip_strdup(tmp));
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					/* Add to SDP config */
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+					/* Add to SDP message */
+
+					snprintf(tmp, sizeof(tmp), "%i %s/%i", codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second);
+					sdp_message_a_attribute_add(tech_pvt->local_sdp, 0, "rtpmap", osip_strdup(tmp));
+					memset(tmp, 0, sizeof(tmp));
+				}
+			}
+		}
+		/* Setup our INVITE */
+		eXosip_lock();
+		if (!(dest_uri = (char *) switch_core_session_alloc(session, strlen(tech_pvt->caller_profile->destination_number) + 10))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "AIEEEE!\n");
+			assert(dest_uri != NULL);
+		}
+		sprintf(dest_uri, "sip:%s", tech_pvt->caller_profile->destination_number);
+		eXosip_call_build_initial_invite(&invite, dest_uri, from_uri, NULL, NULL);
+		osip_message_set_supported(invite, "100rel, replaces");
+		/* Add SDP to the INVITE */
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(invite, buf, strlen(buf));
+		osip_message_set_content_type(invite, "application/sdp");
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OUTBOUND SDP:\n%s\n", buf);
+		free(buf);
+		/* Send the INVITE */
+		tech_pvt->cid = eXosip_call_send_initial_invite(invite);
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", tech_pvt->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);
+		tech_pvt->did = -1;
+		eXosip_unlock();
+	} 
+
+	/* Let Media Work */
+	switch_set_flag(tech_pvt, TFLAG_IO);
+
+	/* Move Channel's State Machine to RING */
+	switch_channel_set_state(channel, CS_RING);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP RING\n");
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_hangup(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	int i;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_core_hash_delete(globals.call_hash, tech_pvt->call_id);	
+	
+
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+
+	deactivate_rtp(tech_pvt);
+
+	i = eXosip_call_terminate(tech_pvt->cid, tech_pvt->did);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		switch_core_codec_destroy(&tech_pvt->read_codec);
+		switch_core_codec_destroy(&tech_pvt->write_codec);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP HANGUP %s %d/%d=%d\n", switch_channel_get_name(channel), tech_pvt->cid, tech_pvt->did, i);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session)
+{
+	if ((*new_session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel, *orig_channel;
+		switch_caller_profile *caller_profile, *originator_caller_profile = NULL;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			//switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(*new_session));
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "Exosip/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		/* (session == NULL) means it was originated from the core not from another channel */
+		if (session && (orig_channel = switch_core_session_get_channel(session))) {
+			switch_caller_profile *cloned_profile;
+
+			if ((originator_caller_profile = switch_channel_get_caller_profile(orig_channel))) {
+				cloned_profile = switch_caller_profile_clone(*new_session, originator_caller_profile);
+				switch_channel_set_originator_caller_profile(channel, cloned_profile);
+			}
+		}
+		
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+}
+
+
+static void deactivate_rtp(struct private_object *tech_pvt)
+{
+	int loops = 0;
+	if (tech_pvt->rtp_session) {
+		//switch_mutex_lock(tech_pvt->rtp_lock);
+
+		while(loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
+			switch_yield(10000);
+			loops++;
+		}
+
+		ccrtp4c_destroy(&tech_pvt->rtp_session);
+		tech_pvt->rtp_session = NULL;
+		//switch_mutex_unlock(tech_pvt->rtp_lock);
+	}
+}
+
+static void activate_rtp(struct private_object *tech_pvt)
+{
+	int bw, ms;
+	switch_channel *channel;
+
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+
+
+	//switch_mutex_lock(tech_pvt->rtp_lock);
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bw = tech_pvt->read_codec.implementation->bits_per_second;
+		ms = tech_pvt->read_codec.implementation->nanoseconds_per_frame;
+	} else {
+		switch_channel_get_raw_mode(channel, NULL, NULL, NULL, &ms, &bw);
+		bw *= 8;
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activating RTP %s:%d->%s:%d codec: %d ms: %d\n",
+						  tech_pvt->local_sdp_audio_ip,
+						  tech_pvt->local_sdp_audio_port,
+						  tech_pvt->remote_sdp_audio_ip,
+						  tech_pvt->remote_sdp_audio_port,
+						  tech_pvt->read_codec.codec_interface->ianacode,
+						  ms
+						  );
+
+
+
+
+	tech_pvt->rtp_session = ccrtp4c_new(
+										tech_pvt->local_sdp_audio_ip,
+										tech_pvt->local_sdp_audio_port,
+										tech_pvt->remote_sdp_audio_ip,
+										tech_pvt->remote_sdp_audio_port,
+										tech_pvt->read_codec.codec_interface->ianacode,
+										ms,
+										ms * 15);
+
+	if (tech_pvt->rtp_session) {
+		tech_pvt->ssrc = ccrtp4c_get_ssrc(tech_pvt->rtp_session);
+		ccrtp4c_start(tech_pvt->rtp_session);
+		switch_set_flag(tech_pvt, TFLAG_RTP);
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Oh oh?\n");
+	}
+
+	//switch_mutex_unlock(tech_pvt->rtp_lock);
+}
+
+static switch_status exosip_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+		char *buf = NULL;
+		osip_message_t *answer = NULL;
+
+
+		/* Transmit 200 OK with SDP */
+		eXosip_lock();
+		eXosip_call_build_answer(tech_pvt->tid, 200, &answer);
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(answer, buf, strlen(buf));
+		osip_message_set_content_type(answer, "application/sdp");
+		free(buf); 
+		eXosip_call_send_answer(tech_pvt->tid, 200, answer);
+		eXosip_unlock();
+	} 
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	struct private_object *tech_pvt = NULL;
+	size_t bytes = 0, samples = 0, frames=0, ms=0;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.datalen = 0;
+	switch_set_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		samples = tech_pvt->read_codec.implementation->samples_per_frame;
+	} else {
+		assert(0);
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
+		if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+			activate_rtp(tech_pvt);
+		}
+
+		assert(tech_pvt->rtp_session != NULL);
+		tech_pvt->read_frame.datalen = 0;
+		
+		while(!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
+			if ((tech_pvt->read_frame.datalen = 
+				 ccrtp4c_read(tech_pvt->rtp_session,
+							  tech_pvt->read_frame.data,
+							  sizeof(tech_pvt->read_buf),
+							  &tech_pvt->timestamp_recv))) {
+				bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+				frames = (tech_pvt->read_frame.datalen / bytes);
+				samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+				ms = frames * tech_pvt->read_codec.implementation->nanoseconds_per_frame / 1000;
+				tech_pvt->timestamp_recv += samples;
+				break;
+			}
+			switch_yield(100);
+		}
+		
+		//printf("%s %s->%s recv %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->local_sdp_audio_ip, tech_pvt->read_frame.datalen, samples, frames, ms, tech_pvt->timestamp_recv);
+		
+
+		//switch_mutex_unlock(tech_pvt->rtp_lock);
+
+	} else {
+		memset(tech_pvt->read_buf, 0, 160);
+		tech_pvt->read_frame.datalen = 160;
+	}
+
+	switch_clear_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	*frame = &tech_pvt->read_frame;
+
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	switch_status status = SWITCH_STATUS_SUCCESS;
+	int bytes=0, samples=0, ms=0, frames=0;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+		activate_rtp(tech_pvt);
+	}
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch_set_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_lock(tech_pvt->rtp_lock);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		frames = (frame->datalen / bytes);
+		samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+		ms = frames * tech_pvt->read_codec.implementation->nanoseconds_per_frame / 1000;
+	} else {
+		assert(0);
+	}
+	
+
+	//printf("%s %s->%s send %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, ms, tech_pvt->timestamp_send);
+	
+	tech_pvt->timestamp_send += (int)samples;
+	ccrtp4c_write(tech_pvt->rtp_session, frame->data, frame->datalen, &tech_pvt->timestamp_send);
+
+	
+
+
+	switch_clear_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_unlock(tech_pvt->rtp_lock);
+	return status;
+}
+
+
+
+static switch_status exosip_kill_channel(switch_core_session *session, int sig)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+	
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status exosip_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	return SWITCH_STATUS_SUCCESS;
+
+}
+	
+static const switch_io_routines exosip_io_routines = {
+	/*.outgoing_channel*/	exosip_outgoing_channel,
+	/*.answer_channel*/		exosip_answer_channel,
+	/*.read_frame*/			exosip_read_frame,
+	/*.write_frame*/		exosip_write_frame,
+	/*.kill_channel*/		exosip_kill_channel,
+	/*.waitfor_read*/		exosip_waitfor_read,
+	/*.waitfor_read*/		exosip_waitfor_write
+};
+
+static const switch_event_handler_table  exosip_event_handlers = {
+	/*.on_init*/			exosip_on_init,
+	/*.on_ring*/			exosip_on_ring,
+	/*.on_execute*/			exosip_on_execute,
+	/*.on_hangup*/			exosip_on_hangup,
+	/*.on_loopback*/		exosip_on_loopback,
+	/*.on_transmit*/		exosip_on_transmit
+};
+
+static const switch_endpoint_interface exosip_endpoint_interface = {
+	/*.interface_name*/		"exosip",
+	/*.io_routines*/		&exosip_io_routines,
+	/*.event_handlers*/		&exosip_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface exosip_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&exosip_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	if (globals.running) {
+		globals.running = -1;
+		while(globals.running) {
+			switch_yield(1000);
+		}
+	}
+	eXosip_quit();
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	/* NOTE:  **interface is **_interface because the common lib redefines interface to struct in some situations */
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+	
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &exosip_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_create_call(eXosip_event_t *event)
+{
+	switch_core_session *session;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL, *audio_tab[10], *video_tab[10], *t38_tab[10], *app_tab[10];
+	char local_sdp_str[8192] = "", port[8] = "";
+	int mline = 0, pos = 0;
+	switch_channel *channel = NULL;
+	char name[128];
+	char *dpayload, *dname, *drate;
+	char *remote_sdp_str = NULL;
+
+	if ((session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_codec_interface *codecs[512];
+		int num_codecs = 0;
+
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(session);
+			switch_core_session_set_private(session, tech_pvt);
+			tech_pvt->session = session;
+			//switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_MEMERR;
+		}
+		
+		if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+															   globals.dialplan,
+															   event->request->from->displayname,
+															   event->request->from->url->username,
+															   event->request->from->url->username,
+															   NULL,
+															   event->request->req_uri->username))) {
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+
+		switch_set_flag(tech_pvt, TFLAG_INBOUND);
+		tech_pvt->did = event->did;
+		tech_pvt->cid = event->cid;
+		tech_pvt->tid = event->tid;
+
+		snprintf(name, sizeof(name), "Exosip/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
+		switch_channel_set_name(channel, name);
+		
+		if (!(remote_sdp = eXosip_get_sdp_info(event->request))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Find Remote SDP!\n");
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		eXosip_guess_localip(AF_INET, tech_pvt->local_sdp_audio_ip, 50);
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Add in what codecs we support locally */
+		
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+				}
+			}
+		}
+		osip_rfc3264_prepare_answer(tech_pvt->sdp_config, remote_sdp, local_sdp_str, 8192);
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_parse(tech_pvt->local_sdp, local_sdp_str);
+
+		sdp_message_to_str(remote_sdp, &remote_sdp_str);
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "LOCAL SDP:\n%s\nREMOTE SDP:\n%s", local_sdp_str,remote_sdp_str);
+		
+		mline = 0;
+		while (0==osip_rfc3264_match(tech_pvt->sdp_config, remote_sdp, audio_tab, video_tab, t38_tab, app_tab, mline)) {
+			if (audio_tab[0] == NULL && video_tab[0] == NULL && t38_tab[0] == NULL && app_tab[0] == NULL) {
+
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got no compatible codecs!\n");
+				break;
+			}
+			for (pos=0; audio_tab[pos]!=NULL; pos++) {
+				osip_rfc3264_complete_answer(tech_pvt->sdp_config, remote_sdp, tech_pvt->local_sdp, audio_tab[pos], mline);
+				if (parse_sdp_media(audio_tab[pos], &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+					tech_pvt->payload_num = atoi(dpayload);
+					break;
+				}
+			}
+			mline++;
+		}
+		free(remote_sdp_str);
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_port_set(tech_pvt->local_sdp, 0, osip_strdup(port));
+
+		conn = eXosip_get_audio_connection(remote_sdp);
+		remote_med = eXosip_get_audio_media(remote_sdp);
+		snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+		tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+		
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", event->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);	
+
+		if (!dname) {
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_state(channel, CS_INIT);
+
+
+		if (1) {
+			int rate = atoi(drate);
+
+			if (switch_core_codec_init(&tech_pvt->read_codec,
+									dname,
+									rate,
+									globals.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_channel_hangup(channel);
+				return SWITCH_STATUS_FALSE;
+			} else {
+				if (switch_core_codec_init(&tech_pvt->write_codec,
+										dname,
+										rate,
+										globals.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_channel_hangup(channel);
+					return SWITCH_STATUS_FALSE;
+				} else {
+					int ms;
+					switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+					ms = tech_pvt->write_codec.implementation->nanoseconds_per_frame / 1000;
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Inbound Codec %s/%d %d ms\n", dname, rate, ms);
+					tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+					switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+					switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+				}
+			}
+		}
+		
+		switch_core_session_thread_launch(session);
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create new Inbound Channel!\n");
+	}
+
+
+	return 0;
+
+
+
+}
+
+static void destroy_call_by_event(eXosip_event_t *event)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt [%d]!\n", event->cid);
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "destroy %s\n", switch_channel_get_name(channel));
+	exosip_kill_channel(tech_pvt->session, SWITCH_SIG_KILL);
+	switch_channel_hangup(channel);
+	
+}
+
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload)
+{
+	int pos = 0;
+	sdp_attribute_t *attr = NULL;
+	char *name, *rate, *payload;
+	switch_status status = SWITCH_STATUS_GENERR;
+
+	while (osip_list_eol(media->a_attributes, pos) == 0) {
+		attr = (sdp_attribute_t *)osip_list_get(media->a_attributes, pos);
+		if (attr != NULL && strcasecmp(attr->a_att_field, "rtpmap") == 0) {
+			payload = attr->a_att_value;
+			if ((name = strchr(payload, ' '))) {
+				*(name++) = '\0';
+				/* Name and payload are required */
+				*dpayload = strdup(payload);
+				status = SWITCH_STATUS_SUCCESS;
+				if ((rate = strchr(name, '/'))) {
+					*(rate++) = '\0';
+					*drate = strdup(rate);
+					*dname = strdup(name);
+				} else {
+					*dname = strdup(name);
+					*drate = strdup("8000");
+				}
+			} else {
+				*dpayload = strdup("10");
+				*dname = strdup("L16");
+				*drate = strdup("8000");
+			}
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Found negotiated codec Payload: %s Name: %s Rate: %s\n", *dpayload, *dname, *drate);
+			break;
+		}
+		attr = NULL;
+		pos++;
+	}
+
+	return status;
+}
+
+static void handle_answer(eXosip_event_t *event)
+{
+	osip_message_t *ack = NULL;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL;
+	struct private_object *tech_pvt;
+	char *dpayload = NULL, *dname = NULL, *drate = NULL;
+	switch_channel *channel;
+
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt!\n");
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (!event->response) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Someone answered... with no SDP information - WTF?!?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+	/* Get all of the remote SDP elements... stuff */
+	if (!(remote_sdp = eXosip_get_sdp_info(event->response))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cant Find SDP?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+
+	conn = eXosip_get_audio_connection(remote_sdp);
+	remote_med = eXosip_get_audio_media(remote_sdp);
+
+	/* Grab IP/port */
+	tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+	snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+	/* Grab codec elements */
+	if (parse_sdp_media(remote_med, &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+		tech_pvt->payload_num = atoi(dpayload);
+	}
+
+	/* Assign them thar IDs */
+	tech_pvt->did = event->did;
+	tech_pvt->tid = event->tid;
+	
+
+	if (1) {
+		int rate = atoi(drate);
+
+
+		if (switch_core_codec_init(&tech_pvt->read_codec, dname, rate, globals.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_channel_hangup(channel);
+			return;
+		} else {
+			if (switch_core_codec_init(&tech_pvt->write_codec, dname, rate, globals.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_channel_hangup(channel);
+				return;
+			} else {
+				int ms;
+				switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+				ms = tech_pvt->write_codec.implementation->nanoseconds_per_frame / 1000;
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Outbound Codec %s/%d %d ms\n", dname, rate, ms);
+				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);
+			}
+		}
+	}
+
+
+	eXosip_lock();
+	eXosip_call_build_ack(event->did, &ack);
+	eXosip_call_send_ack(event->did, ack);
+	eXosip_unlock();
+	
+	free(dname);
+	free(drate);
+	free(dpayload);
+
+
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_channel_answer(channel);
+
+}
+
+static void log_event(eXosip_event_t *je)
+{
+	char buf[100];
+
+	buf[0] = '\0';
+	if (je->type == EXOSIP_CALL_NOANSWER) {
+		snprintf (buf, 99, "<- (%i %i) No answer", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_CLOSED) {
+		snprintf (buf, 99, "<- (%i %i) Call Closed", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_RELEASED) {
+		snprintf (buf, 99, "<- (%i %i) Call released", je->cid, je->did);
+	} else if (je->type == EXOSIP_MESSAGE_NEW
+			   && je->request!=NULL && MSG_IS_MESSAGE(je->request)) {
+		char *tmp = NULL;
+    
+		if (je->request != NULL) {
+			osip_body_t *body;
+			osip_from_to_str (je->request->from, &tmp);
+      
+			osip_message_get_body (je->request, 0, &body);
+			if (body != NULL && body->body != NULL) {
+				snprintf (buf, 99, "<- (%i) from: %s TEXT: %s",
+						  je->tid, tmp, body->body);
+			}
+			osip_free (tmp);
+		} else {
+			snprintf (buf, 99, "<- (%i) New event for unknown request?", je->tid);
+		}
+	} else if (je->type == EXOSIP_MESSAGE_NEW) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+				  je->tid, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->type == EXOSIP_MESSAGE_PROCEEDING
+             || je->type == EXOSIP_MESSAGE_ANSWERED
+             || je->type == EXOSIP_MESSAGE_REDIRECTED
+             || je->type == EXOSIP_MESSAGE_REQUESTFAILURE
+             || je->type == EXOSIP_MESSAGE_SERVERFAILURE
+			   || je->type == EXOSIP_MESSAGE_GLOBALFAILURE) {
+		if (je->response != NULL && je->request != NULL) {
+			char *tmp = NULL;
+      
+			osip_to_to_str (je->request->to, &tmp);
+			snprintf (buf, 99, "<- (%i) [%i %s for %s] to: %s",
+					  je->tid, je->response->status_code,
+					  je->response->reason_phrase, je->request->sip_method, tmp);
+			osip_free (tmp);
+		} else if (je->request != NULL) {
+			snprintf (buf, 99, "<- (%i) Error for %s request",
+					  je->tid, je->request->sip_method);
+		} else {
+			snprintf (buf, 99, "<- (%i) Error for unknown request", je->tid);
+		}
+	} else if (je->response == NULL && je->request != NULL && je->cid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i %i) %s from: %s",
+				  je->cid, je->did, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->cid > 0) {
+		char *tmp = NULL;
+    
+		osip_to_to_str (je->request->to, &tmp);
+		snprintf (buf, 99, "<- (%i %i) [%i %s] for %s to: %s",
+				  je->cid, je->did, je->response->status_code,
+				  je->response->reason_phrase, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->rid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+				  je->rid, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->rid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+				  je->rid, je->response->status_code,
+				  je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->sid > 0) {
+		char *tmp = NULL;
+		char *stat = NULL;
+		osip_header_t *sub_state;
+    
+		osip_message_header_get_byname (je->request, "subscription-state",
+										0, &sub_state);
+		if (sub_state != NULL && sub_state->hvalue != NULL)
+			stat = sub_state->hvalue;
+    
+		osip_uri_to_str (je->request->from->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%s] %s from: %s",
+				  je->sid, stat, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->sid > 0) {
+		char *tmp = NULL;
+    
+		osip_uri_to_str (je->request->to->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+				  je->sid, je->response->status_code,
+				  je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) %s from: %s",
+				  je->cid, je->did, je->sid, je->nid,
+				  je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) [%i %s] for %s from: %s",
+				  je->cid, je->did, je->sid, je->nid,
+				  je->response->status_code, je->response->reason_phrase,
+				  je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else {
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i|t=%i) %s",
+				  je->cid, je->did, je->sid, je->nid, je->tid, je->textinfo);
+	}
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\n%s\n", buf);
+	/* Print it out */
+}
+
+
+
+static void *monitor_thread_run(void)
+{
+	eXosip_event_t *event = NULL;
+	
+	globals.running = 1;
+	while (globals.running > 0) {
+		if (!(event = eXosip_event_wait(0,100))) {
+			switch_yield(100);
+			continue;
+		}
+
+		eXosip_lock();
+		eXosip_automatic_action ();
+		eXosip_unlock();
+
+		log_event(event);
+
+		switch(event->type) {
+		case EXOSIP_CALL_INVITE:
+			exosip_create_call(event);
+			break;
+		case EXOSIP_CALL_REINVITE:
+			/* See what the reinvite is about - on hold or whatever */
+			//handle_reinvite(event);
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got a reinvite.\n");
+			break;
+		case EXOSIP_CALL_MESSAGE_NEW:
+			if (event->request != NULL && MSG_IS_REFER(event->request)) {
+				//handle_call_transfer(event);
+			}
+			break;
+		case EXOSIP_CALL_ACK:
+			/* If audio is not flowing and this has SDP - fire it up! */
+			break;
+		case EXOSIP_CALL_ANSWERED:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was answered.\n");
+			handle_answer(event);
+			break;
+		case EXOSIP_CALL_PROCEEDING:
+			/* This is like a 100 Trying... yeah */
+			break;
+		case EXOSIP_CALL_RINGING:
+			//handle_ringing(event);
+			break;
+		case EXOSIP_CALL_REDIRECTED:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Call was redirect\n");
+			break;
+		case EXOSIP_CALL_CLOSED:
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_RELEASED:
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_NOANSWER:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was not answered.\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_REQUESTFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Request failure\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_SERVERFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Server failure\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_GLOBALFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Global failure\n");
+			destroy_call_by_event(event);
+			break;
+			/* Registration related stuff */
+		case EXOSIP_REGISTRATION_NEW:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Received registration attempt\n");
+			break;
+		default:
+			/* Unknown event... casually absorb it for now */
+			break;
+		}
+
+		//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "There was an event (%d) [%s]\n", event->type, event->textinfo);
+		/* Free the event */
+		eXosip_event_free(event);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Monitor Thread Exiting\n");
+	globals.running = 0;
+	return NULL;
+}
+
+
+static int config_exosip(int reload) 
+{
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "exosip.conf";
+
+	globals.bytes_per_frame = DEFAULT_BYTES_PER_FRAME;
+	switch_core_hash_init(&globals.call_hash, module_pool);
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+
+	globals.rtp_start = 16384;
+	globals.rtp_end = 32768;
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+			} else if (!strcmp(var, "rtp_min_port")) {
+				globals.rtp_start = atoi(val);
+			} else if (!strcmp(var, "rtp_max_port")) {
+				globals.rtp_end = atoi(val);
+			} else if (!strcmp(var, "codec_ms")) {
+				globals.codec_ms = atoi(val);
+			}
+		}
+	}
+	
+	if (!globals.codec_ms) {
+		globals.codec_ms = 20;
+	}
+
+	if (!globals.port) {
+		globals.port = 5060;
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+
+	if (eXosip_init ()) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_init initialization failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+	if (eXosip_listen_addr (IPPROTO_UDP, NULL, globals.port, AF_INET, 0)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_listen_addr failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch_mutex_init(&globals.port_lock, SWITCH_MUTEX_NESTED, module_pool);
+
+
+	/* Setup the user agent */
+	eXosip_set_user_agent("OPENSWITCH 2.0");
+
+
+	monitor_thread_run();
+	return 0;
+
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+	config_exosip(0);
+	return SWITCH_STATUS_TERM;
+}
+
diff --git a/src/mod/endpoints/mod_exosip/mod_exosip_ucl.c b/src/mod/endpoints/mod_exosip/mod_exosip_ucl.c
new file mode 100644
index 0000000000..54c3b0364c
--- /dev/null
+++ b/src/mod/endpoints/mod_exosip/mod_exosip_ucl.c
@@ -0,0 +1,1438 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_exosip.c -- eXoSIP SIP Endpoint
+ *
+ */
+
+
+#define HAVE_APR
+
+#include <config_unix.h>
+#include <config_win32.h>
+
+#include <switch.h>
+
+#include <debug.h>
+#include <memory.h>
+#include <rtp.h>
+
+#include <eXosip2/eXosip.h>
+#include <osip2/osip_mt.h>
+#include <osipparser2/osip_rfc3264.h>
+#include <osipparser2/osip_port.h>
+
+
+
+//#include <sys/queue.h>
+//#include <ctype.h>
+//#include <string.h>
+//#include <byteswap.h>
+//#include <uclconf.h>
+
+static const char modname[] = "mod_exosip";
+#define STRLEN 15
+
+static switch_memory_pool *module_pool;
+
+typedef enum {
+	PFLAG_ANSWER = (1 << 0),
+	PFLAG_HANGUP = (1 << 1),
+} PFLAGS;
+
+
+typedef enum {
+	PPFLAG_RING = (1 << 0),
+} PPFLAGS;
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_READING = (1 << 4),
+	TFLAG_WRITING = (1 << 5),
+	TFLAG_USING_CODEC = (1 << 6),	
+	TFLAG_RTP = (1 << 7),
+	TFLAG_BYE = (1 << 8)
+} TFLAGS;
+
+
+#define PACKET_LEN 160
+#define DEFAULT_BYTES_PER_FRAME 160
+
+
+static const switch_endpoint_interface exosip_endpoint_interface;
+
+static struct {
+	int debug;
+	int bytes_per_frame;
+	char *dialplan;
+	int port;
+	int rtp_start;
+	int rtp_end;
+	switch_hash *call_hash;
+	switch_mutex_t *port_lock;
+	int running;
+	int codec_ms;
+} globals;
+
+struct private_object {
+	unsigned int flags;		
+	switch_core_session *session;
+	switch_frame read_frame;
+	switch_codec read_codec;
+	switch_codec write_codec;
+	unsigned char read_buf[RTP_MAX_PACKET_LEN];
+	switch_caller_profile *caller_profile;
+	int cid;
+	int did;
+	int tid;
+	int32_t timestamp_send;
+	int32_t timestamp_recv;
+	int payload_num;
+	struct rtp	*rtp_session;
+	struct osip_rfc3264 *sdp_config;
+	sdp_message_t *remote_sdp;
+	sdp_message_t *local_sdp;
+	char remote_sdp_audio_ip[50];
+	int remote_sdp_audio_port;
+	char local_sdp_audio_ip[50];
+	int local_sdp_audio_port;
+	char call_id[50];
+	int ssrc;
+	//switch_mutex_t *rtp_lock;
+};
+
+
+static int next_rtp_port(void)
+{
+	int port;
+
+	switch_mutex_lock(globals.port_lock);
+	port = globals.rtp_start;
+	globals.rtp_start += 2;
+	if (port >= globals.rtp_end) {
+		port = globals.rtp_start;
+	}
+	switch_mutex_unlock(globals.port_lock);
+	return port;
+}
+
+
+static void set_global_dialplan(char *dialplan)
+{
+	if (globals.dialplan) {
+		free(globals.dialplan);
+		globals.dialplan = NULL;
+	}
+	
+	globals.dialplan = strdup(dialplan);
+}
+
+static void set_global_dialplan(char *dialplan);
+static switch_status exosip_on_init(switch_core_session *session);
+static switch_status exosip_on_hangup(switch_core_session *session);
+static switch_status exosip_on_loopback(switch_core_session *session);
+static switch_status exosip_on_transmit(switch_core_session *session);
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static int config_exosip(int reload);
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload);
+static switch_status exosip_kill_channel(switch_core_session *session, int sig);
+static void activate_rtp(struct private_object *tech_pvt);
+static void deactivate_rtp(struct private_object *tech_pvt);
+
+static struct private_object *get_pvt_by_call_id(int id)
+{
+	char name[50];
+	snprintf(name, sizeof(name), "%d", id);
+	return (struct private_object *) switch_core_hash_find(globals.call_hash, name);
+}
+
+static switch_status exosip_on_execute(switch_core_session *session)
+{
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static int sdp_add_codec(struct osip_rfc3264 *cnf, int codec_type, int payload, char *attribute, int rate, int index)
+{
+	char tmp[4] = "", string[32] = "";
+	sdp_media_t *med = NULL;
+	sdp_attribute_t *attr = NULL;
+
+	sdp_media_init(&med);
+	if (med == NULL)
+		return -1;
+
+	if (!index) {
+		snprintf(tmp, sizeof(tmp), "%i", payload);
+		med->m_proto = osip_strdup("RTP/AVP");
+		osip_list_add(med->m_payloads, osip_strdup(tmp), -1);
+	}
+	if (attribute) {
+		sdp_attribute_init(&attr);
+		attr->a_att_field = osip_strdup("rtpmap");
+		snprintf(string, sizeof(string), "%i %s/%i", payload, attribute, rate);
+		attr->a_att_value = osip_strdup(string);
+		osip_list_add(med->a_attributes, attr, -1);
+	}
+
+	switch (codec_type) {
+	case SWITCH_CODEC_TYPE_AUDIO:
+		med->m_media = osip_strdup("audio");
+		osip_rfc3264_add_audio_media(cnf, med, -1);
+		break;
+	case SWITCH_CODEC_TYPE_VIDEO:
+		med->m_media = osip_strdup("video");
+		osip_rfc3264_add_video_media(cnf, med, -1);
+		break;
+	default:
+		break;
+	}
+	 return 0;
+}
+
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status exosip_on_init(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	char from_uri[512] = "", localip[128] = "", port[7] = "", *buf = NULL, tmp[512] = "";
+	osip_message_t *invite = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.data = tech_pvt->read_buf;
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP INIT\n");
+
+	if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+		char *dest_uri;
+		switch_codec_interface *codecs[512];
+		int num_codecs = 0;
+		/* do SIP Goodies...*/
+
+		/* Generate callerid URI */
+		eXosip_guess_localip(AF_INET, localip, 128);
+		snprintf(from_uri, sizeof(from_uri), "<sip:%s@%s>", tech_pvt->caller_profile->caller_id_number, localip);
+		/* Setup codec negotiation stuffs */
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Decide on local IP and rtp port */
+		strncpy(tech_pvt->local_sdp_audio_ip, localip, sizeof(tech_pvt->local_sdp_audio_ip));
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		/* Initialize SDP */
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_v_version_set(tech_pvt->local_sdp, "0");
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		sdp_message_t_time_descr_add(tech_pvt->local_sdp, "0", "0");
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_media_add(tech_pvt->local_sdp, "audio", port, NULL, "RTP/AVP");
+		/* Add in every codec we support on this outbound call */
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+
+				snprintf(tmp, sizeof(tmp), "%i", codecs[i]->ianacode);
+				sdp_message_m_payload_add(tech_pvt->local_sdp, 0, osip_strdup(tmp));
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					/* Add to SDP config */
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+					/* Add to SDP message */
+
+					snprintf(tmp, sizeof(tmp), "%i %s/%i", codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second);
+					sdp_message_a_attribute_add(tech_pvt->local_sdp, 0, "rtpmap", osip_strdup(tmp));
+					memset(tmp, 0, sizeof(tmp));
+				}
+			}
+		}
+		/* Setup our INVITE */
+		eXosip_lock();
+		if (!(dest_uri = (char *) switch_core_session_alloc(session, strlen(tech_pvt->caller_profile->destination_number) + 10))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "AIEEEE!\n");
+			assert(dest_uri != NULL);
+		}
+		sprintf(dest_uri, "sip:%s", tech_pvt->caller_profile->destination_number);
+		eXosip_call_build_initial_invite(&invite, dest_uri, from_uri, NULL, NULL);
+		osip_message_set_supported(invite, "100rel, replaces");
+		/* Add SDP to the INVITE */
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(invite, buf, strlen(buf));
+		osip_message_set_content_type(invite, "application/sdp");
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OUTBOUND SDP:\n%s\n", buf);
+		free(buf);
+		/* Send the INVITE */
+		tech_pvt->cid = eXosip_call_send_initial_invite(invite);
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", tech_pvt->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);
+		tech_pvt->did = -1;
+		eXosip_unlock();
+	} 
+
+
+	/* Let Media Work */
+	switch_set_flag(tech_pvt, TFLAG_IO);
+
+	/* Move Channel's State Machine to RING */
+	switch_channel_set_state(channel, CS_RING);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP RING\n");
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_hangup(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	int i;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_core_hash_delete(globals.call_hash, tech_pvt->call_id);	
+	
+
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+
+	deactivate_rtp(tech_pvt);
+
+	i = eXosip_call_terminate(tech_pvt->cid, tech_pvt->did);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		switch_core_codec_destroy(&tech_pvt->read_codec);
+		switch_core_codec_destroy(&tech_pvt->write_codec);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP HANGUP %s %d/%d=%d\n", switch_channel_get_name(channel), tech_pvt->cid, tech_pvt->did, i);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "EXOSIP TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session)
+{
+	if ((*new_session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel, *orig_channel;
+		switch_caller_profile *caller_profile, *originator_caller_profile = NULL;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			//switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(*new_session));
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "Exosip/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		/* (session == NULL) means it was originated from the core not from another channel */
+		if (session && (orig_channel = switch_core_session_get_channel(session))) {
+			switch_caller_profile *cloned_profile;
+
+			if ((originator_caller_profile = switch_channel_get_caller_profile(orig_channel))) {
+				cloned_profile = switch_caller_profile_clone(*new_session, originator_caller_profile);
+				switch_channel_set_originator_caller_profile(channel, cloned_profile);
+			}
+		}
+		
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+}
+
+#if 0
+static const char *event_names[] = {
+	"RX_RTP",
+	"RX_SR",	
+	"RX_RR",
+	"RX_SDES",
+	"RX_BYE",
+	"SOURCE_CREATED",
+	"SOURCE_DELETED",
+	"RX_RR_EMPTY",
+	"RX_RTCP_START",
+	"RX_RTCP_FINISH",
+	"RR_TIMEOUT",
+	"RX_APP"
+};
+#endif
+
+static void rtp_event_handler(struct rtp *session, rtp_event *event) 
+{
+	rtp_packet	*packet;
+	struct private_object *tech_pvt = (struct private_object *) rtp_get_userdata(session);
+
+	if (!session) {
+		return;
+	}
+
+
+	//switch_console_printf(SWITCH_CHANNEL_CONSOLE,	"RTP EVENT (%s)\n", event_names[event->type]);
+
+	switch(event->type) {
+	case RX_RTP:
+		if((packet = (rtp_packet *) event->data)) {
+			if (packet->data_len < 10000) {
+				memcpy(tech_pvt->read_buf, packet->data, packet->data_len);
+				tech_pvt->read_frame.datalen = packet->data_len;
+			} else {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE,	"WTF PACKET LEN %d\n", packet->data_len);
+			}	
+			free(packet); /* xfree() is mandatory to release RTP packet data */		
+		}
+			break;
+	case RR_TIMEOUT:
+	case RX_BYE:
+		switch_set_flag(tech_pvt, TFLAG_BYE);
+	default:
+		break;
+	}
+}
+
+static void deactivate_rtp(struct private_object *tech_pvt)
+{
+	int loops = 0;
+	if (tech_pvt->rtp_session) {
+		//switch_mutex_lock(tech_pvt->rtp_lock);
+
+		while(loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
+			switch_yield(10000);
+			loops++;
+		}
+		rtp_send_bye(tech_pvt->rtp_session);
+		rtp_done(tech_pvt->rtp_session);
+		tech_pvt->rtp_session = NULL;
+		//switch_mutex_unlock(tech_pvt->rtp_lock);
+	}
+}
+
+static void activate_rtp(struct private_object *tech_pvt)
+{
+	int bw, ms;
+	switch_channel *channel;
+
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activating RTP %d->%s:%d\n",
+					   tech_pvt->local_sdp_audio_port,
+					   tech_pvt->remote_sdp_audio_ip,
+					   tech_pvt->remote_sdp_audio_port);
+
+
+	//switch_mutex_lock(tech_pvt->rtp_lock);
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bw = tech_pvt->read_codec.implementation->bits_per_second;
+		ms = tech_pvt->read_codec.implementation->nanoseconds_per_frame / 1000;
+	} else {
+		switch_channel_get_raw_mode(channel, NULL, NULL, NULL, &ms, &bw);
+		bw *= 8;
+	}
+
+	tech_pvt->rtp_session = rtp_init(tech_pvt->remote_sdp_audio_ip,		/* Host/Group IP address */ 
+									 tech_pvt->local_sdp_audio_port,	/* receive port */
+									 tech_pvt->remote_sdp_audio_port,	/* transmit port */
+									 ms * 2,							/* time-to-live */
+									 bw,								/* B/W estimate */
+									 rtp_event_handler,					/* RTP event callback */
+									 (void *) tech_pvt);				/* App. specific data */
+
+
+	if (tech_pvt->rtp_session) {
+		tech_pvt->ssrc = rtp_my_ssrc(tech_pvt->rtp_session);
+		rtp_set_option(tech_pvt->rtp_session, RTP_OPT_PROMISC, 1);
+		/* Set local participant info */
+		rtp_set_sdes(tech_pvt->rtp_session, tech_pvt->ssrc, RTCP_SDES_NAME, "test", 4);
+		rtp_set_sdes(tech_pvt->rtp_session, tech_pvt->ssrc, RTCP_SDES_PHONE, "test", 4);
+		rtp_set_sdes(tech_pvt->rtp_session, tech_pvt->ssrc, RTCP_SDES_TOOL, "test", 4);
+		switch_set_flag(tech_pvt, TFLAG_RTP);		
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Oh oh is your port even?\n");
+	}
+	//switch_mutex_unlock(tech_pvt->rtp_lock);
+}
+
+static switch_status exosip_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!switch_channel_test_flag(channel, CF_OUTBOUND)) {
+		char *buf = NULL;
+		osip_message_t *answer = NULL;
+
+
+		/* Transmit 200 OK with SDP */
+		eXosip_lock();
+		eXosip_call_build_answer(tech_pvt->tid, 200, &answer);
+		sdp_message_to_str(tech_pvt->local_sdp, &buf);
+		osip_message_set_body(answer, buf, strlen(buf));
+		osip_message_set_content_type(answer, "application/sdp");
+		free(buf); 
+		eXosip_call_send_answer(tech_pvt->tid, 200, answer);
+		eXosip_unlock();
+	} 
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	struct private_object *tech_pvt = NULL;
+	size_t bytes = 0, samples = 0, frames, ms, x;
+	switch_channel *channel = NULL;
+	int ns=0;
+	struct timeval tv;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->read_frame.datalen = 0;
+	switch_set_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		samples = tech_pvt->read_codec.implementation->samples_per_frame;
+	} else {
+		assert(0);
+	}
+
+	if (timeout > 0) {
+		ns = timeout * 10000;
+	} else {
+		ns = tech_pvt->read_codec.implementation->nanoseconds_per_frame;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_IO)) {
+		if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+			activate_rtp(tech_pvt);
+		}
+
+		assert(tech_pvt->rtp_session != NULL);
+		tech_pvt->read_frame.datalen = 0;
+		//switch_mutex_lock(tech_pvt->rtp_lock);
+		tv.tv_sec = 0;
+		tv.tv_usec = ns;
+		while(switch_test_flag(tech_pvt, TFLAG_IO) && !switch_test_flag(tech_pvt, TFLAG_BYE)) {
+			x = rtp_recv(tech_pvt->rtp_session, &tv, tech_pvt->timestamp_recv);
+			if(x < 0) {
+				break;
+			}
+			if (tech_pvt->read_frame.datalen) {
+				bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+				frames = (tech_pvt->read_frame.datalen / bytes);
+				samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+				ms = frames * tech_pvt->read_codec.implementation->nanoseconds_per_frame / 1000;
+				break;
+			}
+		}
+		tech_pvt->timestamp_recv += (int)samples;
+		//printf("%s\trecv %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->read_frame.datalen, samples, frames, ms, tech_pvt->timestamp_recv);
+		//switch_mutex_unlock(tech_pvt->rtp_lock);
+
+	} else {
+		memset(tech_pvt->read_buf, 0, 160);
+		tech_pvt->read_frame.datalen = 160;
+	}
+
+	switch_clear_flag(tech_pvt, TFLAG_READING);
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	*frame = &tech_pvt->read_frame;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	switch_status status = SWITCH_STATUS_SUCCESS;
+	size_t x, bytes, samples, ms, frames;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+		activate_rtp(tech_pvt);
+	}
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	if (switch_test_flag(tech_pvt, TFLAG_BYE)) {
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	switch_set_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_lock(tech_pvt->rtp_lock);
+
+	if (switch_test_flag(tech_pvt, TFLAG_USING_CODEC)) {
+		bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+		frames = (frame->datalen / bytes);
+		samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+		ms = frames * tech_pvt->read_codec.implementation->nanoseconds_per_frame / 1000;
+	} else {
+		assert(0);
+	}
+	tech_pvt->timestamp_send += (int)samples;
+
+
+	//printf("%s %s->%s send %d bytes %d samples in %d frames taking up %d ms ts=%d\n", switch_channel_get_name(channel), tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, ms, tech_pvt->timestamp_recv);
+	
+	rtp_send_ctrl(tech_pvt->rtp_session, tech_pvt->timestamp_send, NULL);
+	x = rtp_send_data(tech_pvt->rtp_session, tech_pvt->timestamp_send, tech_pvt->payload_num,
+					  0, 0, 0,
+					  (char *)frame->data, (int)frame->datalen,
+					  0, 0, 0);
+
+
+	switch_clear_flag(tech_pvt, TFLAG_WRITING);
+	//switch_mutex_unlock(tech_pvt->rtp_lock);
+	return status;
+}
+
+
+
+static switch_status exosip_kill_channel(switch_core_session *session, int sig)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_set_flag(tech_pvt, TFLAG_BYE);
+	//rtp_kill(tech_pvt->rtp_session);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status exosip_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status exosip_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	return SWITCH_STATUS_SUCCESS;
+
+}
+	
+static const switch_io_routines exosip_io_routines = {
+	/*.outgoing_channel*/	exosip_outgoing_channel,
+	/*.answer_channel*/		exosip_answer_channel,
+	/*.read_frame*/			exosip_read_frame,
+	/*.write_frame*/		exosip_write_frame,
+	/*.kill_channel*/		exosip_kill_channel,
+	/*.waitfor_read*/		exosip_waitfor_read,
+	/*.waitfor_read*/		exosip_waitfor_write
+};
+
+static const switch_event_handler_table  exosip_event_handlers = {
+	/*.on_init*/			exosip_on_init,
+	/*.on_ring*/			exosip_on_ring,
+	/*.on_execute*/			exosip_on_execute,
+	/*.on_hangup*/			exosip_on_hangup,
+	/*.on_loopback*/		exosip_on_loopback,
+	/*.on_transmit*/		exosip_on_transmit
+};
+
+static const switch_endpoint_interface exosip_endpoint_interface = {
+	/*.interface_name*/		"exosip",
+	/*.io_routines*/		&exosip_io_routines,
+	/*.event_handlers*/		&exosip_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface exosip_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&exosip_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	if (globals.running) {
+		globals.running = -1;
+		while(globals.running) {
+			switch_yield(1000);
+		}
+	}
+	eXosip_quit();
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **_interface, char *filename) {
+	/* NOTE:  **interface is **_interface because the common lib redefines interface to struct in some situations */
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+	
+	/* connect my internal structure to the blank pointer passed to me */
+	*_interface = &exosip_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status exosip_create_call(eXosip_event_t *event)
+{
+	switch_core_session *session;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL, *audio_tab[10], *video_tab[10], *t38_tab[10], *app_tab[10];
+	char local_sdp_str[8192] = "", port[8] = "";
+	int mline = 0, pos = 0;
+	switch_channel *channel = NULL;
+	char name[128];
+	char *dpayload, *dname, *drate;
+	char *remote_sdp_str = NULL;
+
+	if ((session = switch_core_session_request(&exosip_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_codec_interface *codecs[512];
+		int num_codecs = 0;
+
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(session);
+			switch_core_session_set_private(session, tech_pvt);
+			tech_pvt->session = session;
+			//switch_mutex_init(&tech_pvt->rtp_lock, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_MEMERR;
+		}
+		
+		if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+															   globals.dialplan,
+															   event->request->from->displayname,
+															   event->request->from->url->username,
+															   event->request->from->url->username,
+															   NULL,
+															   event->request->req_uri->username))) {
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+
+		switch_set_flag(tech_pvt, TFLAG_INBOUND);
+		tech_pvt->did = event->did;
+		tech_pvt->cid = event->cid;
+		tech_pvt->tid = event->tid;
+
+		snprintf(name, sizeof(name), "Exosip/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
+		switch_channel_set_name(channel, name);
+		
+		if (!(remote_sdp = eXosip_get_sdp_info(event->request))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Find Remote SDP!\n");
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		eXosip_guess_localip(AF_INET, tech_pvt->local_sdp_audio_ip, 50);
+		tech_pvt->local_sdp_audio_port = next_rtp_port();
+		osip_rfc3264_init(&tech_pvt->sdp_config);
+		/* Add in what codecs we support locally */
+		
+		if ((num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(session), codecs, sizeof(codecs)/sizeof(codecs[0]))) > 0) {
+			int i;
+			static const switch_codec_implementation *imp;
+
+			for (i = 0; i < num_codecs; i++) {
+				int x = 0;
+				for (imp = codecs[i]->implementations ; imp ; imp = imp->next) {
+					sdp_add_codec(tech_pvt->sdp_config, codecs[i]->codec_type, codecs[i]->ianacode, codecs[i]->iananame, imp->samples_per_second, x++);
+				}
+			}
+		}
+		osip_rfc3264_prepare_answer(tech_pvt->sdp_config, remote_sdp, local_sdp_str, 8192);
+		sdp_message_init(&tech_pvt->local_sdp);
+		sdp_message_parse(tech_pvt->local_sdp, local_sdp_str);
+
+		sdp_message_to_str(remote_sdp, &remote_sdp_str);
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "LOCAL SDP:\n%s\nREMOTE SDP:\n%s", local_sdp_str,remote_sdp_str);
+		
+		mline = 0;
+		while (0==osip_rfc3264_match(tech_pvt->sdp_config, remote_sdp, audio_tab, video_tab, t38_tab, app_tab, mline)) {
+			if (audio_tab[0] == NULL && video_tab[0] == NULL && t38_tab[0] == NULL && app_tab[0] == NULL) {
+
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got no compatible codecs!\n");
+				break;
+			}
+			for (pos=0; audio_tab[pos]!=NULL; pos++) {
+				osip_rfc3264_complete_answer(tech_pvt->sdp_config, remote_sdp, tech_pvt->local_sdp, audio_tab[pos], mline);
+				if (parse_sdp_media(audio_tab[pos], &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+					tech_pvt->payload_num = atoi(dpayload);
+					break;
+				}
+			}
+			mline++;
+		}
+		free(remote_sdp_str);
+		sdp_message_o_origin_set(tech_pvt->local_sdp, "OpenSWITCH2", "0", "0", "IN", "IP4", tech_pvt->local_sdp_audio_ip);
+		sdp_message_s_name_set(tech_pvt->local_sdp, "SIP Call");
+		sdp_message_c_connection_add(tech_pvt->local_sdp, -1, "IN", "IP4", tech_pvt->local_sdp_audio_ip, NULL, NULL);
+		snprintf(port, sizeof(port), "%i", tech_pvt->local_sdp_audio_port);
+		sdp_message_m_port_set(tech_pvt->local_sdp, 0, osip_strdup(port));
+
+		conn = eXosip_get_audio_connection(remote_sdp);
+		remote_med = eXosip_get_audio_media(remote_sdp);
+		snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+		tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+		
+		snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", event->cid);
+		switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);	
+
+		if (!dname) {
+			exosip_on_hangup(session);
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_state(channel, CS_INIT);
+
+
+		if (1) {
+			int rate = atoi(drate);
+
+			if (switch_core_codec_init(&tech_pvt->read_codec,
+									dname,
+									rate,
+									globals.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_channel_hangup(channel);
+				return SWITCH_STATUS_FALSE;
+			} else {
+				if (switch_core_codec_init(&tech_pvt->write_codec,
+										dname,
+										rate,
+										globals.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_channel_hangup(channel);
+					return SWITCH_STATUS_FALSE;
+				} else {
+					int ms;
+					switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+					ms = tech_pvt->write_codec.implementation->nanoseconds_per_frame / 1000;
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Inbound Codec %s/%d %d ms\n", dname, rate, ms);
+					tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+					switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+					switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+				}
+			}
+		}
+		
+		switch_core_session_thread_launch(session);
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create new Inbound Channel!\n");
+	}
+
+
+	return 0;
+
+
+
+}
+
+static void destroy_call_by_event(eXosip_event_t *event)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt [%d]!\n", event->cid);
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "destroy %s\n", switch_channel_get_name(channel));
+	exosip_kill_channel(tech_pvt->session, SWITCH_SIG_KILL);
+	switch_channel_hangup(channel);
+	
+}
+
+static switch_status parse_sdp_media(sdp_media_t *media, char **dname, char **drate, char **dpayload)
+{
+	int pos = 0;
+	sdp_attribute_t *attr = NULL;
+	char *name, *rate, *payload;
+	switch_status status = SWITCH_STATUS_GENERR;
+
+	while (osip_list_eol(media->a_attributes, pos) == 0) {
+		attr = (sdp_attribute_t *)osip_list_get(media->a_attributes, pos);
+		if (attr != NULL && strcasecmp(attr->a_att_field, "rtpmap") == 0) {
+			payload = attr->a_att_value;
+			if ((name = strchr(payload, ' '))) {
+				*(name++) = '\0';
+				/* Name and payload are required */
+				*dpayload = strdup(payload);
+				status = SWITCH_STATUS_SUCCESS;
+				if ((rate = strchr(name, '/'))) {
+					*(rate++) = '\0';
+					*drate = strdup(rate);
+					*dname = strdup(name);
+				} else {
+					*dname = strdup(name);
+					*drate = strdup("8000");
+				}
+			} else {
+				*dpayload = strdup("10");
+				*dname = strdup("L16");
+				*drate = strdup("8000");
+			}
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Found negotiated codec Payload: %s Name: %s Rate: %s\n", *dpayload, *dname, *drate);
+			break;
+		}
+		attr = NULL;
+		pos++;
+	}
+
+	return status;
+}
+
+static void handle_answer(eXosip_event_t *event)
+{
+	osip_message_t *ack = NULL;
+	sdp_message_t *remote_sdp = NULL;
+	sdp_connection_t *conn = NULL;
+	sdp_media_t *remote_med = NULL;
+	struct private_object *tech_pvt;
+	char *dpayload = NULL, *dname = NULL, *drate = NULL;
+	switch_channel *channel;
+
+
+	if (!(tech_pvt = get_pvt_by_call_id(event->cid))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Um in case you are interested, Can't find the pvt!\n");
+		return;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (!event->response) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Someone answered... with no SDP information - WTF?!?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+	/* Get all of the remote SDP elements... stuff */
+	if (!(remote_sdp = eXosip_get_sdp_info(event->response))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cant Find SDP?\n");
+		switch_channel_hangup(channel);
+		return;
+	}
+
+
+	conn = eXosip_get_audio_connection(remote_sdp);
+	remote_med = eXosip_get_audio_media(remote_sdp);
+
+	/* Grab IP/port */
+	tech_pvt->remote_sdp_audio_port = atoi(remote_med->m_port);
+	snprintf(tech_pvt->remote_sdp_audio_ip, 50, conn->c_addr);
+
+	/* Grab codec elements */
+	if (parse_sdp_media(remote_med, &dname, &drate, &dpayload) == SWITCH_STATUS_SUCCESS) {
+		tech_pvt->payload_num = atoi(dpayload);
+	}
+
+	/* Assign them thar IDs */
+	tech_pvt->did = event->did;
+	tech_pvt->tid = event->tid;
+	
+
+	if (1) {
+		int rate = atoi(drate);
+
+
+		if (switch_core_codec_init(&tech_pvt->read_codec, dname, rate, globals.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_channel_hangup(channel);
+			return;
+		} else {
+			if (switch_core_codec_init(&tech_pvt->write_codec, dname, rate, globals.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_channel_hangup(channel);
+				return;
+			} else {
+				int ms;
+				switch_set_flag(tech_pvt, TFLAG_USING_CODEC);
+				ms = tech_pvt->write_codec.implementation->nanoseconds_per_frame / 1000;
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Outbound Codec %s/%d %d ms\n", dname, rate, ms);
+				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);
+			}
+		}
+	}
+
+
+	eXosip_lock();
+	eXosip_call_build_ack(event->did, &ack);
+	eXosip_call_send_ack(event->did, ack);
+	eXosip_unlock();
+	
+	free(dname);
+	free(drate);
+	free(dpayload);
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	switch_channel_answer(channel);
+
+}
+
+static void log_event(eXosip_event_t *je)
+{
+	char buf[100];
+
+	buf[0] = '\0';
+	if (je->type == EXOSIP_CALL_NOANSWER) {
+		snprintf (buf, 99, "<- (%i %i) No answer", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_CLOSED) {
+		snprintf (buf, 99, "<- (%i %i) Call Closed", je->cid, je->did);
+	} else if (je->type == EXOSIP_CALL_RELEASED) {
+		snprintf (buf, 99, "<- (%i %i) Call released", je->cid, je->did);
+	} else if (je->type == EXOSIP_MESSAGE_NEW
+			   && je->request!=NULL && MSG_IS_MESSAGE(je->request)) {
+		char *tmp = NULL;
+    
+		if (je->request != NULL) {
+			osip_body_t *body;
+			osip_from_to_str (je->request->from, &tmp);
+      
+			osip_message_get_body (je->request, 0, &body);
+			if (body != NULL && body->body != NULL) {
+				snprintf (buf, 99, "<- (%i) from: %s TEXT: %s",
+						  je->tid, tmp, body->body);
+			}
+			osip_free (tmp);
+		} else {
+			snprintf (buf, 99, "<- (%i) New event for unknown request?", je->tid);
+		}
+	} else if (je->type == EXOSIP_MESSAGE_NEW) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+				  je->tid, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->type == EXOSIP_MESSAGE_PROCEEDING
+             || je->type == EXOSIP_MESSAGE_ANSWERED
+             || je->type == EXOSIP_MESSAGE_REDIRECTED
+             || je->type == EXOSIP_MESSAGE_REQUESTFAILURE
+             || je->type == EXOSIP_MESSAGE_SERVERFAILURE
+			   || je->type == EXOSIP_MESSAGE_GLOBALFAILURE) {
+		if (je->response != NULL && je->request != NULL) {
+			char *tmp = NULL;
+      
+			osip_to_to_str (je->request->to, &tmp);
+			snprintf (buf, 99, "<- (%i) [%i %s for %s] to: %s",
+					  je->tid, je->response->status_code,
+					  je->response->reason_phrase, je->request->sip_method, tmp);
+			osip_free (tmp);
+		} else if (je->request != NULL) {
+			snprintf (buf, 99, "<- (%i) Error for %s request",
+					  je->tid, je->request->sip_method);
+		} else {
+			snprintf (buf, 99, "<- (%i) Error for unknown request", je->tid);
+		}
+	} else if (je->response == NULL && je->request != NULL && je->cid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i %i) %s from: %s",
+				  je->cid, je->did, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->cid > 0) {
+		char *tmp = NULL;
+    
+		osip_to_to_str (je->request->to, &tmp);
+		snprintf (buf, 99, "<- (%i %i) [%i %s] for %s to: %s",
+				  je->cid, je->did, je->response->status_code,
+				  je->response->reason_phrase, je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->rid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) %s from: %s",
+				  je->rid, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->rid > 0) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+				  je->rid, je->response->status_code,
+				  je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL && je->sid > 0) {
+		char *tmp = NULL;
+		char *stat = NULL;
+		osip_header_t *sub_state;
+    
+		osip_message_header_get_byname (je->request, "subscription-state",
+										0, &sub_state);
+		if (sub_state != NULL && sub_state->hvalue != NULL)
+			stat = sub_state->hvalue;
+    
+		osip_uri_to_str (je->request->from->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%s] %s from: %s",
+				  je->sid, stat, je->request->cseq->method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL && je->sid > 0) {
+		char *tmp = NULL;
+    
+		osip_uri_to_str (je->request->to->url, &tmp);
+		snprintf (buf, 99, "<- (%i) [%i %s] from: %s",
+				  je->sid, je->response->status_code,
+				  je->response->reason_phrase, tmp);
+		osip_free (tmp);
+	} else if (je->response == NULL && je->request != NULL) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) %s from: %s",
+				  je->cid, je->did, je->sid, je->nid,
+				  je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else if (je->response != NULL) {
+		char *tmp = NULL;
+    
+		osip_from_to_str (je->request->from, &tmp);
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i) [%i %s] for %s from: %s",
+				  je->cid, je->did, je->sid, je->nid,
+				  je->response->status_code, je->response->reason_phrase,
+				  je->request->sip_method, tmp);
+		osip_free (tmp);
+	} else {
+		snprintf (buf, 99, "<- (c=%i|d=%i|s=%i|n=%i|t=%i) %s",
+				  je->cid, je->did, je->sid, je->nid, je->tid, je->textinfo);
+	}
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\n%s\n", buf);
+	/* Print it out */
+}
+
+
+
+static void *monitor_thread_run(void)
+{
+	eXosip_event_t *event = NULL;
+	
+	globals.running = 1;
+	while (globals.running > 0) {
+		if (!(event = eXosip_event_wait(0,100))) {
+			switch_yield(100);
+			continue;
+		}
+
+		eXosip_lock();
+		eXosip_automatic_action ();
+		eXosip_unlock();
+
+		log_event(event);
+
+		switch(event->type) {
+		case EXOSIP_CALL_INVITE:
+			exosip_create_call(event);
+			break;
+		case EXOSIP_CALL_REINVITE:
+			/* See what the reinvite is about - on hold or whatever */
+			//handle_reinvite(event);
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Got a reinvite.\n");
+			break;
+		case EXOSIP_CALL_MESSAGE_NEW:
+			if (event->request != NULL && MSG_IS_REFER(event->request)) {
+				//handle_call_transfer(event);
+			}
+			break;
+		case EXOSIP_CALL_ACK:
+			/* If audio is not flowing and this has SDP - fire it up! */
+			break;
+		case EXOSIP_CALL_ANSWERED:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was answered.\n");
+			handle_answer(event);
+			break;
+		case EXOSIP_CALL_PROCEEDING:
+			/* This is like a 100 Trying... yeah */
+			break;
+		case EXOSIP_CALL_RINGING:
+			//handle_ringing(event);
+			break;
+		case EXOSIP_CALL_REDIRECTED:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Call was redirect\n");
+			break;
+		case EXOSIP_CALL_CLOSED:
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_RELEASED:
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_NOANSWER:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "The call was not answered.\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_REQUESTFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Request failure\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_SERVERFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Server failure\n");
+			destroy_call_by_event(event);
+			break;
+		case EXOSIP_CALL_GLOBALFAILURE:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Global failure\n");
+			destroy_call_by_event(event);
+			break;
+			/* Registration related stuff */
+		case EXOSIP_REGISTRATION_NEW:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Received registration attempt\n");
+			break;
+		default:
+			/* Unknown event... casually absorb it for now */
+			break;
+		}
+
+		//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "There was an event (%d) [%s]\n", event->type, event->textinfo);
+		/* Free the event */
+		eXosip_event_free(event);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Monitor Thread Exiting\n");
+	globals.running = 0;
+	return NULL;
+}
+
+
+static int config_exosip(int reload) 
+{
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "exosip.conf";
+
+	globals.bytes_per_frame = DEFAULT_BYTES_PER_FRAME;
+	switch_core_hash_init(&globals.call_hash, module_pool);
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+
+	globals.rtp_start = 16384;
+	globals.rtp_end = 32768;
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+			} else if (!strcmp(var, "rtp_min_port")) {
+				globals.rtp_start = atoi(val);
+			} else if (!strcmp(var, "rtp_max_port")) {
+				globals.rtp_end = atoi(val);
+			} else if (!strcmp(var, "codec_ms")) {
+				globals.codec_ms = atoi(val);
+			}
+		}
+	}
+	
+	if (!globals.codec_ms) {
+		globals.codec_ms = 20;
+	}
+
+	if (!globals.port) {
+		globals.port = 5060;
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+
+	if (eXosip_init ()) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_init initialization failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+	if (eXosip_listen_addr (IPPROTO_UDP, NULL, globals.port, AF_INET, 0)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "eXosip_listen_addr failed!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch_mutex_init(&globals.port_lock, SWITCH_MUTEX_NESTED, module_pool);
+
+
+	/* Setup the user agent */
+	eXosip_set_user_agent("OPENSWITCH 2.0");
+
+
+	monitor_thread_run();
+	return 0;
+
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+	config_exosip(0);
+	return SWITCH_STATUS_TERM;
+}
+
diff --git a/src/mod/endpoints/mod_iaxchan/Makefile b/src/mod/endpoints/mod_iaxchan/Makefile
new file mode 100644
index 0000000000..6e4f38205a
--- /dev/null
+++ b/src/mod/endpoints/mod_iaxchan/Makefile
@@ -0,0 +1,15 @@
+LDFLAGS += -liax -L/usr/local/lib
+
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install iax --enable-newjb --prefix=$(PREFIX)
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(CC) $(SOLINK) -o $(MOD).so  $(MOD).o $(LDFLAGS)
+
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/endpoints/mod_iaxchan/mod_IaxChan.vcproj b/src/mod/endpoints/mod_iaxchan/mod_IaxChan.vcproj
new file mode 100644
index 0000000000..3b0a8f4d62
--- /dev/null
+++ b/src/mod/endpoints/mod_iaxchan/mod_IaxChan.vcproj
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_IaxChan"
+	ProjectGUID="{3A5B9131-F20C-4A85-9447-6C1610941CEE}"
+	RootNamespace="mod_IaxChan"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_IaxChan Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iax\src&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libiax2.lib Winmm.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_IaxChan.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\iax\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_IaxChan.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_IaxChan.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_IaxChan Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iax\src&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libiax2.lib Winmm.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_IaxChan.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\iax\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				ImportLibrary="$(OutDir)/mod_IaxChan.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_iaxchan.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/endpoints/mod_iaxchan/mod_iaxchan.c b/src/mod/endpoints/mod_iaxchan/mod_iaxchan.c
new file mode 100644
index 0000000000..b3faf65c5e
--- /dev/null
+++ b/src/mod/endpoints/mod_iaxchan/mod_iaxchan.c
@@ -0,0 +1,986 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_iaxchan.c -- IAX2 Endpoint Module
+ *
+ */
+#include <switch.h>
+
+#ifdef WIN32
+#include <iax2.h>
+#include <iax-client.h>
+#include <iax2-parser.h>
+#include <sys/timeb.h>
+#else
+#include <iax/iax2.h>
+#include <iax/iax-client.h>
+#include <iax/iax2-parser.h>
+#endif
+
+static const char modname[] = "mod_iaxchan";
+
+static switch_memory_pool *module_pool;
+static int running = 1;
+
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_VOICE = (1 << 4),
+	TFLAG_HANGUP = (1 << 5),
+	TFLAG_LINEAR = (1 << 6)
+} TFLAGS;
+
+typedef enum {
+	GFLAG_MY_CODEC_PREFS = (1 << 0)
+} GFLAGS;
+
+static struct {
+	int debug;
+	int port;
+	char *dialplan;
+	char *codec_string;
+	char *codec_order[SWITCH_MAX_CODECS];
+	int codec_order_last;
+	unsigned int flags;
+} globals;
+
+struct private_object {
+	unsigned int flags;
+	switch_codec read_codec;
+	switch_codec write_codec;
+	struct switch_frame read_frame;
+	unsigned char databuf[1024];
+	switch_core_session *session;
+	struct iax_session *iax_session;
+	switch_caller_profile *caller_profile;	
+	unsigned int codec;
+	unsigned int codecs;
+	switch_mutex_t *mutex;
+	switch_thread_cond_t *cond;
+};
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, globals.dialplan)
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, globals.codec_string)
+
+
+static char *IAXNAMES[] = {"IAX_EVENT_CONNECT","IAX_EVENT_ACCEPT","IAX_EVENT_HANGUP","IAX_EVENT_REJECT","IAX_EVENT_VOICE",
+						   "IAX_EVENT_DTMF","IAX_EVENT_TIMEOUT","IAX_EVENT_LAGRQ","IAX_EVENT_LAGRP","IAX_EVENT_RINGA",
+						   "IAX_EVENT_PING","IAX_EVENT_PONG","IAX_EVENT_BUSY","IAX_EVENT_ANSWER","IAX_EVENT_IMAGE",
+						   "IAX_EVENT_AUTHRQ","IAX_EVENT_AUTHRP","IAX_EVENT_REGREQ","IAX_EVENT_REGACK",
+						   "IAX_EVENT_URL","IAX_EVENT_LDCOMPLETE","IAX_EVENT_TRANSFER","IAX_EVENT_DPREQ",
+						   "IAX_EVENT_DPREP","IAX_EVENT_DIAL","IAX_EVENT_QUELCH","IAX_EVENT_UNQUELCH",
+						   "IAX_EVENT_UNLINK","IAX_EVENT_LINKREJECT","IAX_EVENT_TEXT","IAX_EVENT_REGREJ",
+						   "IAX_EVENT_LINKURL","IAX_EVENT_CNG","IAX_EVENT_REREQUEST","IAX_EVENT_TXREPLY",
+						   "IAX_EVENT_TXREJECT","IAX_EVENT_TXACCEPT","IAX_EVENT_TXREADY"};
+
+
+struct ast_iana {
+	const unsigned int ast;
+	const int iana;
+	char *name;
+};
+
+//999 means it's wrong nad i dont know the real one 
+static struct ast_iana AST_IANA[] =
+	{{AST_FORMAT_G723_1, 4, "g723.1"},
+	 {AST_FORMAT_GSM, 3, "gsm"},
+	 {AST_FORMAT_ULAW, 0, "ulaw"},
+	 {AST_FORMAT_ALAW, 8, "alaw"},
+	 {AST_FORMAT_G726, 999, "g726"},
+	 {AST_FORMAT_ADPCM, 999, "adpcm"},
+	 {AST_FORMAT_SLINEAR, 10, "slinear"},
+	 {AST_FORMAT_LPC10, 7, "lpc10"},
+	 {AST_FORMAT_G729A, 18, "g729"},
+	 {AST_FORMAT_SPEEX, 98, "speex"},
+	 {AST_FORMAT_ILBC, 999, "ilbc"},
+	 {AST_FORMAT_MAX_AUDIO, 999, ""},
+	 {AST_FORMAT_JPEG, 999, ""},
+	 {AST_FORMAT_PNG, 999, ""},
+	 {AST_FORMAT_H261, 999, ""},
+	 {AST_FORMAT_H263, 999, ""},
+	 {AST_FORMAT_MAX_VIDEO, 999, ""},
+	 {0,0}
+	};
+
+static char *ast2str(unsigned int ast)
+{
+	int x;
+	for(x = 0; x < 32; x++) {
+		if ((1 << x) == ast) {
+			return AST_IANA[x].name;
+		}
+	}
+	return "";
+}
+
+static unsigned int iana2ast(int iana)
+{
+	int x = 0;
+	unsigned int ast = 0;
+
+	for(x = 0; AST_IANA[x].ast; x++) {
+		if (AST_IANA[x].iana == iana) {
+			ast = AST_IANA[x].ast;
+			break;
+		}
+	}
+
+	return ast;
+}
+
+typedef enum {
+	IAX_SET = 1,
+	IAX_QUERY = 2
+} iax_io_t;
+
+static switch_status iax_set_codec(struct private_object *tech_pvt, struct iax_session *iax_session, unsigned int *format, unsigned int *cababilities, iax_io_t io)
+{
+	char *dname = NULL;
+	//int rate = 8000;
+	//int codec_ms = 20;
+	switch_channel *channel;
+	switch_codec_interface *codecs[SWITCH_MAX_CODECS];
+	int num_codecs = 0;
+	unsigned int local_cap = 0, mixed_cap = 0, chosen = 0, leading = 0;
+	int x;
+
+	if (globals.codec_string) {
+		if (!(num_codecs = loadable_module_get_codecs_sorted(switch_core_session_get_pool(tech_pvt->session),
+			codecs,
+			SWITCH_MAX_CODECS,
+			globals.codec_order,
+			globals.codec_order_last)) > 0) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "NO codecs?\n");
+				return SWITCH_STATUS_GENERR;
+		}
+	} else if (!(num_codecs = loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt->session), codecs, SWITCH_MAX_CODECS)) > 0) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "NO codecs?\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	for (x = 0; x < num_codecs; x++) {
+		unsigned int codec = iana2ast(codecs[x]->ianacode);
+		if (io == IAX_QUERY) {
+			iax_pref_codec_add(iax_session, codec);
+		}
+		local_cap |= codec;
+	}
+
+	if (io == IAX_SET) {
+		mixed_cap = (local_cap & *cababilities);
+	} else {
+		mixed_cap = local_cap;
+	}
+
+	leading = iana2ast(codecs[0]->ianacode);
+	if (io == IAX_QUERY) {
+		chosen = leading;
+		*format = chosen;
+		*cababilities = local_cap;
+		return SWITCH_STATUS_SUCCESS;
+	} else if (switch_test_flag(&globals, GFLAG_MY_CODEC_PREFS) && (leading & mixed_cap)) {
+		chosen = leading;
+		dname = codecs[0]->iananame;
+	} else {
+		unsigned int prefs[32];
+		int len = 0;
+
+		if (!switch_test_flag(&globals, GFLAG_MY_CODEC_PREFS)) {
+			len = iax_pref_codec_get(iax_session, prefs, sizeof(prefs));
+		}
+
+		if (len) { /*they sent us a pref and we don't want to be codec master*/
+			char pref_str[256] = "(";
+
+			for (x = 0; x < len; x++) {
+				strncat(pref_str, ast2str(prefs[x]), sizeof(pref_str));
+				strncat(pref_str, x == len - 1 ? ")" : ",", sizeof(pref_str));
+			}
+
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Codec Prefs Detected: %s\n", pref_str);
+
+			for (x = 0; x < len; x++) {
+				if ((prefs[x] & mixed_cap)) {
+					int z;
+					chosen = prefs[x];
+					for (z = 0; z < num_codecs; z++) {
+						if (prefs[x] == iana2ast(codecs[z]->ianacode)) {
+							dname = codecs[z]->iananame;
+						}
+					}
+					break;
+				}
+			}
+		} else {
+			if (*format & mixed_cap) { /* is the one we asked for here? */
+				chosen = *format;
+				for (x = 0; x < num_codecs; x++) {
+					unsigned int cap = iana2ast(codecs[x]->ianacode);
+					if (cap == chosen) {
+						dname = codecs[x]->iananame;
+					}
+				}
+			} else { /* c'mon there has to be SOMETHING...*/
+				for (x = 0; x < num_codecs; x++) {
+					unsigned int cap = iana2ast(codecs[x]->ianacode);
+					if (cap & mixed_cap) {
+						chosen = cap;
+						dname = codecs[x]->iananame;
+					}
+				}
+			}
+		}
+	}
+
+	if (!dname && !chosen) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "NO codecs?\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (!strcasecmp(dname, "l16")) {
+		switch_set_flag(tech_pvt, TFLAG_LINEAR);
+	}
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+		dname,
+		0,
+		0,
+		1,
+		SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+		NULL,
+		switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+			return SWITCH_STATUS_GENERR;
+	} else {
+		if (switch_core_codec_init(&tech_pvt->write_codec,
+			dname,
+			0,
+			0,
+			1,
+			SWITCH_CODEC_FLAG_ENCODE |SWITCH_CODEC_FLAG_DECODE, 
+			NULL,
+			switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+				switch_core_codec_destroy(&tech_pvt->read_codec);	
+				return SWITCH_STATUS_GENERR;
+		} else {
+			int ms;
+			int rate;
+			ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
+			rate = tech_pvt->write_codec.implementation->samples_per_second;
+			tech_pvt->read_frame.rate = rate;
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Activate Codec %s/%d %d ms\n", dname, rate, ms);
+			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);
+		}
+		tech_pvt->codec = chosen;
+		tech_pvt->codecs = local_cap;
+	}
+
+	if (io == IAX_QUERY) {
+		*format = tech_pvt->codec;
+		*cababilities = local_cap;
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static const switch_endpoint_interface channel_endpoint_interface;
+
+static switch_status channel_on_init(switch_core_session *session);
+static switch_status channel_on_hangup(switch_core_session *session);
+static switch_status channel_on_ring(switch_core_session *session);
+static switch_status channel_on_loopback(switch_core_session *session);
+static switch_status channel_on_transmit(switch_core_session *session);
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static switch_status channel_kill_channel(switch_core_session *session, int sig);
+
+
+static void iax_err_cb(const char *s)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "IAX  ERR: %s", s);
+}
+
+static void iax_out_cb(const char *s)
+{
+	if (globals.debug) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "IAX INFO: %s", s);
+	}
+}
+
+
+/* 
+State methods they get called when the state changes to the specific state 
+returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status channel_on_init(switch_core_session *session)
+{
+	switch_channel *channel;
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+	iax_set_private(tech_pvt->iax_session, tech_pvt);
+
+	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);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL RING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_execute(switch_core_session *session)
+{
+
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_hangup(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(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);
+
+	if (tech_pvt->iax_session) {
+		if (!switch_test_flag(tech_pvt, TFLAG_HANGUP)) {
+			iax_hangup(tech_pvt->iax_session, "Hangup");
+			switch_set_flag(tech_pvt, TFLAG_HANGUP);
+		}
+		iax_session_destroy(&tech_pvt->iax_session);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_kill_channel(switch_core_session *session, int sig)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_clear_flag(tech_pvt, TFLAG_VOICE);
+	switch_channel_hangup(channel);
+	switch_thread_cond_signal(tech_pvt->cond);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL KILL\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session) 
+{
+	if ((*new_session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel;
+		switch_caller_profile *caller_profile;
+		unsigned int req = 0, cap = 0;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "IAX/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (!(tech_pvt->iax_session = iax_session_new())) {
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+
+		if (iax_set_codec(tech_pvt, tech_pvt->iax_session, &req, &cap, IAX_QUERY) != SWITCH_STATUS_SUCCESS) {
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+
+
+		iax_call(tech_pvt->iax_session,
+			caller_profile->caller_id_number,
+			caller_profile->caller_id_name,
+			caller_profile->destination_number,
+			NULL, 0, req, cap);
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status channel_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status channel_send_dtmf(switch_core_session *session, char *dtmf)
+{
+	struct private_object *tech_pvt = NULL;
+	char *digit;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	if (tech_pvt->iax_session) {
+		for(digit = dtmf; *digit; digit++) {
+			iax_send_dtmf(tech_pvt->iax_session, *digit);
+		}
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	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;			
+			}
+
+			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;
+}
+
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	//switch_frame *pframe;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if(!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+#ifndef BIGENDIAN
+	if (switch_test_flag(tech_pvt, TFLAG_LINEAR)) {
+		switch_swap_linear(frame->data, (int)frame->datalen / 2);
+	}
+#endif
+	iax_send_voice(tech_pvt->iax_session, tech_pvt->codec, frame->data, (int)frame->datalen, tech_pvt->write_codec.implementation->samples_per_frame);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status channel_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	iax_answer(tech_pvt->iax_session);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_event_handler_table channel_event_handlers = {
+	/*.on_init*/			channel_on_init,
+	/*.on_ring*/			channel_on_ring,
+	/*.on_execute*/			channel_on_execute,
+	/*.on_hangup*/			channel_on_hangup,
+	/*.on_loopback*/		channel_on_loopback,
+	/*.on_transmit*/		channel_on_transmit
+};
+
+static const switch_io_routines channel_io_routines = {
+	/*.outgoing_channel*/	channel_outgoing_channel,
+	/*.answer_channel*/		channel_answer_channel,
+	/*.read_frame*/			channel_read_frame,
+	/*.write_frame*/		channel_write_frame,
+	/*.kill_channel*/		channel_kill_channel,
+	/*.waitfor_read*/		channel_waitfor_read,
+	/*.waitfor_write*/		channel_waitfor_write,
+	/*.send_dtmf*/			channel_send_dtmf
+};
+
+static const switch_endpoint_interface channel_endpoint_interface = {
+	/*.interface_name*/		"iax",
+	/*.io_routines*/		&channel_io_routines,
+	/*.event_handlers*/		&channel_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface channel_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&channel_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &channel_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+#define PHONE_FREED		0
+#define PHONE_CALLACCEPTED	1
+#define PHONE_RINGING		2
+#define PHONE_ANSWERED		3
+#define PHONE_CONNECTED		4
+
+#define UNREGISTERED		0
+#define REGISTERED		1
+
+
+static switch_status load_config(void)
+{
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "iax.conf";
+
+	memset(&globals, 0, sizeof(globals));
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+			} else if (!strcmp(var, "codec_master")) {
+				if (!strcasecmp(val, "us")) {
+					switch_set_flag(&globals, GFLAG_MY_CODEC_PREFS);
+				}
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+			} else if (!strcmp(var, "codec_prefs")) {
+				set_global_codec_string(val);
+				globals.codec_order_last = switch_separate_string(globals.codec_string, ',', globals.codec_order, SWITCH_MAX_CODECS);
+			}
+		}
+	}
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+	if (!globals.port) {
+		globals.port = 4569;
+	}
+
+	switch_config_close_file(&cfg);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+	int res;
+	int netfd;
+	int refresh;
+	struct iax_event *iaxevent = NULL;
+
+	load_config();
+
+	if (globals.debug) {
+		iax_enable_debug();
+	}
+	if ((res = iax_init(globals.port) < 0)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error Binding Port!\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	iax_set_error(iax_err_cb);
+	iax_set_output(iax_out_cb);
+	netfd = iax_get_fd();	
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "IAX Ready Port %d\n", globals.port);
+
+	for(;;) {
+
+		if (running == -1) {
+			break;
+		}
+
+		/* Wait for an event.*/
+		if ((iaxevent = iax_get_event(0)) == NULL) {
+			switch_yield(1000);
+			continue;
+		} else if (iaxevent) {
+			struct private_object *tech_pvt = iax_get_private(iaxevent->session);
+
+			if (globals.debug && iaxevent->etype != IAX_EVENT_VOICE) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Event %d [%s]!\n",
+					iaxevent->etype, IAXNAMES[iaxevent->etype]);
+			}
+			switch (iaxevent->etype) {
+				case IAX_EVENT_REGACK:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Registration completed successfully.\n");
+					if (iaxevent->ies.refresh) refresh = iaxevent->ies.refresh;
+					break;
+				case IAX_EVENT_REGREJ:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Registration failed.\n");
+					break;
+				case IAX_EVENT_TIMEOUT:
+					break;
+				case IAX_EVENT_ACCEPT:
+					if (tech_pvt) {					
+						unsigned int cap =  iax_session_get_capability(iaxevent->session);
+						unsigned int format = iaxevent->ies.format;
+
+						if (iax_set_codec(tech_pvt, iaxevent->session, &format, &cap, IAX_SET) != SWITCH_STATUS_SUCCESS) {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WTF? %d %d\n",iaxevent->ies.format, iaxevent->ies.capability);
+						}
+					}
+
+
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Call accepted.\n");
+					break;
+				case IAX_EVENT_RINGA:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Ringing heard.\n");
+					break;
+				case IAX_EVENT_PONG:
+					// informative only
+					break;
+				case IAX_EVENT_ANSWER:
+					// the other side answered our call
+					if (tech_pvt) {
+						switch_channel *channel;
+						if ((channel = switch_core_session_get_channel(tech_pvt->session))) {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Answer %s\n", switch_channel_get_name(channel));
+							switch_channel_answer(channel);
+						}
+					}
+
+					break;
+				case IAX_EVENT_CONNECT:
+					// incoming call detected
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, 
+						"Incoming call connected %s, %s, %s %d/%d\n",
+						iaxevent->ies.called_number,
+						iaxevent->ies.calling_number,
+						iaxevent->ies.calling_name,
+						iaxevent->ies.format,
+						iaxevent->ies.capability);
+
+					if (iaxevent) {
+						switch_core_session *session;
+
+						switch_console_printf(SWITCH_CHANNEL_CONSOLE, "New Inbound Channel %s!\n", iaxevent->ies.calling_name);
+						if ((session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
+							struct private_object *tech_pvt;
+							switch_channel *channel;
+
+							if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+								memset(tech_pvt, 0, sizeof(*tech_pvt));
+								channel = switch_core_session_get_channel(session);
+								switch_core_session_set_private(session, tech_pvt);
+								tech_pvt->session = session;
+							} else {
+								switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+								switch_core_session_destroy(&session);
+								break;
+							}
+
+
+							if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+								globals.dialplan,
+								iaxevent->ies.calling_name,
+								iaxevent->ies.calling_number,
+								iax_get_peer_ip(iaxevent->session),
+								iaxevent->ies.calling_ani,
+								NULL,
+								iaxevent->ies.called_number))) {
+									char name[128];
+									switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+									snprintf(name, sizeof(name), "IAX/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
+									switch_channel_set_name(channel, name);
+							}
+
+							if (iax_set_codec(tech_pvt, iaxevent->session,
+								&iaxevent->ies.format,
+								&iaxevent->ies.capability,
+								IAX_SET) != SWITCH_STATUS_SUCCESS) {
+									iax_reject(iaxevent->session, "Codec Error!");
+									switch_core_session_destroy(&session);
+							} else {
+								tech_pvt->iax_session = iaxevent->session;						
+								tech_pvt->session = session;
+								iax_accept(tech_pvt->iax_session, tech_pvt->codec);
+								iax_ring_announce(tech_pvt->iax_session);
+								switch_channel_set_state(channel, CS_INIT);
+								switch_core_session_thread_launch(session);
+							}
+						}
+					}
+					break;
+				case IAX_EVENT_REJECT:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Rejected call.\n");
+				case IAX_EVENT_BUSY:
+				case IAX_EVENT_HANGUP:
+					if (tech_pvt) {
+						switch_channel *channel;
+
+						switch_clear_flag(tech_pvt, TFLAG_IO);
+						switch_clear_flag(tech_pvt, TFLAG_VOICE);
+						if ((channel = switch_core_session_get_channel(tech_pvt->session))) {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hangup %s\n", switch_channel_get_name(channel));
+							switch_set_flag(tech_pvt, TFLAG_HANGUP);
+							switch_channel_hangup(channel);
+							switch_thread_cond_signal(tech_pvt->cond);
+							iaxevent->session = NULL;
+						} else {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, "No Session? %s\n", switch_test_flag(tech_pvt, TFLAG_VOICE) ? "yes" : "no");
+						}
+					}
+					break;
+				case IAX_EVENT_CNG:
+					// pseudo-silence
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "sending silence\n");
+					break;
+				case IAX_EVENT_VOICE:
+					if (tech_pvt && (tech_pvt->read_frame.datalen = iaxevent->datalen)) {
+						int bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+						int frames = (int)(tech_pvt->read_frame.datalen / bytes);
+						tech_pvt->read_frame.samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+						memcpy(tech_pvt->read_frame.data, iaxevent->data, iaxevent->datalen);
+						/* wake up the i/o thread*/
+						switch_set_flag(tech_pvt, TFLAG_VOICE);
+						switch_thread_cond_signal(tech_pvt->cond);
+					}				
+					break;
+				case IAX_EVENT_TRANSFER:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Call transfer occurred.\n");
+					//session[0] = iaxevent->session;
+					break;
+				case IAX_EVENT_DTMF:
+					if (tech_pvt) {
+						switch_channel *channel;
+						if ((channel = switch_core_session_get_channel(tech_pvt->session))) {
+							char str[2] = {iaxevent->subclass};
+							if (globals.debug) {
+								switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s DTMF %s\n", str, switch_channel_get_name(channel));
+							}
+							switch_channel_queue_dtmf(channel, str);
+						}
+					}
+
+					break;
+				default:
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Don't know what to do with IAX event %d.\n", iaxevent->etype);
+					break;
+			}
+
+			iax_event_free(iaxevent);
+		}
+
+	}
+
+	running = 0;
+
+	return SWITCH_STATUS_TERM;
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	int x = 0;
+
+	running = -1;
+
+	iax_shutdown();
+
+	while (running) {
+		if (x++ > 100) {
+			break;
+		}
+		switch_yield(20000);
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
diff --git a/src/mod/endpoints/mod_opalchan/Makefile b/src/mod/endpoints/mod_opalchan/Makefile
new file mode 100644
index 0000000000..709a5b7bc5
--- /dev/null
+++ b/src/mod/endpoints/mod_opalchan/Makefile
@@ -0,0 +1,12 @@
+#CFLAGS += -I/usr/src/common/src
+LDFLAGS += -liax
+
+all:	$(MOD).so
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(CC) $(SOLINK) -o $(MOD).so  $(MOD).o $(LDFLAGS)
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/endpoints/mod_opalchan/mod_opalchan.c b/src/mod/endpoints/mod_opalchan/mod_opalchan.c
new file mode 100644
index 0000000000..8aae7ecb7d
--- /dev/null
+++ b/src/mod/endpoints/mod_opalchan/mod_opalchan.c
@@ -0,0 +1,385 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_opalchan.c -- OPAL2 Endpoint Module
+ *
+ */
+#include <switch.h>
+
+
+static const char modname[] = "mod_woomera";
+
+static switch_memory_pool *module_pool;
+
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+} TFLAGS;
+
+static struct {
+	int debug;
+	int port;
+} globals;
+
+struct private_object {
+	unsigned int flags;
+	struct switch_frame frame;
+	unsigned char databuf[1024];
+	switch_core_session *session;
+	switch_caller_profile *caller_profile;	
+};
+
+
+static const switch_endpoint_interface channel_endpoint_interface;
+
+static switch_status channel_on_init(switch_core_session *session);
+static switch_status channel_on_hangup(switch_core_session *session);
+static switch_status channel_on_ring(switch_core_session *session);
+static switch_status channel_on_loopback(switch_core_session *session);
+static switch_status channel_on_transmit(switch_core_session *session);
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static switch_status channel_kill_channel(switch_core_session *session, int sig);
+
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status channel_on_init(switch_core_session *session)
+{
+	switch_channel *channel;
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt->frame.data = tech_pvt->databuf;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL RING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_execute(switch_core_session *session)
+{
+
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_hangup(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_kill_channel(switch_core_session *session, int sig)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_channel_hangup(channel);
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL KILL\n", switch_channel_get_name(channel));
+
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+   that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session) 
+{
+	if ((*new_session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel, *orig_channel;
+		switch_caller_profile *caller_profile, *originator_caller_profile = NULL;
+		
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "Opal/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		/* (session == NULL) means it was originated from the core not from another channel */
+		if (session && (orig_channel = switch_core_session_get_channel(session))) {
+			switch_caller_profile *cloned_profile;
+
+			if ((originator_caller_profile = switch_channel_get_caller_profile(orig_channel))) {
+				cloned_profile = switch_caller_profile_clone(*new_session, originator_caller_profile);
+				switch_channel_set_originator_caller_profile(channel, cloned_profile);
+			}
+		}
+		
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status channel_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	//switch_frame *pframe;
+	//switch_status status;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	//switch_frame *pframe;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+	
+}
+
+static const switch_event_handler_table channel_event_handlers = {
+	/*.on_init*/			channel_on_init,
+	/*.on_ring*/			channel_on_ring,
+	/*.on_execute*/			channel_on_execute,
+	/*.on_hangup*/			channel_on_hangup,
+	/*.on_loopback*/		channel_on_loopback,
+	/*.on_transmit*/		channel_on_transmit
+};
+
+static const switch_io_routines channel_io_routines = {
+	/*.outgoing_channel*/	channel_outgoing_channel,
+	/*.answer_channel*/		NULL,
+	/*.read_frame*/			channel_read_frame,
+	/*.write_frame*/		channel_write_frame,
+	/*.kill_channel*/		channel_kill_channel,
+	/*.waitfor_read*/		channel_waitfor_read,
+	/*.waitfor_write*/		channel_waitfor_write
+};
+
+static const switch_endpoint_interface channel_endpoint_interface = {
+	/*.interface_name*/		"opal",
+	/*.io_routines*/		&channel_io_routines,
+	/*.event_handlers*/		&channel_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface channel_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&channel_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+/*
+
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	int x = 0;
+	opal_profile_thread_running(&default_profile, 1, 0);
+	while (!opal_profile_thread_running(&default_profile, 0, 0)) {
+		opal_socket_close(&default_profile.opal_socket);
+		if (x++ > 10) {
+			break;
+		}
+		switch_yield(1);
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+*/
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "opal.conf";
+	
+	memset(&globals, 0, sizeof(globals));
+	
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "port")) {
+				globals.port = atoi(val);
+			}
+		}
+	}
+
+	switch_config_close_file(&cfg);
+
+	
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &channel_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+
+	return SWITCH_STATUS_TERM;
+}
diff --git a/src/mod/endpoints/mod_portaudio/Makefile b/src/mod/endpoints/mod_portaudio/Makefile
new file mode 100644
index 0000000000..0d78e0b06a
--- /dev/null
+++ b/src/mod/endpoints/mod_portaudio/Makefile
@@ -0,0 +1,19 @@
+LDFLAGS += -lportaudio -L/usr/local/lib
+MYOBJS = pablio.o ringbuffer.o
+
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install portaudio.tar.gz --prefix=$(PREFIX)
+%.o:  %.c
+	$(CC) -fPIC $(CFLAGS) -c -o $@ $<
+
+$(MOD).so: $(MOD).c $(MYOBJS)
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(CC) $(SOLINK) -o $(MOD).so $(MOD).o $(MYOBJS) $(LDFLAGS)
+
+
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/endpoints/mod_portaudio/mod_PortAudio.vcproj b/src/mod/endpoints/mod_portaudio/mod_PortAudio.vcproj
new file mode 100644
index 0000000000..5afdc338d3
--- /dev/null
+++ b/src/mod/endpoints/mod_portaudio/mod_PortAudio.vcproj
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_PortAudio"
+	ProjectGUID="{5FD31A25-5D83-4794-8BEE-904DAD84CE71}"
+	RootNamespace="mod_PortAudio"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_PortAudio Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\portaudio\pa_common&quot;;&quot;$(InputDir)..\..\..\libs\portaudio\pa_win_wmme&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalOptions="/NODEFAULTLIB:LIMBCTD"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib  PAStaticWMMED.lib Winmm.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_PortAudio.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\portaudio\winvc\Lib&quot;"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_PortAudio.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_PortAudio.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_PortAudio Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\portaudio\pa_common&quot;;&quot;$(InputDir)..\..\..\libs\portaudio\pa_win_wmme&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="Ws2_32.lib Iphlpapi.lib  PAStaticWMME.lib Winmm.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_PortAudio.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\portaudio\winvc\Lib&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_PortAudio.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_PortAudio.c"
+				>
+			</File>
+			<File
+				RelativePath=".\pablio.c"
+				>
+			</File>
+			<File
+				RelativePath=".\ringbuffer.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\pablio.h"
+				>
+			</File>
+			<File
+				RelativePath=".\ringbuffer.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c
new file mode 100644
index 0000000000..51e7ec29bd
--- /dev/null
+++ b/src/mod/endpoints/mod_portaudio/mod_portaudio.c
@@ -0,0 +1,934 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_portaudio.c -- PortAudio Endpoint Module
+ *
+ */
+#include <switch.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pablio.h"
+#include <string.h>
+
+#define MY_EVENT_RINGING "portaudio::ringing"
+
+static const char modname[] = "mod_portaudio";
+
+static switch_memory_pool *module_pool;
+//static int running = 1;
+
+#define SAMPLE_TYPE  paInt16
+//#define SAMPLE_TYPE  paFloat32
+typedef short SAMPLE;
+
+typedef enum {
+	TFLAG_IO = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_DTMF = (1 << 3),
+	TFLAG_VOICE = (1 << 4),
+	TFLAG_HANGUP = (1 << 5),
+	TFLAG_LINEAR = (1 << 6),
+	TFLAG_ANSWER = (1 << 7)
+} TFLAGS;
+
+typedef enum {
+	GFLAG_MY_CODEC_PREFS = (1 << 0)
+} GFLAGS;
+
+static struct {
+	int debug;
+	int port;
+	char *cid_name;
+	char *cid_num;
+	char *dialplan;
+	unsigned int flags;
+	int indev;
+	int outdev;
+	int call_id;
+	switch_hash *call_hash;
+	switch_mutex_t *device_lock;
+	int sample_rate;
+} globals;
+
+struct private_object {
+	unsigned int flags;
+	switch_codec read_codec;
+    switch_codec write_codec;
+	struct switch_frame read_frame;
+	unsigned char databuf[1024];
+	switch_core_session *session;
+	switch_caller_profile *caller_profile;	
+	char call_id[50];
+	PaError err;
+    PABLIO_Stream *audio_in;
+    PABLIO_Stream *audio_out;
+	int indev;
+	int outdev;
+};
+
+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 const switch_endpoint_interface channel_endpoint_interface;
+
+static switch_status channel_on_init(switch_core_session *session);
+static switch_status channel_on_hangup(switch_core_session *session);
+static switch_status channel_on_ring(switch_core_session *session);
+static switch_status channel_on_loopback(switch_core_session *session);
+static switch_status channel_on_transmit(switch_core_session *session);
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static switch_status channel_kill_channel(switch_core_session *session, int sig);
+static switch_status engage_device(struct private_object *tech_pvt);
+static int dump_info(void);
+static switch_status load_config(void);
+static int get_dev_by_name(char *name, int in);
+static switch_status place_call(char *dest, char *out, size_t outlen);
+static switch_status hup_call(char *callid, char *out, size_t outlen);
+static switch_status call_info(char *callid, char *out, size_t outlen);
+static switch_status send_dtmf(char *callid, char *out, size_t outlen);
+static switch_status answer_call(char *callid, char *out, size_t outlen);
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status channel_on_init(switch_core_session *session)
+{
+	switch_channel *channel;
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt->read_frame.data = tech_pvt->databuf;
+	tech_pvt->read_frame.buflen = sizeof(tech_pvt->databuf);
+
+	switch_set_flag(tech_pvt, TFLAG_IO);
+	
+	/* Move Channel's State Machine to RING */
+	switch_channel_set_state(channel, CS_RING);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL RING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_execute(switch_core_session *session)
+{
+
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static void deactivate_audio_device(struct private_object *tech_pvt)
+{
+	switch_mutex_lock(globals.device_lock);
+	if (tech_pvt->audio_in) {
+		CloseAudioStream(tech_pvt->audio_in);
+		tech_pvt->audio_in = NULL;
+	}
+	if (tech_pvt->audio_out) {
+		CloseAudioStream(tech_pvt->audio_out);
+		tech_pvt->audio_out = NULL;
+	}
+	switch_mutex_unlock(globals.device_lock);
+}
+
+static switch_status channel_on_hangup(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	switch_core_hash_delete(globals.call_hash, tech_pvt->call_id);
+
+	switch_core_codec_destroy(&tech_pvt->read_codec);
+	switch_core_codec_destroy(&tech_pvt->write_codec);
+
+	deactivate_audio_device(tech_pvt);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL HANGUP\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_kill_channel(switch_core_session *session, int sig)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_clear_flag(tech_pvt, TFLAG_IO);
+	deactivate_audio_device(tech_pvt);
+	switch_channel_hangup(channel);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s CHANNEL KILL\n", switch_channel_get_name(channel));
+
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_on_transmit(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	switch_time_t last;
+	int waitsec = 5 * 1000000;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	last = switch_time_now() - waitsec;
+
+	/* Turn on the device */
+	engage_device(tech_pvt);
+
+	while(switch_channel_get_state(channel) == CS_TRANSMIT && !switch_test_flag(tech_pvt, TFLAG_ANSWER)) {
+		if (switch_time_now() - last >= waitsec) {
+		char buf[512];
+		switch_event *event;
+
+		snprintf(buf, sizeof(buf), "BRRRRING! BRRRRING! call %s\n", tech_pvt->call_id);
+
+		if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_RINGING) == SWITCH_STATUS_SUCCESS) {
+			switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_info", buf);
+			switch_event_fire(&event);
+		}
+
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s\n", buf);
+		last = switch_time_now();
+		}
+		switch_yield(50000);
+	}
+
+	
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CHANNEL TRANSMIT\n");
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+   that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_status channel_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session) 
+{
+	if ((*new_session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel;
+		switch_caller_profile *caller_profile;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "PortAudio/%s-%04x", caller_profile->destination_number ? caller_profile->destination_number : modname, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status channel_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+static switch_status channel_send_dtmf(switch_core_session *session, char *dtmf)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DTMF ON CALL %s [%s]\n", tech_pvt->call_id, dtmf);
+
+    return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status channel_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	int samples;
+	switch_status status = SWITCH_STATUS_FALSE;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	
+	switch_mutex_lock(globals.device_lock);
+	if	(tech_pvt->audio_in && 
+		 (samples = ReadAudioStream(tech_pvt->audio_in, tech_pvt->read_frame.data, tech_pvt->read_codec.implementation->samples_per_frame))) {
+		tech_pvt->read_frame.datalen = samples * 2;
+		tech_pvt->read_frame.samples = samples;
+		*frame = &tech_pvt->read_frame;
+		status = SWITCH_STATUS_SUCCESS;
+	}
+	switch_mutex_unlock(globals.device_lock);
+
+	return status;
+}
+
+static switch_status channel_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	switch_status status = SWITCH_STATUS_FALSE;
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if(!switch_test_flag(tech_pvt, TFLAG_IO)) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	//switch_mutex_lock(globals.device_lock);
+	if (tech_pvt->audio_out) {
+		WriteAudioStream(tech_pvt->audio_out, (short *)frame->data, (int)(frame->datalen / sizeof(SAMPLE)));
+		status = SWITCH_STATUS_SUCCESS;
+	}
+	//switch_mutex_unlock(globals.device_lock);
+
+	return status;
+	
+}
+
+static switch_status channel_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static struct switch_api_interface send_dtmf_interface = {
+	/*.interface_name*/		"padtmf",
+	/*.desc*/				"PortAudio Dial DTMF",
+	/*.function*/			send_dtmf,
+	/*.next*/				NULL
+};
+
+static struct switch_api_interface answer_call_interface = {
+	/*.interface_name*/		"paoffhook",
+	/*.desc*/				"PortAudio Answer Call",
+	/*.function*/			answer_call,
+	/*.next*/				&send_dtmf_interface
+};
+
+static struct switch_api_interface channel_info_interface = {
+	/*.interface_name*/		"painfo",
+	/*.desc*/				"PortAudio Call Info",
+	/*.function*/			call_info,
+	/*.next*/				&answer_call_interface
+};
+
+static struct switch_api_interface channel_hup_interface = {
+	/*.interface_name*/		"pahup",
+	/*.desc*/				"PortAudio Hangup Call",
+	/*.function*/			hup_call,
+	/*.next*/				&channel_info_interface
+};
+
+static struct switch_api_interface channel_api_interface = {
+	/*.interface_name*/		"pacall",
+	/*.desc*/				"PortAudio Call",
+	/*.function*/			place_call,
+	/*.next*/				&channel_hup_interface
+};
+
+static const switch_event_handler_table channel_event_handlers = {
+	/*.on_init*/			channel_on_init,
+	/*.on_ring*/			channel_on_ring,
+	/*.on_execute*/			channel_on_execute,
+	/*.on_hangup*/			channel_on_hangup,
+	/*.on_loopback*/		channel_on_loopback,
+	/*.on_transmit*/		channel_on_transmit
+};
+
+static const switch_io_routines channel_io_routines = {
+	/*.outgoing_channel*/	channel_outgoing_channel,
+	/*.answer_channel*/		channel_answer_channel,
+	/*.read_frame*/			channel_read_frame,
+	/*.write_frame*/		channel_write_frame,
+	/*.kill_channel*/		channel_kill_channel,
+	/*.waitfor_read*/		channel_waitfor_read,
+	/*.waitfor_write*/		channel_waitfor_write,
+	/*.send_dtmf*/			channel_send_dtmf
+};
+
+static const switch_endpoint_interface channel_endpoint_interface = {
+	/*.interface_name*/		"portaudio",
+	/*.io_routines*/		&channel_io_routines,
+	/*.event_handlers*/		&channel_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface channel_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&channel_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL,
+	/*.api_interface*/			&channel_api_interface
+};
+
+
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+
+	Pa_Initialize();
+	load_config();
+	switch_core_hash_init(&globals.call_hash, module_pool);
+	switch_mutex_init(&globals.device_lock, SWITCH_MUTEX_NESTED, module_pool);
+	
+	dump_info();
+
+	if (switch_event_reserve_subclass(MY_EVENT_RINGING) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Couldn't register subclass!");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &channel_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status load_config(void)
+{
+	switch_config cfg;
+	char *var, *val;
+	char *cf = "portaudio.conf";
+	
+	memset(&globals, 0, sizeof(globals));
+	
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "sample_rate")) {
+				globals.sample_rate = atoi(val);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(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, 0);
+				}
+			}
+		}
+	}
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+	
+	if (!globals.sample_rate) {
+		globals.sample_rate = 8000;
+	}
+
+	switch_config_close_file(&cfg);
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/*
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+
+	switch_yield(50000);
+	make_call("8888");
+	return SWITCH_STATUS_TERM;
+}
+*/
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+   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)
+{
+    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 switch_status engage_device(struct private_object *tech_pvt)
+{
+	int sample_rate = globals.sample_rate;
+	int codec_ms = 20;
+
+	switch_channel *channel;
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	if (switch_core_codec_init(&tech_pvt->read_codec,
+							   "L16",
+							   sample_rate,
+							   codec_ms,
+							   1,
+							   SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE,
+							   NULL,
+							   switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+			return SWITCH_STATUS_FALSE;
+		} else {
+			if (switch_core_codec_init(&tech_pvt->write_codec,
+									   "L16",
+									   sample_rate,
+									   codec_ms,
+									   1,
+									   SWITCH_CODEC_FLAG_ENCODE |SWITCH_CODEC_FLAG_DECODE,
+									   NULL,
+									   switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't load codec?\n");
+				switch_core_codec_destroy(&tech_pvt->read_codec);	
+				return SWITCH_STATUS_FALSE;
+			}
+		}
+		tech_pvt->read_frame.rate = sample_rate;
+		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);
+
+		tech_pvt->indev = globals.indev;
+		tech_pvt->outdev = globals.outdev;
+		
+		switch_mutex_lock(globals.device_lock);
+		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 [%d]!\n", tech_pvt->outdev);
+				CloseAudioStream(tech_pvt->audio_in);
+				tech_pvt->audio_in = NULL;
+			}
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open audio in [%d]!\n", tech_pvt->indev);		
+		}
+		switch_mutex_unlock(globals.device_lock);
+
+		if (tech_pvt->err == paNoError) {
+			snprintf(tech_pvt->call_id, sizeof(tech_pvt->call_id), "%d", globals.call_id++);
+			switch_core_hash_insert(globals.call_hash, tech_pvt->call_id, tech_pvt);	
+			return SWITCH_STATUS_SUCCESS;
+		} else {
+			switch_core_codec_destroy(&tech_pvt->read_codec);	
+			switch_core_codec_destroy(&tech_pvt->write_codec);	
+			switch_core_session_destroy(&tech_pvt->session);
+		}
+	
+		return SWITCH_STATUS_FALSE;
+}
+
+static switch_status place_call(char *dest, char *out, size_t outlen)
+{
+	switch_core_session *session;
+	switch_status status = SWITCH_STATUS_FALSE;
+
+	if (!dest) {
+		strncpy(out, "Usage: pacall <exten>", outlen - 1);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	strncpy(out, "FAIL", outlen - 1);
+
+	if ((session = switch_core_session_request(&channel_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel;
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(session);
+			switch_core_session_set_private(session, tech_pvt);
+			tech_pvt->session = session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(&session);
+			return SWITCH_STATUS_FALSE;
+		}
+
+		if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+																  globals.dialplan,
+																  globals.cid_name,
+																  globals.cid_num,
+																  NULL,
+																  NULL,
+																  NULL,
+																  dest))) {
+			char name[128];
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+			snprintf(name, sizeof(name), "PortAudio/%s-%04x", tech_pvt->caller_profile->destination_number ? tech_pvt->caller_profile->destination_number : modname, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		}
+		tech_pvt->session = session;
+		if ((status = engage_device(tech_pvt)) == SWITCH_STATUS_SUCCESS) {
+			switch_channel_set_state(channel, CS_INIT);
+			switch_core_session_thread_launch(tech_pvt->session);
+			snprintf(out, outlen, "SUCCESS: %s", tech_pvt->call_id);
+		}
+	}		
+	return status;
+}
+
+
+static switch_status hup_call(char *callid, char *out, size_t outlen)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	char tmp[50];
+
+	if (callid && !strcasecmp(callid, "last")) {
+		snprintf(tmp, sizeof(tmp), "%d", globals.call_id - 1);
+		callid = tmp;
+	}
+	if (!callid || !strcasecmp(callid, "all")) {
+		switch_hash_index_t* hi;
+		void *val;
+		int i = 0;
+
+		for (hi = apr_hash_first(module_pool, globals.call_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, NULL, NULL, &val);
+			tech_pvt = val;
+			channel = switch_core_session_get_channel(tech_pvt->session);
+			assert(channel != NULL);
+			switch_channel_hangup(channel);
+			i++;
+		}
+
+		snprintf(out, outlen, "HUNGUP: %d", i);
+
+		return SWITCH_STATUS_SUCCESS;
+	}
+	
+	if ((tech_pvt = switch_core_hash_find(globals.call_hash, callid))) {
+
+		channel = switch_core_session_get_channel(tech_pvt->session);
+		assert(channel != NULL);
+
+		switch_channel_hangup(channel);
+		strncpy(out, "OK", outlen - 1);
+	} else {
+		strncpy(out, "NO SUCH CALL", outlen - 1);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status send_dtmf(char *callid, char *out, size_t outlen)
+{
+	struct private_object *tech_pvt = NULL;
+	switch_channel *channel = NULL;
+	char *dtmf;
+
+	if ((dtmf = strchr(callid, ' '))) {
+		*dtmf++ = '\0';
+	} else {
+		dtmf = "";
+	}
+
+	if ((tech_pvt = switch_core_hash_find(globals.call_hash, callid))) {
+		channel = switch_core_session_get_channel(tech_pvt->session);
+		assert(channel != NULL);
+		switch_channel_queue_dtmf(channel, dtmf);
+		strncpy(out, "OK", outlen - 1);
+	} else {
+		strncpy(out, "NO SUCH CALL", outlen - 1);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status answer_call(char *callid, char *out, size_t outlen)
+{
+	struct private_object *tech_pvt = NULL;
+	switch_channel *channel = NULL;
+
+	if ((tech_pvt = switch_core_hash_find(globals.call_hash, callid))) {
+		channel = switch_core_session_get_channel(tech_pvt->session);
+		assert(channel != NULL);
+		switch_set_flag(tech_pvt, TFLAG_ANSWER);
+		switch_channel_answer(channel);
+	} else {
+		strncpy(out, "NO SUCH CALL", outlen - 1);
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+static void print_info(struct private_object *tech_pvt, char *out, size_t outlen)
+{
+	switch_channel *channel = NULL;
+	channel = switch_core_session_get_channel(tech_pvt->session);
+	assert(channel != NULL);
+
+	snprintf(out, outlen, "CALL %s\t%s\t%s\t%s\t%s\n",
+									tech_pvt->call_id,
+			 tech_pvt->caller_profile->caller_id_name ? tech_pvt->caller_profile->caller_id_name : "n/a",
+			 tech_pvt->caller_profile->caller_id_number ? tech_pvt->caller_profile->caller_id_number : "n/a",
+			 tech_pvt->caller_profile->destination_number ? tech_pvt->caller_profile->destination_number : "n/a",
+			 switch_channel_get_name(channel));
+
+}
+
+static switch_status call_info(char *callid, char *out, size_t outlen)
+{
+	struct private_object *tech_pvt;
+	switch_hash_index_t* hi;
+	void *val;
+	if (!callid || !strcasecmp(callid, "all")) {
+		for (hi = apr_hash_first(module_pool, globals.call_hash); hi; hi = switch_hash_next(hi)) {
+			switch_hash_this(hi, NULL, NULL, &val);
+			tech_pvt = val;
+			print_info(tech_pvt, out + strlen(out), outlen - strlen(out));	
+		}
+	} else if ((tech_pvt = switch_core_hash_find(globals.call_hash, callid))) {
+		print_info(tech_pvt, out, outlen);
+	} else {
+		strncpy(out, "NO SUCH CALL", outlen - 1);
+	}
+	
+	return SWITCH_STATUS_SUCCESS;
+}
diff --git a/src/mod/endpoints/mod_portaudio/pablio.c b/src/mod/endpoints/mod_portaudio/pablio.c
new file mode 100644
index 0000000000..b5735daea0
--- /dev/null
+++ b/src/mod/endpoints/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/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h
new file mode 100644
index 0000000000..25bccf8998
--- /dev/null
+++ b/src/mod/endpoints/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/endpoints/mod_portaudio/ringbuffer.c b/src/mod/endpoints/mod_portaudio/ringbuffer.c
new file mode 100644
index 0000000000..867b501965
--- /dev/null
+++ b/src/mod/endpoints/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/endpoints/mod_portaudio/ringbuffer.h b/src/mod/endpoints/mod_portaudio/ringbuffer.h
new file mode 100644
index 0000000000..3cd559488b
--- /dev/null
+++ b/src/mod/endpoints/mod_portaudio/ringbuffer.h
@@ -0,0 +1,103 @@
+#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.
+ *
+ */
+#define PortAudioStream PaStream
+#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/src/mod/endpoints/mod_wanchan/mod_wanchan.c b/src/mod/endpoints/mod_wanchan/mod_wanchan.c
new file mode 100644
index 0000000000..3fd8080084
--- /dev/null
+++ b/src/mod/endpoints/mod_wanchan/mod_wanchan.c
@@ -0,0 +1,634 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_wanchan.c -- WANPIPE PRI Channel Module
+ *
+ */
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <libsangoma.h>
+#include <sangoma_pri.h>
+
+static const char modname[] = "mod_wanchan";
+#define STRLEN 15
+
+static switch_memory_pool *module_pool;
+
+typedef enum {
+	PFLAG_ANSWER = (1 << 0),
+	PFLAG_HANGUP = (1 << 1),
+} PFLAGS;
+
+
+typedef enum {
+	PPFLAG_RING = (1 << 0),
+} PPFLAGS;
+
+typedef enum {
+	TFLAG_MEDIA = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_INCOMING = (1 << 3),
+	TFLAG_PARSE_INCOMING = (1 << 4),
+	TFLAG_ACTIVATE = (1 << 5),
+	TFLAG_DTMF = (1 << 6),
+	TFLAG_DESTROY = (1 << 7),
+	TFLAG_ABORT = (1 << 8),
+	TFLAG_SWITCH = (1 << 9),
+} TFLAGS;
+
+#define PACKET_LEN 160
+#define DEFAULT_BYTES_PER_FRAME 160
+
+static struct {
+	int debug;
+	int panic;
+	int span;
+	int dchan;
+	int node;
+	int pswitch;
+	int bytes_per_frame;
+	char *dialplan;
+} globals;
+
+
+
+struct private_object {
+	unsigned int flags;							/* FLAGS */
+	struct switch_frame frame;						/* Frame for Writing */
+	unsigned char databuf[1024];
+	struct sangoma_pri *spri;
+	pri_event ring_event;
+	pri_event hangup_event;
+	sangoma_api_hdr_t hdrframe;
+	switch_caller_profile *caller_profile;
+	int socket;
+	int callno;
+	int cause;
+};
+
+struct channel_map {
+	switch_core_session *map[36];
+};
+
+
+static void set_global_dialplan(char *dialplan)
+{
+	if (globals.dialplan) {
+		free(globals.dialplan);
+		globals.dialplan = NULL;
+	}
+	
+	globals.dialplan = strdup(dialplan);
+}
+
+
+
+static int str2node(char *node)
+{
+	if (!strcasecmp(node, "cpe"))
+		return PRI_CPE;
+	if (!strcasecmp(node, "network"))
+		return PRI_NETWORK;
+	return -1;
+}
+
+static int str2switch(char *swtype)
+{
+	if (!strcasecmp(swtype, "ni2"))
+		return PRI_SWITCH_NI2;
+	if (!strcasecmp(swtype, "dms100"))
+		return PRI_SWITCH_DMS100;
+	if (!strcasecmp(swtype, "lucent5e"))
+		return PRI_SWITCH_LUCENT5E;
+	if (!strcasecmp(swtype, "att4ess"))
+		return PRI_SWITCH_ATT4ESS;
+	if (!strcasecmp(swtype, "euroisdn"))
+		return PRI_SWITCH_EUROISDN_E1;
+	if (!strcasecmp(swtype, "gr303eoc"))
+		return PRI_SWITCH_GR303_EOC;
+	if (!strcasecmp(swtype, "gr303tmc"))
+		return PRI_SWITCH_GR303_TMC;
+	return -1;
+}
+
+
+
+static void set_global_dialplan(char *dialplan);
+static int str2node(char *node);
+static int str2switch(char *swtype);
+static switch_status wanchan_on_init(switch_core_session *session);
+static switch_status wanchan_on_hangup(switch_core_session *session);
+static switch_status wanchan_on_loopback(switch_core_session *session);
+static switch_status wanchan_on_transmit(switch_core_session *session);
+static switch_status wanchan_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status wanchan_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status wanchan_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event);
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event);
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event);
+static int check_flags(struct sangoma_pri *spri);
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event);
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event);
+static void *pri_thread_run(switch_thread *thread, void *obj);
+static int config_wanpipe(int reload);
+
+
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status wanchan_on_init(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	tech_pvt->frame.data = tech_pvt->databuf;
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WANCHAN INIT\n");
+
+	
+	/* Move Channel's State Machine to RING */
+	switch_channel_set_state(channel, CS_RING);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WANCHAN RING\n");
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_on_hangup(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_socket_close(&tech_pvt->socket);
+	
+	pri_hangup(tech_pvt->spri->pri, tech_pvt->hangup_event.hangup.call ? tech_pvt->hangup_event.hangup.call : tech_pvt->ring_event.ring.call, tech_pvt->cause);
+	pri_destroycall(tech_pvt->spri->pri, tech_pvt->hangup_event.hangup.call ? tech_pvt->hangup_event.hangup.call : tech_pvt->ring_event.ring.call);
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WANCHAN HANGUP\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WANCHAN LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WANCHAN TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "NOT IMPLEMENTED\n");
+
+	return SWITCH_STATUS_GENERR;
+}
+
+static switch_status wanchan_answer_channel(switch_core_session *session)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	pri_answer(tech_pvt->spri->pri, tech_pvt->ring_event.ring.call, 0, 1);
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+static switch_status wanchan_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	void *bp;
+	int bytes = 0, res = 0;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	bp = tech_pvt->databuf;
+
+	*frame = NULL;
+	memset(tech_pvt->databuf, 0, sizeof(tech_pvt->databuf));
+	while (bytes < globals.bytes_per_frame) {
+		if ((res = switch_socket_waitfor(tech_pvt->socket, timeout, POLLIN|POLLERR)) < 0) {
+			return SWITCH_STATUS_GENERR;
+		} else if (res == 0) {
+			tech_pvt->frame.datalen = 0;
+			return SWITCH_STATUS_SUCCESS;
+		}
+
+		if ((res = sangoma_readmsg_socket(
+										  tech_pvt->socket,
+										  &tech_pvt->hdrframe,
+										  sizeof(tech_pvt->hdrframe),
+										  bp,
+										  sizeof(tech_pvt->databuf) - bytes, 0)) < 0) {
+			if (errno == EBUSY) {
+				continue;
+			} else {
+				return SWITCH_STATUS_GENERR;
+			}
+		}
+		bytes += res;
+		bp += bytes;
+	}
+	tech_pvt->frame.datalen = bytes;	
+	
+	*frame = &tech_pvt->frame;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status wanchan_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	struct private_object *tech_pvt;
+	switch_channel *channel = NULL;
+	int res = 0;
+	int bytes = frame->datalen;
+	void *bp = frame->data;
+	switch_status status = SWITCH_STATUS_SUCCESS;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	while (bytes > 0) {
+		switch_socket_waitfor(tech_pvt->socket, -1, POLLOUT | POLLERR | POLLHUP);
+		res = sangoma_sendmsg_socket(
+									 tech_pvt->socket,
+									 &tech_pvt->hdrframe,
+									 sizeof(tech_pvt->hdrframe),
+									 bp,
+									 PACKET_LEN, 0);
+		if (res < 0) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE,	 "Bad Write frame len %d write %d bytes returned %d errno %d!\n", frame->datalen, PACKET_LEN, res, errno);
+			if (errno == EBUSY) {
+				continue;
+			}
+			status = SWITCH_STATUS_GENERR;
+			break;
+		} else {
+			bytes -= res;
+			bp += res;
+			res = 0;
+		}
+	}
+
+	return status;
+}
+
+static const switch_io_routines wanchan_io_routines*/	{
+	/*.outgoing_channel*/	wanchan_outgoing_channel,
+	/*.answer_channel*/		wanchan_answer_channel,
+	/*.read_frame*/			wanchan_read_frame,
+	/*.write_frame*/		wanchan_write_frame
+};
+
+static const switch_event_handler_table  wanchan_event_handlers = {
+	/*.on_init*/		wanchan_on_init,
+	/*.on_ring*/		wanchan_on_ring,
+	/*.on_execute*/		NULL,
+	/*.on_hangup*/		wanchan_on_hangup,
+	/*.on_loopback*/	wanchan_on_loopback,
+	/*.on_transmit*/	wanchan_on_transmit
+};
+
+static const switch_endpoint_interface wanchan_endpoint_interface = {
+	/*.interface_name*/	"wanchan",
+	/*.io_routines*/	&wanchan_io_routines,
+	/*.event_handlers*/	&wanchan_event_handlers,
+	/*.private*/		NULL,
+	/*.next*/			NULL
+};
+
+static const switch_loadable_module_interface wanchan_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&wanchan_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+Public switch_status switch_module_load(const switch_loadable_module_interface **interface, chanr *filename) {
+
+
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+	
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &wanchan_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
+/* Event Handlers */
+
+static int on_info(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "number is: %s\n", event->ring.callednum);
+	if (strlen(event->ring.callednum) > 3) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "final number is: %s\n", event->ring.callednum);
+		pri_answer(spri->pri, event->ring.call, 0, 1);
+	}
+	return 0;
+}
+
+static int on_hangup(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	struct channel_map *chanmap;
+	switch_core_session *session;
+	struct private_object *tech_pvt;
+
+	chanmap = spri->private;
+	if ((session = chanmap->map[event->hangup.channel])) {
+		switch_channel *channel = NULL;
+
+		channel = switch_core_session_get_channel(session);
+		assert(channel != NULL);
+
+		tech_pvt = switch_core_session_get_private(session);
+		assert(tech_pvt != NULL);
+		
+		tech_pvt->cause = event->hangup.cause;
+		memcpy(&tech_pvt->hangup_event, event, sizeof(*event));
+
+		switch_channel_set_state(channel, CS_HANGUP);
+	}
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE,"-- Hanging up channel %d\n", event->hangup.channel);
+	return 0;
+}
+
+static int on_ring(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	char name[128];
+	switch_core_session *session;
+	switch_channel *channel;
+	struct channel_map *chanmap;
+
+
+
+	chanmap = spri->private;
+	if (chanmap->map[event->ring.channel]) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE,"--Duplicate Ring on channel %d (ignored)\n", event->ring.channel);
+		return 0;
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE,"-- Ring on channel %d (from %s to %s)\n", event->ring.channel, event->ring.callingnum, event->ring.callednum);
+
+	sprintf(name, "w%dg%d", globals.span, event->ring.channel);
+	if ((session = switch_core_session_request(&wanchan_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		int fd;
+		char ani2str[4] = "";
+		//wanpipe_tdm_api_t tdm_api;
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			channel = switch_core_session_get_channel(session);
+			switch_core_session_set_private(session, tech_pvt);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(&session);
+			return 0;
+		}
+		
+		if (event->ring.ani2 >= 0) {
+			snprintf(ani2str, 5, "%.2d", event->ring.ani2);
+		}
+
+		if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+															   globals.dialplan,
+															   "wanchan fixme",
+															   event->ring.callingnum,
+															   event->ring.callingani,
+															   switch_strlen_zero(ani2str) ? NULL : ani2str,
+															   event->ring.callednum))) {
+			switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+		}
+
+		switch_set_flag(tech_pvt, TFLAG_INBOUND);
+		tech_pvt->spri = spri;
+		tech_pvt->cause = -1;
+
+		memcpy(&tech_pvt->ring_event, event, sizeof(*event));
+
+		tech_pvt->callno = event->ring.channel;
+
+		if ((fd = sangoma_create_socket_intr(spri->span, event->ring.channel)) < 0) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't open fd!\n");
+		}
+
+		//sangoma_tdm_set_hw_period(fd, &tdm_api, 480);
+
+		tech_pvt->socket = fd;
+		chanmap->map[event->ring.channel] = session;
+
+		switch_channel_set_state(channel, CS_INIT);
+		switch_core_session_thread_launch(session);
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create new Inbound Channel!\n");
+	}
+
+
+	return 0;
+}
+
+static int check_flags(struct sangoma_pri *spri)
+{
+	
+	return 0;
+}
+
+static int on_restart(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event)
+{
+	int fd;
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE,"-- Restarting channel %d\n", event->restart.channel);
+
+	if ((fd = sangoma_create_socket_intr(spri->span, event->restart.channel)) < 0) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE,"Can't open fd!\n");
+	} else {
+		close(fd);
+	}
+	return 0;
+}
+
+static int on_anything(struct sangoma_pri *spri, sangoma_pri_event_t event_type, pri_event *event) 
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE,"Caught Event %d (%s)\n", event_type, sangoma_pri_event_str(event_type));
+	return 0;
+}
+
+
+static void *pri_thread_run(switch_thread *thread, void *obj)
+{
+	struct sangoma_pri *spri = obj;
+	struct channel_map chanmap;
+
+	SANGOMA_MAP_PRI_EVENT((*spri), SANGOMA_PRI_EVENT_ANY, on_anything);
+	SANGOMA_MAP_PRI_EVENT((*spri), SANGOMA_PRI_EVENT_RING, on_ring);
+	SANGOMA_MAP_PRI_EVENT((*spri), SANGOMA_PRI_EVENT_HANGUP_REQ, on_hangup);
+	SANGOMA_MAP_PRI_EVENT((*spri), SANGOMA_PRI_EVENT_INFO_RECEIVED, on_info);
+	SANGOMA_MAP_PRI_EVENT((*spri), SANGOMA_PRI_EVENT_RESTART, on_restart);
+
+	spri->on_loop = check_flags;
+	spri->private = &chanmap;
+	sangoma_run_pri(spri);
+	
+	free(spri);
+	return NULL;
+}
+
+
+static int config_wanpipe(int reload) 
+{
+	switch_config cfg;
+	char *var, *val;
+	int count = 0;
+	struct sangoma_pri *spri;
+	char *cf = "wanchan.conf";
+
+	globals.bytes_per_frame = DEFAULT_BYTES_PER_FRAME;
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			} else if (!strcmp(var, "span")) {
+				globals.span = atoi(val);
+			} else if (!strcmp(var, "dchan")) {
+				globals.dchan = atoi(val);
+			} else if (!strcmp(var, "node")) {
+				globals.node = str2node(val);
+			} else if (!strcmp(var, "switch")) {
+				globals.pswitch = str2switch(val);
+			} else if (!strcmp(var, "bpf")) {
+				globals.bytes_per_frame = atoi(val);
+			} else if (!strcmp(var, "dialplan")) {
+				set_global_dialplan(val);
+			}			
+		}
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (!globals.dialplan) {
+		set_global_dialplan("default");
+	}
+
+	if ((spri=switch_core_alloc(module_pool, sizeof(*spri)))) {
+		memset(spri, 0, sizeof(*spri));
+		sangoma_init_pri(spri,
+						 globals.span,
+						 globals.dchan,
+						 23, 
+						 globals.pswitch,
+						 globals.node,
+						 globals.debug);
+		
+		pri_thread_run(NULL, spri);
+		
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "error!\n");
+	}
+
+	return count;
+
+}
+
+
+Public switch_status switch_module_runtime(void)
+{
+	config_wanpipe(0);
+	return SWITCH_STATUS_TERM;
+}
+
diff --git a/src/mod/endpoints/mod_woomerachan/mod_woomerachan.c b/src/mod/endpoints/mod_woomerachan/mod_woomerachan.c
new file mode 100644
index 0000000000..9ecbf59f11
--- /dev/null
+++ b/src/mod/endpoints/mod_woomerachan/mod_woomerachan.c
@@ -0,0 +1,1387 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_woomerachan.c -- Woomera Endpoint Module
+ *
+ */
+#include <switch.h>
+
+#define WOOMERA_STRLEN 256
+#define WOOMERA_ARRAY_LEN 50
+#define WOOMERA_MIN_PORT 9900
+#define WOOMERA_MAX_PORT 9999
+#define WOOMERA_BODYLEN 2048
+#define WOOMERA_LINE_SEPERATOR "\r\n"
+#define WOOMERA_RECORD_SEPERATOR "\r\n\r\n"
+#define WOOMERA_DEBUG_PREFIX "**[DEBUG]** "
+#define WOOMERA_DEBUG_LINE "--------------------------------------------------------------------------------" 
+#define WOOMERA_HARD_TIMEOUT -10000
+#define WOOMERA_QLEN 10
+#define WOOMERA_RECONNECT_TIME 5000000
+#define MEDIA_ANSWER "ANSWER"
+// THE ONE ABOVE OR THE 2 BELOW BUT NOT BOTH
+//#define MEDIA_ANSWER "ANSWER"
+//#define USE_ANSWER 1
+
+static const char modname[] = "mod_woomera";
+
+static switch_memory_pool *module_pool;
+
+#define STRLEN 15
+#define FRAME_LEN 480
+//static int WFORMAT = AST_FORMAT_SLINEAR;
+
+typedef enum {
+	WFLAG_EXISTS = (1 << 0),
+	WFLAG_EVENT = (1 << 1),
+	WFLAG_CONTENT = (1 << 2),
+} WFLAGS;
+
+
+typedef enum {
+	WCFLAG_NOWAIT = (1 << 0)
+} WCFLAGS;
+
+
+typedef enum {
+	PFLAG_INBOUND = (1 << 0),
+	PFLAG_OUTBOUND = (1 << 1),
+	PFLAG_DYNAMIC = (1 << 2),
+	PFLAG_DISABLED = (1 << 3)
+} PFLAGS;
+
+typedef enum {
+	TFLAG_MEDIA = (1 << 0),
+	TFLAG_INBOUND = (1 << 1),
+	TFLAG_OUTBOUND = (1 << 2),
+	TFLAG_INCOMING = (1 << 3),
+	TFLAG_PARSE_INCOMING = (1 << 4),
+	TFLAG_ACTIVATE = (1 << 5),
+	TFLAG_DTMF = (1 << 6),
+	TFLAG_DESTROY = (1 << 7),
+	TFLAG_ABORT = (1 << 8),
+	TFLAG_SWITCH = (1 << 9),
+	TFLAG_ANSWER = (1 << 10),
+} TFLAGS;
+
+struct woomera_message {
+	char callid[WOOMERA_STRLEN];
+	int mval;
+	char command[WOOMERA_STRLEN];
+	char command_args[WOOMERA_STRLEN];
+	char names[WOOMERA_STRLEN][WOOMERA_ARRAY_LEN];
+	char values[WOOMERA_STRLEN][WOOMERA_ARRAY_LEN];
+	char body[WOOMERA_BODYLEN];
+	unsigned int flags;
+	int last;
+	struct woomera_message *next;
+};
+
+
+static struct {
+	int next_woomera_port;	
+	int debug;
+	int panic;
+	int rtpmode;
+} globals;
+
+struct woomera_event_queue {
+	struct woomera_message *head;
+};
+
+struct woomera_profile {
+	char *name;
+	switch_socket_t *woomera_socket;
+	apr_thread_mutex_t *iolock;
+	char woomera_host[WOOMERA_STRLEN];
+	int woomera_port;
+	char audio_ip[WOOMERA_STRLEN];
+	char dialplan[WOOMERA_STRLEN];
+//	pthread_t thread;
+	unsigned int flags;
+	int thread_running;
+	struct woomera_event_queue event_queue;
+};
+
+
+struct private_object {
+	char *name;
+	switch_frame frame;
+	switch_codec read_codec;
+	switch_codec write_codec;
+	switch_core_session *session;
+	switch_pollfd_t read_poll;
+	switch_pollfd_t write_poll;
+	switch_pollfd_t command_poll;
+	unsigned char databuf[2048];
+	switch_mutex_t *iolock;
+	switch_sockaddr_t *udpread;
+	switch_sockaddr_t *udpwrite;
+	switch_socket_t *command_channel;
+	switch_socket_t *udp_socket;
+	unsigned int flags;
+	short fdata[FRAME_LEN];
+	struct woomera_message call_info;
+	struct woomera_profile *profile;
+	char dest[WOOMERA_STRLEN];
+	int port;
+	switch_time_t started;
+	int timeout;
+	char dtmfbuf[WOOMERA_STRLEN];
+	switch_caller_profile *caller_profile;
+	struct woomera_event_queue event_queue;
+};
+
+typedef struct private_object private_object;
+typedef struct woomera_message woomera_message;
+typedef struct woomera_profile woomera_profile;
+typedef struct woomera_event_queue woomera_event_queue;
+
+static woomera_profile default_profile;
+
+static const switch_endpoint_interface woomerachan_endpoint_interface;
+
+static switch_status woomerachan_on_init(switch_core_session *session);
+static switch_status woomerachan_on_hangup(switch_core_session *session);
+static switch_status woomerachan_on_ring(switch_core_session *session);
+static switch_status woomerachan_on_loopback(switch_core_session *session);
+static switch_status woomerachan_on_transmit(switch_core_session *session);
+static switch_status woomerachan_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session);
+static switch_status woomerachan_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags);
+static switch_status woomerachan_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags);
+static switch_status woomerachan_kill_channel(switch_core_session *session, int sig);
+static void tech_destroy(private_object *tech_pvt);
+static void woomera_printf(woomera_profile *profile, switch_socket_t *socket, char *fmt, ...);
+static char *woomera_message_header(woomera_message *wmsg, char *key);
+static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
+static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg);
+static int woomera_message_parse(switch_socket_t *fd, woomera_message *wmsg, int timeout, woomera_profile *profile, woomera_event_queue *event_queue);
+static int connect_woomera(switch_socket_t **new_sock, woomera_profile *profile, int flags);
+static int woomera_profile_thread_running(woomera_profile *profile, int set, int new);
+static int woomera_locate_socket(woomera_profile *profile, switch_socket_t **woomera_socket);
+static int tech_create_read_socket(private_object *tech_pvt);
+static void *woomera_channel_thread_run(switch_thread *thread, void *obj);
+static void *woomera_thread_run(void *obj);
+static int tech_activate(private_object *tech_pvt);
+
+/* 
+   State methods they get called when the state changes to the specific state 
+   returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+   so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status woomerachan_on_init(switch_core_session *session)
+{
+	switch_channel *channel;
+	struct private_object *tech_pvt = NULL;
+	int rate = 8000;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt->frame.data = tech_pvt->databuf;
+
+	if (switch_core_codec_init(&tech_pvt->read_codec, "L16", rate, 30, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s Cannot set read codec\n", switch_channel_get_name(channel));
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+
+	if (switch_core_codec_init(&tech_pvt->write_codec, "L16", rate, 30, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s Cannot set read codec\n", switch_channel_get_name(channel));
+		switch_channel_hangup(channel);
+		return SWITCH_STATUS_FALSE;
+	}
+	tech_pvt->frame.rate = rate;
+	tech_pvt->frame.codec = &tech_pvt->read_codec;
+	switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
+	switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
+
+
+	switch_set_flag(tech_pvt, TFLAG_ACTIVATE);
+
+	switch_core_session_launch_thread(session, woomera_channel_thread_run, session);
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s WOOMERACHAN INIT\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status woomerachan_on_ring(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s WOOMERACHAN RING\n", switch_channel_get_name(channel));
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status woomerachan_on_execute(switch_core_session *session)
+{
+
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+	
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s WOOMERACHAN EXECUTE\n", switch_channel_get_name(channel));
+
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status woomerachan_on_hangup(switch_core_session *session)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s WOOMERACHAN HANGUP\n", switch_channel_get_name(channel));
+	tech_destroy(tech_pvt);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static void woomera_socket_close(switch_socket_t **socket)
+{
+	if (*socket) {
+		switch_socket_close(*socket);
+		*socket = NULL;
+	}
+}
+
+
+static void udp_socket_close(struct private_object *tech_pvt) 
+{
+	if (tech_pvt->udp_socket) {
+		apr_socket_shutdown(tech_pvt->udp_socket, APR_SHUTDOWN_READWRITE);
+		woomera_socket_close(&tech_pvt->udp_socket);
+	}
+}
+
+
+static switch_status woomerachan_kill_channel(switch_core_session *session, int sig)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->udp_socket) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	udp_socket_close(tech_pvt);
+
+	switch_channel_hangup(channel);
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s WOOMERACHAN KILL %d\n", switch_channel_get_name(channel), tech_pvt->udp_socket);
+
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status woomerachan_on_loopback(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WOOMERACHAN LOOPBACK\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status woomerachan_on_transmit(switch_core_session *session)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "WOOMERACHAN TRANSMIT\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+/* Make sure when you have 2 sessions in the same scope that you pass the appropriate one to the routines
+   that allocate memory or you will have 1 channel with memory allocated from another channel's pool!
+*/
+static switch_status woomerachan_outgoing_channel(switch_core_session *session, switch_caller_profile *outbound_profile, switch_core_session **new_session) 
+{
+	if ((*new_session = switch_core_session_request(&woomerachan_endpoint_interface, NULL))) {
+		struct private_object *tech_pvt;
+		switch_channel *channel;
+		
+
+		if ((tech_pvt = (struct private_object *) switch_core_session_alloc(*new_session, sizeof(struct private_object)))) {
+			memset(tech_pvt, 0, sizeof(*tech_pvt));
+			tech_pvt->profile = &default_profile;
+			channel = switch_core_session_get_channel(*new_session);
+			switch_core_session_set_private(*new_session, tech_pvt);
+			tech_pvt->session = *new_session;
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		if (outbound_profile) {
+			char name[128];
+			switch_caller_profile *caller_profile;
+
+			caller_profile = switch_caller_profile_clone(*new_session, outbound_profile);
+			switch_channel_set_caller_profile(channel, caller_profile);
+			tech_pvt->caller_profile = caller_profile;
+			snprintf(name, sizeof(name), "Woomera/%s-%04x", caller_profile->destination_number, rand() & 0xffff);
+			switch_channel_set_name(channel, name);
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Doh! no caller profile\n");
+			switch_core_session_destroy(new_session);
+			return SWITCH_STATUS_GENERR;
+		}
+
+		switch_channel_set_flag(channel, CF_OUTBOUND);
+		switch_set_flag(tech_pvt, TFLAG_OUTBOUND);
+		switch_channel_set_state(channel, CS_INIT);
+		return SWITCH_STATUS_SUCCESS;
+	}
+
+	return SWITCH_STATUS_GENERR;
+
+}
+
+static switch_status woomerachan_waitfor_read(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return switch_socket_waitfor(&tech_pvt->read_poll, ms);
+}
+
+static switch_status woomerachan_waitfor_write(switch_core_session *session, int ms)
+{
+	struct private_object *tech_pvt = NULL;
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	return SWITCH_STATUS_SUCCESS;
+	return switch_socket_waitfor(&tech_pvt->write_poll, ms);
+}
+
+static switch_status woomerachan_read_frame(switch_core_session *session, switch_frame **frame, int timeout, switch_io_flag flags) 
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	switch_frame *pframe;
+	switch_status status;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->udp_socket) {
+		return SWITCH_STATUS_GENERR;
+	}
+	/*
+	if ((status = woomerachan_waitfor_read(session, -1)) != SWITCH_STATUS_SUCCESS) {
+		return status;
+	}1<
+	*/
+	pframe = &tech_pvt->frame;
+	*frame = pframe;	
+	
+	pframe->datalen = sizeof(tech_pvt->databuf);
+	if ((status = switch_socket_recvfrom (tech_pvt->udpread, tech_pvt->udp_socket, 0, tech_pvt->databuf, &pframe->datalen)) == SWITCH_STATUS_SUCCESS) {
+		pframe->samples = (int)pframe->datalen / 2;
+	}
+	return status;
+}
+
+static switch_status woomerachan_write_frame(switch_core_session *session, switch_frame *frame, int timeout, switch_io_flag flags)
+{
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	switch_frame *pframe;
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->udp_socket) {
+		return SWITCH_STATUS_GENERR;
+	}
+
+	pframe = &tech_pvt->frame;
+	return switch_socket_sendto(tech_pvt->udp_socket, tech_pvt->udpwrite, 0, frame->data, &frame->datalen);
+	
+}
+
+static const switch_event_handler_table woomerachan_event_handlers = {
+	/*.on_init*/			woomerachan_on_init,
+	/*.on_ring*/			woomerachan_on_ring,
+	/*.on_execute*/			woomerachan_on_execute,
+	/*.on_hangup*/			woomerachan_on_hangup,
+	/*.on_loopback*/		woomerachan_on_loopback,
+	/*.on_transmit*/		woomerachan_on_transmit
+};
+
+static const switch_io_routines woomerachan_io_routines = {
+	/*.outgoing_channel*/	woomerachan_outgoing_channel,
+	/*.answer_channel*/		NULL,
+	/*.read_frame*/			woomerachan_read_frame,
+	/*.write_frame*/		woomerachan_write_frame,
+	/*.kill_channel*/		woomerachan_kill_channel,
+	/*.waitfor_read*/		woomerachan_waitfor_read,
+	/*.waitfor_write*/		woomerachan_waitfor_write
+};
+
+static const switch_endpoint_interface woomerachan_endpoint_interface = {
+	/*.interface_name*/		"woomera",
+	/*.io_routines*/		&woomerachan_io_routines,
+	/*.event_handlers*/		&woomerachan_event_handlers,
+	/*.private*/			NULL,
+	/*.next*/				NULL
+};
+
+static const switch_loadable_module_interface woomerachan_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		&woomerachan_endpoint_interface,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+
+static void tech_destroy(private_object *tech_pvt) 
+{
+	woomera_message wmsg;
+	
+	if (globals.debug > 1) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, WOOMERA_DEBUG_PREFIX "+++DESTROY\n");
+	}
+
+
+	woomera_printf(tech_pvt->profile, tech_pvt->command_channel, "hangup %s%s", tech_pvt->call_info.callid, WOOMERA_RECORD_SEPERATOR);
+	if(woomera_message_parse(tech_pvt->command_channel,
+							 &wmsg,
+							 WOOMERA_HARD_TIMEOUT,
+							 tech_pvt->profile,
+							 &tech_pvt->event_queue
+							 ) < 0) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE,	 "{%s} Already Disconnected\n", tech_pvt->profile->name);
+	}
+	
+	woomera_printf(tech_pvt->profile, tech_pvt->command_channel, "bye%s", WOOMERA_RECORD_SEPERATOR);
+	woomera_socket_close(&tech_pvt->command_channel);
+	udp_socket_close(tech_pvt);
+}
+
+
+static void woomera_printf(woomera_profile *profile, switch_socket_t *socket, char *fmt, ...)
+{
+	char *stuff;
+	size_t res = 0, len = 0;
+
+	va_list ap;
+	va_start(ap, fmt);
+#ifndef vasprintf
+	stuff = (char *)malloc(10240);
+	vsnprintf(stuff, 10240, fmt, ap);
+#else
+	res = vasprintf(&stuff, fmt, ap);
+#endif
+	va_end(ap);
+	if (res == -1) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Out of memory\n");
+	} else {
+		if (profile && globals.debug) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Send Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, stuff);
+		}
+		len = strlen(stuff);
+		switch_socket_send(socket, stuff, &len);
+		
+		free(stuff);
+	}
+
+}
+
+static char *woomera_message_header(woomera_message *wmsg, char *key) 
+{
+	int x = 0;
+	char *value = NULL;
+
+	for (x = 0 ; x < wmsg->last ; x++) {
+		if (!strcasecmp(wmsg->names[x], key)) {
+			value = wmsg->values[x];
+			break;
+		}
+	}
+
+	return value;
+}
+
+static int woomera_enqueue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
+{
+	woomera_message *new, *mptr;
+
+	if ((new = malloc(sizeof(woomera_message)))) {
+		memcpy(new, wmsg, sizeof(woomera_message));
+		new->next = NULL;
+
+		if (!event_queue->head) {
+			event_queue->head = new;
+		} else {
+			for (mptr = event_queue->head; mptr && mptr->next ; mptr = mptr->next);
+			mptr->next = new;
+		}
+		return 1;
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Memory Allocation Error!\n");
+	}
+
+	return 0;
+}
+
+static int woomera_dequeue_event(woomera_event_queue *event_queue, woomera_message *wmsg)
+{
+	woomera_message *mptr = NULL;
+	
+	if (event_queue->head) {
+		mptr = event_queue->head;
+		event_queue->head = mptr->next;
+	}
+
+	if (mptr) {
+		memcpy(wmsg, mptr, sizeof(woomera_message));
+		free(mptr);
+		return 1;
+	} else {
+		memset(wmsg, 0, sizeof(woomera_message));
+	}
+	
+	return 0;
+}
+
+static int woomera_message_parse(switch_socket_t *fd, woomera_message *wmsg, int timeout, woomera_profile *profile, woomera_event_queue *event_queue) 
+{
+	char *cur, *cr, *next = NULL, *eor = NULL;
+	char buf[2048] = "", *ptr;
+	int bytes = 0;
+	int failto = 0;
+
+	memset(wmsg, 0, sizeof(woomera_message));
+
+	if (fd < 0 ) {
+		return -1;
+	}
+
+	if (timeout < 0) {
+		timeout = abs(timeout);
+		failto = 1;
+	} else if (timeout == 0) {
+		timeout = -1;
+	}
+
+	ptr = buf;
+	bytes = 0;
+	while (!(eor = strstr(buf, WOOMERA_RECORD_SEPERATOR))) {
+		size_t len = 1;
+
+		if (!profile->thread_running) {
+			return -1;
+		}
+
+		if (switch_socket_recv(fd, ptr, &len) != SWITCH_STATUS_SUCCESS) {
+			return -1;
+		}
+		ptr++;
+		bytes++;
+	}
+	//*eor = '\0';
+	next = buf;
+
+	if (globals.debug) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Receive Message: {%s} [%s/%d]\n%s\n%s", profile->name, profile->woomera_host, profile->woomera_port, WOOMERA_DEBUG_LINE, buf);
+	}
+
+	while((cur = next)) {
+		if ((cr = strstr(cur, WOOMERA_LINE_SEPERATOR))) {
+			*cr = '\0';
+			next = cr + (sizeof(WOOMERA_LINE_SEPERATOR) - 1);
+			if (!strcmp(next, WOOMERA_RECORD_SEPERATOR)) {
+				break;
+			}
+		} 
+
+		if (!cur || !cur[0]) {
+			break;
+		}
+
+		if (!wmsg->last) {
+			switch_set_flag(wmsg, WFLAG_EXISTS);
+			if (!strncasecmp(cur, "EVENT", 5)) {
+				cur += 6;
+				switch_set_flag(wmsg, WFLAG_EVENT);
+
+				if (cur && (cr = strchr(cur, ' '))) {
+					char *id;
+
+					*cr = '\0';
+					cr++;
+					id = cr;
+					if (cr && (cr = strchr(cr, ' '))) {
+						*cr = '\0';
+						cr++;
+						strncpy(wmsg->command_args, cr, WOOMERA_STRLEN);
+					}
+					if (id) {
+						strncpy(wmsg->callid, id, sizeof(wmsg->callid) - 1);
+					}
+				}
+			} else {
+				if (cur && (cur = strchr(cur, ' '))) {
+					*cur = '\0';
+					cur++;
+					wmsg->mval = atoi(buf);
+				} else {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Malformed Message!\n");
+					break;
+				}
+			}
+			if (cur) {
+				strncpy(wmsg->command, cur, WOOMERA_STRLEN);
+			} else {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Malformed Message!\n");
+				break;
+			}
+		} else {
+			char *name, *val;
+			name = cur;
+			if ((val = strchr(name, ':'))) {
+				*val = '\0';
+				val++;
+				while (*val == ' ') {
+					*val = '\0';
+					val++;
+				}
+				strncpy(wmsg->values[wmsg->last-1], val, WOOMERA_STRLEN);
+			}
+			strncpy(wmsg->names[wmsg->last-1], name, WOOMERA_STRLEN);
+			if (name && val && !strcasecmp(name, "content-type")) {
+				switch_set_flag(wmsg, WFLAG_CONTENT);
+				bytes = atoi(val);
+			}
+
+		}
+		wmsg->last++;
+	}
+
+	wmsg->last--;
+
+	if (bytes && switch_test_flag(wmsg, WFLAG_CONTENT)) {
+		size_t len = (bytes > sizeof(wmsg->body)) ? sizeof(wmsg->body) : bytes;
+		switch_socket_recv(fd, wmsg->body, &len);
+
+		if (globals.debug) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "%s\n", wmsg->body);
+		}
+	}
+
+	if (event_queue && switch_test_flag(wmsg, WFLAG_EVENT)) {
+		if (globals.debug) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Queue Event: {%s} [%s]\n", profile->name, wmsg->command);
+		}
+		/* we don't want events we want a reply so we will stash them for later */
+		woomera_enqueue_event(event_queue, wmsg);
+
+		/* call ourself recursively to find the reply. we'll keep doing this as long we get events.
+		 * wmsg will be overwritten but it's ok we just queued it.
+		 */
+		return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
+		
+	} else if (wmsg->mval > 99 && wmsg->mval < 200) {
+		/* reply in the 100's are nice but we need to wait for another reply 
+		   call ourself recursively to find the reply > 199 and forget this reply.
+		*/
+		return woomera_message_parse(fd, wmsg, timeout, profile, event_queue);
+	} else {
+		return switch_test_flag(wmsg, WFLAG_EXISTS);
+	}
+}
+
+
+static int connect_woomera(switch_socket_t **new_sock, woomera_profile *profile, int flags) 
+{
+
+	switch_sockaddr_t *sa;
+	switch_status status;
+
+	status = switch_sockaddr_info_get(&sa, profile->woomera_host, AF_INET, profile->woomera_port, 0, module_pool);
+	if (status != SWITCH_STATUS_SUCCESS) {
+		return -1;
+	}
+	status = switch_socket_create(new_sock, AF_INET, SOCK_STREAM, 0, module_pool);
+	if (status != SWITCH_STATUS_SUCCESS) {
+		return -1;
+	}
+	/*
+	status = switch_socket_bind((*new_sock), sa);
+	if (0 && status != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't Bind to %s:%d!\n", profile->woomera_host, profile->woomera_port);
+		return -1;
+	}
+	*/
+	status = switch_socket_connect((*new_sock), sa);
+	if (status != SWITCH_STATUS_SUCCESS) {
+		return -1;
+	}
+
+	return 1;
+}
+
+static int woomera_profile_thread_running(woomera_profile *profile, int set, int new) 
+{
+	int running = 0;
+
+	switch_mutex_lock(profile->iolock);
+	if (set) {
+		profile->thread_running = new;
+	}
+	running = profile->thread_running;
+	switch_mutex_unlock(profile->iolock);
+	return running;
+	
+}
+
+static int woomera_locate_socket(woomera_profile *profile, switch_socket_t **woomera_socket) 
+{
+	woomera_message wmsg;
+	
+	for (;;) {
+
+		while (connect_woomera(woomera_socket, profile, 0) < 0) {
+			if (!woomera_profile_thread_running(profile, 0, 0)) {
+				break;
+			}
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "{%s} Cannot Reconnect to Woomera! retry in 5 seconds\n", profile->name);
+			switch_sleep(WOOMERA_RECONNECT_TIME);
+		}
+
+		if (*woomera_socket) {
+			if (switch_test_flag(profile, PFLAG_INBOUND)) {
+				woomera_printf(profile, *woomera_socket, "LISTEN%s", WOOMERA_RECORD_SEPERATOR);
+				if (woomera_message_parse(*woomera_socket,
+										  &wmsg,
+										  WOOMERA_HARD_TIMEOUT,
+										  profile,
+										  &profile->event_queue
+										  ) < 0) {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "{%s} HELP! Woomera is broken!\n", profile->name);
+					globals.panic = 1;
+					woomera_profile_thread_running(&default_profile, 1, 0);
+					switch_sleep(WOOMERA_RECONNECT_TIME);
+					if (*woomera_socket) {
+						woomera_socket_close(woomera_socket);
+					}
+					
+					continue;
+				}
+			}
+
+		}
+		switch_sleep(100);
+		break;
+	}	
+	return *woomera_socket ? 1 : 0;
+}
+
+
+
+static int tech_create_read_socket(private_object *tech_pvt)
+{
+	switch_memory_pool *pool = switch_core_session_get_pool(tech_pvt->session);
+
+	if ((tech_pvt->port = globals.next_woomera_port++) >= WOOMERA_MAX_PORT) {
+		tech_pvt->port = globals.next_woomera_port = WOOMERA_MIN_PORT;
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "connect %s:%d\n", tech_pvt->profile->audio_ip, tech_pvt->port);
+	//tech_pvt->udp_socket = create_udp_socket(tech_pvt->profile->audio_ip, tech_pvt->port, &tech_pvt->udpread, 0);
+
+	switch_sockaddr_info_get(&tech_pvt->udpread, tech_pvt->profile->audio_ip, SWITCH_UNSPEC, tech_pvt->port, 0, pool);
+	if (switch_socket_create(&tech_pvt->udp_socket, AF_INET, SOCK_DGRAM, 0, pool) == SWITCH_STATUS_SUCCESS) {
+		switch_socket_bind(tech_pvt->udp_socket, tech_pvt->udpread);
+		switch_socket_create_pollfd(&tech_pvt->read_poll, tech_pvt->udp_socket, SWITCH_POLLIN|SWITCH_POLLERR, pool);
+		switch_socket_create_pollfd(&tech_pvt->write_poll, tech_pvt->udp_socket, SWITCH_POLLOUT|SWITCH_POLLERR, pool);
+	}
+
+	return 0;
+}
+
+
+static int tech_activate(private_object *tech_pvt) 
+{
+	woomera_message wmsg;
+
+	if (tech_pvt) {
+		if((connect_woomera(&tech_pvt->command_channel, tech_pvt->profile, 0))) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "connected to woomera!\n");
+		} else {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Can't connect to woomera!\n");
+			switch_sleep(WOOMERA_RECONNECT_TIME);
+			return -1;
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+
+			woomera_printf(tech_pvt->profile,
+						   tech_pvt->command_channel, 
+						   "CALL %s%sRaw-Audio: %s/%d%sLocal-Name: %s!%s%s", 
+						   tech_pvt->caller_profile->destination_number,
+						   WOOMERA_LINE_SEPERATOR,
+						   tech_pvt->profile->audio_ip,
+						   tech_pvt->port,
+						   WOOMERA_LINE_SEPERATOR,
+						   tech_pvt->caller_profile->caller_id_name,
+						   tech_pvt->caller_profile->caller_id_number,
+						   WOOMERA_RECORD_SEPERATOR
+						   );
+
+			woomera_message_parse(tech_pvt->command_channel,
+								  &wmsg,
+								  WOOMERA_HARD_TIMEOUT,
+								  tech_pvt->profile,
+								  &tech_pvt->event_queue
+								  );
+		} else {
+			switch_set_flag(tech_pvt, TFLAG_PARSE_INCOMING);
+			woomera_printf(tech_pvt->profile, tech_pvt->command_channel, "LISTEN%s", WOOMERA_RECORD_SEPERATOR);
+			if (woomera_message_parse(tech_pvt->command_channel,
+									  &wmsg,
+									  WOOMERA_HARD_TIMEOUT,
+									  tech_pvt->profile,
+									  &tech_pvt->event_queue
+									  ) < 0) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "{%s} HELP! Woomera is broken!\n", tech_pvt->profile->name);
+				switch_set_flag(tech_pvt, TFLAG_ABORT);
+				globals.panic = 1;
+			}
+		}
+	} else {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Where's my tech_pvt?\n");
+	}
+
+	return 0;
+}
+
+
+
+static void *woomera_channel_thread_run(switch_thread *thread, void *obj)
+{
+	switch_core_session *session = obj;
+	switch_channel *channel = NULL;
+	struct private_object *tech_pvt = NULL;
+	woomera_message wmsg;
+	int res = 0;
+
+	assert(session != NULL);
+
+	channel = switch_core_session_get_channel(session);
+	assert(channel != NULL);
+
+	tech_pvt = switch_core_session_get_private(session);
+	assert(tech_pvt != NULL);
+
+	if (!tech_pvt->udp_socket) {
+		tech_create_read_socket(tech_pvt);
+	}
+	
+
+	for(;;) {
+		if (globals.panic) {
+			switch_set_flag(tech_pvt, TFLAG_ABORT);
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_ABORT)) {
+			if (switch_channel_get_state(channel) < CS_HANGUP) {
+				switch_channel_set_state(channel, CS_HANGUP);
+			}
+			udp_socket_close(tech_pvt);
+			break;
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_ACTIVATE)) {
+			switch_clear_flag(tech_pvt, TFLAG_ACTIVATE);
+			tech_activate(tech_pvt);
+		}
+
+		if (switch_test_flag(tech_pvt, TFLAG_ANSWER)) {
+			switch_clear_flag(tech_pvt, TFLAG_ANSWER);
+#ifdef USE_ANSWER
+			woomera_printf(tech_pvt->profile, tech_pvt->command_channel, "ANSWER %s%s",tech_pvt->call_info.callid, WOOMERA_RECORD_SEPERATOR);
+			if(woomera_message_parse(tech_pvt->command_channel,
+									 &wmsg,
+									 WOOMERA_HARD_TIMEOUT,
+									 tech_pvt->profile,
+									 &tech_pvt->event_queue
+									 ) < 0) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE,	 "{%s} HELP! Woomera is broken!\n", tech_pvt->profile->name);
+				switch_set_flag(tech_pvt, TFLAG_ABORT);
+				globals.panic = 1;
+				continue;
+			}
+#endif
+		}
+		
+		if (switch_test_flag(tech_pvt, TFLAG_DTMF)) {
+			switch_mutex_lock(tech_pvt->iolock);
+			woomera_printf(tech_pvt->profile, tech_pvt->command_channel, "DTMF %s %s%s",tech_pvt->call_info.callid, tech_pvt->dtmfbuf, WOOMERA_RECORD_SEPERATOR);
+			if(woomera_message_parse(tech_pvt->command_channel,
+									 &wmsg,
+									 WOOMERA_HARD_TIMEOUT,
+									 tech_pvt->profile,
+									 &tech_pvt->event_queue
+									 ) < 0) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE,	 "{%s} HELP! Woomera is broken!\n", tech_pvt->profile->name);
+				switch_set_flag(tech_pvt, TFLAG_ABORT);
+				globals.panic = 1;
+				continue;
+			}
+			switch_clear_flag(tech_pvt, TFLAG_DTMF);
+			memset(tech_pvt->dtmfbuf, 0, sizeof(tech_pvt->dtmfbuf));
+			switch_mutex_unlock(tech_pvt->iolock);
+		}
+
+#if 1==0   /*convert to use switch_time_now */
+		if(tech_pvt->timeout) {
+			struct timeval now;
+			int elapsed;
+			gettimeofday(&now, NULL);
+			elapsed = (((now.tv_sec * 1000) + now.tv_usec / 1000) - ((tech_pvt->started.tv_sec * 1000) + tech_pvt->started.tv_usec / 1000));
+			if (elapsed > tech_pvt->timeout) {
+				/* call timed out! */
+				switch_set_flag(tech_pvt, TFLAG_ABORT);
+			}
+		}
+#endif
+
+		if (!tech_pvt->command_channel) {
+			break;
+		}
+		/* Check for events */
+		if((res = woomera_dequeue_event(&tech_pvt->event_queue, &wmsg)) ||
+		   (res = woomera_message_parse(tech_pvt->command_channel,
+										&wmsg,
+										100,
+										tech_pvt->profile,
+										NULL
+										))) {
+
+			if (res < 0 || !strcasecmp(wmsg.command, "HANGUP")) {
+				switch_set_flag(tech_pvt, TFLAG_ABORT);
+				continue;
+			} else if (!strcasecmp(wmsg.command, "DTMF")) {
+				/*
+				  struct ast_frame dtmf_frame = {AST_FRAME_DTMF};
+				  int x = 0;
+				  for (x = 0; x < strlen(wmsg.command_args); x++) {
+				  dtmf_frame.subclass = wmsg.command_args[x];
+				  ast_queue_frame(tech_pvt->owner, ast_frdup(&dtmf_frame));
+				  if (globals.debug > 1) {
+				  switch_console_printf(SWITCH_CHANNEL_CONSOLE, WOOMERA_DEBUG_PREFIX "SEND DTMF [%c] to %s\n", dtmf_frame.subclass, tech_pvt->owner->name);
+				  }
+				  }
+				*/
+			} else if (!strcasecmp(wmsg.command, "PROCEED")) {
+				/* This packet has lots of info so well keep it */
+				tech_pvt->call_info = wmsg;
+			} else if (switch_test_flag(tech_pvt, TFLAG_PARSE_INCOMING) && !strcasecmp(wmsg.command, "INCOMING")) {
+				char *exten;
+				char cid_name[512];
+				char *cid_num;
+				char *ip;
+				char *p;
+				switch_clear_flag(tech_pvt, TFLAG_PARSE_INCOMING);
+				switch_set_flag(tech_pvt, TFLAG_INCOMING);
+				tech_pvt->call_info = wmsg;
+
+				exten = woomera_message_header(&wmsg, "Local-Number");
+				if (switch_strlen_zero(exten)) {
+					exten = "s";
+				}
+
+				if ((p = woomera_message_header(&wmsg, "Remote-Name"))) {
+					strncpy(cid_name, p, sizeof(cid_name));
+				}
+				
+				if ((cid_num = strchr(cid_name, '!'))) {
+					*cid_num = '\0';
+					cid_num++;
+				} else {
+					cid_num = woomera_message_header(&wmsg, "Remote-Number");
+				}
+				ip = woomera_message_header(&wmsg, "Remote-Address");
+
+				if ((tech_pvt->caller_profile = switch_caller_profile_new(session,
+																		  tech_pvt->profile->dialplan,
+																		  cid_name,
+																		  cid_num,
+																		  ip,
+																		  NULL,
+																		  NULL,
+																		  exten))) {
+					char name[128];
+					switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+					snprintf(name, sizeof(name), "Woomera/%s-%04x", tech_pvt->caller_profile->destination_number, rand() & 0xffff);
+					switch_channel_set_name(channel, name);
+				}
+
+				woomera_printf(tech_pvt->profile, tech_pvt->command_channel, 
+							   "%s %s%s"
+							   "Raw-Audio: %s/%d%s",
+							   MEDIA_ANSWER,
+							   wmsg.callid,
+							   WOOMERA_LINE_SEPERATOR,
+							   tech_pvt->profile->audio_ip,
+							   tech_pvt->port,
+							   WOOMERA_RECORD_SEPERATOR);
+				
+				if(woomera_message_parse(tech_pvt->command_channel, 
+										 &wmsg,
+										 WOOMERA_HARD_TIMEOUT,
+										 tech_pvt->profile,
+										 &tech_pvt->event_queue
+										 ) < 0) {
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE,	 "{%s} HELP! Woomera is broken!\n", tech_pvt->profile->name);
+					switch_set_flag(tech_pvt, TFLAG_ABORT);
+					globals.panic = 1;
+					continue;
+				}
+			
+			} else if (!strcasecmp(wmsg.command, "CONNECT")) {
+
+			} else if (!strcasecmp(wmsg.command, "MEDIA")) {
+				char *raw_audio_header;
+
+				if ((raw_audio_header = woomera_message_header(&wmsg, "Raw-Audio"))) {
+					char ip[25];
+					char *ptr;
+					int port = 0;
+
+					strncpy(ip, raw_audio_header, sizeof(ip) - 1);
+					if ((ptr=strchr(ip, '/'))) {
+						*ptr = '\0';
+						ptr++;
+						port = atoi(ptr);
+					}
+					/* Move Channel's State Machine to RING */
+					switch_channel_answer(channel);
+					switch_channel_set_state(channel, CS_RING);
+
+					if (switch_sockaddr_info_get(&tech_pvt->udpwrite,
+												 ip,
+												 SWITCH_UNSPEC,
+												 port,
+												 0,
+												 switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+						if (globals.debug) {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, WOOMERA_DEBUG_PREFIX "{%s} Cannot resolve %s\n", tech_pvt->profile->name, ip);
+						}
+						switch_channel_hangup(channel);
+					}
+				}
+			}
+		}
+		if (globals.debug > 2) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, WOOMERA_DEBUG_PREFIX "CHECK {%s}(%d)\n", tech_pvt->profile->name, res);
+		}
+	}
+	if (globals.debug > 1) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, WOOMERA_DEBUG_PREFIX "Monitor thread for %s done.\n", tech_pvt->profile->name);
+	}
+
+	return NULL;
+}
+	
+
+
+
+static void *woomera_thread_run(void *obj) 
+{
+
+	int res = 0;
+	woomera_message wmsg;
+	woomera_profile *profile;
+
+	profile = obj;
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Started Woomera Thread {%s}.\n", profile->name);
+ 
+	profile->thread_running = 1;
+	profile->woomera_socket = NULL;
+
+
+	while(woomera_profile_thread_running(profile, 0, 0)) {
+		/* listen on socket and handle events */
+		if (globals.panic == 2) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Woomera is disabled!\n");
+			switch_sleep(WOOMERA_RECONNECT_TIME);
+			continue;
+		}
+
+		if (! profile->woomera_socket) {
+			if (woomera_locate_socket(profile, &profile->woomera_socket)) {
+				globals.panic = 0;
+			}
+			if (!woomera_profile_thread_running(profile, 0, 0)) {
+				break;
+			}
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Woomera Thread Up {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port);
+
+		}
+
+		if (globals.panic) {
+			if (globals.panic != 2) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Help I'm in a state of panic!\n");
+				globals.panic = 0;//fix
+			}
+			woomera_socket_close(&profile->woomera_socket);
+
+
+			continue;
+		}
+
+		if ((res = woomera_dequeue_event(&profile->event_queue, &wmsg) ||
+			 (res = woomera_message_parse(profile->woomera_socket,
+										  &wmsg,
+										  /* if we are not stingy with threads we can block forever */
+										  0,
+										  profile,
+										  NULL
+										  )))) {
+			if (res < 0) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "{%s} HELP! I lost my connection to woomera!\n", profile->name);
+				woomera_socket_close(&profile->woomera_socket);
+
+				//global_set_flag(TFLAG_ABORT);
+				globals.panic = 1;
+				continue;
+
+				if (profile->woomera_socket) {
+					if (switch_test_flag(profile, PFLAG_INBOUND)) {
+						woomera_printf(profile, profile->woomera_socket, "LISTEN%s", WOOMERA_RECORD_SEPERATOR);
+						if (woomera_message_parse(profile->woomera_socket,
+												  &wmsg,
+												  WOOMERA_HARD_TIMEOUT,
+												  profile,
+												  &profile->event_queue
+												  ) < 0) {
+							switch_console_printf(SWITCH_CHANNEL_CONSOLE, "{%s} HELP! Woomera is broken!\n", profile->name);
+							globals.panic = 1;
+							woomera_socket_close(&profile->woomera_socket);
+						} 
+					}
+					if (profile->woomera_socket) {
+						switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Woomera Thread Up {%s} %s/%d\n", profile->name, profile->woomera_host, profile->woomera_port);
+					}
+				}
+				continue;
+			}
+
+			if (!strcasecmp(wmsg.command, "INCOMING")) {
+				char *name;
+				switch_core_session *session;
+				
+				if (!(name = woomera_message_header(&wmsg, "Remote-Address"))) {
+					name = woomera_message_header(&wmsg, "Channel-Name");
+				}
+				
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "New Inbound Channel %s!\n", name);
+				if ((session = switch_core_session_request(&woomerachan_endpoint_interface, NULL))) {
+					struct private_object *tech_pvt;
+					switch_channel *channel;
+
+					if ((tech_pvt = (struct private_object *) switch_core_session_alloc(session, sizeof(struct private_object)))) {
+						memset(tech_pvt, 0, sizeof(*tech_pvt));
+						tech_pvt->profile = &default_profile;
+						channel = switch_core_session_get_channel(session);
+						switch_core_session_set_private(session, tech_pvt);
+						tech_pvt->session = session;
+					} else {
+						switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Hey where is my memory pool?\n");
+						switch_core_session_destroy(&session);
+						break;
+					}
+					switch_channel_set_state(channel, CS_INIT);
+					switch_core_session_thread_launch(session);
+				}
+			}
+		}
+		
+		if (globals.debug > 2) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Main Thread {%s} Select Return %d\n", profile->name, res);
+		}
+
+		switch_yield(100);
+	}
+	
+
+	if (profile->woomera_socket) {
+		woomera_printf(profile, profile->woomera_socket, "BYE%s", WOOMERA_RECORD_SEPERATOR);
+		woomera_socket_close(&profile->woomera_socket);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Ended Woomera Thread {%s}.\n", profile->name);
+	woomera_profile_thread_running(profile, 1, -1);
+	return NULL;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+
+	woomera_thread_run(&default_profile);
+
+	return SWITCH_STATUS_TERM;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	int x = 0;
+	woomera_profile_thread_running(&default_profile, 1, 0);
+	while (!woomera_profile_thread_running(&default_profile, 0, 0)) {
+		woomera_socket_close(&default_profile.woomera_socket);
+		if (x++ > 10) {
+			break;
+		}
+		switch_yield(1);
+	}
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+
+	switch_config cfg;
+	char *var, *val;
+	struct woomera_profile *profile = &default_profile;
+	char *cf = "woomera.conf";
+	
+	memset(&globals, 0, sizeof(globals));
+	globals.next_woomera_port = WOOMERA_MIN_PORT;
+	
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+	switch_set_flag(profile, PFLAG_INBOUND | PFLAG_OUTBOUND);
+	profile->name = "main";
+	strncpy(profile->dialplan, "default", sizeof(profile->dialplan) - 1);
+	
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+		if (!strcmp(var, "noload") && atoi(val)) {			
+			return SWITCH_STATUS_TERM;
+		}	
+			if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			}
+		} else if (!strcasecmp(cfg.category, "profile")) {
+			if (!strcmp(var, "audio_ip")) {
+				strncpy(profile->audio_ip, val, sizeof(profile->audio_ip) - 1);
+			} else if (!strcmp(var, "host")) {
+				strncpy(profile->woomera_host, val, sizeof(profile->woomera_host) - 1);
+			} else if (!strcmp(var, "port")) {
+				profile->woomera_port = atoi(val);
+			} else if (!strcmp(var, "disabled")) {
+				if (atoi(val) > 0) {
+					switch_set_flag(profile, PFLAG_DISABLED);
+				}
+			} else if (!strcmp(var, "inbound")) {
+				if (atoi(val) < 1) {
+					switch_clear_flag(profile, PFLAG_INBOUND);
+				}
+			} else if (!strcmp(var, "outbound")) {
+				if (atoi(val) < 1) {
+					switch_clear_flag(profile, PFLAG_OUTBOUND);
+				}
+			} else if (!strcmp(var, "dialplan")) {
+				strncpy(profile->dialplan, val, sizeof(profile->dialplan) - 1);
+			}
+		}
+	}
+
+	switch_config_close_file(&cfg);
+
+	
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+		//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+
+		if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) {
+			//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no pool\n");
+			return SWITCH_STATUS_MEMERR;
+		}
+		return SWITCH_STATUS_MEMERR;
+	}
+
+
+
+	if (switch_mutex_init(&default_profile.iolock, SWITCH_MUTEX_NESTED, module_pool) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "OH OH no lock\n");
+		return SWITCH_STATUS_TERM;
+	}
+	
+
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &woomerachan_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
diff --git a/src/mod/endpoints/mod_woomerachan/mod_woomerachan.vcproj b/src/mod/endpoints/mod_woomerachan/mod_woomerachan.vcproj
new file mode 100644
index 0000000000..2d89ed1f2f
--- /dev/null
+++ b/src/mod/endpoints/mod_woomerachan/mod_woomerachan.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_woomerachan"
+	ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"
+	RootNamespace="mod_woomerachan"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_woomerachan.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_woomerachan.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_woomerachan.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_woomerachan.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_woomerachan.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_woomerachan.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/event_handlers/mod_event_test/mod_event_test.c b/src/mod/event_handlers/mod_event_test/mod_event_test.c
new file mode 100644
index 0000000000..58c406c719
--- /dev/null
+++ b/src/mod/event_handlers/mod_event_test/mod_event_test.c
@@ -0,0 +1,133 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_event_test.c -- Framework Demo Module
+ *
+ */
+#include <switch.h>
+
+static const char modname[] = "mod_event_test";
+
+static void event_handler (switch_event *event)
+{
+	char buf[1024];
+
+	switch(event->event_id) {
+	case SWITCH_EVENT_LOG:
+		return;
+		break;
+	default:
+		switch_event_serialize(event, buf, sizeof(buf), NULL);
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\nEVENT\n--------------------------------\n%s\n", buf);
+		break;
+	}
+}
+
+
+static switch_loadable_module_interface event_test_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+#define MY_EVENT_COOL "test::cool"
+
+
+//#define TORTURE_ME
+
+#ifdef TORTURE_ME
+#define TTHREADS 500
+static int THREADS = 0;
+
+static void *torture_thread(switch_thread *thread, void *obj)
+{
+	int y = 0;
+	int z = 0;
+	switch_core_thread_session *ts = obj;
+	switch_event *event;
+
+	z = THREADS++;
+
+	while(THREADS > 0) {
+		int x;
+		for(x = 0; x < 1; x++) {
+			if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_COOL) == SWITCH_STATUS_SUCCESS) {
+				switch_event_add_header(event, "event_info", "hello world %d %d", z, y++);
+				switch_event_fire(&event);
+			}
+		}
+		switch_yield(100000);
+	}
+
+	if (ts->pool) {
+		switch_memory_pool *pool = ts->pool;
+		switch_core_destroy_memory_pool(&pool);
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Thread Ended\n");
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+	THREADS = -1;
+	switch_yield(100000);
+	return SWITCH_STATUS_SUCCESS;
+}
+#endif
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &event_test_module_interface;
+
+	if (switch_event_reserve_subclass(MY_EVENT_COOL) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Couldn't register subclass!");
+		return SWITCH_STATUS_GENERR;
+	}
+
+#ifdef TORTURE_ME
+	if (switch_event_bind((char *)modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Couldn't bind!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+	if (1) {
+		int x = 0;
+		for(x = 0 ; x < TTHREADS  ; x++) {
+			switch_core_launch_thread(torture_thread, NULL);
+		}
+	}
+#endif
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
diff --git a/src/mod/event_handlers/mod_event_test/mod_event_test.vcproj b/src/mod/event_handlers/mod_event_test/mod_event_test.vcproj
new file mode 100644
index 0000000000..6952239ce6
--- /dev/null
+++ b/src/mod/event_handlers/mod_event_test/mod_event_test.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_event_test"
+	ProjectGUID="{3A2A7795-C216-4FFF-B8EF-4D17A84BACCC}"
+	RootNamespace="mod_event_test"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_event_test.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_event_test.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_event_test.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_event_test.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/event_handlers/mod_xmpp_event/Makefile b/src/mod/event_handlers/mod_xmpp_event/Makefile
new file mode 100644
index 0000000000..e99f9650eb
--- /dev/null
+++ b/src/mod/event_handlers/mod_xmpp_event/Makefile
@@ -0,0 +1,14 @@
+LDFLAGS += -liksemel -L/usr/local/lib
+
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install iksemel-1.2.tar.gz --prefix=$(PREFIX)
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(CC) $(SOLINK) -o $(MOD).so  $(MOD).o $(LDFLAGS)
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.c b/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.c
new file mode 100644
index 0000000000..6f983723d6
--- /dev/null
+++ b/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.c
@@ -0,0 +1,386 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_xmpp_event.c -- XMPP Event Logger
+ *
+ */
+#include <switch.h>
+#include <iksemel.h>
+
+static const char modname[] = "mod_xmpp_event";
+
+static int RUNNING = 0;
+static iksfilter *my_filter;
+static int opt_timeout = 30;
+static int opt_use_tls = 0;
+
+/* stuff we keep per session */
+struct session {
+	iksparser *parser;
+	iksid *acc;
+	char *pass;
+	int features;
+	int authorized;
+	int counter;
+	int job_done;
+};
+
+static struct {
+	char *jid;
+	char *passwd;
+	char *target_jid;
+	int debug;
+	struct session session;
+} globals;
+
+static void event_handler (switch_event *event)
+{
+	char buf[1024];
+	iks *msg;
+	int loops = 0;
+
+	if (!RUNNING) {
+		return;
+	}
+
+	while (!globals.session.authorized) {
+		switch_yield(100000);
+		if (loops++ > 5) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Nothing to do with this Event!\n");
+			return;
+		}
+	}
+
+	switch(event->event_id) {
+	default:
+		switch_event_serialize(event, buf, sizeof(buf), NULL);
+		//switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\nEVENT\n--------------------------------\n%s\n", buf);
+		msg = iks_make_msg(IKS_TYPE_NONE, globals.target_jid, buf);
+		iks_insert_attrib(msg, "subject", "Event");
+		iks_send(globals.session.parser, msg);
+
+		break;
+	}
+}
+
+
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_jid, globals.jid)
+	 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_target_jid, globals.target_jid)
+	 SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_passwd, globals.passwd)
+
+
+	 static switch_status load_config(void)
+{
+	switch_config cfg;
+	switch_status status = SWITCH_STATUS_FALSE;
+	char *var, *val;
+	char *cf = "xmpp_event.conf";
+	int count = 0;
+
+	memset(&globals, 0, sizeof(globals));	
+
+	if (!switch_config_open_file(&cfg, cf)) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "open of %s failed\n", cf);
+		return SWITCH_STATUS_TERM;
+	}
+	
+	while (switch_config_next_pair(&cfg, &var, &val)) {
+		if (!strcasecmp(cfg.category, "settings")) {
+			if (!strcmp(var, "jid")) {
+				set_global_jid(val);
+				count++;
+			} else if (!strcmp(var, "target_jid")) {
+				set_global_target_jid(val);
+				count++;
+			} else if (!strcmp(var, "passwd")) {
+				set_global_passwd(val);
+				count++;
+			} else if (!strcmp(var, "debug")) {
+				globals.debug = atoi(val);
+			}
+		}
+	}
+
+	switch_config_close_file(&cfg);
+
+	if (count == 3) {
+		/* TBD use config to pick what events to bind to */
+		if (switch_event_bind((char *)modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Couldn't bind!\n");
+			return SWITCH_STATUS_GENERR;
+		}
+	
+		status = SWITCH_STATUS_SUCCESS;
+	}
+
+	return status;
+	
+}
+
+int on_result (struct session *sess, ikspak *pak)
+{
+
+	return IKS_FILTER_EAT;
+}
+
+int on_stream (struct session *sess, int type, iks *node)
+{
+	sess->counter = opt_timeout;
+
+	switch (type) {
+	case IKS_NODE_START:
+		if (opt_use_tls && !iks_is_secure (sess->parser)) {
+			iks_start_tls (sess->parser);
+		}
+		break;
+	case IKS_NODE_NORMAL:
+		if (strcmp ("stream:features", iks_name (node)) == 0) {
+			sess->features = iks_stream_features (node);
+			if (opt_use_tls && !iks_is_secure (sess->parser)) break;
+			if (sess->authorized) {
+				iks *t;
+				if (sess->features & IKS_STREAM_BIND) {
+					t = iks_make_resource_bind (sess->acc);
+					iks_send (sess->parser, t);
+					iks_delete (t);
+				}
+				if (sess->features & IKS_STREAM_SESSION) {
+					t = iks_make_session ();
+					iks_insert_attrib (t, "id", "auth");
+					iks_send (sess->parser, t);
+					iks_delete (t);
+				}
+			} else {
+				if (sess->features & IKS_STREAM_SASL_MD5)
+					iks_start_sasl (sess->parser, IKS_SASL_DIGEST_MD5, sess->acc->user, sess->pass);
+				else if (sess->features & IKS_STREAM_SASL_PLAIN)
+					iks_start_sasl (sess->parser, IKS_SASL_PLAIN, sess->acc->user, sess->pass);
+			}
+		} else if (strcmp ("failure", iks_name (node)) == 0) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "sasl authentication failed\n");
+		} else if (strcmp ("success", iks_name (node)) == 0) {
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "server connected\n");
+			sess->authorized = 1;
+			iks_send_header (sess->parser, sess->acc->server);
+		} else {
+			ikspak *pak;
+
+			pak = iks_packet (node);
+			iks_filter_packet (my_filter, pak);
+			if (sess->job_done == 1) return IKS_HOOK;
+		}
+		break;
+#if 0
+	case IKS_NODE_STOP:
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "server disconnected\n");
+		break;
+		
+	case IKS_NODE_ERROR:
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "stream error\n");
+		break;
+#endif
+
+	}
+
+	if (node) iks_delete (node);
+	return IKS_OK;
+}
+
+int on_msg (void *user_data, ikspak *pak)
+{
+	char *cmd = iks_find_cdata (pak->x, "body");
+	char *arg = NULL;
+	char retbuf[1024] = "";
+	char *p;
+
+	if ((p = strchr(cmd, '\r'))) {
+		*p++ = '\0';
+	} else if ((p = strchr(cmd, '\n'))) {
+		*p++ = '\0';
+	}
+
+	if ((arg = strchr(cmd, ' '))) {
+		*arg++ = '\0';
+	} 
+
+	switch_api_execute(cmd, arg, retbuf, sizeof(retbuf));
+
+	return 0;
+}
+
+int on_error (void *user_data, ikspak *pak)
+{
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "authorization failed\n");
+	return IKS_FILTER_EAT;
+}
+
+void on_log (struct session *sess, const char *data, size_t size, int is_incoming)
+{
+	if (iks_is_secure (sess->parser)) fprintf (stderr, "Sec");
+	if (is_incoming) fprintf (stderr, "RECV"); else fprintf (stderr, "SEND");
+	fprintf (stderr, "[%s]\n", data);
+}
+
+void j_setup_filter (struct session *sess)
+{
+	if (my_filter) iks_filter_delete (my_filter);
+	my_filter = iks_filter_new ();
+	iks_filter_add_rule (my_filter, on_msg, 0,
+						 IKS_RULE_TYPE, IKS_PAK_MESSAGE,
+						 IKS_RULE_SUBTYPE, IKS_TYPE_CHAT,
+						 IKS_RULE_FROM, globals.target_jid,
+						 IKS_RULE_DONE);
+	iks_filter_add_rule (my_filter, (iksFilterHook *) on_result, sess,
+						 IKS_RULE_TYPE, IKS_PAK_IQ,
+						 IKS_RULE_SUBTYPE, IKS_TYPE_RESULT,
+						 IKS_RULE_ID, "auth",
+						 IKS_RULE_DONE);
+	iks_filter_add_rule (my_filter, on_error, sess,
+						 IKS_RULE_TYPE, IKS_PAK_IQ,
+						 IKS_RULE_SUBTYPE, IKS_TYPE_ERROR,
+						 IKS_RULE_ID, "auth",
+						 IKS_RULE_DONE);
+}
+
+static void xmpp_connect (char *jabber_id, char *pass)
+{
+	while (RUNNING == 1) {
+		int e;
+
+		memset (&globals.session, 0, sizeof (globals.session));
+		globals.session.parser = iks_stream_new (IKS_NS_CLIENT, &globals.session, (iksStreamHook *) on_stream);
+		if (globals.debug) iks_set_log_hook (globals.session.parser, (iksLogHook *) on_log);
+		globals.session.acc = iks_id_new (iks_parser_stack (globals.session.parser), jabber_id);
+		if (NULL == globals.session.acc->resource) {
+			/* user gave no resource name, use the default */
+			char tmp[512];
+			sprintf (tmp, "%s@%s/%s", globals.session.acc->user, globals.session.acc->server, modname);
+			globals.session.acc = iks_id_new (iks_parser_stack (globals.session.parser), tmp);
+		}
+		globals.session.pass = pass;
+
+		j_setup_filter (&globals.session);
+
+		e = iks_connect_tcp (globals.session.parser, globals.session.acc->server, IKS_JABBER_PORT);
+		switch (e) {
+		case IKS_OK:
+			break;
+		case IKS_NET_NODNS:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "hostname lookup failed\n");
+		case IKS_NET_NOCONN:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "connection failed\n");
+		default:
+			switch_console_printf(SWITCH_CHANNEL_CONSOLE, "io error\n");
+			switch_sleep(5000000);
+			continue;
+		}
+
+		globals.session.counter = opt_timeout;
+		while (RUNNING == 1) {
+			e = iks_recv (globals.session.parser, 1);
+
+			if(globals.session.job_done) {
+				break;
+			}
+
+			if (IKS_HOOK == e) { 
+				break;
+			}
+
+			if (IKS_OK != e) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE, "io error %d\n", e);
+				switch_sleep(5000000);
+				break;
+			}
+
+			if (!globals.session.authorized) {
+				if (IKS_NET_TLSFAIL == e) { 
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "tls handshake failed\n");
+					switch_sleep(5000000);
+					break;
+				}
+
+				if (globals.session.counter == 0) { 
+					switch_console_printf(SWITCH_CHANNEL_CONSOLE, "network timeout\n");
+					switch_sleep(5000000);
+					break;
+				}
+			}
+		}
+	
+		iks_disconnect(globals.session.parser);
+		iks_parser_delete (globals.session.parser);
+		globals.session.authorized = 0;
+	}
+	RUNNING = 0;
+	
+}
+						  
+static switch_loadable_module_interface xmpp_event_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(switch_loadable_module_interface **interface, char *filename) {
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &xmpp_event_module_interface;
+
+	if (load_config() != SWITCH_STATUS_SUCCESS) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_shutdown(void)
+{
+
+	if (RUNNING) {
+		RUNNING = -1;
+		while (RUNNING) {
+			switch_yield(1000);
+		}
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
+{
+	RUNNING = 1;
+	xmpp_connect(globals.jid, globals.passwd);
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "disconnecting client %d\n", RUNNING);
+	return RUNNING ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_TERM;
+}
diff --git a/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.vcproj b/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.vcproj
new file mode 100644
index 0000000000..fa9167be6a
--- /dev/null
+++ b/src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.vcproj
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_xmpp_event"
+	ProjectGUID="{F10BE67C-A8FF-4CB2-AF29-D46D2590DC59}"
+	RootNamespace="mod_xmpp_event"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_XMPPEvent Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iksemel\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib iksemel.lib Ws2_32.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_xmpp_event.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\w32\vsnet\Debug;..\..\..\libs\iksemel\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_xmpp_event.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_xmpp_event.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_XMPPEvent Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iksemel\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="FreeSwitchCore.lib iksemel.lib Ws2_32.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_xmpp_event.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\w32\vsnet\Release;..\..\..\libs\iksemel\Release"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				ImportLibrary="$(OutDir)/mod_xmpp_event.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="mod_xmpp_event.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/formats/mod_sndfile/Makefile b/src/mod/formats/mod_sndfile/Makefile
new file mode 100644
index 0000000000..1056e8fdd8
--- /dev/null
+++ b/src/mod/formats/mod_sndfile/Makefile
@@ -0,0 +1,15 @@
+LDFLAGS += -lsndfile -L/usr/local/lib
+
+all:	depends $(MOD).so
+
+depends:
+	$(BASE)/buildlib.sh $(BASE) install libsndfile-1.0.12.tar.gz --prefix=$(PREFIX)
+
+$(MOD).so: $(MOD).c
+	$(CC) $(CFLAGS) -fPIC -c $(MOD).c -o $(MOD).o 
+	$(CC) $(SOLINK) -o $(MOD).so  $(MOD).o $(LDFLAGS)
+
+
+clean:
+	rm -fr *.so *.o *~
+
diff --git a/src/mod/formats/mod_sndfile/mod_sndfile.c b/src/mod/formats/mod_sndfile/mod_sndfile.c
new file mode 100644
index 0000000000..98a4f7dc25
--- /dev/null
+++ b/src/mod/formats/mod_sndfile/mod_sndfile.c
@@ -0,0 +1,294 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_sndfile.c -- Framework Demo Module
+ *
+ */
+#include <switch.h>
+#include <sndfile.h>
+
+static const char modname[] = "mod_sndfile";
+
+struct sndfile_context {
+	SF_INFO sfinfo;
+	SNDFILE* handle;
+};
+
+typedef struct sndfile_context sndfile_context;
+
+switch_status sndfile_file_open(switch_file_handle *handle, char *path)
+{
+	sndfile_context *context;
+	int mode = 0;
+	char *ext;
+
+	if (!(ext = strrchr(path, '.'))) {
+        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Format\n");
+        return SWITCH_STATUS_GENERR;
+    }	
+    ext++;
+	
+
+	if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) {
+		mode += SFM_READ;
+	}
+
+	if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
+		mode += SFM_WRITE;
+	}
+
+	if (!mode) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Mode!\n");
+		return SWITCH_STATUS_GENERR;
+	}
+
+
+	if (!(context = switch_core_alloc(handle->memory_pool, sizeof(*context)))) {
+		return SWITCH_STATUS_MEMERR;
+	}
+
+	if (!strcmp(ext, "r8") || !strcmp(ext, "raw")) {
+		context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
+		context->sfinfo.channels = 1;
+		context->sfinfo.samplerate = 8000;
+	}
+
+	if (!strcmp(ext, "r16")) {
+		context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
+		context->sfinfo.channels = 1;
+		context->sfinfo.samplerate = 16000;
+	}
+
+	if (!strcmp(ext, "r24")) {
+		context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_24;
+		context->sfinfo.channels = 1;
+		context->sfinfo.samplerate = 24000;
+	}
+
+	if (!strcmp(ext, "r32")) {
+		context->sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_32;
+		context->sfinfo.channels = 1;
+		context->sfinfo.samplerate = 32000;
+	}
+
+	if (!strcmp(ext, "gsm")) {
+		context->sfinfo.format = SF_FORMAT_RAW |SF_FORMAT_GSM610;
+		context->sfinfo.channels = 1;
+		context->sfinfo.samplerate = 8000;
+	}
+
+	if (!(context->handle = sf_open(path, mode, &context->sfinfo))) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error Opening File [%s] [%s]\n", path, sf_strerror(context->handle));
+		return SWITCH_STATUS_GENERR;
+	}
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Opening File [%s] %dhz\n", path, context->sfinfo.samplerate);
+	handle->samples = (unsigned int)context->sfinfo.frames;
+	handle->samplerate = context->sfinfo.samplerate;
+	handle->channels = context->sfinfo.channels;
+	handle->format = context->sfinfo.format;
+	handle->sections = context->sfinfo.sections;
+	handle->seekable = context->sfinfo.seekable;
+
+	handle->private = context;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status sndfile_file_close(switch_file_handle *handle)
+{
+	sndfile_context *context = handle->private;
+
+	sf_close(context->handle);
+	
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status sndfile_file_seek(switch_file_handle *handle, unsigned int *cur_sample, unsigned int samples, int whence)
+{
+	sndfile_context *context = handle->private;
+	
+	if (!handle->seekable) {
+		return SWITCH_STATUS_NOTIMPL;
+	}
+
+	*cur_sample = (unsigned int)sf_seek(context->handle, samples, whence);
+	
+	return SWITCH_STATUS_SUCCESS;
+
+}
+
+switch_status sndfile_file_read (switch_file_handle *handle, void *data, size_t *len)
+{
+	size_t inlen = *len;
+	sndfile_context *context = handle->private;
+
+	if (switch_test_flag(handle, SWITCH_FILE_DATA_RAW)) {	
+		*len = (size_t)sf_read_raw (context->handle, data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_INT)) {
+		*len = (size_t)sf_readf_int(context->handle, (int *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_SHORT)) {
+		*len = (size_t)sf_readf_short(context->handle, (short *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_FLOAT)) {
+		*len = (size_t)sf_readf_float(context->handle, (float *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_DOUBLE)) {
+		*len = (size_t)sf_readf_double(context->handle, (double *) data, inlen);
+	} else {
+		*len = (size_t)sf_readf_int(context->handle, (int *) data, inlen);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status sndfile_file_write (switch_file_handle *handle, void *data, size_t *len)
+{
+	size_t inlen = *len;
+	sndfile_context *context = handle->private;
+	
+	if (switch_test_flag(handle, SWITCH_FILE_DATA_RAW)) {	
+		*len = (size_t)sf_write_raw (context->handle, data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_INT)) {
+		*len = (size_t)sf_writef_int(context->handle, (int *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_SHORT)) {
+		*len = (size_t)sf_writef_short(context->handle, (short *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_FLOAT)) {
+		*len = (size_t)sf_writef_float(context->handle, (float *) data, inlen);
+	} else if (switch_test_flag(handle, SWITCH_FILE_DATA_DOUBLE)) {
+		*len = (size_t)sf_writef_double(context->handle, (double *) data, inlen);
+	} else {
+		*len = (size_t)sf_writef_int(context->handle, (int *) data, inlen);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+/* Registration */
+
+static char **supported_formats;
+
+static switch_file_interface sndfile_file_interface = {
+	/*.interface_name*/		modname,
+	/*.file_open*/			sndfile_file_open,
+	/*.file_close*/			sndfile_file_close,
+	/*.file_read*/			sndfile_file_read,
+	/*.file_write*/			sndfile_file_write,
+	/*.file_seek*/			sndfile_file_seek,
+	/*.extens*/ 			NULL,
+	/*.next*/				NULL,
+};
+
+static switch_loadable_module_interface sndfile_module_interface = {
+	/*.module_name*/			modname,
+	/*.endpoint_interface*/		NULL,
+	/*.timer_interface*/		NULL,
+	/*.dialplan_interface*/		NULL,
+	/*.codec_interface*/		NULL,
+	/*.application_interface*/	NULL,
+	/*.api_interface*/			NULL,
+	/*.file_interface*/			&sndfile_file_interface
+};
+
+static switch_status setup_formats(void)
+{
+	SF_FORMAT_INFO	info ;
+	SF_INFO 		sfinfo ;
+	char buffer [128] ;
+	int format, major_count, subtype_count, m, s ;
+	int len,x,skip;
+	char *extras[] = {"r8", "r16", "r24", "r32", "gsm", NULL};
+	int exlen = (sizeof(extras) / sizeof(extras[0]));
+	buffer [0] = 0 ;
+	sf_command (NULL, SFC_GET_LIB_VERSION, buffer, sizeof (buffer)) ;
+	if (strlen (buffer) < 1) {
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "Line %d: could not retrieve lib version.\n", __LINE__) ;
+		return SWITCH_STATUS_FALSE;
+	}
+
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE, "\nLibSndFile Version : %s Supported Formats\n", buffer) ;
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "================================================================================\n");
+	sf_command (NULL, SFC_GET_FORMAT_MAJOR_COUNT, &major_count, sizeof (int)) ;
+	sf_command (NULL, SFC_GET_FORMAT_SUBTYPE_COUNT, &subtype_count, sizeof (int)) ;
+	
+	sfinfo.channels = 1 ;
+	len = ((major_count + (exlen + 2)) * sizeof(char *));
+	supported_formats = switch_core_permenant_alloc(len);
+
+	len = 0;
+	for (m = 0 ; m < major_count ; m++) {
+		skip = 0;
+		info.format = m ;
+		sf_command (NULL, SFC_GET_FORMAT_MAJOR, &info, sizeof (info)) ;
+		switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "%s  (extension \"%s\")\n", info.name, info.extension) ;
+		for (x = 0 ; x < len ; x++) {
+			if (supported_formats[x] == info.extension) {
+				skip++;
+				break;
+			}
+		}
+		if (!skip) {
+			supported_formats[len++] = (char *) info.extension;
+		}
+		format = info.format;
+		
+		for (s = 0 ; s < subtype_count ; s++) {	
+			info.format = s ;
+			sf_command (NULL, SFC_GET_FORMAT_SUBTYPE, &info, sizeof (info)) ;
+			format = (format & SF_FORMAT_TYPEMASK) | info.format ;
+			sfinfo.format = format ;
+			if (sf_format_check (&sfinfo)) {
+				switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "   %s\n", info.name) ;
+			}
+		}
+
+	}
+	for(m=0; m< exlen; m++) {
+		supported_formats[len++] = extras[m];
+	}
+	
+
+
+	switch_console_printf(SWITCH_CHANNEL_CONSOLE_CLEAN, "================================================================================\n");
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(switch_loadable_module_interface **interface, char *filename) {
+
+	
+	if (setup_formats() != SWITCH_STATUS_SUCCESS) {
+		return SWITCH_STATUS_FALSE;
+	}
+
+	/* connect my internal structure to the blank pointer passed to me */
+	sndfile_file_interface.extens = supported_formats;
+	*interface = &sndfile_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
diff --git a/src/mod/formats/mod_sndfile/mod_sndfilel.vcproj b/src/mod/formats/mod_sndfile/mod_sndfilel.vcproj
new file mode 100644
index 0000000000..79db6aea16
--- /dev/null
+++ b/src/mod/formats/mod_sndfile/mod_sndfilel.vcproj
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_sndfile"
+	ProjectGUID="{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}"
+	RootNamespace="mod_sndfile"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_sndfile Debug"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libsndfile\Win32&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libsndfile.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_sndfile.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\libsndfile\Win32\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_sndfile.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_sndfile.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+				CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_sndfile Release"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libsndfile\Win32&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="libsndfile.lib"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_sndfile.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\libsndfile\Win32\Release"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				LinkTimeCodeGeneration="1"
+				ImportLibrary="$(OutDir)/mod_sndfile.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_sndfile.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/src/mod/timers/mod_softtimer/mod_softtimer.c b/src/mod/timers/mod_softtimer/mod_softtimer.c
new file mode 100644
index 0000000000..c379436ab3
--- /dev/null
+++ b/src/mod/timers/mod_softtimer/mod_softtimer.c
@@ -0,0 +1,128 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct@yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct@yahoo.com>
+ *
+ *
+ * mod_softtimer.c -- Software Timer Module
+ *
+ */
+#include <switch.h>
+#include <stdio.h>
+
+static const char modname[] = "mod_softtimer";
+
+#ifdef WIN32
+//#define WINTIMER
+#endif
+
+struct timer_private {
+#ifdef WINTIMER
+	LARGE_INTEGER freq;
+	LARGE_INTEGER base;
+	LARGE_INTEGER now;
+#else
+	switch_time_t reference;
+#endif
+};
+
+static switch_status soft_timer_init(switch_timer *timer)
+{
+	struct timer_private *private;
+
+	private = switch_core_alloc(timer->memory_pool, sizeof(*private));
+	timer->private = private;
+
+#ifdef WINTIMER
+	QueryPerformanceFrequency(&private->freq);
+	QueryPerformanceCounter(&private->base);
+#else
+	private->reference = switch_time_now();
+#endif
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status soft_timer_next(switch_timer *timer)
+{
+	struct timer_private *private = timer->private;
+
+#ifdef WINTIMER
+	private->base.QuadPart += timer->interval * (private->freq.QuadPart / 1000);
+	for(;;) {
+		QueryPerformanceCounter(&private->now);
+		if(private->now.QuadPart >= private->base.QuadPart) {
+			break;
+		}
+		switch_yield(100);
+	}
+#else
+	private->reference += timer->interval * 1000;
+
+	while (switch_time_now() < private->reference) {
+		switch_yield(1000);
+	}
+#endif
+
+	timer->samplecount += timer->samples;
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status soft_timer_destroy(switch_timer *timer)
+{
+	timer->private = NULL;
+	return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_timer_interface soft_timer_interface = {
+	/*.interface_name*/		"soft",
+	/*.timer_init*/			soft_timer_init,
+	/*.timer_next*/			soft_timer_next,
+	/*.timer_destroy*/		soft_timer_destroy
+};
+
+static const switch_loadable_module_interface mod_timers_module_interface = {
+	/*.module_name*/					modname,
+	/*.endpoint_interface*/				NULL,
+	/*.timer_interface*/				&soft_timer_interface,
+	/*.switch_dialplan_interface*/		NULL,
+	/*.switch_codec_interface*/			NULL,
+	/*.switch_application_interface*/	NULL
+};
+
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {
+	
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &mod_timers_module_interface;
+
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
diff --git a/src/mod/timers/mod_softtimer/mod_softtimer.vcproj b/src/mod/timers/mod_softtimer/mod_softtimer.vcproj
new file mode 100644
index 0000000000..b268d2fe5d
--- /dev/null
+++ b/src/mod/timers/mod_softtimer/mod_softtimer.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_softtimer"
+	ProjectGUID="{DCC13474-28DF-47CA-A8EB-72F8CE9A78C5}"
+	RootNamespace="mod_softtimer"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_softtimer.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_softtimer.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_softtimer.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="0"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_softtimer.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_softtimer.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\mod_softtimer.c"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>