提交 0d2f1a41 authored 作者: Georgiewskiy Yuriy's avatar Georgiewskiy Yuriy

initial commit


git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15223 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 2a02981b
BASE=../../../..
LOCAL_CFLAGS+=-g -I/usr/include/ptlib -I/usr/local/src/h323plus/include -I. -DPTRACING=1 -D_REENTRANT -fno-exceptions
LOCAL_LDFLAGS= -L/usr/local/src/h323plus/lib -lh323_linux_x86_ -lpt -lrt
include $(BASE)/build/modmake.rules
faststart and codecs v CallProceeding due to h323plus, grep "Very Frustrating - S.H." in h323plus
source and uncomment commented lines.
\ No newline at end of file
fix misstype in codec conversion.
fix rtp issue causes choppy sound.
fix progress ind handling on outbound calls.
fix crash on log line, btw not understand why.
implement dtmf transfer.
fix codec name conversion a bit.
fix crash on inbound fast start connection.
initial release.
<configuration name="h323.conf" description="H323 Endpoints">
<settings>
<param name="trace-level" value="10"/>
<param name="context" value="default"/>
<param name="dialplan" value="XML"/>
<param name="codec-prefs" value="PCMA,GSM,G729,G726"/>
<param name="gk-address" value=""/> <!-- empty to disable, "*" to search LAN -->
<param name="gk-identifer" value=""/> <!-- optional name of gk -->
<param name="gk-interface" value=""/> <!-- optional listener interface name -->
</settings>
<listeners>
<listener name="default">
<param name="h323-ip" value="$${local_ip_v4}"/>
<param name="h323-port" value="1720"/>
</listener>
</listeners>
</configuration>
#include "mod_h323.h"
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_codec_string, mod_h323_globals.codec_string);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_context, mod_h323_globals.context);
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_global_dialplan, mod_h323_globals.dialplan);
SWITCH_MODULE_LOAD_FUNCTION(mod_h323_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_h323_shutdown);
SWITCH_MODULE_DEFINITION(mod_h323, mod_h323_load, mod_h323_shutdown, NULL);
#define CF_NEED_FLUSH (1 << 1)
struct mod_h323_globals mod_h323_globals = { 0 };
static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event,
switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
switch_memory_pool_t **pool, switch_originate_flag_t flags);
static const char modulename[] = "h323";
static const char* h323_formats[] = {
"G.711-ALaw-64k", "PCMA",
"G.711-uLaw-64k", "PCMU",
"GSM-06.10", "GSM",
"MS-GSM", "msgsm",
"SpeexNarrow", "speex",
"LPC-10", "lpc10",
"iLBC-15k2", "ilbc20",
"iLBC-13k3", "ilbc30",
"G.723", "G723",
"G.726", "G726",
"G.728", "G728",
"G.729B", "G729b",
"G.729", "G729",
"PCM-16", "slin",
"G.729A", "G729a",
"G.729A/B", "G729ab",
"G.723.1", "G723.1",
"G.723.1(5.3k)", "G723.1-5k3",
"G.723.1A(5.3k)", "G723.1a-5k3",
"G.723.1A(6.3k)", "G723.1a-6k3",
"G.723.1A(6.3k)-Cisco", "g723.1a-6k3-cisco",
"G.726-16k", "G726-16",
"G.726-24k", "G726-24",
"G.726-32k", "G726-32",
"G.726-40k", "G726-40",
"iLBC", "ilbc",
"SpeexNarrow-18.2k", "speex-18k2",
"SpeexNarrow-15k", "speex-15k",
"SpeexNarrow-11k", "speex-11k",
"SpeexNarrow-8k", "speex-8k",
"SpeexNarrow-5.95k", "speex-5k95",
0
};
static switch_status_t on_hangup(switch_core_session_t *session);
static switch_status_t on_destroy(switch_core_session_t *session);
static switch_io_routines_t h323fs_io_routines = {
/*.outgoing_channel */ create_outgoing_channel,
/*.read_frame */ FSH323Connection::read_audio_frame,
/*.write_frame */ FSH323Connection::write_audio_frame,
/*.kill_channel */ FSH323Connection::kill_channel,
/*.send_dtmf */ FSH323Connection::send_dtmf,
/*.receive_message */ FSH323Connection::receive_message,
/*.receive_event */ FSH323Connection::receive_event,
/*.state_change */ FSH323Connection::state_change,
/*.read_video_frame */ FSH323Connection::read_video_frame,
/*.write_video_frame */ FSH323Connection::write_video_frame
};
static switch_state_handler_table_t h323fs_event_handlers = {
/*.on_init */ FSH323Connection::on_init,
/*.on_routing */ FSH323Connection::on_routing,
/*.on_execute */ FSH323Connection::on_execute,
/*.on_hangup */ on_hangup,
/*.on_exchange_media */ FSH323Connection::on_exchange_media,
/*.on_soft_execute */ FSH323Connection::on_soft_execute,
/*.on_consume_media*/ NULL,
/*.on_hibernate*/ NULL,
/*.on_reset*/ NULL,
/*.on_park*/ NULL,
/*.on_reporting*/ NULL,
/*.on_destroy*/ on_destroy
};
static FSProcess *opal_process = NULL;
SWITCH_MODULE_LOAD_FUNCTION(mod_h323_load){
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Starting loading mod_h323\n");
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
if (!*module_interface) {
return SWITCH_STATUS_MEMERR;
}
h323_process = new FSProcess();
if (h323_process == NULL) {
return SWITCH_STATUS_MEMERR;
}
if (h323_process->Initialise(*module_interface)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Opal manager initialized and running\n");
//unloading causes a seg in linux
return SWITCH_STATUS_NOUNLOAD;
//return SWITCH_STATUS_SUCCESS;
}
delete h323_process;
h323_process = NULL;
return SWITCH_STATUS_FALSE;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_h323_shutdown){
switch_safe_free(mod_h323_globals.context);
switch_safe_free(mod_h323_globals.dialplan);
switch_safe_free(mod_h323_globals.codec_string);
delete h323_process;
h323_process = NULL;
return SWITCH_STATUS_SUCCESS;
}
#if PTRACING
class FSTrace : public ostream {
public:
FSTrace()
: ostream(&buffer)
{
}
private:
class Buffer : public streambuf {
char buffer[250];
public:
Buffer()
{
setg(buffer, buffer, &buffer[sizeof(buffer)-2]);
setp(buffer, &buffer[sizeof(buffer)-2]);
}
virtual int sync()
{
return overflow(EOF);
}
virtual int underflow()
{
return EOF;
}
virtual int overflow(int c)
{
const char *fmt = "%s";
char *func = NULL;
int bufSize = pptr() - pbase();
if (c != EOF) {
*pptr() = (char)c;
bufSize++;
}
if (bufSize != 0) {
char *bufPtr = pbase();
char *bufEndPtr = NULL;
setp(bufPtr, epptr());
bufPtr[bufSize] = '\0';
int line = 0;
char *p;
char *file = NULL;
switch_log_level_t level;
switch (strtoul(bufPtr, &file, 10)) {
case 1 :
level = SWITCH_LOG_INFO;
break;
default :
level = SWITCH_LOG_DEBUG;
break;
}
if (file) {
while (isspace(*file)) file++;
if (file && (bufPtr = strchr(file, '(')) && (bufEndPtr = strchr(bufPtr, ')'))) {
char *e;
for(p = bufPtr; p && *p; p++) {
if (*p == '\t') {
*p = ' ';
}
}
*bufPtr++ = '\0';
line = atoi(bufPtr);
while (bufEndPtr && isspace(*(++bufEndPtr)));
bufPtr = bufEndPtr;
if (bufPtr && (e = strchr(bufPtr, ' ')) || (e = strchr(bufPtr, '\t'))) {
func = bufPtr;
bufPtr = e;
*bufPtr++ = '\0';
}
}
}
switch_text_channel_t tchannel = SWITCH_CHANNEL_ID_LOG;
if (!bufPtr) {
bufPtr = pbase();
level = SWITCH_LOG_DEBUG;
}
if (bufPtr) {
if (end_of(bufPtr) != '\n') {
fmt = "%s\n";
}
if (!(file && func && line)) tchannel = SWITCH_CHANNEL_ID_LOG_CLEAN;
switch_log_printf(tchannel, file, func, line, NULL, level, fmt, bufPtr);
}
}
return 0;
}
} buffer;
};
#endif
PString GetH245CodecName(const H245_AudioCapability &cap){
switch (cap.GetTag()) {
case H245_AudioCapability::e_g711Alaw64k:
case H245_AudioCapability::e_g711Alaw56k:
return "PCMA";
case H245_AudioCapability::e_g711Ulaw64k:
case H245_AudioCapability::e_g711Ulaw56k:
return "PCMU";
case H245_AudioCapability::e_g722_64k:
case H245_AudioCapability::e_g722_56k:
case H245_AudioCapability::e_g722_48k:
return "G722";
case H245_AudioCapability::e_g728:
return "G728";
case H245_AudioCapability::e_g729:
case H245_AudioCapability::e_g729AnnexA:
case H245_AudioCapability::e_g729wAnnexB:
case H245_AudioCapability::e_g729AnnexAwAnnexB:
return "G729";
case H245_AudioCapability::e_g7231:
case H245_AudioCapability::e_g7231AnnexCCapability:
return "G723";
case H245_AudioCapability::e_gsmFullRate:
case H245_AudioCapability::e_gsmHalfRate:
case H245_AudioCapability::e_gsmEnhancedFullRate:
return "GSM";
}
return "Unknown";
}
FSProcess::FSProcess()
: PLibraryProcess("Test", "mod_h323", 1, 0, AlphaCode, 1)
, m_h323endpoint(NULL){
}
FSProcess::~FSProcess(){
delete m_h323endpoint;
}
bool FSProcess::Initialise(switch_loadable_module_interface_t *iface){
PTRACE(4, "mod_h323\t======>FSProcess::Initialise " << *this);
m_h323endpoint = new FSH323EndPoint();
return m_h323endpoint != NULL && m_h323endpoint->Initialise(iface);
}
bool FSH323EndPoint::Initialise(switch_loadable_module_interface_t *iface){
PTRACE(4, "mod_h323\t======>FSManager::Initialise " << *this);
ReadConfig(false);
PTrace::SetLevel(mod_h323_globals.trace_level); //just for fun and eyecandy ;)
PTrace::SetOptions(PTrace::TraceLevel);
PTrace::SetStream(new FSTrace);
m_freeswitch = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(iface, SWITCH_ENDPOINT_INTERFACE);
m_freeswitch->interface_name = modulename;
m_freeswitch->io_routines = &h323fs_io_routines;
m_freeswitch->state_handler = &h323fs_event_handlers;
PString codec = ((const char *)mod_h323_globals.codec_string);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Config capabilliti %s \n",(const char *)codec);
if (!codec.IsEmpty()) {
const char** f = h323_formats;
for (; *f; f += 2) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Find capabilliti %s to %s\n",f[1],(const char *)codec);
if (codec.Find(f[1]) != P_MAX_INDEX) {
PString tmp = f[0];
tmp += "*{sw}";
PINDEX init = GetCapabilities().GetSize();
AddAllCapabilities(0, 0, tmp);
PINDEX num = GetCapabilities().GetSize() - init;
if (!num) {
// failed to add so pretend we support it in hardware
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H323 failed to add capability '%s' \n",(const char *)tmp);
tmp = f[0];
tmp += "*{hw}";
AddAllCapabilities(0, 0, tmp);
num = GetCapabilities().GetSize() - init;
}
if (num)
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H.323 added %d capabilities '%s' \n",num,(const char *)tmp);
else
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "H323 failed to add capability '%s' \n",(const char *)tmp);
}
}
}
AddAllUserInputCapabilities(0,1);
PTRACE(1, "OpenPhone\tCapability Table:\n" << setprecision(4) << capabilities);
if (m_listeners.empty()) {
StartListener("");
} else {
for (std::list < FSListener >::iterator it = m_listeners.begin(); it != m_listeners.end(); ++it) {
if (!StartListener(it->listenAddress)) {
PTRACE(3, "mod_h323\tCannot start listener for " << it->name);
}
}
}
/*
OpalMediaFormatList allCodecs = OpalMediaFormat::GetAllRegisteredMediaFormats();
for (OpalMediaFormatList::iterator it = allCodecs.begin(); it != allCodecs.end(); ++it) {
if (it->GetMediaType() == OpalMediaType::Audio()) {
it->SetOptionInteger(OpalAudioFormat::RxFramesPerPacketOption(), 1);
it->SetOptionInteger(OpalAudioFormat::TxFramesPerPacketOption(), 1);
}
}
*/
if (!m_gkAddress.IsEmpty()) {
if (UseGatekeeper(m_gkAddress, m_gkIdentifer, m_gkInterface))
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Started gatekeeper: %s\n",
(const char *)GetGatekeeper()->GetName());
else
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
"Could not start gatekeeper: addr=\"%s\", id=\"%s\", if=\"%s\"\n",
(const char *)m_gkAddress,
(const char *)m_gkIdentifer,
(const char *)m_gkInterface);
}
return TRUE;
}
switch_status_t FSH323EndPoint::ReadConfig(int reload){
PTRACE(4, "mod_h323\t======>FSH323EndPoint::ReadConfig " << *this);
const char *cf = "h323.conf";
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_memory_pool_t *pool = NULL;
if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
return status;
}
set_global_context("default");
set_global_dialplan("XML");
switch_event_t *params = NULL;
switch_event_create(&params, SWITCH_EVENT_REQUEST_PARAMS);
switch_assert(params);
switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile", switch_str_nil(""));
switch_xml_t cfg;
switch_xml_t xml = switch_xml_open_cfg(cf, &cfg, params);
if (xml == NULL) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
return SWITCH_STATUS_FALSE;
}
switch_xml_t xmlSettings = switch_xml_child(cfg, "settings");
if (xmlSettings) {
for (switch_xml_t xmlParam = switch_xml_child(xmlSettings, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
const char *var = switch_xml_attr_soft(xmlParam, "name");
const char *val = switch_xml_attr_soft(xmlParam, "value");
if (!strcasecmp(var, "trace-level")) {
int level = atoi(val);
if (level > 0) {
mod_h323_globals.trace_level = level;
}
} else if (!strcasecmp(var, "context")) {
set_global_context(val);
} else if (!strcasecmp(var, "dialplan")) {
set_global_dialplan(val);
} else if (!strcasecmp(var, "codec-prefs")) {
set_global_codec_string(val);
} else if (!strcasecmp(var, "jitter-size")) {
char * next;
unsigned minJitter = strtoul(val, &next, 10);
if (minJitter >= 10) {
unsigned maxJitter = minJitter;
if (*next == ',')
maxJitter = atoi(next+1);
SetAudioJitterDelay(minJitter, maxJitter); // In milliseconds
} else{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set zero Jitter buffer\n");
SetAudioJitterDelay(0, 0);
}
} else if (!strcasecmp(var, "gk-address")) {
m_gkAddress = val;
} else if (!strcasecmp(var, "gk-identifer")) {
m_gkIdentifer = val;
} else if (!strcasecmp(var, "gk-interface")) {
m_gkInterface = val;
} else if (!strcasecmp(var, "gk-prefix")) {
m_gkPrefixes.AppendString(val);
}
}
}
switch_xml_t xmlListeners = switch_xml_child(cfg, "listeners");
if (xmlListeners != NULL) {
for (switch_xml_t xmlListener = switch_xml_child(xmlListeners, "listener"); xmlListener != NULL; xmlListener = xmlListener->next) {
m_listeners.push_back(FSListener());
FSListener & listener = m_listeners.back();
listener.name = switch_xml_attr_soft(xmlListener, "name");
if (listener.name.IsEmpty())
listener.name = "unnamed";
PIPSocket::Address ip;
WORD port = 1720;
for (switch_xml_t xmlParam = switch_xml_child(xmlListener, "param"); xmlParam != NULL; xmlParam = xmlParam->next) {
const char *var = switch_xml_attr_soft(xmlParam, "name");
const char *val = switch_xml_attr_soft(xmlParam, "value");
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Var - '%s' and Val - '%s' \n", var, val);
if (!strcasecmp(var, "h323-ip"))
ip = val;
else if (!strcasecmp(var, "h323-port"))
port = (WORD) atoi(val);
}
listener.listenAddress = new H323ListenerTCP(*this,ip,port);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created Listener '%s'\n", (const char *) listener.name);
}
}
switch_event_destroy(&params);
if (xml)
switch_xml_free(xml);
return status;
}
FSH323EndPoint::FSH323EndPoint(){
PTRACE(4, "mod_h323\t======>FSH323EndPoint::FSH323EndPoint " << *this);
terminalType = e_GatewayOnly;
}
H323Connection *FSH323EndPoint::CreateConnection(
unsigned callReference,
void* userData,
H323Transport* transport,
H323SignalPDU* setupPDU){
PTRACE(4, "mod_h323\t======>FSH323EndPoint::CreateConnection callReference = "<< callReference <<" userDate = "<<userData<<" [" << *this<<"]");
if ((switch_caller_profile_t *)userData){
PTRACE(4, "mod_h323\t------> SWITCH_CALL_DIRECTION_OUTBOUND");
} else{
PTRACE(4, "mod_h323\t------> SWITCH_CALL_DIRECTION_INBOUND");
}
switch_core_session_t *fsSession = switch_core_session_request(GetSwitchInterface(),
(switch_caller_profile_t *)userData ? SWITCH_CALL_DIRECTION_OUTBOUND : SWITCH_CALL_DIRECTION_INBOUND, NULL);
if (fsSession == NULL)
return NULL;
PTRACE(4, "mod_h323\t------> fsSession = "<<fsSession);
switch_channel_t *fsChannel = switch_core_session_get_channel(fsSession);
if (fsChannel == NULL) {
switch_core_session_destroy(&fsSession);
return NULL;
}
return new FSH323Connection(*this,transport,callReference,(switch_caller_profile_t *)userData, fsSession, fsChannel);
}
bool FSH323EndPoint::OnSetGatewayPrefixes(PStringList & prefixes) const{
PTRACE(4, "mod_h323\t======>FSH323EndPoint::OnSetGatewayPrefixes " << *this);
if(m_gkPrefixes.GetSize() > 0) {
PTRACE(4, "mod_h323\tOnSetGatewayPrefixes " << m_gkPrefixes);
prefixes = m_gkPrefixes;
return true;
}
return false;
}
FSH323Connection::FSH323Connection(FSH323EndPoint& endpoint, H323Transport* transport, unsigned callReference, switch_caller_profile_t *outbound_profile, switch_core_session_t *fsSession, switch_channel_t *fsChannel)
: H323Connection(endpoint,callReference)
, m_endpoint(&endpoint)
, m_fsSession(fsSession)
, m_fsChannel(fsChannel)
, m_callOnPreAnswer(false)
, m_startRTP(false){
PTRACE(4, "mod_h323\t======>FSH323Connection::FSH323Connection " << *this);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_alloc(m_fsSession, sizeof(*tech_pvt));
tech_pvt->me = this;
switch_core_session_set_private(m_fsSession, tech_pvt);
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession));
switch_mutex_init(&tech_pvt->h323_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(m_fsSession));
if (outbound_profile != NULL) {
SetLocalPartyName(outbound_profile->caller_id_number);
SetDisplayName(outbound_profile->caller_id_name);
switch_caller_profile_t *caller_profile = switch_caller_profile_clone(m_fsSession, outbound_profile);
switch_channel_set_caller_profile(m_fsChannel, caller_profile);
PString name = "h323/";
name += outbound_profile->destination_number;
switch_channel_set_name(m_fsChannel, name);
switch_channel_set_flag(m_fsChannel, CF_OUTBOUND);
switch_channel_set_state(m_fsChannel, CS_INIT);
}
m_RTPlocalPort = switch_rtp_request_port((const char *)m_RTPlocalIP.AsString());
}
FSH323Connection::~FSH323Connection(){
PTRACE(4, "mod_h323\t======>FSH323Connection::~FSH323Connection ["<<*this<<"]");
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
tech_pvt->me = NULL;
}
void FSH323Connection::OnSetLocalCapabilities(){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnSetLocalCapabilities() [" << *this<<"]");
H323Connection::OnSetLocalCapabilities();
SetLocalCapabilities();
}
bool FSH323Connection::SetLocalCapabilities(){
PTRACE(4, "mod_h323\t======>FSH323Connection::SetLocalCapabilities() Size local capability = "<<localCapabilities.GetSize()<<" [" << *this<<"]");
if (!mod_h323_globals.codec_string)
return false;
bool nocodecs = true;
bool changed = false;
for (int i = 0; i < localCapabilities.GetSize(); i++) {
const char* format = 0;
PString fname;
decodeCapability(localCapabilities[i],&format,0,&fname);
if (format) {
PString m_globalcodec = ((const char *)mod_h323_globals.codec_string);
if (m_globalcodec.Find(format) < 0) {
PTRACE(1, "mod_h323\tRemoving capability '"<<fname<<"' ("<<format<<") not in remote '"<<m_globalcodec<<"'");
changed = true;
for (PINDEX idx = 0; idx < fastStartChannels.GetSize(); idx++) {
if (fastStartChannels[idx].GetCapability() == localCapabilities[i]) {
PTRACE(1, "mod_h323\tRemoving fast start channel "<<fastStartChannels[idx].GetDirection()<<" '"<<fname<<"' ("<<format<<")");
fastStartChannels.RemoveAt(idx--);
}
}
localCapabilities.Remove(fname);
i--;
} else nocodecs = false;
}
}
if (nocodecs) {
PTRACE(3, "mod_h323\tNo codecs remaining for H323 connection ["<<*this<<"]");
changed = false;
ClearCall(EndedByCapabilityExchange);
}
return changed;
}
bool FSH323Connection::decodeCapability(const H323Capability& capability, const char** dataFormat, int* payload, PString* capabName){
PTRACE(4, "mod_h323\t======>FSH323Connection::decodeCapability");
PString fname((const char *)capability.GetFormatName());
if (fname.Find("{sw}") == (fname.GetLength() - 4))
fname = fname.Mid(0,fname.GetLength()-4);
if (fname.Find("{hw}") == (fname.GetLength() - 4))
fname = fname.Mid(0,fname.GetLength()-4);
OpalMediaFormat oformat(fname, false);
int pload = oformat.GetPayloadType();
const char *format = 0;
const char** f = h323_formats;
for (; *f; f += 2) {
if (fname.Find(*f) == 0) {
format = f[1];
break;
}
}
PTRACE(1, "mod_h323\tcapability '"<< fname << "' format '"<<format<<"' payload "<<pload);
if (format) {
if (capabName)
*capabName = fname;
if (dataFormat)
*dataFormat = format;
if (payload)
*payload = pload;
return true;
}
return false;
}
H323Connection::AnswerCallResponse FSH323Connection::OnAnswerCall(const PString &caller,
const H323SignalPDU &setupPDU, H323SignalPDU &connectPDU){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnAnswerCall caller = "<< caller<<" [" << *this<<"]");
if (m_fsSession == NULL) {
PTRACE(1, "mod_h323\tSession request failed.");
return H323Connection::AnswerCallDenied;
}
switch_core_session_add_stream(m_fsSession, NULL);
switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
if (channel == NULL) {
PTRACE(1, "mod_h323\tSession does not have a channel");
return H323Connection::AnswerCallDenied;
}
const Q931& q931 = setupPDU.GetQ931();
const H225_Setup_UUIE& setup = setupPDU.m_h323_uu_pdu.m_h323_message_body;
const H225_ArrayOf_AliasAddress& address = setup.m_destinationAddress;
for (int i = 0; i<address.GetSize(); i++)
PTRACE(2, "mod_h323\t address index = "<<i<<" value = "<<(const char *)H323GetAliasAddressString(address[i]));
PString called;
if (address.GetSize() > 0)
called = (const char *)H323GetAliasAddressString(address[0]);
if (!called.IsEmpty())
PTRACE(2, "mod_h323\t Called number or alias = "<<called);
else {
PString callnam;
if (q931.GetCalledPartyNumber(callnam)) {
called=(const char *)callnam;
PTRACE(2, "mod_h323\t Called-Party-Number = "<<called);
}
}
switch_caller_profile_t *caller_profile = switch_caller_profile_new(switch_core_session_get_pool(m_fsSession),
NULL,
/** username */
mod_h323_globals.dialplan,
/** dial plan */
GetRemotePartyName(),
/** caller_id_name */
GetRemotePartyNumber(),
/** caller_id_number */
NULL,
/** network addr */
NULL,
/** ANI */
NULL,
/** ANI II */
NULL,
/** RDNIS */
modulename,
/** source */
mod_h323_globals.context,
/** set context */
called
/** destination_number */
);
if (caller_profile == NULL) {
PTRACE(1, "mod_h323\tCould not create caller profile");
return H323Connection::AnswerCallDenied;
}
PTRACE(4, "mod_h323\tCreated switch caller profile:\n"
" username = " << caller_profile->username << "\n"
" dialplan = " << caller_profile->dialplan << "\n"
" caller_id_name = " << caller_profile->caller_id_name << "\n"
" caller_id_number = " << caller_profile->caller_id_number << "\n"
" network_addr = " << caller_profile->network_addr << "\n"
" source = " << caller_profile->source << "\n"
" context = " << caller_profile->context << "\n"
" destination_number= " << caller_profile->destination_number);
switch_channel_set_caller_profile(channel, caller_profile);
char name[256] = "h323/";
switch_copy_string(name + 5, caller_profile->destination_number, sizeof(name)-5);
switch_channel_set_name(channel, name);
switch_channel_set_state(channel, CS_INIT);
if (switch_core_session_thread_launch(m_fsSession) != SWITCH_STATUS_SUCCESS) {
PTRACE(1, "mod_h323\tCould not launch session thread");
return H323Connection::AnswerCallDenied;
}
return H323Connection::AnswerCallDeferred;
}
H323Channel* FSH323Connection::CreateRealTimeLogicalChannel(const H323Capability& capability,H323Channel::Directions dir,unsigned sessionID,const H245_H2250LogicalChannelParameters* param, RTP_QOS * rtpqos){
PTRACE(4, "mod_h323\t======>FSH323Connection::CreateRealTimeLogicalChannel " << *this);
H323TransportAddress m_h323transportadd = GetSignallingChannel()->GetLocalAddress();
m_h323transportadd.GetIpAddress(m_RTPlocalIP);
// return H323Connection::CreateRealTimeLogicalChannel(capability,dir,sessionID,param);
return new FSH323_ExternalRTPChannel(*this, capability, dir, sessionID,m_RTPlocalIP,m_RTPlocalPort);
}
PBoolean FSH323Connection::OnStartLogicalChannel(H323Channel & channel){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnStartLogicalChannel chennel = "<<&channel<<", "<<*this);
// return H323Connection::OnStartLogicalChannel(channel);
return true;
}
PBoolean FSH323Connection::OnCreateLogicalChannel(const H323Capability& capability, H323Channel::Directions dir, unsigned& errorCode){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnCreateLogicalChannel ('"<< (const char *)capability.GetFormatName()<<"',"<<dir<<") "<<*this);
return H323Connection::OnCreateLogicalChannel(capability,dir,errorCode);
}
void FSH323Connection::OnReceivedReleaseComplete(const H323SignalPDU & pdu){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedReleaseComplete cause = "<<pdu.GetQ931().GetCause()<<" value = "<<(switch_call_cause_t)pdu.GetQ931().GetCause());
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
// tech_pvt->me = NULL;
switch_channel_hangup(switch_core_session_get_channel(m_fsSession),(switch_call_cause_t)pdu.GetQ931().GetCause());
// on_hangup(GetCallReference(), (const char *)GetCallToken(), pdu.GetQ931().GetCause());
return H323Connection::OnReceivedReleaseComplete(pdu);
}
bool FSH323Connection::OnReceivedProgress(const H323SignalPDU &pdu)
{
PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedProgress");
m_txAudioOpened.Wait();
switch_channel_mark_pre_answered(m_fsChannel);
return true;
}
bool FSH323Connection::OnSendReleaseComplete(H323SignalPDU & pdu)
{
PTRACE(4, "mod_h323\t======>FSH323Connection::OnSendReleaseComplete cause = "<<pdu.GetQ931().GetCause()<<" value = "<<(switch_call_cause_t)pdu.GetQ931().GetCause());
switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
return H323Connection::OnSendReleaseComplete(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);
return H323Connection::OpenLogicalChannel(capability,sessionID,dir);
}
bool FSH323Connection::OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
const H245_MultiplexCapability * muxCap,
H245_TerminalCapabilitySetReject & reject){
PTRACE(4, "mod_h323\t======>FSH323Connection::OnReceivedCapabilitySet ["<<*this<<"]");
if (!H323Connection::OnReceivedCapabilitySet(remoteCaps, muxCap, reject)) {
return false;
}
PTRACE(4, "mod_h323\t======>END H323Connection::OnReceivedCapabilitySet ["<<*this<<"]");
for (int i = 0; i < remoteCapabilities.GetSize(); ++i) {
PTRACE(4, "mod_h323\t----> Capabilities = "<<remoteCapabilities[i]);
}
H323Capability * cap = remoteCapabilities.FindCapability(H323Capability::e_Audio);
if (cap == NULL) {
PTRACE(4, "mod_h323\t----> Capabilities is NULL ");
return false;
}
PTRACE(4, "mod_h323\t----> Capabilities not NULL ");
return true;
}
bool FSH323Connection::OnAlerting(const H323SignalPDU &alertingPDU, const PString &user){
PTRACE(4, "mod_h323\t======>PFSH323Connection::OnAlerting user = "<<(const char *)user<<" ["<<*this<<"]");
return (switch_channel_mark_ring_ready(m_fsChannel) == SWITCH_STATUS_SUCCESS);
;
}
void FSH323Connection::OnEstablished(){
PTRACE(4, "mod_h323\t======>PFSH323Connection::OnEstablished ["<<*this<<"]");
switch_channel_mark_answered(m_fsChannel);
}
void FSH323Connection::setRemoteAddress(const char* remoteIP, WORD remotePort){
PTRACE(4, "mod_h323\t======>PFSH323Connection::setRemoteAddress remoteIP ="<<remoteIP<<", remotePort = "<<remotePort<<" "<<*this);
if (!m_remotePort) {
PTRACE(4, "mod_h323\tGot remote RTP address "<<remoteIP<<":"<<remotePort<<" "<<*this);
m_remotePort = remotePort;
m_remoteAddr = remoteIP;
}
}
switch_status_t FSH323Connection::on_execute(){
PTRACE(4, "mod_h323\t======>FSH323Connection::on_execute " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::on_routing(){
PTRACE(4, "mod_h323\t======>FSH323Connection::on_routing " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::kill_channel(int sig){
PTRACE(4, "mod_h323\t======>FSH323Connection::kill_channel " << *this);
PTRACE(3, "mod_h323\tKill " << sig << " on connection " << *this);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
if (!tech_pvt) {
return SWITCH_STATUS_FALSE;
}
switch (sig) {
case SWITCH_SIG_BREAK:
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_break(tech_pvt->rtp_session);
}
break;
case SWITCH_SIG_KILL:
default:
m_rxAudioOpened.Signal();
m_txAudioOpened.Signal();
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_kill_socket(tech_pvt->rtp_session);
}
break;
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::send_dtmf(const switch_dtmf_t *dtmf){
PTRACE(4, "mod_h323\t======>FSH323Connection::send_dtmf " << *this);
SendUserInputTone(dtmf->digit, dtmf->duration);
return SWITCH_STATUS_SUCCESS;
}
void FSH323Connection::SendUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
{
PTRACE(4, "mod_h323\t======>FSH323Connection::SendUserInputTone [" << *this<<"]");
H323Connection::SendUserInputTone(tone, duration);
}
void FSH323Connection::OnUserInputTone(char tone, unsigned duration, unsigned logicalChannel, unsigned rtpTimestamp)
{
PTRACE(4, "mod_h323\t======>FSH323Connection::OnUserInputTone [" << *this<<"]");
switch_dtmf_t dtmf = { tone, duration };
switch_channel_queue_dtmf(m_fsChannel, &dtmf);
H323Connection::OnUserInputTone( tone, duration, logicalChannel, rtpTimestamp);
}
void FSH323Connection::OnUserInputString(const PString &value)
{
PTRACE(4, "mod_h323\t======>FSH323Connection::OnUserInputString [" << *this<<"]");
switch_dtmf_t dtmf = { value[0], 0 };
switch_channel_queue_dtmf(m_fsChannel, &dtmf);
H323Connection::OnUserInputString(value);
}
switch_status_t FSH323Connection::receive_message(switch_core_session_message_t *msg){
PTRACE(4, "mod_h323\t======>FSH323Connection::receive_message MSG=" << msg->message_id);
switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_BRIDGE:
case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
switch_channel_set_private_flag(channel, CF_NEED_FLUSH);
break;
default:
break;
}
switch (msg->message_id) {
case SWITCH_MESSAGE_INDICATE_RINGING:{
// AnsweringCall(AnswerCallAlertWithMedia);
AnsweringCall(AnswerCallPending);
break;
}
case SWITCH_MESSAGE_INDICATE_DEFLECT:{
/* PSafePtr<OpalConnection> other = GetOtherPartyConnection();
if (other != NULL)
other->TransferConnection(msg->string_arg);
break;
*/
}
case SWITCH_MESSAGE_INDICATE_PROGRESS:{
m_callOnPreAnswer = true;
AnsweringCall(AnswerCallPending);
AnsweringCall(AnswerCallDeferredWithMedia);
m_txAudioOpened.Wait();
if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {
switch_channel_mark_pre_answered(m_fsChannel);
}
break;
}
case SWITCH_MESSAGE_INDICATE_ANSWER:{
if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
return SWITCH_STATUS_FALSE;
}
AnsweringCall(H323Connection::AnswerCallNow);
PTRACE(4, "mod_h323\tMedia started on connection " << *this);
m_rxAudioOpened.Wait();
m_txAudioOpened.Wait();
if (!switch_channel_test_flag(m_fsChannel, CF_EARLY_MEDIA)) {
PTRACE(4, "mod_h323\t-------------------->switch_channel_mark_answered(m_fsChannel) " << *this);
switch_channel_mark_answered(m_fsChannel);
}
break;
}
default:{
PTRACE(3, "mod_h323\tReceived message " << msg->message_id << " on connection " << *this);
}
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::receive_event(switch_event_t *event){
PTRACE(4, "mod_h323\t======>FSH323Connection::receive_event " << *this);
PTRACE(3, "mod_h323\tReceived event " << event->event_id << " on connection " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::state_change(){
PTRACE(4, "mod_h323\t======>FSH323Connection::state_change " << *this);
PTRACE(3, "mod_h323\tState changed on connection " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::on_init(){
PTRACE(4, "mod_h323\t======>FSH323Connection::on_init " << *this);
switch_channel_t *channel = switch_core_session_get_channel(m_fsSession);
if (channel == NULL) {
return SWITCH_STATUS_FALSE;
}
PTRACE(3, "mod_h323\tStarted routing for connection " << *this);
switch_channel_set_state(channel, CS_ROUTING);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::on_exchange_media(){
PTRACE(4, "mod_h323\t======>FSH323Connection::on_exchange_media " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::on_soft_execute(){
PTRACE(4, "mod_h323\t======>FSH323Connection::on_soft_execute " << *this);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::read_audio_frame(switch_frame_t **frame, switch_io_flag_t flags, int stream_id){
PTRACE(4, "mod_h323\t======>FSH323Connection::read_audio_frame " << *this);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
tech_pvt->read_frame.flags = 0;
/*
if (switch_channel_test_private_flag(m_fsChannel, CF_NEED_FLUSH)) {
switch_channel_clear_private_flag(m_fsChannel, CF_NEED_FLUSH);
} else {
switch_core_timer_next(&tech_pvt->read_timer);
}
*/
switch_set_flag_locked(tech_pvt, TFLAG_READING);
if (!switch_channel_ready(m_fsChannel)) {
PTRACE(4, "mod_h323\t---------> RETURN");
switch_clear_flag_locked(tech_pvt, TFLAG_READING);
return SWITCH_STATUS_FALSE;
}
if (!switch_core_codec_ready(&tech_pvt->read_codec )) {
PTRACE(4, "mod_h323\t---------> RETURN");
switch_clear_flag_locked(tech_pvt, TFLAG_READING);
return SWITCH_STATUS_FALSE;
}
//switch_core_timer_step(&m_switchTimer);
switch_status_t status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame, flags);
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
PTRACE(4, "mod_h323\t---------> RETURN");
switch_clear_flag_locked(tech_pvt, TFLAG_READING);
return SWITCH_STATUS_FALSE;
}
PTRACE(4, "mod_h323\t--------->\n source = "<<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_clear_flag_locked(tech_pvt, TFLAG_READING);
*frame = &tech_pvt->read_frame;
return SWITCH_STATUS_SUCCESS;
}
switch_status_t FSH323Connection::write_audio_frame(switch_frame_t *frame, switch_io_flag_t flags, int stream_id){
PTRACE(4, "mod_h323\t======>FSH323Connection::write_audio_frame " << *this);
switch_status_t status = SWITCH_STATUS_SUCCESS;
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
switch_assert(tech_pvt != NULL);
if (!switch_channel_ready(m_fsChannel)) {
PTRACE(4, "mod_h323\t---------> RETURN");
return SWITCH_STATUS_FALSE;
}
while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
if (switch_channel_ready(m_fsChannel)) {
switch_yield(10000);
} else {
PTRACE(4, "mod_h323\t---------> RETURN");
return SWITCH_STATUS_GENERR;
}
}
if (!switch_core_codec_ready(&tech_pvt->read_codec) || !tech_pvt->read_codec.implementation) {
PTRACE(4, "mod_h323\t---------> RETURN");
return SWITCH_STATUS_GENERR;
}
if ((frame->flags & SFF_CNG)) {
PTRACE(4, "mod_h323\t---------> RETURN");
return SWITCH_STATUS_SUCCESS;
}
switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
if (switch_rtp_write_frame(tech_pvt->rtp_session, frame)< 0) {
status = SWITCH_STATUS_GENERR;
}
switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
PTRACE(4, "mod_h323\t---------> RETURN");
return status;
}
switch_status_t FSH323Connection::read_video_frame(switch_frame_t **frame, switch_io_flag_t flag, int stream_id){
PTRACE(4, "mod_h323\t======>FSH323Connection::read_video_frame " << *this);
}
switch_status_t FSH323Connection::write_video_frame(switch_frame_t *frame, switch_io_flag_t flag, int stream_id){
PTRACE(4, "mod_h323\t======>FSH323Connection::write_video_frame " << *this);
// return write_frame(OpalMediaType::Video(), frame, flag);
}
///////////////////////////////////////////////////////////////////////
FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel(
FSH323Connection& connection,
const H323Capability& capability,
Directions direction,
unsigned sessionID,
const PIPSocket::Address& ip,
WORD dataPort)
: H323_ExternalRTPChannel(connection, capability, direction, sessionID,ip,dataPort)
, m_conn(&connection)
, m_fsSession(connection.GetSession())
, m_capability(&capability)
, m_RTPlocalPort(dataPort){
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
m_RTPlocalIP = (const char *)ip.AsString();
SetExternalAddress(H323TransportAddress(ip, dataPort), H323TransportAddress(ip, dataPort+1));
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::FSH323_ExternalRTPChannel "<< GetDirection()<< " addr="<< m_RTPlocalIP <<":"<< m_RTPlocalPort<<" ["<<*this<<"]");
memset(&m_readFrame, 0, sizeof(m_readFrame));
m_readFrame.codec = m_switchCodec;
m_readFrame.flags = SFF_RAW_RTP;
m_fsChannel = switch_core_session_get_channel(m_fsSession);
//SetExternalAddress(H323TransportAddress(localIpAddress, m_RTPlocalPort), H323TransportAddress(localIpAddress, m_RTPlocalPort+1));
PTRACE(4, "mod_h323\t------->capability.GetPayloadType() return = "<<capability.GetPayloadType());
PTRACE(4, "mod_h323\t------->capability.GetFormatName() return = "<<capability.GetFormatName());
PString fname((const char *)capability.GetFormatName());
if (fname.Find("{sw}") == (fname.GetLength() - 4))
fname = fname.Mid(0,fname.GetLength()-4);
if (fname.Find("{hw}") == (fname.GetLength() - 4))
fname = fname.Mid(0,fname.GetLength()-4);
OpalMediaFormat format(fname, FALSE);
m_format = &format;
payloadCode = format.GetPayloadType();
PTRACE(4, "mod_h323\t------->payloadCode = "<<(int)payloadCode);
}
FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel(){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::~FSH323_ExternalRTPChannel "<< GetDirection()<<" "<<*this);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
if (IsRunning()){
PTRACE(4, "mod_h323\t------------->Running");
if (switch_rtp_ready(tech_pvt->rtp_session)) {
switch_rtp_kill_socket(tech_pvt->rtp_session);
}
}
}
PBoolean FSH323_ExternalRTPChannel::Start(){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::Start() "<<*this);
const char *err = NULL;
switch_rtp_flag_t flags;
char * timer_name = NULL;
const char *var;
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(m_fsSession);
if (!(m_conn && H323_ExternalRTPChannel::Start()))
return FALSE;
bool isAudio;
if (m_capability->GetMainType() == H323Capability::e_Audio) {
isAudio = true;
PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Audio");
} else if (m_capability->GetMainType() == H323Capability::e_Video) {
isAudio = false;
PTRACE(4, "mod_h323\t------------------------->H323Capability::e_Video");
}
H323Codec *codec = GetCodec();
PTRACE(4, "mod_h323\t------------------->GetFrameSize() return = "<<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_capability->GetFormatName() return = "<<m_capability->GetFormatName());
PTRACE(4, "mod_h323\t------------------->GetH245CodecName() return = "<<GetH245CodecName(m_capability->GetSubType()));
if (GetDirection() == IsReceiver){
m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec;
m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer;
}else{
m_switchCodec = isAudio ? &tech_pvt->write_codec : &tech_pvt->vid_write_codec;
}
if (m_conn->m_callOnPreAnswer && !(GetDirection() == IsReceiver)){
m_switchCodec = isAudio ? &tech_pvt->read_codec : &tech_pvt->vid_read_codec;
m_switchTimer = isAudio ? &tech_pvt->read_timer : &tech_pvt->vid_read_timer;
}
if (switch_core_codec_init(m_switchCodec, GetH245CodecName(m_capability->GetSubType()), NULL, // FMTP
8000, m_capability->GetTxFramesInPacket(), 1, // Channels
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
if (switch_core_codec_init(m_switchCodec, GetH245CodecName(m_capability->GetSubType()), NULL, // FMTP
8000, 0, 1, // Channels
SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, // Settings
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
PTRACE(1, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Cannot initialise " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
<< m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
switch_channel_hangup(m_fsChannel, SWITCH_CAUSE_INCOMPATIBLE_DESTINATION);
return false;
}
PTRACE(2, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " Unsupported ptime of " << m_capability->GetTxFramesInPacket() << " on " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
<< m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
}
PTRACE(1, "mod_h323\t" << switch_channel_get_name(m_fsChannel)<< " initialise " <<
switch_channel_get_name(m_fsChannel) << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
<< m_capability->GetMainType() << " codec " << m_capability << " for connection " << *this);
if (GetDirection() == IsReceiver) {
m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
if (isAudio) {
switch_core_session_set_read_codec(m_fsSession, m_switchCodec);
if (switch_core_timer_init(m_switchTimer,
"soft",
m_switchCodec->implementation->microseconds_per_packet / 1000,
m_switchCodec->implementation->samples_per_packet,
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
switch_core_codec_destroy(m_switchCodec);
m_switchCodec = NULL;
return false;
}
} else {
switch_core_session_set_video_read_codec(m_fsSession, m_switchCodec);
switch_channel_set_flag(m_fsChannel, CF_VIDEO);
}
} else {
if (isAudio) {
switch_core_session_set_write_codec(m_fsSession, m_switchCodec);
} else {
switch_core_session_set_video_write_codec(m_fsSession, m_switchCodec);
switch_channel_set_flag(m_fsChannel, CF_VIDEO);
}
}
if (m_conn->m_callOnPreAnswer && !(GetDirection() == IsReceiver)){
m_readFrame.rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
if (isAudio) {
switch_core_session_set_read_codec(m_fsSession, m_switchCodec);
if (switch_core_timer_init(m_switchTimer,
"soft",
m_switchCodec->implementation->microseconds_per_packet / 1000,
m_switchCodec->implementation->samples_per_packet,
switch_core_session_get_pool(m_fsSession)) != SWITCH_STATUS_SUCCESS) {
switch_core_codec_destroy(m_switchCodec);
m_switchCodec = NULL;
return false;
}
switch_channel_set_variable(m_fsChannel,"timer_name","soft");
}
}
PTRACE(3, "mod_h323\tSet " << ((GetDirection() == IsReceiver)? " read" : " write") << ' '
<< m_capability->GetMainType() << " codec to << " << m_capability << " for connection " << *this);
switch_mutex_lock(tech_pvt->h323_mutex);
PIPSocket::Address remoteIpAddress;
GetRemoteAddress(remoteIpAddress,m_RTPremotePort);
m_RTPremoteIP = (const char *)remoteIpAddress.AsString();
PTRACE(4, "mod_h323\t------------------->tech_pvt->rtp_session = "<<tech_pvt->rtp_session);
PTRACE(4, "mod_h323\t------------------->samples_per_packet = "<<m_switchCodec->implementation->samples_per_packet);
PTRACE(4, "mod_h323\t------------------->actual_samples_per_second = "<<m_switchCodec->implementation->actual_samples_per_second);
if (!m_conn->m_startRTP) {
flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_DATAWAIT|SWITCH_RTP_FLAG_AUTO_CNG|SWITCH_RTP_FLAG_RAW_WRITE|SWITCH_RTP_FLAG_AUTOADJ);
if ((var = switch_channel_get_variable(m_fsChannel, "timer_name"))) {
timer_name = (char *) var;
}
tech_pvt->rtp_session = switch_rtp_new((const char *)m_RTPlocalIP,
m_RTPlocalPort,
(const char *)m_RTPremoteIP,
m_RTPremotePort,
(switch_payload_t)payloadCode,
m_switchCodec->implementation->samples_per_packet,
m_capability->GetTxFramesInPacket() * 1000,
(switch_rtp_flag_t) flags, timer_name, &err,
switch_core_session_get_pool(m_fsSession));
PTRACE(4, "mod_h323\t------------------------->tech_pvt->rtp_session = "<<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);
switch_mutex_unlock(tech_pvt->h323_mutex);
return SWITCH_STATUS_FALSE;
}
}
if (GetDirection() == IsReceiver) m_conn->m_rxAudioOpened.Signal();
else m_conn->m_txAudioOpened.Signal();
PTRACE(4, "mod_h323\t------------->External RTP address "<<m_RTPremoteIP<<":"<<m_RTPremotePort);
switch_mutex_unlock(tech_pvt->h323_mutex);
return true;
}
PBoolean FSH323_ExternalRTPChannel::OnReceivedPDU(
const H245_H2250LogicalChannelParameters& param,
unsigned& errorCode){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnReceivedPDU ["<<*this<<"]");
if (!H323_ExternalRTPChannel::OnReceivedPDU(param,errorCode))
return true;
// if (!m_conn || m_conn->hasRemoteAddress())
// return true;
PIPSocket::Address remoteIpAddress;
WORD remotePort;
GetRemoteAddress(remoteIpAddress,remotePort);
PTRACE(4, "mod_h323\tRemote RTP address "<<(const char *)remoteIpAddress.AsString()<<":"<<remotePort);
m_conn->setRemoteAddress((const char *)remoteIpAddress.AsString(), remotePort);
return true;
}
PBoolean FSH323_ExternalRTPChannel::OnSendingPDU(H245_H2250LogicalChannelParameters& param){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnSendingPDU ["<<*this<<"]");
return H323_ExternalRTPChannel::OnSendingPDU(param);
}
PBoolean FSH323_ExternalRTPChannel::OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters& param){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnReceivedAckPDU ["<<*this<<"]");
return H323_ExternalRTPChannel::OnReceivedAckPDU(param);
}
void FSH323_ExternalRTPChannel::OnSendOpenAck(H245_H2250LogicalChannelAckParameters& param){
PTRACE(4, "mod_h323\t======>FSH323_ExternalRTPChannel::OnSendOpenAck ["<<*this<<"]");
H323_ExternalRTPChannel::OnSendOpenAck(param);
}
FSH323Connection * FSH323EndPoint::FSMakeCall(const PString & dest, void *userData){
PTRACE(4, "mod_h323\t======>FSH323EndPoint::FSMakeCall DST NUMBER = "<<dest<<" ["<<*this<<"]");
FSH323Connection * connection;
PString token;
H323Transport *transport = NULL;
if (listeners.GetSize() > 0) {
H323TransportAddress taddr = listeners[0].GetTransportAddress();
PIPSocket::Address addr;
WORD port;
if (taddr.GetIpAndPort(addr, port)) {
if (addr) {
PTRACE(4, "mod_h323\t----> Using "<<addr<<" for outbound call");
transport = new H323TransportTCP(*this, addr,false);
if (!transport)
PTRACE(4, "mod_h323\t----> Unable to create transport for outgoing call");
}
} else
PTRACE(4, "mod_h323\t----> Unable to get address and port");
}
/*
if (!(connection = (FSH323Connection *)H323EndPoint::MakeCallLocked(dest, token, userData, transport))) {
return NULL;
}
*/
if (!(connection = (FSH323Connection *)H323EndPoint::MakeCall(dest, token, userData))) {
return NULL;
}
/*
unsigned int *callReference;
*callReference = connection->GetCallReference();
PTRACE(2, "mod_h323\t======>\n\tCreate outgoing cennel\n\tCall token = "<<(const char *)token<<"\n\tCall reference = "<<*callReference);
*/
return connection;
}
static switch_call_cause_t create_outgoing_channel(switch_core_session_t *session,
switch_event_t *var_event,
switch_caller_profile_t *outbound_profile,
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags){
PTRACE(4, "mod_h323\t======>create_outgoing_channel DST NUMBER = "<<outbound_profile->destination_number);
FSH323Connection * connection;
if (h323_process == NULL) {
return SWITCH_CAUSE_CRASH;
}
FSH323EndPoint & ep = h323_process->GetH323EndPoint();
if (!(connection = ep.FSMakeCall(outbound_profile->destination_number,outbound_profile))){
return SWITCH_CAUSE_PROTOCOL_ERROR;
}
/* PSafePtr < OpalCall > call = manager.FindCallWithLock(token);
if (call == NULL) {
return SWITCH_CAUSE_PROTOCOL_ERROR;
}
PSafePtr < FSConnection > connection = call->GetConnectionAs < FSConnection > (0);
if (connection == NULL) {
return SWITCH_CAUSE_PROTOCOL_ERROR;
}
*/
*new_session = connection->GetSession();
PTRACE(4, "mod_h323\t--------->GetSession() return = "<<connection->GetSession());
return SWITCH_CAUSE_SUCCESS;
}
static switch_status_t on_destroy(switch_core_session_t *session){
PTRACE(4, "mod_h323\t======>on_destroy ");
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
if (tech_pvt) {
if (tech_pvt->read_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->read_codec);
}
if (tech_pvt->write_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->write_codec);
}
if (tech_pvt->vid_read_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->vid_read_codec);
}
if (tech_pvt->vid_write_codec.implementation) {
switch_core_codec_destroy(&tech_pvt->vid_write_codec);
}
if (tech_pvt->read_timer.timer_interface) {
switch_core_timer_destroy(&tech_pvt->read_timer);
}
if (tech_pvt->vid_read_timer.timer_interface) {
switch_core_timer_destroy(&tech_pvt->vid_read_timer);
}
}
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t on_hangup(switch_core_session_t *session){
PTRACE(4, "mod_h323\t======>switch_status_t on_hangup ");
switch_channel_t *channel = switch_core_session_get_channel(session);
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session);
if (tech_pvt->me) {
PTRACE(4, "mod_h323\t----->");
Q931::CauseValues cause = (Q931::CauseValues)switch_channel_get_cause_q850(channel);
tech_pvt->me->SetQ931Cause(cause);
tech_pvt->me->ClearCallSynchronous(NULL, H323TranslateToCallEndReason(cause, UINT_MAX));
tech_pvt->me = NULL;
}
return SWITCH_STATUS_SUCCESS;
}
#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
#pragma GCC visibility push(default)
#endif
#include <ptlib.h>
#include <h323.h>
#include <h323neg.h>
#include <h323pdu.h>
#include <h323caps.h>
#include <ptclib/delaychan.h>
#include <list>
#if defined(__GNUC__) && defined(HAVE_VISIBILITY)
#pragma GCC visibility pop
#endif
#undef strcasecmp
#undef strncasecmp
#define HAVE_APR
#include <switch.h>
#include <switch_version.h>
#define MODNAME "mod_h323"
typedef enum {
TFLAG_IO = (1 << 0),
TFLAG_INBOUND = (1 << 1),
TFLAG_OUTBOUND = (1 << 2),
TFLAG_READING = (1 << 3),
TFLAG_WRITING = (1 << 4),
TFLAG_BYE = (1 << 5),
TFLAG_VOICE = (1 << 6),
TFLAG_RTP_READY = (1 << 7),
TFLAG_CODEC_READY = (1 << 8),
TFLAG_TRANSPORT = (1 << 9),
TFLAG_ANSWER = (1 << 10),
TFLAG_VAD_IN = (1 << 11),
TFLAG_VAD_OUT = (1 << 12),
TFLAG_VAD = (1 << 13),
TFLAG_DO_CAND = (1 << 14),
TFLAG_DO_DESC = (1 << 15),
TFLAG_LANADDR = (1 << 16),
TFLAG_AUTO = (1 << 17),
TFLAG_DTMF = (1 << 18),
TFLAG_TIMER = (1 << 19),
TFLAG_TERM = (1 << 20),
TFLAG_TRANSPORT_ACCEPT = (1 << 21),
TFLAG_READY = (1 << 22),
} TFLAGS;
struct mod_h323_globals {
int trace_level;
char *codec_string;
char *context;
char *dialplan;
};
extern struct mod_h323_globals mod_h323_globals;
class FSH323Connection;
class FSH323_ExternalRTPChannel;
typedef struct {
unsigned int flags;
switch_timer_t read_timer;
switch_codec_t read_codec;
switch_codec_t write_codec;
switch_frame_t read_frame;
switch_timer_t vid_read_timer;
switch_codec_t vid_read_codec;
switch_codec_t vid_write_codec;
switch_rtp_t *rtp_session;
switch_mutex_t *flag_mutex;
switch_mutex_t *h323_mutex;
FSH323Connection *me;
} h323_private_t;
#define DECLARE_CALLBACK0(name) \
static switch_status_t name(switch_core_session_t *session) { \
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name() : SWITCH_STATUS_FALSE; } \
switch_status_t name()
#define DECLARE_CALLBACK1(name, type1, name1) \
static switch_status_t name(switch_core_session_t *session, type1 name1) { \
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1)
#define DECLARE_CALLBACK3(name, type1, name1, type2, name2, type3, name3) \
static switch_status_t name(switch_core_session_t *session, type1 name1, type2 name2, type3 name3) { \
h323_private_t *tech_pvt = (h323_private_t *) switch_core_session_get_private(session); \
return tech_pvt && tech_pvt->me != NULL ? tech_pvt->me->name(name1, name2, name3) : SWITCH_STATUS_FALSE; } \
switch_status_t name(type1 name1, type2 name2, type3 name3)
class FSH323EndPoint;
class FSProcess : public PLibraryProcess {
PCLASSINFO(FSProcess, PLibraryProcess);
public:
FSProcess();
~FSProcess();
bool Initialise(switch_loadable_module_interface_t *iface);
FSH323EndPoint & GetH323EndPoint() const { return *m_h323endpoint; }
protected:
FSH323EndPoint * m_h323endpoint;
};
struct FSListener {
FSListener() {
}
PString name;
H323ListenerTCP *listenAddress;
PString localUserName;
PString gatekeeper;
};
class FSH323EndPoint:public H323EndPoint {
PCLASSINFO(FSH323EndPoint, H323EndPoint);
public:
FSH323EndPoint();
/**Create a connection that uses the specified call.
*/
virtual H323Connection* CreateConnection(
unsigned callReference,
void* userData,
H323Transport* transport,
H323SignalPDU* setupPDU
);
virtual bool OnSetGatewayPrefixes(PStringList & prefixes) const;
bool Initialise(switch_loadable_module_interface_t *iface);
switch_status_t ReadConfig(int reload);
switch_endpoint_interface_t *GetSwitchInterface() const {
return m_freeswitch;
}
FSH323Connection * FSMakeCall(const PString & dest,void *userData);
list <FSListener> m_listeners;
protected:
PStringList m_gkPrefixes;
switch_endpoint_interface_t *m_freeswitch;
PString m_gkAddress;
PString m_gkIdentifer;
PString m_gkInterface;
};
class FSH323Connection:public H323Connection {
PCLASSINFO(FSH323Connection, H323Connection)
public:
FSH323Connection(FSH323EndPoint& endpoint,
H323Transport* transport,
unsigned callReference,
switch_caller_profile_t *outbound_profile,
switch_core_session_t *fsSession,
switch_channel_t *fsChannel);
~FSH323Connection();
virtual H323Channel* CreateRealTimeLogicalChannel(
const H323Capability& capability,
H323Channel::Directions dir,
unsigned sessionID,
const H245_H2250LogicalChannelParameters* param,
RTP_QOS * rtpqos = NULL
);
virtual PBoolean OnStartLogicalChannel(H323Channel& channel);
virtual PBoolean OnCreateLogicalChannel(const H323Capability& capability, H323Channel::Directions dir, unsigned& errorCode);
virtual void OnReceivedReleaseComplete(const H323SignalPDU & pdu);
virtual bool OnReceivedProgress(const H323SignalPDU &);
virtual bool OnSendReleaseComplete(H323SignalPDU & pdu);
virtual PBoolean OpenLogicalChannel(const H323Capability& capability, unsigned sessionID, H323Channel::Directions dir);
void setRemoteAddress(const char* remoteIP, WORD remotePort);
virtual void OnSetLocalCapabilities();
virtual bool OnAlerting(const H323SignalPDU &alertingPDU, const PString &user);
virtual void OnEstablished();
bool SetLocalCapabilities();
static bool decodeCapability(const H323Capability& capability, const char** dataFormat, int* payload = 0, PString* capabName = 0);
virtual H323Connection::AnswerCallResponse OnAnswerCall(const PString& caller,
const H323SignalPDU& signalPDU, H323SignalPDU& connectPDU);
virtual bool OnReceivedCapabilitySet(const H323Capabilities & remoteCaps,
const H245_MultiplexCapability * muxCap,
H245_TerminalCapabilitySetReject & reject);
switch_core_session_t *GetSession() const {
return m_fsSession;
}
virtual void SendUserInputTone(char tone, unsigned duration = 0, unsigned logicalChannel = 0, unsigned rtpTimestamp = 0);
virtual void OnUserInputTone(char, unsigned, unsigned, unsigned);
virtual void OnUserInputString(const PString &value);
DECLARE_CALLBACK0(on_init);
DECLARE_CALLBACK0(on_routing);
DECLARE_CALLBACK0(on_execute);
DECLARE_CALLBACK0(on_exchange_media);
DECLARE_CALLBACK0(on_soft_execute);
DECLARE_CALLBACK1(kill_channel, int, sig);
DECLARE_CALLBACK1(send_dtmf, const switch_dtmf_t *, dtmf);
DECLARE_CALLBACK1(receive_message, switch_core_session_message_t *, msg);
DECLARE_CALLBACK1(receive_event, switch_event_t *, event);
DECLARE_CALLBACK0(state_change);
DECLARE_CALLBACK3(read_audio_frame, switch_frame_t **, frame, switch_io_flag_t, flags, int, stream_id);
DECLARE_CALLBACK3(write_audio_frame, switch_frame_t *, frame, switch_io_flag_t, flags, int, stream_id);
DECLARE_CALLBACK3(read_video_frame, switch_frame_t **, frame, switch_io_flag_t, flag, int, stream_id);
DECLARE_CALLBACK3(write_video_frame, switch_frame_t *, frame, switch_io_flag_t, flag, int, stream_id);
bool m_callOnPreAnswer;
bool m_startRTP;
PSyncPoint m_rxAudioOpened;
PSyncPoint m_txAudioOpened;
protected:
FSH323EndPoint * m_endpoint;
PString m_remoteAddr;
int m_remotePort;
switch_core_session_t *m_fsSession;
switch_channel_t *m_fsChannel;
PIPSocket::Address m_RTPlocalIP;
WORD m_RTPlocalPort;
unsigned char m_buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
};
class FSH323_ExternalRTPChannel : public H323_ExternalRTPChannel{
PCLASSINFO(FSH323_ExternalRTPChannel, H323_ExternalRTPChannel);
public:
/* Create a new channel. */
FSH323_ExternalRTPChannel(
FSH323Connection& connection,
const H323Capability& capability,
Directions direction,
unsigned sessionID,
const PIPSocket::Address& ip,
WORD dataPort
);
/* Destructor */
~FSH323_ExternalRTPChannel();
virtual PBoolean Start();
virtual PBoolean OnReceivedAckPDU(const H245_H2250LogicalChannelAckParameters& param);
virtual PBoolean OnSendingPDU(H245_H2250LogicalChannelParameters& param);
virtual PBoolean OnReceivedPDU(const H245_H2250LogicalChannelParameters& param,unsigned& errorCode);
virtual void OnSendOpenAck(H245_H2250LogicalChannelAckParameters& param);
private:
FSH323Connection* m_conn;
const H323Capability* m_capability;
switch_core_session_t *m_fsSession;
switch_channel_t *m_fsChannel;
switch_codec_t *m_switchCodec;
OpalMediaFormat *m_format;
switch_frame_t m_readFrame;
switch_timer_t *m_switchTimer;
PString m_RTPremoteIP;
WORD m_RTPremotePort;
PString m_RTPlocalIP;
WORD m_RTPlocalPort;
BYTE payloadCode;
};
class BaseG7231Capab : public H323AudioCapability
{
PCLASSINFO(BaseG7231Capab, H323AudioCapability);
public:
BaseG7231Capab(const char* fname, bool annexA = true)
: H323AudioCapability(7,4), m_name(fname), m_aa(annexA)
{ }
virtual PObject* Clone() const{
return new BaseG7231Capab(*this);
}
virtual unsigned GetSubType() const{
return H245_AudioCapability::e_g7231;
}
virtual PString GetFormatName() const{
return m_name;
}
virtual H323Codec* CreateCodec(H323Codec::Direction direction) const{
return 0;
}
virtual Comparison Compare(const PObject& obj) const{
Comparison res = H323AudioCapability::Compare(obj);
if (res != EqualTo)
return res;
bool aa = static_cast<const BaseG7231Capab&>(obj).m_aa;
if (aa && !m_aa)
return LessThan;
if (m_aa && !aa)
return GreaterThan;
return EqualTo;
}
virtual bool OnSendingPDU(H245_AudioCapability& pdu, unsigned packetSize) const {
pdu.SetTag(GetSubType());
H245_AudioCapability_g7231& g7231 = pdu;
g7231.m_maxAl_sduAudioFrames = packetSize;
g7231.m_silenceSuppression = m_aa;
return true;
}
virtual bool OnReceivedPDU(const H245_AudioCapability& pdu, unsigned& packetSize){
if (pdu.GetTag() != H245_AudioCapability::e_g7231)
return false;
const H245_AudioCapability_g7231& g7231 = pdu;
packetSize = g7231.m_maxAl_sduAudioFrames;
m_aa = (g7231.m_silenceSuppression != 0);
return true;
}
protected:
const char* m_name;
bool m_aa;
};
class BaseG729Capab : public H323AudioCapability
{
PCLASSINFO(BaseG729Capab, H323AudioCapability);
public:
BaseG729Capab(const char* fname, unsigned type = H245_AudioCapability::e_g729)
: H323AudioCapability(24,6), m_name(fname), m_type(type)
{ }
virtual PObject* Clone() const
// default copy constructor - take care!
{ return new BaseG729Capab(*this); }
virtual unsigned GetSubType() const
{ return m_type; }
virtual PString GetFormatName() const
{ return m_name; }
virtual H323Codec* CreateCodec(H323Codec::Direction direction) const
{ return 0; }
protected:
const char* m_name;
unsigned m_type;
};
class BaseGSM0610Cap : public H323AudioCapability
{
PCLASSINFO(BaseGSM0610Cap, H323AudioCapability);
public:
BaseGSM0610Cap(const char* fname, unsigned type = H245_AudioCapability::e_gsmFullRate)
: H323AudioCapability(24,2), m_name(fname), m_type(type),m_comfortNoise(0),m_scrambled(0)
{ }
virtual PObject * Clone() const{
return new BaseGSM0610Cap(*this);
}
virtual H323Codec* CreateCodec(H323Codec::Direction direction) const{
return 0;
}
virtual unsigned GetSubType() const{
return H245_AudioCapability::e_gsmFullRate;
}
virtual PString GetFormatName() const{
return m_name;
}
virtual bool OnSendingPDU(H245_AudioCapability & pdu, unsigned packetSize) const{
pdu.SetTag(H245_AudioCapability::e_gsmFullRate);
H245_GSMAudioCapability & gsm = pdu;
gsm.m_audioUnitSize = packetSize * 33;
gsm.m_comfortNoise = m_comfortNoise;
gsm.m_scrambled = m_scrambled;
return true;
}
virtual bool OnReceivedPDU(const H245_AudioCapability & pdu, unsigned & packetSize){
PTRACE(2, "mod_h323\t==============>BaseGSM0610Cap::OnReceivedPDU");
if (pdu.GetTag() != H245_AudioCapability::e_gsmFullRate)
return false;
const H245_GSMAudioCapability & gsm = pdu;
packetSize = (gsm.m_audioUnitSize + 32) / 33;
m_comfortNoise = gsm.m_comfortNoise;
m_scrambled = gsm.m_scrambled;
return true;
}
protected:
const char* m_name;
int m_comfortNoise;
int m_scrambled;
unsigned m_type;
};
#define DEFINE_H323_CAPAB(cls,base,param,name) \
class cls : public base { \
public: \
cls() : base(name,param) { } \
}; \
H323_REGISTER_CAPABILITY(cls,name) \
DEFINE_H323_CAPAB(FS_G7231_5,BaseG7231Capab,false,OPAL_G7231_5k3"{sw}")
DEFINE_H323_CAPAB(FS_G7231_6,BaseG7231Capab,false,OPAL_G7231_6k3"{sw}")
DEFINE_H323_CAPAB(FS_G7231A_5,BaseG7231Capab,true,OPAL_G7231A_5k3"{sw}")
DEFINE_H323_CAPAB(FS_G7231A_6,BaseG7231Capab,true,OPAL_G7231A_6k3"{sw}")
DEFINE_H323_CAPAB(FS_G729,BaseG729Capab,H245_AudioCapability::e_g729,OPAL_G729"{sw}")
DEFINE_H323_CAPAB(FS_G729A,BaseG729Capab,H245_AudioCapability::e_g729AnnexA,OPAL_G729A"{sw}")
DEFINE_H323_CAPAB(FS_G729B,BaseG729Capab,H245_AudioCapability::e_g729wAnnexB,OPAL_G729B"{sw}")
DEFINE_H323_CAPAB(FS_G729AB,BaseG729Capab,H245_AudioCapability::e_g729AnnexAwAnnexB,OPAL_G729AB"{sw}")
DEFINE_H323_CAPAB(FS_GSM,BaseGSM0610Cap,H245_AudioCapability::e_gsmFullRate,OPAL_GSM0610"{sw}")
static FSProcess *h323_process = NULL;
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论