Support receiving overlapped dialing on ISUP.

Send extra Called Party Number digits in a SAM message.
The overlapped dialing script accepts an initial number.
Merged branch paulc/pstn -c 3485


git-svn-id: http://voip.null.ro/svn/yate@3493 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2010-08-21 18:34:01 +00:00
parent d69f79fada
commit d236762fc1
7 changed files with 321 additions and 36 deletions

View File

@ -331,6 +331,10 @@
; 0..255 Explicit numeric value, gets truncated to the SLS bit range
;sls=last (cic if pointcodetype is ITU)
; maxcalleddigits: integer: Maximum number of digits in an IAM Called Party Number
; If the called number is longer the extra digits will be sent in a SAM message
;maxcalleddigits=16
; numplan: string: Default numbering plan for outgoing calls
; Values: unknown, isdn, data, telex, national, private
; Defaults to unknown if missing or incorrect

View File

@ -751,6 +751,14 @@ static unsigned char encodeDigits(const SS7ISUP* isup, SS7MSU& msu,
return setDigits(msu,val ? val->c_str() : 0,nai,b2,-1,b0);
}
// Special encoder for subsequent number
static unsigned char encodeSubseq(const SS7ISUP* isup, SS7MSU& msu,
unsigned char* buf, const IsupParam* param, const NamedString* val,
const NamedList* extra, const String& prefix)
{
return setDigits(msu,val ? val->c_str() : 0,0);
}
// Encoder for circuit group range and status (Q.763 3.43)
static unsigned char encodeRangeSt(const SS7ISUP* isup, SS7MSU& msu,
unsigned char* buf, const IsupParam* param, const NamedString* val,
@ -1252,7 +1260,7 @@ static const IsupParam s_paramDefs[] = {
MAKE_PARAM(RemoteOperations, 0,0, 0, 0), // 3.48
MAKE_PARAM(ServiceActivation, 0,0, 0, 0), // 3.49
MAKE_PARAM(SignallingPointCode, 0,0, 0, 0), // 3.50
MAKE_PARAM(SubsequentNumber, 0,decodeSubseq, 0, 0), // 3.51
MAKE_PARAM(SubsequentNumber, 0,decodeSubseq, encodeSubseq, 0), // 3.51
MAKE_PARAM(SuspendResumeIndicators, 0,0, 0, 0), // 3.52
MAKE_PARAM(TransitNetworkSelection, 0,0, 0, 0), // 3.53
MAKE_PARAM(TransmissionMediumRequirement, 1,decodeInt, encodeInt, s_dict_mediumReq), // 3.54
@ -1932,6 +1940,12 @@ static int transmitCNF(SS7ISUP* isup, unsigned int cic, const SS7Label& label, b
}
// Utility used to check for called number completion
static inline bool isCalledIncomplete(const NamedList& l, const String& p = "CalledPartyNumber")
{
return !l[p].endsWith(".");
}
/**
* SS7ISUPCall
*/
@ -1949,6 +1963,7 @@ SS7ISUPCall::SS7ISUPCall(SS7ISUP* controller, SignallingCircuit* cic,
m_inbandAvailable(false),
m_iamMsg(0),
m_sgmMsg(0),
m_sentSamDigits(0),
m_relTimer(300000), // Q.764: T5 - 5..15 minutes
m_iamTimer(20000), // Q.764: T7 - 20..30 seconds
m_sgmRecvTimer(3000) // Q.764: T34 - 2..4 seconds
@ -2043,6 +2058,7 @@ SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
const char* sgmParam = "OptionalBackwardCallIndicators";
if (msg->type() == SS7MsgISUP::IAM) {
copyParamIAM(msg);
setOverlapped(isCalledIncomplete(msg->params()));
sgmParam = "OptionalForwardCallIndicators";
}
// Check segmentation. Keep the message and start timer if segmented
@ -2055,7 +2071,9 @@ SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
processSegmented(0,false);
break;
case SS7MsgISUP::SAM:
setOverlapped(isCalledIncomplete(msg->params(),"SubsequentNumber"));
msg->params().addParam("tone",msg->params().getValue("SubsequentNumber"));
msg->params().addParam("dialing",String::boolText(true));
m_lastEvent = new SignallingEvent(SignallingEvent::Info,msg,this);
break;
case SS7MsgISUP::RLC:
@ -2101,6 +2119,9 @@ SignallingEvent* SS7ISUPCall::getEvent(const Time& when)
default: ;
}
}
// Reset overlapped if our state is greater then Setup
if (m_state > Setup)
setOverlapped(false,false);
// Check circuit event
if (!m_lastEvent && m_circuit) {
SignallingCircuitEvent* cicEvent = m_circuit->getEvent(when);
@ -2153,6 +2174,16 @@ bool SS7ISUPCall::sendEvent(SignallingEvent* event)
}
m_iamMsg = new SS7MsgISUP(SS7MsgISUP::IAM,id());
copyParamIAM(m_iamMsg,true,event->message());
// Update overlap
setOverlapped(m_iamMsg->params());
if (m_overlap) {
// Check for maximum number of digits allowed
String* called = m_iamMsg->params().getParam("CalledPartyNumber");
if (called && called->length() > isup()->m_maxCalledDigits) {
m_samDigits = called->substr(isup()->m_maxCalledDigits);
*called = called->substr(0,isup()->m_maxCalledDigits);
}
}
result = transmitIAM();
}
break;
@ -2217,6 +2248,12 @@ bool SS7ISUPCall::sendEvent(SignallingEvent* event)
}
break;
case SignallingEvent::Info:
if (validMsgState(true,SS7MsgISUP::SAM)) {
mylock.drop();
transmitSAM(event->message()->params().getValue("tone"));
result = true;
break;
}
//case SignallingEvent::Message:
//case SignallingEvent::Transfer:
default:
@ -2224,6 +2261,9 @@ bool SS7ISUPCall::sendEvent(SignallingEvent* event)
"Call(%u). sendEvent not implemented for '%s' [%p]",
id(),event->name(),this);
}
// Reset overlapped if our state is greater then Setup
if (m_state > Setup)
setOverlapped(false,false);
XDebug(isup(),DebugAll,"Call(%u). Event (%p,'%s') sent. Result: %s [%p]",
id(),event,event->name(),String::boolText(result),this);
mylock.drop();
@ -2429,7 +2469,7 @@ bool SS7ISUPCall::validMsgState(bool send, SS7MsgISUP::Type type)
break;
return true;
case SS7MsgISUP::SAM: // Subsequent address
if (m_state != Setup)
if (m_state != Setup || !m_overlap || send != outgoing())
break;
return true;
case SS7MsgISUP::REL: // Release
@ -2504,7 +2544,49 @@ bool SS7ISUPCall::transmitIAM()
m_state = Setup;
m_iamMsg->m_cic = id();
m_iamMsg->ref();
return transmitMessage(m_iamMsg);
// Reset SAM digits: this might be a re-send
m_sentSamDigits = 0;
bool ok = transmitMessage(m_iamMsg);
if (ok && m_overlap)
transmitSAM();
return ok;
}
// Transmit SAM digits
bool SS7ISUPCall::transmitSAM(const char* extra)
{
if (!m_overlap)
return false;
m_samDigits << extra;
while (m_samDigits.length() > m_sentSamDigits) {
unsigned int send = m_samDigits.length() - m_sentSamDigits;
if (send > isup()->m_maxCalledDigits)
send = isup()->m_maxCalledDigits;
SS7MsgISUP* m = new SS7MsgISUP(SS7MsgISUP::SAM,id());
String number = m_samDigits.substr(m_sentSamDigits,send);
m->params().addParam("SubsequentNumber",number);
bool complete = !isCalledIncomplete(m->params(),"SubsequentNumber");
bool ok = transmitMessage(m);
if (ok) {
m_sentSamDigits += send;
if (complete) {
if (m_samDigits.length() > m_sentSamDigits)
Debug(isup(),DebugNote,
"Call(%u). Completed number sending remaining='%s' [%p]",
id(),m_samDigits.substr(m_sentSamDigits).c_str(),this);
// Reset overlap sending
setOverlapped(false);
break;
}
}
else {
Debug(isup(),DebugNote,"Call(%u). Failed to send SAM with '%s' [%p]",
id(),number.c_str(),this);
complete = false;
break;
}
}
return true;
}
bool SS7ISUPCall::needsTesting(const SS7MsgISUP* msg)
@ -2598,6 +2680,7 @@ SignallingEvent* SS7ISUPCall::processSegmented(SS7MsgISUP* sgm, bool timeout)
}
connectCircuit();
m_state = Setup;
m_sgmMsg->params().setParam("overlapped",String::boolText(m_overlap));
m_lastEvent = new SignallingEvent(SignallingEvent::NewCall,m_sgmMsg,this);
break;
case SS7MsgISUP::CCR:
@ -2700,6 +2783,17 @@ SS7ISUP* SS7ISUPCall::isup() const
return static_cast<SS7ISUP*>(SignallingCall::controller());
}
// Set overlapped flag. Output a debug message
void SS7ISUPCall::setOverlapped(bool on, bool numberComplete)
{
if (m_overlap == on)
return;
m_overlap = on;
const char* reason = on ? "" : (numberComplete ? " (number complete)" : " (state changed)");
Debug(isup(),DebugAll,"Call(%u). Overlapped dialing is %s%s [%p]",
id(),String::boolText(on),reason,this);
}
/**
* SS7ISUP
@ -2716,6 +2810,7 @@ SS7ISUP::SS7ISUP(const NamedList& params, unsigned char sio)
m_earlyAcm(true),
m_inn(false),
m_defaultSls(SlsLatest),
m_maxCalledDigits(16),
m_l3LinkUp(false),
m_uptTimer(0),
m_userPartAvail(true),
@ -2799,6 +2894,9 @@ SS7ISUP::SS7ISUP(const NamedList& params, unsigned char sio)
m_continuity = params.getValue("continuity");
m_defaultSls = params.getIntValue("sls",s_dict_callSls,m_defaultSls);
m_maxCalledDigits = params.getIntValue("maxcalleddigits",m_maxCalledDigits);
if (m_maxCalledDigits < 1)
m_maxCalledDigits = 16;
setDebug(params.getBoolValue("print-messages",false),
params.getBoolValue("extended-debug",false));

View File

@ -713,7 +713,6 @@ ISDNQ931Call::ISDNQ931Call(ISDNQ931* controller, bool outgoing,
m_callRefLen(callRefLen),
m_tei(tei),
m_circuit(0),
m_overlap(false),
m_circuitChange(false),
m_channelIDSent(false),
m_rspBearerCaps(false),

View File

@ -240,6 +240,7 @@ void SignallingCallControl::removeCall(SignallingCall* call, bool del)
SignallingCall::SignallingCall(SignallingCallControl* controller, bool outgoing, bool signalOnly)
: Mutex(true,"SignallingCall"),
m_lastEvent(0),
m_overlap(false),
m_controller(controller),
m_outgoing(outgoing),
m_signalOnly(signalOnly),

View File

@ -1173,6 +1173,13 @@ public:
inline bool signalOnly() const
{ return m_signalOnly; }
/**
* Check if this call is in overlapped send/recv state
* @return True if this call is expecting more digits to be sent/received
*/
inline bool overlapDialing() const
{ return m_overlap; }
/**
* Send an event to this call
* @param event The event to send
@ -1227,6 +1234,11 @@ protected:
*/
SignallingEvent* m_lastEvent;
/**
* Call is in overlapped send/recv state
*/
bool m_overlap;
private:
SignallingCallControl* m_controller; // Call controller this call belongs to
bool m_outgoing; // Call direction
@ -7130,6 +7142,8 @@ private:
bool connectCircuit(const char* special = 0);
// Transmit the IAM message. Start IAM timer if not started
bool transmitIAM();
// Transmit SAM digits
bool transmitSAM(const char* extra = 0);
// Check if the circuit needs continuity testing
bool needsTesting(const SS7MsgISUP* msg);
// Stop waiting for a SGM (Segmentation) message. Copy parameters to the pending segmented message if sgm is valid.
@ -7142,6 +7156,8 @@ private:
inline bool transmitMessage(SS7MsgISUP* msg);
// Get the ISUP call controller
inline SS7ISUP* isup() const;
// Set overlapped flag. Output a debug message
void setOverlapped(bool on, bool numberComplete = true);
State m_state; // Call state
SignallingCircuit* m_circuit; // Circuit reserved for this call
@ -7158,6 +7174,9 @@ private:
String m_location; // Termination location
SS7MsgISUP* m_iamMsg; // Message with the call parameters for outgoing calls
SS7MsgISUP* m_sgmMsg; // Pending received message with segmentation flag set
// Overlapped
String m_samDigits; // SAM digits
unsigned int m_sentSamDigits; // The number of sent SAM digits
// Timers
SignallingTimer m_relTimer; // Send release
SignallingTimer m_iamTimer; // Send initial address
@ -7454,6 +7473,7 @@ private:
bool m_earlyAcm; // Accept progress/ringing in early ACM
bool m_inn; // Routing to internal network number flag
int m_defaultSls; // Default SLS to use in outbound calls
unsigned int m_maxCalledDigits; // Maximum digits allowed in Called Number in IAM
String m_numPlan; // Numbering plan
String m_numType; // Number type
String m_numPresentation; // Number presentation
@ -9566,7 +9586,6 @@ private:
u_int32_t m_callRefLen; // Call reference length
u_int8_t m_tei; // TEI used for the call
SignallingCircuit* m_circuit; // Circuit reserved for this call
bool m_overlap; // Call is using overlapped sending
bool m_circuitChange; // True if circuit changed
bool m_channelIDSent; // Incoming calls: ChannelID IE already sent
bool m_rspBearerCaps; // Incoming calls: Send BearerCaps IE in the first response

View File

@ -78,6 +78,7 @@ public:
virtual void callAccept(Message& msg);
virtual void callRejected(const char* error, const char* reason = 0,
const Message* msg = 0);
virtual void connected(const char *reason);
virtual void disconnected(bool final, const char* reason);
bool disconnect()
{ return Channel::disconnect(m_reason); }
@ -122,6 +123,10 @@ private:
// Process parameter compatibility data from a message
// Return true if the call was terminated
bool processCompat(const NamedList& list);
// Send a tone through signalling call
bool sendSigTone(Message& msg, const char* tone);
// Release postponed call accepted event. Send it if requested
void releaseCallAccepted(bool send = false);
private:
String m_caller;
String m_called;
@ -133,6 +138,8 @@ private:
bool m_rtpForward; // Forward RTP
bool m_sdpForward; // Forward SDP (only of rtp forward is enabled)
Message* m_route; // Prepared call.preroute message
ObjList m_chanDtmf; // Postponed (received while routing) chan.dtmf messages
SignallingEvent* m_callAccdEvent; // Postponed call accepted event to be sent to remote
};
class SigDriver : public Driver
@ -759,7 +766,8 @@ SigChannel::SigChannel(SignallingEvent* event)
m_inband(false),
m_rtpForward(false),
m_sdpForward(false),
m_route(0)
m_route(0),
m_callAccdEvent(0)
{
if (!(m_call && m_call->ref())) {
Debug(this,DebugCall,"No signalling call for this incoming call");
@ -817,13 +825,15 @@ SigChannel::SigChannel(const char* caller, const char* called)
m_inband(false),
m_rtpForward(false),
m_sdpForward(false),
m_route(0)
m_route(0),
m_callAccdEvent(0)
{
}
SigChannel::~SigChannel()
{
TelEngine::destruct(m_route);
releaseCallAccepted();
hangup();
setState("destroyed",true,true);
}
@ -1062,6 +1072,14 @@ bool SigChannel::msgTone(Message& msg, const char* tone)
return true;
Lock lock(m_mutex);
DDebug(this,DebugCall,"Tone. '%s' %s[%p]",tone,(m_call ? "" : ". No call "),this);
// Outgoing, overlap dialing call: try it first
if (isOutgoing() && m_call && m_call->overlapDialing()) {
lock.drop();
if (sendSigTone(msg,tone))
return true;
}
// Re-aquire lock
Lock lock2(m_mutex);
// Try to send: through the circuit, in band or through the signalling protocol
SignallingCircuit* cic = getCircuit();
if (cic) {
@ -1074,13 +1092,9 @@ bool SigChannel::msgTone(Message& msg, const char* tone)
return true;
if (!m_call)
return true;
SignallingMessage* sm = new SignallingMessage;
sm->params().addParam("tone",tone);
SignallingEvent* event = new SignallingEvent(SignallingEvent::Info,sm,m_call);
TelEngine::destruct(sm);
lock2.drop();
lock.drop();
plugin.copySigMsgParams(event,msg);
event->sendEvent();
sendSigTone(msg,tone);
return true;
}
@ -1158,12 +1172,20 @@ void SigChannel::callAccept(Message& msg)
Lock lock(m_mutex);
SignallingEvent* event = 0;
if (!terminated && m_call) {
// Check if we should accept now the call
bool acceptNow = msg.getBoolValue("accept_call",true);
const char* format = msg.getValue("format");
updateConsumer(format,false);
SignallingMessage* sm = new SignallingMessage;
if (format)
sm->params().addParam("format",format);
event = new SignallingEvent(SignallingEvent::Accept,sm,m_call);
if (acceptNow)
event = new SignallingEvent(SignallingEvent::Accept,sm,m_call);
else {
DDebug(this,DebugAll,"Postponing call accepted [%p]",this);
m_callAccdEvent = new SignallingEvent(SignallingEvent::Accept,sm,m_call);
plugin.copySigMsgParams(m_callAccdEvent,msg,"i");
}
TelEngine::destruct(sm);
}
if (m_rtpForward) {
@ -1178,6 +1200,13 @@ void SigChannel::callAccept(Message& msg)
event->sendEvent();
}
Channel::callAccept(msg);
// Enqueue pending DTMFs
GenObject* gen = 0;
while (0 != (gen = m_chanDtmf.remove(false))) {
Message* m = static_cast<Message*>(gen);
complete(*m);
dtmfEnqueue(m);
}
}
void SigChannel::callRejected(const char* error, const char* reason, const Message* msg)
@ -1188,6 +1217,12 @@ void SigChannel::callRejected(const char* error, const char* reason, const Messa
hangup();
}
void SigChannel::connected(const char *reason)
{
releaseCallAccepted(true);
Channel::connected(m_reason);
}
void SigChannel::disconnected(bool final, const char* reason)
{
if (m_reason.null())
@ -1201,6 +1236,7 @@ void SigChannel::hangup(const char* reason, SignallingEvent* event)
{
static String params = "reason";
Lock lock(m_mutex);
releaseCallAccepted();
if (m_hungup)
return;
m_hungup = true;
@ -1283,7 +1319,13 @@ void SigChannel::evInfo(SignallingEvent* event)
Message* m = message("chan.dtmf");
m->addParam("text",tmp);
m->addParam("detected",inband ? "inband" : "signal");
dtmfEnqueue(m);
m->copyParams(event->message()->params(),"dialing");
if (status() != "incoming")
dtmfEnqueue(m);
else {
Lock lock(m_mutex);
m_chanDtmf.append(m);
}
}
}
@ -1506,6 +1548,34 @@ bool SigChannel::processCompat(const NamedList& list)
return terminated;
}
// Send a tone through signalling call
bool SigChannel::sendSigTone(Message& msg, const char* tone)
{
Lock lock(m_mutex);
if (!m_call)
return false;
SignallingMessage* sm = new SignallingMessage;
sm->params().addParam("tone",tone);
SignallingEvent* event = new SignallingEvent(SignallingEvent::Info,sm,m_call);
TelEngine::destruct(sm);
lock.drop();
plugin.copySigMsgParams(event,msg);
return event->sendEvent();
}
// Release postponed call accepted event. Sent it if requested
void SigChannel::releaseCallAccepted(bool send)
{
Lock lock(m_mutex);
if (!m_callAccdEvent)
return;
if (send)
m_callAccdEvent->sendEvent();
else
delete m_callAccdEvent;
m_callAccdEvent = 0;
}
/**
* SigDriver
*/

View File

@ -30,12 +30,21 @@ $partycallid = "";
$state = "call";
$num = "";
$collect = "";
// Queued, not yet used DTMFs
$queue = "";
// Initial call.execute message used when re-routing
$executeParams = array();
// Final digit detected: no more routes allowed
$final = false;
// Don't answer the call, don't use prompts
$routeOnly = true;
function setState($newstate)
{
global $ourcallid;
global $state;
global $collect;
global $routeOnly;
// are we exiting?
if ($state == "")
@ -59,6 +68,11 @@ function setState($newstate)
if ($newstate == $state)
return;
if ($routeOnly) {
$state = $newstate;
return;
}
switch ($newstate) {
case "goodbye":
$m = new Yate("chan.attach");
@ -94,8 +108,10 @@ function setState($newstate)
function routeTo($num)
{
global $ourcallid;
global $executeParams;
setState("routing");
$m = new Yate("call.route");
$m->params = $executeParams;
$m->params["id"] = $ourcallid;
$m->params["called"] = $num;
$m->params["overlapped"] = "yes";
@ -119,25 +135,71 @@ function gotNotify()
}
}
function gotDTMF($dtmf)
function gotDTMF($dtmfs)
{
global $state;
global $collect;
global $queue;
global $final;
global $routeOnly;
Yate::Debug("Overlapped gotDTMF('$dtmf') in state: $state collected: '$collect'");
switch ($dtmf) {
case "*":
Yate::Debug("Overlapped gotDTMF('$dtmfs') in state: '$state' collected: '$collect' queued: '$queue'");
$queue .= $dtmfs;
if ($state == "routing")
return;
$route = false;
while (true) {
$n = strlen($queue);
if ($n < 1)
break;
if ($state == "call") {
// First call: use all digits to route
$route = true;
if ($queue[$n - 1] != ".")
$collect .= $queue;
else {
$collect .= substr($queue,0,$n - 1);
$final = true;
}
$queue = "";
break;
}
if ($queue[0] == "*") {
$queue = substr($queue,1);
setState("");
return;
case "#":
continue;
}
if ($queue[0] == "#") {
Yate::Output("Overlapped clearing already collected: '$collect'");
$collect="";
setState("prompt");
return;
$collect = "";
$queue = substr($queue,1);
if (!$routeOnly)
setState("prompt");
continue;
}
if (!$final) {
$route = true;
$dtmf = $queue[0];
$queue = substr($queue,1);
$final = ($dtmf == ".");
if (!$final) {
$collect .= $dtmf;
// Check for next char now
$n = strlen($queue);
if ($n > 0 && $queue[0] == ".") {
$final = true;
$queue = substr($queue,1);
}
}
}
break;
}
if ($route) {
if ($final)
Yate::Debug("Overlapped got final digit. Collected: '$collect' queued: '$queue'");
routeTo($collect);
}
$collect .= $dtmf;
routeTo($collect);
}
function endRoute($callto,$ok,$err,$params)
@ -145,6 +207,8 @@ function endRoute($callto,$ok,$err,$params)
global $partycallid;
global $num;
global $collect;
global $final;
global $queue;
if ($ok && ($callto != "-") && ($callto != "error")) {
Yate::Output("Overlapped got route: '$callto' for '$collect'");
$m = new Yate("chan.masquerade");
@ -155,14 +219,32 @@ function endRoute($callto,$ok,$err,$params)
$m->params["caller"] = $num;
$m->params["called"] = $collect;
$m->Dispatch();
if (strlen($queue)) {
// Masquerade the remaining digits
// TODO: wait for call.execute to be processed to do that?
$d = new Yate("chan.masquerade");
$d->params["message"] = "chan.dtmf";
$d->params["id"] = $partycallid;
$d->params["tone"] = $queue;
$d->Dispatch();
}
return;
}
if ($err != "incomplete") {
Yate::Output("Overlapped get error '$err' for '$collect'");
setState("noroute");
if ($final) {
Yate::Output("Overlapped got final error '$err' for '$collect'");
setState("");
}
else
else if ($err != "incomplete") {
Yate::Output("Overlapped got error '$err' for '$collect'");
setState("");
$final = true;
}
else {
Yate::Debug("Overlapped still incomplete: '$collect'");
setState("noroute");
// Check if got some other digits
gotDTMF("");
}
}
/* The main loop. We pick events and handle them */
@ -181,7 +263,17 @@ while ($state != "") {
$partycallid = $ev->GetValue("id");
$ev->params["targetid"] = $ourcallid;
$num = $ev->GetValue("caller");
$autoanswer = ($ev->GetValue("called") != "off-hook");
$routeOnly = !Yate::Str2bool($ev->getValue("accept_call"));
$autoanswer = false;
$callednum = "";
if ($routeOnly) {
$callednum = $ev->GetValue("called");
if ($callednum == "off-hook")
$callednum = "";
}
else
$autoanswer = ($ev->GetValue("called") != "off-hook");
$executeParams = $ev->params;
$ev->handled = true;
// we must ACK this message before dispatching a call.answered
$ev->Acknowledge();
@ -193,8 +285,12 @@ while ($state != "") {
$m->params["targetid"] = $partycallid;
$m->Dispatch();
}
// Route initial called number
if (strlen($callednum))
gotDTMF($callednum);
setState("prompt");
if (!$routeOnly)
setState("prompt");
break;
case "chan.notify":
@ -206,9 +302,7 @@ while ($state != "") {
case "chan.dtmf":
if ($ev->GetValue("targetid") == $ourcallid ) {
$dtmfs = $ev->GetValue("text");
for ($i = 0; $i < strlen($dtmfs); $i++)
gotDTMF($dtmfs[$i]);
gotDTMF($ev->GetValue("text"));
$ev->handled = true;
}
break;