Call progress support.

git-svn-id: http://voip.null.ro/svn/yate@442 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2005-07-12 16:05:29 +00:00
parent 8dd3c5c771
commit c581a7803a
11 changed files with 138 additions and 51 deletions

View File

@ -1117,6 +1117,7 @@ void GTKDriver::initialize()
} }
setup(); setup();
installRelay(Halt); installRelay(Halt);
installRelay(Progress);
} }
bool GTKDriver::factory(UIFactory* factory, const char* type) bool GTKDriver::factory(UIFactory* factory, const char* type)

View File

@ -279,13 +279,21 @@ bool Channel::startRouter(Message* msg)
} }
else else
delete msg; delete msg;
callReject("failure","Internal server error"); callRejected("failure","Internal server error");
// dereference and die if the channel is dynamic // dereference and die if the channel is dynamic
if (m_driver && m_driver->varchan()) if (m_driver && m_driver->varchan())
deref(); deref();
return false; return false;
} }
bool Channel::msgProgress(Message& msg)
{
status("progressing");
if (m_billid.null())
m_billid = msg.getValue("billid");
return true;
}
bool Channel::msgRinging(Message& msg) bool Channel::msgRinging(Message& msg)
{ {
status("ringing"); status("ringing");
@ -347,7 +355,7 @@ void Channel::callAccept(Message& msg)
} }
} }
void Channel::callReject(const char* error, const char* reason) void Channel::callRejected(const char* error, const char* reason, const Message* msg)
{ {
status("rejected"); status("rejected");
} }
@ -382,6 +390,7 @@ TokenDict Module::s_messages[] = {
{ "engine.halt", Module::Halt }, { "engine.halt", Module::Halt },
{ "call.execute", Module::Execute }, { "call.execute", Module::Execute },
{ "call.drop", Module::Drop }, { "call.drop", Module::Drop },
{ "call.progress", Module::Progress },
{ "call.ringing", Module::Ringing }, { "call.ringing", Module::Ringing },
{ "call.answered", Module::Answered }, { "call.answered", Module::Answered },
{ "chan.dtmf", Module::Tone }, { "chan.dtmf", Module::Tone },
@ -691,6 +700,8 @@ bool Driver::received(Message &msg, int id)
} }
switch (id) { switch (id) {
case Progress:
return chan->isIncoming() && chan->msgProgress(msg);
case Ringing: case Ringing:
return chan->isIncoming() && chan->msgRinging(msg); return chan->isIncoming() && chan->msgRinging(msg);
case Answered: case Answered:
@ -859,11 +870,11 @@ bool Router::route()
if (ok) { if (ok) {
if (m_msg->retValue() == "-") if (m_msg->retValue() == "-")
chan->callReject(m_msg->getValue("error","unknown"), chan->callRejected(m_msg->getValue("error","unknown"),
m_msg->getValue("reason")); m_msg->getValue("reason"),m_msg);
else if (m_msg->getIntValue("antiloop",1) <= 0) else if (m_msg->getIntValue("antiloop",1) <= 0)
chan->callReject(m_msg->getValue("error","looping"), chan->callRejected(m_msg->getValue("error","looping"),
m_msg->getValue("reason","Call is looping")); m_msg->getValue("reason","Call is looping"),m_msg);
else if (chan->callRouted(*m_msg)) { else if (chan->callRouted(*m_msg)) {
*m_msg = "call.execute"; *m_msg = "call.execute";
m_msg->setParam("callto",m_msg->retValue()); m_msg->setParam("callto",m_msg->retValue());
@ -874,13 +885,13 @@ bool Router::route()
if (ok) if (ok)
chan->callAccept(*m_msg); chan->callAccept(*m_msg);
else else
chan->callReject(m_msg->getValue("error","noconn"), chan->callRejected(m_msg->getValue("error","noconn"),
m_msg->getValue("reason","Could not connect to target")); m_msg->getValue("reason","Could not connect to target"),m_msg);
} }
} }
else else
chan->callReject(m_msg->getValue("error","noroute"), chan->callRejected(m_msg->getValue("error","noroute"),
m_msg->getValue("reason","No route to call target")); m_msg->getValue("reason","No route to call target"),m_msg);
chan->deref(); chan->deref();
// dereference again if the channel is dynamic // dereference again if the channel is dynamic

View File

@ -34,6 +34,13 @@ public:
virtual bool received(Message &msg); virtual bool received(Message &msg);
}; };
// utility function to check if a string begins and ends with -dashes-
static bool checkDashes(String& str)
{
if (str.startsWith("-") && str.endsWith("-"))
str.clear();
return str.null();
}
Window::Window(const char* id) Window::Window(const char* id)
: m_id(id), m_visible(false), m_master(false) : m_id(id), m_visible(false), m_master(false)
@ -319,12 +326,15 @@ bool Client::action(Window* wnd, const String& name)
String line; String line;
getText("line",line,wnd); getText("line",line,wnd);
line.trimBlanks(); line.trimBlanks();
checkDashes(line);
String proto; String proto;
getText("protocol",proto,wnd); getText("protocol",proto,wnd);
proto.trimBlanks(); proto.trimBlanks();
checkDashes(proto);
String account; String account;
getText("account",account,wnd); getText("account",account,wnd);
account.trimBlanks(); account.trimBlanks();
checkDashes(account);
return callStart(target,line,proto,account); return callStart(target,line,proto,account);
} }
else if (name.startsWith("callto:")) else if (name.startsWith("callto:"))
@ -448,8 +458,11 @@ bool Client::callStart(const String& target, const String& line,
ClientChannel* cc = new ClientChannel(); ClientChannel* cc = new ClientChannel();
Message* m = cc->message("call.route"); Message* m = cc->message("call.route");
Regexp r("^[a-z0-9]\\+/"); Regexp r("^[a-z0-9]\\+/");
if (r.matches(target.safe())) bool hasProto = r.matches(target.safe());
if (hasProto)
m->setParam("callto",target); m->setParam("callto",target);
else if (proto)
m->setParam("callto",proto + "/" + target);
else else
m->setParam("called",target); m->setParam("called",target);
if (line) if (line)
@ -577,11 +590,13 @@ ClientChannel::~ClientChannel()
Engine::enqueue(message("chan.hangup")); Engine::enqueue(message("chan.hangup"));
} }
bool ClientChannel::openMedia() bool ClientChannel::openMedia(bool replace)
{ {
String dev = ClientDriver::device(); String dev = ClientDriver::device();
if (dev.null()) if (dev.null())
return false; return false;
if ((!replace) && getSource() && getConsumer())
return true;
Message m("chan.attach"); Message m("chan.attach");
complete(m,true); complete(m,true);
m.setParam("source",dev); m.setParam("source",dev);
@ -619,10 +634,10 @@ void ClientChannel::callAccept(Message& msg)
Channel::callAccept(msg); Channel::callAccept(msg);
} }
void ClientChannel::callReject(const char* error, const char* reason) void ClientChannel::callRejected(const char* error, const char* reason, const Message* msg)
{ {
Debug(ClientDriver::self(),DebugAll,"ClientChannel::callReject('%s','%s') [%p]", Debug(ClientDriver::self(),DebugAll,"ClientChannel::callReject('%s','%s',%p) [%p]",
error,reason,this); error,reason,msg,this);
if (!reason) if (!reason)
reason = error; reason = error;
if (!reason) if (!reason)
@ -631,13 +646,26 @@ void ClientChannel::callReject(const char* error, const char* reason)
tmp << " " << reason; tmp << " " << reason;
if (Client::self()) if (Client::self())
Client::self()->setStatusLocked(tmp); Client::self()->setStatusLocked(tmp);
Channel::callReject(error,reason); Channel::callRejected(error,reason,msg);
}
bool ClientChannel::msgProgress(Message& msg)
{
Debug(ClientDriver::self(),DebugAll,"ClientChannel::msgProgress() [%p]",this);
Client::self()->setStatusLocked("Call progressing");
CallEndpoint *ch = static_cast<CallEndpoint*>(msg.userObject("CallEndpoint"));
if (ch && ch->getSource())
openMedia();
return Channel::msgAnswered(msg);
} }
bool ClientChannel::msgRinging(Message& msg) bool ClientChannel::msgRinging(Message& msg)
{ {
Debug(ClientDriver::self(),DebugAll,"ClientChannel::msgRinging() [%p]",this); Debug(ClientDriver::self(),DebugAll,"ClientChannel::msgRinging() [%p]",this);
Client::self()->setStatusLocked("Call ringing"); Client::self()->setStatusLocked("Call ringing");
CallEndpoint *ch = static_cast<CallEndpoint*>(msg.userObject("CallEndpoint"));
if (ch && ch->getSource())
openMedia();
return Channel::msgRinging(msg); return Channel::msgRinging(msg);
} }

View File

@ -447,13 +447,14 @@ public:
BOOL OpenAudioChannel(BOOL isEncoding, H323AudioCodec &codec); BOOL OpenAudioChannel(BOOL isEncoding, H323AudioCodec &codec);
virtual void disconnected(bool final, const char *reason); virtual void disconnected(bool final, const char *reason);
virtual bool msgProgress(Message& msg);
virtual bool msgRinging(Message& msg); virtual bool msgRinging(Message& msg);
virtual bool msgAnswered(Message& msg); virtual bool msgAnswered(Message& msg);
virtual bool msgTone(Message& msg, const char* tone); virtual bool msgTone(Message& msg, const char* tone);
virtual bool msgText(Message& msg, const char* text); virtual bool msgText(Message& msg, const char* text);
virtual bool callRouted(Message& msg); virtual bool callRouted(Message& msg);
virtual void callAccept(Message& msg); virtual void callAccept(Message& msg);
virtual void callReject(const char* error, const char* reason); virtual void callRejected(const char* error, const char* reason, const Message* msg);
inline void setTarget(const char* targetid) inline void setTarget(const char* targetid)
{ m_targetid = targetid; } { m_targetid = targetid; }
private: private:
@ -1750,13 +1751,24 @@ void YateH323Chan::callAccept(Message& msg)
Channel::callAccept(msg); Channel::callAccept(msg);
if (m_conn) { if (m_conn) {
m_conn->rtpExecuted(msg); m_conn->rtpExecuted(msg);
m_conn->answerCall(H323Connection::AnswerCallPending); m_conn->answerCall(H323Connection::AnswerCallDeferred);
} }
} }
void YateH323Chan::callReject(const char* error, const char* reason) void YateH323Chan::callRejected(const char* error, const char* reason, const Message* msg)
{ {
Channel::callReject(error,reason); Channel::callRejected(error,reason,msg);
}
bool YateH323Chan::msgProgress(Message& msg)
{
Channel::msgProgress(msg);
if (!m_conn)
return false;
if (msg.getParam("rtp_forward"))
m_conn->rtpForward(msg);
m_conn->answerCall(H323Connection::AnswerCallDeferred);
return true;
} }
bool YateH323Chan::msgRinging(Message& msg) bool YateH323Chan::msgRinging(Message& msg)
@ -1886,6 +1898,7 @@ void H323Driver::initialize()
if (!s_process) { if (!s_process) {
installRelay(Halt); installRelay(Halt);
s_process = new H323Process; s_process = new H323Process;
installRelay(Progress);
Engine::install(new UserHandler); Engine::install(new UserHandler);
} }
int dbg = s_cfg.getIntValue("general","debug"); int dbg = s_cfg.getIntValue("general","debug");

View File

@ -122,7 +122,7 @@ public:
bool startRouting(iax_event *e); bool startRouting(iax_event *e);
void hangup(const char *reason = 0); void hangup(const char *reason = 0);
virtual void callAccept(Message& msg); virtual void callAccept(Message& msg);
virtual void callReject(const char* error, const char* reason = 0); virtual void callRejected(const char* error, const char* reason = 0, const Message* msg = 0);
virtual bool msgRinging(Message& msg); virtual bool msgRinging(Message& msg);
virtual bool msgAnswered(Message& msg); virtual bool msgAnswered(Message& msg);
virtual bool msgTone(Message& msg, const char* tone); virtual bool msgTone(Message& msg, const char* tone);
@ -655,10 +655,11 @@ void IAXConnection::callAccept(Message& msg)
Channel::callAccept(msg); Channel::callAccept(msg);
} }
void IAXConnection::callReject(const char* error, const char* reason) void IAXConnection::callRejected(const char* error, const char* reason, const Message* msg)
{ {
Debug(this,DebugAll,"IAXConnection::callReject('%s','%s') [%p]",error,reason,this); Debug(this,DebugAll,"IAXConnection::callRejected('%s','%s',%p) [%p]",
Channel::callReject(error,reason); error,reason,msg,this);
Channel::callRejected(error,reason,msg);
if (!reason) if (!reason)
reason = m_reason; reason = m_reason;
if (!reason) if (!reason)

View File

@ -791,9 +791,10 @@ void PriChan::callAccept(Message& msg)
Channel::callAccept(msg); Channel::callAccept(msg);
} }
void PriChan::callReject(const char* error, const char* reason) void PriChan::callRejected(const char* error, const char* reason, const Message* msg)
{ {
int cause = lookup(error,dict_str2cause,PRI_CAUSE_NETWORK_OUT_OF_ORDER); int cause = lookup(error,dict_str2cause,PRI_CAUSE_NETWORK_OUT_OF_ORDER);
Channel::callRejected(error,reason,msg);
hangup(cause); hangup(cause);
} }

View File

@ -149,7 +149,7 @@ public:
virtual bool msgText(Message& msg, const char* text); virtual bool msgText(Message& msg, const char* text);
virtual bool msgDrop(Message& msg, const char* reason); virtual bool msgDrop(Message& msg, const char* reason);
virtual void callAccept(Message& msg); virtual void callAccept(Message& msg);
virtual void callReject(const char* error, const char* reason = 0); virtual void callRejected(const char* error, const char* reason = 0, const Message* msg = 0);
inline PriSpan *span() const inline PriSpan *span() const
{ return m_span; } { return m_span; }
inline int chan() const inline int chan() const

View File

@ -13,11 +13,11 @@ button_hide=,,20,20,decoration,
leave=< leave=<
leave=< leave=<
label=12,30,80,20,Protocol label=12,30,80,20,Protocol
option=10,48,80,30,protocol, ,sip,h323,iax option=10,48,80,30,protocol,--,sip,h323,iax
label=95,30,160,20,Call address or number label=95,30,160,20,Call address or number
combo=95,50,160,26,callto, combo=95,50,160,26,callto,
label=262,30,80,20,Account label=262,30,80,20,Account
option=260,48,80,30,account, ,l 1,l 2,l 3 option=260,48,80,30,account,--
button=70,85,100,28,call,Call button=70,85,100,28,call,Call
button=200,85,100,28,hangup,Hangup button=200,85,100,28,hangup,Hangup
label=10,115,200,20,status,Initializing... label=10,115,200,20,status,Initializing...

View File

@ -182,13 +182,14 @@ public:
YateSIPConnection(Message& msg, const String& uri, const char* target = 0); YateSIPConnection(Message& msg, const String& uri, const char* target = 0);
~YateSIPConnection(); ~YateSIPConnection();
virtual void disconnected(bool final, const char *reason); virtual void disconnected(bool final, const char *reason);
virtual bool msgProgress(Message& msg);
virtual bool msgRinging(Message& msg); virtual bool msgRinging(Message& msg);
virtual bool msgAnswered(Message& msg); virtual bool msgAnswered(Message& msg);
virtual bool msgTone(Message& msg, const char* tone); virtual bool msgTone(Message& msg, const char* tone);
virtual bool msgText(Message& msg, const char* text); virtual bool msgText(Message& msg, const char* text);
virtual bool callRouted(Message& msg); virtual bool callRouted(Message& msg);
virtual void callAccept(Message& msg); virtual void callAccept(Message& msg);
virtual void callReject(const char* error, const char* reason); virtual void callRejected(const char* error, const char* reason, const Message* msg);
void startRouter(); void startRouter();
bool process(SIPEvent* ev); bool process(SIPEvent* ev);
bool checkUser(SIPTransaction* t, bool refuse = true); bool checkUser(SIPTransaction* t, bool refuse = true);
@ -221,6 +222,7 @@ private:
SDPBody* createRtpSDP(SIPMessage* msg, const char* formats); SDPBody* createRtpSDP(SIPMessage* msg, const char* formats);
SDPBody* createRtpSDP(bool start = false); SDPBody* createRtpSDP(bool start = false);
bool startRtp(); bool startRtp();
bool addRtpParams(Message& msg, const String& natAddr = String::empty());
SIPTransaction* m_tr; SIPTransaction* m_tr;
bool m_hungup; bool m_hungup;
bool m_byebye; bool m_byebye;
@ -1142,6 +1144,20 @@ SDPBody* YateSIPConnection::createSDP(const char* addr, const char* port, const
return sdp; return sdp;
} }
bool YateSIPConnection::addRtpParams(Message& msg, const String& natAddr)
{
if (m_rtpPort && m_rtpAddr && !startRtp()) {
if (natAddr)
msg.addParam("rtp_nat_addr",natAddr);
msg.addParam("rtp_forward","yes");
msg.addParam("rtp_addr",m_rtpAddr);
msg.addParam("rtp_port",m_rtpPort);
msg.addParam("formats",m_formats);
return true;
}
return false;
}
// Process SIP events belonging to this connection // Process SIP events belonging to this connection
bool YateSIPConnection::process(SIPEvent* ev) bool YateSIPConnection::process(SIPEvent* ev)
{ {
@ -1221,28 +1237,20 @@ bool YateSIPConnection::process(SIPEvent* ev)
} }
setStatus("answered",Established); setStatus("answered",Established);
Message *m = message("call.answered"); Message *m = message("call.answered");
if (m_rtpPort && m_rtpAddr && !startRtp()) { addRtpParams(*m,natAddr);
if (natAddr)
m->addParam("rtp_nat_addr",natAddr);
m->addParam("rtp_forward","yes");
m->addParam("rtp_addr",m_rtpAddr);
m->addParam("rtp_port",m_rtpPort);
m->addParam("formats",m_formats);
}
Engine::enqueue(m); Engine::enqueue(m);
} }
if ((m_state < Ringing) && msg->isAnswer()) { if ((m_state < Ringing) && msg->isAnswer()) {
if (msg->code == 180) { if (msg->code == 180) {
setStatus("ringing",Ringing); setStatus("ringing",Ringing);
Message *m = message("call.ringing"); Message *m = message("call.ringing");
if (m_rtpPort && m_rtpAddr && !startRtp()) { addRtpParams(*m,natAddr);
if (natAddr) Engine::enqueue(m);
m->addParam("rtp_nat_addr",natAddr); }
m->addParam("rtp_forward","yes"); if (msg->code == 183) {
m->addParam("rtp_addr",m_rtpAddr); setStatus("progressing");
m->addParam("rtp_port",m_rtpPort); Message *m = message("call.progress");
m->addParam("formats",m_formats); addRtpParams(*m,natAddr);
}
Engine::enqueue(m); Engine::enqueue(m);
} }
if ((msg->code > 100) && (msg->code < 200)) if ((msg->code > 100) && (msg->code < 200))
@ -1354,6 +1362,20 @@ void YateSIPConnection::disconnected(bool final, const char *reason)
Channel::disconnected(final,reason); Channel::disconnected(final,reason);
} }
bool YateSIPConnection::msgProgress(Message& msg)
{
Channel::msgProgress(msg);
if (m_tr && (m_tr->getState() == SIPTransaction::Process)) {
SIPMessage* m = new SIPMessage(m_tr->initialMessage(), 183);
SDPBody* sdp = createPasstroughSDP(msg);
m->setBody(sdp);
m_tr->setResponse(m);
m->deref();
}
setStatus("progressing");
return true;
}
bool YateSIPConnection::msgRinging(Message& msg) bool YateSIPConnection::msgRinging(Message& msg)
{ {
Channel::msgRinging(msg); Channel::msgRinging(msg);
@ -1425,9 +1447,9 @@ void YateSIPConnection::callAccept(Message& msg)
m_authBye = msg.getBoolValue("xsip_auth_bye",true); m_authBye = msg.getBoolValue("xsip_auth_bye",true);
} }
void YateSIPConnection::callReject(const char* error, const char* reason) void YateSIPConnection::callRejected(const char* error, const char* reason, const Message* msg)
{ {
Channel::callReject(error,reason); Channel::callRejected(error,reason,msg);
int code = lookup(error,dict_errors,500); int code = lookup(error,dict_errors,500);
if (code == 401) if (code == 401)
m_tr->requestAuth("realm","domain",false); m_tr->requestAuth("realm","domain",false);

View File

@ -160,12 +160,13 @@ class YATE_API ClientChannel : public Channel
public: public:
ClientChannel(const char* target = 0); ClientChannel(const char* target = 0);
virtual ~ClientChannel(); virtual ~ClientChannel();
virtual bool msgProgress(Message& msg);
virtual bool msgRinging(Message& msg); virtual bool msgRinging(Message& msg);
virtual bool msgAnswered(Message& msg); virtual bool msgAnswered(Message& msg);
virtual bool callRouted(Message& msg); virtual bool callRouted(Message& msg);
virtual void callAccept(Message& msg); virtual void callAccept(Message& msg);
virtual void callReject(const char* error, const char* reason); virtual void callRejected(const char* error, const char* reason, const Message* msg);
bool openMedia(); bool openMedia(bool replace = false);
void closeMedia(); void closeMedia();
inline int line() const inline int line() const
{ return m_line; } { return m_line; }

View File

@ -972,6 +972,7 @@ protected:
Masquerade = 0x1000, Masquerade = 0x1000,
Locate = 0x2000, Locate = 0x2000,
Transfer = 0x4000, Transfer = 0x4000,
Progress = 0x8000,
// Last possible public ID // Last possible public ID
PubLast = 0xffff, PubLast = 0xffff,
// Private messages base ID // Private messages base ID
@ -1123,6 +1124,13 @@ public:
*/ */
Message* message(const char* name, bool minimal = false, bool data = false); Message* message(const char* name, bool minimal = false, bool data = false);
/**
* Notification on remote call making some progress, not enabled by default
* @param msg Notification message
* @return True to stop processing the message, false to let it flow
*/
virtual bool msgProgress(Message& msg);
/** /**
* Notification on remote ringing * Notification on remote ringing
* @param msg Notification message * @param msg Notification message
@ -1169,7 +1177,7 @@ public:
virtual bool msgTransfer(Message& msg); virtual bool msgTransfer(Message& msg);
/** /**
* Notification on progress of incoming call * Notification on progress of routing incoming call
* @param msg Notification call.route message just after being dispatched * @param msg Notification call.route message just after being dispatched
* @return True to continue with the call, false to abort the route * @return True to continue with the call, false to abort the route
*/ */
@ -1185,8 +1193,9 @@ public:
* Notification on failure of incoming call * Notification on failure of incoming call
* @param error Standard error keyword * @param error Standard error keyword
* @param reason Textual failure reason * @param reason Textual failure reason
* @param msg Pointer to message causing the rejection, if any
*/ */
virtual void callReject(const char* error, const char* reason = 0); virtual void callRejected(const char* error, const char* reason = 0, const Message* msg = 0);
/** /**
* Set the local debugging level * Set the local debugging level