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:
paulc 2005-01-29 15:55:06 +00:00
parent 704351f1b7
commit ca232d251c
3 changed files with 106 additions and 44 deletions

View File

@ -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

View File

@ -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;

View File

@ -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)
);