Added SDP and RTP support in the MGCP GW.

git-svn-id: http://voip.null.ro/svn/yate@4655 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2011-10-27 16:12:30 +00:00
parent f582f74053
commit a22f352c8b
3 changed files with 151 additions and 17 deletions

View File

@ -41,6 +41,72 @@
;retrans_count=3
[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
;[ep PUT_NAME_HERE]
; One ep ... section is required for each of our endpoints
; Each endpoint can be associated with at most one Call Agent

View File

@ -313,9 +313,9 @@ 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
server/mgcpgw.yate: ../libyatemgcp.so ../libs/ysdp/libyatesdp.a
server/mgcpgw.yate: LOCALFLAGS = -I@top_srcdir@/libs/ymgcp -I@top_srcdir@/libs/ysdp
server/mgcpgw.yate: LOCALLIBS = -lyatemgcp -L../libs/ysdp -lyatesdp
server/lksctp.yate: LOCALFLAGS = @SCTP_FLAGS@
server/lksctp.yate: LOCALLIBS = -lsctp

View File

@ -25,6 +25,7 @@
#include <yatephone.h>
#include <yatemgcp.h>
#include <yatesdp.h>
#include <stdlib.h>
@ -43,7 +44,7 @@ private:
bool createConn(MGCPTransaction* trans, MGCPMessage* msg);
};
class MGCPChan : public Channel
class MGCPChan : public Channel, public SDPSession
{
YCLASS(MGCPChan,Channel);
public:
@ -62,8 +63,22 @@ public:
void activate(bool standby);
protected:
void disconnected(bool final, const char* reason);
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)
m->addParam("mgcp_allowed",String::boolText(false));
return m;
}
void mediaChanged(const SDPMedia& media);
private:
void endTransaction(int code = 407, const NamedList* params = 0);
void endTransaction(int code = 407, const NamedList* params = 0, MimeSdpBody* sdp = 0);
bool reqNotify(String& evt);
bool setSignal(String& req);
bool rqntParams(const MGCPMessage* mm);
@ -73,6 +88,7 @@ private:
String m_callId;
String m_ntfyId;
String m_rtpId;
String m_stats;
bool m_standby;
bool m_isRtp;
};
@ -87,7 +103,11 @@ public:
RefPointer<MGCPChan> findConn(const String* id, MGCPChan::IdType type);
inline RefPointer<MGCPChan> findConn(const String& id, MGCPChan::IdType type)
{ return findConn(&id,type); }
inline SDPParser& parser()
{ return m_parser; }
void activate(bool standby);
private:
SDPParser m_parser;
};
class DummyCall : public CallEndpoint
@ -217,6 +237,7 @@ bool YMGCPEngine::createConn(MGCPTransaction* trans, MGCPMessage* msg)
MGCPChan::MGCPChan(const char* connId)
: Channel(splugin),
SDPSession(&splugin.parser()),
m_tr(0), m_standby(s_standby), m_isRtp(false)
{
DDebug(this,DebugAll,"MGCPChan::MGCPChan('%s') [%p]",connId,this);
@ -271,18 +292,36 @@ void MGCPChan::activate(bool standby)
m_standby = standby;
}
void MGCPChan::endTransaction(int code, const NamedList* params)
void MGCPChan::endTransaction(int code, const NamedList* params, MimeSdpBody* sdp)
{
Lock mylock(s_mutex);
MGCPTransaction* tr = m_tr;
m_tr = 0;
if (!tr)
return;
tr->userData(0);
mylock.drop();
if (!tr->msgResponse()) {
Debug(this,DebugInfo,"Finishing transaction %p with code %d [%p]",tr,code,this);
tr->setResponse(code,params);
if (tr) {
tr->userData(0);
mylock.drop();
if (!tr->msgResponse()) {
Debug(this,DebugInfo,"Finishing transaction %p with code %d [%p]",tr,code,this);
tr->setResponse(code,params,sdp);
sdp = 0;
}
}
TelEngine::destruct(sdp);
}
void MGCPChan::mediaChanged(const SDPMedia& media)
{
SDPSession::mediaChanged(media);
m_stats.clear();
if (media.id() && media.transport()) {
Message m("chan.rtp");
m.addParam("rtpid",media.id());
m.addParam("media",media);
m.addParam("transport",media.transport());
m.addParam("terminate",String::boolText(true));
m.addParam("mgcp_allowed",String::boolText(false));
Engine::dispatch(m);
m_stats = m.getValue(YSTRING("stats"));
}
}
@ -306,7 +345,15 @@ void MGCPChan::callAccept(Message& msg)
params.addParam("I",address());
if (s_cluster || m_standby)
params.addParam("x-standby",String::boolText(m_standby));
endTransaction(200,&params);
MimeSdpBody* sdp = 0;
if (!m_isRtp) {
sdp = createRtpSDP(true);
if (sdp)
params.addParam("M","sendrecv");
else
params.addParam("M","inactive");
}
endTransaction(200,&params,sdp);
}
bool MGCPChan::msgTone(Message& msg, const char* tone)
@ -355,8 +402,11 @@ bool MGCPChan::processEvent(MGCPTransaction* tr, MGCPMessage* mm)
if (mm->name() == YSTRING("DLCX")) {
disconnect();
status("deleted");
setMedia(0);
clearEndpoint();
m_address.clear();
params.addParam("P",m_stats,false);
m_stats.clear();
tr->setResponse(250,&params);
return true;
}
@ -438,8 +488,8 @@ bool MGCPChan::initialEvent(MGCPTransaction* tr, MGCPMessage* mm, const MGCPEndp
m_ntfyId = mm->params.getValue(YSTRING("x"));
rqntParams(mm);
if (id.user() == "gigi")
m_isRtp = true;
MimeSdpBody* sdp = static_cast<MimeSdpBody*>(mm->sdp[0]);
m_isRtp = mm->params.getParam(YSTRING("x-mediatype")) || mm->params.getParam(YSTRING("x-remoteip"));
Message* m = message(m_isRtp ? "chan.rtp" : "call.route");
m->addParam("mgcp_allowed",String::boolText(false));
@ -467,6 +517,20 @@ bool MGCPChan::initialEvent(MGCPTransaction* tr, MGCPMessage* mm, const MGCPEndp
deref();
return true;
}
if (sdp) {
setMedia(splugin.parser().parse(sdp,m_rtpAddr,m_rtpMedia));
if (m_rtpMedia) {
m_rtpForward = true;
m->addParam("rtp_addr",m_rtpAddr);
putMedia(*m);
}
if (splugin.parser().sdpForward()) {
m_rtpForward = true;
const DataBlock& raw = sdp->getBody();
String tmp((const char*)raw.data(),raw.length());
m->addParam("sdp_raw",tmp);
}
}
m_tr = tr;
tr->userData(static_cast<GenObject*>(this));
m->addParam("called",id.id());
@ -496,9 +560,11 @@ void MGCPChan::copyRtpParams(NamedList& dest, const NamedList& src)
}
MGCPPlugin::MGCPPlugin()
: Driver("mgcpgw","misc")
: Driver("mgcpgw","misc"),
m_parser("mgcpgw","Gateway")
{
Output("Loaded module MGCP-GW");
m_parser.debugChain(this);
}
MGCPPlugin::~MGCPPlugin()
@ -592,6 +658,8 @@ void MGCPPlugin::initialize()
}
}
}
m_parser.initialize(cfg.getSection("codecs"),cfg.getSection("hacks"),
cfg.getSection("general"));
}
}; // anonymous namespace