Added capability to force a ringback to a MGCP gateway from ISDN and ISUP.

Fixed ring end on FXS analog MGCP gateways.


git-svn-id: http://voip.null.ro/svn/yate@4062 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2011-01-25 11:46:13 +00:00
parent 26f88f5539
commit 13a1cf786d
4 changed files with 79 additions and 5 deletions

View File

@ -146,6 +146,10 @@
; alaw is used commonly in Europe while mulaw is used commonly in US and Japan. ; alaw is used commonly in Europe while mulaw is used commonly in US and Japan.
;format=alaw ;format=alaw
; ringback: boolean: Offer a ringback tone even if not provided by peer channel
; If it fails the correct indication (no inband available) is signaled
;ringback=no
; print-messages: boolean: Print decoded protocol data units to output ; print-messages: boolean: Print decoded protocol data units to output
; This option is applied on reload ; This option is applied on reload
; Defaults to no ; Defaults to no
@ -377,6 +381,10 @@
; If not set calls that request continuity check will be rejected ; If not set calls that request continuity check will be rejected
;continuity= ;continuity=
; ringback: boolean: Offer a ringback tone even if not provided by peer channel
; If it fails the correct indication (no inband available) is signaled
;ringback=no
; location: string: Exchange location to be set when sending Q.850 causes ; location: string: Exchange location to be set when sending Q.850 causes
; Available values are: ; Available values are:
; U User ; U User

View File

@ -1466,6 +1466,7 @@ public:
enum Type { enum Type {
Unknown = 0, Unknown = 0,
Dtmf = 1, // Transfer tones: param: tone Dtmf = 1, // Transfer tones: param: tone
GenericTone = 2, // Play or detect tones: param: tone
// Analog line events // Analog line events
Timeout = 10, // Timeout = 10, //
Polarity = 11, // Line's polarity changed Polarity = 11, // Line's polarity changed

View File

@ -227,6 +227,7 @@ private:
bool sendAsync(MGCPMessage* mm); bool sendAsync(MGCPMessage* mm);
RefPointer<MGCPMessage> sendSync(MGCPMessage* mm); RefPointer<MGCPMessage> sendSync(MGCPMessage* mm);
bool sendRequest(const char* sigReq, const char* reqEvt = 0, const char* digitMap = 0); bool sendRequest(const char* sigReq, const char* reqEvt = 0, const char* digitMap = 0);
bool sendPending(const char* sigReq = 0);
bool enqueueEvent(SignallingCircuitEvent::Type type, const char* name, const char* dtmf = 0); bool enqueueEvent(SignallingCircuitEvent::Type type, const char* name, const char* dtmf = 0);
void cleanupRtp(); void cleanupRtp();
bool createRtp(); bool createRtp();
@ -236,6 +237,7 @@ private:
String m_notify; String m_notify;
String m_specialMode; String m_specialMode;
bool m_changing; bool m_changing;
bool m_pending;
// Gateway endpoint bearer information // Gateway endpoint bearer information
String m_gwFormat; String m_gwFormat;
bool m_gwFormatChanged; bool m_gwFormatChanged;
@ -1214,7 +1216,8 @@ bool MGCPSpan::processDelete(MGCPTransaction* tr, MGCPMessage* mm, const String&
MGCPCircuit::MGCPCircuit(unsigned int code, MGCPSpan* span, const char* id) MGCPCircuit::MGCPCircuit(unsigned int code, MGCPSpan* span, const char* id)
: SignallingCircuit(RTP,code,Missing,span->group(),span), : SignallingCircuit(RTP,code,Missing,span->group(),span),
SDPSession(&splugin.parser()), SDPSession(&splugin.parser()),
m_epId(id), m_statusReq(Missing), m_changing(false), m_gwFormatChanged(false), m_epId(id), m_statusReq(Missing),
m_changing(false), m_pending(false), m_gwFormatChanged(false),
m_localRtpChanged(false), m_needClear(false), m_tr(0) m_localRtpChanged(false), m_needClear(false), m_tr(0)
{ {
Debug(&splugin,DebugAll,"MGCPCircuit::MGCPCircuit(%u,%p,'%s') [%p]", Debug(&splugin,DebugAll,"MGCPCircuit::MGCPCircuit(%u,%p,'%s') [%p]",
@ -1360,6 +1363,7 @@ void MGCPCircuit::clearConn(bool force)
m_remoteRawSdp.clear(); m_remoteRawSdp.clear();
m_localRtpChanged = false; m_localRtpChanged = false;
sendAsync(mm); sendAsync(mm);
sendPending();
} }
// Wait for changing flag to be false // Wait for changing flag to be false
@ -1438,6 +1442,8 @@ bool MGCPCircuit::sendRequest(const char* sigReq, const char* reqEvt, const char
mm->params.addParam("X",m_notify); mm->params.addParam("X",m_notify);
if (sigReq) if (sigReq)
mm->params.addParam("S",sigReq); mm->params.addParam("S",sigReq);
else
m_pending = false;
if (reqEvt) if (reqEvt)
mm->params.addParam("R",reqEvt); mm->params.addParam("R",reqEvt);
if (digitMap) if (digitMap)
@ -1445,6 +1451,25 @@ bool MGCPCircuit::sendRequest(const char* sigReq, const char* reqEvt, const char
return sendAsync(mm); return sendAsync(mm);
} }
// Send or clear pending (timeout) signal requests
bool MGCPCircuit::sendPending(const char* sigReq)
{
if (TelEngine::null(sigReq) && !m_pending)
return true;
Debug(&splugin,DebugInfo,"MGCPCircuit %s pending%s%s %u [%p]",
(sigReq ? "Signal" : "Clear all"),
(sigReq ? ": " : ""),c_safe(sigReq),
code(),this);
MGCPMessage* mm = message("RQNT");
mm->params.addParam("X",m_notify);
if (sigReq)
mm->params.addParam("S",sigReq);
if (!sendAsync(mm))
return false;
m_pending = !TelEngine::null(sigReq);
return true;
}
// Circuit status change request // Circuit status change request
bool MGCPCircuit::status(Status newStat, bool sync) bool MGCPCircuit::status(Status newStat, bool sync)
{ {
@ -1657,11 +1682,12 @@ bool MGCPCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params
case SignallingCircuitEvent::Connect: case SignallingCircuitEvent::Connect:
if (params) if (params)
setParams(*params); setParams(*params);
sendPending();
return status(Connected,!params || params->getBoolValue("sync",true)); return status(Connected,!params || params->getBoolValue("sync",true));
case SignallingCircuitEvent::RingBegin: case SignallingCircuitEvent::RingBegin:
return fxs() && sendRequest("L/rg"); return fxs() && sendPending("L/rg");
// case SignallingCircuitEvent::RingEnd: case SignallingCircuitEvent::RingEnd:
// return fxs() && sendRequest("L/rg(-)"); return fxs() && sendPending();
case SignallingCircuitEvent::Polarity: case SignallingCircuitEvent::Polarity:
return fxs() && sendRequest("L/lsa"); return fxs() && sendRequest("L/lsa");
case SignallingCircuitEvent::OffHook: case SignallingCircuitEvent::OffHook:
@ -1679,6 +1705,19 @@ bool MGCPCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params
return sendRequest("D/" + *tone); return sendRequest("D/" + *tone);
} }
break; break;
case SignallingCircuitEvent::GenericTone:
if (params) {
const String* tone = params->getParam("tone");
if (!tone)
tone = params;
if (null(tone))
break;
if (*tone == "ringback" || *tone == "ring" || *tone == "rt")
return sendPending("G/rt");
if (*tone == "congestion" || *tone == "cg")
return sendPending("G/cg");
}
break;
default: default:
; ;
} }

View File

@ -136,6 +136,7 @@ private:
bool m_hungup; // Hang up flag bool m_hungup; // Hang up flag
String m_reason; // Hangup reason String m_reason; // Hangup reason
bool m_inband; // True to try to send in-band tones bool m_inband; // True to try to send in-band tones
bool m_ringback; // Always provide ringback media
bool m_rtpForward; // Forward RTP bool m_rtpForward; // Forward RTP
bool m_sdpForward; // Forward SDP (only of rtp forward is enabled) bool m_sdpForward; // Forward SDP (only of rtp forward is enabled)
Message* m_route; // Prepared call.preroute message Message* m_route; // Prepared call.preroute message
@ -329,6 +330,8 @@ public:
{ return m_controller; } { return m_controller; }
inline bool inband() const inline bool inband() const
{ return m_inband; } { return m_inband; }
inline bool ringback() const
{ return m_ringback; }
// Set exiting flag for call controller and timeout for the thread // Set exiting flag for call controller and timeout for the thread
void setExiting(unsigned int msec); void setExiting(unsigned int msec);
// Initialize (create or reload) the trunk. Process the debuglayer parameter. // Initialize (create or reload) the trunk. Process the debuglayer parameter.
@ -376,6 +379,7 @@ protected:
SignallingCallControl* m_controller; // Call controller, if any SignallingCallControl* m_controller; // Call controller, if any
bool m_init; // True if already initialized bool m_init; // True if already initialized
bool m_inband; // True to send in-band tones through this trunk bool m_inband; // True to send in-band tones through this trunk
bool m_ringback; // Always provide ringback media
private: private:
Type m_type; // Trunk type Type m_type; // Trunk type
SigTrunkThread* m_thread; // Event thread for call controller SigTrunkThread* m_thread; // Event thread for call controller
@ -792,6 +796,7 @@ SigChannel::SigChannel(SignallingEvent* event)
m_trunk(0), m_trunk(0),
m_hungup(true), m_hungup(true),
m_inband(false), m_inband(false),
m_ringback(false),
m_rtpForward(false), m_rtpForward(false),
m_sdpForward(false), m_sdpForward(false),
m_route(0), m_route(0),
@ -807,8 +812,10 @@ SigChannel::SigChannel(SignallingEvent* event)
m_called = msg ? msg->params().getValue("called") : 0; m_called = msg ? msg->params().getValue("called") : 0;
m_call->userdata(this); m_call->userdata(this);
m_trunk = plugin.findTrunk(m_call->controller()); m_trunk = plugin.findTrunk(m_call->controller());
if (m_trunk) if (m_trunk) {
m_inband = m_trunk->inband(); m_inband = m_trunk->inband();
m_ringback = m_trunk->ringback();
}
// Startup // Startup
m_hungup = false; m_hungup = false;
setState(0); setState(0);
@ -851,6 +858,7 @@ SigChannel::SigChannel(const char* caller, const char* called)
m_hungup(true), m_hungup(true),
m_reason("noconn"), m_reason("noconn"),
m_inband(false), m_inband(false),
m_ringback(false),
m_rtpForward(false), m_rtpForward(false),
m_sdpForward(false), m_sdpForward(false),
m_route(0), m_route(0),
@ -951,6 +959,7 @@ bool SigChannel::startCall(Message& msg, SigTrunk* trunk)
return false; return false;
// Data // Data
m_inband = msg.getBoolValue("dtmfinband",trunk->inband()); m_inband = msg.getBoolValue("dtmfinband",trunk->inband());
m_ringback = msg.getBoolValue("ringback",trunk->ringback());
// Make the call // Make the call
SignallingMessage* sigMsg = new SignallingMessage; SignallingMessage* sigMsg = new SignallingMessage;
sigMsg->params().addParam("caller",m_caller); sigMsg->params().addParam("caller",m_caller);
@ -1037,6 +1046,8 @@ bool SigChannel::msgProgress(Message& msg)
SignallingMessage* sm = new SignallingMessage; SignallingMessage* sm = new SignallingMessage;
if (media && updateConsumer(format,false) && format) if (media && updateConsumer(format,false) && format)
sm->params().addParam("format",format); sm->params().addParam("format",format);
if (media)
m_ringback = false;
sm->params().addParam("earlymedia",String::boolText(media)); sm->params().addParam("earlymedia",String::boolText(media));
SignallingEvent* event = new SignallingEvent(SignallingEvent::Progress,sm,m_call); SignallingEvent* event = new SignallingEvent(SignallingEvent::Progress,sm,m_call);
TelEngine::destruct(sm); TelEngine::destruct(sm);
@ -1060,6 +1071,17 @@ bool SigChannel::msgRinging(Message& msg)
SignallingMessage* sm = new SignallingMessage; SignallingMessage* sm = new SignallingMessage;
if (media && updateConsumer(format,false) && format) if (media && updateConsumer(format,false) && format)
sm->params().addParam("format",format); sm->params().addParam("format",format);
if (m_ringback && !media) {
// Attempt to provide ringback using circuit features
SignallingCircuit* cic = getCircuit();
if (cic) {
NamedList params("ringback");
params.addParam("tone","ringback");
media = cic->sendEvent(SignallingCircuitEvent::GenericTone,&params);
}
}
if (media)
m_ringback = false;
sm->params().addParam("earlymedia",String::boolText(media)); sm->params().addParam("earlymedia",String::boolText(media));
SignallingEvent* event = new SignallingEvent(SignallingEvent::Ringing,sm,m_call); SignallingEvent* event = new SignallingEvent(SignallingEvent::Ringing,sm,m_call);
TelEngine::destruct(sm); TelEngine::destruct(sm);
@ -1078,6 +1100,7 @@ bool SigChannel::msgAnswered(Message& msg)
setState("answered"); setState("answered");
if (!m_call) if (!m_call)
return true; return true;
m_ringback = false;
updateSource(0,false); updateSource(0,false);
// Start echo training // Start echo training
SignallingCircuit* cic = getCircuit(); SignallingCircuit* cic = getCircuit();
@ -1222,6 +1245,7 @@ void SigChannel::callAccept(Message& msg)
} }
TelEngine::destruct(sm); TelEngine::destruct(sm);
} }
m_ringback = msg.getBoolValue("ringback",m_ringback);
if (m_rtpForward) { if (m_rtpForward) {
const String* tmp = msg.getParam("rtp_forward"); const String* tmp = msg.getParam("rtp_forward");
if (!(tmp && (*tmp == "accepted"))) if (!(tmp && (*tmp == "accepted")))
@ -2605,6 +2629,7 @@ SigTrunk::SigTrunk(const char* name, Type type)
m_controller(0), m_controller(0),
m_init(false), m_init(false),
m_inband(false), m_inband(false),
m_ringback(false),
m_type(type), m_type(type),
m_thread(0) m_thread(0)
{ {
@ -2636,6 +2661,7 @@ bool SigTrunk::initialize(NamedList& params)
{ {
// Reload common parameters // Reload common parameters
m_inband = params.getBoolValue("dtmfinband",s_cfg.getBoolValue("general","dtmfinband",false)); m_inband = params.getBoolValue("dtmfinband",s_cfg.getBoolValue("general","dtmfinband",false));
m_ringback = params.getBoolValue("ringback",s_cfg.getBoolValue("general","ringback",false));
// Check error: // Check error:
// No need to initialize if no signalling engine or not in plugin's list // No need to initialize if no signalling engine or not in plugin's list