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;