Implemented sending of trunk without miniframes timestamp. Fixed timestamp handling when processing trunk without miniframes timestamps. Check for thread termination when parsing lists tp process transactions and trunks.

git-svn-id: http://yate.null.ro/svn/yate/trunk@5535 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2013-06-11 08:57:46 +00:00
parent 9d8f0a75b0
commit 3021fe3b2a
6 changed files with 571 additions and 221 deletions

View File

@ -32,6 +32,66 @@
; Defaults to user-provided if missing or incorrect
;screening=user-provided
; trunk_timestamps: boolean: Configure how trunked audio data is sent, enable it for
; trunked data with timestamps and disable it to send trunked data without timestamps
; This parameter is applied on reload
; It can be overridden when routing by 'trunkin_timestamps' for incoming calls
; or 'trunkout_timestamps' for outgoing calls
; This parameter is applied when a new trunk is created (a trunked call is created and
; there is no trunk for the same remote address)
; Defaults to yes
;trunk_timestamps=yes
; trunk_sendinterval: integer: Interval, in milliseconds, to send trunked trunked audio data
; The interval is measured from the first packet put in a trunk
; Trunked data is sent when this interval ellapses or the buffer is full
; This parameter is applied on reload
; It can be overridden when routing by 'trunkin_sendinterval' for incoming calls
; or 'trunkout_sendinterval' for outgoing calls
; This parameter is applied when a new trunk is created (a trunked call is created and
; there is no trunk for the same remote address)
; Minimum allowed value is 5
; Defaults to 20
;trunk_sendinterval=20
; trunk_maxlen: integer: Maximum value for trunked data frames.
; This value includes the length if trunk frame header (8 bytes)
; Trunked data is sent when the send interval ellapses or the buffer is full
; This parameter is applied on reload
; It can be overridden when routing by 'trunkin_maxlen' for incoming calls
; or 'trunkout_maxlen' for outgoing calls
; This parameter is applied when a new trunk is created (a trunked call is created and
; there is no trunk for the same remote address)
; Minimum allowed value is 20
; Defaults to 1400
;trunk_maxlen=1400
; trunk_nominits_sync_use_ts: boolean: Configure how to re-build timestamps when
; processing incoming trunked audio without miniframe timestamps
; When enabled the transaction will use trunk timestamp and last received full voice
; frame time and timestamp to build miniframe timestamps
; When disabled the transaction will use the time difference between current time and
; last received full voice frame to build the miniframe timestamps
; This parameter is applied on reload
; It can be overridden when routing by 'trunkin_nominits_sync_use_ts' for incoming calls
; or 'trunkout_nominits_sync_use_ts' for outgoing calls
; Defaults to yes
;trunk_nominits_sync_use_ts=yes
; trunk_nominits_ts_diff_restart: integer: The difference (in milliseconds) between
; current timestamp and first timestamp of incoming trunked audio data without miniframe
; timestamps at which to restart timestamps build data
; This value is used when received trunk timestamp is older then first timestamp
; If the difference is less then this value the miniframes will be dropped
; This will deal with trunk timestamp wraparound or restarted by remote party
; This parameter is ignored if trunk_nominits_sync_use_ts is disabled
; This parameter is applied on reload
; It can be overridden when routing by 'trunkin_nominits_ts_diff_restart' for incoming
; calls or 'trunkout_nominits_ts_diff_restart' for outgoing calls
; Minimum allowed value is 1000
; Defaults to 5000
;trunk_nominits_ts_diff_restart=5000
; calltoken_in: boolean: Use call token ip address authentication on incoming calls
; Note: If the caller don't support the call token IAX extension the call request
; will be ignored anyway

View File

@ -57,8 +57,7 @@ static void buildSecretDigest(String& buf, const String& secret, unsigned int t,
IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen,
u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval, bool authRequired,
NamedList* params)
u_int32_t format, u_int32_t capab, bool authRequired, NamedList* params)
: Mutex(true,"IAXEngine"),
m_lastGetEvIndex(0),
m_authRequired(authRequired),
@ -81,8 +80,7 @@ IAXEngine::IAXEngine(const char* iface, int port, u_int16_t transListCount, u_in
m_adjustTsOutThreshold(IAX2_ADJUSTTSOUT_THRES),
m_adjustTsOutOverrun(IAX2_ADJUSTTSOUT_OVER),
m_adjustTsOutUnderrun(IAX2_ADJUSTTSOUT_UNDER),
m_mutexTrunk(true,"IAXEngine::Trunk"),
m_trunkSendInterval(trunkSendInterval)
m_mutexTrunk(false,"IAXEngine::Trunk")
{
debugName("iaxengine");
Debug(this,DebugAll,"Automatically request authentication set to '%s'.",
@ -412,6 +410,7 @@ void IAXEngine::initialize(const NamedList& params)
m_callerNumType = lookup(params["numtype"],IAXInfoElement::s_typeOfNumber);
m_callingPres = lookup(params["presentation"],IAXInfoElement::s_presentation) |
lookup(params["screening"],IAXInfoElement::s_screening);
m_trunkInfoDef.init(params,"trunk_");
initOutDataAdjust(params);
}
@ -420,6 +419,8 @@ void IAXEngine::readSocket(SocketAddr& addr)
unsigned char buf[1500];
while (1) {
if (Thread::check(false))
break;
int len = m_socket.recvFrom(buf,sizeof(buf),addr);
if (len == Socket::socketError()) {
if (!m_socket.canRetry()) {
@ -428,7 +429,7 @@ void IAXEngine::readSocket(SocketAddr& addr)
Debug(this,DebugWarn,"Socket read error: %s (%d)",
tmp.c_str(),m_socket.error());
}
Thread::idle(true);
Thread::idle(false);
continue;
}
addFrame(addr,buf,len);
@ -471,10 +472,10 @@ bool IAXEngine::writeSocket(const void* buf, int len, const SocketAddr& addr,
void IAXEngine::runGetEvents()
{
while (1) {
if (!process()) {
Thread::idle(true);
continue;
}
if (Thread::check(false))
break;
if (!process())
Thread::idle(false);
}
}
@ -537,21 +538,27 @@ void IAXEngine::decodeDateTime(u_int32_t dt, unsigned int& year, unsigned int& m
sec = dt & 0x1f;
}
bool IAXEngine::processTrunkFrames(u_int32_t time)
bool IAXEngine::processTrunkFrames(const Time& time)
{
Lock lock(&m_mutexTrunk);
Lock lck(m_mutexTrunk);
bool sent = false;
for (ObjList* l = m_trunkList.skipNull(); l; l = l->skipNext()) {
for (ObjList* l = m_trunkList.skipNull(); l;) {
if (Thread::check(false))
break;
IAXMetaTrunkFrame* frame = static_cast<IAXMetaTrunkFrame*>(l->get());
// Frame has mini frame(s) ?
if (!frame->timestamp())
if (frame->refcount() != 1) {
l = l->skipNext();
if (frame->timerTick(time))
sent = true;
continue;
int32_t interval = time - frame->timestamp();
if (!interval || (interval && (u_int32_t)interval < m_trunkSendInterval))
continue;
// If the time wrapped around, send it. Worst case: we'll send an empty frame
frame->send(time);
sent = true;
}
Debug(this,DebugAll,
"Removing trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums",
frame,frame->addr().host().c_str(),frame->addr().port(),
String::boolText(frame->trunkTimestamps()),frame->maxLen(),
frame->sendInterval());
l->remove();
l = l->skipNull();
}
return sent;
}
@ -573,15 +580,18 @@ IAXEvent* IAXEngine::getEvent(u_int64_t time)
// Find for incomplete transactions
l = m_incompleteTransList.skipNull();
for (; l; l = l->next()) {
if (Thread::check(false))
break;
tr = static_cast<IAXTransaction*>(l->get());
if (tr && 0 != (ev = tr->getEvent(time))) {
unlock();
return ev;
}
continue;
}
// Find for complete transactions, start with current index
while (m_lastGetEvIndex < m_transListCount) {
if (Thread::check(false))
break;
l = m_transList[m_lastGetEvIndex++]->skipNull();
if (!l)
continue;
@ -633,18 +643,16 @@ void IAXEngine::releaseCallNo(u_int16_t lcallno)
m_lUsedCallNo[lcallno] = false;
}
IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList, bool trunking)
IAXTransaction* IAXEngine::startLocalTransaction(IAXTransaction::Type type,
const SocketAddr& addr, IAXIEList& ieList)
{
Lock lock(this);
u_int16_t lcn = generateCallNo();
if (!lcn)
return 0;
IAXTransaction* tr = IAXTransaction::factoryOut(this,type,lcn,addr,ieList);
if (tr) {
if (tr)
m_incompleteTransList.append(tr);
if (trunking)
enableTrunking(tr);
}
else
releaseCallNo(lcn);
return tr;
@ -774,31 +782,55 @@ void IAXEngine::defaultEventHandler(IAXEvent* event)
}
}
void IAXEngine::enableTrunking(IAXTransaction* trans)
void IAXEngine::enableTrunking(IAXTransaction* trans, const NamedList* params,
const String& prefix)
{
if (!trans || trans->type() != IAXTransaction::New)
return;
Lock lock(&m_mutexTrunk);
Lock lock(m_mutexTrunk);
IAXMetaTrunkFrame* frame;
// Already enabled ?
for (ObjList* l = m_trunkList.skipNull(); l; l = l->next()) {
for (ObjList* l = m_trunkList.skipNull(); l; l = l->skipNext()) {
frame = static_cast<IAXMetaTrunkFrame*>(l->get());
if (frame && frame->addr() == trans->remoteAddr()) {
if (frame->addr() == trans->remoteAddr()) {
trans->enableTrunking(frame);
return;
}
}
frame = new IAXMetaTrunkFrame(this,trans->remoteAddr());
if (trans->enableTrunking(frame))
IAXTrunkInfo tmp;
IAXTrunkInfo* trunk = &m_trunkInfoDef;
if (params) {
tmp.initTrunking(*params,prefix,trunk,true);
trunk = &tmp;
}
frame = new IAXMetaTrunkFrame(this,trans->remoteAddr(),trunk->m_timestamps,
trunk->m_maxLen,trunk->m_sendInterval);
if (trans->enableTrunking(frame)) {
m_trunkList.append(frame);
// Deref frame: Only transactions are allowed to keep references for it
frame->deref();
Debug(this,DebugAll,
"Added trunk frame (%p) '%s:%d' timestamps=%s maxlen=%u interval=%ums",
frame,frame->addr().host().c_str(),frame->addr().port(),
String::boolText(frame->trunkTimestamps()),frame->maxLen(),
frame->sendInterval());
}
else
TelEngine::destruct(frame);
}
void IAXEngine::removeTrunkFrame(IAXMetaTrunkFrame* trunkFrame)
// Init incoming trunking data for a given transaction
void IAXEngine::initTrunkIn(IAXTransaction* trans, const NamedList* params,
const String& prefix)
{
Lock lock(&m_mutexTrunk);
m_trunkList.remove(trunkFrame,false);
if (!trans)
return;
IAXTrunkInfo tmp;
IAXTrunkInfo* trunk = &m_trunkInfoDef;
if (params) {
tmp.initTrunking(*params,prefix,trunk,false);
trunk = &tmp;
}
trans->m_trunkInSyncUsingTs = trunk->m_trunkInSyncUsingTs;
trans->m_trunkInTsDiffRestart = trunk->m_trunkInTsDiffRestart;
}
void IAXEngine::runProcessTrunkFrames()

View File

@ -50,25 +50,24 @@ static inline void setStringFromInteger(String& dest, u_int32_t value, u_int8_t
class IAXTrunkFrameTrans : public GenObject
{
public:
inline IAXTrunkFrameTrans(IAXTransaction* tr, u_int32_t frameTs)
: m_tr(tr), m_frameTs(frameTs), m_trunkIndex(0)
inline IAXTrunkFrameTrans(u_int16_t callNo)
: m_callNo(callNo)
{}
~IAXTrunkFrameTrans()
{ TelEngine::destruct(m_tr); }
static IAXTrunkFrameTrans* find(ObjList& list, u_int16_t rCallNo);
IAXTransaction* m_tr;
u_int32_t m_frameTs;
unsigned int m_trunkIndex;
static IAXTrunkFrameTrans* get(ObjList& list, u_int16_t rCallNo);
u_int16_t m_callNo;
ObjList m_blocks;
};
IAXTrunkFrameTrans* IAXTrunkFrameTrans::find(ObjList& list, u_int16_t rCallNo)
IAXTrunkFrameTrans* IAXTrunkFrameTrans::get(ObjList& list, u_int16_t callNo)
{
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
IAXTrunkFrameTrans* t = static_cast<IAXTrunkFrameTrans*>(o->get());
if (t->m_tr->remoteCallNo() == rCallNo)
if (t->m_callNo == callNo)
return t;
}
return 0;
IAXTrunkFrameTrans* t = new IAXTrunkFrameTrans(callNo);
list.append(t);
return t;
}
@ -1080,43 +1079,33 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
u_int32_t ts = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
buf += 8;
len -= 8;
u_int64_t timeMs = Time::msecNow();
Time now;
ObjList list;
while (len >= 4) {
u_int16_t dlen = (buf[2] << 8) | buf[3];
if ((unsigned int)(dlen + 4) > len)
return 0;
break;
scn = (buf[0] << 8) | buf[1];
bool retrans = false;
if (scn & 0x8000) {
retrans = true;
scn &= 0x7fff;
}
IAXTrunkFrameTrans* t = IAXTrunkFrameTrans::find(list,scn);
if (!t) {
IAXTransaction* tr = engine->findTransaction(*addr,scn);
if (tr) {
u_int32_t frameTs = 0;
if (tr->updateTrunkRecvTs(frameTs,ts,timeMs)) {
t = new IAXTrunkFrameTrans(tr,frameTs);
list.append(t);
}
else
TelEngine::destruct(tr);
}
}
else
// Adjust timestamp: there are more packets for the same transaction
t->m_frameTs++;
if (t) {
IAXFrame* frame = new IAXFrame(IAXFrame::Voice,scn,t->m_frameTs,retrans,buf+4,dlen);
if (!t->m_tr->processFrame(frame))
frame->deref();
}
IAXTrunkFrameTrans* t = IAXTrunkFrameTrans::get(list,scn);
t->m_blocks.append(new DataBlock((void*)(buf+4),dlen));
dlen += 4;
buf += dlen;
len -= dlen;
}
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
IAXTrunkFrameTrans* t = static_cast<IAXTrunkFrameTrans*>(o->get());
IAXTransaction* tr = engine->findTransaction(*addr,t->m_callNo);
if (!tr)
continue;
tr->processMiniNoTs(ts,t->m_blocks,now);
TelEngine::destruct(tr);
}
}
return 0;
}
@ -1450,74 +1439,158 @@ void IAXFrameOut::adjustAuthTimeout(u_int64_t nextTransTime)
m_nextTransTime = nextTransTime;
}
/*
* IAXTrunkInfo
*/
// Init all data from parameters
void IAXTrunkInfo::init(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def)
{
initTrunking(params,prefix,def,true);
initTrunking(params,prefix,def,false);
}
// Init from parameters
void IAXTrunkInfo::initTrunking(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def, bool out)
{
if (out) {
m_timestamps = params.getBoolValue(prefix + "timestamps",
!def || def->m_timestamps);
m_sendInterval = params.getIntValue(prefix + "sendinterval",
def ? def->m_sendInterval : IAX2_TRUNKFRAME_SEND_DEF,IAX2_TRUNKFRAME_SEND_MIN);
m_maxLen = params.getIntValue(prefix + "maxlen",
def ? def->m_maxLen : IAX2_TRUNKFRAME_LEN_DEF,IAX2_TRUNKFRAME_LEN_MIN);
}
else {
m_trunkInSyncUsingTs = params.getBoolValue(prefix + "nominits_sync_use_ts",
!def || def->m_trunkInSyncUsingTs);
m_trunkInTsDiffRestart = params.getIntValue(prefix + "nominits_ts_diff_restart",
def ? m_trunkInTsDiffRestart : 5000,1000);
}
}
/*
* IAXMetaTrunkFrame
*/
#define IAX2_METATRUNK_HEADERLENGTH 8
#define IAX2_MINIFRAME_HEADERLENGTH 6
IAXMetaTrunkFrame::IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr)
: Mutex(true,"IAXMetaTrunkFrame"),
m_data(0), m_dataAddIdx(IAX2_METATRUNK_HEADERLENGTH), m_engine(engine), m_addr(addr)
IAXMetaTrunkFrame::IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr,
bool timestamps, unsigned int maxLen, unsigned int sendInterval)
: Mutex(false,"IAXMetaTrunkFrame"),
m_data(0), m_dataAddIdx(IAX2_TRUNKFRAME_HEADERLENGTH),
m_timeStamp(0), m_send(0), m_lastSentTs(0),
m_sendInterval(sendInterval),
m_engine(engine), m_addr(addr),
m_trunkTimestamps(timestamps), m_maxLen(maxLen), m_maxDataLen(0),
m_miniHdrLen(timestamps ? 6 : 4)
{
m_data = new u_int8_t[m_engine->maxFullFrameDataLen()];
// Make sure we don't receive invalid values
if (m_maxLen < IAX2_TRUNKFRAME_LEN_MIN)
m_maxLen = IAX2_TRUNKFRAME_LEN_MIN;
m_data = new u_int8_t[m_maxLen];
// Audio data length can't be greater the remaining space
// Also make sure we can put it in 2 bytes
m_maxDataLen = m_maxLen - IAX2_TRUNKFRAME_HEADERLENGTH - m_miniHdrLen;
if (m_maxDataLen > 0xffff)
m_maxDataLen = 0xffff;
// Meta indicator
*(u_int16_t*)m_data = 0;
// Meta command & Command data (use timestamps)
m_data[2] = 1;
m_data[3] = 1;
// Frame timestamp
setTimestamp((u_int32_t)Time::msecNow());
m_data[3] = m_trunkTimestamps ? 1 : 0;
}
IAXMetaTrunkFrame::~IAXMetaTrunkFrame()
{
m_engine->removeTrunkFrame(this);
delete[] m_data;
}
void IAXMetaTrunkFrame::setTimestamp(u_int32_t tStamp)
{
m_timestamp = tStamp;
m_data[4] = (u_int8_t)(tStamp >> 24);
m_data[5] = (u_int8_t)(tStamp >> 16);
m_data[6] = (u_int8_t)(tStamp >> 8);
m_data[7] = (u_int8_t)tStamp;
delete[] m_data;
}
bool IAXMetaTrunkFrame::add(u_int16_t sCallNo, const DataBlock& data, u_int32_t tStamp)
{
Lock lock(this);
bool b = true;
// Do we have data ?
if (!data.length())
return b;
return false;
// Avoid buffer overflow
if (data.length() > m_maxDataLen) {
Debug(m_engine,DebugGoOn,
"Trunk frame '%s:%d' can't add %u bytes (max=%u) for call %u [%p]",
m_addr.host().c_str(),m_addr.port(),data.length(),m_maxDataLen,sCallNo,this);
return false;
}
Lock lck(this);
if (!m_timeStamp)
setTimestamp(Time::now());
bool b = true;
// If no more room, send it
if (m_dataAddIdx + data.length() + IAX2_MINIFRAME_HEADERLENGTH > m_engine->maxFullFrameDataLen())
b = send((u_int32_t)Time::msecNow());
// Is the first mini frame ?
if (m_dataAddIdx == IAX2_METATRUNK_HEADERLENGTH)
m_timestamp = (u_int32_t)Time::msecNow();
if (m_dataAddIdx + data.length() + m_miniHdrLen > m_maxLen)
b = doSend();
XDebug(m_engine,DebugAll,"Trunk frame '%s:%d' adding %u payload bytes call=%u [%p]",
m_addr.host().c_str(),m_addr.port(),data.length(),sCallNo,this);
// Add the mini frame
m_data[m_dataAddIdx++] = (u_int8_t)(data.length() >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)data.length();
m_data[m_dataAddIdx++] = (u_int8_t)(sCallNo >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)sCallNo;
m_data[m_dataAddIdx++] = (u_int8_t)(tStamp >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)tStamp;
if (m_trunkTimestamps) {
// data length + call no + timestamp
m_data[m_dataAddIdx++] = (u_int8_t)(data.length() >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)data.length();
m_data[m_dataAddIdx++] = (u_int8_t)(sCallNo >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)sCallNo;
m_data[m_dataAddIdx++] = (u_int8_t)(tStamp >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)tStamp;
}
else {
// call no + data length
m_data[m_dataAddIdx++] = (u_int8_t)(sCallNo >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)sCallNo;
m_data[m_dataAddIdx++] = (u_int8_t)(data.length() >> 8);
m_data[m_dataAddIdx++] = (u_int8_t)data.length();
}
memcpy(m_data + m_dataAddIdx,data.data(),data.length());
m_dataAddIdx += data.length();
return b;
}
bool IAXMetaTrunkFrame::send(u_int32_t tStamp)
// Send this frame to remote peer
bool IAXMetaTrunkFrame::doSend(const Time& now, bool onTime)
{
Lock lock(this);
setTimestamp(tStamp);
#define IAX2_TRUNKDATA_DELTA 160
bool dontSend = (m_dataAddIdx <= IAX2_TRUNKFRAME_HEADERLENGTH);
u_int64_t ellapsed = (now - m_timeStamp) / 1000;
if (ellapsed <= 0xffffffff) {
// Sent on time: set timestamp from send interval
// Sent on buffer full: set timestamp from ellapsed time
u_int32_t ts = 0;
if (onTime) {
setSendTime(now);
ts = m_lastSentTs + m_sendInterval;
if (ts != ellapsed) {
// Adjust timestamp
if (ts > ellapsed) {
if ((ts - ellapsed) >= IAX2_TRUNKDATA_DELTA)
ts = (u_int32_t)ellapsed;
}
else if ((ellapsed - ts) >= IAX2_TRUNKDATA_DELTA)
ts = (u_int32_t)ellapsed;
}
}
else
ts = (u_int32_t)ellapsed;
if (ts > m_lastSentTs || dontSend)
m_lastSentTs = ts;
else
m_lastSentTs++;
}
else {
// Timestamp wraparound: reset
setTimestamp(now);
m_lastSentTs = 0;
}
if (dontSend)
return false;
XDebug(m_engine,DebugAll,"Trunk frame '%s:%d' sending %u tStamp=%u [%p]",
m_addr.host().c_str(),m_addr.port(),m_dataAddIdx,m_lastSentTs,this);
setTimestamp(m_lastSentTs);
bool b = m_engine->writeSocket(m_data,m_dataAddIdx,m_addr);
// Reset index & timestamp
m_dataAddIdx = IAX2_METATRUNK_HEADERLENGTH;
m_timestamp = 0;
m_dataAddIdx = IAX2_TRUNKFRAME_HEADERLENGTH;
return b;
}

View File

@ -94,8 +94,15 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
m_adjustTsOutThreshold(0),
m_adjustTsOutOverrun(0),
m_adjustTsOutUnderrun(0),
m_lastVoiceFrameIn(0),
m_lastVoiceFrameInTs(0),
m_reqVoiceVNAK(0),
m_trunkFrame(0),
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
m_trunkInSyncUsingTs(true),
m_trunkInStartTime(0),
m_trunkInTsDelta(0),
m_trunkInTsDiffRestart(5000),
m_trunkInFirstTs(0)
{
// Setup transaction
m_retransCount = engine->retransCount();
@ -123,6 +130,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
localCallNo(),remoteCallNo(),typeName(),m_addr.host().c_str(),m_addr.port(),this);
engine->getOutDataAdjust(m_adjustTsOutThreshold,m_adjustTsOutOverrun,
m_adjustTsOutUnderrun);
engine->initTrunkIn(this);
// Append frame to incoming list
Lock lock(this);
m_inFrames.append(frame);
@ -163,8 +171,15 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
m_adjustTsOutThreshold(0),
m_adjustTsOutOverrun(0),
m_adjustTsOutUnderrun(0),
m_lastVoiceFrameIn(0),
m_lastVoiceFrameInTs(0),
m_reqVoiceVNAK(0),
m_trunkFrame(0),
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
m_trunkInSyncUsingTs(true),
m_trunkInStartTime(0),
m_trunkInTsDelta(0),
m_trunkInTsDiffRestart(5000),
m_trunkInFirstTs(0)
{
Debug(m_engine,DebugAll,"Transaction(%u,%u) outgoing type=%s remote=%s:%d [%p]",
localCallNo(),remoteCallNo(),typeName(),m_addr.host().c_str(),m_addr.port(),this);
@ -224,6 +239,7 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
}
engine->getOutDataAdjust(m_adjustTsOutThreshold,m_adjustTsOutOverrun,
m_adjustTsOutUnderrun);
engine->initTrunkIn(this);
postFrameIes(IAXFrame::IAX,frametype,ies);
changeState(NewLocalInvite);
}
@ -312,8 +328,12 @@ IAXTransaction* IAXTransaction::processFrame(IAXFrame* frame)
t = IAXFormat::Video;
if (!processMediaFrame(full,t))
return 0;
// Frame accepted: process voice data
lock.drop();
if (t == IAXFormat::Audio) {
Lock lck(m_dataAudio.m_inMutex);
m_lastVoiceFrameIn = Time::now();
m_lastVoiceFrameInTs = frame->timeStamp();
}
return processMedia(frame->data(),frame->timeStamp(),t,true,frame->mark());
}
// Process incoming Ping
@ -347,6 +367,10 @@ IAXTransaction* IAXTransaction::processMedia(DataBlock& data, u_int32_t tStamp,
return 0;
}
Lock lck(d->m_inMutex);
if (type == IAXFormat::Audio && !m_lastVoiceFrameIn) {
receivedVoiceMiniBeforeFull();
return 0;
}
const IAXFormatDesc& desc = fmt->formatDesc(true);
if (!desc.format()) {
if (d->m_showInNoFmt) {
@ -543,7 +567,7 @@ unsigned int IAXTransaction::sendMedia(const DataBlock& data, unsigned int tStam
if (fullFrame) {
// Send trunked frame before full frame to keep the media order
if (m_trunkFrame)
m_engine->sendTrunkFrame(m_trunkFrame);
m_trunkFrame->send();
postFrame(IAXFrame::Voice,fmt->out(),data.data(),data.length(),ts,true);
sent = data.length();
}
@ -908,10 +932,13 @@ bool IAXTransaction::abortReg()
bool IAXTransaction::enableTrunking(IAXMetaTrunkFrame* trunkFrame)
{
if (!trunkFrame)
return false;
Lock lck(m_dataAudio.m_outMutex);
if (m_trunkFrame)
return false;
// Get a reference to the trunk frame
if (!(trunkFrame && trunkFrame->ref()))
if (!trunkFrame->ref())
return false;
m_trunkFrame = trunkFrame;
return true;
@ -952,45 +979,49 @@ void IAXTransaction::processCallToken(const DataBlock& callToken)
sendFrame(frame);
}
// Update transaction incoming trunk data (used for trunk without timestamps)
bool IAXTransaction::updateTrunkRecvTs(u_int32_t& frameTs, u_int32_t ts, u_int64_t currentTimeMs)
// Process incoming audio miniframes from trunk without timestamps
void IAXTransaction::processMiniNoTs(u_int32_t ts, ObjList& blocks, const Time& now)
{
Lock lck(this);
if (m_trunkInLastTs) {
bool ok = (ts > m_trunkInLastTs);
if (!ok) {
// Allow frames older then 5 seconds to restart trunk
if ((m_trunkInLastTs - ts) >= 5000) {
ok = true;
m_trunkInOffsetTimeMs = 0;
}
else
ok = (m_trunkInOffsetTimeMs == 0);
}
if (!ok) {
if (m_warnTrunkInTimestamp) {
Debug(m_engine,DebugNote,
"Transaction(%u,%u) ignoring trunked mini-frame without timestamps from %s:%d with ts=%u last=%u [%p]",
localCallNo(),remoteCallNo(),remoteAddr().host().c_str(),remoteAddr().port(),
ts,m_trunkInLastTs,this);
m_warnTrunkInTimestamp = false;
}
return false;
}
m_warnTrunkInTimestamp = true;
Lock lck(m_dataAudio.m_inMutex);
if (!m_lastVoiceFrameIn) {
receivedVoiceMiniBeforeFull();
return;
}
m_trunkInLastTs = ts;
if (!m_trunkInOffsetTimeMs) {
if (!currentTimeMs)
currentTimeMs = Time::msecNow();
u_int64_t trunkStart = currentTimeMs - ts;
m_trunkInOffsetTimeMs = (int64_t)m_timeStamp - trunkStart;
u_int32_t tStamp = 0;
if (m_trunkInSyncUsingTs) {
if (m_trunkInStartTime) {
if (ts < m_trunkInFirstTs) {
// Restart?
if ((m_trunkInFirstTs - ts) > m_trunkInTsDiffRestart)
restartTrunkIn(now,ts);
else {
// Drop
for (ObjList* o = blocks.skipNull(); o; o = o->skipNext()) {
DataBlock* db = static_cast<DataBlock*>(o->get());
if (db->length()) {
m_dataAudio.m_ooPackets++;
m_dataAudio.m_ooBytes += db->length();
}
}
return;
}
}
}
else
restartTrunkIn(now,ts);
tStamp = m_trunkInTsDelta + (ts - m_trunkInFirstTs);
}
if (m_trunkInOffsetTimeMs >= 0)
frameTs = ts - (u_int32_t)m_trunkInOffsetTimeMs;
else
frameTs = ts + (u_int32_t)(-m_trunkInOffsetTimeMs);
return true;
tStamp = (u_int32_t)((now - m_lastVoiceFrameIn) / 1000) + m_lastVoiceFrameInTs;
XDebug(m_engine,DebugAll,"(%u,%u) processMiniNoTs(sync=%u packets=%u) %u --> %u [%p]",
localCallNo(),remoteCallNo(),m_trunkInSyncUsingTs,blocks.count(),ts,tStamp,this);
lck.drop();
for (ObjList* o = blocks.skipNull(); o; o = o->skipNext()) {
DataBlock* db = static_cast<DataBlock*>(o->get());
// Signal full frame timestamp (we calculate it from full voice frame)
processMedia(*db,tStamp,IAXFormat::Audio,true);
tStamp++;
}
}
void IAXTransaction::print(bool printStats, bool printFrames, const char* location)
@ -1197,8 +1228,11 @@ void IAXTransaction::postFrame(IAXFrame::Type type, u_int32_t subclass, void* da
return;
// Pong and LagRp don't need timestamp to be adjusted
// Don't adjust for video
if ((type != IAXFrame::IAX && type == IAXFrame::Video) ||
(subclass != IAXControl::Pong && subclass != IAXControl::LagRp))
if (type == IAXFrame::IAX) {
if (subclass != IAXControl::Pong && subclass != IAXControl::LagRp)
adjustTStamp(tStamp);
}
else if (type != IAXFrame::Video)
adjustTStamp(tStamp);
IAXFrameOut* frame = new IAXFrameOut(type,subclass,m_lCallNo,m_rCallNo,m_oSeqNo,m_iSeqNo,tStamp,
(unsigned char*)data,len,m_retransCount,m_retransInterval,ackOnly,mark);
@ -1998,4 +2032,17 @@ void IAXTransaction::postFrame(IAXFrameOut* frame)
sendFrame(frame);
}
void IAXTransaction::receivedVoiceMiniBeforeFull()
{
if (m_reqVoiceVNAK > 15)
return;
m_reqVoiceVNAK++;
if (m_reqVoiceVNAK == 3)
Debug(m_engine,DebugAll,
"Transaction(%u,%u) received audio miniframe before full voice frame [%p]",
localCallNo(),remoteCallNo(),this);
if (0 == (m_reqVoiceVNAK % 3))
sendVNAK();
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -47,20 +47,38 @@
*/
namespace TelEngine {
class IAXInfoElement;
class IAXInfoElementString;
class IAXInfoElementNumeric;
class IAXInfoElementBinary;
class IAXFrame;
class IAXFullFrame;
class IAXFrameOut;
class IAXEvent;
class IAXEngine;
class IAXInfoElement; // A single IAX2 Information Element
class IAXInfoElementString; // A single IAX2 text Information Element
class IAXInfoElementNumeric; // A single IAX2 numeric Information Element
class IAXInfoElementBinary; // A single IAX2 numeric Information Element
class IAXIEList; // Information Element container
class IAXAuthMethod; // Wrapper class for authentication methods values
class IAXFormatDesc; // IAX format description
class IAXFormat; // Wrapper class for formats
class IAXControl; // Wrapper class for subclasses of frames of type IAX
class IAXFrame; // This class holds an IAX frame
class IAXFullFrame; // This class holds an IAX full frame
class IAXFrameOut; // This class holds an outgoing IAX full frame
class IAXTrunkInfo; // Trunk info
class IAXMetaTrunkFrame; // Meta trunk frame
class IAXMediaData; // IAX2 transaction media data
class IAXTransaction; // An IAX2 transaction
class IAXEvent; // Event class
class IAXEngine; // IAX engine
#define IAX_PROTOCOL_VERSION 0x0002 // Protocol version
#define IAX2_MAX_CALLNO 32767 // Max call number value
#define IAX2_MAX_TRANSINFRAMELIST 127 // Max transaction incoming frame list
// Trunk frame header length
#define IAX2_TRUNKFRAME_HEADERLENGTH 8
// Trunk frame length
#define IAX2_TRUNKFRAME_LEN_MIN 20 // 16 bytes: meta header + miniframe with timestamps header
#define IAX2_TRUNKFRAME_LEN_DEF 1400
// Trunk frame send interval in milliseconds
#define IAX2_TRUNKFRAME_SEND_MIN 5
#define IAX2_TRUNKFRAME_SEND_DEF 20
/**
* This class holds a single Information Element with no data
* @short A single IAX2 Information Element
@ -265,7 +283,7 @@ private:
* This class holds a single Information Element with 1, 2 or 4 byte(s) length data
* @short A single IAX2 numeric Information Element
*/
class IAXInfoElementNumeric : public IAXInfoElement
class YIAX_API IAXInfoElementNumeric : public IAXInfoElement
{
public:
/**
@ -1384,6 +1402,50 @@ private:
u_int64_t m_nextTransTime; // Next transmission time
};
/**
* This class holds trunk description
* @short Trunk info
*/
class YIAX_API IAXTrunkInfo : public GenObject
{
public:
/**
* Constructor
*/
inline IAXTrunkInfo()
: m_timestamps(true), m_sendInterval(IAX2_TRUNKFRAME_SEND_DEF),
m_maxLen(IAX2_TRUNKFRAME_LEN_DEF), m_trunkInSyncUsingTs(true),
m_trunkInTsDiffRestart(5000)
{}
/**
* Init all data from parameters
* @param params Parameter list
* @param prefix Parameter prefix (used as value for enable parameter also)
* @param def Optional defaults
*/
void init(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def = 0);
/**
* Init trunking from parameters
* @param params Parameter list
* @param prefix Parameter prefix (used as value for enable parameter also)
* @param def Optional defaults
* @param out True to init outgoing trunk data, false to init incoming trunk info
*/
void initTrunking(const NamedList& params, const String& prefix,
const IAXTrunkInfo* def = 0, bool out = true);
bool m_timestamps; // Trunk type: with(out) timestamps
unsigned int m_sendInterval; // Send interval
unsigned int m_maxLen; // Max frame length
bool m_trunkInSyncUsingTs; // Incoming trunk without timestamps: use trunk
// time or trunk timestamp to re-build frame ts
u_int32_t m_trunkInTsDiffRestart; // Incoming trunk without timestamp: diff between
// timestamps at which we restart
};
/**
* Handle meta trunk frame with timestamps
* @short Meta trunk frame
@ -1395,8 +1457,12 @@ public:
* Constructor. Constructs an outgoing meta trunk frame
* @param engine The engine that owns this frame
* @param addr Remote peer address
* @param timestamps True if miniframes have timestamps, false if not
* @param maxLen Maximum frame length
* @param sendInterval Trunk send interval in milliseconds
*/
IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr);
IAXMetaTrunkFrame(IAXEngine* engine, const SocketAddr& addr, bool timestamps,
unsigned int maxLen, unsigned int sendInterval);
/**
* Destructor
@ -1411,17 +1477,25 @@ public:
{ return m_addr; }
/**
* Get the timestamp of this frame
* @return The timestamp of this frame
* Check if the frame is adding mini frames timestamps
* @return True if the frame is adding mini frames timestamps
*/
inline u_int32_t timestamp()
{ return m_timestamp; }
inline bool trunkTimestamps() const
{ return m_trunkTimestamps; }
/**
* Set the timestamp of this frame
* @param tStamp Timestamp value to set
* Retrieve the send interval
* @return Send interval in milliseconds
*/
void setTimestamp(u_int32_t tStamp);
inline unsigned int sendInterval() const
{ return m_sendInterval; }
/**
* Retrieve the frame maximum length
* @return Frame maximum length
*/
inline unsigned int maxLen() const
{ return m_maxLen; }
/**
* Add a mini frame. If no room, send before adding
@ -1433,18 +1507,61 @@ public:
bool add(u_int16_t sCallNo, const DataBlock& data, u_int32_t tStamp);
/**
* Send this frame to remote peer
* @param tStamp Frame timestamp
* Send this frame to remote peer if the time arrived
* @param now Current time
* @return The result of the write operation
*/
bool send(u_int32_t tStamp = Time::msecNow());
inline bool timerTick(const Time& now = Time()) {
if (m_dataAddIdx == IAX2_TRUNKFRAME_HEADERLENGTH || !m_send)
return false;
Lock lck(this);
return (now > m_send) && doSend(now,true);
}
/**
* Send this frame to remote peer if there is any data in buffer
* @return The result of the write operation
*/
inline bool send() {
if (m_dataAddIdx == IAX2_TRUNKFRAME_HEADERLENGTH)
return false;
Lock lck(this);
return m_dataAddIdx != IAX2_TRUNKFRAME_HEADERLENGTH && doSend();
}
private:
IAXMetaTrunkFrame() {} // No default constructor
// Send this frame to remote peer
bool doSend(const Time& now = Time(), bool onTime = false);
// Set timestamp and next time to send
inline void setTimestamp(u_int64_t now) {
m_timeStamp = now;
m_send = now + (u_int64_t)m_sendInterval * 1000;
}
// Set next time to send
inline void setSendTime(u_int64_t now)
{ m_send = now + (u_int64_t)m_sendInterval * 1000; }
// Set the timestamp of this frame
inline void setTimestamp(u_int32_t tStamp) {
m_data[4] = (u_int8_t)(tStamp >> 24);
m_data[5] = (u_int8_t)(tStamp >> 16);
m_data[6] = (u_int8_t)(tStamp >> 8);
m_data[7] = (u_int8_t)tStamp;
}
u_int8_t* m_data; // Data buffer
u_int16_t m_dataAddIdx; // Current add index
u_int32_t m_timestamp; // Frame timestamp
u_int64_t m_timeStamp; // First time data was added
u_int64_t m_send; // Time to send
u_int32_t m_lastSentTs; // Last sent timestamp
unsigned int m_sendInterval;// Send interval in milliseconds
IAXEngine* m_engine; // The engine that owns this frame
SocketAddr m_addr; // Remote peer address
bool m_trunkTimestamps; // Trunk type: with(out) timestamps
unsigned int m_maxLen; // Max frame length
unsigned int m_maxDataLen; // Max frame data length
unsigned char m_miniHdrLen; // Miniframe header length
};
/**
@ -1939,13 +2056,12 @@ public:
void processCallToken(const DataBlock& callToken);
/**
* Update transaction incoming trunk data (used for trunk without timestamps)
* @param frameTs Address of variable to be set with frame timestamp
* Process incoming audio miniframes from trunk without timestamps
* @param ts Trunk frame timestamp
* @param currentTimeMs Current time
* @return True if accepted
* @param blocks Received blocks
* @param now Current time
*/
bool updateTrunkRecvTs(u_int32_t& frameTs, u_int32_t ts, u_int64_t currentTimeMs);
void processMiniNoTs(u_int32_t ts, ObjList& blocks, const Time& now = Time());
/**
* Print transaction data on stdin
@ -2354,6 +2470,13 @@ protected:
private:
void adjustTStamp(u_int32_t& tStamp);
void postFrame(IAXFrameOut* frame);
void receivedVoiceMiniBeforeFull();
inline void restartTrunkIn(u_int64_t now, u_int32_t ts) {
m_trunkInStartTime = now;
u_int64_t dt = (now - m_lastVoiceFrameIn) / 1000;
m_trunkInTsDelta = m_lastVoiceFrameInTs + (u_int32_t)dt;
m_trunkInFirstTs = ts;
}
// Params
bool m_localInitTrans; // True: local initiated transaction
@ -2408,11 +2531,17 @@ private:
// overrun (incoming data with rate greater then expected)
unsigned int m_adjustTsOutUnderrun; // Value used to adjust outgoing data timestamp on data
// underrun (incoming data with rate less then expected)
u_int64_t m_lastVoiceFrameIn; // Time we received the last voice frame
u_int32_t m_lastVoiceFrameInTs; // Timestamp in the last received voice frame
int m_reqVoiceVNAK; // Send VNAK if not received full voice frame
// Meta trunking
IAXMetaTrunkFrame* m_trunkFrame; // Reference to a trunk frame if trunking is enabled for this transaction
int64_t m_trunkInOffsetTimeMs; // Offset between transaction start and trunk start
u_int32_t m_trunkInLastTs; // Last received trunk timestamp
bool m_warnTrunkInTimestamp; // Warn incoming trunk invalid timestamp
bool m_trunkInSyncUsingTs; // Incoming trunk without timestamps: generate timestamp
// using time or using trunk timestamp
u_int64_t m_trunkInStartTime; // First time we received trunk in data
u_int32_t m_trunkInTsDelta; // Value used to re-build ts: last voice timestamp
u_int32_t m_trunkInTsDiffRestart; // Incoming trunk without timestamp: diff between timestamps at which we restart
u_int32_t m_trunkInFirstTs; // Incoming trunk without timestamp: first trunk timestamp
};
/**
@ -2578,14 +2707,12 @@ public:
* @param maxFullFrameDataLen Max full frame IE list (buffer) length
* @param format Default media format
* @param capab Media capabilities of this engine
* @param trunkSendInterval Send trunk meta frame interval
* @param authRequired Automatically challenge all clients for authentication
* @param params Optional extra parameter list
*/
IAXEngine(const char* iface, int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
u_int16_t authTimeout, u_int16_t transTimeout, u_int16_t maxFullFrameDataLen,
u_int32_t format, u_int32_t capab, u_int32_t trunkSendInterval, bool authRequired,
NamedList* params = 0);
u_int32_t format, u_int32_t capab, bool authRequired, NamedList* params = 0);
/**
* Destructor
@ -2825,16 +2952,30 @@ public:
virtual void defaultEventHandler(IAXEvent* event);
/**
* Enable trunking for the given transaction. Allocate a trunk meta frame if needded
* Enable trunking for the given transaction. Allocate a trunk meta frame if needed.
* Trunk data is ignored if a trunk object for transaction remote address already exists
* @param trans Transaction to enable trunking for
* @param params Optional trunk parameters list
* @param prefix Trunk parameters name prefix
*/
void enableTrunking(IAXTransaction* trans);
void enableTrunking(IAXTransaction* trans, const NamedList* params = 0,
const String& prefix = String::empty());
/**
* Remove a trunk meta frame from the queue and deref it
* @param metaFrame The trunk meta frame to remove
* Init incoming trunking data for a given transaction
* @param trans Transaction to init
* @param params Optional trunk parameters list
* @param prefix Trunk parameters name prefix
*/
void removeTrunkFrame(IAXMetaTrunkFrame* metaFrame);
void initTrunkIn(IAXTransaction* trans, const NamedList* params = 0,
const String& prefix = String::empty());
/**
* Retrieve the default trunk info data
* @return Trunk info pointer, 0 if not found
*/
inline IAXTrunkInfo* trunkInfo()
{ return &m_trunkInfoDef; }
/**
* Send an INVAL frame
@ -2843,17 +2984,6 @@ public:
*/
void sendInval(IAXFullFrame* frame, const SocketAddr& addr);
/**
* Send a trunk frame
* @param metaFrame The trunk meta frame to sent
*/
inline void sendTrunkFrame(IAXMetaTrunkFrame* metaFrame) {
if (!metaFrame)
return;
Lock lck(m_mutexTrunk);
metaFrame->send();
}
/**
* Keep calling processTrunkFrames to send trunked media data
*/
@ -2948,7 +3078,7 @@ protected:
* @param time Time of the call
* @return True if at least one frame was sent
*/
bool processTrunkFrames(u_int32_t time = Time::msecNow());
bool processTrunkFrames(const Time& time = Time());
/**
* Default event for connection transactions handler. This method may be overriden to perform custom
@ -2983,10 +3113,10 @@ protected:
* @param type Transaction type
* @param addr Remote address to send the request
* @param ieList First frame IE list
* @param trunking Enable/disable trunking for this transaction
* @return IAXTransaction pointer on success.
*/
IAXTransaction* startLocalTransaction(IAXTransaction::Type type, const SocketAddr& addr, IAXIEList& ieList, bool trunking = false);
IAXTransaction* startLocalTransaction(IAXTransaction::Type type,
const SocketAddr& addr, IAXIEList& ieList);
private:
Socket m_socket; // Socket
@ -3024,7 +3154,7 @@ private:
// Trunking
Mutex m_mutexTrunk; // Mutex for trunk operations
ObjList m_trunkList; // Trunk frames list
u_int32_t m_trunkSendInterval; // Trunk frame send interval
IAXTrunkInfo m_trunkInfoDef; // Defaults for trunk data
};
}

View File

@ -284,17 +284,19 @@ public:
* @param authTimeout Timeout (in seconds) of acknoledged auth frames sent
* @param transTimeout Timeout (in seconds) on remote request of transactions belonging to this engine
* @param maxFullFrameDataLen Max full frame IE list (buffer) length
* @param trunkSendInterval Send trunk meta frame interval
* @param authRequired Automatically challenge all clients for authentication
*/
YIAXEngine(const char* iface, int port, u_int16_t transListCount, u_int16_t retransCount, u_int16_t retransInterval,
u_int16_t authTimeout, u_int16_t transTimeout,
u_int16_t maxFullFrameDataLen, u_int32_t trunkSendInterval, bool authRequired,
u_int16_t maxFullFrameDataLen, bool authRequired,
NamedList* params);
virtual ~YIAXEngine()
{}
// Setup a given transaction from parameters
void initTransaction(IAXTransaction* tr, const NamedList& params);
/*
* Process media from remote peer.
* @param transaction IAXTransaction that owns the call leg
@ -1032,14 +1034,25 @@ void YIAXTrunking::run()
YIAXEngine::YIAXEngine(const char* iface, int port, u_int16_t transListCount,
u_int16_t retransCount, u_int16_t retransInterval, u_int16_t authTimeout,
u_int16_t transTimeout, u_int16_t maxFullFrameDataLen,
u_int32_t trunkSendInterval, bool authRequired, NamedList* params)
bool authRequired, NamedList* params)
: IAXEngine(iface,port,transListCount,retransCount,retransInterval,authTimeout,
transTimeout,maxFullFrameDataLen,0,0,
trunkSendInterval,authRequired,params),
transTimeout,maxFullFrameDataLen,0,0,authRequired,params),
m_threadsCreated(false)
{
}
// Setup a given transaction from parameters
void YIAXEngine::initTransaction(IAXTransaction* tr, const NamedList& params)
{
if (!tr)
return;
String prefix = tr->outgoing() ? "trunkout" : "trunkin";
String pref = prefix + "_";
if (params.getBoolValue(prefix))
enableTrunking(tr,&params,pref);
initTrunkIn(tr,&params,pref);
}
// Handle received voice data, forward it to connection's source
void YIAXEngine::processMedia(IAXTransaction* transaction, DataBlock& data,
u_int32_t tStamp, int type, bool mark)
@ -1439,14 +1452,13 @@ void YIAXDriver::initialize()
u_int16_t authTimeout = 30;
u_int16_t transTimeout = 10;
u_int16_t maxFullFrameDataLen = 1400;
u_int32_t trunkSendInterval = 10;
m_port = gen->getIntValue("port",4569);
String iface = gen->getValue("addr","0.0.0.0");
// set max chans
maxChans(gen->getIntValue("maxchans",maxChans()));
bool authReq = cfg.getBoolValue("registrar","auth_required",true);
m_iaxEngine = new YIAXEngine(iface,m_port,transListCount,retransCount,retransInterval,authTimeout,
transTimeout,maxFullFrameDataLen,trunkSendInterval,authReq,gen);
m_iaxEngine = new YIAXEngine(iface,m_port,transListCount,retransCount,
retransInterval,authTimeout,transTimeout,maxFullFrameDataLen,authReq,gen);
m_iaxEngine->debugChain(this);
m_iaxEngine->initFormats(cfg.getSection("formats"));
int tos = gen->getIntValue("tos",dict_tos,0);
@ -1536,9 +1548,7 @@ bool YIAXDriver::msgExecute(Message& msg, String& dest)
conn->callConnect(msg);
msg.setParam("peerid",conn->id());
msg.setParam("targetid",conn->id());
// Enable trunking if trunkout parameter is enabled
if (msg.getBoolValue("trunkout"))
m_iaxEngine->enableTrunking(tr);
(static_cast<YIAXEngine*>(tr->getEngine()))->initTransaction(tr,msg);
}
else
tr->setUserData(0);
@ -1806,10 +1816,8 @@ void YIAXConnection::callAccept(Message& msg)
u_int32_t ci = IAXFormat::mask(codecs,IAXFormat::Image);
iplugin.updateCodecsFromRoute(ci,msg,IAXFormat::Image);
iplugin.getEngine()->acceptFormatAndCapability(m_transaction,&ci,IAXFormat::Image);
(static_cast<YIAXEngine*>(m_transaction->getEngine()))->initTransaction(m_transaction,msg);
m_transaction->sendAccept();
// Enable trunking if trunkin parameter is enabled
if (msg.getBoolValue("trunkin"))
m_iaxEngine->enableTrunking(m_transaction);
}
m_mutexTrans.unlock();
Channel::callAccept(msg);