Override (local announcement) fully supported in tone and wavefile.

Inband DTMF for PRI channels by using the tone generator.
Reduced the default PRI buffer from 60 to 20 msec.


git-svn-id: http://yate.null.ro/svn/yate/trunk@528 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
paulc 2005-09-28 22:06:11 +00:00
parent 39e6ae4ecb
commit a497425f07
7 changed files with 130 additions and 34 deletions

View File

@ -183,5 +183,5 @@ context=default
; do a DoS attack over your server.
;maxqueue=5
; called: string: Default number to call
called=8989989
; called: string: Default number to call if not present in call setup
;called=

View File

@ -13,9 +13,10 @@
; type= pri_net,pri_cpe
[general]
;buflen=480
;buflen=160
;restart=0
;dumpevents=no
;dtmfinband=no
[span 1]
;dgroup=w1g1

View File

@ -13,9 +13,10 @@
; type= pri_net,pri_cpe,bri_net_ptmp,bri_cpe_ptmp,bri_net,bri_cpe
[general]
;buflen=480
;buflen=160
;restart=0
;dumpevents=no
;dtmfinband=no
[span 1]
chans=31

View File

@ -36,7 +36,8 @@ extern int q931_setup(struct pri *pri, q931_call *c, struct pri_sr *req);
using namespace TelEngine;
static int s_buflen = 480;
// default buffer length: 20 ms
static int s_buflen = 160;
#ifdef PRI_NEW_SET_API
#define PRI_CB_STR struct pri *pri,
@ -245,6 +246,7 @@ PriSpan::PriSpan(struct pri *_pri, PriDriver* driver, int span, int first, int c
Debug(m_driver,DebugAll,"PriSpan::PriSpan() [%p]",this);
int buflength = cfg.getIntValue(sect,"buflen", s_buflen);
m_inband = cfg.getBoolValue(sect,"dtmfinband",cfg.getBoolValue("general","dtmfinband"));
m_layer1 = cfg.getIntValue(sect,"format",dict_str2law,(chans == 24) ? PRI_LAYER_1_ULAW : PRI_LAYER_1_ALAW);
m_dplan = cfg.getIntValue(sect,"dialplan",dict_str2dplan,PRI_UNKNOWN);
m_pres = cfg.getIntValue(sect,"presentation",dict_str2pres,PRES_ALLOWED_USER_NUMBER_NOT_SCREENED);
@ -753,6 +755,7 @@ bool PriChan::call(Message &msg, const char *called)
}
else
msg.userData(this);
m_inband = msg.getBoolValue("dtmfinband",m_span->inband());
Output("Calling '%s' on %s (%d/%d)",called,id().c_str(),m_span->span(),m_chan);
char *caller = (char *)msg.getValue("caller");
int callerplan = msg.getIntValue("callerplan",dict_str2dplan,m_span->dplan());
@ -805,6 +808,7 @@ void PriChan::ring(pri_event_ring &ev)
m->addParam("direction","incoming");
Engine::enqueue(m);
m_inband = m_span->inband();
openData(lookup(ev.layer1,dict_str2law),0);
m = message("call.route");
@ -858,8 +862,22 @@ bool PriChan::msgAnswered(Message& msg)
bool PriChan::msgTone(Message& msg, const char* tone)
{
for (; !null(tone); tone++)
sendDigit(*tone);
if (null(tone))
return false;
if (m_inband) {
Message m("chan.attach");
complete(m,true);
m.userData(this);
String tmp("tone/dtmfstr/");
tmp += tone;
m.setParam("override",tmp);
m.setParam("single","yes");
if (Engine::dispatch(m))
return true;
// if we failed try to send as signalling anyway
}
while (*tone)
sendDigit(*tone++);
return true;
}
@ -1054,7 +1072,7 @@ void PriDriver::netParams(Configuration& cfg, const String& sect, int chans, int
void PriDriver::init(const char* configName)
{
Configuration cfg(Engine::configFile(configName));
s_buflen = cfg.getIntValue("general","buflen",480);
s_buflen = cfg.getIntValue("general","buflen",160);
if (!m_spans.count()) {
int chan1 = 1;
for (int span = 1;;span++) {

View File

@ -72,6 +72,8 @@ public:
{ return m_pres; }
inline unsigned int overlapped() const
{ return m_overlapped; }
inline bool inband() const
{ return m_inband; }
inline bool outOfOrder() const
{ return !m_ok; }
inline int buflen() const
@ -105,6 +107,7 @@ protected:
int m_pres;
int m_buflen;
int m_layer1;
bool m_inband;
unsigned int m_overlapped;
String m_callednumber;
struct pri *m_pri;
@ -160,6 +163,8 @@ public:
{ return m_abschan; }
inline bool inUse() const
{ return (m_ring || m_call); }
inline bool inband() const
{ return m_inband; }
void ring(pri_event_ring &ev);
void hangup(int cause = 0);
void sendDigit(char digit);
@ -187,6 +192,7 @@ protected:
unsigned int m_bufsize;
int m_abschan;
bool m_isdn;
bool m_inband;
};
class PriDriver : public Driver

View File

@ -32,6 +32,10 @@
#define M_PI 3.14159265358979323846
#endif
// 40ms silence, 120ms tone, 40ms silence, total 200ms - slow but safe
#define DTMF_LEN 960
#define DTMF_GAP 320
using namespace TelEngine;
static ObjList tones;
@ -93,7 +97,7 @@ public:
static ToneSource* getTone(String& tone);
static const Tone* getBlock(String& tone);
static Tone* buildCadence(const String& desc);
static Tone* buildDtmf(const String& dtmf);
static Tone* buildDtmf(const String& dtmf, int len = DTMF_LEN, int gap = DTMF_GAP);
protected:
ToneSource();
ToneSource(String& tone);
@ -185,10 +189,6 @@ static const Tone t_silence[] = { { 8000, 0 }, { 0, 0 } };
static const Tone t_noise[] = { { 2000, ToneData::getData("noise")->data() }, { 0, 0 } };
// 20ms silence, 85ms tone, 20ms silence, total 125ms
#define DTMF_GAP 160
#define DTMF_LEN 680
#define MAKE_DTMF(s) { \
{ DTMF_GAP, 0 }, \
{ DTMF_LEN, ToneData::getData(s)->data() }, \
@ -204,14 +204,14 @@ static const Tone t_dtmf[][4] = {
MAKE_DTMF("1209+770"),
MAKE_DTMF("1336+770"),
MAKE_DTMF("1477+770"),
MAKE_DTMF("1209+825"),
MAKE_DTMF("1336+825"),
MAKE_DTMF("1477+825"),
MAKE_DTMF("1209+852"),
MAKE_DTMF("1336+852"),
MAKE_DTMF("1477+852"),
MAKE_DTMF("1209+941"),
MAKE_DTMF("1477+941"),
MAKE_DTMF("1633+697"),
MAKE_DTMF("1633+770"),
MAKE_DTMF("1633+825"),
MAKE_DTMF("1633+852"),
MAKE_DTMF("1633+941")
};
#undef MAKE_DTMF
@ -346,7 +346,7 @@ const short* ToneData::data()
else
y += z;
}
*tmp++ = (short)(y*10000);
*tmp++ = (short)(y*5000);
}
}
m_data = dat;
@ -372,14 +372,14 @@ ToneData* ToneData::getData(const char* desc)
ToneSource::ToneSource()
: m_tone(0), m_repeat(1),
m_data(0,480), m_brate(16000), m_total(0), m_time(0)
m_data(0,320), m_brate(16000), m_total(0), m_time(0)
{
Debug(&__plugin,DebugAll,"ToneSource::ToneSource() [%p]",this);
}
ToneSource::ToneSource(String& tone)
: m_name(tone), m_tone(0), m_repeat(0),
m_data(0,480), m_brate(16000), m_total(0), m_time(0)
m_data(0,320), m_brate(16000), m_total(0), m_time(0)
{
Debug(&__plugin,DebugAll,"ToneSource::ToneSource(\"%s\") [%p]",tone.c_str(),this);
m_tone = getBlock(tone);
@ -423,12 +423,15 @@ const Tone* ToneSource::getBlock(String& tone)
return 0;
}
// Build an user defined cadence
Tone* ToneSource::buildCadence(const String& desc)
{
// TBD
return 0;
}
Tone* ToneSource::buildDtmf(const String& dtmf)
// Build a cadence out of DTMFs
Tone* ToneSource::buildDtmf(const String& dtmf, int len, int gap)
{
if (dtmf.null())
return 0;
@ -438,7 +441,7 @@ Tone* ToneSource::buildDtmf(const String& dtmf)
Tone* t = tmp;
for (unsigned int i = 0; i < dtmf.length(); i++) {
t->nsamples = i ? DTMF_GAP : (2*DTMF_GAP);
t->nsamples = gap;
t->data = 0;
t++;
@ -453,12 +456,12 @@ Tone* ToneSource::buildDtmf(const String& dtmf)
c -= ('a' - 12);
else c = -1;
t->nsamples = DTMF_LEN;
t->data = ((c > 0) && (c < 16)) ? t_dtmf[c][1].data : 0;
t->nsamples = len;
t->data = ((c >= 0) && (c < 16)) ? t_dtmf[c][1].data : 0;
t++;
}
t->nsamples = DTMF_GAP;
t->nsamples = gap;
t->data = 0;
t++;
t->nsamples = 0;
@ -548,13 +551,21 @@ TempSource::TempSource(String& desc)
return;
if (desc.startSkip("*",false))
m_repeat = 0;
// try first the named tones
m_tone = getBlock(desc);
if (m_tone)
return;
// for performance reason accept an entire string of DTMFs
if (desc.startSkip("dtmfstr/",false)) {
m_tone = m_single = buildDtmf(desc);
return;
}
// or an entire user defined cadence of tones
if (desc.startSkip("cadence/",false)) {
m_tone = m_single = buildCadence(desc);
return;
}
// now try to build a single tone
ToneData* td = ToneData::getData(desc);
if (!td)
return;
@ -675,6 +686,9 @@ bool AttachHandler::received(Message& msg)
return false;
}
// if single attach was requested we can return true if everything is ok
bool ret = msg.getBoolValue("single");
Lock lock(__plugin);
if (src) {
ToneSource* t = ToneSource::getTone(src);
@ -683,8 +697,10 @@ bool AttachHandler::received(Message& msg)
t->deref();
msg.clearParam("source");
}
else
else {
Debug(DebugWarn,"No source tone '%s' could be attached to %p",src.c_str(),de);
ret = false;
}
}
if (ovr) {
DataConsumer* c = de->getConsumer();
@ -692,13 +708,17 @@ bool AttachHandler::received(Message& msg)
TempSource* t = new TempSource(ovr);
if (DataTranslator::attachChain(t,c,true) && t->startup())
msg.clearParam("override");
else
else {
Debug(DebugWarn,"Override source tone '%s' failed to start [%p]",ovr.c_str(),t);
ret = false;
}
}
else
else {
Debug(DebugWarn,"Requested override '%s' to missing consumer of %p",ovr.c_str(),de);
ret = false;
}
}
return false;
return ret;
}
void ToneGenDriver::statusModule(String& str)

View File

@ -261,12 +261,13 @@ void WaveSource::run()
tpos += (r*(u_int64_t)1000000/m_brate);
} while (r > 0);
Debug(&__plugin,DebugAll,"WaveSource [%p] end of data [%p] [%s] ",this,m_chan,m_id.c_str());
if (m_chan && !m_id.null()) {
if (m_id) {
Message *m = new Message("chan.notify");
m->addParam("targetid",m_id);
m->userData(m_chan);
Engine::enqueue(m);
m_chan->setSource();
if (m_chan && (m_chan->getSource() == this))
m_chan->setSource();
}
}
@ -275,6 +276,8 @@ void WaveSource::cleanup()
Debug(&__plugin,DebugAll,"WaveSource [%p] cleanup, total=%u",this,m_total);
if (m_chan && m_autoclose)
m_chan->disconnect("eof");
if (!m_chan)
deref();
}
WaveConsumer::WaveConsumer(const String& file, CallEndpoint* chan, unsigned maxlen)
@ -375,7 +378,7 @@ WaveChan::~WaveChan()
bool AttachHandler::received(Message &msg)
{
int more = 2;
int more = 3;
String src(msg.getValue("source"));
if (src.null())
more--;
@ -415,9 +418,33 @@ bool AttachHandler::received(Message &msg)
else
cons = "";
}
if (src.null() && cons.null())
String ovr(msg.getValue("override"));
if (ovr.null())
more--;
else {
Regexp r("^wave/\\([^/]*\\)/\\(.*\\)$");
if (ovr.matches(r)) {
if (ovr.matchString(1) == "play") {
ovr = ovr.matchString(2);
more--;
}
else {
Debug(DebugWarn,"Could not attach override with method '%s', use 'play'",
ovr.matchString(1).c_str());
ovr = "";
}
}
else
ovr = "";
}
if (src.null() && cons.null() && ovr.null())
return false;
// if single attach was requested we can return true if everything is ok
bool ret = msg.getBoolValue("single");
String ml(msg.getValue("maxlen"));
unsigned maxlen = ml.toInteger(0);
CallEndpoint *ch = static_cast<CallEndpoint*>(msg.userData());
@ -426,6 +453,8 @@ bool AttachHandler::received(Message &msg)
Debug(DebugWarn,"Wave source '%s' attach request with no data channel!",src.c_str());
if (!cons.null())
Debug(DebugWarn,"Wave consumer '%s' attach request with no data channel!",cons.c_str());
if (!ovr.null())
Debug(DebugWarn,"Wave override '%s' attach request with no data channel!",ovr.c_str());
return false;
}
@ -434,6 +463,7 @@ bool AttachHandler::received(Message &msg)
s->setNotify(msg.getValue("notify"));
ch->setSource(s);
s->deref();
msg.clearParam("source");
}
if (!cons.null()) {
@ -441,10 +471,30 @@ bool AttachHandler::received(Message &msg)
c->setNotify(msg.getValue("notify"));
ch->setConsumer(c);
c->deref();
msg.clearParam("consumer");
}
while (!ovr.null()) {
DataConsumer* c = ch->getConsumer();
if (!c) {
Debug(DebugWarn,"Wave override '%s' attach request with no consumer!",ovr.c_str());
ret = false;
break;
}
WaveSource* s = new WaveSource(ovr,0,false);
s->setNotify(msg.getValue("notify"));
if (DataTranslator::attachChain(s,c,true))
msg.clearParam("override");
else {
Debug(DebugWarn,"Failed to override attach wave '%s' to consumer %p",ovr.c_str(),c);
s->deref();
ret = false;
}
break;
}
// Stop dispatching if we handled all requested
return !more;
return ret && !more;
}
bool RecordHandler::received(Message &msg)