diff --git a/conf.d/mgcpgw.conf.sample b/conf.d/mgcpgw.conf.sample index 653afd26..1da45747 100644 --- a/conf.d/mgcpgw.conf.sample +++ b/conf.d/mgcpgw.conf.sample @@ -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 diff --git a/modules/Makefile.in b/modules/Makefile.in index c669cd54..ba45602d 100644 --- a/modules/Makefile.in +++ b/modules/Makefile.in @@ -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 diff --git a/modules/server/mgcpgw.cpp b/modules/server/mgcpgw.cpp index e67c374b..b85da95c 100644 --- a/modules/server/mgcpgw.cpp +++ b/modules/server/mgcpgw.cpp @@ -25,6 +25,7 @@ #include #include +#include #include @@ -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 findConn(const String* id, MGCPChan::IdType type); inline RefPointer 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,¶ms); + MimeSdpBody* sdp = 0; + if (!m_isRtp) { + sdp = createRtpSDP(true); + if (sdp) + params.addParam("M","sendrecv"); + else + params.addParam("M","inactive"); + } + endTransaction(200,¶ms,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,¶ms); 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(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(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