diff --git a/src/mod/endpoints/mod_h323/Makefile b/src/mod/endpoints/mod_h323/Makefile
new file mode 100644
index 0000000000..e38e8b6e97
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/Makefile
@@ -0,0 +1,5 @@
+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
diff --git a/src/mod/endpoints/mod_h323/bugs b/src/mod/endpoints/mod_h323/bugs
new file mode 100644
index 0000000000..8e08697df2
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/bugs
@@ -0,0 +1,2 @@
+faststart and codecs v CallProceeding due to h323plus, grep "Very Frustrating - S.H." in h323plus
+source and uncomment commented lines.
\ No newline at end of file
diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt
new file mode 100644
index 0000000000..1bc56e60de
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/changes.txt
@@ -0,0 +1,10 @@
+
+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.
diff --git a/src/mod/endpoints/mod_h323/h323.conf.xml b/src/mod/endpoints/mod_h323/h323.conf.xml
new file mode 100644
index 0000000000..0a0fb09587
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/h323.conf.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp
new file mode 100644
index 0000000000..ac04599b32
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/mod_h323.cpp
@@ -0,0 +1,1485 @@
+
+
+#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(¶ms, 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(¶ms);
+
+ 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 = "< 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 = "<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 = "<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 '"<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; idestination_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()<<"',"<FSH323Connection::OnReceivedReleaseComplete cause = "<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 = "<FSH323Connection::OpenLogicalChannel ('"<< (const char *)capability.GetFormatName()<<"', "<< sessionID<<", "<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 = "< 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 ="<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 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 = "<read_frame.source<< "\n packetlen = "<read_frame.packetlen<<"\n datalen = "<read_frame.datalen<<"\n samples = "<read_frame.samples<<"\n rate = "<read_frame.rate<<"\n payload = "<<(int)tech_pvt->read_frame.payload<<"\n timestamp = "<read_frame.timestamp<<"\n seq = "<read_frame.seq<<"\n ssrc = "<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.GetFormatName() return = "<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 = "<GetFrameSize());
+ PTRACE(4, "mod_h323\t------------------->GetFrameTime() return = "<GetFrameTime());
+ PTRACE(4, "mod_h323\t------------------->payloadCode = "<<(int)payloadCode);
+ PTRACE(4, "mod_h323\t------------------->m_capability->GetTxFramesInPacket() return = "<GetTxFramesInPacket());
+ PTRACE(4, "mod_h323\t------------------->m_capability->GetFormatName() return = "<GetFormatName());
+
+ PTRACE(4, "mod_h323\t------------------->GetH245CodecName() return = "<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 = "<rtp_session);
+ PTRACE(4, "mod_h323\t------------------->samples_per_packet = "<implementation->samples_per_packet);
+ PTRACE(4, "mod_h323\t------------------->actual_samples_per_second = "<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 = "<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 "<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()<<":"<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 = "< 0) {
+ H323TransportAddress taddr = listeners[0].GetTransportAddress();
+ PIPSocket::Address addr;
+ WORD port;
+ if (taddr.GetIpAndPort(addr, port)) {
+ if (addr) {
+ PTRACE(4, "mod_h323\t----> Using "< 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 = "<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 = "<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;
+}
+
+
+
+
+
+
+
+
diff --git a/src/mod/endpoints/mod_h323/mod_h323.h b/src/mod/endpoints/mod_h323/mod_h323.h
new file mode 100644
index 0000000000..727169e3c7
--- /dev/null
+++ b/src/mod/endpoints/mod_h323/mod_h323.h
@@ -0,0 +1,431 @@
+
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility push(default)
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+
+#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
+#pragma GCC visibility pop
+#endif
+
+#undef strcasecmp
+#undef strncasecmp
+
+#define HAVE_APR
+#include
+#include
+#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 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(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;