]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
update
authorAnthony Minessale <anthony.minessale@gmail.com>
Tue, 3 Jan 2006 22:13:59 +0000 (22:13 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Tue, 3 Jan 2006 22:13:59 +0000 (22:13 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@263 d0543943-73ff-0310-b7d9-9358b9ac24b2

50 files changed:
src/mod/aplications/mod_bridgecall.c [new file with mode: 0644]
src/mod/aplications/mod_bridgecall.vcproj [new file with mode: 0644]
src/mod/aplications/mod_playback/mod_playback.c [new file with mode: 0644]
src/mod/aplications/mod_playback/mod_playback.vcproj [new file with mode: 0644]
src/mod/aplications/mod_skel/mod_skel.c [new file with mode: 0644]
src/mod/codec/mod_codec_g729/Makefile [new file with mode: 0644]
src/mod/codec/mod_codec_g729/mod_codec_g729.c [new file with mode: 0644]
src/mod/codec/mod_codec_g729/mod_codec_g729.vcproj [new file with mode: 0644]
src/mod/codec/mod_g711codec/Makefile [new file with mode: 0644]
src/mod/codec/mod_g711codec/g711.c [new file with mode: 0644]
src/mod/codec/mod_g711codec/g711.h [new file with mode: 0644]
src/mod/codec/mod_g711codec/mod_g711codec.c [new file with mode: 0644]
src/mod/codec/mod_g711codec/mod_g711codec.vcproj [new file with mode: 0644]
src/mod/codec/mod_rawaudio/mod_rawaudio.c [new file with mode: 0644]
src/mod/codec/mod_rawaudio/mod_rawaudio.vcproj [new file with mode: 0644]
src/mod/codec/mod_speexcodec/Makefile [new file with mode: 0644]
src/mod/codec/mod_speexcodec/mod_speexcodec.c [new file with mode: 0644]
src/mod/codec/mod_speexcodec/mod_speexcodec.vcproj [new file with mode: 0644]
src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.c [new file with mode: 0644]
src/mod/dialplan/mod_dialplan_demo/mod_dialplan_demo.vcproj [new file with mode: 0644]
src/mod/endpoints/mod_exosip/Makefile [new file with mode: 0644]
src/mod/endpoints/mod_exosip/mod_exosip.c [new file with mode: 0644]
src/mod/endpoints/mod_exosip/mod_exosip.vcproj [new file with mode: 0644]
src/mod/endpoints/mod_exosip/mod_exosip_ccrtp.c [new file with mode: 0644]
src/mod/endpoints/mod_exosip/mod_exosip_ucl.c [new file with mode: 0644]
src/mod/endpoints/mod_iaxchan/Makefile [new file with mode: 0644]
src/mod/endpoints/mod_iaxchan/mod_IaxChan.vcproj [new file with mode: 0644]
src/mod/endpoints/mod_iaxchan/mod_iaxchan.c [new file with mode: 0644]
src/mod/endpoints/mod_opalchan/Makefile [new file with mode: 0644]
src/mod/endpoints/mod_opalchan/mod_opalchan.c [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/Makefile [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/mod_PortAudio.vcproj [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/mod_portaudio.c [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/pablio.c [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/pablio.h [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/ringbuffer.c [new file with mode: 0644]
src/mod/endpoints/mod_portaudio/ringbuffer.h [new file with mode: 0644]
src/mod/endpoints/mod_wanchan/mod_wanchan.c [new file with mode: 0644]
src/mod/endpoints/mod_woomerachan/mod_woomerachan.c [new file with mode: 0644]
src/mod/endpoints/mod_woomerachan/mod_woomerachan.vcproj [new file with mode: 0644]
src/mod/event_handlers/mod_event_test/mod_event_test.c [new file with mode: 0644]
src/mod/event_handlers/mod_event_test/mod_event_test.vcproj [new file with mode: 0644]
src/mod/event_handlers/mod_xmpp_event/Makefile [new file with mode: 0644]
src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.c [new file with mode: 0644]
src/mod/event_handlers/mod_xmpp_event/mod_xmpp_event.vcproj [new file with mode: 0644]
src/mod/formats/mod_sndfile/Makefile [new file with mode: 0644]
src/mod/formats/mod_sndfile/mod_sndfile.c [new file with mode: 0644]
src/mod/formats/mod_sndfile/mod_sndfilel.vcproj [new file with mode: 0644]
src/mod/timers/mod_softtimer/mod_softtimer.c [new file with mode: 0644]
src/mod/timers/mod_softtimer/mod_softtimer.vcproj [new file with mode: 0644]

diff --git a/src/mod/aplications/mod_bridgecall.c b/src/mod/aplications/mod_bridgecall.c
new file mode 100644 (file)
index 0000000..facdca0
--- /dev/null
@@ -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 (file)
index 0000000..86366d0
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_bridgecall"\r
+       ProjectGUID="{E1794405-29D4-466D-9BE3-DD2344C2A663}"\r
+       RootNamespace="mod_bridgecall"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_bridgecall.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_bridgecall.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_bridgecall.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_bridgecall.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_bridgecall.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_bridgecall.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/aplications/mod_playback/mod_playback.c b/src/mod/aplications/mod_playback/mod_playback.c
new file mode 100644 (file)
index 0000000..757f7e7
--- /dev/null
@@ -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 (file)
index 0000000..a63395a
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_playback"\r
+       ProjectGUID="{78100236-7CEA-4948-96CC-E8ED3160329C}"\r
+       RootNamespace="mod_playback"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_playback.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_playback.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_playback.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_playback.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_playback.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_playback.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/aplications/mod_skel/mod_skel.c b/src/mod/aplications/mod_skel/mod_skel.c
new file mode 100644 (file)
index 0000000..21126d1
--- /dev/null
@@ -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 (file)
index 0000000..6657b4c
--- /dev/null
@@ -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 (file)
index 0000000..e85d461
--- /dev/null
@@ -0,0 +1,203 @@
+/* \r
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application\r
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>\r
+ *\r
+ * Version: MPL 1.1\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License. You may obtain a copy of the License at\r
+ * http://www.mozilla.org/MPL/\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ *\r
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application\r
+ *\r
+ * The Initial Developer of the Original Code is\r
+ * Anthony Minessale II <anthmct@yahoo.com>\r
+ * Portions created by the Initial Developer are Copyright (C)\r
+ * the Initial Developer. All Rights Reserved.\r
+ *\r
+ * Contributor(s):\r
+ * \r
+ * Anthony Minessale II <anthmct@yahoo.com>\r
+ * Michael Jerris <mike@jerris.com>\r
+ *\r
+ * mod_codec_g729.c -- G729 Codec Module\r
+ *\r
+ */\r
+#include "switch.h"\r
+#include "g729.h"\r
+\r
+static const char modname[] = "mod_codec_g729";\r
+\r
+struct g729_context {\r
+       struct dec_state decoder_object;\r
+       struct cod_state encoder_object;\r
+};\r
+\r
+static switch_status switch_g729_init(switch_codec *codec, switch_codec_flag flags, const struct switch_codec_settings *codec_settings)\r
+{\r
+       struct g729_context *context = NULL;\r
+       int encoding, decoding;\r
+\r
+       encoding = (flags & SWITCH_CODEC_FLAG_ENCODE);\r
+       decoding = (flags & SWITCH_CODEC_FLAG_DECODE);\r
+\r
+       if (!(encoding || decoding) || (!(context = switch_core_alloc(codec->memory_pool, sizeof(struct g729_context))))) {\r
+               return SWITCH_STATUS_FALSE;\r
+       } else {\r
+               if (encoding) {\r
+                       g729_init_coder(&context->encoder_object, 0);\r
+               }\r
+               if (decoding) {\r
+                       g729_init_decoder(&context->decoder_object);\r
+               }\r
+\r
+               codec->private = context;\r
+\r
+               return SWITCH_STATUS_SUCCESS;\r
+       }\r
+}\r
+\r
+static switch_status switch_g729_destroy(switch_codec *codec)\r
+{\r
+       codec->private = NULL;\r
+       return SWITCH_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static switch_status switch_g729_encode(switch_codec *codec,\r
+                                                                               switch_codec *other_codec,\r
+                                                                               void *decoded_data,\r
+                                                                               size_t decoded_data_len,\r
+                                                                               int decoded_rate,\r
+                                                                               void *encoded_data,\r
+                                                                               size_t *encoded_data_len,\r
+                                                                               int *encoded_rate,\r
+                                                                               unsigned int *flag)\r
+{\r
+       struct g729_context *context = codec->private;\r
+       int cbret = 0;\r
+\r
+       if (!context) {\r
+               return SWITCH_STATUS_FALSE;\r
+       }\r
+       if (decoded_data_len % 160 == 0) {\r
+               unsigned int new_len = 0;\r
+               INT16 *ddp = decoded_data;\r
+               char *edp = encoded_data;\r
+               int x;\r
+               int loops = (int) decoded_data_len / 160;\r
+\r
+               for(x = 0; x < loops && new_len < *encoded_data_len; x++) {\r
+                       g729_coder(&context->encoder_object, ddp, edp, &cbret);\r
+                       edp += 10;\r
+                       ddp += 80;\r
+                       new_len += 10;\r
+               }\r
+               if( new_len <= *encoded_data_len ) {\r
+                       *encoded_data_len = new_len;\r
+               } else {\r
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "buffer overflow!!! %u >= %u\n", new_len, *encoded_data_len);\r
+                       return SWITCH_STATUS_FALSE;                     \r
+               }\r
+       }\r
+       return SWITCH_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+static switch_status switch_g729_decode(switch_codec *codec,\r
+                                                                               switch_codec *other_codec,\r
+                                                                               void *encoded_data,\r
+                                                                               size_t encoded_data_len,\r
+                                                                               int encoded_rate,\r
+                                                                               void *decoded_data,\r
+                                                                               size_t *decoded_data_len,\r
+                                                                               int *decoded_rate,\r
+                                                                               unsigned int *flag) \r
+{\r
+       struct g729_context *context = codec->private;\r
+\r
+       if (!context) {\r
+               return SWITCH_STATUS_FALSE;\r
+       }\r
+\r
+\r
+       if (encoded_data_len % 10 == 0) {\r
+               int loops = (int) encoded_data_len / 10;\r
+               char *edp = encoded_data;\r
+               short *ddp = decoded_data;\r
+               int x;\r
+               unsigned int new_len = 0;\r
+               for(x = 0; x < loops && new_len < *decoded_data_len; x++) {\r
+                       g729_decoder(&context->decoder_object, ddp, edp, 10);\r
+                       ddp += 80;\r
+                       edp += 10;\r
+                       new_len += 160;\r
+               }\r
+               if (new_len <= *decoded_data_len) {\r
+                       *decoded_data_len = new_len;\r
+               } else {\r
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "buffer overflow!!!\n");\r
+                       return SWITCH_STATUS_FALSE;\r
+               }\r
+       } else {\r
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "yo this frame is an odd size [%d]\n", encoded_data_len);\r
+       }\r
+\r
+\r
+       return SWITCH_STATUS_SUCCESS;\r
+}\r
+\r
+/* Registration */\r
+\r
+static const switch_codec_implementation g729_8k_implementation = {\r
+       /*.samples_per_second*/                         8000,\r
+       /*.bits_per_second*/                            64000,\r
+       /*.microseconds_per_frame*/                     20000,\r
+       /*.samples_per_frame*/                          160,\r
+       /*.bytes_per_frame*/                            320,\r
+       /*.encoded_bytes_per_frame*/            20,\r
+       /*.number_of_channels*/                         1,\r
+       /*.pref_frames_per_packet*/                     1,\r
+       /*.max_frames_per_packet*/                      24,\r
+       /*.init*/                                                       switch_g729_init,\r
+       /*.encode*/                                                     switch_g729_encode,\r
+       /*.decode*/                                                     switch_g729_decode,\r
+       /*.destroy*/                                            switch_g729_destroy,\r
+};\r
+\r
+static const switch_codec_interface g729_codec_interface = {\r
+       /*.interface_name*/                                     "g729",\r
+       /*.codec_type*/                                         SWITCH_CODEC_TYPE_AUDIO,\r
+       /*.ianacode*/                                           18,\r
+       /*.iananame*/                                           "G729",\r
+       /*.implementations*/                            &g729_8k_implementation,\r
+};\r
+\r
+static switch_loadable_module_interface g729_module_interface = {\r
+       /*.module_name*/                                        modname,\r
+       /*.endpoint_interface*/                         NULL,\r
+       /*.timer_interface*/                            NULL,\r
+       /*.dialplan_interface*/                         NULL,\r
+       /*.codec_interface*/                            &g729_codec_interface,\r
+       /*.application_interface*/                      NULL\r
+};\r
+\r
+\r
+SWITCH_MOD_DECLARE(switch_status) switch_module_load(const switch_loadable_module_interface **interface, char *filename) {\r
+       /* connect my internal structure to the blank pointer passed to me */\r
+       *interface = &g729_module_interface;\r
+\r
+       /* indicate that the module should continue to be loaded */\r
+       return SWITCH_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+\r
+\r
+\r
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 (file)
index 0000000..9b7ecda
--- /dev/null
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_codec_g729"\r
+       ProjectGUID="{1D95CD95-0DE2-48C3-AC23-D5C7D1C9C0F0}"\r
+       RootNamespace="mod_codec_g729"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_CodecG729 Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libg729.lib FreeSwitchCore.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_codec_g729.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Debug&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729\Debug&quot;;..\..\..\w32\vsnet\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_codec_g729.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_codec_g729.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_CodecG729 Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libg729.lib FreeSwitchCore.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_codec_g729.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\apr\Release&quot;;&quot;$(InputDir)..\..\..\libs\codec\libg729\Release&quot;;..\..\..\w32\vsnet\Release"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_codec_g729.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="mod_codec_g729.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/codec/mod_g711codec/Makefile b/src/mod/codec/mod_g711codec/Makefile
new file mode 100644 (file)
index 0000000..60ab1c4
--- /dev/null
@@ -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 (file)
index 0000000..b69eb4f
--- /dev/null
@@ -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 (file)
index 0000000..015c232
--- /dev/null
@@ -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 (file)
index 0000000..e1cd6fc
--- /dev/null
@@ -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 (file)
index 0000000..2d79448
--- /dev/null
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_g711codec"\r
+       ProjectGUID="{B1FE4613-3F4B-4DAF-9714-2472BF8F56AE}"\r
+       RootNamespace="mod_g711codec"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_g711codec.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_g711codec.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_g711codec.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_g711codec.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_g711codec.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\g711.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\mod_g711codec.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\g711.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/codec/mod_rawaudio/mod_rawaudio.c b/src/mod/codec/mod_rawaudio/mod_rawaudio.c
new file mode 100644 (file)
index 0000000..7dca809
--- /dev/null
@@ -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 (file)
index 0000000..2fb5317
--- /dev/null
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_rawaudio"\r
+       ProjectGUID="{5844AFE1-AA3E-4BDB-A9EF-119AEF19DF88}"\r
+       RootNamespace="mod_rawaudio"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_rawaudio Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libresample\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libresampled.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_rawaudio.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\libresample\win&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_rawaudio.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_rawaudio.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_rawaudio Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libresample\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libresample.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_rawaudio.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\libresample\win&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_rawaudio.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_rawaudio.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/codec/mod_speexcodec/Makefile b/src/mod/codec/mod_speexcodec/Makefile
new file mode 100644 (file)
index 0000000..396db30
--- /dev/null
@@ -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 (file)
index 0000000..d20d646
--- /dev/null
@@ -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 (file)
index 0000000..0abb26a
--- /dev/null
@@ -0,0 +1,211 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_speexcodec"\r
+       ProjectGUID="{5580D60E-0F77-4716-9CD4-B8E5986FA375}"\r
+       RootNamespace="mod_speexcodec"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_SpeexCodec Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libspeex.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_speexcodec.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\speex\win32\libspeex\Debug&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_speexcodec.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_speexcodec.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_SpeexCodec Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libspeex.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_speexcodec.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\speex\win32\libspeex\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_speexcodec.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_speexcodec.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
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 (file)
index 0000000..c071f61
--- /dev/null
@@ -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 (file)
index 0000000..ecf5b98
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_dialplan_demo"\r
+       ProjectGUID="{2988EB83-785F-45D4-8731-8E1E4345177E}"\r
+       RootNamespace="mod_dialplan_demo"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_dialplan_demo.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_dialplan_demo.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_dialplan_demo.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_dialplan_demo.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_dialplan_demo.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_dialplan_demo.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/endpoints/mod_exosip/Makefile b/src/mod/endpoints/mod_exosip/Makefile
new file mode 100644 (file)
index 0000000..5e89063
--- /dev/null
@@ -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 (file)
index 0000000..972797c
--- /dev/null
@@ -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 (file)
index 0000000..014a0e5
--- /dev/null
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_exosip"\r
+       ProjectGUID="{45DF84ED-D24A-4FF6-B5B0-0A9A5FDB9552}"\r
+       RootNamespace="mod_exosip"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_Exosip Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalOptions="/D _CRT_SECURE_NO_DEPRECATE"\r
+                               Optimization="0"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               GeneratePreprocessedFile="0"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NODEFAULTLIB:LIBCMT"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libcpmt.lib eXosip.lib jrtplib.lib jthread.lib osipparser2.lib osip2.lib"\r
+                               ShowProgress="0"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_exosip.dll"\r
+                               LinkIncremental="2"\r
+                               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;"\r
+                               IgnoreAllDefaultLibraries="false"\r
+                               IgnoreDefaultLibraryNames=""\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_exosip.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_exosip.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_Exosip Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libcpmt.lib eXosip.lib jrtplib.lib jthread.lib osipparser2.lib osip2.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_exosip.dll"\r
+                               LinkIncremental="1"\r
+                               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;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_exosip.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\libs\jrtp4c\src\jrtp4c.cpp"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\mod_exosip.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath="..\..\..\libs\osip\src\osipparser2\osip_rfc3264.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath="..\..\..\libs\osip\src\osipparser2\osip_rfc3264i.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
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 (file)
index 0000000..4d895ca
--- /dev/null
@@ -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 (file)
index 0000000..54c3b03
--- /dev/null
@@ -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 (file)
index 0000000..6e4f382
--- /dev/null
@@ -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 (file)
index 0000000..3b0a8f4
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_IaxChan"\r
+       ProjectGUID="{3A5B9131-F20C-4A85-9447-6C1610941CEE}"\r
+       RootNamespace="mod_IaxChan"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_IaxChan Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iax\src&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libiax2.lib Winmm.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_IaxChan.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\iax\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_IaxChan.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_IaxChan.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_IaxChan Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iax\src&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib libiax2.lib Winmm.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_IaxChan.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\iax\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               ImportLibrary="$(OutDir)/mod_IaxChan.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_iaxchan.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/endpoints/mod_iaxchan/mod_iaxchan.c b/src/mod/endpoints/mod_iaxchan/mod_iaxchan.c
new file mode 100644 (file)
index 0000000..b3faf65
--- /dev/null
@@ -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 (file)
index 0000000..709a5b7
--- /dev/null
@@ -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 (file)
index 0000000..8aae7ec
--- /dev/null
@@ -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 (file)
index 0000000..0d78e0b
--- /dev/null
@@ -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 (file)
index 0000000..5afdc33
--- /dev/null
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_PortAudio"\r
+       ProjectGUID="{5FD31A25-5D83-4794-8BEE-904DAD84CE71}"\r
+       RootNamespace="mod_PortAudio"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_PortAudio Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalOptions="/NODEFAULTLIB:LIMBCTD"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib  PAStaticWMMED.lib Winmm.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_PortAudio.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\portaudio\winvc\Lib&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_PortAudio.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_PortAudio.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_PortAudio Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               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;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="Ws2_32.lib Iphlpapi.lib  PAStaticWMME.lib Winmm.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_PortAudio.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\..\libs\portaudio\winvc\Lib&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_PortAudio.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_PortAudio.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\pablio.c"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ringbuffer.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\pablio.h"\r
+                               >\r
+                       </File>\r
+                       <File\r
+                               RelativePath=".\ringbuffer.h"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/endpoints/mod_portaudio/mod_portaudio.c b/src/mod/endpoints/mod_portaudio/mod_portaudio.c
new file mode 100644 (file)
index 0000000..51e7ec2
--- /dev/null
@@ -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 (file)
index 0000000..b5735da
--- /dev/null
@@ -0,0 +1,327 @@
+/*\r
+ * $Id: pablio.c,v 1.1.1.1.4.4 2003/03/13 17:28:33 philburk Exp $\r
+ * pablio.c\r
+ * Portable Audio Blocking Input/Output utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+\r
+/* History:\r
+ * PLB021214 - check for valid stream in CloseAudioStream() to prevent hang.\r
+ *             add timeOutMSec to CloseAudioStream() to prevent hang.\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include "pablio.h"\r
+#include <string.h>\r
+\r
+/************************************************************************/\r
+/******** Constants *****************************************************/\r
+/************************************************************************/\r
+\r
+#define FRAMES_PER_BUFFER    (256)\r
+\r
+/************************************************************************/\r
+/******** Prototypes ****************************************************/\r
+/************************************************************************/\r
+\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+                               unsigned long framesPerBuffer,\r
+                               PaTimestamp outTime, void *userData );\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame );\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf );\r
+\r
+/************************************************************************/\r
+/******** Functions *****************************************************/\r
+/************************************************************************/\r
+\r
+/* Called from PortAudio.\r
+ * Read and write data only if there is room in FIFOs.\r
+ */\r
+static int blockingIOCallback( void *inputBuffer, void *outputBuffer,\r
+                               unsigned long framesPerBuffer,\r
+                               PaTimestamp outTime, void *userData )\r
+{\r
+    PABLIO_Stream *data = (PABLIO_Stream*)userData;\r
+    long numBytes = data->bytesPerFrame * framesPerBuffer;\r
+    (void) outTime;\r
+\r
+    /* This may get called with NULL inputBuffer during initial setup. */\r
+    if( inputBuffer != NULL )\r
+    {\r
+        RingBuffer_Write( &data->inFIFO, inputBuffer, numBytes );\r
+    }\r
+    if( outputBuffer != NULL )\r
+    {\r
+        int i;\r
+        int numRead = RingBuffer_Read( &data->outFIFO, outputBuffer, numBytes );\r
+        /* Zero out remainder of buffer if we run out of data. */\r
+        for( i=numRead; i<numBytes; i++ )\r
+        {\r
+            ((char *)outputBuffer)[i] = 0;\r
+        }\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+/* Allocate buffer. */\r
+static PaError PABLIO_InitFIFO( RingBuffer *rbuf, long numFrames, long bytesPerFrame )\r
+{\r
+    long numBytes = numFrames * bytesPerFrame;\r
+    char *buffer = (char *) malloc( numBytes );\r
+    if( buffer == NULL ) return paInsufficientMemory;\r
+    memset( buffer, 0, numBytes );\r
+    return (PaError) RingBuffer_Init( rbuf, numBytes, buffer );\r
+}\r
+\r
+/* Free buffer. */\r
+static PaError PABLIO_TermFIFO( RingBuffer *rbuf )\r
+{\r
+    if( rbuf->buffer ) free( rbuf->buffer );\r
+    rbuf->buffer = NULL;\r
+    return paNoError;\r
+}\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+    long bytesWritten;\r
+    char *p = (char *) data;\r
+    long numBytes = aStream->bytesPerFrame * numFrames;\r
+    while( numBytes > 0)\r
+    {\r
+        bytesWritten = RingBuffer_Write( &aStream->outFIFO, p, numBytes );\r
+        numBytes -= bytesWritten;\r
+        p += bytesWritten;\r
+        if( numBytes > 0) Pa_Sleep(10);\r
+    }\r
+    return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames )\r
+{\r
+    long bytesRead;\r
+    char *p = (char *) data;\r
+    long numBytes = aStream->bytesPerFrame * numFrames;\r
+    while( numBytes > 0)\r
+    {\r
+        bytesRead = RingBuffer_Read( &aStream->inFIFO, p, numBytes );\r
+        numBytes -= bytesRead;\r
+        p += bytesRead;\r
+        if( numBytes > 0) Pa_Sleep(10);\r
+    }\r
+    return numFrames;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream )\r
+{\r
+    int bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+    return bytesEmpty / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream )\r
+{\r
+    int bytesFull = RingBuffer_GetReadAvailable( &aStream->inFIFO );\r
+    return bytesFull / aStream->bytesPerFrame;\r
+}\r
+\r
+/************************************************************/\r
+static unsigned long RoundUpToNextPowerOf2( unsigned long n )\r
+{\r
+    long numBits = 0;\r
+    if( ((n-1) & n) == 0) return n; /* Already Power of two. */\r
+    while( n > 0 )\r
+    {\r
+        n= n>>1;\r
+        numBits++;\r
+    }\r
+    return (1<<numBits);\r
+}\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ *    and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **rwblPtr, double sampleRate,\r
+                         PaSampleFormat format, long flags, int indev, int outdev )\r
+{\r
+    long   bytesPerSample;\r
+    long   doRead = 0;\r
+    long   doWrite = 0;\r
+    PaError err;\r
+    PABLIO_Stream *aStream;\r
+    long   minNumBuffers;\r
+    long   numFrames;\r
+\r
+    /* Allocate PABLIO_Stream structure for caller. */\r
+    aStream = (PABLIO_Stream *) malloc( sizeof(PABLIO_Stream) );\r
+    if( aStream == NULL ) return paInsufficientMemory;\r
+    memset( aStream, 0, sizeof(PABLIO_Stream) );\r
+\r
+    /* Determine size of a sample. */\r
+    bytesPerSample = Pa_GetSampleSize( format );\r
+    if( bytesPerSample < 0 )\r
+    {\r
+        err = (PaError) bytesPerSample;\r
+        goto error;\r
+    }\r
+    aStream->samplesPerFrame = ((flags&PABLIO_MONO) != 0) ? 1 : 2;\r
+    aStream->bytesPerFrame = bytesPerSample * aStream->samplesPerFrame;\r
+\r
+    /* Initialize PortAudio  */\r
+    err = Pa_Initialize();\r
+    if( err != paNoError ) goto error;\r
+\r
+    /* Warning: numFrames must be larger than amount of data processed per interrupt\r
+     *    inside PA to prevent glitches. Just to be safe, adjust size upwards.\r
+     */\r
+    minNumBuffers = 2 * Pa_GetMinNumBuffers( FRAMES_PER_BUFFER, sampleRate );\r
+    numFrames = minNumBuffers * FRAMES_PER_BUFFER;\r
+    /* The PortAudio callback runs in a high priority thread. But PABLIO\r
+     * runs in a normal foreground thread. So we may have much worse\r
+     * latency in PABLIO. So adjust latency to a safe level.\r
+     */\r
+    {\r
+        const int safeLatencyMSec = 200;\r
+        int minLatencyMSec = (int) ((1000 * numFrames) / sampleRate);\r
+        if( minLatencyMSec < safeLatencyMSec )\r
+        {\r
+            numFrames = (int) ((safeLatencyMSec * sampleRate) / 1000);\r
+        }\r
+    }\r
+    numFrames = RoundUpToNextPowerOf2( numFrames );\r
+\r
+    /* Initialize Ring Buffers */\r
+    doRead = ((flags & PABLIO_READ) != 0);\r
+    doWrite = ((flags & PABLIO_WRITE) != 0);\r
+    if(doRead)\r
+    {\r
+        err = PABLIO_InitFIFO( &aStream->inFIFO, numFrames, aStream->bytesPerFrame );\r
+        if( err != paNoError ) goto error;\r
+    }\r
+    if(doWrite)\r
+    {\r
+        long numBytes;\r
+        err = PABLIO_InitFIFO( &aStream->outFIFO, numFrames, aStream->bytesPerFrame );\r
+        if( err != paNoError ) goto error;\r
+        /* Make Write FIFO appear full initially. */\r
+        numBytes = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+        RingBuffer_AdvanceWriteIndex( &aStream->outFIFO, numBytes );\r
+    }\r
+\r
+    /* Open a PortAudio stream that we will use to communicate with the underlying\r
+     * audio drivers. */\r
+    err = Pa_OpenStream(\r
+              &aStream->stream,\r
+                         (doRead ? (indev > -1) ? indev : Pa_GetDefaultInputDeviceID() : paNoDevice),\r
+              (doRead ? aStream->samplesPerFrame : 0 ),\r
+              format,\r
+              NULL,\r
+                         (doWrite ? (outdev > -1) ? outdev : Pa_GetDefaultOutputDeviceID() : paNoDevice),\r
+              (doWrite ? aStream->samplesPerFrame : 0 ),\r
+              format,\r
+              NULL,\r
+              sampleRate,\r
+              FRAMES_PER_BUFFER,\r
+              minNumBuffers,\r
+              paClipOff,       /* we won't output out of range samples so don't bother clipping them */\r
+              blockingIOCallback,\r
+              aStream );\r
+    if( err != paNoError ) goto error;\r
+\r
+    err = Pa_StartStream( aStream->stream );\r
+    if( err != paNoError ) goto error;\r
+\r
+    *rwblPtr = aStream;\r
+    return paNoError;\r
+\r
+error:\r
+    CloseAudioStream( aStream );\r
+    *rwblPtr = NULL;\r
+    return err;\r
+}\r
+\r
+/************************************************************/\r
+PaError CloseAudioStream( PABLIO_Stream *aStream )\r
+{\r
+    PaError err = paNoError;\r
+    int bytesEmpty;\r
+    int byteSize = aStream->outFIFO.bufferSize;\r
+\r
+    if( aStream->stream != NULL ) /* Make sure stream was opened. PLB021214 */\r
+    {\r
+        /* If we are writing data, make sure we play everything written. */\r
+        if( byteSize > 0 )\r
+        {\r
+            int timeOutMSec = 2000;\r
+            bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+            while( (bytesEmpty < byteSize) && (timeOutMSec > 0) )\r
+            {\r
+                Pa_Sleep( 20 );\r
+                timeOutMSec -= 20;\r
+                bytesEmpty = RingBuffer_GetWriteAvailable( &aStream->outFIFO );\r
+            }\r
+        }\r
+        err = Pa_StopStream( aStream->stream );\r
+        if( err != paNoError ) goto error;\r
+        err = Pa_CloseStream( aStream->stream );\r
+    }\r
+\r
+error:\r
+    Pa_Terminate();\r
+    PABLIO_TermFIFO( &aStream->inFIFO );\r
+    PABLIO_TermFIFO( &aStream->outFIFO );\r
+    free( aStream );\r
+    return err;\r
+}\r
diff --git a/src/mod/endpoints/mod_portaudio/pablio.h b/src/mod/endpoints/mod_portaudio/pablio.h
new file mode 100644 (file)
index 0000000..25bccf8
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef _PABLIO_H\r
+#define _PABLIO_H\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: pablio.h,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * PABLIO.h\r
+ * Portable Audio Blocking read/write utility.\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/\r
+ *\r
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.\r
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "portaudio.h"\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+    RingBuffer   inFIFO;\r
+    RingBuffer   outFIFO;\r
+    PortAudioStream *stream;\r
+    int          bytesPerFrame;\r
+    int          samplesPerFrame;\r
+}\r
+PABLIO_Stream;\r
+\r
+/* Values for flags for OpenAudioStream(). */\r
+#define PABLIO_READ     (1<<0)\r
+#define PABLIO_WRITE    (1<<1)\r
+#define PABLIO_READ_WRITE    (PABLIO_READ|PABLIO_WRITE)\r
+#define PABLIO_MONO     (1<<2)\r
+#define PABLIO_STEREO   (1<<3)\r
+\r
+/************************************************************\r
+ * Write data to ring buffer.\r
+ * Will not return until all the data has been written.\r
+ */\r
+long WriteAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Read data from ring buffer.\r
+ * Will not return until all the data has been read.\r
+ */\r
+long ReadAudioStream( PABLIO_Stream *aStream, void *data, long numFrames );\r
+\r
+/************************************************************\r
+ * Return the number of frames that could be written to the stream without\r
+ * having to wait.\r
+ */\r
+long GetAudioStreamWriteable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Return the number of frames that are available to be read from the\r
+ * stream without having to wait.\r
+ */\r
+long GetAudioStreamReadable( PABLIO_Stream *aStream );\r
+\r
+/************************************************************\r
+ * Opens a PortAudio stream with default characteristics.\r
+ * Allocates PABLIO_Stream structure.\r
+ *\r
+ * flags parameter can be an ORed combination of:\r
+ *    PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,\r
+ *    and either PABLIO_MONO or PABLIO_STEREO\r
+ */\r
+PaError OpenAudioStream( PABLIO_Stream **aStreamPtr, double sampleRate,\r
+                         PaSampleFormat format, long flags, int indev, int outdev );\r
+\r
+PaError CloseAudioStream( PABLIO_Stream *aStream );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _PABLIO_H */\r
diff --git a/src/mod/endpoints/mod_portaudio/ringbuffer.c b/src/mod/endpoints/mod_portaudio/ringbuffer.c
new file mode 100644 (file)
index 0000000..867b501
--- /dev/null
@@ -0,0 +1,199 @@
+/*\r
+ * $Id: ringbuffer.c,v 1.1.1.1 2002/01/22 00:52:53 phil Exp $\r
+ * ringbuffer.c\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program uses the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+/***************************************************************************\r
+ * Initialize FIFO.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr )\r
+{\r
+    if( ((numBytes-1) & numBytes) != 0) return -1; /* Not Power of two. */\r
+    rbuf->bufferSize = numBytes;\r
+    rbuf->buffer = (char *)dataPtr;\r
+    RingBuffer_Flush( rbuf );\r
+    rbuf->bigMask = (numBytes*2)-1;\r
+    rbuf->smallMask = (numBytes)-1;\r
+    return 0;\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for reading. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf )\r
+{\r
+    return ( (rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask );\r
+}\r
+/***************************************************************************\r
+** Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf )\r
+{\r
+    return ( rbuf->bufferSize - RingBuffer_GetReadAvailable(rbuf));\r
+}\r
+\r
+/***************************************************************************\r
+** Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf )\r
+{\r
+    rbuf->writeIndex = rbuf->readIndex = 0;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+                                 void **dataPtr1, long *sizePtr1,\r
+                                 void **dataPtr2, long *sizePtr2 )\r
+{\r
+    long   index;\r
+    long   available = RingBuffer_GetWriteAvailable( rbuf );\r
+    if( numBytes > available ) numBytes = available;\r
+    /* Check to see if write is not contiguous. */\r
+    index = rbuf->writeIndex & rbuf->smallMask;\r
+    if( (index + numBytes) > rbuf->bufferSize )\r
+    {\r
+        /* Write data in two blocks that wrap the buffer. */\r
+        long   firstHalf = rbuf->bufferSize - index;\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = firstHalf;\r
+        *dataPtr2 = &rbuf->buffer[0];\r
+        *sizePtr2 = numBytes - firstHalf;\r
+    }\r
+    else\r
+    {\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = numBytes;\r
+        *dataPtr2 = NULL;\r
+        *sizePtr2 = 0;\r
+    }\r
+    return numBytes;\r
+}\r
+\r
+\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+    return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+                                void **dataPtr1, long *sizePtr1,\r
+                                void **dataPtr2, long *sizePtr2 )\r
+{\r
+    long   index;\r
+    long   available = RingBuffer_GetReadAvailable( rbuf );\r
+    if( numBytes > available ) numBytes = available;\r
+    /* Check to see if read is not contiguous. */\r
+    index = rbuf->readIndex & rbuf->smallMask;\r
+    if( (index + numBytes) > rbuf->bufferSize )\r
+    {\r
+        /* Write data in two blocks that wrap the buffer. */\r
+        long firstHalf = rbuf->bufferSize - index;\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = firstHalf;\r
+        *dataPtr2 = &rbuf->buffer[0];\r
+        *sizePtr2 = numBytes - firstHalf;\r
+    }\r
+    else\r
+    {\r
+        *dataPtr1 = &rbuf->buffer[index];\r
+        *sizePtr1 = numBytes;\r
+        *dataPtr2 = NULL;\r
+        *sizePtr2 = 0;\r
+    }\r
+    return numBytes;\r
+}\r
+/***************************************************************************\r
+*/\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes )\r
+{\r
+    return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+    long size1, size2, numWritten;\r
+    void *data1, *data2;\r
+    numWritten = RingBuffer_GetWriteRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+    if( size2 > 0 )\r
+    {\r
+\r
+        memcpy( data1, data, size1 );\r
+        data = ((char *)data) + size1;\r
+        memcpy( data2, data, size2 );\r
+    }\r
+    else\r
+    {\r
+        memcpy( data1, data, size1 );\r
+    }\r
+    RingBuffer_AdvanceWriteIndex( rbuf, numWritten );\r
+    return numWritten;\r
+}\r
+\r
+/***************************************************************************\r
+** Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes )\r
+{\r
+    long size1, size2, numRead;\r
+    void *data1, *data2;\r
+    numRead = RingBuffer_GetReadRegions( rbuf, numBytes, &data1, &size1, &data2, &size2 );\r
+    if( size2 > 0 )\r
+    {\r
+        memcpy( data, data1, size1 );\r
+        data = ((char *)data) + size1;\r
+        memcpy( data, data2, size2 );\r
+    }\r
+    else\r
+    {\r
+        memcpy( data, data1, size1 );\r
+    }\r
+    RingBuffer_AdvanceReadIndex( rbuf, numRead );\r
+    return numRead;\r
+}\r
diff --git a/src/mod/endpoints/mod_portaudio/ringbuffer.h b/src/mod/endpoints/mod_portaudio/ringbuffer.h
new file mode 100644 (file)
index 0000000..3cd5594
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef _RINGBUFFER_H\r
+#define _RINGBUFFER_H\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif /* __cplusplus */\r
+\r
+/*\r
+ * $Id: ringbuffer.h,v 1.1.1.1.4.2 2003/04/28 17:45:34 philburk Exp $\r
+ * ringbuffer.h\r
+ * Ring Buffer utility..\r
+ *\r
+ * Author: Phil Burk, http://www.softsynth.com\r
+ *\r
+ * This program is distributed with the PortAudio Portable Audio Library.\r
+ * For more information see: http://www.audiomulch.com/portaudio/\r
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk\r
+ *\r
+ * Permission is hereby granted, free of charge, to any person obtaining\r
+ * a copy of this software and associated documentation files\r
+ * (the "Software"), to deal in the Software without restriction,\r
+ * including without limitation the rights to use, copy, modify, merge,\r
+ * publish, distribute, sublicense, and/or sell copies of the Software,\r
+ * and to permit persons to whom the Software is furnished to do so,\r
+ * subject to the following conditions:\r
+ *\r
+ * The above copyright notice and this permission notice shall be\r
+ * included in all copies or substantial portions of the Software.\r
+ *\r
+ * Any person wishing to distribute modifications to the Software is\r
+ * requested to send the modifications to the original developer so that\r
+ * they can be incorporated into the canonical version.\r
+ *\r
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR\r
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF\r
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
+ *\r
+ */\r
+#define PortAudioStream PaStream\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <math.h>\r
+#include "ringbuffer.h"\r
+#include <string.h>\r
+\r
+typedef struct\r
+{\r
+    long   bufferSize; /* Number of bytes in FIFO. Power of 2. Set by RingBuffer_Init. */\r
+/* These are declared volatile because they are written by a different thread than the reader. */\r
+    volatile long   writeIndex; /* Index of next writable byte. Set by RingBuffer_AdvanceWriteIndex. */\r
+    volatile long   readIndex;  /* Index of next readable byte. Set by RingBuffer_AdvanceReadIndex. */\r
+    long   bigMask;    /* Used for wrapping indices with extra bit to distinguish full/empty. */\r
+    long   smallMask;  /* Used for fitting indices to buffer. */\r
+    char *buffer;\r
+}\r
+RingBuffer;\r
+/*\r
+ * Initialize Ring Buffer.\r
+ * numBytes must be power of 2, returns -1 if not.\r
+ */\r
+long RingBuffer_Init( RingBuffer *rbuf, long numBytes, void *dataPtr );\r
+\r
+/* Clear buffer. Should only be called when buffer is NOT being read. */\r
+void RingBuffer_Flush( RingBuffer *rbuf );\r
+\r
+/* Return number of bytes available for writing. */\r
+long RingBuffer_GetWriteAvailable( RingBuffer *rbuf );\r
+/* Return number of bytes available for read. */\r
+long RingBuffer_GetReadAvailable( RingBuffer *rbuf );\r
+/* Return bytes written. */\r
+long RingBuffer_Write( RingBuffer *rbuf, void *data, long numBytes );\r
+/* Return bytes read. */\r
+long RingBuffer_Read( RingBuffer *rbuf, void *data, long numBytes );\r
+\r
+/* Get address of region(s) to which we can write data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be written or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetWriteRegions( RingBuffer *rbuf, long numBytes,\r
+                                 void **dataPtr1, long *sizePtr1,\r
+                                 void **dataPtr2, long *sizePtr2 );\r
+long RingBuffer_AdvanceWriteIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+/* Get address of region(s) from which we can read data.\r
+** If the region is contiguous, size2 will be zero.\r
+** If non-contiguous, size2 will be the size of second region.\r
+** Returns room available to be read or numBytes, whichever is smaller.\r
+*/\r
+long RingBuffer_GetReadRegions( RingBuffer *rbuf, long numBytes,\r
+                                void **dataPtr1, long *sizePtr1,\r
+                                void **dataPtr2, long *sizePtr2 );\r
+\r
+long RingBuffer_AdvanceReadIndex( RingBuffer *rbuf, long numBytes );\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif /* __cplusplus */\r
+#endif /* _RINGBUFFER_H */\r
diff --git a/src/mod/endpoints/mod_wanchan/mod_wanchan.c b/src/mod/endpoints/mod_wanchan/mod_wanchan.c
new file mode 100644 (file)
index 0000000..3fd8080
--- /dev/null
@@ -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 (file)
index 0000000..9ecbf59
--- /dev/null
@@ -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 (file)
index 0000000..2d89ed1
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_woomerachan"\r
+       ProjectGUID="{FE3540C5-3303-46E0-A69E-D92F775687F1}"\r
+       RootNamespace="mod_woomerachan"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_woomerachan.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_woomerachan.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_woomerachan.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_woomerachan.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_woomerachan.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_woomerachan.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
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 (file)
index 0000000..58c406c
--- /dev/null
@@ -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 (file)
index 0000000..6952239
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_event_test"\r
+       ProjectGUID="{3A2A7795-C216-4FFF-B8EF-4D17A84BACCC}"\r
+       RootNamespace="mod_event_test"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_event_test.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_event_test.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_event_test.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_event_test.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/event_handlers/mod_xmpp_event/Makefile b/src/mod/event_handlers/mod_xmpp_event/Makefile
new file mode 100644 (file)
index 0000000..e99f965
--- /dev/null
@@ -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 (file)
index 0000000..6f98372
--- /dev/null
@@ -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 (file)
index 0000000..fa9167b
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_xmpp_event"\r
+       ProjectGUID="{F10BE67C-A8FF-4CB2-AF29-D46D2590DC59}"\r
+       RootNamespace="mod_xmpp_event"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_XMPPEvent Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iksemel\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="FreeSwitchCore.lib iksemel.lib Ws2_32.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_xmpp_event.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="..\..\..\w32\vsnet\Debug;..\..\..\libs\iksemel\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_xmpp_event.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_xmpp_event.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_XMPPEvent Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\iksemel\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="FreeSwitchCore.lib iksemel.lib Ws2_32.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_xmpp_event.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="..\..\..\w32\vsnet\Release;..\..\..\libs\iksemel\Release"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               ImportLibrary="$(OutDir)/mod_xmpp_event.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath="mod_xmpp_event.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/formats/mod_sndfile/Makefile b/src/mod/formats/mod_sndfile/Makefile
new file mode 100644 (file)
index 0000000..1056e8f
--- /dev/null
@@ -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 (file)
index 0000000..98a4f7d
--- /dev/null
@@ -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 (file)
index 0000000..79db6ae
--- /dev/null
@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_sndfile"\r
+       ProjectGUID="{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6}"\r
+       RootNamespace="mod_sndfile"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_sndfile Debug"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libsndfile\Win32&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="3"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libsndfile.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_sndfile.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\libsndfile\Win32\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_sndfile.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_sndfile.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                               CommandLine="cscript /nologo $(InputDir)..\..\..\w32\vsnet\getlibs.vbs Mod_sndfile Release"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;;&quot;$(InputDir)..\..\..\libs\libsndfile\Win32&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="2"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               AdditionalDependencies="libsndfile.lib"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_sndfile.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\..\libs\libsndfile\Win32\Release"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               LinkTimeCodeGeneration="1"\r
+                               ImportLibrary="$(OutDir)/mod_sndfile.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_sndfile.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r
diff --git a/src/mod/timers/mod_softtimer/mod_softtimer.c b/src/mod/timers/mod_softtimer/mod_softtimer.c
new file mode 100644 (file)
index 0000000..c379436
--- /dev/null
@@ -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 (file)
index 0000000..b268d2f
--- /dev/null
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="8.00"\r
+       Name="mod_softtimer"\r
+       ProjectGUID="{DCC13474-28DF-47CA-A8EB-72F8CE9A78C5}"\r
+       RootNamespace="mod_softtimer"\r
+       Keyword="Win32Proj"\r
+       >\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"\r
+               />\r
+       </Platforms>\r
+       <ToolFiles>\r
+       </ToolFiles>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               MinimalRebuild="true"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="1"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="4"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_softtimer.dll"\r
+                               LinkIncremental="2"\r
+                               AdditionalLibraryDirectories="$(InputDir)..\..\libs\apr\Debug"\r
+                               GenerateDebugInformation="true"\r
+                               ProgramDatabaseFile="$(OutDir)/mod_softtimer.pdb"\r
+                               SubSystem="2"\r
+                               ImportLibrary="$(OutDir)/mod_softtimer.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="2"\r
+                       InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"\r
+                       CharacterSet="2"\r
+                       >\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCMIDLTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               AdditionalIncludeDirectories="&quot;$(InputDir)..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\libs\include&quot;"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"\r
+                               RuntimeLibrary="0"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="true"\r
+                               DebugInformationFormat="3"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManagedResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="..\..\..\w32\vsnet\$(OutDir)/mod/mod_softtimer.dll"\r
+                               LinkIncremental="1"\r
+                               AdditionalLibraryDirectories="&quot;$(InputDir)..\..\libs\apr\Release&quot;"\r
+                               GenerateDebugInformation="true"\r
+                               SubSystem="2"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               ImportLibrary="$(OutDir)/mod_softtimer.lib"\r
+                               TargetMachine="1"\r
+                       />\r
+                       <Tool\r
+                               Name="VCALinkTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCManifestTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCXDCMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCBscMakeTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCFxCopTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCAppVerifierTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"\r
+                       />\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"\r
+                       />\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"\r
+                       >\r
+                       <File\r
+                               RelativePath=".\mod_softtimer.c"\r
+                               >\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"\r
+                       >\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"\r
+                       >\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r