forked from Mirrors/freeswitch
initial commit
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@15223 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
2a02981b8c
commit
0d2f1a4159
5
src/mod/endpoints/mod_h323/Makefile
Normal file
5
src/mod/endpoints/mod_h323/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
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
|
2
src/mod/endpoints/mod_h323/bugs
Normal file
2
src/mod/endpoints/mod_h323/bugs
Normal file
@ -0,0 +1,2 @@
|
||||
faststart and codecs v CallProceeding due to h323plus, grep "Very Frustrating - S.H." in h323plus
|
||||
source and uncomment commented lines.
|
10
src/mod/endpoints/mod_h323/changes.txt
Normal file
10
src/mod/endpoints/mod_h323/changes.txt
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
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.
|
18
src/mod/endpoints/mod_h323/h323.conf.xml
Normal file
18
src/mod/endpoints/mod_h323/h323.conf.xml
Normal file
@ -0,0 +1,18 @@
|
||||
<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>
|
||||
|
1485
src/mod/endpoints/mod_h323/mod_h323.cpp
Normal file
1485
src/mod/endpoints/mod_h323/mod_h323.cpp
Normal file
File diff suppressed because it is too large
Load Diff
431
src/mod/endpoints/mod_h323/mod_h323.h
Normal file
431
src/mod/endpoints/mod_h323/mod_h323.h
Normal file
@ -0,0 +1,431 @@
|
||||
|
||||
|
||||
#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;
|
Loading…
Reference in New Issue
Block a user