DTMF handling in oRTP channel. Mute support in SIP.
BRI support in Zaptel (trough patched libpri). git-svn-id: http://yate.null.ro/svn/yate/trunk@237 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
704351f1b7
commit
ca232d251c
|
@ -10,6 +10,7 @@
|
|||
; presentation= allow_user_not_screened,allow_user_passed,allow_user_failed,
|
||||
; allow_network,prohibit_user_not_screened,prohibit_user_passed,
|
||||
; prohibit_user_failed,prohibit_network,not_available
|
||||
; type= pri_net,pri_cpe,bri_net_ptmp,bri_cpe_ptmp,bri_net,bri_cpe
|
||||
|
||||
[general]
|
||||
;buflen=480
|
||||
|
@ -17,10 +18,10 @@
|
|||
;dumpevents=no
|
||||
|
||||
[span 1]
|
||||
first=1
|
||||
chans=31
|
||||
dchan=16
|
||||
isnet=yes
|
||||
;first=1
|
||||
;dchan=16
|
||||
;type=pri_net
|
||||
;swtype=unknown
|
||||
;dialplan=unknown
|
||||
;presentation=allow_user_not_screened
|
||||
|
|
|
@ -223,6 +223,7 @@ private:
|
|||
String m_rtpAddr;
|
||||
String m_rtpPort;
|
||||
String m_rtpFormat;
|
||||
String m_rtpLocal;
|
||||
int m_rtpSession;
|
||||
int m_rtpVersion;
|
||||
String m_formats;
|
||||
|
@ -271,6 +272,9 @@ static void parseSDP(SDPBody* sdp, String& addr, String& port, String& formats)
|
|||
String tmp(*c);
|
||||
if (tmp.startSkip("IN IP4")) {
|
||||
tmp.trimBlanks();
|
||||
// Handle the case media is muted
|
||||
if (tmp == "0.0.0.0")
|
||||
tmp.clear();
|
||||
addr = tmp;
|
||||
}
|
||||
}
|
||||
|
@ -632,10 +636,12 @@ void YateSIPEndPoint::invite(SIPEvent* e, SIPTransaction* t)
|
|||
if (e->getMessage()->body && e->getMessage()->body->isSDP()) {
|
||||
String addr,port,formats;
|
||||
parseSDP(static_cast<SDPBody*>(e->getMessage()->body),addr,port,formats);
|
||||
m->addParam("rtp_forward","possible");
|
||||
m->addParam("rtp_addr",addr);
|
||||
m->addParam("rtp_port",port);
|
||||
m->addParam("formats",formats);
|
||||
if (addr) {
|
||||
m->addParam("rtp_forward","possible");
|
||||
m->addParam("rtp_addr",addr);
|
||||
m->addParam("rtp_port",port);
|
||||
m->addParam("formats",formats);
|
||||
}
|
||||
}
|
||||
SipMsgThread *thr = new SipMsgThread(t,m);
|
||||
if (!thr->startup()) {
|
||||
|
@ -883,7 +889,8 @@ SDPBody* YateSIPConnection::createRtpSDP(SIPMessage* msg, const char* formats)
|
|||
m.userData(static_cast<DataEndpoint *>(this));
|
||||
if (Engine::dispatch(m)) {
|
||||
m_rtpid = m.getValue("rtpid");
|
||||
return createSDP(m.getValue("localip"),m.getValue("localport"),formats);
|
||||
m_rtpLocal = m.getValue("localip",m_rtpLocal);
|
||||
return createSDP(m_rtpLocal,m.getValue("localport"),formats);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -891,6 +898,10 @@ SDPBody* YateSIPConnection::createRtpSDP(SIPMessage* msg, const char* formats)
|
|||
// Creates a started external RTP channel from remote addr and builds SDP from it
|
||||
SDPBody* YateSIPConnection::createRtpSDP(bool start)
|
||||
{
|
||||
if (m_rtpAddr.null()) {
|
||||
m_rtpid = "-";
|
||||
return createSDP(m_rtpLocal,0,m_formats);
|
||||
}
|
||||
Message m("chan.rtp");
|
||||
m.addParam("id",id());
|
||||
m.addParam("direction","bidir");
|
||||
|
@ -902,9 +913,10 @@ SDPBody* YateSIPConnection::createRtpSDP(bool start)
|
|||
m.userData(static_cast<DataEndpoint *>(this));
|
||||
if (Engine::dispatch(m)) {
|
||||
m_rtpid = m.getValue("rtpid");
|
||||
m_rtpLocal = m.getValue("localip",m_rtpLocal);
|
||||
if (start)
|
||||
m_rtpFormat = m.getValue("format");
|
||||
return createSDP(m.getValue("localip"),m.getValue("localport"),m_formats,m_rtpFormat);
|
||||
return createSDP(m_rtpLocal,m.getValue("localport"),m_formats,m_rtpFormat);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -912,7 +924,7 @@ SDPBody* YateSIPConnection::createRtpSDP(bool start)
|
|||
// Starts an already created external RTP channel
|
||||
bool YateSIPConnection::startRtp()
|
||||
{
|
||||
if (m_rtpid.null())
|
||||
if (m_rtpid.null() || m_rtpid == "-")
|
||||
return false;
|
||||
Debug(DebugAll,"YateSIPConnection::startRtp() [%p]",this);
|
||||
Message m("chan.rtp");
|
||||
|
@ -930,14 +942,20 @@ SDPBody* YateSIPConnection::createSDP(const char* addr, const char* port, const
|
|||
{
|
||||
Debug(DebugAll,"YateSIPConnection::createSDP('%s','%s','%s') [%p]",
|
||||
addr,port,formats,this);
|
||||
if (!addr)
|
||||
return 0;
|
||||
if (m_rtpSession)
|
||||
++m_rtpVersion;
|
||||
else
|
||||
m_rtpVersion = m_rtpSession = Time::now() / 10000000000ULL;
|
||||
String owner;
|
||||
owner << "yate " << m_rtpSession << " " << m_rtpVersion << " IN IP4 " << addr;
|
||||
if (!port) {
|
||||
port = "1";
|
||||
addr = "0.0.0.0";
|
||||
}
|
||||
String tmp;
|
||||
tmp << "IN IP4 " << addr;
|
||||
String owner;
|
||||
owner << "1 " << m_rtpSession << " " << m_rtpVersion << " " << tmp;
|
||||
String frm(format ? format : formats);
|
||||
if (frm.null())
|
||||
frm = "alaw,mulaw";
|
||||
|
@ -1030,7 +1048,7 @@ bool YateSIPConnection::process(SIPEvent* ev)
|
|||
if (m_target)
|
||||
m->addParam("targetid",m_target);
|
||||
m->addParam("status","answered");
|
||||
if (m_rtpPort && !startRtp()) {
|
||||
if (m_rtpPort && m_rtpAddr && !startRtp()) {
|
||||
m->addParam("rtp_forward","yes");
|
||||
m->addParam("rtp_addr",m_rtpAddr);
|
||||
m->addParam("rtp_port",m_rtpPort);
|
||||
|
@ -1056,7 +1074,7 @@ void YateSIPConnection::reInvite(SIPTransaction* t)
|
|||
parseSDP(static_cast<SDPBody*>(t->initialMessage()->body),addr,port,formats);
|
||||
int q = formats.find(',');
|
||||
String frm = formats.substr(0,q);
|
||||
if (addr.null() || port.null() || frm.null())
|
||||
if (port.null() || frm.null())
|
||||
break;
|
||||
m_rtpAddr = addr;
|
||||
m_rtpPort = port;
|
||||
|
|
|
@ -224,6 +224,18 @@ static TokenDict dict_str2switch[] = {
|
|||
{ 0, -1 }
|
||||
};
|
||||
|
||||
static TokenDict dict_str2type[] = {
|
||||
{ "pri_net", PRI_NETWORK },
|
||||
{ "pri_cpe", PRI_CPE },
|
||||
#ifdef BRI_NETWORK_PTMP
|
||||
{ "bri_net_ptmp", BRI_NETWORK_PTMP },
|
||||
{ "bri_cpe_ptmp", BRI_CPE_PTMP },
|
||||
{ "bri_net", BRI_NETWORK },
|
||||
{ "bri_cpe", BRI_CPE },
|
||||
#endif
|
||||
{ 0, -1 }
|
||||
};
|
||||
|
||||
#if 0
|
||||
/* Numbering plan identifier */
|
||||
static TokenDict dict_str2nplan[] = {
|
||||
|
@ -325,9 +337,9 @@ class ZapChan;
|
|||
class PriSpan : public GenObject, public Thread
|
||||
{
|
||||
public:
|
||||
static PriSpan *create(int span, int chan1, int nChans, int dChan, bool isNet,
|
||||
static PriSpan *create(int span, int chan1, int nChans, int dChan, int netType,
|
||||
int switchType, int dialPlan, int presentation,
|
||||
bool overlapDial, int nsf = YATE_NSF_DEFAULT);
|
||||
int overlapDial, int nsf = YATE_NSF_DEFAULT);
|
||||
virtual ~PriSpan();
|
||||
virtual void run();
|
||||
inline struct pri *pri()
|
||||
|
@ -344,6 +356,8 @@ public:
|
|||
{ return m_dplan; }
|
||||
inline int pres() const
|
||||
{ return m_pres; }
|
||||
inline unsigned int overlapped() const
|
||||
{ return m_overlapped; }
|
||||
inline bool outOfOrder() const
|
||||
{ return !m_ok; }
|
||||
int findEmptyChan(int first = 0, int last = 65535) const;
|
||||
|
@ -353,8 +367,8 @@ public:
|
|||
static bool dumpEvents;
|
||||
|
||||
private:
|
||||
PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres);
|
||||
static struct pri *makePri(int fd, int dchan, int nettype, int swtype, bool overlapDial, int nsf);
|
||||
PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial);
|
||||
static struct pri *makePri(int fd, int dchan, int nettype, int swtype, int overlapDial, int nsf);
|
||||
void handleEvent(pri_event &ev);
|
||||
bool validChan(int chan) const;
|
||||
void restartChan(int chan, bool outgoing, bool force = false);
|
||||
|
@ -370,6 +384,7 @@ private:
|
|||
int m_fd;
|
||||
int m_dplan;
|
||||
int m_pres;
|
||||
unsigned int m_overlapped;
|
||||
struct pri *m_pri;
|
||||
unsigned long long m_restart;
|
||||
ZapChan **m_chans;
|
||||
|
@ -411,6 +426,8 @@ public:
|
|||
{ return m_law; }
|
||||
const String& id() const
|
||||
{ return m_id; }
|
||||
bool isISDN() const
|
||||
{ return m_isdn; }
|
||||
inline void setTarget(const char *target = 0)
|
||||
{ m_targetid = target; }
|
||||
inline const String& getTarget() const
|
||||
|
@ -495,9 +512,9 @@ class ZapChanHandler : public MessageReceiver
|
|||
{
|
||||
public:
|
||||
enum {
|
||||
Ringing,
|
||||
Answered,
|
||||
DTMF,
|
||||
Ringing,
|
||||
Answered,
|
||||
DTMF,
|
||||
};
|
||||
virtual bool received(Message &msg, int id);
|
||||
};
|
||||
|
@ -522,28 +539,28 @@ ZaptelPlugin zplugin;
|
|||
unsigned long long PriSpan::restartPeriod = 0;
|
||||
bool PriSpan::dumpEvents = false;
|
||||
|
||||
PriSpan *PriSpan::create(int span, int chan1, int nChans, int dChan, bool isNet,
|
||||
PriSpan *PriSpan::create(int span, int chan1, int nChans, int dChan, int netType,
|
||||
int switchType, int dialPlan, int presentation,
|
||||
bool overlapDial, int nsf)
|
||||
int overlapDial, int nsf)
|
||||
{
|
||||
int fd = ::open("/dev/zap/channel", O_RDWR, 0600);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
struct pri *p = makePri(fd,
|
||||
(dChan >= 0) ? dChan+chan1-1 : -1,
|
||||
(isNet ? PRI_NETWORK : PRI_CPE),
|
||||
netType,
|
||||
switchType, overlapDial, nsf);
|
||||
if (!p) {
|
||||
::close(fd);
|
||||
return 0;
|
||||
}
|
||||
PriSpan *ps = new PriSpan(p,span,chan1,nChans,dChan,fd,dialPlan,presentation);
|
||||
PriSpan *ps = new PriSpan(p,span,chan1,nChans,dChan,fd,dialPlan,presentation,overlapDial);
|
||||
ps->startup();
|
||||
return ps;
|
||||
}
|
||||
|
||||
struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype,
|
||||
bool overlapDial, int nsf)
|
||||
int overlapDial, int nsf)
|
||||
{
|
||||
if (dchan >= 0) {
|
||||
// Set up the D channel if we have one
|
||||
|
@ -579,17 +596,19 @@ struct pri *PriSpan::makePri(int fd, int dchan, int nettype, int swtype,
|
|||
#endif
|
||||
#ifdef PRI_SET_OVERLAPDIAL
|
||||
if (ret)
|
||||
::pri_set_overlapdial(ret, overlapDial);
|
||||
::pri_set_overlapdial(ret, (overlapDial > 0));
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
PriSpan::PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres)
|
||||
PriSpan::PriSpan(struct pri *_pri, int span, int first, int chans, int dchan, int fd, int dplan, int pres, int overlapDial)
|
||||
: Thread("PriSpan"), m_span(span), m_offs(first), m_nchans(chans),
|
||||
m_fd(fd), m_dplan(dplan), m_pres(pres), m_pri(_pri),
|
||||
m_fd(fd), m_dplan(dplan), m_pres(pres), m_overlapped(0), m_pri(_pri),
|
||||
m_restart(0), m_chans(0), m_ok(false)
|
||||
{
|
||||
Debug(DebugAll,"PriSpan::PriSpan(%p,%d,%d,%d) [%p]",_pri,span,chans,fd,this);
|
||||
if (overlapDial > 0)
|
||||
m_overlapped = overlapDial;
|
||||
ZapChan **ch = new ZapChan* [chans];
|
||||
for (int i = 1; i <= chans; i++)
|
||||
ch[i-1] = (i == dchan) ? 0 : new ZapChan(this,i,s_buflen);
|
||||
|
@ -789,14 +808,20 @@ void PriSpan::ringChan(int chan, pri_event_ring &ev)
|
|||
return;
|
||||
}
|
||||
Debug(DebugInfo,"Ring on channel %d on span %d",chan,m_span);
|
||||
ZapChan* c = getChan(chan);
|
||||
c->ring(ev.call);
|
||||
Debug(DebugInfo,"caller='%s' callerno='%s' callingplan=%d",
|
||||
ev.callingname,ev.callingnum,ev.callingplan);
|
||||
Debug(DebugInfo,"callednum='%s' redirectnum='%s' calledplan=%d",
|
||||
ev.callednum,ev.redirectingnum,ev.calledplan);
|
||||
Debug(DebugInfo,"type=%d complete=%d format='%s'",
|
||||
ev.ctype,ev.complete,lookup(ev.layer1,dict_str2law,"unknown"));
|
||||
ZapChan* c = getChan(chan);
|
||||
c->ring(ev.call);
|
||||
if (m_overlapped && !ev.complete) {
|
||||
if (::strlen(ev.callednum) < m_overlapped) {
|
||||
::pri_need_more_info(pri(),ev.call,chan,!c->isISDN());
|
||||
return;
|
||||
}
|
||||
}
|
||||
Message *m = new Message("call.route");
|
||||
m->addParam("driver","zap");
|
||||
m->addParam("id",c->id());
|
||||
|
@ -806,6 +831,8 @@ void PriSpan::ringChan(int chan, pri_event_ring &ev)
|
|||
m->addParam("caller",ev.callingnum);
|
||||
if (ev.callednum[0])
|
||||
m->addParam("called",ev.callednum);
|
||||
if (m_overlapped && !ev.complete)
|
||||
m->addParam("overlapped","yes");
|
||||
if (Engine::dispatch(m)) {
|
||||
*m = "call.execute";
|
||||
m->addParam("callto",m->retValue());
|
||||
|
@ -1023,7 +1050,7 @@ bool ZapChan::nativeConnect(DataEndpoint *peer)
|
|||
return false;
|
||||
conf.confno = zap->absChan();
|
||||
if (ioctl(m_fd, ZT_SETCONF, &conf))
|
||||
return false;
|
||||
return false;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -1152,7 +1179,7 @@ void ZapChan::answered()
|
|||
m->addParam("span",String(m_span->span()));
|
||||
m->addParam("channel",String(m_chan));
|
||||
if (m_targetid)
|
||||
m->addParam("targetid",m_targetid);
|
||||
m->addParam("targetid",m_targetid);
|
||||
m->addParam("status","answered");
|
||||
Engine::enqueue(m);
|
||||
}
|
||||
|
@ -1165,7 +1192,7 @@ void ZapChan::gotDigits(const char *digits)
|
|||
m->addParam("span",String(m_span->span()));
|
||||
m->addParam("channel",String(m_chan));
|
||||
if (m_targetid)
|
||||
m->addParam("targetid",m_targetid);
|
||||
m->addParam("targetid",m_targetid);
|
||||
m->addParam("text",digits);
|
||||
Engine::enqueue(m);
|
||||
}
|
||||
|
@ -1209,7 +1236,7 @@ bool ZapChan::call(Message &msg, const char *called)
|
|||
break;
|
||||
}
|
||||
connect(dd);
|
||||
msg.addParam("targetid",id());
|
||||
msg.addParam("targetid",id());
|
||||
}
|
||||
else
|
||||
msg.userData(this);
|
||||
|
@ -1305,7 +1332,7 @@ bool ZapDropper::received(Message &msg)
|
|||
{
|
||||
String id(msg.getValue("id"));
|
||||
if (id.null()) {
|
||||
Debug("ZapDropper",DebugInfo,"Dropping all calls");
|
||||
Debug("ZapDropper",DebugInfo,"Dropping all calls");
|
||||
zplugin.mutex.lock();
|
||||
const ObjList *l = &zplugin.m_spans;
|
||||
for (; l; l=l->next()) {
|
||||
|
@ -1319,15 +1346,15 @@ bool ZapDropper::received(Message &msg)
|
|||
}
|
||||
}
|
||||
zplugin.mutex.unlock();
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
if (!id.startsWith("zap/"))
|
||||
return false;
|
||||
return false;
|
||||
ZapChan *c = 0;
|
||||
id >> "zap/";
|
||||
int n = id.toInteger();
|
||||
if ((n > 0) && (c = zplugin.findChan(n))) {
|
||||
Debug("ZapDropper",DebugInfo,"Dropping zap/%d (%d/%d)",
|
||||
Debug("ZapDropper",DebugInfo,"Dropping zap/%d (%d/%d)",
|
||||
n,c->span()->span(),c->chan());
|
||||
zplugin.mutex.lock();
|
||||
c->hangup(PRI_CAUSE_INTERWORKING);
|
||||
|
@ -1342,7 +1369,7 @@ bool ZapChanHandler::received(Message &msg, int id)
|
|||
{
|
||||
String tid(msg.getValue("targetid"));
|
||||
if (!tid.startSkip("zap/",false))
|
||||
return false;
|
||||
return false;
|
||||
int n = tid.toInteger();
|
||||
ZapChan* c = 0;
|
||||
if ((n > 0) && (c = zplugin.findChan(n))) {
|
||||
|
@ -1436,7 +1463,7 @@ ZapChan *ZaptelPlugin::findChan(const char *id)
|
|||
{
|
||||
String s(id);
|
||||
if (!s.startsWith("zap/"))
|
||||
return 0;
|
||||
return 0;
|
||||
s >> "zap/";
|
||||
int n = s.toInteger();
|
||||
return (n > 0) ? findChan(n) : 0;
|
||||
|
@ -1500,17 +1527,33 @@ void ZaptelPlugin::initialize()
|
|||
if (num < 0)
|
||||
break;
|
||||
if (num) {
|
||||
int dchan = -1;
|
||||
// guess where we may have a D channel
|
||||
switch (num) {
|
||||
case 3:
|
||||
// BRI ISDN
|
||||
dchan = 3;
|
||||
break;
|
||||
case 24:
|
||||
// T1 with CCS
|
||||
dchan = 24;
|
||||
break;
|
||||
case 31:
|
||||
// EuroISDN
|
||||
dchan = 16;
|
||||
break;
|
||||
}
|
||||
chan1 = cfg.getIntValue(sect,"first",chan1);
|
||||
PriSpan::create(span,chan1,num,
|
||||
cfg.getIntValue(sect,"dchan", num > 24 ? 16 : -1),
|
||||
cfg.getBoolValue(sect,"isnet",true),
|
||||
cfg.getIntValue(sect,"dchan", dchan),
|
||||
cfg.getIntValue(sect,"type",dict_str2type,PRI_NETWORK),
|
||||
cfg.getIntValue(sect,"swtype",dict_str2switch,
|
||||
PRI_SWITCH_UNKNOWN),
|
||||
cfg.getIntValue(sect,"dialplan",dict_str2dplan,
|
||||
PRI_UNKNOWN),
|
||||
cfg.getIntValue(sect,"presentation",dict_str2pres,
|
||||
PRES_ALLOWED_USER_NUMBER_NOT_SCREENED),
|
||||
cfg.getBoolValue(sect,"overlapdial",false),
|
||||
cfg.getIntValue(sect,"overlapdial"),
|
||||
cfg.getIntValue(sect,"facilities",dict_str2nsf,
|
||||
YATE_NSF_DEFAULT)
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue