]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
initial t.38 support.
authorroot <root@proxy-2.(none)>
Wed, 7 Jul 2010 16:22:56 +0000 (20:22 +0400)
committerroot <root@proxy-2.(none)>
Wed, 7 Jul 2010 16:22:56 +0000 (20:22 +0400)
remake logical channel opening.
add missing param name in example config.

src/mod/endpoints/mod_h323/changes.txt
src/mod/endpoints/mod_h323/h323.conf.xml
src/mod/endpoints/mod_h323/mod_h323.cpp
src/mod/endpoints/mod_h323/mod_h323.h

index f49fd770da5bdd071c4ab600e8b3a99da6e70f6a..aeeab5414e8993faf3a4dcf5abac9db1fc22b444 100644 (file)
@@ -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.
index 63fc21ec217094c3e094ae6b652063ce8b9c7ef6..705da48b852fb064d92472c32f8d8432f3c77780 100644 (file)
@@ -14,6 +14,7 @@
     <param name="jitter-size" value="60"/>  <!-- optional -->
     <param name="progress-indication" value="8"/> <!-- optional - PI value in progress message-->
     <param name="alerting-indication" value="8"/> <!-- optional - PI value in alerting message-->
+    <param name="endpoint-name" value="fs"/>
   </settings>
   <listeners>
     <listener name="default">
index f005ddaa2c2e3de8de6b2144705b60f32ec13190..25f70cb8b6fcaecd92a6093ccc9a67f4533b2ffa 100644 (file)
@@ -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  = "<<connectionState<<" ["<<*this<<"]");
+       return connectionState != ShuttingDownConnection;
 }
 
 PBoolean FSH323Connection::OnCreateLogicalChannel(const H323Capability& capability, H323Channel::Directions dir, unsigned& errorCode){
@@ -810,32 +861,46 @@ bool FSH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
 bool FSH323Connection::OnReceivedSignalSetup(const H323SignalPDU & setupPDU){
 
        PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedSignalSetup ["<<*this<<"]");
-       
+//     Lock();
        if (!H323Connection::OnReceivedSignalSetup(setupPDU)) return false;
-       
+       PTRACE(4, "mod_h323\t---------> after FSH323Connection::OnReceivedSignalSetup connectionState = "<<connectionState<<" ["<<*this<<"]");
        H323SignalPDU callProceedingPDU;
        H225_CallProceeding_UUIE & callProceeding = callProceedingPDU.BuildCallProceeding(*this);
+       PTRACE(4, "mod_h323\t---------> after callProceedingPDU.BuildCallProceeding connectionState = "<<connectionState<<" ["<<*this<<"]");
+       if (connectionState == ShuttingDownConnection){
+               PTRACE(4, "mod_h323\t---------> 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<<", "<<dir <<") "<<*this);
-    
+//    if (m_rxChennel &&  m_txChennel)
+//             return true;
+               
     return H323Connection::OpenLogicalChannel(capability,sessionID,dir);
 }
 
@@ -884,6 +951,8 @@ bool FSH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCa
                                                        H245_TerminalCapabilitySetReject & reject){
        
        PTRACE(4, "mod_h323\t======>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:"<<profile.m_version);
+                                       t38_options->T38MaxBitRate = type.m_bitRate*100;
+                                       PTRACE(1, "mod_h323\tT38MaxBitRate:"<<t38_options->T38MaxBitRate);
+                                       if (profile.m_fillBitRemoval) 
+                                               t38_options->T38FaxFillBitRemoval = SWITCH_TRUE;
+                                       PTRACE(1, "mod_h323\tT38FaxFillBitRemoval:"<<profile.m_fillBitRemoval);
+                                       if (profile.m_transcodingMMR)
+                                               t38_options->T38FaxTranscodingMMR = SWITCH_TRUE;
+                                       PTRACE(1, "mod_h323\tT38FaxTranscodingMMR:"<<profile.m_transcodingMMR);
+                                       if (profile.m_transcodingJBIG) 
+                                               t38_options->T38FaxTranscodingJBIG = SWITCH_TRUE;
+                                       PTRACE(1, "mod_h323\tT38FaxTranscodingJBIG:"<<profile.m_transcodingJBIG);
+                                       if (profile.m_t38FaxRateManagement.GetTag() == H245_T38FaxRateManagement::e_transferredTCF)
+                                               t38_options->T38FaxRateManagement = "transferredTCF";
+                                       else
+                                               t38_options->T38FaxRateManagement = "localTCF";
+                                       PTRACE(1, "mod_h323\tT38FaxRateManagement:"<<t38_options->T38FaxRateManagement);
+                                       t38_options->T38FaxMaxBuffer = profile.m_t38FaxUdpOptions.m_t38FaxMaxBuffer;
+                                       PTRACE(1, "mod_h323\tT38FaxMaxBuffer:"<<profile.m_t38FaxUdpOptions.m_t38FaxMaxBuffer);
+                                       t38_options->T38FaxMaxDatagram = profile.m_t38FaxUdpOptions.m_t38FaxMaxDatagram;
+                                       PTRACE(1, "mod_h323\tT38FaxMaxDatagram:"<<profile.m_t38FaxUdpOptions.m_t38FaxMaxDatagram);
+                                       if (profile.m_t38FaxUdpOptions.m_t38FaxUdpEC.GetTag() == H245_T38FaxUdpOptions_t38FaxUdpEC::e_t38UDPFEC)
+                                               t38_options->T38FaxUdpEC = "t38UDPFEC";
+                                       else
+                                               t38_options->T38FaxUdpEC = "t38UDPRedundancy";
+                                       PTRACE(1, "mod_h323\tT38FaxUdpEC:"<<t38_options->T38FaxUdpEC);
+                                       const char *uuid = switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE); 
+                                       if (uuid != NULL){
+                                               PTRACE(1, "mod_h323\t uuid:"<<uuid);
+                                               switch_channel_set_private(switch_core_session_get_channel(switch_core_session_locate(switch_channel_get_variable(m_fsChannel, SWITCH_SIGNAL_BOND_VARIABLE))), "t38_options", t38_options);
+                                       
+                                       
+                                               switch_core_session_message_t msg = { 0 };
+                                               int insist = 0;
+                                               const char *v;
+                                               if ((v = switch_channel_get_variable(m_fsChannel, "fax_enable_t38_insist"))) {
+                                                       insist = switch_true(v);
+                                               } 
+                                               msg.from = switch_channel_get_name(m_fsChannel);
+                                               msg.message_id = SWITCH_MESSAGE_INDICATE_REQUEST_IMAGE_MEDIA;
+                                               msg.numeric_arg = insist;
+                                               PTRACE(1, "mod_h323\tuuid:"<<switch_channel_get_uuid(switch_core_session_get_channel(switch_channel_get_session(m_fsChannel))));                                        
+                                               PTRACE(1, "mod_h323\tuuid:"<<uuid);
+                                               switch_core_session_message_send(uuid,&msg);
+                                       } else {
+                                               switch_channel_set_private(m_fsChannel, "t38_options", t38_options);
+                                       }
+                               }
+                       }
+               } 
+       }
+       H323Connection::OnModeChanged(newMode);
+}
 
 void FSH323Connection::setRemoteAddress(const char* remoteIP, WORD remotePort){
        PTRACE(4, "mod_h323\t======>PFSH323Connection::setRemoteAddress remoteIP ="<<remoteIP<<", remotePort = "<<remotePort<<" "<<*this);
@@ -1062,6 +1229,7 @@ switch_status_t FSH323Connection::kill_channel(int sig){
                m_rxAudioOpened.Signal();
                m_txAudioOpened.Signal();        
                if (switch_rtp_ready(tech_pvt->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 = "<<status);
+                       switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+                       switch_mutex_unlock(tech_pvt->h323_io_mutex);
+                       return status;                  
+               }
+       //      PTRACE(4, "mod_h323\t--------->\n source = "<<tech_pvt->read_frame.source<< "\n packetlen = "<<tech_pvt->read_frame.packetlen<<"\n datalen = "<<tech_pvt->read_frame.datalen<<"\n samples = "<<tech_pvt->read_frame.samples<<"\n rate = "<<tech_pvt->read_frame.rate<<"\n payload = "<<(int)tech_pvt->read_frame.payload<<"\n timestamp = "<<tech_pvt->read_frame.timestamp<<"\n seq = "<<tech_pvt->read_frame.seq<<"\n ssrc = "<<tech_pvt->read_frame.ssrc);
+               if (tech_pvt->read_frame.flags & SFF_CNG) {
+                       tech_pvt->read_frame.buflen = sizeof(m_buf);
+                       tech_pvt->read_frame.data = m_buf;
+                       tech_pvt->read_frame.packet = NULL;
+                       tech_pvt->read_frame.packetlen = 0;
+                       tech_pvt->read_frame.timestamp = 0;
+                       tech_pvt->read_frame.m = SWITCH_FALSE;
+                       tech_pvt->read_frame.seq = 0;
+                       tech_pvt->read_frame.ssrc = 0;
+                       tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
+               } else {
+                       tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
+               }
+       }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 = "<<tech_pvt->read_frame.source<< "\n packetlen = "<<tech_pvt->read_frame.packetlen<<"\n datalen = "<<tech_pvt->read_frame.datalen<<"\n samples = "<<tech_pvt->read_frame.samples<<"\n rate = "<<tech_pvt->read_frame.rate<<"\n payload = "<<(int)tech_pvt->read_frame.payload<<"\n timestamp = "<<tech_pvt->read_frame.timestamp<<"\n seq = "<<tech_pvt->read_frame.seq<<"\n ssrc = "<<tech_pvt->read_frame.ssrc);
-    if (tech_pvt->read_frame.flags & SFF_CNG) {
-        tech_pvt->read_frame.buflen = sizeof(m_buf);
-        tech_pvt->read_frame.data = m_buf;
-        tech_pvt->read_frame.packet = NULL;
-        tech_pvt->read_frame.packetlen = 0;
-        tech_pvt->read_frame.timestamp = 0;
-        tech_pvt->read_frame.m = SWITCH_FALSE;
-        tech_pvt->read_frame.seq = 0;
-        tech_pvt->read_frame.ssrc = 0;
-        tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
-    } else {
-        tech_pvt->read_frame.codec = &tech_pvt->read_codec ;
-    }
+       switch_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="<<sessionID<<" :"<< GetDirection()<< " addr="<< m_RTPlocalIP <<":"<< m_RTPlocalPort<<" ["<<*this<<"]");        
        
        memset(&m_readFrame, 0, sizeof(m_readFrame));
     m_readFrame.codec = m_switchCodec;
@@ -1346,43 +1566,96 @@ FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel(
 
 
 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()){
+       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 = "<<m_sessionID<<" m_active_sessionID = "<<m_conn->m_active_sessionID);
+               if (switch_rtp_ready(tech_pvt->rtp_session)) {                  
+                       if (m_sessionID == m_conn->m_active_sessionID ){
+                               m_conn->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;
+                               switch_core_session_unlock_codec_read(m_fsSession);             
+                               switch_core_session_unlock_codec_write(m_fsSession);                            
+                       }
                }
        }
+       */
+       switch_mutex_unlock(tech_pvt->h323_mutex);
 }
 
 PBoolean FSH323_ExternalRTPChannel::Start(){
+       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======>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 = "<<sessionID<<" m_active_sessionID = "<<m_conn->m_active_sessionID);    
+       if (!(m_conn && H323_ExternalRTPChannel::Start())){
+               switch_mutex_unlock(tech_pvt->h323_mutex);
                return FALSE;
+       }
        
+       if ((m_conn->m_active_sessionID != 0) && (m_conn->m_active_sessionID != sessionID)){
+               if (switch_core_codec_ready(&tech_pvt->read_codec) || switch_core_codec_ready(&tech_pvt->write_codec)) {
+                       PTRACE(4, "mod_h323\t------------------->Changing Codec to "<<GetH245CodecName(m_capability));
+                       m_conn->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 = "<<m_format->GetFrameSize());
        PTRACE(4, "mod_h323\t------------------->GetFrameTime() return = "<<m_format->GetFrameTime());
        PTRACE(4, "mod_h323\t------------------->payloadCode = "<<(int)payloadCode);
-       PTRACE(4, "mod_h323\t------------------->m_capability->GetTxFramesInPacket() return =  "<<m_capability->GetTxFramesInPacket());
+       PTRACE(4, "mod_h323\t------------------->m_codec_ms return =  "<<m_codec_ms);
        PTRACE(4, "mod_h323\t------------------->m_capability->GetFormatName() return =  "<<m_capability->GetFormatName());
        PTRACE(4, "mod_h323\t------------------->GetH245CodecName() return =  "<<GetH245CodecName(m_capability));
        
@@ -1393,15 +1666,14 @@ PBoolean FSH323_ExternalRTPChannel::Start(){
        }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 (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 = "<<tech_pvt->rtp_session);
                m_conn->m_startRTP = true;
                if (switch_rtp_ready(tech_pvt->rtp_session)) {
-                       PTRACE(4, "mod_h323\t+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");             
                        switch_channel_set_flag(m_fsChannel, CF_FS_RTP);
-                       
                }else{
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AUDIO RTP REPORTS ERROR: [%s]\n", switch_str_nil(err));
                        switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);                      
@@ -1517,17 +1782,46 @@ PBoolean FSH323_ExternalRTPChannel::Start(){
        }
        
     PTRACE(4, "mod_h323\t------------->External RTP address "<<m_RTPremoteIP<<":"<<m_RTPremotePort);
-       switch_mutex_unlock(tech_pvt->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;
     }
 
index 9d834496f946b5b706e11404783dd724375b7b1c..d8b828f2ce2b9525b0eafe717dfa5f9788e70d73 100644 (file)
 #include <h323pdu.h>
 #include <h323caps.h>
 #include <ptclib/delaychan.h>
-
+#include <h323t38.h>
+#include "t38proto.h"
+#include "t38.h"
+#include <mediafmt.h>
 #include <list>
 
 
 #include <switch.h>
 #include <switch_version.h>
 #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),
@@ -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);
-
-             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);
+       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_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(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_m(FS_T38_COR,FSH323_T38Capability,OpalT38_IFP_COR)
+//DEFINE_H323_CAPAB_m(FS_T38_RPE,FSH323_T38Capability,OpalT38_IFP_PRE)
 
-        static FSProcess *h323_process = NULL;
+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;