Use the new SDP library in SIP and MGCP.

The PSTN channel can negotiate RTP forwarding if the circuits are terminated on a MGCP gateway.


git-svn-id: http://voip.null.ro/svn/yate@2805 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2009-08-24 12:09:34 +00:00
parent 5b8b3431c6
commit aaa1c2048d
5 changed files with 548 additions and 1310 deletions

View File

@ -37,6 +37,72 @@
;port=
[codecs]
; This section allows to individually enable or disable the codecs
; default: bool: Enable all unlisted codecs by default if a transcoder exists
;default=enable
; mulaw: bool: Companded-only G711 mu-law (PCMU/8000)
;mulaw=default
; alaw: bool: Companded-only G711 a-law (PCMU/8000)
;alaw=default
; gsm: bool: European GSM 06.10 (GSM/8000)
;gsm=default
; lpc10: bool: Linear Prediction Codec (LPC/8000)
;lpc10=default
; ilbc: bool: Internet Low Bandwidth Codec (iLBC/8000)
;ilbc=default
; amr: bool: Adaptive Multi-Rate 3GPP (AMR/8000)
;amr=default
; slin: bool: Signed Linear 16-bit uncompressed (L16/8000)
;slin=default
; g723: bool: ITU G.723 all variations (G723/8000)
;g723=default
; g726: bool: ITU G.726 32-bit (G726-32/8000)
;g726=default
; g728: bool: ITU G.728 all variations (G728/8000)
;g728=default
; g729: bool: ITU G.729 all variations (G729/8000)
;g729=default
; g729_annexb: bool: G.729 Annex B (VAD) support default (if not in SDP)
; NOTE: RFC 3555 specifies the default should be yes
;g729_annexb=no
; amr_octet: bool: Octet aligned AMR RTP payload default (if not in SDP)
; NOTE: RFC 4867 (and older 3267) specifies the default is bandwidth efficient
;amr_octet=no
[hacks]
; This section holds the dirty stuff required to work with some broken
; implementations
;
; ilbc_forced: string: Format to force as iLBC, can be: ilbc20 or ilbc30
;ilbc_forced=
;
; ilbc_default: string: Format to use for iLBC when packetization is unknown
;ilbc_default=ilbc30
; g729_annexb: bool: Force G.729 Annex B support when parsing the SDP
;g729_annexb=
; ignore_sdp_port: bool: Ignore SDP changes if only the port is different
; This allows preserving the local RTP session and port
;ignore_sdp_port=no
;[gw PUT_NAME_HERE]
; One gw ... section is required for each gateway we control
; The gateway name is a string that can be referenced from other modules
@ -80,3 +146,10 @@
; clearconn: bool: Clear all connections of remote endpoints when initialized
;clearconn=no
; forward_rtp: bool: Support to forward RTP directly to protocols that support it
; The actual direct RTP forwarding is still negotiated in routing
;forward_rtp=yes for digital gateways, no for analogic
; forward_sdp: bool: Also include the raw SDP in the RTP forward offer
;forward_sdp=no

View File

@ -248,18 +248,18 @@ yjinglechan.yate jingle/jinglefeatures.yate: LOCALLIBS = -lyatejingle
server/dbpbx.yate server/pbxassist.yate: ../libs/ypbx/libyatepbx.a
server/dbpbx.yate server/pbxassist.yate: LOCALFLAGS = -I@top_srcdir@/libs/ypbx
server/dbpbx.yate server/pbxassist.yate: LOCALLIBS = ../libs/ypbx/libyatepbx.a
server/dbpbx.yate server/pbxassist.yate: LOCALLIBS = -L../libs/ypbx -lyatepbx
server/mgcpca.yate: ../libyatemgcp.so ../libyatesig.so
server/mgcpca.yate: LOCALFLAGS = -I@top_srcdir@/libs/ymgcp -I@top_srcdir@/libs/ysig
server/mgcpca.yate: LOCALLIBS = -lyatemgcp -lyatesig
server/mgcpca.yate: ../libyatemgcp.so ../libyatesig.so ../libs/ysdp/libyatesdp.a
server/mgcpca.yate: LOCALFLAGS = -I@top_srcdir@/libs/ymgcp -I@top_srcdir@/libs/ysig -I@top_srcdir@/libs/ysdp
server/mgcpca.yate: LOCALLIBS = -lyatemgcp -lyatesig -L../libs/ysdp -lyatesdp
server/mgcpgw.yate: ../libyatemgcp.so
server/mgcpgw.yate: LOCALFLAGS = -I@top_srcdir@/libs/ymgcp
server/mgcpgw.yate: LOCALLIBS = -lyatemgcp
ilbccodec.yate: ../libs/ilbc/libilbc.a
ilbccodec.yate: LOCALLIBS = ../libs/ilbc/libilbc.a
ilbccodec.yate: LOCALLIBS = -L../libs/ilbc -lilbc
ilbccodec.yate: LOCALFLAGS = @ILBC_INC@
gsmcodec.yate: LOCALLIBS = -lgsm
@ -274,13 +274,13 @@ amrnbcodec.yate: LOCALLIBS = @AMRNB_LIB@
faxchan.yate: LOCALLIBS = -lspandsp
faxchan.yate: LOCALFLAGS = @SPANDSP_INC@
ysipchan.yate: ../libs/ysip/libyatesip.a
ysipchan.yate: LOCALFLAGS = -I@top_srcdir@/libs/ysip
ysipchan.yate: LOCALLIBS = ../libs/ysip/libyatesip.a
ysipchan.yate: ../libs/ysip/libyatesip.a ../libs/ysdp/libyatesdp.a
ysipchan.yate: LOCALFLAGS = -I@top_srcdir@/libs/ysip -I@top_srcdir@/libs/ysdp
ysipchan.yate: LOCALLIBS = -L../libs/ysip -lyatesip -L../libs/ysdp -lyatesdp
yrtpchan.yate: ../libs/yrtp/libyatertp.a
yrtpchan.yate: LOCALFLAGS = -I@top_srcdir@/libs/yrtp
yrtpchan.yate: LOCALLIBS = ../libs/yrtp/libyatertp.a
yrtpchan.yate: LOCALLIBS = -L../libs/yrtp -lyatertp
openssl.yate: LOCALFLAGS = @OPENSSL_INC@
openssl.yate: LOCALLIBS = @OPENSSL_LIB@
@ -304,6 +304,9 @@ qt4/updater.yate: LOCALLIBS = @QT4_LIB_NET@
../libs/yrtp/libyatertp.a:
$(MAKE) -C ../libs/yrtp
../libs/ysdp/libyatesdp.a:
$(MAKE) -C ../libs/ysdp
../libs/yiax/libyateiax.a:
$(MAKE) -C ../libs/yiax

View File

@ -27,6 +27,7 @@
#include <yatephone.h>
#include <yatemgcp.h>
#include <yatesig.h>
#include <yatesdp.h>
#include <stdlib.h>
#include <string.h>
@ -112,6 +113,7 @@ public:
bool ownsId(const String& rqId) const;
static SignallingComponent* create(const String& type, const NamedList& name);
static MGCPSpan* findNotify(const String& id);
bool getBoolParam(const String& param, bool defValue) const;
bool matchEndpoint(const MGCPEndpointId& ep);
bool processEvent(MGCPTransaction* tr, MGCPMessage* mm);
bool processNotify(MGCPTransaction* tr, MGCPMessage* mm, const String& event, const String& requestId);
@ -127,6 +129,8 @@ private:
unsigned int m_count;
MGCPEndpointId m_epId;
bool m_operational;
bool m_rtpForward;
bool m_sdpForward;
bool m_fxo;
bool m_fxs;
String m_notify;
@ -134,7 +138,7 @@ private:
String m_version;
};
class MGCPCircuit : public SignallingCircuit
class MGCPCircuit : public SignallingCircuit, public SDPSession
{
public:
MGCPCircuit(unsigned int code, MGCPSpan* span, const char* id);
@ -142,6 +146,11 @@ public:
virtual void* getObject(const String& name) const;
virtual bool status(Status newStat, bool sync);
virtual bool updateFormat(const char* format, int direction);
virtual bool setParam(const String& param, const String& value);
virtual bool getParam(const String& param, String& value) const;
virtual bool getBoolParam(const String& param, bool defValue) const;
virtual bool setParams(const NamedList& params);
virtual bool getParams(NamedList& params, const String& category = String::empty());
virtual bool sendEvent(SignallingCircuitEvent::Type type, NamedList* params);
inline const String& epId() const
{ return m_epId; }
@ -150,12 +159,16 @@ public:
inline const String& connId() const
{ return m_connId; }
inline bool hasRtp() const
{ return m_rtpId && (m_source || m_consumer); }
{ return m_source || m_consumer; }
inline bool hasLocalRtp() const
{ return m_rtpLocalAddr || m_localRawSdp; }
inline MGCPSpan* mySpan()
{ return static_cast<MGCPSpan*>(span()); }
inline bool fxo()
inline const MGCPSpan* mySpan() const
{ return static_cast<const MGCPSpan*>(span()); }
inline bool fxo() const
{ return mySpan()->fxo(); }
inline bool fxs()
inline bool fxs() const
{ return mySpan()->fxs(); }
inline void needClear()
{ m_needClear = true; }
@ -163,7 +176,26 @@ public:
bool processNotify(const String& package, const String& event, const String& fullName);
void processDelete(MGCPMessage* mm, const String& error);
void clearConn(bool force = false);
protected:
// Create a chan.rtp message pointing to the circuit
virtual Message* buildChanRtp(RefObject* context)
{
Message* m = new Message("chan.rtp");
m->userData(context ? context : this);
return m;
}
virtual Message* buildChanRtp(SDPMedia* media, const char* addr, bool start, RefObject* context)
{
Message* m = SDPSession::buildChanRtp(media,addr,start,context);
if (m) {
if (start && media->id())
m->addParam("rtpid",media->id());
m->addParam("mgcp_allowed",String::boolText(false));
}
return m;
}
private:
void waitNotChanging();
MGCPMessage* message(const char* cmd);
bool sendAsync(MGCPMessage* mm);
RefPointer<MGCPMessage> sendSync(MGCPMessage* mm);
@ -171,28 +203,25 @@ private:
bool enqueueEvent(SignallingCircuitEvent::Type type, const char* name, const char* dtmf = 0);
void cleanupRtp();
bool createRtp();
bool startRtp();
bool setupConn();
String m_epId;
Status m_statusReq;
String m_notify;
bool m_changing;
// Gateway endpoint bearer information
String m_gwFormat;
bool m_gwFormatChanged;
// Connection data
String m_connId;
String m_callId;
// Local RTP related data
RefPointer<DataSource> m_source;
RefPointer<DataConsumer> m_consumer;
String m_rtpId;
String m_localIp;
int m_localPort;
int m_sdpSession;
int m_sdpVersion;
String m_localRawSdp;
bool m_localRtpChanged;
// Remote (MGCP GW side) RTP data
String m_remoteIp;
int m_remotePort;
int m_remotePayload;
const char* m_payloads;
bool m_needClear;
String m_remoteRawSdp;
// Synchronous transaction data
MGCPTransaction* m_tr;
RefPointer<MGCPMessage> m_msg;
@ -227,12 +256,14 @@ public:
virtual void initialize();
virtual void statusParams(String& str);
virtual void statusDetail(String& str);
inline SDPParser& parser()
{ return m_parser; }
private:
SDPParser m_parser;
};
YSIGFACTORY2(MGCPSpan);
static const char* s_payloads = "0 8";
static YMGCPEngine* s_engine = 0;
static MGCPEndpoint* s_endpoint = 0;
static String s_defaultEp;
@ -242,6 +273,40 @@ static ObjList s_wrappers;
static ObjList s_spans;
static Mutex s_mutex(false,"MGCP-CA");
// Yate Payloads for the AV profile
static TokenDict s_dict_payloads[] = {
{ "mulaw", 0 },
{ "alaw", 8 },
{ "gsm", 3 },
{ "lpc10", 7 },
{ "slin", 11 },
{ "g726", 2 },
{ "g722", 9 },
{ "g723", 4 },
{ "g728", 15 },
{ "g729", 18 },
{ "ilbc", 98 },
{ "ilbc20", 98 },
{ "ilbc30", 98 },
{ "amr", 96 },
{ "amr-o", 96 },
{ "amr/16000", 99 },
{ "amr-o/16000", 99 },
{ "speex", 102 },
{ "speex/16000", 103 },
{ "speex/32000", 104 },
{ "h261", 31 },
{ "h263", 34 },
{ "mpv", 32 },
{ 0, 0 },
};
// Media gateway bearer information (mapped from s_dict_payloads)
static TokenDict s_dict_gwbearerinfo[] = {
{ "e:mu", 0 },
{ "e:A", 8 },
{ 0, 0 },
};
// Copy one parameter (if present) with new name
static bool copyRename(NamedList& dest, const char* dname, const NamedList& src, const String& sname)
@ -742,7 +807,7 @@ MGCPSpan::MGCPSpan(const NamedList& params, const char* name, const MGCPEpInfo&
: SignallingCircuitSpan(params.getValue("debugname",name),
static_cast<SignallingCircuitGroup*>(params.getObject("SignallingCircuitGroup"))),
m_circuits(0), m_count(0), m_epId(ep), m_operational(false),
m_fxo(false), m_fxs(false)
m_rtpForward(false), m_sdpForward(false), m_fxo(false), m_fxs(false)
{
Debug(&splugin,DebugAll,"MGCPSpan::MGCPSpan(%p,'%s') [%p]",
&params,name,this);
@ -824,6 +889,8 @@ bool MGCPSpan::init(const NamedList& params)
break;
}
m_increment = config->getIntValue("increment",m_increment);
m_rtpForward = config->getBoolValue("forward_rtp",!(m_fxo || m_fxs));
m_sdpForward = config->getBoolValue("forward_sdp",false);
bool clear = config->getBoolValue("clearconn",false);
m_circuits = new MGCPCircuit*[m_count];
unsigned int i;
@ -897,6 +964,18 @@ void MGCPSpan::operational(const SocketAddr& address)
operational(true);
}
// Get a configuration or operational boolean parameter by name
bool MGCPSpan::getBoolParam(const String& param, bool defValue) const
{
if (param == "operational")
return operational();
if (param == "rtp_forward")
return m_rtpForward;
if (param == "sdp_forward")
return m_sdpForward;
return defValue;
}
// Check if this span matches an endpoint ID
bool MGCPSpan::matchEndpoint(const MGCPEndpointId& ep)
{
@ -1048,10 +1127,9 @@ bool MGCPSpan::processDelete(MGCPTransaction* tr, MGCPMessage* mm, const String&
MGCPCircuit::MGCPCircuit(unsigned int code, MGCPSpan* span, const char* id)
: SignallingCircuit(RTP,code,Missing,span->group(),span),
m_epId(id), m_statusReq(Missing),
m_localPort(0), m_sdpSession(0), m_sdpVersion(0),
m_remotePort(0), m_remotePayload(-1),
m_payloads(s_payloads), m_needClear(false), m_tr(0)
SDPSession(&splugin.parser()),
m_epId(id), m_statusReq(Missing), m_changing(false), m_gwFormatChanged(false),
m_localRtpChanged(false), m_needClear(false), m_tr(0)
{
Debug(&splugin,DebugAll,"MGCPCircuit::MGCPCircuit(%u,%p,'%s') [%p]",
code,span,id,this);
@ -1093,11 +1171,10 @@ void* MGCPCircuit::getObject(const String& name) const
// Clean up any RTP we may still hold
void MGCPCircuit::cleanupRtp()
{
if (m_rtpId) {
m_rtpId.clear();
m_localIp.clear();
m_localPort = 0;
}
resetSdp();
m_localRawSdp.clear();
m_localRtpChanged = false;
m_remoteRawSdp.clear();
m_source = 0;
m_consumer = 0;
}
@ -1108,54 +1185,22 @@ bool MGCPCircuit::createRtp()
if (hasRtp())
return true;
cleanupRtp();
Message m("chan.rtp");
resetSdp();
updateSDP(NamedList::empty());
RefPointer<DataEndpoint> de = new DataEndpoint;
de->deref();
m.userData(de);
m.addParam("direction","bidir");
if (m_remoteIp && m_remotePort) {
m.addParam("remoteip",m_remoteIp);
m.addParam("remoteport",String(m_remotePort));
}
else
m.addParam("remoteip",mySpan()->address());
m.addParam("mgcp_allowed",String::boolText(false));
if (Engine::dispatch(m)) {
bool ok = dispatchRtp(mySpan()->address(),false,de);
if (ok) {
m_source = de->getSource();
m_consumer = de->getConsumer();
m_rtpId = m.getValue("rtpid");
m_localIp = m.getValue("localip");
m_localPort = m.getIntValue("localport");
if (m_localIp && m_localPort && hasRtp())
return true;
DDebug(&splugin,DebugAll,"MGCPCircuit::createRtp() src=%p cons=%p [%p]",
(void*)m_source,(void*)m_consumer,this);
}
m_localIp.clear();
m_localPort = 0;
Debug(&splugin,DebugWarn,"MGCPCircuit::createRtp() failed [%p]",this);
cleanupRtp();
return false;
}
// Start the local RTP instance
bool MGCPCircuit::startRtp()
{
if (!(m_remoteIp && m_remotePort && (m_remotePayload >= 0) && hasRtp()))
return false;
Message m("chan.rtp");
m.addParam("direction","bidir");
m.addParam("rtpid",m_rtpId);
m.addParam("remoteip",m_remoteIp);
m.addParam("remoteport",String(m_remotePort));
m.addParam("payload",String(m_remotePayload));
if (m_localIp)
m.addParam("localip",m_localIp);
if (m_localPort)
m.addParam("localport",String(m_localPort));
m.addParam("mgcp_allowed",String::boolText(false));
if (Engine::dispatch(m))
return true;
Debug(&splugin,DebugWarn,"MGCPCircuit::startRtp() failed [%p]",this);
return false;
else {
Debug(&splugin,DebugWarn,"MGCPCircuit::createRtp() failed [%p]",this);
cleanupRtp();
}
TelEngine::destruct(de);
return ok;
}
// Create or update remote connection
@ -1165,61 +1210,41 @@ bool MGCPCircuit::setupConn()
mm->params.addParam("C",m_callId);
if (m_connId)
mm->params.addParam("I",m_connId);
if (m_localIp && m_localPort) {
if (m_gwFormatChanged && m_gwFormat)
mm->params.addParam("B",m_gwFormat);
if (m_localRawSdp) {
mm->params.addParam("M","sendrecv");
if (m_sdpSession)
++m_sdpVersion;
else
m_sdpSession = m_sdpVersion = Time::secNow();
String mLine("audio ");
String oLine("yate ");
mLine << m_localPort << " RTP/AVP " << m_payloads;
oLine << m_sdpSession << " " << m_sdpVersion << " IN IP4 " << m_localIp;
MimeSdpBody* sdp = new MimeSdpBody;
sdp->addLine("v","0");
sdp->addLine("o",oLine);
sdp->addLine("s","PSTN Circuit");
sdp->addLine("c","IN IP4 " + m_localIp);
sdp->addLine("t","0 0");
sdp->addLine("m",mLine);
mm->sdp.append(sdp);
mm->sdp.append(new MimeSdpBody("application/sdp",
m_localRawSdp.safe(),m_localRawSdp.length()));
}
else {
MimeSdpBody* sdp = createSDP(getRtpAddr());
if (sdp) {
mm->params.addParam("M","sendrecv");
mm->sdp.append(sdp);
}
}
mm = sendSync(mm);
if (!mm)
return false;
m_gwFormatChanged = false;
if (m_connId.null())
m_connId = mm->params.getParam("i");
if (m_connId.null()) {
m_needClear = true;
return false;
}
m_localRtpChanged = false;
MimeSdpBody* sdp = static_cast<MimeSdpBody*>(mm->sdp[0]);
if (sdp) {
m_remoteIp.clear();
m_remotePort = 0;
const NamedString* c = sdp->getLine("c");
if (c) {
String tmp(*c);
if (tmp.startSkip("IN IP4")) {
tmp.trimBlanks();
if (tmp == "0.0.0.0")
tmp.clear();
m_remoteIp = tmp;
}
}
c = sdp->getLine("m");
for (; c; c = sdp->getNextLine(c)) {
String tmp(*c);
if (!tmp.startSkip("audio",true))
continue;
int port = 0;
tmp >> port >> " ";
if (!tmp.startSkip("RTP/AVP",true,true))
continue;
m_remotePort = port;
tmp >> m_remotePayload;
return (m_remotePayload >= 0) && (m_remotePayload <= 255);
}
String oldIp = m_rtpAddr;
bool mediaChanged = setMedia(splugin.parser().parse(*sdp,m_rtpAddr,m_rtpMedia));
const DataBlock& raw = sdp->getBody();
m_remoteRawSdp.assign((const char*)raw.data(),raw.length());
// Disconnect if media changed
if (mediaChanged && oldIp && oldIp != m_rtpAddr)
enqueueEvent(SignallingCircuitEvent::Disconnected,"Disconnected");
return true;
}
return true;
}
@ -1236,13 +1261,31 @@ void MGCPCircuit::clearConn(bool force)
}
if (!force)
mm->params.addParam("C",m_callId);
else {
m_gwFormat.clear();
m_gwFormatChanged = false;
}
m_connId.clear();
m_remoteIp.clear();
m_remotePort = 0;
m_sdpSession = 0;
resetSdp();
m_remoteRawSdp.clear();
m_localRtpChanged = false;
sendAsync(mm);
}
// Wait for changing flag to be false
void MGCPCircuit::waitNotChanging()
{
while (true) {
Lock lock(s_mutex);
if (!m_changing) {
m_changing = true;
break;
}
lock.drop();
Thread::yield(true);
}
}
// Build a MGCP message
MGCPMessage* MGCPCircuit::message(const char* cmd)
{
@ -1308,32 +1351,65 @@ bool MGCPCircuit::sendRequest(const char* sigReq, const char* reqEvt, const char
// Circuit status change request
bool MGCPCircuit::status(Status newStat, bool sync)
{
Debug(&splugin,DebugInfo,"MGCPCircuit::status(%s,%s) [%p]",
lookupStatus(newStat),String::boolText(sync),this);
if ((newStat == m_statusReq) && ((SignallingCircuit::status() == newStat) || !sync))
return true;
if (!mySpan()->operational()) {
if (newStat >= Idle)
Debug(&splugin,DebugInfo,"MGCPCircuit::status(%s,%s) %u [%p]",
lookupStatus(newStat),String::boolText(sync),code(),this);
waitNotChanging();
// Don't notify local rtp if we already have it (addr/port/sdp) and didn't changed
// Accept only synchronous connect requests
bool allowRtpChange = false;
if (newStat == Connected) {
if (!sync) {
m_changing = false;
return false;
}
allowRtpChange = SignallingCircuit::status() == Connected &&
hasLocalRtp() && m_localRtpChanged;
if (SignallingCircuit::status() != Connected && !(fxs() || fxo()))
sendRequest(0,"D/[0-9#*](N)");
}
if (!allowRtpChange && (newStat == m_statusReq) &&
((SignallingCircuit::status() == newStat) || !sync)) {
m_changing = false;
return true;
}
if (!mySpan()->operational()) {
if (newStat >= Idle) {
m_changing = false;
return false;
}
}
m_statusReq = newStat;
switch (newStat) {
case Connected:
if (createRtp() && setupConn() && startRtp())
break;
// Create local rtp if we don't have one
// Start it if we don't forward the rtp
if (m_rtpForward || hasLocalRtp() || createRtp()) {
if (setupConn()) {
if (m_rtpForward || startRtp())
break;
clearConn();
}
cleanupRtp();
}
m_statusReq = SignallingCircuit::status();
m_changing = false;
return false;
case Reserved:
break;
case Idle:
if (m_needClear) {
m_needClear = false;
clearConn(true);
}
default:
m_payloads = s_payloads;
cleanupRtp();
clearConn();
}
return SignallingCircuit::status(newStat,sync);
DDebug(&splugin,DebugInfo,"MGCPCircuit new status '%s' on %u [%p]",
lookupStatus(newStat),code(),this);
bool ok = SignallingCircuit::status(newStat,sync);
m_changing = false;
return ok;
}
// Change the format of this circuit
@ -1343,12 +1419,99 @@ bool MGCPCircuit::updateFormat(const char* format, int direction)
return false;
Debug(&splugin,DebugInfo,"MGCPCircuit::updateFormat('%s',%d) %u [%p]",
format,direction,code(),this);
if (0 == ::strcmp(format,"mulaw"))
m_payloads = "0";
else if (0 == ::strcmp(format,"alaw"))
m_payloads = "8";
int fmt = lookup(format,s_dict_payloads,-1);
const char* gwFmt = lookup(fmt,s_dict_gwbearerinfo);
if (!gwFmt)
return false;
waitNotChanging();
if (m_gwFormat != gwFmt) {
m_gwFormat = gwFmt;
m_gwFormatChanged = true;
}
m_changing = false;
return true;
}
bool MGCPCircuit::setParam(const String& param, const String& value)
{
if (m_changing)
return false;
Lock lock(s_mutex);
if (m_changing)
return false;
bool rtpChanged = false;
if (param == "sdp_raw") {
rtpChanged = m_localRawSdp != value;
m_localRawSdp = value;
}
else if (param == "rtp_forward") {
bool fwd = value.toBoolean();
rtpChanged = m_rtpForward != fwd;
m_rtpForward = fwd;
}
else
return false;
m_localRtpChanged = m_localRtpChanged || rtpChanged;
lock.drop();
DDebug(&splugin,DebugAll,"MGCPCircuit::setParam(%s,%s) %u [%p]",
param.c_str(),value.c_str(),code(),this);
return true;
}
bool MGCPCircuit::getParam(const String& param, String& value) const
{
if (m_changing)
return false;
Lock lock(s_mutex);
if (m_changing)
return false;
if (param == "rtp_addr") {
value = m_rtpAddr;
return true;
}
else if (param == "sdp_raw") {
value = m_remoteRawSdp;
return true;
}
return false;
}
bool MGCPCircuit::getBoolParam(const String& param, bool defValue) const
{
return mySpan()->getBoolParam(param,defValue);
}
// Set circuit data from a list of parameters
bool MGCPCircuit::setParams(const NamedList& params)
{
if (params == "rtp") {
waitNotChanging();
DDebug(&splugin,DebugAll,"MGCPCircuit::setParams(rtp) %u [%p]",code(),this);
String* raw = params.getParam("sdp_raw");
if (raw && m_localRawSdp != *raw) {
m_localRawSdp = *raw;
m_localRtpChanged = true;
m_rtpForward = true;
}
if (!m_localRawSdp) {
m_localRtpChanged = updateRtpSDP(params) || localRtpChanged() || m_localRtpChanged;
setLocalRtpChanged();
if (m_localRtpChanged)
m_rtpForward = true;
}
m_changing = false;
return true;
}
return SignallingCircuit::setParams(params);
}
bool MGCPCircuit::getParams(NamedList& params, const String& category)
{
if (category != "rtp")
return false;
waitNotChanging();
addRtpParams(params,String::empty(),0,true);
m_changing = false;
return true;
}
@ -1358,6 +1521,10 @@ bool MGCPCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params
DDebug(&splugin,DebugAll,"MGCPCircuit::sendEvent(%u,%p) %u [%p]",
type,params,code(),this);
switch (type) {
case SignallingCircuitEvent::Connect:
if (params)
setParams(*params);
return status(Connected,!params || params->getBoolValue("sync",true));
case SignallingCircuitEvent::RingBegin:
return fxs() && sendRequest("L/rg");
// case SignallingCircuitEvent::RingEnd:
@ -1434,6 +1601,11 @@ bool MGCPCircuit::processNotify(const String& package, const String& event, cons
return enqueueEvent(SignallingCircuitEvent::Polarity,fullName);
}
else if (package == "D") {
#if 0
// TEST
Debug(&splugin,DebugStub,"MGCPCircuit::processNotify() sending DTMF req [%p]",this);
sendRequest(0,"D/[0-9#*](N)");
#endif
// DTMF events
if (event.length() == 1)
return enqueueEvent(SignallingCircuitEvent::Dtmf,fullName,event);
@ -1444,14 +1616,15 @@ bool MGCPCircuit::processNotify(const String& package, const String& event, cons
// We were forcibly disconnected by the gateway
void MGCPCircuit::processDelete(MGCPMessage* mm, const String& error)
{
waitNotChanging();
if (m_connId)
Debug(&splugin,DebugWarn,"Gateway deleted connection '%s' on circuit %u [%p]",
m_connId.c_str(),code(),this);
m_connId.clear();
m_remoteIp.clear();
m_remotePort = 0;
m_sdpSession = 0;
m_payloads = s_payloads;
m_gwFormat.clear();
m_gwFormatChanged = false;
cleanupRtp();
m_changing = false;
unsigned int code = 0;
String tmp(error);
tmp >> code;
@ -1469,7 +1642,8 @@ void MGCPCircuit::processDelete(MGCPMessage* mm, const String& error)
}
// Enqueue an event detected by this circuit
bool MGCPCircuit::enqueueEvent(SignallingCircuitEvent::Type type, const char* name, const char* dtmf)
bool MGCPCircuit::enqueueEvent(SignallingCircuitEvent::Type type, const char* name,
const char* dtmf)
{
DDebug(&splugin,DebugAll,"Enqueueing event %u '%s' '%s' on %u [%p]",
type,name,dtmf,code(),this);
@ -1553,9 +1727,11 @@ bool DTMFHandler::received(Message& msg)
MGCPPlugin::MGCPPlugin()
: Module("mgcpca","misc")
: Module("mgcpca","misc"),
m_parser("mgcpca","PSTN Circuit")
{
Output("Loaded module MGCP-CA");
m_parser.debugChain(this);
}
MGCPPlugin::~MGCPPlugin()
@ -1644,6 +1820,7 @@ void MGCPPlugin::initialize()
Engine::install(new DTMFHandler);
}
}
m_parser.initialize(cfg.getSection("codecs"),cfg.getSection("hacks"));
}
}; // anonymous namespace

View File

@ -94,6 +94,11 @@ private:
void evAnswer(SignallingEvent* event);
void evRinging(SignallingEvent* event);
void evCircuit(SignallingEvent* event);
// Handle RTP forward from a message.
// Return a circuit event to be sent or 0 if not handled
SignallingCircuitEvent* handleRtp(Message& msg);
// Set RTP data from circuit to message
bool addRtp(Message& msg, bool possible = false);
// Update circuit and format in source, optionally in consumer too
void updateCircuitFormat(SignallingEvent* event, bool consumer);
// Open or update format source/consumer
@ -115,6 +120,8 @@ private:
bool m_hungup; // Hang up flag
String m_reason; // Hangup reason
bool m_inband; // True to try to send in-band tones
bool m_rtpForward; // Forward RTP
bool m_sdpForward; // Forward SDP (only of rtp forward is enabled)
Message* m_route; // Prepared call.preroute message
};
@ -642,6 +649,8 @@ SigChannel::SigChannel(SignallingEvent* event)
m_trunk(0),
m_hungup(true),
m_inband(false),
m_rtpForward(false),
m_sdpForward(false),
m_route(0)
{
if (!(m_call && m_call->ref())) {
@ -660,8 +669,12 @@ SigChannel::SigChannel(SignallingEvent* event)
m_hungup = false;
setState(0);
SignallingCircuit* cic = getCircuit();
if (m_trunk && cic)
m_address << m_trunk->name() << "/" << cic->code();
if (cic) {
if (m_trunk)
m_address << m_trunk->name() << "/" << cic->code();
m_rtpForward = cic->getBoolParam("rtp_forward");
m_sdpForward = cic->getBoolParam("sdp_forward");
}
Message* m = message("chan.startup");
m->setParam("direction",status());
m->addParam("caller",m_caller);
@ -689,6 +702,8 @@ SigChannel::SigChannel(const char* caller, const char* called)
m_hungup(true),
m_reason("noconn"),
m_inband(false),
m_rtpForward(false),
m_sdpForward(false),
m_route(0)
{
}
@ -704,6 +719,15 @@ bool SigChannel::startRouter()
{
Message* m = m_route;
m_route = 0;
Lock lock(m_mutex);
SignallingCircuit* cic = getCircuit();
String addr;
if (cic && cic->getParam("rtp_addr",addr)) {
m_rtpForward = true;
m_sdpForward = cic->getBoolParam("sdp_forward");
addRtp(*m,true);
}
lock.drop();
return Channel::startRouter(m);
}
@ -748,6 +772,11 @@ bool SigChannel::startCall(Message& msg, String& trunks)
else
cic->setParam("echocancel",String::boolText(echo->toBoolean(true)));
}
m_rtpForward = cic->getBoolParam("rtp_forward") && msg.getBoolValue("rtp_forward");
if (m_rtpForward) {
m_sdpForward = (0 != msg.getParam("sdp_raw"));
msg.setParam("rtp_forward","accepted");
}
}
setMaxcall(msg);
Message* m = message("chan.startup",msg);
@ -781,6 +810,12 @@ bool SigChannel::startCall(Message& msg, SigTrunk* trunk)
sigMsg->params().copyParam(msg,"callednumtype");
sigMsg->params().copyParam(msg,"callednumplan");
sigMsg->params().copyParam(msg,"calledpointcode");
// Copy RTP parameters
if (msg.getBoolValue("rtp_forward")) {
NamedList* tmp = new NamedList("rtp");
tmp->copyParams(msg);
sigMsg->params().addParam(new NamedPointer("circuit_parameters",tmp));
}
// Copy routing params
unsigned int n = msg.length();
String prefix;
@ -838,7 +873,10 @@ bool SigChannel::msgProgress(Message& msg)
}
SignallingEvent* event = new SignallingEvent(SignallingEvent::Progress,sm,m_call);
TelEngine::destruct(sm);
SignallingCircuitEvent* cicEvent = handleRtp(msg);
lock.drop();
if (cicEvent)
cicEvent->sendEvent();
plugin.copySigMsgParams(event,msg);
event->sendEvent();
return true;
@ -859,7 +897,10 @@ bool SigChannel::msgRinging(Message& msg)
}
SignallingEvent* event = new SignallingEvent(SignallingEvent::Ringing,sm,m_call);
TelEngine::destruct(sm);
SignallingCircuitEvent* cicEvent = handleRtp(msg);
lock.drop();
if (cicEvent)
cicEvent->sendEvent();
plugin.copySigMsgParams(event,msg);
event->sendEvent();
return true;
@ -886,7 +927,10 @@ bool SigChannel::msgAnswered(Message& msg)
}
SignallingEvent* event = new SignallingEvent(SignallingEvent::Answer,sm,m_call);
TelEngine::destruct(sm);
SignallingCircuitEvent* cicEvent = handleRtp(msg);
lock.drop();
if (cicEvent)
cicEvent->sendEvent();
plugin.copySigMsgParams(event,msg);
event->sendEvent();
return true;
@ -964,6 +1008,8 @@ bool SigChannel::callPrerouted(Message& msg, bool handled)
bool SigChannel::callRouted(Message& msg)
{
Lock lock(m_mutex);
if (m_rtpForward && !msg.getBoolValue("rtp_forward"))
m_rtpForward = false;
setState("routed",false);
return m_call != 0;
}
@ -983,6 +1029,11 @@ void SigChannel::callAccept(Message& msg)
event = new SignallingEvent(SignallingEvent::Accept,sm,m_call);
TelEngine::destruct(sm);
}
if (m_rtpForward) {
const String* tmp = msg.getParam("rtp_forward");
if (!(tmp && (*tmp == "accepted")))
m_rtpForward = false;
}
setState("accepted",false);
lock.drop();
if (event) {
@ -1098,6 +1149,7 @@ void SigChannel::evProgress(SignallingEvent* event)
updateCircuitFormat(event,false);
Message* msg = message("call.progress");
plugin.copySigMsgParams(*msg,event,&s_noPrefixParams);
addRtp(*msg);
Engine::enqueue(msg);
}
@ -1129,6 +1181,7 @@ void SigChannel::evAnswer(SignallingEvent* event)
Message* msg = message("call.answered",false,true);
plugin.copySigMsgParams(*msg,event,&s_noPrefixParams);
msg->clearParam("earlymedia");
addRtp(*msg);
Engine::enqueue(msg);
}
@ -1138,6 +1191,7 @@ void SigChannel::evRinging(SignallingEvent* event)
updateCircuitFormat(event,false);
Message* msg = message("call.ringing",false,true);
plugin.copySigMsgParams(*msg,event,&s_noPrefixParams);
addRtp(*msg);
Engine::enqueue(msg);
}
@ -1157,6 +1211,42 @@ void SigChannel::evCircuit(SignallingEvent* event)
}
}
// Handle RTP forward from a message.
// Return a circuit event to be sent or 0 if not handled
SignallingCircuitEvent* SigChannel::handleRtp(Message& msg)
{
if (!(m_rtpForward && msg.getBoolValue("rtp_forward")))
return 0;
SignallingCircuit* cic = getCircuit();
if (!cic)
return 0;
SignallingCircuitEvent* ev = new SignallingCircuitEvent(cic,
SignallingCircuitEvent::Connect,"rtp");
ev->copyParams(msg);
return ev;
}
// Set RTP data from circuit to message
bool SigChannel::addRtp(Message& msg, bool possible)
{
if (!m_rtpForward)
return false;
SignallingCircuit* cic = getCircuit();
if (!cic)
return false;
bool ok = cic->getParams(msg,"rtp");
if (m_sdpForward) {
String sdp;
if (cic->getParam("sdp_raw",sdp) && sdp) {
ok = true;
msg.setParam("sdp_raw",sdp);
}
}
if (ok)
msg.setParam("rtp_forward",possible ? "possible" : String::boolText(true));
return ok;
}
void SigChannel::updateCircuitFormat(SignallingEvent* event, bool consumer)
{
const char* format = 0;
@ -1173,6 +1263,8 @@ void SigChannel::updateCircuitFormat(SignallingEvent* event, bool consumer)
bool SigChannel::updateConsumer(const char* format, bool force)
{
if (m_rtpForward)
return true;
DataConsumer* consumer = getConsumer();
SignallingCircuit* cic = getCircuit();
if (!cic)
@ -1194,6 +1286,8 @@ bool SigChannel::updateConsumer(const char* format, bool force)
bool SigChannel::updateSource(const char* format, bool force)
{
if (m_rtpForward)
return true;
DataSource* source = getSource();
SignallingCircuit* cic = getCircuit();
if (!cic)

File diff suppressed because it is too large Load Diff