Honor detected method when sending DTMFs.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5277 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2012-09-20 09:29:28 +00:00
parent 08654d5b53
commit ec97de2487
4 changed files with 138 additions and 76 deletions

View File

@ -49,6 +49,15 @@
; This parameter is applied on reload for new calls only
;dtmfmethods=rfc2833,h323,inband
; honor_dtmf_detect: bool: Honor DTMF detected method when sending DTMFs
; If enabled the channel will try to send a DTMF using the same method as received
; If the detected method is not enabled it won't be used
; This parameter can be overridden from routing by 'ohonor_dtmf_detect' for outgoing call leg
; and 'ihonor_dtmf_detect' for incoming call leg
; This parameter is applied on reload for new calls only
; Defaults to enable
;honor_dtmf_detect=enable
; Use an external RTP module instead of the native OpenH323 RTP stack, which is
; very cpu intensive. If no external RTP can be found it will fallback to the
; native stack. The only external RTP now is yrtp (see the yrtpchan module).

View File

@ -130,6 +130,15 @@
; This parameter is applied on reload for new calls only
;dtmfmethods=rfc2833,info,inband
; honor_dtmf_detect: bool: Honor DTMF detected method when sending DTMFs
; If enabled the channel will try to send a DTMF using the same method as received
; If the detected method is not enabled it won't be used
; This parameter can be overridden from routing by 'ohonor_dtmf_detect' for outgoing call leg
; and 'ihonor_dtmf_detect' for incoming call leg
; This parameter is applied on reload for new calls only
; Defaults to enable
;honor_dtmf_detect=enable
; rfc2833: bool: Offer RFC2833 telephone-event by default
; A numeric payload >= 96 can be provided
;rfc2833=yes

View File

@ -525,7 +525,6 @@ public:
void stoppedExternal(H323Channel::Directions dir);
void setRemoteAddress(const char* remoteIP, WORD remotePort);
void cleanups(bool closeChans = true, bool dropChan = true);
bool sendTone(Message& msg, const char* tone);
void setCallerID(const char* number, const char* name);
void rtpExecuted(Message& msg);
void rtpForward(Message& msg, bool init = false);
@ -622,10 +621,14 @@ public:
protected:
virtual void endDisconnect(const Message& msg, bool handled);
private:
// Send tone(s) using method
bool sendTone(Message& msg, const char* tone, int meth, bool& retVal);
YateH323Connection* m_conn;
H323Connection::CallEndReason m_reason;
bool m_hungup;
DtmfMethods m_dtmfMethods;
bool m_honorDtmfDetect;
};
class YateGkRegThread : public PThread
@ -759,6 +762,7 @@ protected:
unsigned int YateGkRegThread::s_count = 0;
Mutex YateGkRegThread::s_mutexCount(false,"H323GkThreads");
static DtmfMethods s_dtmfMethods;
static bool s_honorDtmfDetect = true;
// Deprecated dtmf params warn
static bool s_warnDtmfInbandCfg = true;
static bool s_warnDtmfInbandCallExecute = true;
@ -2382,17 +2386,6 @@ void YateH323Connection::stoppedExternal(H323Channel::Directions dir)
}
}
bool YateH323Connection::sendTone(Message& msg, const char* tone)
{
if (m_rtpid) {
msg.setParam("targetid",m_rtpid);
return false;
}
while (*tone)
SendUserInputTone(*tone++);
return true;
}
void YateH323Connection::setEpConn(bool created)
{
YateH323EndPoint* ep = static_cast<YateH323EndPoint*>(&endpoint);
@ -2784,7 +2777,8 @@ void YateH323Connection::setCallerID(const char* number, const char* name)
YateH323Chan::YateH323Chan(YateH323Connection* conn,Message* msg,const char* addr)
: Channel(hplugin,0,(msg != 0)),
m_conn(conn), m_reason(H323Connection::EndedByLocalUser),
m_hungup(false)
m_hungup(false),
m_honorDtmfDetect(s_honorDtmfDetect)
{
s_mutex.lock();
s_chanCount++;
@ -2806,6 +2800,7 @@ YateH323Chan::YateH323Chan(YateH323Connection* conn,Message* msg,const char* add
else
m_dtmfMethods.getDeprecatedDtmfMethod(*msg,"dtmfinband",DtmfMethods::Inband,&s_warnDtmfInbandCallExecute);
s->copyParams(*msg,"caller,callername,called,billid,callto,username");
m_honorDtmfDetect = msg->getBoolValue(YSTRING("ohonor_dtmf_detect"),m_honorDtmfDetect);
}
Engine::enqueue(s);
}
@ -2915,6 +2910,33 @@ void YateH323Chan::endDisconnect(const Message& msg, bool handled)
#endif
}
// Send tone(s) using method
bool YateH323Chan::sendTone(Message& msg, const char* tone, int meth, bool& retVal)
{
if (!(m_conn && tone))
return false;
bool ok = false;
if (meth == DtmfMethods::H323) {
const char* t = tone;
while (*t)
m_conn->SendUserInputTone(*t++);
retVal = true;
ok = true;
}
else if (meth == DtmfMethods::Rfc2833) {
ok = m_conn->rtpStarted() && m_conn->rtpId() && m_conn->dtmfPayload() > 0;
if (ok)
msg.setParam("targetid",m_conn->rtpId());
}
else if (meth == DtmfMethods::Inband) {
ok = dtmfInband(tone);
retVal = ok;
}
XDebug(this,ok ? DebugAll : DebugNote,"sendTone(%s) meth=%s (%d) ok=%u [%p]",
tone,lookup(meth,DtmfMethods::s_methodName),meth,ok,this);
return ok;
}
// Set the signalling address
void YateH323Chan::setAddress(const char* addr)
{
@ -2994,6 +3016,7 @@ void YateH323Chan::callAccept(Message& msg)
DtmfMethods old = m_dtmfMethods;
m_dtmfMethods.set(*meths,&old);
}
m_honorDtmfDetect = msg.getBoolValue(YSTRING("ihonor_dtmf_detect"),m_honorDtmfDetect);
Channel::callAccept(msg);
if (m_conn) {
m_conn->rtpExecuted(msg);
@ -3056,23 +3079,18 @@ bool YateH323Chan::msgTone(Message& msg, const char* tone)
}
bool retVal = false;
bool ok = false;
if (msg.getBoolValue(YSTRING("honor_dtmf_detect"),m_honorDtmfDetect)) {
const String& detected = msg[YSTRING("detected")];
int meth = lookup(detected,DtmfMethods::s_methodName,DtmfMethods::MethodCount);
if (meth != DtmfMethods::MethodCount && methods.hasMethod(meth)) {
ok = sendTone(msg,tone,meth,retVal);
methods.reset(meth);
}
}
for (int i = 0; !ok && i < DtmfMethods::MethodCount; i++) {
int meth = methods[i];
if (meth == DtmfMethods::H323) {
while (*tone)
m_conn->SendUserInputTone(*tone++);
ok = true;
retVal = true;
}
else if (meth == DtmfMethods::Rfc2833) {
ok = m_conn->rtpStarted() && m_conn->rtpId() && m_conn->dtmfPayload() > 0;
if (ok)
msg.setParam("targetid",m_conn->rtpId());
}
else if (meth == DtmfMethods::Inband) {
ok = dtmfInband(tone);
retVal = ok;
}
if (meth != DtmfMethods::MethodCount)
ok = sendTone(msg,tone,meth,retVal);
}
if (!ok && debugAt(DebugNote)) {
String tmp;
@ -3280,6 +3298,7 @@ void H323Driver::initialize()
else
s_dtmfMethods.setDefault();
s_cfgMutex.unlock();
s_honorDtmfDetect = s_cfg.getBoolValue("general","honor_dtmf_detect",true);
s_externalRtp = s_cfg.getBoolValue("general","external_rtp",true);
s_passtrough = s_cfg.getBoolValue("general","forward_rtp",false);
s_fallbackRtp = s_cfg.getBoolValue("general","fallback_rtp",true);

View File

@ -940,6 +940,8 @@ private:
void updateRtpNatAddress(NamedList* params = 0);
// Process allow list. Get INFO support
bool infoAllowed(const SIPMessage* msg);
// Send tone(s) using method
bool sendTone(Message& msg, const char* tone, int meth, bool& retVal);
SIPTransaction* m_tr;
SIPTransaction* m_tr2;
@ -967,6 +969,7 @@ private:
bool m_checkAllowInfo; // Check Allow in INVITE and OK for INFO support
bool m_missingAllowInfoDefVal; // Default INFO support if Allow header is missing
DtmfMethods m_dtmfMethods;
bool m_honorDtmfDetect;
// REFER already running
bool m_referring;
// reINVITE requested or in progress
@ -1132,6 +1135,7 @@ int YateSIPEndPoint::s_evCount = 0;
static bool s_checkAllowInfo = true; // Check Allow in INVITE and OK for INFO support
static bool s_missingAllowInfoDefVal = true; // Default INFO support if Allow header is missing
static DtmfMethods s_dtmfMethods;
static bool s_honorDtmfDetect = true;
// Deprecated dtmf params warn
static bool s_warnDtmfInfoCfg = true;
static bool s_warnDtmfInbandCfg = true;
@ -1143,6 +1147,7 @@ const TokenDict DtmfMethods::s_methodName[] = {
{ "info", Info},
{ "rfc2833", Rfc2833},
{ "inband", Inband},
{ "sip-info", Info},
{ 0, 0 },
};
@ -5075,6 +5080,7 @@ YateSIPConnection::YateSIPConnection(SIPEvent* ev, SIPTransaction* tr)
m_state(Incoming), m_port(0), m_route(0), m_routes(0),
m_authBye(true),
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0)
{
Debug(this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,%p) [%p]",ev,tr,this);
@ -5247,6 +5253,7 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
m_state(Outgoing), m_port(0), m_route(0), m_routes(0),
m_authBye(false),
m_checkAllowInfo(s_checkAllowInfo), m_missingAllowInfoDefVal(s_missingAllowInfoDefVal),
m_honorDtmfDetect(s_honorDtmfDetect),
m_referring(false), m_reInviting(ReinviteNone), m_lastRseq(0)
{
Debug(this,DebugAll,"YateSIPConnection::YateSIPConnection(%p,'%s') [%p]",
@ -5265,6 +5272,7 @@ YateSIPConnection::YateSIPConnection(Message& msg, const String& uri, const char
m_dtmfMethods.getDeprecatedDtmfMethod(msg,"dtmfinband",DtmfMethods::Inband,&s_warnDtmfInbandCallExecute);
}
s_globalMutex.unlock();
m_honorDtmfDetect = msg.getBoolValue(YSTRING("ohonor_dtmf_detect"),m_honorDtmfDetect);
m_secure = msg.getBoolValue(YSTRING("secure"),plugin.parser().secure());
setRfc2833(msg.getParam(YSTRING("rfc2833")));
m_rtpForward = msg.getBoolValue(YSTRING("rtp_forward"));
@ -6581,60 +6589,25 @@ bool YateSIPConnection::msgTone(Message& msg, const char* tone)
s_warnDtmfMethodChanDtmf = false;
Debug(this,DebugConf,"Deprecated 'method' parameter in '%s'. Use 'methods' instead!",msg.c_str());
}
if ((*method == YSTRING("info")) || (*method == YSTRING("sip-info")))
methods.set(DtmfMethods::Info);
else if (*method == YSTRING("rfc2833"))
methods.set(DtmfMethods::Rfc2833);
else if (*method == YSTRING("inband"))
methods.set(DtmfMethods::Inband);
int meth = lookup(*method,DtmfMethods::s_methodName,DtmfMethods::MethodCount);
if (meth != DtmfMethods::MethodCount)
methods.set(meth);
}
}
bool retVal = false;
bool ok = false;
if (msg.getBoolValue(YSTRING("honor_dtmf_detect"),m_honorDtmfDetect)) {
const String& detected = msg[YSTRING("detected")];
int meth = lookup(detected,DtmfMethods::s_methodName,DtmfMethods::MethodCount);
if (meth != DtmfMethods::MethodCount && methods.hasMethod(meth)) {
ok = sendTone(msg,tone,meth,retVal);
methods.reset(meth);
}
}
for (int i = 0; !ok && i < DtmfMethods::MethodCount; i++) {
int meth = methods[i];
if (meth == DtmfMethods::Info) {
// Send INFO only if initial transaction finished
if (m_tr)
continue;
for (; tone && *tone; tone++) {
char c = *tone;
for (int j = 0; j <= 16; j++) {
if (s_dtmfs[j] != c)
continue;
SIPMessage* m = createDlgMsg("INFO");
if (!m)
break;
copySipHeaders(*m,msg);
String tmp;
tmp << "Signal=" << j << "\r\n";
m->setBody(new MimeStringBody("application/dtmf-relay",tmp));
plugin.ep()->engine()->addMessage(m);
m->deref();
break;
}
}
ok = true;
retVal = true;
}
else if (meth == DtmfMethods::Rfc2833 || meth == DtmfMethods::Inband) {
// RFC2833 and inband require media to be started
if (!(m_rtpMedia && (m_mediaStatus == MediaStarted)))
continue;
ObjList* l = m_rtpMedia->find("audio");
const SDPMedia* m = static_cast<const SDPMedia*>(l ? l->get() : 0);
if (!m)
continue;
if (meth == DtmfMethods::Rfc2833) {
ok = m->rfc2833().toBoolean(true);
if (ok)
msg.setParam("targetid",m->id());
}
else {
ok = dtmfInband(tone);
retVal = ok;
}
}
if (meth != DtmfMethods::MethodCount)
ok = sendTone(msg,tone,meth,retVal);
}
if (!ok && debugAt(DebugNote)) {
String tmp;
@ -6877,6 +6850,7 @@ void YateSIPConnection::callAccept(Message& msg)
// Update dtmf methods from message
m_checkAllowInfo = msg.getBoolValue(YSTRING("icheck_allow_info"),m_checkAllowInfo);
m_missingAllowInfoDefVal = msg.getBoolValue(YSTRING("imissing_allow_info"),m_missingAllowInfoDefVal);
m_honorDtmfDetect = msg.getBoolValue(YSTRING("ihonor_dtmf_detect"),m_honorDtmfDetect);
String* meths = msg.getParam(YSTRING("idtmfmethods"));
if (meths) {
DtmfMethods old = m_dtmfMethods;
@ -7144,6 +7118,56 @@ bool YateSIPConnection::infoAllowed(const SIPMessage* msg)
return ok;
}
// Send tone(s) using method
bool YateSIPConnection::sendTone(Message& msg, const char* tone, int meth, bool& retVal)
{
bool ok = false;
if (meth == DtmfMethods::Info) {
// Send INFO only if initial transaction finished
if (!m_tr) {
const char* t = tone;
for (; t && *t; t++) {
char c = *t;
for (int j = 0; j <= 16; j++) {
if (s_dtmfs[j] != c)
continue;
SIPMessage* m = createDlgMsg("INFO");
if (!m)
break;
copySipHeaders(*m,msg);
String tmp;
tmp << "Signal=" << j << "\r\n";
m->setBody(new MimeStringBody("application/dtmf-relay",tmp));
plugin.ep()->engine()->addMessage(m);
m->deref();
break;
}
}
retVal = true;
ok = true;
}
}
else if (meth == DtmfMethods::Rfc2833 || meth == DtmfMethods::Inband) {
// RFC2833 and inband require media to be started
if (m_rtpMedia && (m_mediaStatus == MediaStarted)) {
ObjList* l = m_rtpMedia->find("audio");
const SDPMedia* m = static_cast<const SDPMedia*>(l ? l->get() : 0);
if (meth == DtmfMethods::Rfc2833) {
ok = m && m->rfc2833().toBoolean(true);
if (ok)
msg.setParam("targetid",m->id());
}
else if (m) {
ok = dtmfInband(tone);
retVal = ok;
}
}
}
XDebug(this,ok ? DebugAll : DebugNote,"sendTone(%s) meth=%s (%d) ok=%u [%p]",
tone,lookup(meth,DtmfMethods::s_methodName),meth,ok,this);
return ok;
}
YateSIPLine::YateSIPLine(const String& name)
: String(name), Mutex(true,"YateSIPLine"),
@ -7983,6 +8007,7 @@ void SIPDriver::initialize()
s_globalMutex.unlock();
s_checkAllowInfo = s_cfg.getBoolValue("general","check_allow_info",true);
s_missingAllowInfoDefVal = s_cfg.getBoolValue("general","missing_allow_info",true);
s_honorDtmfDetect = s_cfg.getBoolValue("general","honor_dtmf_detect",true);
s_maxForwards = s_cfg.getIntValue("general","maxforwards",20);
s_floodEvents = s_cfg.getIntValue("general","floodevents",100);
s_floodProtection = s_cfg.getBoolValue("general","floodprotection",true);