Properly handle trunk frames without miniframe timestamps.
git-svn-id: http://yate.null.ro/svn/yate/trunk@5344 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
parent
8137d40d31
commit
fd88ed1260
|
@ -268,6 +268,19 @@ IAXTransaction* IAXEngine::addFrame(const SocketAddr& addr, const unsigned char*
|
|||
return tr;
|
||||
}
|
||||
|
||||
// Find a complete transaction
|
||||
IAXTransaction* IAXEngine::findTransaction(const SocketAddr& addr, u_int16_t rCallNo)
|
||||
{
|
||||
Lock lck(this);
|
||||
ObjList* o = m_transList[rCallNo % m_transListCount]->skipNull();
|
||||
for (; o; o = o->skipNext()) {
|
||||
IAXTransaction* tr = static_cast<IAXTransaction*>(o->get());
|
||||
if (tr->remoteCallNo() == rCallNo && addr == tr->remoteAddr())
|
||||
return tr->ref() ? tr : 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void IAXEngine::sendInval(IAXFullFrame* frame, const SocketAddr& addr)
|
||||
{
|
||||
if (!frame)
|
||||
|
|
|
@ -46,6 +46,32 @@ inline void setStringFromInteger(String& dest, u_int32_t value, u_int8_t length)
|
|||
dest = tmp;
|
||||
}
|
||||
|
||||
|
||||
class IAXTrunkFrameTrans : public GenObject
|
||||
{
|
||||
public:
|
||||
inline IAXTrunkFrameTrans(IAXTransaction* tr, u_int32_t frameTs)
|
||||
: m_tr(tr), m_frameTs(frameTs), m_trunkIndex(0)
|
||||
{}
|
||||
~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;
|
||||
};
|
||||
|
||||
IAXTrunkFrameTrans* IAXTrunkFrameTrans::find(ObjList& list, u_int16_t rCallNo)
|
||||
{
|
||||
for (ObjList* o = list.skipNull(); o; o = o->skipNext()) {
|
||||
IAXTrunkFrameTrans* t = static_cast<IAXTrunkFrameTrans*>(o->get());
|
||||
if (t->m_tr->remoteCallNo() == rCallNo)
|
||||
return t;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* IAXInfoElement
|
||||
*/
|
||||
|
@ -824,11 +850,10 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
|
|||
if (buf[2] != 1)
|
||||
return 0;
|
||||
bool tstamps = (buf[3] & 1) != 0;
|
||||
// u_int32_t ts = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
|
||||
buf += 8;
|
||||
len -= 8;
|
||||
if (tstamps) {
|
||||
// Trunk timestamps (mini frames)
|
||||
buf += 8;
|
||||
len -= 8;
|
||||
while (len >= 6) {
|
||||
u_int16_t dlen = (buf[0] << 8) | buf[1];
|
||||
if ((unsigned int)(dlen + 6) > len)
|
||||
|
@ -850,6 +875,11 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
|
|||
}
|
||||
else {
|
||||
// No trunk timestamps
|
||||
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();
|
||||
ObjList list;
|
||||
while (len >= 4) {
|
||||
u_int16_t dlen = (buf[2] << 8) | buf[3];
|
||||
if ((unsigned int)(dlen + 4) > len)
|
||||
|
@ -860,9 +890,27 @@ IAXFrame* IAXFrame::parse(const unsigned char* buf, unsigned int len, IAXEngine*
|
|||
retrans = true;
|
||||
scn &= 0x7fff;
|
||||
}
|
||||
IAXFrame* frame = new IAXFrame(IAXFrame::Voice,scn,0,retrans,buf+4,dlen);
|
||||
engine->addFrame(*addr,frame);
|
||||
frame->deref();
|
||||
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();
|
||||
}
|
||||
dlen += 4;
|
||||
buf += dlen;
|
||||
len -= dlen;
|
||||
|
|
|
@ -76,7 +76,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, IAXFullFrame* frame, u_int16_t
|
|||
m_expire(60),
|
||||
m_format(IAXFormat::Audio), m_formatVideo(IAXFormat::Video),
|
||||
m_capability(0), m_callToken(false),
|
||||
m_trunkFrame(0)
|
||||
m_trunkFrame(0),
|
||||
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
|
||||
{
|
||||
Debug(m_engine,DebugAll,"Transaction(%u,%u) incoming type=%u remote=%s:%d [%p]",
|
||||
localCallNo(),remoteCallNo(),m_type,m_addr.host().c_str(),m_addr.port(),this);
|
||||
|
@ -139,7 +140,8 @@ IAXTransaction::IAXTransaction(IAXEngine* engine, Type type, u_int16_t lcallno,
|
|||
m_expire(60),
|
||||
m_format(IAXFormat::Audio), m_formatVideo(IAXFormat::Video),
|
||||
m_capability(0), m_callToken(false),
|
||||
m_trunkFrame(0)
|
||||
m_trunkFrame(0),
|
||||
m_trunkInOffsetTimeMs(0), m_trunkInLastTs(0), m_warnTrunkInTimestamp(true)
|
||||
{
|
||||
Debug(m_engine,DebugAll,"Transaction(%u,%u) outgoing type=%u remote=%s:%d [%p]",
|
||||
localCallNo(),remoteCallNo(),m_type,m_addr.host().c_str(),m_addr.port(),this);
|
||||
|
@ -838,6 +840,47 @@ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
m_trunkInLastTs = ts;
|
||||
if (!m_trunkInOffsetTimeMs) {
|
||||
if (!currentTimeMs)
|
||||
currentTimeMs = Time::msecNow();
|
||||
u_int64_t trunkStart = currentTimeMs - ts;
|
||||
m_trunkInOffsetTimeMs = (int64_t)m_timeStamp - trunkStart;
|
||||
}
|
||||
if (m_trunkInOffsetTimeMs >= 0)
|
||||
frameTs = ts - (u_int32_t)m_trunkInOffsetTimeMs;
|
||||
else
|
||||
frameTs = ts + (u_int32_t)(-m_trunkInOffsetTimeMs);
|
||||
return true;
|
||||
}
|
||||
|
||||
void IAXTransaction::print(bool printStats, bool printFrames, const char* location)
|
||||
{
|
||||
if (m_engine && !m_engine->debugAt(DebugAll))
|
||||
|
|
|
@ -1791,6 +1791,15 @@ 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
|
||||
* @param ts Trunk frame timestamp
|
||||
* @param currentTimeMs Current time
|
||||
* @return True if accepted
|
||||
*/
|
||||
bool updateTrunkRecvTs(u_int32_t& frameTs, u_int32_t ts, u_int64_t currentTimeMs);
|
||||
|
||||
/**
|
||||
* Print transaction data on stdin
|
||||
* @param printStats True to print media statistics
|
||||
|
@ -2236,6 +2245,9 @@ private:
|
|||
bool m_callToken; // Call token supported/expected
|
||||
// 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
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -2433,6 +2445,15 @@ public:
|
|||
*/
|
||||
IAXTransaction* addFrame(const SocketAddr& addr, const unsigned char* buf, unsigned int len);
|
||||
|
||||
/**
|
||||
* Find a complete transaction.
|
||||
* This method is thread safe
|
||||
* @param addr Remote address
|
||||
* @param rCallNo Remote transaction call number
|
||||
* @return Referrenced pointer to the transaction or 0
|
||||
*/
|
||||
IAXTransaction* findTransaction(const SocketAddr& addr, u_int16_t rCallNo);
|
||||
|
||||
/**
|
||||
* Process media from remote peer. Descendents must override this method
|
||||
* @param transaction IAXTransaction that owns the call leg
|
||||
|
|
Loading…
Reference in New Issue