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.
;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
; This option is applied on reload
; Defaults to no
@ -377,6 +381,10 @@
; If not set calls that request continuity check will be rejected
;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
; Available values are:
; U User

View File

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

View File

@ -227,6 +227,7 @@ private:
bool sendAsync(MGCPMessage* mm);
RefPointer<MGCPMessage> sendSync(MGCPMessage* mm);
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);
void cleanupRtp();
bool createRtp();
@ -236,6 +237,7 @@ private:
String m_notify;
String m_specialMode;
bool m_changing;
bool m_pending;
// Gateway endpoint bearer information
String m_gwFormat;
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)
: SignallingCircuit(RTP,code,Missing,span->group(),span),
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)
{
Debug(&splugin,DebugAll,"MGCPCircuit::MGCPCircuit(%u,%p,'%s') [%p]",
@ -1360,6 +1363,7 @@ void MGCPCircuit::clearConn(bool force)
m_remoteRawSdp.clear();
m_localRtpChanged = false;
sendAsync(mm);
sendPending();
}
// 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);
if (sigReq)
mm->params.addParam("S",sigReq);
else
m_pending = false;
if (reqEvt)
mm->params.addParam("R",reqEvt);
if (digitMap)
@ -1445,6 +1451,25 @@ bool MGCPCircuit::sendRequest(const char* sigReq, const char* reqEvt, const char
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
bool MGCPCircuit::status(Status newStat, bool sync)
{
@ -1657,11 +1682,12 @@ bool MGCPCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params
case SignallingCircuitEvent::Connect:
if (params)
setParams(*params);
sendPending();
return status(Connected,!params || params->getBoolValue("sync",true));
case SignallingCircuitEvent::RingBegin:
return fxs() && sendRequest("L/rg");
// case SignallingCircuitEvent::RingEnd:
// return fxs() && sendRequest("L/rg(-)");
return fxs() && sendPending("L/rg");
case SignallingCircuitEvent::RingEnd:
return fxs() && sendPending();
case SignallingCircuitEvent::Polarity:
return fxs() && sendRequest("L/lsa");
case SignallingCircuitEvent::OffHook:
@ -1679,6 +1705,19 @@ bool MGCPCircuit::sendEvent(SignallingCircuitEvent::Type type, NamedList* params
return sendRequest("D/" + *tone);
}
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:
;
}

View File

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