/* Version 0.0.11 */ #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", "G.723", "G723", "G.729B", "G729b", "G.729", "G729", "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", 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 H323Capability* cap){ switch (cap->GetSubType()) { 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); DisableFastStart(!m_faststart); DisableH245Tunneling(!m_h245tunneling); DisableH245inSetup(!m_h245insetup); 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); } } } if (!m_gkAddress.IsEmpty() && !m_gkIdentifer.IsEmpty() && !m_gkInterface.IsEmpty()) { m_thread = new FSGkRegThread(this,&m_gkAddress,&m_gkIdentifer,&m_gkInterface,m_gkretry); m_thread->SetAutoDelete(); m_thread->Resume(); } 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, "faststart")) { m_faststart = switch_true(val); } else if (!strcasecmp(var, "h245tunneling")) { m_h245tunneling = switch_true(val); } else if (!strcasecmp(var, "h245insetup")) { m_h245insetup = switch_true(val); } 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); } else if (!strcasecmp(var, "gk-retry")) { m_gkretry = atoi(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"); 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() :m_faststart(true) ,m_h245tunneling(true) ,m_h245insetup(true) { PTRACE(4, "mod_h323\t======>FSH323EndPoint::FSH323EndPoint [" << *this<<"]"); terminalType = e_GatewayOnly; } FSH323EndPoint::~FSH323EndPoint(){ PTRACE(4, "mod_h323\t======>FSH323EndPoint::~FSH323EndPoint [" << *this<<"]"); StopGkClient(); } 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; } void FSH323EndPoint::StartGkClient(int retry, PString* gkAddress,PString* gkIdentifer,PString* gkInterface){ PTRACE(4, "mod_h323\t======>FSH323EndPoint::StartGkClient [" << *this<<"]"); while(!UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface) && retry > 0 ){ 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); switch_yield(retry*1000); } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n", (const char *)GetGatekeeper()->GetName()); m_thread = 0; } void FSH323EndPoint::StopGkClient(){ PTRACE(4, "mod_h323\t======> FSH323EndPoint::StopGkClient [" << *this<<"]"); if (m_thread) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper thread\n"); RemoveGatekeeper(); m_thread->Terminate(); m_thread = 0; } } 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) , m_rxChennel(false) , m_txChennel(false) , m_ChennelAnswer(false) , m_ChennelProgress(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 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 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 ["<<*this<<"]"); if ((m_rxChennel && m_txChennel) || (m_ChennelProgress && m_rxChennel)) switch_channel_mark_pre_answered(m_fsChannel); else{ m_ChennelProgress = true; } 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<<"]"); switch_status_t status = switch_channel_mark_ring_ready(m_fsChannel); PTRACE(4, "mod_h323\t----------->OnAlerting return = "<PFSH323Connection::OnEstablished ["<<*this<<"]"); if(m_startRTP) switch_channel_mark_answered(m_fsChannel); else m_ChennelAnswer = true; } 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: 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(AnswerCallPending); break; } case SWITCH_MESSAGE_INDICATE_DEFLECT:{ break; } case SWITCH_MESSAGE_INDICATE_PROGRESS:{ AnsweringCall(AnswerCallPending); AnsweringCall(AnswerCallDeferredWithMedia); if (m_txChennel && m_rxChennel) if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) { switch_channel_mark_pre_answered(m_fsChannel); } else m_callOnPreAnswer = true; 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); if (m_txChennel && m_rxChennel) 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); } else m_ChennelAnswer = true; 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; 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_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); } /////////////////////////////////////////////////////////////////////// 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 = "<read_codec : &tech_pvt->vid_read_codec; m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer; m_conn->m_rxChennel = true; }else{ m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec; m_conn->m_txChennel = true; } 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), 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), 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"); } } if (m_conn->m_ChennelProgress && (GetDirection() == IsReceiver)){ if (isAudio) { switch_core_session_set_write_codec(m_fsSession, m_switchCodec); } } 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; } } PTRACE(4, "mod_h323\t------------->External RTP address "<h323_mutex); if ( m_conn->m_ChennelAnswer && m_conn->m_rxChennel && m_conn->m_txChennel) switch_channel_mark_answered(m_fsChannel); if ((m_conn->m_ChennelProgress && m_conn->m_rxChennel)||(m_conn->m_callOnPreAnswer && m_conn->m_txChennel)) switch_channel_mark_pre_answered(m_fsChannel); 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; 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::MakeCall(dest, token, userData))) { return NULL; } 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; } *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; }