diff --git a/src/mod/endpoints/mod_h323/changes.txt b/src/mod/endpoints/mod_h323/changes.txt index f49fd770da..aeeab5414e 100644 --- a/src/mod/endpoints/mod_h323/changes.txt +++ b/src/mod/endpoints/mod_h323/changes.txt @@ -1,3 +1,6 @@ +initial t.38 support. +remake logical channel opening. +add missing param name in example config. add dtmfinband conf parameter. add endpoint-name conf parameter represents endpoint name. fix GK registration retrying in case of registration reject. diff --git a/src/mod/endpoints/mod_h323/h323.conf.xml b/src/mod/endpoints/mod_h323/h323.conf.xml index 63fc21ec21..705da48b85 100644 --- a/src/mod/endpoints/mod_h323/h323.conf.xml +++ b/src/mod/endpoints/mod_h323/h323.conf.xml @@ -14,6 +14,7 @@ + diff --git a/src/mod/endpoints/mod_h323/mod_h323.cpp b/src/mod/endpoints/mod_h323/mod_h323.cpp index f005ddaa2c..25f70cb8b6 100644 --- a/src/mod/endpoints/mod_h323/mod_h323.cpp +++ b/src/mod/endpoints/mod_h323/mod_h323.cpp @@ -1,9 +1,10 @@ /* - Version 0.0.22 + Version 0.0.25 */ #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); @@ -38,6 +39,47 @@ static const char* h323_formats[] = { 0 }; +static char encodingName_COR[7] = "t38"; +static char encodingName_PRE[7] = "t38pre"; + +void SetT38_IFP_PRE() +{ + strcpy(encodingName_COR, "t38cor"); + strcpy(encodingName_PRE, "t38"); +} + +const OpalMediaFormat & GetOpalT38_IFP_COR() +{ + static const OpalMediaFormat opalT38_IFP( + "T.38-IFP-COR", + OpalMediaFormat::DefaultDataSessionID, + RTP_DataFrame::IllegalPayloadType, + encodingName_COR, + FALSE, // No jitter for data + 1440, // 100's bits/sec + 0, + 0, + 0); + + return opalT38_IFP; +} + +const OpalMediaFormat & GetOpalT38_IFP_PRE() +{ + static const OpalMediaFormat opalT38_IFP( + "T.38-IFP-PRE", + OpalMediaFormat::DefaultDataSessionID, + RTP_DataFrame::IllegalPayloadType, + encodingName_PRE, + FALSE, // No jitter for data + 1440, // 100's bits/sec + 0, + 0, + 0); + + return opalT38_IFP; +} + static switch_status_t on_hangup(switch_core_session_t *session); static switch_status_t on_destroy(switch_core_session_t *session); @@ -71,7 +113,7 @@ static switch_state_handler_table_t h323fs_event_handlers = { 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"); + 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) { @@ -110,6 +152,7 @@ void h_timer(unsigned sec){ select(NULL, NULL, NULL, NULL, &timeout); } + #if PTRACING class FSTrace : public ostream { @@ -250,12 +293,16 @@ PString GetH245CodecName(const H323Capability* cap){ case H245_AudioCapability::e_gsmEnhancedFullRate: return "GSM"; } - return "Unknown"; + return "L16"; } FSProcess::FSProcess() : PLibraryProcess("Test", "mod_h323", 1, 0, AlphaCode, 1) , m_h323endpoint(NULL){ + + PTrace::SetLevel(10); + PTrace::SetOptions(PTrace::TraceLevel); + PTrace::SetStream(new FSTrace); } FSProcess::~FSProcess(){ @@ -273,9 +320,7 @@ 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; @@ -312,7 +357,7 @@ bool FSH323EndPoint::Initialise(switch_loadable_module_interface_t *iface){ } } - + SetCapability(0, 0, new FSH323_T38Capability(OpalT38_IFP_PRE)); AddAllUserInputCapabilities(0,1); PTRACE(1, "OpenPhone\tCapability Table:\n" << setprecision(4) << capabilities); @@ -369,6 +414,7 @@ switch_status_t FSH323EndPoint::ReadConfig(int reload){ switch_xml_t xmlSettings = switch_xml_child(cfg, "settings"); m_pi = 8; m_ai = 0; + m_endpointname = "FreeSwitch"; 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"); @@ -570,7 +616,11 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran , m_txChennel(false) , m_ChennelAnswer(false) , m_ChennelProgress(false) - , m_select_dtmf(0){ + , m_select_dtmf(0) + , m_active_sessionID(0) + , m_active_chennel_fax(false) + , m_rtp_resetting(0) + , m_isRequst_fax(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)); @@ -579,6 +629,7 @@ FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* tran 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)); + switch_mutex_init(&tech_pvt->h323_io_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession)); if (outbound_profile != NULL) { SetLocalPartyName(outbound_profile->caller_id_number); @@ -777,8 +828,8 @@ H323Channel* FSH323Connection::CreateRealTimeLogicalChannel(const H323Capability PBoolean FSH323Connection::OnStartLogicalChannel(H323Channel & channel){ PTRACE(4, "mod_h323\t======>FSH323Connection::OnStartLogicalChannel chennel = "<<&channel<<" ["<<*this<<"]"); - - return true; + PTRACE(4, "mod_h323\t======>FSH323Connection::OnStartLogicalChannel connectionState = "<FSH323Connection::OnReceivedSignalSetup ["<<*this<<"]"); - +// Lock(); if (!H323Connection::OnReceivedSignalSetup(setupPDU)) return false; - + PTRACE(4, "mod_h323\t---------> after FSH323Connection::OnReceivedSignalSetup connectionState = "< after callProceedingPDU.BuildCallProceeding connectionState = "< connectionState = ShuttingDownConnection ["<<*this<<"]"); +// Unlock(); + return false; + } if (SendFastStartAcknowledge(callProceeding.m_fastStart)){ callProceeding.IncludeOptionalField(H225_CallProceeding_UUIE::e_fastStart); } else { PTRACE(2, "H323\tSendFastStartAcknowledge = FALSE "); if (connectionState == ShuttingDownConnection){ +// Unlock(); return true; } earlyStart = TRUE; if (!h245Tunneling && (controlChannel == NULL)) { if (!StartControlChannel()){ +// Unlock(); return true; } callProceeding.IncludeOptionalField(H225_CallProceeding_UUIE::e_h245Address); controlChannel->SetUpTransportPDU(callProceeding.m_h245Address, TRUE); } } - - if (!WriteSignalPDU(callProceedingPDU)) + if (connectionState == ShuttingDownConnection){ +// Unlock(); + return true; + } + + if (!WriteSignalPDU(callProceedingPDU)){ +// Unlock(); return false; - + } +// Unlock(); return true; } @@ -874,7 +939,9 @@ bool FSH323Connection::OnSendReleaseComplete(H323SignalPDU & pdu) PBoolean FSH323Connection::OpenLogicalChannel(const H323Capability& capability, unsigned sessionID, H323Channel::Directions dir){ PTRACE(4, "mod_h323\t======>FSH323Connection::OpenLogicalChannel ('"<< (const char *)capability.GetFormatName()<<"', "<< sessionID<<", "<FSH323Connection::OnReceivedCapabilitySet ["<<*this<<"]"); + if (connectionState == ShuttingDownConnection) + return false; if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) { return false; } @@ -900,7 +969,7 @@ bool FSH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa } PTRACE(4, "mod_h323\t----> Capabilities not NULL "); - return true; + return connectionState != ShuttingDownConnection; } @@ -1016,9 +1085,107 @@ void FSH323Connection::OnEstablished(){ if(m_startRTP) switch_channel_mark_answered(m_fsChannel); else m_ChennelAnswer = true; + if (m_active_chennel_fax) + RequestModeChangeT38(); + else + m_active_chennel_fax = true; +} +PBoolean FSH323Connection::OnRequestModeChange(const H245_RequestMode & pdu, + H245_RequestModeAck & /*ack*/, + H245_RequestModeReject & /*reject*/, + PINDEX & selectedMode) +{ + h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession); + switch_mutex_lock(tech_pvt->h323_mutex); + PTRACE(4, "mod_h323\t======>PFSH323Connection::OnRequestModeChange ["<<*this<<"]"); + if (!m_isRequst_fax){ + m_isRequst_fax = true; + switch_mutex_unlock(tech_pvt->h323_mutex); + return true; + } + return false; + switch_mutex_unlock(tech_pvt->h323_mutex); } +void FSH323Connection::OnModeChanged(const H245_ModeDescription & newMode){ + PTRACE(4, "mod_h323\t======>PFSH323Connection::OnModeChanged ["<<*this<<"]"); + for (PINDEX i = 0; i < newMode.GetSize(); i++) { + H323Capability * capability = localCapabilities.FindCapability(newMode[i]); + if (PAssertNULL(capability) != NULL) { + PTRACE(1, "mod_h323\tOpen channel after mode change: " << *capability); + if (capability->GetMainType() == H323Capability::e_Data){ + PTRACE(1, "mod_h323\tcapability->GetMainType() = H323Capability::e_Data"); + H245_DataMode & type = newMode[i].m_type; + if (type.m_application.GetTag() == H245_DataMode_application::e_t38fax){ + PTRACE(1, "mod_h323\ttype.m_application.GetTag() = H245_DataMode_application::e_t38fax"); + H245_DataMode_application_t38fax & fax = type.m_application; + H245_DataProtocolCapability & proto = fax.m_t38FaxProtocol; + const H245_T38FaxProfile & profile = fax.m_t38FaxProfile; + switch_t38_options_t* t38_options = (switch_t38_options_t*)switch_channel_get_private(m_fsChannel, "t38_options"); + if (!t38_options) { + t38_options = (switch_t38_options_t*)switch_core_session_alloc(m_fsSession, sizeof(* t38_options)); + PTRACE(1, "mod_h323\tswitch_core_session_alloc t38_options"); + } + +// t38_options->port = 0; +// t38_options->ip = NULL; + t38_options->T38VendorInfo = "0 0 0"; + + t38_options->T38FaxVersion = profile.m_version; + PTRACE(1, "mod_h323\tT38FaxVersion:"<T38MaxBitRate = type.m_bitRate*100; + PTRACE(1, "mod_h323\tT38MaxBitRate:"<T38MaxBitRate); + if (profile.m_fillBitRemoval) + t38_options->T38FaxFillBitRemoval = SWITCH_TRUE; + PTRACE(1, "mod_h323\tT38FaxFillBitRemoval:"<T38FaxTranscodingMMR = SWITCH_TRUE; + PTRACE(1, "mod_h323\tT38FaxTranscodingMMR:"<T38FaxTranscodingJBIG = SWITCH_TRUE; + PTRACE(1, "mod_h323\tT38FaxTranscodingJBIG:"<T38FaxRateManagement = "transferredTCF"; + else + t38_options->T38FaxRateManagement = "localTCF"; + PTRACE(1, "mod_h323\tT38FaxRateManagement:"<T38FaxRateManagement); + t38_options->T38FaxMaxBuffer = profile.m_t38FaxUdpOptions.m_t38FaxMaxBuffer; + PTRACE(1, "mod_h323\tT38FaxMaxBuffer:"<T38FaxMaxDatagram = profile.m_t38FaxUdpOptions.m_t38FaxMaxDatagram; + PTRACE(1, "mod_h323\tT38FaxMaxDatagram:"<T38FaxUdpEC = "t38UDPFEC"; + else + t38_options->T38FaxUdpEC = "t38UDPRedundancy"; + PTRACE(1, "mod_h323\tT38FaxUdpEC:"<T38FaxUdpEC); + const char *uuid = switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE); + if (uuid != NULL){ + PTRACE(1, "mod_h323\t uuid:"<PFSH323Connection::setRemoteAddress remoteIP ="<rtp_session)) { + PTRACE(3, "mod_h323\t--->Kill soket" << *this); switch_rtp_kill_socket(tech_pvt->rtp_session); } break; @@ -1104,11 +1272,20 @@ void FSH323Connection::OnUserInputString(const PString &value) } } +void FSH323Connection::CleanUpOnCall(){ + PTRACE(4, "mod_h323\t======>FSH323Connection::CleanUpOnCall [" << *this<<"]"); +// Lock(); + connectionState = ShuttingDownConnection; +// Unlock(); + PTRACE(4, "mod_h323\t<======FSH323Connection::CleanUpOnCall [" << *this<<"]"); +} switch_status_t FSH323Connection::receive_message(switch_core_session_message_t *msg){ PTRACE(4, "mod_h323\t======>FSH323Connection::receive_message MSG=" << msg->message_id); +// Lock(); +// Unlock(); switch_channel_t *channel = switch_core_session_get_channel(m_fsSession); - + h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession); switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_BRIDGE: case SWITCH_MESSAGE_INDICATE_UNBRIDGE: @@ -1138,7 +1315,9 @@ switch_status_t FSH323Connection::receive_message(switch_core_session_message_t } else { m_callOnPreAnswer = true; if (fastStartState == FastStartDisabled){ + PTRACE(4, "mod_h323\t-------------------->m_txAudioOpened.Wait START" << *this); m_txAudioOpened.Wait(); + PTRACE(4, "mod_h323\t-------------------->m_rxAudioOpened.Wait STOP" << *this); } } break; @@ -1152,18 +1331,49 @@ switch_status_t FSH323Connection::receive_message(switch_core_session_message_t 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); + PTRACE(4, "mod_h323\t-------------------->switch_channel_mark_answered(m_fsChannel) " << *this); switch_channel_mark_answered(m_fsChannel); } } else{ m_ChennelAnswer = true; if (fastStartState == FastStartDisabled){ + PTRACE(4, "mod_h323\t-------------------->m_txAudioOpened.Wait START" << *this); + PTRACE(4, "mod_h323\t-------------------->m_rxAudioOpened.Wait START" << *this); m_txAudioOpened.Wait(); m_rxAudioOpened.Wait(); + PTRACE(4, "mod_h323\t-------------------->m_txAudioOpened.Wait STOP" << *this); + PTRACE(4, "mod_h323\t-------------------->m_rxAudioOpened.Wait STOP" << *this); } } break; } + case SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA: { + PTRACE(3, "mod_h323\tReceived message SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA on connection " << *this); + switch_mutex_lock(tech_pvt->h323_mutex); + if (!m_isRequst_fax) + m_isRequst_fax = true; + switch_mutex_unlock(tech_pvt->h323_mutex); + if (m_active_chennel_fax) + RequestModeChangeT38(); + else + m_active_chennel_fax = true; + break; + } + case SWITCH_MESSAGE_INDICATE_UDPTL_MODE:{ + PTRACE(3, "mod_h323\tReceived message SWITCH_MESSAGE_INDICATE_UDPTL_MODE on connection " << *this); + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_rtp_udptl_mode(tech_pvt->rtp_session); + } + break; + } + case SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION:{ + PTRACE(3, "mod_h323\tReceived message SWITCH_MESSAGE_INDICATE_T38_DESCRIPTION on connection " << *this); + if (switch_rtp_ready(tech_pvt->rtp_session)) { + switch_rtp_udptl_mode(tech_pvt->rtp_session); + } + break; + } + default:{ PTRACE(3, "mod_h323\tReceived message " << msg->message_id << " on connection " << *this); } @@ -1218,33 +1428,42 @@ switch_status_t FSH323Connection::read_audio_frame(switch_frame_t **frame, switc 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) { + switch_mutex_lock(tech_pvt->h323_io_mutex); + if (switch_test_flag(tech_pvt, TFLAG_IO)) { + if (!switch_core_codec_ready(&tech_pvt->read_codec )) { PTRACE(4, "mod_h323\t---------> RETURN"); switch_clear_flag_locked(tech_pvt, TFLAG_READING); + switch_mutex_unlock(tech_pvt->h323_io_mutex); 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 status = "<h323_io_mutex); + return status; + } + // 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 ; + } + }else{ + switch_mutex_unlock(tech_pvt->h323_io_mutex); + PTRACE(4, "mod_h323\t--------->TFLAG_IO OFF"); + switch_yield(10000); } - 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_mutex_unlock(tech_pvt->h323_io_mutex); switch_clear_flag_locked(tech_pvt, TFLAG_READING); *frame = &tech_pvt->read_frame; @@ -1315,12 +1534,13 @@ FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel( , m_conn(&connection) , m_fsSession(connection.GetSession()) , m_capability(&capability) - , m_RTPlocalPort(dataPort){ - + , m_RTPlocalPort(dataPort) + , m_sessionID(sessionID){ + 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<<"]"); + PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel sessionID="<FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel "<< GetDirection()<<" "<<*this); - h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession); - if (IsRunning()){ + switch_mutex_lock(tech_pvt->h323_mutex); + PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel "<< GetDirection()<<" "<<*this); +/* if (IsRunning()){ PTRACE(4, "mod_h323\t------------->Running"); - if (switch_rtp_ready(tech_pvt->rtp_session)) { - switch_rtp_kill_socket(tech_pvt->rtp_session); + PTRACE(4, "mod_h323\t------------->m_sessionID = "<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())) + + PTRACE(4, "mod_h323\t------------->m_sessionID = "<Changing Codec to "<m_rxChennel = false; + m_conn->m_txChennel = false; + switch_core_session_lock_codec_read(m_fsSession); + switch_core_session_lock_codec_write(m_fsSession); + switch_mutex_lock(tech_pvt->h323_io_mutex); + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + switch_mutex_unlock(tech_pvt->h323_io_mutex); + m_conn->m_rtp_resetting = 1; + switch_core_codec_destroy(&tech_pvt->read_codec); + switch_core_codec_destroy(&tech_pvt->write_codec); + switch_rtp_destroy(&tech_pvt->rtp_session); + m_conn->m_startRTP = false; + } + } + m_conn->m_active_sessionID = sessionID; 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"); - } - + unsigned m_codec_ms = m_capability->GetTxFramesInPacket(); + switch (m_capability->GetMainType()){ + case H323Capability::e_Audio:{ + PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Audio"); + isAudio = true; + break; + } + case H323Capability::e_Video:{ + PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Video"); + isAudio = false; + break; + } + case H323Capability::e_Data:{ + PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Data"); + isAudio = true; + m_codec_ms = 20; + switch_channel_set_app_flag(m_fsChannel, CF_APP_T38); + break; + } + default:break; + } 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_codec_ms return = "<m_capability->GetFormatName() return = "<GetFormatName()); PTRACE(4, "mod_h323\t------------------->GetH245CodecName() return = "<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 (m_conn->m_callOnPreAnswer){ + 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 + 8000, m_codec_ms, 1, // Channels SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { @@ -1412,9 +1684,10 @@ PBoolean FSH323_ExternalRTPChannel::Start(){ 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); + switch_mutex_unlock(tech_pvt->h323_mutex); return false; } - PTRACE(2, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Unsupported ptime of " << m_capability->GetTxFramesInPacket() << " on " << ((GetDirection() == IsReceiver)? " read" : " write") << ' ' + PTRACE(2, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Unsupported ptime of " << m_codec_ms << " on " << ((GetDirection() == IsReceiver)? " read" : " write") << ' ' << m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this); } @@ -1434,9 +1707,12 @@ PBoolean FSH323_ExternalRTPChannel::Start(){ switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) { switch_core_codec_destroy(m_switchCodec); m_switchCodec = NULL; + switch_mutex_unlock(tech_pvt->h323_mutex); return false; } switch_channel_set_variable(m_fsChannel,"timer_name","soft"); + if (m_conn->m_ChennelProgress) + switch_core_session_set_write_codec(m_fsSession, m_switchCodec); } else { switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec); switch_channel_set_flag(m_fsChannel, CF_VIDEO); @@ -1444,40 +1720,31 @@ PBoolean FSH323_ExternalRTPChannel::Start(){ } else { if (isAudio) { switch_core_session_set_write_codec(m_fsSession, m_switchCodec); + if (m_conn->m_callOnPreAnswer){ + m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second; + 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; + switch_mutex_unlock(tech_pvt->h323_mutex); + return false; + } + switch_channel_set_variable(m_fsChannel,"timer_name","soft"); + } } 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); + PTRACE(4, "mod_h323\t------------->h323_mutex_lock"); + PIPSocket::Address remoteIpAddress; GetRemoteAddress(remoteIpAddress,m_RTPremotePort); @@ -1499,15 +1766,13 @@ PBoolean FSH323_ExternalRTPChannel::Start(){ m_RTPremotePort, (switch_payload_t)payloadCode, m_switchCodec->implementation->samples_per_packet, - m_capability->GetTxFramesInPacket() * 1000, + m_codec_ms * 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); @@ -1517,17 +1782,46 @@ PBoolean FSH323_ExternalRTPChannel::Start(){ } PTRACE(4, "mod_h323\t------------->External RTP address "<h323_mutex); + PTRACE(4, "mod_h323\t------------->h323_mutex_unlock"); + + if (m_conn->m_rtp_resetting) { + if (GetDirection() == IsReceiver) + switch_core_session_unlock_codec_read(m_fsSession); + else{ + switch_core_session_unlock_codec_write(m_fsSession); + if (m_conn->m_callOnPreAnswer) + switch_core_session_unlock_codec_read(m_fsSession); + } + } if (GetDirection() == IsReceiver) m_conn->m_rxAudioOpened.Signal(); else m_conn->m_txAudioOpened.Signal(); - if ( m_conn->m_ChennelAnswer && m_conn->m_rxChennel && m_conn->m_txChennel) - switch_channel_mark_answered(m_fsChannel); + 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)) + if ((m_conn->m_ChennelProgress && m_conn->m_rxChennel)||(m_conn->m_callOnPreAnswer && m_conn->m_txChennel)){ switch_channel_mark_pre_answered(m_fsChannel); - + } + + PTRACE(4, "mod_h323\t------------->h323_io_mutex_lock"); + switch_mutex_lock(tech_pvt->h323_io_mutex); + switch_set_flag_locked(tech_pvt, TFLAG_IO); + switch_mutex_unlock(tech_pvt->h323_io_mutex); + PTRACE(4, "mod_h323\t------------->h323_io_mutex_unlock"); + if ((m_capability->GetMainType() == H323Capability::e_Data) && m_conn->m_rxChennel && m_conn->m_txChennel ) { + const char *uuid = switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE); + if (uuid != NULL){ + PTRACE(4, "mod_h323\t------------------------->switch_rtp_udptl_mode"); + switch_rtp_udptl_mode(tech_pvt->rtp_session); + switch_core_session_message_t msg = { 0 }; + msg.from = switch_channel_get_name(m_fsChannel); + msg.message_id = SWITCH_MESSAGE_INDICATE_UDPTL_MODE; + switch_core_session_message_send(uuid,&msg); + } + } + switch_mutex_unlock(tech_pvt->h323_mutex); return true; } @@ -1648,11 +1942,11 @@ static switch_status_t on_hangup(switch_core_session_t *session){ 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----->"); + if (tech_pvt->me) { + PTRACE(4, "mod_h323\t----->"<<(const char *)(tech_pvt->me->GetCallToken())); 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->SetQ931Cause(cause); + tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX)); tech_pvt->me = NULL; } diff --git a/src/mod/endpoints/mod_h323/mod_h323.h b/src/mod/endpoints/mod_h323/mod_h323.h index 9d834496f9..d8b828f2ce 100644 --- a/src/mod/endpoints/mod_h323/mod_h323.h +++ b/src/mod/endpoints/mod_h323/mod_h323.h @@ -10,7 +10,10 @@ #include #include #include - +#include +#include "t38proto.h" +#include "t38.h" +#include #include @@ -25,8 +28,17 @@ #include #include #define MODNAME "mod_h323" +#define OpalT38_IFP_COR GetOpalT38_IFP_COR() +#define OpalT38_IFP_PRE GetOpalT38_IFP_PRE() +extern void SetT38_IFP_PRE(); +class OpalMediaFormat; +class H245_T38FaxProfile; +class OpalT38Protocol; +extern const OpalMediaFormat & GetOpalT38_IFP_COR(); +extern const OpalMediaFormat & GetOpalT38_IFP_PRE(); + typedef enum { TFLAG_IO = (1 << 0), TFLAG_INBOUND = (1 << 1), @@ -78,6 +90,7 @@ typedef struct { switch_rtp_t *rtp_session; switch_mutex_t *flag_mutex; switch_mutex_t *h323_mutex; + switch_mutex_t *h323_io_mutex; FSH323Connection *me; } h323_private_t; @@ -125,6 +138,7 @@ struct FSListener { }; class FSGkRegThread; +class OpalMediaFormat; class FSH323EndPoint:public H323EndPoint { PCLASSINFO(FSH323EndPoint, H323EndPoint); @@ -139,7 +153,7 @@ class FSH323EndPoint:public H323EndPoint { virtual bool OnSetGatewayPrefixes(PStringList & prefixes) const; bool Initialise(switch_loadable_module_interface_t *iface); - + switch_status_t ReadConfig(int reload); void StartGkClient(int retry, PString * gkAddress, PString * gkIdentifer, PString * gkInterface); @@ -152,7 +166,7 @@ class FSH323EndPoint:public H323EndPoint { int m_ai; int m_pi; protected: - PStringList m_gkPrefixes; + PStringList m_gkPrefixes; switch_endpoint_interface_t *m_freeswitch; PString m_gkAddress; PString m_gkIdentifer; @@ -191,9 +205,9 @@ class FSH323Connection:public 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(); + 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, @@ -212,33 +226,39 @@ class FSH323Connection:public H323Connection { virtual bool OnAlerting(const H323SignalPDU & alertingPDU, const PString & user); virtual void AnsweringCall(AnswerCallResponse response); virtual void OnEstablished(); + virtual void OnModeChanged(const H245_ModeDescription & newMode); + virtual bool OnRequestModeChange(const H245_RequestMode & pdu, + H245_RequestModeAck & ack, + H245_RequestModeReject & reject, + PINDEX & selectedMode); 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); + 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 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); + void CleanUpOnCall(); + + 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_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); + 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; @@ -249,15 +269,19 @@ class FSH323Connection:public H323Connection { unsigned char m_select_dtmf; PSyncPoint m_rxAudioOpened; PSyncPoint m_txAudioOpened; + unsigned m_active_sessionID; + bool m_active_chennel_fax; + int m_rtp_resetting; + bool m_isRequst_fax; protected: - FSH323EndPoint * m_endpoint; + FSH323EndPoint * m_endpoint; PString m_remoteAddr; int m_remotePort; switch_core_session_t *m_fsSession; switch_channel_t *m_fsChannel; - PIPSocket::Address m_RTPlocalIP; + PIPSocket::Address m_RTPlocalIP; WORD m_RTPlocalPort; - unsigned char m_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; + unsigned char m_buf[SWITCH_RECOMMENDED_BUFFER_SIZE]; }; @@ -278,7 +302,7 @@ class FSH323_ExternalRTPChannel:public H323_ExternalRTPChannel { private: - FSH323Connection * m_conn; + FSH323Connection * m_conn; const H323Capability *m_capability; switch_core_session_t *m_fsSession; switch_channel_t *m_fsChannel; @@ -290,8 +314,8 @@ class FSH323_ExternalRTPChannel:public H323_ExternalRTPChannel { WORD m_RTPremotePort; PString m_RTPlocalIP; WORD m_RTPlocalPort; - BYTE payloadCode; - + BYTE payloadCode; + unsigned m_sessionID; }; class BaseG7231Capab:public H323AudioCapability { @@ -342,17 +366,21 @@ class BaseG729Capab:public 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! + } + virtual PObject *Clone() const { return new BaseG729Capab(*this); - } virtual unsigned GetSubType() const { + } + virtual unsigned GetSubType() const { return m_type; - } virtual PString GetFormatName() const { + } + virtual PString GetFormatName() const { return m_name; - } virtual H323Codec *CreateCodec(H323Codec::Direction direction) const { + } + virtual H323Codec *CreateCodec(H323Codec::Direction direction) const { return 0; - } protected: + } + protected: const char *m_name; unsigned m_type; }; @@ -398,6 +426,58 @@ class BaseGSM0610Cap:public H323AudioCapability { }; +class FSH323_T38Capability : public H323_T38Capability +{ + PCLASSINFO(FSH323_T38Capability, H323_T38Capability); + public: + FSH323_T38Capability(const OpalMediaFormat &_mediaFormat) + : H323_T38Capability(e_UDP), + mediaFormat(_mediaFormat) { + } + virtual PObject * Clone() const { + return new FSH323_T38Capability(*this); + } + virtual PString GetFormatName() const { + return mediaFormat; + } + virtual H323Channel * CreateChannel( + H323Connection & connection, + H323Channel::Directions dir, + unsigned sessionID, + const H245_H2250LogicalChannelParameters * param ) const; + protected: + const OpalMediaFormat &mediaFormat; +}; + +class FSH323_T38CapabilityCor : public FSH323_T38Capability { + public: + FSH323_T38CapabilityCor() : FSH323_T38Capability(OpalT38_IFP_COR) {} +}; + +class FSH323_T38CapabilityPre : public FSH323_T38Capability { + public: + FSH323_T38CapabilityPre() : FSH323_T38Capability(OpalT38_IFP_PRE) {} +}; + +//H323_REGISTER_CAPABILITY(FSH323_T38CapabilityCor, OpalT38_IFP_COR) +//H323_REGISTER_CAPABILITY(FSH323_T38CapabilityPre, OpalT38_IFP_PRE) + + +H323Channel * FSH323_T38Capability::CreateChannel( + H323Connection & connection, + H323Channel::Directions direction, + unsigned int sessionID, + const H245_H2250LogicalChannelParameters * params) const +{ + PTRACE(1, "FSH323_T38Capability::CreateChannel " + << connection + << " sessionID=" << sessionID + << " direction=" << direction); + + return connection.CreateRealTimeLogicalChannel(*this, direction, sessionID, params); +} + + #define DEFINE_H323_CAPAB(cls,base,param,name) \ class cls : public base { \ public: \ @@ -406,17 +486,25 @@ class cls : public base { \ H323_REGISTER_CAPABILITY(cls,name) \ +#define DEFINE_H323_CAPAB_m(cls,base,name) \ +class cls : public base { \ + public: \ + cls() : base(name) { } \ +}; \ +H323_REGISTER_CAPABILITY(cls,name) \ +//DEFINE_H323_CAPAB_m(FS_T38_COR,FSH323_T38Capability,OpalT38_IFP_COR) +//DEFINE_H323_CAPAB_m(FS_T38_RPE,FSH323_T38Capability,OpalT38_IFP_PRE) + 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}") +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; +static FSProcess *h323_process = NULL;