diff --git a/conf.d/ysigchan.conf.sample b/conf.d/ysigchan.conf.sample index eb4daa9b..f39e2a7b 100644 --- a/conf.d/ysigchan.conf.sample +++ b/conf.d/ysigchan.conf.sample @@ -406,6 +406,15 @@ ; or unsupported message is received in an early state ;drop_unknown=yes +; needmedia: keyword: When is media absolutely required to continue the call +; In case of circuit failure the call may continue and retry circuit setup later +; Allowed values: +; no Media not required, always continue the call (default) +; ringing Media required after call is ringing +; answered Media required after call is answered +; yes Media required from the beginning +;needmedia=no + ; ignore-grs-single: boolean: Ignore (drop) circuit group reset messages with ; range 0 (1 circuit affected) ; Defaults to no diff --git a/libs/ysig/isup.cpp b/libs/ysig/isup.cpp index 0d9474e3..6c896017 100644 --- a/libs/ysig/isup.cpp +++ b/libs/ysig/isup.cpp @@ -2941,7 +2941,12 @@ SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout) m_sgmMsg = 0; return 0; } - connectCircuit(); + if (!connectCircuit() && isup() && + (isup()->mediaRequired() >= SignallingCallControl::MediaAlways)) { + TelEngine::destruct(m_sgmMsg); + setReason("bearer-cap-not-available",0,0,isup()->location()); + return release(); + } m_state = Setup; m_sgmMsg->params().setParam("overlapped",String::boolText(m_overlap)); m_lastEvent = new SignallingEvent(SignallingEvent::NewCall,m_sgmMsg,this); @@ -2976,7 +2981,12 @@ SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout) transmitMessage(new SS7MsgISUP(SS7MsgISUP::LPA,id())); break; case SS7MsgISUP::ACM: - connectCircuit(); + if (!connectCircuit() && isup() && + (isup()->mediaRequired() >= SignallingCallControl::MediaAlways)) { + TelEngine::destruct(m_sgmMsg); + setReason("bearer-cap-not-available",0,0,isup()->location()); + return release(); + } m_state = Accepted; { m_lastEvent = 0; @@ -3003,7 +3013,12 @@ SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout) } break; case SS7MsgISUP::CPR: - connectCircuit(); + if (!connectCircuit() && isup() && + (isup()->mediaRequired() >= SignallingCallControl::MediaRinging)) { + TelEngine::destruct(m_sgmMsg); + setReason("bearer-cap-not-available",0,0,isup()->location()); + return release(); + } m_state = Ringing; { bool ring = SignallingUtils::hasFlag(m_sgmMsg->params(),"EventInformation","ringing"); @@ -3016,7 +3031,12 @@ SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout) break; case SS7MsgISUP::ANM: case SS7MsgISUP::CON: - connectCircuit(); + if (!connectCircuit() && isup() && + (isup()->mediaRequired() >= SignallingCallControl::MediaAnswered)) { + TelEngine::destruct(m_sgmMsg); + setReason("bearer-cap-not-available",0,0,isup()->location()); + return release(); + } m_state = Answered; m_anmTimer.stop(); m_lastEvent = new SignallingEvent(SignallingEvent::Answer,m_sgmMsg,this); @@ -3211,6 +3231,7 @@ SS7ISUP::SS7ISUP(const NamedList& params, unsigned char sio) s << " lockcircuits=" << params.getValue("lockcircuits"); s << " userpartavail=" << String::boolText(m_userPartAvail); s << " lockgroup=" << String::boolText(m_lockGroup); + s << " mediareq=" << lookup(m_mediaRequired,s_mediaRequired); const char* sls = lookup(m_defaultSls,s_dict_callSls); s << " outboundsls="; if (sls) @@ -3254,6 +3275,8 @@ bool SS7ISUP::initialize(const NamedList* config) m_ignoreCGUSingle = config->getBoolValue("ignore-cgu-single"); m_ignoreUnkDigits = config->getBoolValue("ignore-unknown-digits",true); m_defaultSls = config->getIntValue("sls",s_dict_callSls,m_defaultSls); + m_mediaRequired = (MediaRequired)config->getIntValue("needmedia", + s_mediaRequired,m_mediaRequired); // Timers m_t9Interval = SignallingTimer::getInterval(*config,"t9",ISUP_T9_MINVAL,0,ISUP_T9_MAXVAL,true); } diff --git a/libs/ysig/sigcall.cpp b/libs/ysig/sigcall.cpp index 841ca10d..f107d18a 100644 --- a/libs/ysig/sigcall.cpp +++ b/libs/ysig/sigcall.cpp @@ -45,6 +45,21 @@ TokenDict SignallingCircuit::s_lockNames[] = { {0,0}, }; +const TokenDict SignallingCallControl::s_mediaRequired[] = { + { "no", SignallingCallControl::MediaNever }, + { "false", SignallingCallControl::MediaNever }, + { "off", SignallingCallControl::MediaNever }, + { "disable", SignallingCallControl::MediaNever }, + { "answered", SignallingCallControl::MediaAnswered }, + { "connected", SignallingCallControl::MediaAnswered }, + { "ringing", SignallingCallControl::MediaRinging }, + { "progress", SignallingCallControl::MediaRinging }, + { "yes", SignallingCallControl::MediaAlways }, + { "true", SignallingCallControl::MediaAlways }, + { "on", SignallingCallControl::MediaAlways }, + { "enable", SignallingCallControl::MediaAlways }, + { 0, 0 } +}; /** * SignallingCallControl @@ -52,6 +67,7 @@ TokenDict SignallingCircuit::s_lockNames[] = { SignallingCallControl::SignallingCallControl(const NamedList& params, const char* msgPrefix) : Mutex(true,"SignallingCallControl"), + m_mediaRequired(MediaNever), m_verifyEvent(false), m_verifyTimer(0), m_circuits(0), @@ -83,6 +99,10 @@ SignallingCallControl::SignallingCallControl(const NamedList& params, // Verify event timer m_verifyTimer.interval(params,"verifyeventinterval",10,120,true,true); m_verifyTimer.start(); + + // Media Required + m_mediaRequired = (MediaRequired)params.getIntValue("needmedia", + s_mediaRequired,m_mediaRequired); } SignallingCallControl::~SignallingCallControl() diff --git a/libs/ysig/yatesig.h b/libs/ysig/yatesig.h index a28627d4..3efd6b5b 100644 --- a/libs/ysig/yatesig.h +++ b/libs/ysig/yatesig.h @@ -987,6 +987,17 @@ class YSIG_API SignallingCallControl : public Mutex friend class ISDNQ931Call; friend class ISDNQ931CallMonitor; public: + + /** + * When is media absolutely required during the call + */ + enum MediaRequired { + MediaNever, + MediaAnswered, + MediaRinging, + MediaAlways + }; + /** * Constructor * @param params Call controller's parameters @@ -1033,6 +1044,13 @@ public: return true; } + /** + * Get the Media Required flag + * @return Configured media requirement + */ + inline MediaRequired mediaRequired() const + { return m_mediaRequired; } + /** * Get the prefix used by this call controller when decoding message parameters or * retrieve message parameters from a list @@ -1183,6 +1201,11 @@ protected: */ String m_msgPrefix; + /** + * Media required flag, call should drop if requirement not satisfied + */ + MediaRequired m_mediaRequired; + /** * Draw attention to call controller's user that something changed by * raising a Verify event @@ -1199,6 +1222,11 @@ protected: */ String m_location; + /** + * Media required keywords + */ + static const TokenDict s_mediaRequired[]; + private: SignallingCircuitGroup* m_circuits; // Circuit group int m_strategy; // Strategy to allocate circuits for outgoing calls