<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][15223] </title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=15223">15223</a></dd>
<dt>Author</dt> <dd>bottleman</dd>
<dt>Date</dt> <dd>2009-10-23 20:48:45 -0500 (Fri, 23 Oct 2009)</dd>
</dl>
<h3>Log Message</h3>
<pre>initial commit</pre>
<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323Makefile">freeswitch/trunk/src/mod/endpoints/mod_h323/Makefile</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323bugs">freeswitch/trunk/src/mod/endpoints/mod_h323/bugs</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323changestxt">freeswitch/trunk/src/mod/endpoints/mod_h323/changes.txt</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323h323confxml">freeswitch/trunk/src/mod/endpoints/mod_h323/h323.conf.xml</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323mod_h323cpp">freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.cpp</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_h323mod_h323h">freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunksrcmodendpointsmod_h323Makefile"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/Makefile (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/Makefile         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/Makefile        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+BASE=../../../..
+LOCAL_CFLAGS+=-g -I/usr/include/ptlib -I/usr/local/src/h323plus/include -I. -DPTRACING=1 -D_REENTRANT -fno-exceptions
+LOCAL_LDFLAGS= -L/usr/local/src/h323plus/lib -lh323_linux_x86_ -lpt -lrt
+
+include $(BASE)/build/modmake.rules
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_h323bugs"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/bugs (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/bugs         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/bugs        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+faststart and codecs v CallProceeding due to h323plus, grep "Very Frustrating - S.H." in h323plus
+source and uncomment commented lines.
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_h323changestxt"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/changes.txt (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/changes.txt         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/changes.txt        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+
+fix misstype in codec conversion.
+fix rtp issue causes choppy sound.
+fix progress ind handling on outbound calls.
+fix crash on log line, btw not understand why.
+implement dtmf transfer.
+fix codec name conversion a bit.
+fix crash on inbound fast start connection.
+
+initial release.
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_h323h323confxml"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/h323.conf.xml (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/h323.conf.xml         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/h323.conf.xml        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+<configuration name="h323.conf" description="H323 Endpoints">
+ <settings>
+ <param name="trace-level" value="10"/>
+ <param name="context" value="default"/>
+ <param name="dialplan" value="XML"/>
+ <param name="codec-prefs" value="PCMA,GSM,G729,G726"/>
+ <param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
+ <param name="gk-identifer" value=""/> <!-- optional name of gk -->
+ <param name="gk-interface" value=""/> <!-- optional listener interface name -->
+ </settings>
+ <listeners>
+ <listener name="default">
+ <param name="h323-ip" value="$${local_ip_v4}"/>
+ <param name="h323-port" value="1720"/>
+ </listener>
+ </listeners>
+</configuration>
+
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_h323mod_h323cpp"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.cpp (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.cpp         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.cpp        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,1485 @@
</span><ins>+
+
+#include "mod_h323.h"
+
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, mod_h323_globals.codec_string);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, mod_h323_globals.context);
+SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, mod_h323_globals.dialplan);
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_h323_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_h323_shutdown);
+SWITCH_MODULE_DEFINITION(mod_h323, mod_h323_load, mod_h323_shutdown, NULL);
+
+#define CF_NEED_FLUSH (1 << 1)
+struct mod_h323_globals mod_h323_globals = { 0 };
+
+static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
+ switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
+ switch_memory_pool_t **pool, switch_originate_flag_t flags);
+
+static const char modulename[] = "h323";
+static const char* h323_formats[] = {
+ "G.711-ALaw-64k", "PCMA",
+ "G.711-uLaw-64k", "PCMU",
+ "GSM-06.10", "GSM",
+ "MS-GSM", "msgsm",
+ "SpeexNarrow", "speex",
+ "LPC-10", "lpc10",
+ "iLBC-15k2", "ilbc20",
+ "iLBC-13k3", "ilbc30",
+ "G.723", "G723",
+ "G.726", "G726",
+ "G.728", "G728",
+ "G.729B", "G729b",
+ "G.729", "G729",
+ "PCM-16", "slin",
+ "G.729A", "G729a",
+ "G.729A/B", "G729ab",
+ "G.723.1", "G723.1",
+ "G.723.1(5.3k)", "G723.1-5k3",
+ "G.723.1A(5.3k)", "G723.1a-5k3",
+ "G.723.1A(6.3k)", "G723.1a-6k3",
+ "G.723.1A(6.3k)-Cisco", "g723.1a-6k3-cisco",
+ "G.726-16k", "G726-16",
+ "G.726-24k", "G726-24",
+ "G.726-32k", "G726-32",
+ "G.726-40k", "G726-40",
+ "iLBC", "ilbc",
+ "SpeexNarrow-18.2k", "speex-18k2",
+ "SpeexNarrow-15k", "speex-15k",
+ "SpeexNarrow-11k", "speex-11k",
+ "SpeexNarrow-8k", "speex-8k",
+ "SpeexNarrow-5.95k", "speex-5k95",
+ 0
+};
+
+static switch_status_t on_hangup(switch_core_session_t *session);
+static switch_status_t on_destroy(switch_core_session_t *session);
+
+
+static switch_io_routines_t h323fs_io_routines = {
+ /*.outgoing_channel */ create_outgoing_channel,
+ /*.read_frame */ FSH323Connection::read_audio_frame,
+ /*.write_frame */ FSH323Connection::write_audio_frame,
+ /*.kill_channel */ FSH323Connection::kill_channel,
+ /*.send_dtmf */ FSH323Connection::send_dtmf,
+ /*.receive_message */ FSH323Connection::receive_message,
+ /*.receive_event */ FSH323Connection::receive_event,
+ /*.state_change */ FSH323Connection::state_change,
+ /*.read_video_frame */ FSH323Connection::read_video_frame,
+ /*.write_video_frame */ FSH323Connection::write_video_frame
+};
+
+static switch_state_handler_table_t h323fs_event_handlers = {
+ /*.on_init */ FSH323Connection::on_init,
+ /*.on_routing */ FSH323Connection::on_routing,
+ /*.on_execute */ FSH323Connection::on_execute,
+ /*.on_hangup */ on_hangup,
+ /*.on_exchange_media */ FSH323Connection::on_exchange_media,
+ /*.on_soft_execute */ FSH323Connection::on_soft_execute,
+ /*.on_consume_media*/ NULL,
+ /*.on_hibernate*/ NULL,
+ /*.on_reset*/ NULL,
+ /*.on_park*/ NULL,
+ /*.on_reporting*/ NULL,
+ /*.on_destroy*/ on_destroy
+};
+
+
+static FSProcess *opal_process = NULL;
+SWITCH_MODULE_LOAD_FUNCTION(mod_h323_load){
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Starting loading mod_h323\n");
+
+
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+                        
+ if (!*module_interface) {
+ return SWITCH_STATUS_MEMERR;
+ }
+
+ h323_process = new FSProcess();
+ if (h323_process == NULL) {
+ return SWITCH_STATUS_MEMERR;
+ }
+
+ if (h323_process->Initialise(*module_interface)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Opal manager initialized and running\n");
+ //unloading causes a seg in linux
+ return SWITCH_STATUS_NOUNLOAD;
+ //return SWITCH_STATUS_SUCCESS;
+ }
+
+ delete h323_process;
+ h323_process = NULL;
+ return SWITCH_STATUS_FALSE;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_h323_shutdown){
+
+ switch_safe_free(mod_h323_globals.context);
+ switch_safe_free(mod_h323_globals.dialplan);
+ switch_safe_free(mod_h323_globals.codec_string);
+ delete h323_process;
+ h323_process = NULL;
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+#if PTRACING
+
+class FSTrace : public ostream {
+ public:
+ FSTrace()
+ : ostream(&buffer)
+ {
+ }
+
+ private:
+ class Buffer : public streambuf {
+ char buffer[250];
+
+ public:
+ Buffer()
+ {
+ setg(buffer, buffer, &buffer[sizeof(buffer)-2]);
+ setp(buffer, &buffer[sizeof(buffer)-2]);
+ }
+
+ virtual int sync()
+ {
+ return overflow(EOF);
+ }
+
+ virtual int underflow()
+ {
+ return EOF;
+ }
+
+ virtual int overflow(int c)
+ {
+ const char *fmt = "%s";
+ char *func = NULL;
+
+ int bufSize = pptr() - pbase();
+
+ if (c != EOF) {
+ *pptr() = (char)c;
+ bufSize++;
+ }
+
+ if (bufSize != 0) {
+ char *bufPtr = pbase();
+ char *bufEndPtr = NULL;
+ setp(bufPtr, epptr());
+ bufPtr[bufSize] = '\0';
+ int line = 0;
+ char *p;
+
+ char *file = NULL;
+ switch_log_level_t level;
+
+
+ switch (strtoul(bufPtr, &file, 10)) {
+ case 1 :
+ level = SWITCH_LOG_INFO;
+ break;
+ default :
+ level = SWITCH_LOG_DEBUG;
+ break;
+ }
+
+ if (file) {
+ while (isspace(*file)) file++;
+
+ if (file && (bufPtr = strchr(file, '(')) && (bufEndPtr = strchr(bufPtr, ')'))) {
+ char *e;
+
+ for(p = bufPtr; p && *p; p++) {
+ if (*p == '\t') {
+ *p = ' ';
+ }
+ }
+
+ *bufPtr++ = '\0';
+ line = atoi(bufPtr);
+ while (bufEndPtr && isspace(*(++bufEndPtr)));
+ bufPtr = bufEndPtr;
+ if (bufPtr && (e = strchr(bufPtr, ' ')) || (e = strchr(bufPtr, '\t'))) {
+ func = bufPtr;
+ bufPtr = e;
+ *bufPtr++ = '\0';
+ }
+ }
+ }
+
+ switch_text_channel_t tchannel = SWITCH_CHANNEL_ID_LOG;
+
+ if (!bufPtr) {
+ bufPtr = pbase();
+ level = SWITCH_LOG_DEBUG;
+ }
+
+ if (bufPtr) {
+ if (end_of(bufPtr) != '\n') {
+ fmt = "%s\n";
+ }
+ if (!(file && func && line)) tchannel = SWITCH_CHANNEL_ID_LOG_CLEAN;
+
+ switch_log_printf(tchannel, file, func, line, NULL, level, fmt, bufPtr);
+ }
+
+ }
+
+ return 0;
+ }
+ } buffer;
+};
+
+#endif
+
+PString GetH245CodecName(const H245_AudioCapability &cap){
+        switch (cap.GetTag()) {
+        case H245_AudioCapability::e_g711Alaw64k:
+        case H245_AudioCapability::e_g711Alaw56k:
+                return "PCMA";
+        case H245_AudioCapability::e_g711Ulaw64k:
+        case H245_AudioCapability::e_g711Ulaw56k:
+                return "PCMU";
+        case H245_AudioCapability::e_g722_64k:
+        case H245_AudioCapability::e_g722_56k:
+        case H245_AudioCapability::e_g722_48k:
+                return "G722";
+        case H245_AudioCapability::e_g728:
+                return "G728";
+        case H245_AudioCapability::e_g729:
+        case H245_AudioCapability::e_g729AnnexA:
+        case H245_AudioCapability::e_g729wAnnexB:
+        case H245_AudioCapability::e_g729AnnexAwAnnexB:
+                return "G729";
+        case H245_AudioCapability::e_g7231:
+        case H245_AudioCapability::e_g7231AnnexCCapability:
+                return "G723";
+        case H245_AudioCapability::e_gsmFullRate:
+        case H245_AudioCapability::e_gsmHalfRate:
+        case H245_AudioCapability::e_gsmEnhancedFullRate:
+                return "GSM";
+        }
+        return "Unknown";
+}
+
+FSProcess::FSProcess()
+ : PLibraryProcess("Test", "mod_h323", 1, 0, AlphaCode, 1)
+ , m_h323endpoint(NULL){
+}
+
+
+FSProcess::~FSProcess(){
+ delete m_h323endpoint;
+}
+
+
+bool FSProcess::Initialise(switch_loadable_module_interface_t *iface){
+        PTRACE(4, "mod_h323\t======>FSProcess::Initialise " << *this);
+        
+ m_h323endpoint = new FSH323EndPoint();
+ return m_h323endpoint != NULL && m_h323endpoint->Initialise(iface);
+}
+
+bool FSH323EndPoint::Initialise(switch_loadable_module_interface_t *iface){
+        PTRACE(4, "mod_h323\t======>FSManager::Initialise " << *this);
+ ReadConfig(false);
+
+ PTrace::SetLevel(mod_h323_globals.trace_level); //just for fun and eyecandy ;)
+ PTrace::SetOptions(PTrace::TraceLevel);
+ PTrace::SetStream(new FSTrace);
+
+ m_freeswitch = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(iface, SWITCH_ENDPOINT_INTERFACE);
+ m_freeswitch->interface_name = modulename;
+ m_freeswitch->io_routines = &h323fs_io_routines;
+ m_freeswitch->state_handler = &h323fs_event_handlers;
+                        
+        PString codec = ((const char *)mod_h323_globals.codec_string);
+        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Config capabilliti %s \n",(const char *)codec);
+        if (!codec.IsEmpty()) {                
+                const char** f = h323_formats;
+                for (; *f; f += 2) {                        
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Find capabilliti %s to %s\n",f[1],(const char *)codec);
+                        if (codec.Find(f[1]) != P_MAX_INDEX) {
+                                PString tmp = f[0];
+                                tmp += "*{sw}";
+                                PINDEX init = GetCapabilities().GetSize();
+                                AddAllCapabilities(0, 0, tmp);
+                                PINDEX num = GetCapabilities().GetSize() - init;
+                                if (!num) {
+                                        // failed to add so pretend we support it in hardware
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H323 failed to add capability '%s' \n",(const char *)tmp);
+                                        tmp = f[0];
+                                        tmp += "*{hw}";
+                                        AddAllCapabilities(0, 0, tmp);
+                                        num = GetCapabilities().GetSize() - init;
+                                }
+                                if (num)                                        
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H.323 added %d capabilities '%s' \n",num,(const char *)tmp);
+                                else
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H323 failed to add capability '%s' \n",(const char *)tmp);
+                                        
+                        }                
+                }
+        }
+
+
+                
+ AddAllUserInputCapabilities(0,1);
+         PTRACE(1, "OpenPhone\tCapability Table:\n" << setprecision(4) << capabilities);
+ if (m_listeners.empty()) {
+ StartListener("");
+ } else {
+ for (std::list < FSListener >::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) {
+ if (!StartListener(it->listenAddress)) {
+ PTRACE(3, "mod_h323\tCannot start listener for " << it->name);
+ }
+ }
+ }
+
+/*
+ OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats();
+ for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) {
+ if (it->GetMediaType() == OpalMediaType::Audio()) {
+ it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), 1);
+ it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), 1);
+ }
+ }
+*/
+
+ if (!m_gkAddress.IsEmpty()) {
+ if (UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface))
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n",
+ (const char *)GetGatekeeper()->GetName());
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Could not start gatekeeper: addr=\"%s\", id=\"%s\", if=\"%s\"\n",
+ (const char *)m_gkAddress,
+ (const char *)m_gkIdentifer,
+ (const char *)m_gkInterface);
+ }
+
+ return TRUE;
+}
+
+switch_status_t FSH323EndPoint::ReadConfig(int reload){
+        PTRACE(4, "mod_h323\t======>FSH323EndPoint::ReadConfig " << *this);
+ const char *cf = "h323.conf";
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+        switch_memory_pool_t *pool = NULL;
+ if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+ return status;
+ }
+
+ set_global_context("default");
+ set_global_dialplan("XML");
+
+ switch_event_t *params = NULL;
+ switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
+ switch_assert(params);
+ switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil(""));
+ switch_xml_t cfg;
+ switch_xml_t xml = switch_xml_open_cfg(cf, &cfg, params);
+ if (xml == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch_xml_t xmlSettings = switch_xml_child(cfg, "settings");
+ if (xmlSettings) {
+ for (switch_xml_t xmlParam = switch_xml_child(xmlSettings, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
+ const char *var = switch_xml_attr_soft(xmlParam, "name");
+ const char *val = switch_xml_attr_soft(xmlParam, "value");
+
+ if (!strcasecmp(var, "trace-level")) {
+ int level = atoi(val);
+ if (level > 0) {
+ mod_h323_globals.trace_level = level;
+ }
+ } else if (!strcasecmp(var, "context")) {
+ set_global_context(val);
+ } else if (!strcasecmp(var, "dialplan")) {
+ set_global_dialplan(val);
+ } else if (!strcasecmp(var, "codec-prefs")) {
+ set_global_codec_string(val);
+ } else if (!strcasecmp(var, "jitter-size")) {
+ char * next;
+ unsigned minJitter = strtoul(val, &next, 10);
+ if (minJitter >= 10) {
+ unsigned maxJitter = minJitter;
+ if (*next == ',')
+ maxJitter = atoi(next+1);
+ SetAudioJitterDelay(minJitter, maxJitter); // In milliseconds
+ } else{
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set zero Jitter buffer\n");
+                                        SetAudioJitterDelay(0, 0);
+                                }
+ } else if (!strcasecmp(var, "gk-address")) {
+ m_gkAddress = val;
+ } else if (!strcasecmp(var, "gk-identifer")) {
+ m_gkIdentifer = val;
+ } else if (!strcasecmp(var, "gk-interface")) {
+ m_gkInterface = val;
+ } else if (!strcasecmp(var, "gk-prefix")) {
+                                m_gkPrefixes.AppendString(val);
+                        }
+ }
+ }
+
+ switch_xml_t xmlListeners = switch_xml_child(cfg, "listeners");
+ if (xmlListeners != NULL) {
+ for (switch_xml_t xmlListener = switch_xml_child(xmlListeners, "listener"); xmlListener != NULL; xmlListener = xmlListener->next) {
+
+ m_listeners.push_back(FSListener());
+ FSListener & listener = m_listeners.back();
+
+ listener.name = switch_xml_attr_soft(xmlListener, "name");
+ if (listener.name.IsEmpty())
+ listener.name = "unnamed";
+
+ PIPSocket::Address ip;
+ WORD port = 1720;
+
+ for (switch_xml_t xmlParam = switch_xml_child(xmlListener, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
+ const char *var = switch_xml_attr_soft(xmlParam, "name");
+ const char *val = switch_xml_attr_soft(xmlParam, "value");
+ //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Var - '%s' and Val - '%s' \n", var, val);
+ if (!strcasecmp(var, "h323-ip"))
+ ip = val;
+ else if (!strcasecmp(var, "h323-port"))
+ port = (WORD) atoi(val);
+ }
+
+ listener.listenAddress = new H323ListenerTCP(*this,ip,port);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.name);
+ }
+ }
+
+ switch_event_destroy(&params);
+
+ if (xml)
+ switch_xml_free(xml);
+
+ return status;
+}
+
+FSH323EndPoint::FSH323EndPoint(){
+        PTRACE(4, "mod_h323\t======>FSH323EndPoint::FSH323EndPoint " << *this);
+        terminalType = e_GatewayOnly;
+}        
+
+H323Connection *FSH323EndPoint::CreateConnection(
+        unsigned callReference,
+        void* userData,
+        H323Transport* transport,
+        H323SignalPDU* setupPDU){
+        PTRACE(4, "mod_h323\t======>FSH323EndPoint::CreateConnection callReference = "<< callReference <<" userDate = "<<userData<<" [" << *this<<"]");
+
+        if ((switch_caller_profile_t *)userData){
+                PTRACE(4, "mod_h323\t------> SWITCH_CALL_DIRECTION_OUTBOUND");
+        } else{
+                PTRACE(4, "mod_h323\t------> SWITCH_CALL_DIRECTION_INBOUND");
+        }
+        
+ switch_core_session_t *fsSession = switch_core_session_request(GetSwitchInterface(),
+ (switch_caller_profile_t *)userData ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND, NULL);
+ if (fsSession == NULL)
+ return NULL;
+        
+        PTRACE(4, "mod_h323\t------> fsSession = "<<fsSession);
+ switch_channel_t *fsChannel = switch_core_session_get_channel(fsSession);
+
+        if (fsChannel == NULL) {
+ switch_core_session_destroy(&fsSession);
+ return NULL;
+        }
+        
+ return new FSH323Connection(*this,transport,callReference,(switch_caller_profile_t *)userData, fsSession, fsChannel);
+
+}
+
+bool FSH323EndPoint::OnSetGatewayPrefixes(PStringList & prefixes) const{
+        PTRACE(4, "mod_h323\t======>FSH323EndPoint::OnSetGatewayPrefixes " << *this);
+        if(m_gkPrefixes.GetSize() > 0) {
+                PTRACE(4, "mod_h323\tOnSetGatewayPrefixes " << m_gkPrefixes);
+                prefixes = m_gkPrefixes;
+                return true;
+        }
+        return false;
+}
+
+FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* transport, unsigned callReference, switch_caller_profile_t *outbound_profile, switch_core_session_t *fsSession, switch_channel_t *fsChannel)
+        : H323Connection(endpoint,callReference)
+        , m_endpoint(&endpoint)
+        , m_fsSession(fsSession)
+ , m_fsChannel(fsChannel)
+        , m_callOnPreAnswer(false)
+        , m_startRTP(false){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::FSH323Connection " << *this);
+
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt));
+ tech_pvt->me = this;
+ switch_core_session_set_private(m_fsSession, tech_pvt);
+        
+        switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession));
+        switch_mutex_init(&tech_pvt->h323_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession));
+        
+ if (outbound_profile != NULL) {
+ SetLocalPartyName(outbound_profile->caller_id_number);
+ SetDisplayName(outbound_profile->caller_id_name);
+
+ switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, outbound_profile);
+ switch_channel_set_caller_profile(m_fsChannel, caller_profile);
+
+ PString name = "h323/";
+ name += outbound_profile->destination_number;
+ switch_channel_set_name(m_fsChannel, name);
+
+ switch_channel_set_flag(m_fsChannel, CF_OUTBOUND);
+ switch_channel_set_state(m_fsChannel, CS_INIT);
+ }
+        
+        m_RTPlocalPort = switch_rtp_request_port((const char *)m_RTPlocalIP.AsString());
+}        
+
+FSH323Connection::~FSH323Connection(){
+ PTRACE(4, "mod_h323\t======>FSH323Connection::~FSH323Connection ["<<*this<<"]");
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+ tech_pvt->me = NULL;
+}        
+
+void FSH323Connection::OnSetLocalCapabilities(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnSetLocalCapabilities() [" << *this<<"]");
+        H323Connection::OnSetLocalCapabilities();
+        SetLocalCapabilities();
+}
+
+bool FSH323Connection::SetLocalCapabilities(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::SetLocalCapabilities() Size local capability = "<<localCapabilities.GetSize()<<" [" << *this<<"]");
+ if (!mod_h323_globals.codec_string)
+                return false;
+
+ bool nocodecs = true;
+ bool changed = false;
+ for (int i = 0; i < localCapabilities.GetSize(); i++) {
+                const char* format = 0;
+                PString fname;
+                decodeCapability(localCapabilities[i],&format,0,&fname);
+                if (format) {
+                        PString m_globalcodec = ((const char *)mod_h323_globals.codec_string);
+                        if (m_globalcodec.Find(format) < 0) {
+                                PTRACE(1, "mod_h323\tRemoving capability '"<<fname<<"' ("<<format<<") not in remote '"<<m_globalcodec<<"'");
+                                changed = true;
+                                for (PINDEX idx = 0; idx < fastStartChannels.GetSize(); idx++) {
+                                        if (fastStartChannels[idx].GetCapability() == localCapabilities[i]) {
+                                                PTRACE(1, "mod_h323\tRemoving fast start channel "<<fastStartChannels[idx].GetDirection()<<" '"<<fname<<"' ("<<format<<")");
+                                                fastStartChannels.RemoveAt(idx--);
+                                        }                
+                                }
+                                localCapabilities.Remove(fname);
+                                i--;
+                        } else        nocodecs = false;
+                }
+ }
+ if (nocodecs) {
+                PTRACE(3, "mod_h323\tNo codecs remaining for H323 connection ["<<*this<<"]");
+                changed = false;
+                ClearCall(EndedByCapabilityExchange);                
+ }
+ return changed;
+}
+
+bool FSH323Connection::decodeCapability(const H323Capability& capability, const char** dataFormat, int* payload, PString* capabName){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::decodeCapability");
+ PString fname((const char *)capability.GetFormatName());
+
+ if (fname.Find("{sw}") == (fname.GetLength() - 4))
+                fname = fname.Mid(0,fname.GetLength()-4);
+ if (fname.Find("{hw}") == (fname.GetLength() - 4))
+                fname = fname.Mid(0,fname.GetLength()-4);
+                
+ OpalMediaFormat oformat(fname, false);
+ int pload = oformat.GetPayloadType();
+ const char *format = 0;
+ const char** f = h323_formats;
+ for (; *f; f += 2) {
+                if (fname.Find(*f) == 0) {
+                        format = f[1];
+                        break;
+                }
+ }
+
+        PTRACE(1, "mod_h323\tcapability '"<< fname << "' format '"<<format<<"' payload "<<pload);
+ if (format) {
+                if (capabName)
+                        *capabName = fname;
+                if (dataFormat)
+                        *dataFormat = format;
+                if (payload)
+                        *payload = pload;
+                return true;
+ }
+ return false;
+}
+
+H323Connection::AnswerCallResponse FSH323Connection::OnAnswerCall(const PString &caller,
+ const H323SignalPDU &setupPDU, H323SignalPDU &connectPDU){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnAnswerCall caller = "<< caller<<" [" << *this<<"]");
+        
+        if (m_fsSession == NULL) {
+ PTRACE(1, "mod_h323\tSession request failed.");
+ return H323Connection::AnswerCallDenied;
+ }
+
+ switch_core_session_add_stream(m_fsSession, NULL);
+
+ switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
+ if (channel == NULL) {
+ PTRACE(1, "mod_h323\tSession does not have a channel");
+ return H323Connection::AnswerCallDenied;
+ }
+
+        const Q931& q931 = setupPDU.GetQ931();
+        const H225_Setup_UUIE& setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
+ const H225_ArrayOf_AliasAddress& address = setup.m_destinationAddress;
+ for (int i = 0; i<address.GetSize(); i++)
+                PTRACE(2, "mod_h323\t address index = "<<i<<" value = "<<(const char *)H323GetAliasAddressString(address[i]));
+        PString called;
+ if (address.GetSize() > 0)
+                called = (const char *)H323GetAliasAddressString(address[0]);
+ if (!called.IsEmpty())
+                PTRACE(2, "mod_h323\t Called number or alias = "<<called);
+ else {
+                PString callnam;
+                if (q931.GetCalledPartyNumber(callnam)) {
+                        called=(const char *)callnam;                        
+                        PTRACE(2, "mod_h323\t Called-Party-Number = "<<called);
+                }
+ }
+
+        
+ switch_caller_profile_t *caller_profile = switch_caller_profile_new(switch_core_session_get_pool(m_fsSession),
+ NULL,
+ /** username */
+ mod_h323_globals.dialplan,
+ /** dial plan */
+ GetRemotePartyName(),
+ /** caller_id_name */
+ GetRemotePartyNumber(),
+ /** caller_id_number */
+ NULL,
+ /** network addr */
+ NULL,
+ /** ANI */
+ NULL,
+ /** ANI II */
+ NULL,
+ /** RDNIS */
+ modulename,
+ /** source */
+ mod_h323_globals.context,
+ /** set context */
+ called
+ /** destination_number */
+ );
+ if (caller_profile == NULL) {
+ PTRACE(1, "mod_h323\tCould not create caller profile");
+ return H323Connection::AnswerCallDenied;
+ }
+
+ PTRACE(4, "mod_h323\tCreated switch caller profile:\n"
+ " username = " << caller_profile->username << "\n"
+ " dialplan = " << caller_profile->dialplan << "\n"
+ " caller_id_name = " << caller_profile->caller_id_name << "\n"
+ " caller_id_number = " << caller_profile->caller_id_number << "\n"
+ " network_addr = " << caller_profile->network_addr << "\n"
+ " source = " << caller_profile->source << "\n"
+ " context = " << caller_profile->context << "\n"
+                 " destination_number= " << caller_profile->destination_number);
+ switch_channel_set_caller_profile(channel, caller_profile);
+
+ char name[256] = "h323/";
+ switch_copy_string(name + 5, caller_profile->destination_number, sizeof(name)-5);
+ switch_channel_set_name(channel, name);
+ switch_channel_set_state(channel, CS_INIT);
+
+ if (switch_core_session_thread_launch(m_fsSession) != SWITCH_STATUS_SUCCESS) {
+ PTRACE(1, "mod_h323\tCould not launch session thread");
+ return H323Connection::AnswerCallDenied;
+ }
+
+        return H323Connection::AnswerCallDeferred;
+}
+
+H323Channel* FSH323Connection::CreateRealTimeLogicalChannel(const H323Capability& capability,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters* param, RTP_QOS * rtpqos){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::CreateRealTimeLogicalChannel " << *this);
+        
+        H323TransportAddress m_h323transportadd = GetSignallingChannel()->GetLocalAddress();
+        m_h323transportadd.GetIpAddress(m_RTPlocalIP);
+//        return H323Connection::CreateRealTimeLogicalChannel(capability,dir,sessionID,param);
+        return new FSH323_ExternalRTPChannel(*this, capability, dir, sessionID,m_RTPlocalIP,m_RTPlocalPort);
+}
+
+PBoolean FSH323Connection::OnStartLogicalChannel(H323Channel & channel){
+ PTRACE(4, "mod_h323\t======>FSH323Connection::OnStartLogicalChannel chennel = "<<&channel<<", "<<*this);
+
+// return H323Connection::OnStartLogicalChannel(channel);
+        return true;
+}
+
+PBoolean FSH323Connection::OnCreateLogicalChannel(const H323Capability& capability, H323Channel::Directions dir, unsigned& errorCode){
+ PTRACE(4, "mod_h323\t======>FSH323Connection::OnCreateLogicalChannel ('"<< (const char *)capability.GetFormatName()<<"',"<<dir<<") "<<*this);
+
+        return H323Connection::OnCreateLogicalChannel(capability,dir,errorCode);
+}
+
+void FSH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedReleaseComplete cause = "<<pdu.GetQ931().GetCause()<<" value = "<<(switch_call_cause_t)pdu.GetQ931().GetCause());
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+//        tech_pvt->me = NULL;
+        
+        switch_channel_hangup(switch_core_session_get_channel(m_fsSession),(switch_call_cause_t)pdu.GetQ931().GetCause());
+//        on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
+        return H323Connection::OnReceivedReleaseComplete(pdu);
+}
+
+bool FSH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
+{
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedProgress");
+        m_txAudioOpened.Wait();
+        switch_channel_mark_pre_answered(m_fsChannel);
+        return true;
+}
+
+
+bool FSH323Connection::OnSendReleaseComplete(H323SignalPDU & pdu)
+{
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnSendReleaseComplete cause = "<<pdu.GetQ931().GetCause()<<" value = "<<(switch_call_cause_t)pdu.GetQ931().GetCause());
+        
+        switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);                        
+        return H323Connection::OnSendReleaseComplete(pdu);
+}
+
+PBoolean FSH323Connection::OpenLogicalChannel(const H323Capability& capability, unsigned sessionID, H323Channel::Directions dir){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OpenLogicalChannel ('"<< (const char *)capability.GetFormatName()<<"', "<< sessionID<<", "<<dir <<") "<<*this);
+
+ return H323Connection::OpenLogicalChannel(capability,sessionID,dir);
+}
+
+
+bool FSH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
+                                                        const H245_MultiplexCapability * muxCap,
+                                                        H245_TerminalCapabilitySetReject & reject){
+        
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedCapabilitySet ["<<*this<<"]");
+        if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
+                return false;
+        }
+        PTRACE(4, "mod_h323\t======>END H323Connection::OnReceivedCapabilitySet ["<<*this<<"]");
+        
+        for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
+                PTRACE(4, "mod_h323\t----> Capabilities = "<<remoteCapabilities[i]);
+        }
+        
+        H323Capability * cap = remoteCapabilities.FindCapability(H323Capability::e_Audio);
+        if (cap == NULL) {
+                PTRACE(4, "mod_h323\t----> Capabilities is NULL ");
+                return false;
+        }
+        PTRACE(4, "mod_h323\t----> Capabilities not NULL ");
+        return true;                                                
+}
+
+
+bool FSH323Connection::OnAlerting(const H323SignalPDU &alertingPDU, const PString &user){
+
+        PTRACE(4, "mod_h323\t======>PFSH323Connection::OnAlerting user = "<<(const char *)user<<" ["<<*this<<"]");
+        
+        return (switch_channel_mark_ring_ready(m_fsChannel) == SWITCH_STATUS_SUCCESS);
+         ;
+}
+
+void FSH323Connection::OnEstablished(){
+
+        PTRACE(4, "mod_h323\t======>PFSH323Connection::OnEstablished ["<<*this<<"]");
+        
+        switch_channel_mark_answered(m_fsChannel);
+}
+
+
+
+void FSH323Connection::setRemoteAddress(const char* remoteIP, WORD remotePort){
+        PTRACE(4, "mod_h323\t======>PFSH323Connection::setRemoteAddress remoteIP ="<<remoteIP<<", remotePort = "<<remotePort<<" "<<*this);
+ if (!m_remotePort) {
+        PTRACE(4, "mod_h323\tGot remote RTP address "<<remoteIP<<":"<<remotePort<<" "<<*this);
+        m_remotePort = remotePort;
+        m_remoteAddr = remoteIP;
+ }
+}
+
+switch_status_t FSH323Connection::on_execute(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::on_execute " << *this);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::on_routing(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::on_routing " << *this);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::kill_channel(int sig){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::kill_channel " << *this);
+ PTRACE(3, "mod_h323\tKill " << sig << " on connection " << *this);
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        
+        if (!tech_pvt) {
+                return SWITCH_STATUS_FALSE;
+        }
+        
+ switch (sig) {
+ case SWITCH_SIG_BREAK:
+                if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                        switch_rtp_break(tech_pvt->rtp_session);
+                }
+ break;
+ case SWITCH_SIG_KILL:
+ default:
+                m_rxAudioOpened.Signal();
+ m_txAudioOpened.Signal();
+                if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                        switch_rtp_kill_socket(tech_pvt->rtp_session);
+                }
+ break;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::send_dtmf(const switch_dtmf_t *dtmf){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::send_dtmf " << *this);
+ SendUserInputTone(dtmf->digit, dtmf->duration);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+void FSH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+        PTRACE(4, "mod_h323\t======>FSH323Connection::SendUserInputTone [" << *this<<"]");
+        H323Connection::SendUserInputTone(tone, duration);
+}
+
+void FSH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
+{
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnUserInputTone [" << *this<<"]");
+        switch_dtmf_t dtmf = { tone, duration };
+ switch_channel_queue_dtmf(m_fsChannel, &dtmf);
+        H323Connection::OnUserInputTone( tone, duration, logicalChannel, rtpTimestamp);
+}
+
+void FSH323Connection::OnUserInputString(const PString &value)
+{
+        PTRACE(4, "mod_h323\t======>FSH323Connection::OnUserInputString [" << *this<<"]");
+        switch_dtmf_t dtmf = { value[0], 0 };
+ switch_channel_queue_dtmf(m_fsChannel, &dtmf);
+        H323Connection::OnUserInputString(value);
+}
+
+
+switch_status_t FSH323Connection::receive_message(switch_core_session_message_t *msg){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::receive_message MSG=" << msg->message_id);
+        
+        
+ switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
+
+
+
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_BRIDGE:
+ case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+ case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
+ switch_channel_set_private_flag(channel, CF_NEED_FLUSH);
+ break;
+ default:
+ break;
+ }
+
+ switch (msg->message_id) {
+                case SWITCH_MESSAGE_INDICATE_RINGING:{
+//                         AnsweringCall(AnswerCallAlertWithMedia);
+                         AnsweringCall(AnswerCallPending);
+                        break;
+                }
+                case SWITCH_MESSAGE_INDICATE_DEFLECT:{
+        /* PSafePtr<OpalConnection> other = GetOtherPartyConnection();
+                        if (other != NULL)
+                         other->TransferConnection(msg->string_arg);
+                        break;
+        */                
+                }
+                case SWITCH_MESSAGE_INDICATE_PROGRESS:{
+                        m_callOnPreAnswer = true;                
+                        AnsweringCall(AnswerCallPending);
+                        AnsweringCall(AnswerCallDeferredWithMedia);
+                        m_txAudioOpened.Wait();
+                        if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {
+                                switch_channel_mark_pre_answered(m_fsChannel);
+                        }
+                        break;
+                }
+                case SWITCH_MESSAGE_INDICATE_ANSWER:{
+                        if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+                                return SWITCH_STATUS_FALSE;
+                        }
+                        AnsweringCall(H323Connection::AnswerCallNow);
+                        PTRACE(4, "mod_h323\tMedia started on connection " << *this);
+
+                        m_rxAudioOpened.Wait();
+ m_txAudioOpened.Wait();
+
+                        if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {
+                                PTRACE(4, "mod_h323\t-------------------->switch_channel_mark_answered(m_fsChannel) " << *this);
+                                switch_channel_mark_answered(m_fsChannel);
+                        }
+                        break;
+                }
+                default:{
+                        PTRACE(3, "mod_h323\tReceived message " << msg->message_id << " on connection " << *this);
+                }        
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::receive_event(switch_event_t *event){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::receive_event " << *this);
+ PTRACE(3, "mod_h323\tReceived event " << event->event_id << " on connection " << *this);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::state_change(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::state_change " << *this);
+ PTRACE(3, "mod_h323\tState changed on connection " << *this);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::on_init(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::on_init " << *this);
+ switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
+ if (channel == NULL) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ PTRACE(3, "mod_h323\tStarted routing for connection " << *this);
+ switch_channel_set_state(channel, CS_ROUTING);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::on_exchange_media(){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::on_exchange_media " << *this);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::on_soft_execute(){
+ PTRACE(4, "mod_h323\t======>FSH323Connection::on_soft_execute " << *this);
+        
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t FSH323Connection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::read_audio_frame " << *this);
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        tech_pvt->read_frame.flags = 0;
+/*        
+        if (switch_channel_test_private_flag(m_fsChannel, CF_NEED_FLUSH)) {
+ switch_channel_clear_private_flag(m_fsChannel, CF_NEED_FLUSH);
+ } else {
+ switch_core_timer_next(&tech_pvt->read_timer);
+ }
+*/
+        switch_set_flag_locked(tech_pvt, TFLAG_READING);
+        
+ if (!switch_channel_ready(m_fsChannel)) {
+                PTRACE(4, "mod_h323\t---------> RETURN");
+                switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!switch_core_codec_ready(&tech_pvt->read_codec )) {
+                PTRACE(4, "mod_h323\t---------> RETURN");
+                switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ //switch_core_timer_step(&m_switchTimer);
+
+        
+        switch_status_t status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
+        if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+                        PTRACE(4, "mod_h323\t---------> RETURN");
+                        switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+                        return SWITCH_STATUS_FALSE;
+        }
+        PTRACE(4, "mod_h323\t--------->\n source = "<<tech_pvt->read_frame.source<< "\n packetlen = "<<tech_pvt->read_frame.packetlen<<"\n datalen = "<<tech_pvt->read_frame.datalen<<"\n samples = "<<tech_pvt->read_frame.samples<<"\n rate = "<<tech_pvt->read_frame.rate<<"\n payload = "<<(int)tech_pvt->read_frame.payload<<"\n timestamp = "<<tech_pvt->read_frame.timestamp<<"\n seq = "<<tech_pvt->read_frame.seq<<"\n ssrc = "<<tech_pvt->read_frame.ssrc);
+ if (tech_pvt->read_frame.flags & SFF_CNG) {
+ tech_pvt->read_frame.buflen = sizeof(m_buf);
+ tech_pvt->read_frame.data = m_buf;
+ tech_pvt->read_frame.packet = NULL;
+ tech_pvt->read_frame.packetlen = 0;
+ tech_pvt->read_frame.timestamp = 0;
+ tech_pvt->read_frame.m = SWITCH_FALSE;
+ tech_pvt->read_frame.seq = 0;
+ tech_pvt->read_frame.ssrc = 0;
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
+ } else {
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
+ }
+        switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+ *frame = &tech_pvt->read_frame;
+
+ return SWITCH_STATUS_SUCCESS;
+        
+
+}
+
+switch_status_t FSH323Connection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::write_audio_frame " << *this);
+        
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        switch_assert(tech_pvt != NULL);
+        
+        if (!switch_channel_ready(m_fsChannel)) {
+                PTRACE(4, "mod_h323\t---------> RETURN");
+ return SWITCH_STATUS_FALSE;
+ }        
+        
+        while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+                if (switch_channel_ready(m_fsChannel)) {
+                        switch_yield(10000);
+                } else {
+                        PTRACE(4, "mod_h323\t---------> RETURN");
+                        return SWITCH_STATUS_GENERR;
+                }
+        }
+        
+        if (!switch_core_codec_ready(&tech_pvt->read_codec) || !tech_pvt->read_codec.implementation) {
+                PTRACE(4, "mod_h323\t---------> RETURN");
+                return SWITCH_STATUS_GENERR;
+        }
+
+        if ((frame->flags & SFF_CNG)) {
+                PTRACE(4, "mod_h323\t---------> RETURN");
+ return SWITCH_STATUS_SUCCESS;
+ }
+        switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
+        
+        if (switch_rtp_write_frame(tech_pvt->rtp_session, frame)< 0) {
+                status = SWITCH_STATUS_GENERR;
+        }
+        
+        switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
+        PTRACE(4, "mod_h323\t---------> RETURN");        
+        return status;
+}
+
+switch_status_t FSH323Connection::read_video_frame(switch_frame_t **frame, switch_io_flag_t flag, int stream_id){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::read_video_frame " << *this);
+
+}
+
+switch_status_t FSH323Connection::write_video_frame(switch_frame_t *frame, switch_io_flag_t flag, int stream_id){
+        PTRACE(4, "mod_h323\t======>FSH323Connection::write_video_frame " << *this);
+// return write_frame(OpalMediaType::Video(), frame, flag);
+}
+
+///////////////////////////////////////////////////////////////////////
+
+FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel(
+ FSH323Connection& connection,
+ const H323Capability& capability,
+ Directions direction,
+ unsigned sessionID,
+        const PIPSocket::Address& ip,
+        WORD dataPort)
+ : H323_ExternalRTPChannel(connection, capability, direction, sessionID,ip,dataPort)
+        , m_conn(&connection)
+        , m_fsSession(connection.GetSession())
+        , m_capability(&capability)
+        , m_RTPlocalPort(dataPort){
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        
+ m_RTPlocalIP = (const char *)ip.AsString();
+        SetExternalAddress(H323TransportAddress(ip, dataPort), H323TransportAddress(ip, dataPort+1));
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel "<< GetDirection()<< " addr="<< m_RTPlocalIP <<":"<< m_RTPlocalPort<<" ["<<*this<<"]");        
+        
+        memset(&m_readFrame, 0, sizeof(m_readFrame));
+ m_readFrame.codec = m_switchCodec;
+ m_readFrame.flags = SFF_RAW_RTP;
+        
+        m_fsChannel = switch_core_session_get_channel(m_fsSession);
+ //SetExternalAddress(H323TransportAddress(localIpAddress, m_RTPlocalPort), H323TransportAddress(localIpAddress, m_RTPlocalPort+1));
+        PTRACE(4, "mod_h323\t------->capability.GetPayloadType() return = "<<capability.GetPayloadType());
+        PTRACE(4, "mod_h323\t------->capability.GetFormatName() return = "<<capability.GetFormatName());
+        
+        PString fname((const char *)capability.GetFormatName());
+
+ if (fname.Find("{sw}") == (fname.GetLength() - 4))
+                fname = fname.Mid(0,fname.GetLength()-4);
+ if (fname.Find("{hw}") == (fname.GetLength() - 4))
+                fname = fname.Mid(0,fname.GetLength()-4);
+        
+        OpalMediaFormat format(fname, FALSE);
+        m_format = &format;
+        payloadCode = format.GetPayloadType();
+        PTRACE(4, "mod_h323\t------->payloadCode = "<<(int)payloadCode);
+}
+
+
+FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel(){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel "<< GetDirection()<<" "<<*this);
+        h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        if (IsRunning()){
+                PTRACE(4, "mod_h323\t------------->Running");
+                if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                        switch_rtp_kill_socket(tech_pvt->rtp_session);
+                }
+        }
+}
+
+PBoolean FSH323_ExternalRTPChannel::Start(){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::Start() "<<*this);
+        const char *err = NULL;
+        switch_rtp_flag_t flags;
+        char * timer_name = NULL;
+        const char *var;
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
+        if (!(m_conn && H323_ExternalRTPChannel::Start()))
+                return FALSE;
+        
+        
+        bool isAudio;
+ if (m_capability->GetMainType() == H323Capability::e_Audio) {
+ isAudio = true;
+                PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Audio");
+ } else if (m_capability->GetMainType() == H323Capability::e_Video) {
+ isAudio = false;
+                PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Video");
+ }
+        
+        H323Codec *codec = GetCodec();
+        
+        
+        PTRACE(4, "mod_h323\t------------------->GetFrameSize() return = "<<m_format->GetFrameSize());
+        PTRACE(4, "mod_h323\t------------------->GetFrameTime() return = "<<m_format->GetFrameTime());
+        PTRACE(4, "mod_h323\t------------------->payloadCode = "<<(int)payloadCode);
+        PTRACE(4, "mod_h323\t------------------->m_capability->GetTxFramesInPacket() return = "<<m_capability->GetTxFramesInPacket());
+        PTRACE(4, "mod_h323\t------------------->m_capability->GetFormatName() return = "<<m_capability->GetFormatName());
+        
+        PTRACE(4, "mod_h323\t------------------->GetH245CodecName() return = "<<GetH245CodecName(m_capability->GetSubType()));
+        
+        
+        
+        
+        
+        if (GetDirection() == IsReceiver){
+                m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec;
+ m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer;
+        }else{
+                m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec;
+        }
+        
+        if (m_conn->m_callOnPreAnswer && !(GetDirection() == IsReceiver)){
+                m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec;
+ m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer;
+        }
+        
+        
+        
+        if (switch_core_codec_init(m_switchCodec, GetH245CodecName(m_capability->GetSubType()), NULL, // FMTP
+ 8000, m_capability->GetTxFramesInPacket(), 1, // Channels
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings
+ switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
+
+ if (switch_core_codec_init(m_switchCodec, GetH245CodecName(m_capability->GetSubType()), NULL, // FMTP
+ 8000, 0, 1, // Channels
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings
+ switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
+ PTRACE(1, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Cannot initialise " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
+ << m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
+ switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
+ return false;
+ }
+ PTRACE(2, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Unsupported ptime of " << m_capability->GetTxFramesInPacket() << " on " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
+ << m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
+ }
+
+ PTRACE(1, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " initialise " <<
+ switch_channel_get_name(m_fsChannel) << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
+ << m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
+        
+         if (GetDirection() == IsReceiver) {
+ m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
+
+ if (isAudio) {
+ switch_core_session_set_read_codec(m_fsSession, m_switchCodec);
+ if (switch_core_timer_init(m_switchTimer,
+ "soft",
+ m_switchCodec->implementation->microseconds_per_packet / 1000,
+ m_switchCodec->implementation->samples_per_packet,
+ switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
+ switch_core_codec_destroy(m_switchCodec);
+ m_switchCodec = NULL;
+ return false;
+ }
+ } else {
+ switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec);
+ switch_channel_set_flag(m_fsChannel, CF_VIDEO);
+ }
+ } else {
+ if (isAudio) {
+ switch_core_session_set_write_codec(m_fsSession, m_switchCodec);
+ } else {
+ switch_core_session_set_video_write_codec(m_fsSession, m_switchCodec);
+ switch_channel_set_flag(m_fsChannel, CF_VIDEO);
+ }
+ }
+
+        if (m_conn->m_callOnPreAnswer && !(GetDirection() == IsReceiver)){
+                m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
+
+ if (isAudio) {
+ switch_core_session_set_read_codec(m_fsSession, m_switchCodec);
+ if (switch_core_timer_init(m_switchTimer,
+ "soft",
+ m_switchCodec->implementation->microseconds_per_packet / 1000,
+ m_switchCodec->implementation->samples_per_packet,
+ switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
+ switch_core_codec_destroy(m_switchCodec);
+ m_switchCodec = NULL;
+ return false;
+ }
+                        switch_channel_set_variable(m_fsChannel,"timer_name","soft");
+                }        
+        }
+        
+ PTRACE(3, "mod_h323\tSet " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
+ << m_capability->GetMainType() << " codec to << " << m_capability << " for connection " << *this);
+
+        switch_mutex_lock(tech_pvt->h323_mutex);
+        
+        PIPSocket::Address remoteIpAddress;
+ GetRemoteAddress(remoteIpAddress,m_RTPremotePort);        
+        m_RTPremoteIP = (const char *)remoteIpAddress.AsString();
+        PTRACE(4, "mod_h323\t------------------->tech_pvt->rtp_session = "<<tech_pvt->rtp_session);
+        PTRACE(4, "mod_h323\t------------------->samples_per_packet = "<<m_switchCodec->implementation->samples_per_packet);
+        PTRACE(4, "mod_h323\t------------------->actual_samples_per_second = "<<m_switchCodec->implementation->actual_samples_per_second);
+        
+        if (!m_conn->m_startRTP) {                        
+                flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT|SWITCH_RTP_FLAG_AUTO_CNG|SWITCH_RTP_FLAG_RAW_WRITE|SWITCH_RTP_FLAG_AUTOADJ);                
+                if ((var = switch_channel_get_variable(m_fsChannel, "timer_name"))) {
+                        timer_name = (char *) var;
+                }
+                tech_pvt->rtp_session = switch_rtp_new((const char *)m_RTPlocalIP,
+                                                                                         m_RTPlocalPort,
+                                                                                         (const char *)m_RTPremoteIP,
+                                                                                         m_RTPremotePort,
+                                                                                         (switch_payload_t)payloadCode,
+                                                                                         m_switchCodec->implementation->samples_per_packet,        
+                                                                                         m_capability->GetTxFramesInPacket() * 1000,
+                                                                                         (switch_rtp_flag_t) flags, timer_name, &err,
+                                                                                         switch_core_session_get_pool(m_fsSession));
+                PTRACE(4, "mod_h323\t------------------------->tech_pvt->rtp_session = "<<tech_pvt->rtp_session);
+                m_conn->m_startRTP = true;
+                if (switch_rtp_ready(tech_pvt->rtp_session)) {
+                        PTRACE(4, "mod_h323\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");                
+                        switch_channel_set_flag(m_fsChannel, CF_FS_RTP);
+                        
+                }else{
+                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
+                        switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);                        
+                        switch_mutex_unlock(tech_pvt->h323_mutex);
+                        return SWITCH_STATUS_FALSE;
+                }
+        }
+        if (GetDirection() == IsReceiver) m_conn->m_rxAudioOpened.Signal();
+        else m_conn->m_txAudioOpened.Signal();
+ PTRACE(4, "mod_h323\t------------->External RTP address "<<m_RTPremoteIP<<":"<<m_RTPremotePort);
+        switch_mutex_unlock(tech_pvt->h323_mutex);
+        
+        return true;
+}
+
+
+PBoolean FSH323_ExternalRTPChannel::OnReceivedPDU(
+                                const H245_H2250LogicalChannelParameters& param,
+                                unsigned& errorCode){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnReceivedPDU ["<<*this<<"]");
+ if (!H323_ExternalRTPChannel::OnReceivedPDU(param,errorCode))
+                return true;
+// if (!m_conn || m_conn->hasRemoteAddress())
+//                return true;
+ PIPSocket::Address remoteIpAddress;
+ WORD remotePort;
+ GetRemoteAddress(remoteIpAddress,remotePort);
+ PTRACE(4, "mod_h323\tRemote RTP address "<<(const char *)remoteIpAddress.AsString()<<":"<<remotePort);
+ m_conn->setRemoteAddress((const char *)remoteIpAddress.AsString(), remotePort);
+ return true;
+}
+
+PBoolean FSH323_ExternalRTPChannel::OnSendingPDU(H245_H2250LogicalChannelParameters& param){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnSendingPDU ["<<*this<<"]");
+ return H323_ExternalRTPChannel::OnSendingPDU(param);
+}
+
+PBoolean FSH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters& param){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnReceivedAckPDU ["<<*this<<"]");
+ return H323_ExternalRTPChannel::OnReceivedAckPDU(param);
+}
+
+void FSH323_ExternalRTPChannel::OnSendOpenAck(H245_H2250LogicalChannelAckParameters& param){
+ PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnSendOpenAck ["<<*this<<"]");
+ H323_ExternalRTPChannel::OnSendOpenAck(param);
+}
+
+
+FSH323Connection * FSH323EndPoint::FSMakeCall(const PString & dest, void *userData){
+        PTRACE(4, "mod_h323\t======>FSH323EndPoint::FSMakeCall DST NUMBER = "<<dest<<" ["<<*this<<"]");
+        
+        FSH323Connection * connection;
+        PString token;
+        H323Transport *transport = NULL;
+        
+ if (listeners.GetSize() > 0) {
+                        H323TransportAddress taddr = listeners[0].GetTransportAddress();
+                        PIPSocket::Address addr;
+                        WORD port;
+                        if (taddr.GetIpAndPort(addr, port)) {                                
+                                if (addr) {
+                                        PTRACE(4, "mod_h323\t----> Using "<<addr<<" for outbound call");
+                                        transport = new H323TransportTCP(*this, addr,false);
+                                        if (!transport)                                                
+                                                PTRACE(4, "mod_h323\t----> Unable to create transport for outgoing call");
+                                }
+                        } else
+                                PTRACE(4, "mod_h323\t----> Unable to get address and port");
+        }
+        
+/*        
+ if (!(connection = (FSH323Connection *)H323EndPoint::MakeCallLocked(dest, token, userData, transport))) {
+ return NULL;
+ }
+*/        
+
+ if (!(connection = (FSH323Connection *)H323EndPoint::MakeCall(dest, token, userData))) {
+ return NULL;
+ }
+
+/*
+        unsigned int *callReference;
+        
+        *callReference = connection->GetCallReference();
+        PTRACE(2, "mod_h323\t======>\n\tCreate outgoing cennel\n\tCall token = "<<(const char *)token<<"\n\tCall reference = "<<*callReference);
+*/
+        return connection;
+}
+
+
+static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session,
+ switch_event_t *var_event,
+ switch_caller_profile_t *outbound_profile,
+ switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags){
+        PTRACE(4, "mod_h323\t======>create_outgoing_channel DST NUMBER = "<<outbound_profile->destination_number);
+        
+        FSH323Connection * connection;
+ if (h323_process == NULL) {
+ return SWITCH_CAUSE_CRASH;
+ }
+        FSH323EndPoint & ep = h323_process->GetH323EndPoint();
+        if (!(connection = ep.FSMakeCall(outbound_profile->destination_number,outbound_profile))){
+                return SWITCH_CAUSE_PROTOCOL_ERROR;
+        }
+/* PSafePtr < OpalCall > call = manager.FindCallWithLock(token);
+
+ if (call == NULL) {
+ return SWITCH_CAUSE_PROTOCOL_ERROR;
+ }
+
+ PSafePtr < FSConnection > connection = call->GetConnectionAs < FSConnection > (0);
+
+ if (connection == NULL) {
+ return SWITCH_CAUSE_PROTOCOL_ERROR;
+ }
+*/
+ *new_session = connection->GetSession();
+        PTRACE(4, "mod_h323\t--------->GetSession() return = "<<connection->GetSession());
+ return SWITCH_CAUSE_SUCCESS;
+}
+
+
+static switch_status_t on_destroy(switch_core_session_t *session){
+        PTRACE(4, "mod_h323\t======>on_destroy ");
+
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
+
+ if (tech_pvt) {
+ if (tech_pvt->read_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ }
+
+ if (tech_pvt->write_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ }
+
+ if (tech_pvt->vid_read_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->vid_read_codec);
+ }
+
+ if (tech_pvt->vid_write_codec.implementation) {
+ switch_core_codec_destroy(&tech_pvt->vid_write_codec);
+ }
+
+ if (tech_pvt->read_timer.timer_interface) {
+ switch_core_timer_destroy(&tech_pvt->read_timer);
+ }
+
+ if (tech_pvt->vid_read_timer.timer_interface) {
+ switch_core_timer_destroy(&tech_pvt->vid_read_timer);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+static switch_status_t on_hangup(switch_core_session_t *session){
+        PTRACE(4, "mod_h323\t======>switch_status_t on_hangup ");
+
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
+ if (tech_pvt->me) {
+                PTRACE(4, "mod_h323\t----->");
+ Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);
+ tech_pvt->me->SetQ931Cause(cause);
+ tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
+ tech_pvt->me = NULL;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+
+
+
+
+
</ins></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_h323mod_h323h"></a>
<div class="addfile"><h4>Added: freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.h (0 => 15223)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.h         (rev 0)
+++ freeswitch/trunk/src/mod/endpoints/mod_h323/mod_h323.h        2009-10-24 01:48:45 UTC (rev 15223)
</span><span class="lines">@@ -0,0 +1,431 @@
</span><ins>+
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility push(default)
+#endif
+
+#include <ptlib.h>
+#include <h323.h>
+#include <h323neg.h>
+#include <h323pdu.h>
+#include <h323caps.h>
+#include <ptclib/delaychan.h>
+
+#include <list>
+
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility pop
+#endif
+
+#undef strcasecmp
+#undef strncasecmp
+
+#define HAVE_APR
+#include <switch.h>
+#include <switch_version.h>
+#define MODNAME "mod_h323"
+
+
+typedef enum {
+        TFLAG_IO = (1 << 0),
+        TFLAG_INBOUND = (1 << 1),
+        TFLAG_OUTBOUND = (1 << 2),
+        TFLAG_READING = (1 << 3),
+        TFLAG_WRITING = (1 << 4),
+        TFLAG_BYE = (1 << 5),
+        TFLAG_VOICE = (1 << 6),
+        TFLAG_RTP_READY = (1 << 7),
+        TFLAG_CODEC_READY = (1 << 8),
+        TFLAG_TRANSPORT = (1 << 9),
+        TFLAG_ANSWER = (1 << 10),
+        TFLAG_VAD_IN = (1 << 11),
+        TFLAG_VAD_OUT = (1 << 12),
+        TFLAG_VAD = (1 << 13),
+        TFLAG_DO_CAND = (1 << 14),
+        TFLAG_DO_DESC = (1 << 15),
+        TFLAG_LANADDR = (1 << 16),
+        TFLAG_AUTO = (1 << 17),
+        TFLAG_DTMF = (1 << 18),
+        TFLAG_TIMER = (1 << 19),
+        TFLAG_TERM = (1 << 20),
+        TFLAG_TRANSPORT_ACCEPT = (1 << 21),
+        TFLAG_READY = (1 << 22),
+} TFLAGS;
+
+struct mod_h323_globals {
+ int trace_level;
+ char *codec_string;
+ char *context;
+ char *dialplan;
+};
+
+extern struct mod_h323_globals mod_h323_globals;
+
+class FSH323Connection;
+class FSH323_ExternalRTPChannel;
+
+typedef struct {
+        unsigned int flags;
+ switch_timer_t read_timer;
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+        switch_frame_t read_frame;
+        
+ switch_timer_t vid_read_timer;
+ switch_codec_t vid_read_codec;
+ switch_codec_t vid_write_codec;
+        switch_rtp_t *rtp_session;
+        switch_mutex_t *flag_mutex;
+        switch_mutex_t *h323_mutex;
+        
+ FSH323Connection *me;
+} h323_private_t;
+
+#define DECLARE_CALLBACK0(name) \
+ static switch_status_t name(switch_core_session_t *session) { \
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name() : SWITCH_STATUS_FALSE; } \
+switch_status_t name()
+
+#define DECLARE_CALLBACK1(name, type1, name1) \
+ static switch_status_t name(switch_core_session_t *session, type1 name1) { \
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1) : SWITCH_STATUS_FALSE; } \
+switch_status_t name(type1 name1)
+
+#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \
+ static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \
+ h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
+ return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
+switch_status_t name(type1 name1, type2 name2, type3 name3)
+
+class FSH323EndPoint;
+class FSProcess : public PLibraryProcess {
+ PCLASSINFO(FSProcess, PLibraryProcess);
+
+ public:
+ FSProcess();
+ ~FSProcess();
+
+ bool Initialise(switch_loadable_module_interface_t *iface);
+
+ FSH323EndPoint & GetH323EndPoint() const { return *m_h323endpoint; }
+
+ protected:
+ FSH323EndPoint * m_h323endpoint;
+};
+
+struct FSListener {
+ FSListener() {
+ }
+
+ PString name;
+ H323ListenerTCP *listenAddress;
+ PString localUserName;
+ PString gatekeeper;
+};
+
+class FSH323EndPoint:public H323EndPoint {
+
+ PCLASSINFO(FSH323EndPoint, H323EndPoint);
+        public:
+                FSH323EndPoint();
+                
+                
+         /**Create a connection that uses the specified call.
+ */
+        virtual H323Connection* CreateConnection(
+                unsigned callReference,
+                void* userData,
+                H323Transport* transport,
+                H323SignalPDU* setupPDU
+        );
+        virtual bool OnSetGatewayPrefixes(PStringList & prefixes) const;
+        
+        bool Initialise(switch_loadable_module_interface_t *iface);
+        
+ switch_status_t ReadConfig(int reload);
+        
+        switch_endpoint_interface_t *GetSwitchInterface() const {
+ return m_freeswitch;
+ }
+        FSH323Connection * FSMakeCall(const PString & dest,void *userData);
+        list <FSListener> m_listeners;
+        
+        protected:
+                PStringList m_gkPrefixes;
+                switch_endpoint_interface_t *m_freeswitch;
+                PString m_gkAddress;
+                PString m_gkIdentifer;
+                PString m_gkInterface;
+                
+};
+
+class FSH323Connection:public H323Connection {
+ PCLASSINFO(FSH323Connection, H323Connection)
+
+ public:
+        FSH323Connection(FSH323EndPoint& endpoint,
+                                        H323Transport* transport,
+                                        unsigned callReference,
+                                        switch_caller_profile_t *outbound_profile,
+                                        switch_core_session_t *fsSession,
+                                        switch_channel_t *fsChannel);
+
+        ~FSH323Connection();                                
+
+        virtual H323Channel* CreateRealTimeLogicalChannel(
+                const H323Capability& capability,
+                H323Channel::Directions dir,
+                unsigned sessionID,
+                const H245_H2250LogicalChannelParameters* param,
+                RTP_QOS * rtpqos = NULL
+        );
+        virtual PBoolean OnStartLogicalChannel(H323Channel& channel);
+        virtual PBoolean OnCreateLogicalChannel(const H323Capability& capability, H323Channel::Directions dir, unsigned& errorCode);
+        virtual void OnReceivedReleaseComplete(const H323SignalPDU & pdu);
+        virtual        bool OnReceivedProgress(const H323SignalPDU &);
+        virtual bool OnSendReleaseComplete(H323SignalPDU & pdu);
+        virtual PBoolean OpenLogicalChannel(const H323Capability& capability, unsigned sessionID, H323Channel::Directions dir);
+ void setRemoteAddress(const char* remoteIP, WORD remotePort);
+        virtual void OnSetLocalCapabilities();
+        virtual bool OnAlerting(const H323SignalPDU &alertingPDU, const PString &user);
+        virtual void OnEstablished();
+        bool SetLocalCapabilities();
+        static bool decodeCapability(const H323Capability& capability, const char** dataFormat, int* payload = 0, PString* capabName = 0);
+        virtual H323Connection::AnswerCallResponse OnAnswerCall(const PString& caller,
+                                                const H323SignalPDU& signalPDU, H323SignalPDU& connectPDU);
+        virtual bool OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
+                                                                const H245_MultiplexCapability * muxCap,
+                                                                H245_TerminalCapabilitySetReject & reject);
+        switch_core_session_t *GetSession() const {
+ return m_fsSession;
+ }
+        virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
+        virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
+        virtual void OnUserInputString(const PString &value);
+        DECLARE_CALLBACK0(on_init);
+ DECLARE_CALLBACK0(on_routing);
+ DECLARE_CALLBACK0(on_execute);
+
+ DECLARE_CALLBACK0(on_exchange_media);
+ DECLARE_CALLBACK0(on_soft_execute);
+
+ DECLARE_CALLBACK1(kill_channel, int, sig);
+ DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf);
+ DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg);
+ DECLARE_CALLBACK1(receive_event, switch_event_t *, event);
+ DECLARE_CALLBACK0(state_change);
+
+        DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id);
+ DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id);
+ DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id);
+ DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id);
+        
+        bool m_callOnPreAnswer;
+        bool m_startRTP;
+        PSyncPoint m_rxAudioOpened;
+ PSyncPoint m_txAudioOpened;
+ protected:
+        FSH323EndPoint * m_endpoint;
+        PString m_remoteAddr;
+ int m_remotePort;
+        switch_core_session_t *m_fsSession;
+ switch_channel_t *m_fsChannel;
+        PIPSocket::Address m_RTPlocalIP;
+        WORD m_RTPlocalPort;
+        unsigned char m_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
+};
+
+class FSH323_ExternalRTPChannel : public H323_ExternalRTPChannel{
+ PCLASSINFO(FSH323_ExternalRTPChannel, H323_ExternalRTPChannel);
+public:
+ /* Create a new channel. */
+ FSH323_ExternalRTPChannel(
+                FSH323Connection& connection,
+                const H323Capability& capability,
+                Directions direction,
+                unsigned sessionID,
+                const PIPSocket::Address& ip,
+                WORD dataPort
+        );
+ /* Destructor */
+ ~FSH323_ExternalRTPChannel();
+
+ virtual PBoolean Start();
+ virtual PBoolean OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters& param);
+ virtual PBoolean OnSendingPDU(H245_H2250LogicalChannelParameters& param);
+ virtual PBoolean OnReceivedPDU(const H245_H2250LogicalChannelParameters& param,unsigned& errorCode);
+ virtual void OnSendOpenAck(H245_H2250LogicalChannelAckParameters& param);
+        
+
+private:
+ FSH323Connection* m_conn;
+        const H323Capability* m_capability;
+        switch_core_session_t *m_fsSession;
+        switch_channel_t *m_fsChannel;
+        switch_codec_t *m_switchCodec;
+        OpalMediaFormat *m_format;
+        switch_frame_t m_readFrame;
+        switch_timer_t *m_switchTimer;
+        PString m_RTPremoteIP;
+        WORD m_RTPremotePort;
+        PString m_RTPlocalIP;
+        WORD m_RTPlocalPort;
+        BYTE payloadCode;
+        
+};
+
+class BaseG7231Capab : public H323AudioCapability
+{
+ PCLASSINFO(BaseG7231Capab, H323AudioCapability);
+public:
+ BaseG7231Capab(const char* fname, bool annexA = true)
+        : H323AudioCapability(7,4), m_name(fname), m_aa(annexA)
+        { }
+        
+ virtual PObject* Clone() const{
+                return new BaseG7231Capab(*this);
+        }
+        
+ virtual unsigned GetSubType() const{
+                return H245_AudioCapability::e_g7231;
+        }
+        
+ virtual PString GetFormatName() const{
+                return m_name;
+        }
+        
+ virtual H323Codec* CreateCodec(H323Codec::Direction direction) const{
+                return 0;
+        }
+        
+ virtual Comparison Compare(const PObject& obj) const{
+         Comparison res = H323AudioCapability::Compare(obj);
+         if (res != EqualTo)
+                        return res;
+         bool aa = static_cast<const BaseG7231Capab&>(obj).m_aa;
+         if (aa && !m_aa)
+                        return LessThan;
+         if (m_aa && !aa)
+                        return GreaterThan;
+         return EqualTo;
+        }
+        
+ virtual bool OnSendingPDU(H245_AudioCapability& pdu, unsigned packetSize) const        {
+         pdu.SetTag(GetSubType());
+         H245_AudioCapability_g7231& g7231 = pdu;
+         g7231.m_maxAl_sduAudioFrames = packetSize;
+         g7231.m_silenceSuppression = m_aa;
+         return true;
+        }
+        
+ virtual bool OnReceivedPDU(const H245_AudioCapability& pdu, unsigned& packetSize){
+         if (pdu.GetTag() != H245_AudioCapability::e_g7231)
+                        return false;
+         const H245_AudioCapability_g7231& g7231 = pdu;
+         packetSize = g7231.m_maxAl_sduAudioFrames;
+         m_aa = (g7231.m_silenceSuppression != 0);
+         return true;
+        }
+
+protected:
+ const char* m_name;
+ bool m_aa;
+};
+
+class BaseG729Capab : public H323AudioCapability
+{
+ PCLASSINFO(BaseG729Capab, H323AudioCapability);
+public:
+ BaseG729Capab(const char* fname, unsigned type = H245_AudioCapability::e_g729)
+        : H323AudioCapability(24,6), m_name(fname), m_type(type)
+        { }
+ virtual PObject* Clone() const
+        // default copy constructor - take care!
+        { return new BaseG729Capab(*this); }
+ virtual unsigned GetSubType() const
+        { return m_type; }
+ virtual PString GetFormatName() const
+        { return m_name; }
+ virtual H323Codec* CreateCodec(H323Codec::Direction direction) const
+        { return 0; }
+protected:
+ const char* m_name;
+ unsigned m_type;
+};
+
+class BaseGSM0610Cap : public H323AudioCapability
+{
+        PCLASSINFO(BaseGSM0610Cap, H323AudioCapability);
+
+public:
+        
+        BaseGSM0610Cap(const char* fname, unsigned type = H245_AudioCapability::e_gsmFullRate)
+        : H323AudioCapability(24,2), m_name(fname), m_type(type),m_comfortNoise(0),m_scrambled(0)
+        { }
+        
+        virtual PObject * Clone() const{
+                return new BaseGSM0610Cap(*this);
+        }
+
+        virtual H323Codec* CreateCodec(H323Codec::Direction direction) const{
+                return 0;
+        }
+
+        virtual unsigned GetSubType() const{
+                return H245_AudioCapability::e_gsmFullRate;
+        }
+
+        virtual PString GetFormatName() const{
+                return m_name;
+        }
+
+        virtual bool OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const{
+                pdu.SetTag(H245_AudioCapability::e_gsmFullRate);
+                H245_GSMAudioCapability & gsm = pdu;
+                gsm.m_audioUnitSize = packetSize * 33;
+                gsm.m_comfortNoise = m_comfortNoise;
+                gsm.m_scrambled = m_scrambled;
+                return true;
+        }
+        
+        virtual bool OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize){
+                PTRACE(2, "mod_h323\t==============>BaseGSM0610Cap::OnReceivedPDU");
+                if (pdu.GetTag() != H245_AudioCapability::e_gsmFullRate)
+                        return false;
+                const H245_GSMAudioCapability & gsm = pdu;
+                packetSize = (gsm.m_audioUnitSize + 32) / 33;
+                m_comfortNoise = gsm.m_comfortNoise;
+                m_scrambled = gsm.m_scrambled;
+                return true;
+        }
+
+protected:
+        const char* m_name;
+        int m_comfortNoise;
+        int m_scrambled;
+        unsigned m_type;
+};
+
+
+#define DEFINE_H323_CAPAB(cls,base,param,name) \
+class cls : public base { \
+ public: \
+ cls() : base(name,param) { } \
+}; \
+H323_REGISTER_CAPABILITY(cls,name) \
+
+
+DEFINE_H323_CAPAB(FS_G7231_5,BaseG7231Capab,false,OPAL_G7231_5k3"{sw}")
+DEFINE_H323_CAPAB(FS_G7231_6,BaseG7231Capab,false,OPAL_G7231_6k3"{sw}")
+DEFINE_H323_CAPAB(FS_G7231A_5,BaseG7231Capab,true,OPAL_G7231A_5k3"{sw}")
+DEFINE_H323_CAPAB(FS_G7231A_6,BaseG7231Capab,true,OPAL_G7231A_6k3"{sw}")
+DEFINE_H323_CAPAB(FS_G729,BaseG729Capab,H245_AudioCapability::e_g729,OPAL_G729"{sw}")
+DEFINE_H323_CAPAB(FS_G729A,BaseG729Capab,H245_AudioCapability::e_g729AnnexA,OPAL_G729A"{sw}")
+DEFINE_H323_CAPAB(FS_G729B,BaseG729Capab,H245_AudioCapability::e_g729wAnnexB,OPAL_G729B"{sw}")
+DEFINE_H323_CAPAB(FS_G729AB,BaseG729Capab,H245_AudioCapability::e_g729AnnexAwAnnexB,OPAL_G729AB"{sw}")
+DEFINE_H323_CAPAB(FS_GSM,BaseGSM0610Cap,H245_AudioCapability::e_gsmFullRate,OPAL_GSM0610"{sw}")
+
+static FSProcess *h323_process = NULL;
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>