2005-05-02 18:31:05 +00:00
|
|
|
/**
|
|
|
|
* session.cpp
|
|
|
|
* Yet Another RTP Stack
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
2014-02-05 11:42:17 +00:00
|
|
|
* Copyright (C) 2004-2014 Null Team
|
2005-05-02 18:31:05 +00:00
|
|
|
*
|
2013-08-06 13:38:10 +00:00
|
|
|
* This software is distributed under multiple licenses;
|
|
|
|
* see the COPYING file in the main directory for licensing
|
|
|
|
* information for this specific distribution.
|
|
|
|
*
|
|
|
|
* This use of this software may be subject to additional restrictions.
|
|
|
|
* See the LEGAL file in the main directory for details.
|
2005-05-02 18:31:05 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2013-08-06 13:38:10 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
2005-05-02 18:31:05 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <yatertp.h>
|
|
|
|
|
2005-05-03 20:16:07 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
using namespace TelEngine;
|
|
|
|
|
2009-05-05 21:22:58 +00:00
|
|
|
// u_int64_t Infinity
|
2008-04-10 18:58:11 +00:00
|
|
|
#define INF_TIMEOUT ((u_int64_t)(int64_t)-1)
|
|
|
|
|
2009-05-05 21:22:58 +00:00
|
|
|
// How many lost packets mean we lost sequence sync
|
|
|
|
#define SEQ_DESYNC_COUNT 50
|
|
|
|
// How many packets in a row will resync sequence
|
|
|
|
#define SEQ_RESYNC_COUNT 5
|
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
RTPDebug::RTPDebug(RTPSession* session)
|
|
|
|
: m_dbg(0)
|
|
|
|
{
|
|
|
|
if (session)
|
|
|
|
setDebug(session->dbg(),session->dbgTraceId());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
RTPBaseIO::~RTPBaseIO()
|
|
|
|
{
|
|
|
|
security(0);
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPBaseIO::dataPayload(int type)
|
|
|
|
{
|
|
|
|
if ((type >= -1) && (type <= 127)) {
|
|
|
|
m_dataType = type;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPBaseIO::eventPayload(int type)
|
|
|
|
{
|
|
|
|
if ((type >= -1) && (type <= 127)) {
|
|
|
|
m_eventType = type;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-10 20:26:01 +00:00
|
|
|
bool RTPBaseIO::silencePayload(int type)
|
2005-05-06 18:13:33 +00:00
|
|
|
{
|
|
|
|
if ((type >= -1) && (type <= 127)) {
|
2005-05-10 20:26:01 +00:00
|
|
|
m_silenceType = type;
|
2005-05-06 18:13:33 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-04-10 16:35:20 +00:00
|
|
|
unsigned int RTPBaseIO::ssrcInit()
|
|
|
|
{
|
|
|
|
if (m_ssrcInit) {
|
|
|
|
m_ssrcInit = false;
|
2008-04-10 18:29:58 +00:00
|
|
|
do {
|
2011-06-29 11:19:02 +00:00
|
|
|
m_ssrc = Random::random();
|
2008-04-10 18:29:58 +00:00
|
|
|
} while (0 == m_ssrc);
|
2008-04-10 16:35:20 +00:00
|
|
|
}
|
|
|
|
return m_ssrc;
|
|
|
|
}
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
void RTPBaseIO::security(RTPSecure* secure)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPBaseIO::security(%p) old=%p [%p]",secure,m_secure,this);
|
2008-11-26 17:50:43 +00:00
|
|
|
if (secure == m_secure)
|
|
|
|
return;
|
|
|
|
RTPSecure* tmp = m_secure;
|
|
|
|
m_secure = 0;
|
|
|
|
if (secure) {
|
|
|
|
secure->owner(this);
|
|
|
|
m_secure = secure;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
secLength(0,0);
|
|
|
|
TelEngine::destruct(tmp);
|
|
|
|
}
|
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
void RTPBaseIO::initDebugData(bool recv, const NamedList& params)
|
|
|
|
{
|
|
|
|
const String* p = params.getParam(YSTRING("debug_rtp"));
|
|
|
|
if (!p)
|
|
|
|
return;
|
|
|
|
bool on = p->toBoolean();
|
|
|
|
String suff(recv ? "_recv" : "_send");
|
|
|
|
m_debugData = params.getBoolValue("debug_rtp_data" + suff,
|
|
|
|
params.getBoolValue(YSTRING("debug_rtp_data"),on));
|
|
|
|
m_debugEvent = params.getBoolValue("debug_rtp_event" + suff,
|
|
|
|
params.getBoolValue(YSTRING("debug_rtp_event"),on));
|
|
|
|
m_debugDataLevel = params.getIntValue(YSTRING("debug_rtp_level"),DebugAll);
|
|
|
|
if (m_debugDataLevel <= DebugFail)
|
|
|
|
m_debugDataLevel = 1 + DebugFail;
|
|
|
|
}
|
|
|
|
|
2006-05-27 15:18:34 +00:00
|
|
|
|
|
|
|
RTPReceiver::~RTPReceiver()
|
|
|
|
{
|
|
|
|
setDejitter(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPReceiver::setDejitter(RTPDejitter* dejitter)
|
|
|
|
{
|
|
|
|
if (dejitter == m_dejitter)
|
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTP setting new dejitter %p [%p]",dejitter,this);
|
2006-05-27 15:18:34 +00:00
|
|
|
RTPDejitter* tmp = m_dejitter;
|
|
|
|
m_dejitter = 0;
|
|
|
|
if (tmp) {
|
|
|
|
tmp->group(0);
|
|
|
|
tmp->destruct();
|
|
|
|
}
|
|
|
|
// make the dejitter buffer belong to the same group as the session
|
|
|
|
if (dejitter && m_session)
|
|
|
|
dejitter->group(m_session->group());
|
|
|
|
m_dejitter = dejitter;
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
void RTPReceiver::rtpData(const void* data, int len)
|
|
|
|
{
|
|
|
|
// trivial check for basic fields validity
|
2008-11-26 17:50:43 +00:00
|
|
|
if ((len < m_secLen + 12) || !data)
|
2005-05-06 18:13:33 +00:00
|
|
|
return;
|
|
|
|
const unsigned char* pc = (const unsigned char*)data;
|
|
|
|
// check protocol version number
|
|
|
|
if ((pc[0] & 0xc0) != 0x80)
|
|
|
|
return;
|
2008-11-26 17:50:43 +00:00
|
|
|
const unsigned char* secPtr = 0;
|
|
|
|
if (m_secLen) {
|
|
|
|
// security info is placed after data and padding
|
|
|
|
len -= m_secLen;
|
|
|
|
secPtr = pc + len;
|
|
|
|
}
|
|
|
|
// check if padding is present and remove it (but remember length)
|
|
|
|
unsigned char padding = 0;
|
2005-05-06 18:13:33 +00:00
|
|
|
if (pc[0] & 0x20) {
|
2008-11-26 17:50:43 +00:00
|
|
|
len -= (padding = pc[len-1]);
|
2005-05-06 18:13:33 +00:00
|
|
|
if (len < 12)
|
|
|
|
return;
|
|
|
|
}
|
2008-11-26 17:50:43 +00:00
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool ext = (pc[0] & 0x10) != 0;
|
|
|
|
int cc = pc[0] & 0x0f;
|
|
|
|
bool marker = (pc[1] & 0x80) != 0;
|
|
|
|
int typ = pc[1] & 0x7f;
|
|
|
|
u_int16_t seq = ((u_int16_t)pc[2] << 8) | pc[3];
|
|
|
|
u_int32_t ts = ((u_int32_t)pc[4] << 24) | ((u_int32_t)pc[5] << 16) |
|
|
|
|
((u_int32_t)pc[6] << 8) | pc[7];
|
|
|
|
u_int32_t ss = ((u_int32_t)pc[8] << 24) | ((u_int32_t)pc[9] << 16) |
|
|
|
|
((u_int32_t)pc[10] << 8) | pc[11];
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
// skip over header and any CSRC
|
|
|
|
pc += 12+(4*cc);
|
|
|
|
len -= 12+(4*cc);
|
|
|
|
// check if extension is present and skip it
|
|
|
|
if (ext) {
|
|
|
|
if (len < 4)
|
|
|
|
return;
|
|
|
|
int xl = ((int)pc[2] << 8) | pc[3];
|
|
|
|
pc += xl+4;
|
|
|
|
len -= xl+4;
|
|
|
|
}
|
|
|
|
if (len < 0)
|
|
|
|
return;
|
2012-03-13 09:43:47 +00:00
|
|
|
if (!len)
|
|
|
|
pc = 0;
|
2008-11-26 17:50:43 +00:00
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
// grab some data at the first packet received or resync
|
2006-09-13 22:31:01 +00:00
|
|
|
if (m_ssrcInit) {
|
|
|
|
m_ssrcInit = false;
|
2005-05-07 23:47:37 +00:00
|
|
|
m_ssrc = ss;
|
2006-05-27 15:18:34 +00:00
|
|
|
m_ts = ts - m_tsLast;
|
|
|
|
m_seq = seq-1;
|
2009-05-05 21:22:58 +00:00
|
|
|
m_seqCount = 0;
|
2005-07-13 23:45:26 +00:00
|
|
|
m_warn = true;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,"RTP recv INIT SEQ=%u TS=%u TS_LAST=%u [%p]",
|
|
|
|
seq,ts,m_tsLast,this);
|
2012-03-13 09:43:47 +00:00
|
|
|
if (m_dejitter)
|
|
|
|
m_dejitter->clear();
|
2005-05-06 18:13:33 +00:00
|
|
|
}
|
|
|
|
|
2005-06-17 18:09:07 +00:00
|
|
|
if (ss != m_ssrc) {
|
2008-02-18 14:40:36 +00:00
|
|
|
rtpNewSSRC(ss,marker);
|
|
|
|
// check if the SSRC is still unchanged
|
|
|
|
if (ss != m_ssrc) {
|
|
|
|
if (m_warn) {
|
|
|
|
m_warn = false;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"RTP Received SSRC %08X but expecting %08X [%p]",
|
2008-02-18 14:40:36 +00:00
|
|
|
ss,m_ssrc,this);
|
|
|
|
}
|
2010-11-03 16:27:30 +00:00
|
|
|
m_wrongSSRC++;
|
2008-02-18 14:40:36 +00:00
|
|
|
return;
|
2005-06-17 18:09:07 +00:00
|
|
|
}
|
2008-11-26 17:50:43 +00:00
|
|
|
// SSRC accepted, sync sequence and resync the timestamp offset
|
2008-02-18 14:40:36 +00:00
|
|
|
m_seq = seq;
|
|
|
|
m_ts = ts - m_tsLast;
|
2009-05-05 21:22:58 +00:00
|
|
|
m_seqCount = 0;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv SEQ=%u TS=%u TS_LAST=%u new SSRC accepted, dropping [%p]",
|
|
|
|
seq,ts,m_tsLast,this);
|
2012-03-13 09:43:47 +00:00
|
|
|
if (m_dejitter)
|
|
|
|
m_dejitter->clear();
|
2008-11-26 17:50:43 +00:00
|
|
|
// drop this packet, next packet will come in correctly
|
|
|
|
return;
|
2005-06-17 18:09:07 +00:00
|
|
|
}
|
2005-05-06 18:13:33 +00:00
|
|
|
|
2012-03-13 09:43:47 +00:00
|
|
|
u_int32_t rollover = m_rollover;
|
|
|
|
// compare unsigned to detect rollovers
|
|
|
|
if (seq < m_seq)
|
|
|
|
rollover++;
|
|
|
|
u_int64_t seq48 = rollover;
|
|
|
|
seq48 = (seq48 << 16) | seq;
|
|
|
|
|
|
|
|
// if some security data is present authenticate the packet now
|
2020-07-21 07:39:54 +00:00
|
|
|
if (secPtr && !rtpCheckIntegrity((const unsigned char*)data,len + padding + 12,secPtr + m_mkiLen,ss,seq48)) {
|
|
|
|
if (m_debugData)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv SEQ=%u TS=%u TS_LAST=%u integrity check failed, dropping [%p]",
|
|
|
|
seq,ts,m_tsLast,this);
|
2012-03-13 09:43:47 +00:00
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
}
|
2012-03-13 09:43:47 +00:00
|
|
|
|
|
|
|
// substraction with overflow to compute sequence difference
|
2006-05-27 15:18:34 +00:00
|
|
|
int16_t ds = seq - m_seq;
|
2010-11-03 16:27:30 +00:00
|
|
|
if (ds != 1)
|
|
|
|
m_seqLost++;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (ds == 0) {
|
|
|
|
if (m_debugData)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv SEQ=%u TS=%u TS_LAST=%u same as our last seq, dropping [%p]",
|
|
|
|
seq,ts,m_tsLast,this);
|
2012-03-13 09:43:47 +00:00
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
}
|
2012-03-13 09:43:47 +00:00
|
|
|
|
|
|
|
// check if we received a packet too much out of sequence
|
2009-05-05 21:22:58 +00:00
|
|
|
// be much more tolerant when authenticating as we cannot resync
|
2012-03-13 09:43:47 +00:00
|
|
|
if ((ds <= -SEQ_DESYNC_COUNT) || ((ds > SEQ_DESYNC_COUNT) && !secPtr)) {
|
2010-03-03 18:52:40 +00:00
|
|
|
m_ioLostPkt++;
|
2012-03-13 09:43:47 +00:00
|
|
|
if (!secPtr) {
|
2009-05-05 21:22:58 +00:00
|
|
|
// try to resync sequence unless we need to authenticate
|
|
|
|
if (m_seqCount++) {
|
|
|
|
if (seq == ++m_seqSync) {
|
|
|
|
// good - packets numbers still in sequence
|
|
|
|
if (m_seqCount >= SEQ_RESYNC_COUNT) {
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv SEQ=%u TS=%u TS_LAST=%u sequence resync from current %u [%p]",
|
|
|
|
seq,ts,m_tsLast,m_seq,this);
|
|
|
|
else
|
|
|
|
TraceDebug(m_traceId,dbg(),DebugNote,"RTP sequence resync: %u -> %u [%p]",m_seq,seq,this);
|
2009-05-05 21:22:58 +00:00
|
|
|
// sync sequence and resync the timestamp offset
|
|
|
|
m_seq = seq;
|
|
|
|
m_ts = ts - m_tsLast;
|
|
|
|
m_seqCount = 0;
|
2013-10-10 14:38:42 +00:00
|
|
|
if (m_warnSeq > 0)
|
|
|
|
m_warn = true;
|
|
|
|
else
|
|
|
|
m_warnSeq = -1;
|
2010-11-03 16:27:30 +00:00
|
|
|
m_syncLost++;
|
2012-03-13 09:43:47 +00:00
|
|
|
if (m_dejitter)
|
|
|
|
m_dejitter->clear();
|
2009-05-05 21:22:58 +00:00
|
|
|
// drop this packet, next packet will come in correctly
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_seqCount = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_seqSync = seq;
|
|
|
|
}
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData)
|
|
|
|
m_warnSeq = -1;
|
2013-10-10 14:38:42 +00:00
|
|
|
if (m_warnSeq > 0) {
|
|
|
|
if (m_warn) {
|
|
|
|
m_warn = false;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"RTP received SEQ %u while current is %u [%p]",seq,m_seq,this);
|
2013-10-10 14:38:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_warnSeq < 0) {
|
|
|
|
m_warnSeq = 0;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugInfo,"RTP received SEQ %u while current is %u [%p]",seq,m_seq,this);
|
2009-05-05 21:22:58 +00:00
|
|
|
}
|
2006-05-27 15:18:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2008-11-26 17:50:43 +00:00
|
|
|
|
2012-03-13 09:43:47 +00:00
|
|
|
if (!rtpDecipher(const_cast<unsigned char*>(pc),len + padding,secPtr,ss,seq48))
|
2008-11-26 17:50:43 +00:00
|
|
|
return;
|
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData) {
|
|
|
|
const char* extra = "";
|
|
|
|
if (m_dejitter)
|
|
|
|
extra = " [DEJITTER]";
|
|
|
|
else if (ds < 1)
|
|
|
|
extra = ", dropping";
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv payload=%d SEQ=%u (delta=%d) TS=%u TS_LAST %u -> %u%s [%p]",
|
|
|
|
typ,seq,ds,ts,m_tsLast,(ts - m_ts),extra,this);
|
|
|
|
}
|
2006-05-27 15:18:34 +00:00
|
|
|
m_tsLast = ts - m_ts;
|
2009-05-05 21:22:58 +00:00
|
|
|
m_seqCount = 0;
|
2010-03-03 18:52:40 +00:00
|
|
|
m_ioPackets++;
|
|
|
|
m_ioOctets += len;
|
2012-03-13 09:43:47 +00:00
|
|
|
// keep track of the last valid sequence number and timestamp we have seen
|
|
|
|
m_seq = seq;
|
|
|
|
m_rollover = rollover;
|
2006-05-27 15:18:34 +00:00
|
|
|
|
2012-03-13 09:43:47 +00:00
|
|
|
if (m_dejitter) {
|
|
|
|
if (!m_dejitter->rtpRecv(marker,typ,m_tsLast,pc,len))
|
|
|
|
m_ioLostPkt++;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (ds > 1)
|
|
|
|
m_ioLostPkt += (ds - 1);
|
|
|
|
if (ds >= 1)
|
2008-11-26 17:50:43 +00:00
|
|
|
rtpRecv(marker,typ,m_tsLast,pc,len);
|
2005-05-02 18:31:05 +00:00
|
|
|
}
|
|
|
|
|
2005-05-09 22:55:47 +00:00
|
|
|
void RTPReceiver::rtcpData(const void* data, int len)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPReceiver::rtpRecv(bool marker, int payload, unsigned int timestamp, const void* data, int len)
|
2005-05-03 20:16:07 +00:00
|
|
|
{
|
2005-05-10 20:26:01 +00:00
|
|
|
if ((payload != dataPayload()) && (payload != eventPayload()) && (payload != silencePayload()))
|
2005-05-04 22:52:53 +00:00
|
|
|
rtpNewPayload(payload,timestamp);
|
2005-05-06 18:13:33 +00:00
|
|
|
if (payload == eventPayload())
|
2005-05-04 22:52:53 +00:00
|
|
|
return decodeEvent(marker,timestamp,data,len);
|
2005-05-10 20:26:01 +00:00
|
|
|
if (payload == silencePayload())
|
|
|
|
return decodeSilence(marker,timestamp,data,len);
|
2005-05-04 22:52:53 +00:00
|
|
|
finishEvent(timestamp);
|
2012-03-13 09:43:47 +00:00
|
|
|
if (payload == dataPayload())
|
|
|
|
return rtpRecvData(marker,timestamp,data,len);
|
2005-05-03 20:16:07 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPReceiver::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-05-10 20:26:01 +00:00
|
|
|
return m_session && m_session->rtpRecvData(marker,timestamp,data,len);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPReceiver::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-05-10 20:26:01 +00:00
|
|
|
return m_session && m_session->rtpRecvEvent(event,key,duration,volume,timestamp);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
void RTPReceiver::rtpNewPayload(int payload, unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-05-10 20:26:01 +00:00
|
|
|
if (m_session)
|
|
|
|
m_session->rtpNewPayload(payload,timestamp);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2008-02-18 14:40:36 +00:00
|
|
|
void RTPReceiver::rtpNewSSRC(u_int32_t newSsrc, bool marker)
|
2005-07-13 23:45:26 +00:00
|
|
|
{
|
|
|
|
if (m_session)
|
2008-02-18 14:40:36 +00:00
|
|
|
m_session->rtpNewSSRC(newSsrc,marker);
|
2005-07-13 23:45:26 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPReceiver::decodeEvent(bool marker, unsigned int timestamp, const void* data, int len)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
|
|
|
// we support only basic RFC2833, no RFC2198 redundancy
|
2009-02-05 22:43:07 +00:00
|
|
|
if (len < 4)
|
2005-05-04 22:52:53 +00:00
|
|
|
return false;
|
|
|
|
const unsigned char* pc = (const unsigned char*)data;
|
2009-02-05 22:43:07 +00:00
|
|
|
for (; len >= 4; len-=4, pc+=4) {
|
|
|
|
int event = pc[0];
|
|
|
|
int vol = pc[1] & 0x3f;
|
|
|
|
bool end = (pc[1] & 0x80) != 0;
|
|
|
|
int duration = ((int)pc[2] << 8) | pc[3];
|
|
|
|
if (m_evTs && (m_evNum >= 0)) {
|
2020-07-21 07:39:54 +00:00
|
|
|
if ((m_evNum != event) && (m_evTs <= timestamp)) {
|
|
|
|
if (m_debugEvent)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv ending current event (event/ts changed) event=%d (received=%d) "
|
|
|
|
"ts=%u event_ts=%u duration=%u [%p]",
|
|
|
|
m_evNum,event,timestamp,m_evTs,timestamp - m_evTs,this);
|
2009-02-05 22:43:07 +00:00
|
|
|
pushEvent(m_evNum,timestamp - m_evTs,m_evVol,m_evTs);
|
2020-07-21 07:39:54 +00:00
|
|
|
}
|
2009-02-05 22:43:07 +00:00
|
|
|
}
|
|
|
|
m_evVol = vol;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugEvent) {
|
|
|
|
const char* oper = "start";
|
|
|
|
if (end)
|
|
|
|
oper = "end";
|
|
|
|
else if (m_evNum >= 0)
|
|
|
|
oper = "update";
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv event oper=%s event=%d (old=%d) ts=%u event_ts=%u duration=%u [%p]",
|
|
|
|
oper,event,m_evNum,timestamp,m_evTs,duration,this);
|
|
|
|
}
|
2009-02-05 22:43:07 +00:00
|
|
|
if (!end) {
|
|
|
|
m_evTs = timestamp;
|
|
|
|
m_evNum = event;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (m_evTs > timestamp)
|
|
|
|
return false;
|
|
|
|
// make sure we don't see the same event again
|
|
|
|
m_evTs = timestamp+1;
|
|
|
|
m_evNum = -1;
|
|
|
|
pushEvent(event,duration,vol,timestamp);
|
2005-09-06 02:51:09 +00:00
|
|
|
}
|
|
|
|
return true;
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-10 20:26:01 +00:00
|
|
|
bool RTPReceiver::decodeSilence(bool marker, unsigned int timestamp, const void* data, int len)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-05-10 11:52:48 +00:00
|
|
|
return false;
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
void RTPReceiver::finishEvent(unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-09-06 02:51:09 +00:00
|
|
|
if ((m_evNum < 0) || !m_evTs)
|
2005-05-06 18:13:33 +00:00
|
|
|
return;
|
|
|
|
int duration = timestamp - m_evTs;
|
|
|
|
if (duration < 10000)
|
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugEvent)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP recv finishing event=%d ts=%u event_ts=%u duration=%u [%p]",
|
|
|
|
m_evNum,timestamp,m_evTs,duration,this);
|
2005-05-06 18:13:33 +00:00
|
|
|
timestamp = m_evTs;
|
|
|
|
m_evTs = 0;
|
|
|
|
pushEvent(m_evNum,duration,m_evVol,timestamp);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPReceiver::pushEvent(int event, int duration, int volume, unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
|
|
|
static const char dtmf[] = "0123456789*#ABCDF";
|
|
|
|
char key = (event <= 16) ? dtmf[event] : 0;
|
|
|
|
return rtpRecvEvent(event,key,duration,volume,timestamp);
|
|
|
|
}
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
void RTPReceiver::timerTick(const Time& when)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
bool RTPReceiver::rtpDecipher(unsigned char* data, int len, const void* secData, u_int32_t ssrc, u_int64_t seq)
|
|
|
|
{
|
|
|
|
return (m_secure)
|
|
|
|
? m_secure->rtpDecipher(data,len,secData,ssrc,seq)
|
|
|
|
: true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPReceiver::rtpCheckIntegrity(const unsigned char* data, int len, const void* authData, u_int32_t ssrc, u_int64_t seq)
|
|
|
|
{
|
|
|
|
return (m_secure)
|
|
|
|
? m_secure->rtpCheckIntegrity(data,len,authData,ssrc,seq)
|
|
|
|
: true;
|
|
|
|
}
|
|
|
|
|
2010-11-03 16:27:30 +00:00
|
|
|
void RTPReceiver::stats(NamedList& stat) const
|
|
|
|
{
|
|
|
|
if (m_session)
|
|
|
|
stat.setParam("remoteip",m_session->UDPSession::transport()->remoteAddr().host());
|
|
|
|
stat.setParam("lostpkts",String(m_ioLostPkt));
|
|
|
|
stat.setParam("synclost",String(m_syncLost));
|
|
|
|
stat.setParam("wrongssrc",String(m_wrongSSRC));
|
|
|
|
stat.setParam("seqslost",String(m_seqLost));
|
|
|
|
}
|
2007-02-01 23:33:30 +00:00
|
|
|
|
2011-03-29 09:38:21 +00:00
|
|
|
|
2006-09-13 18:50:04 +00:00
|
|
|
RTPSender::RTPSender(RTPSession* session, bool randomTs)
|
2010-04-27 22:20:09 +00:00
|
|
|
: RTPBaseIO(session), m_evTime(0), m_padding(0)
|
2006-09-13 18:50:04 +00:00
|
|
|
{
|
2008-11-26 17:50:43 +00:00
|
|
|
if (randomTs) {
|
2011-06-29 11:19:02 +00:00
|
|
|
m_ts = Random::random() & ~1;
|
2008-11-26 17:50:43 +00:00
|
|
|
// avoid starting sequence numbers too close to zero
|
2013-08-07 11:24:10 +00:00
|
|
|
m_seq = (uint16_t)(2500 + (Random::random() % 60000));
|
2008-11-26 17:50:43 +00:00
|
|
|
}
|
2006-09-13 18:50:04 +00:00
|
|
|
}
|
2010-03-03 18:52:40 +00:00
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPSender::rtpSend(bool marker, int payload, unsigned int timestamp, const void* data, int len)
|
2005-05-03 20:16:07 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
if (m_debugData) {
|
|
|
|
const char* oper = "send";
|
|
|
|
if (!(m_session && m_session->UDPSession::transport()))
|
|
|
|
oper = "not sending";
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP %s seq=%u payload=%d ts=%u len=%u [%p]",
|
|
|
|
oper,(m_seq + 1),payload,timestamp,(data ? len : 0),this);
|
|
|
|
}
|
|
|
|
|
2009-11-03 10:49:12 +00:00
|
|
|
if (!(m_session && m_session->UDPSession::transport()))
|
2005-05-03 20:16:07 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
len = 0;
|
|
|
|
payload &= 0x7f;
|
2008-11-26 17:50:43 +00:00
|
|
|
if (marker || m_ssrcInit)
|
2005-05-03 20:16:07 +00:00
|
|
|
payload |= 0x80;
|
2005-06-08 15:09:27 +00:00
|
|
|
m_tsLast = timestamp;
|
2005-05-07 23:47:37 +00:00
|
|
|
timestamp += m_ts;
|
2008-04-10 16:35:20 +00:00
|
|
|
ssrcInit();
|
2005-05-07 23:47:37 +00:00
|
|
|
m_seq++;
|
2008-11-26 17:50:43 +00:00
|
|
|
if (m_seq == 0)
|
|
|
|
m_rollover++;
|
2010-03-03 18:52:40 +00:00
|
|
|
m_ioPackets++;
|
|
|
|
m_ioOctets += len;
|
2005-05-03 20:16:07 +00:00
|
|
|
|
2008-06-19 13:52:18 +00:00
|
|
|
unsigned char padding = 0;
|
|
|
|
unsigned char byte1 = 0x80;
|
|
|
|
if (m_padding > 1) {
|
|
|
|
padding = len % m_padding;
|
|
|
|
if (padding) {
|
|
|
|
padding = m_padding - padding;
|
|
|
|
byte1 |= 0x20;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-02 13:13:10 +00:00
|
|
|
m_buffer.resize(len + padding + m_secLen + 12);
|
|
|
|
unsigned char* pc = (unsigned char*)m_buffer.data();
|
2008-06-19 13:52:18 +00:00
|
|
|
if (padding)
|
2008-11-26 17:50:43 +00:00
|
|
|
pc[len + padding + 11] = padding;
|
2008-06-19 13:52:18 +00:00
|
|
|
*pc++ = byte1;
|
2005-05-03 20:16:07 +00:00
|
|
|
*pc++ = payload;
|
2006-05-26 08:16:45 +00:00
|
|
|
*pc++ = (unsigned char)(m_seq >> 8);
|
|
|
|
*pc++ = (unsigned char)(m_seq & 0xff);
|
|
|
|
*pc++ = (unsigned char)(timestamp >> 24);
|
|
|
|
*pc++ = (unsigned char)(timestamp >> 16);
|
|
|
|
*pc++ = (unsigned char)(timestamp >> 8);
|
|
|
|
*pc++ = (unsigned char)(timestamp & 0xff);
|
|
|
|
*pc++ = (unsigned char)(m_ssrc >> 24);
|
|
|
|
*pc++ = (unsigned char)(m_ssrc >> 16);
|
|
|
|
*pc++ = (unsigned char)(m_ssrc >> 8);
|
|
|
|
*pc++ = (unsigned char)(m_ssrc & 0xff);
|
2008-11-26 17:50:43 +00:00
|
|
|
if (data && len) {
|
2005-05-03 20:16:07 +00:00
|
|
|
::memcpy(pc,data,len);
|
2008-11-26 17:50:43 +00:00
|
|
|
rtpEncipher(pc,len + padding);
|
|
|
|
}
|
|
|
|
if (m_secLen)
|
2010-11-02 13:13:10 +00:00
|
|
|
rtpAddIntegrity((const unsigned char*)m_buffer.data(),len + padding + 12,pc + (len + padding + m_mkiLen));
|
|
|
|
static_cast<RTPProcessor*>(m_session->UDPSession::transport())->rtpData(m_buffer.data(),m_buffer.length());
|
2005-05-03 20:16:07 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPSender::rtpSendData(bool marker, unsigned int timestamp, const void* data, int len)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
2005-05-07 23:47:37 +00:00
|
|
|
if (dataPayload() < 0)
|
2005-05-04 22:52:53 +00:00
|
|
|
return false;
|
2005-05-10 20:26:01 +00:00
|
|
|
if (sendEventData(timestamp))
|
|
|
|
return true;
|
2005-05-07 23:47:37 +00:00
|
|
|
return rtpSend(marker,dataPayload(),timestamp,data,len);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPSender::rtpSendEvent(int event, int duration, int volume, unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
|
|
|
// send as RFC2833 if we have the payload type set
|
2005-05-10 20:26:01 +00:00
|
|
|
if (eventPayload() < 0)
|
|
|
|
return false;
|
|
|
|
if ((duration <= 50) || (duration > 10000))
|
2007-11-20 01:28:37 +00:00
|
|
|
duration = 1600;
|
2005-06-08 15:09:27 +00:00
|
|
|
if (!timestamp)
|
|
|
|
timestamp = m_tsLast;
|
2007-11-20 01:28:37 +00:00
|
|
|
if (m_evTs) {
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugNote,"RFC 2833 overlapped in RTP event %d, session %p, fixing.",
|
2007-11-20 01:28:37 +00:00
|
|
|
event,m_session);
|
|
|
|
// the timestamp must always advance to avoid misdetections
|
|
|
|
if (timestamp == m_evTs)
|
|
|
|
m_tsLast = timestamp = timestamp + 2;
|
|
|
|
// make sure we send an event end packet
|
|
|
|
m_evTime = 0;
|
|
|
|
sendEventData(timestamp);
|
|
|
|
}
|
2005-05-10 20:26:01 +00:00
|
|
|
m_evTs = timestamp;
|
|
|
|
m_evNum = event;
|
|
|
|
m_evVol = volume;
|
|
|
|
m_evTime = duration;
|
2020-07-21 07:39:54 +00:00
|
|
|
m_evSeq = 0;
|
2005-05-10 20:26:01 +00:00
|
|
|
return sendEventData(timestamp);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-06 18:13:33 +00:00
|
|
|
bool RTPSender::rtpSendKey(char key, int duration, int volume, unsigned int timestamp)
|
2005-05-04 22:52:53 +00:00
|
|
|
{
|
|
|
|
int event = 0;
|
|
|
|
if ((key >= '0') && (key <= '9'))
|
|
|
|
event = key - '0';
|
|
|
|
else if (key == '*')
|
|
|
|
event = 10;
|
|
|
|
else if (key == '#')
|
|
|
|
event = 11;
|
|
|
|
else if ((key >= 'A') && (key <= 'D'))
|
|
|
|
event = key + 12 - 'A';
|
|
|
|
else if ((key >= 'a') && (key <= 'd'))
|
|
|
|
event = key + 12 - 'a';
|
|
|
|
else if ((key == 'F') || (key == 'f'))
|
|
|
|
event = 16;
|
|
|
|
else
|
|
|
|
return false;
|
2005-05-06 18:13:33 +00:00
|
|
|
return rtpSendEvent(event,duration,volume,timestamp);
|
2005-05-04 22:52:53 +00:00
|
|
|
}
|
|
|
|
|
2005-05-10 20:26:01 +00:00
|
|
|
bool RTPSender::sendEventData(unsigned int timestamp)
|
|
|
|
{
|
|
|
|
if (m_evTs) {
|
|
|
|
if (eventPayload() < 0) {
|
|
|
|
m_evTs = 0;
|
|
|
|
return false;
|
|
|
|
}
|
2020-07-21 07:39:54 +00:00
|
|
|
if (timestamp <= m_tsLast && m_evSeq) {
|
|
|
|
if (m_debugEvent)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP send event %d timestamp=%u before last ts=%u - ignoring [%p]",
|
|
|
|
m_evNum,timestamp,m_evTs,this);
|
|
|
|
else
|
|
|
|
DDebug(dbg(),DebugNote,
|
|
|
|
"RTP send event %d timestamp=%u before last ts=%u - ignoring [%p]",
|
|
|
|
m_evNum,timestamp,m_evTs,this);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
m_evSeq++;
|
2005-05-10 20:26:01 +00:00
|
|
|
int duration = timestamp - m_evTs;
|
2020-07-21 07:39:54 +00:00
|
|
|
char end = (duration >= m_evTime) ? 0x80 : 0x00;
|
|
|
|
if (m_debugEvent)
|
|
|
|
TraceDebug(m_traceId,dbg(),m_debugDataLevel,
|
|
|
|
"RTP send event=%d ts=%u event_ts=%u duration=%u ev_duration=%u ev_seq=%u end=%s [%p]",
|
|
|
|
m_evNum,timestamp,m_evTs,duration,m_evTime,m_evSeq,String::boolText(end),this);
|
|
|
|
if (end)
|
|
|
|
duration = m_evTime;
|
2005-05-10 20:26:01 +00:00
|
|
|
char buf[4];
|
|
|
|
buf[0] = m_evNum;
|
2020-07-21 07:39:54 +00:00
|
|
|
buf[1] = (m_evVol & 0x7f) | end;
|
2005-05-10 20:26:01 +00:00
|
|
|
buf[2] = duration >> 8;
|
|
|
|
buf[3] = duration & 0xff;
|
2007-11-20 01:28:37 +00:00
|
|
|
unsigned int tstamp = m_evTs;
|
2020-07-21 07:39:54 +00:00
|
|
|
if (end) {
|
2005-05-10 20:26:01 +00:00
|
|
|
m_evTs = 0;
|
2007-11-20 01:28:37 +00:00
|
|
|
// repeat the event end packet to increase chances it gets seen
|
|
|
|
if (rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf)))
|
|
|
|
m_seq--;
|
2005-05-10 20:26:01 +00:00
|
|
|
}
|
2007-11-20 01:28:37 +00:00
|
|
|
bool ok = rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf));
|
|
|
|
// have to update last timestamp since we sent the event start stamp
|
|
|
|
m_tsLast = timestamp;
|
|
|
|
return ok;
|
2005-05-10 20:26:01 +00:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-06-19 13:52:18 +00:00
|
|
|
bool RTPSender::padding(int chunk)
|
|
|
|
{
|
|
|
|
if ((chunk < 0) || (chunk > 128))
|
|
|
|
return false;
|
|
|
|
m_padding = chunk;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
void RTPSender::timerTick(const Time& when)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
void RTPSender::rtpEncipher(unsigned char* data, int len)
|
|
|
|
{
|
|
|
|
if (m_secure)
|
|
|
|
m_secure->rtpEncipher(data,len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSender::rtpAddIntegrity(const unsigned char* data, int len, unsigned char* authData)
|
|
|
|
{
|
|
|
|
if (m_secure)
|
|
|
|
m_secure->rtpAddIntegrity(data,len,authData);
|
|
|
|
}
|
|
|
|
|
2010-11-03 16:27:30 +00:00
|
|
|
void RTPSender::stats(NamedList& stat) const
|
|
|
|
{
|
|
|
|
}
|
2006-05-27 15:18:34 +00:00
|
|
|
|
2011-03-29 09:38:21 +00:00
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
UDPSession::UDPSession(DebugEnabler* dbg, const char* traceId)
|
|
|
|
: RTPProcessor(dbg,traceId),
|
|
|
|
m_transport(0), m_timeoutTime(0), m_timeoutInterval(0)
|
2009-11-03 10:49:12 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(this->dbg(),DebugAll,"UDPSession::UDPSession() [%p]",this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UDPSession::~UDPSession()
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugAll,"UDPSession::~UDPSession() [%p]",this);
|
2009-11-03 10:49:12 +00:00
|
|
|
group(0);
|
|
|
|
transport(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPSession::timeout(bool initial)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugNote,"UDPSession::timeout(%s) [%p]",String::boolText(initial),this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UDPSession::transport(RTPTransport* trans)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"UDPSession::transport(%p) old=%p [%p]",trans,m_transport,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
if (trans == m_transport)
|
|
|
|
return;
|
2012-08-27 11:17:33 +00:00
|
|
|
TelEngine::destruct(m_transport);
|
2009-11-03 10:49:12 +00:00
|
|
|
m_transport = trans;
|
|
|
|
if (m_transport)
|
|
|
|
m_transport->setProcessor(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
RTPTransport* UDPSession::createTransport()
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
RTPTransport* trans = new RTPTransport(RTPTransport::RTP,dbg(),m_traceId);
|
2009-11-03 10:49:12 +00:00
|
|
|
trans->group(group());
|
|
|
|
return trans;
|
|
|
|
}
|
|
|
|
|
2020-09-23 13:12:56 +00:00
|
|
|
bool UDPSession::initGroup(int msec, Thread::Priority prio, const String& affinity)
|
2009-11-03 10:49:12 +00:00
|
|
|
{
|
|
|
|
if (m_group)
|
|
|
|
return true;
|
2020-09-23 13:12:56 +00:00
|
|
|
// try to pick the group from the transport if it has one
|
2009-11-03 10:49:12 +00:00
|
|
|
if (m_transport)
|
|
|
|
group(m_transport->group());
|
|
|
|
if (!m_group)
|
2020-09-23 13:12:56 +00:00
|
|
|
group(new RTPGroup(msec,prio,affinity));
|
2009-11-03 10:49:12 +00:00
|
|
|
if (!m_group)
|
|
|
|
return false;
|
|
|
|
if (m_transport)
|
|
|
|
m_transport->group(m_group);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UDPSession::initTransport()
|
|
|
|
{
|
|
|
|
if (m_transport)
|
|
|
|
return true;
|
|
|
|
transport(createTransport());
|
|
|
|
return (m_transport != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPSession::setTimeout(int interval)
|
|
|
|
{
|
|
|
|
if (interval) {
|
|
|
|
if (interval < 0)
|
|
|
|
interval = 0;
|
|
|
|
// force sane limits: between 500ms and 60s
|
|
|
|
else if (interval < 500)
|
|
|
|
interval = 500;
|
|
|
|
else if (interval > 60000)
|
|
|
|
interval = 60000;
|
|
|
|
}
|
|
|
|
m_timeoutTime = 0;
|
|
|
|
m_timeoutInterval = interval * (u_int64_t)1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
RTPSession::RTPSession(DebugEnabler* dbg, const char* traceId)
|
|
|
|
: UDPSession(dbg,traceId), Mutex(true,"RTPSession"),
|
2011-03-29 09:38:21 +00:00
|
|
|
m_direction(FullStop),
|
2010-04-27 22:20:09 +00:00
|
|
|
m_send(0), m_recv(0), m_secure(0),
|
2013-10-10 14:38:42 +00:00
|
|
|
m_reportTime(0), m_reportInterval(0),
|
|
|
|
m_warnSeq(1)
|
2005-05-07 23:47:37 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(this->dbg(),DebugInfo,"RTPSession::RTPSession() [%p]",this);
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RTPSession::~RTPSession()
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::~RTPSession() [%p]",this);
|
2005-05-07 23:47:37 +00:00
|
|
|
direction(FullStop);
|
2005-05-10 14:54:04 +00:00
|
|
|
group(0);
|
2005-12-30 17:45:30 +00:00
|
|
|
transport(0);
|
2008-11-26 17:50:43 +00:00
|
|
|
TelEngine::destruct(m_secure);
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::timerTick(const Time& when)
|
|
|
|
{
|
|
|
|
if (m_send)
|
|
|
|
static_cast<RTPBaseIO*>(m_send)->timerTick(when);
|
|
|
|
if (m_recv)
|
|
|
|
static_cast<RTPBaseIO*>(m_recv)->timerTick(when);
|
2008-04-10 16:35:20 +00:00
|
|
|
|
|
|
|
if (m_timeoutInterval) {
|
|
|
|
// only check timeout if we have a receiver
|
|
|
|
if (m_timeoutTime && m_recv) {
|
|
|
|
if (when >= m_timeoutTime) {
|
2008-04-10 18:58:11 +00:00
|
|
|
// rearm timeout next time we get a packet
|
|
|
|
m_timeoutTime = INF_TIMEOUT;
|
2008-04-10 16:35:20 +00:00
|
|
|
timeout(0 == m_recv->ssrc());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_timeoutTime = when + m_timeoutInterval;
|
|
|
|
}
|
2010-04-27 22:20:09 +00:00
|
|
|
if (m_reportInterval) {
|
|
|
|
if (when >= m_reportTime) {
|
|
|
|
m_reportTime = when + m_reportInterval;
|
|
|
|
sendRtcpReport(when);
|
|
|
|
}
|
|
|
|
}
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::rtpData(const void* data, int len)
|
|
|
|
{
|
|
|
|
if ((m_direction & RecvOnly) == 0)
|
|
|
|
return;
|
2008-04-10 16:35:20 +00:00
|
|
|
if (m_recv) {
|
|
|
|
m_timeoutTime = 0;
|
2005-05-07 23:47:37 +00:00
|
|
|
m_recv->rtpData(data,len);
|
2008-04-10 16:35:20 +00:00
|
|
|
}
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::rtcpData(const void* data, int len)
|
|
|
|
{
|
|
|
|
if ((m_direction & RecvOnly) == 0)
|
|
|
|
return;
|
2008-04-10 16:35:20 +00:00
|
|
|
if (m_recv) {
|
2011-04-16 13:16:32 +00:00
|
|
|
if ((m_timeoutTime != INF_TIMEOUT) || m_recv->ssrc())
|
|
|
|
m_timeoutTime = 0;
|
2005-05-07 23:47:37 +00:00
|
|
|
m_recv->rtcpData(data,len);
|
2008-04-10 16:35:20 +00:00
|
|
|
}
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
2005-05-10 20:26:01 +00:00
|
|
|
bool RTPSession::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
XDebug(dbg(),DebugAll,"RTPSession::rtpRecv(%s,%u,%p,%d) [%p]",
|
2005-05-10 20:26:01 +00:00
|
|
|
String::boolText(marker),timestamp,data,len,this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPSession::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
XDebug(dbg(),DebugAll,"RTPSession::rtpRecvEvent(%d,%02x,%d,%d,%u) [%p]",
|
2005-05-10 20:26:01 +00:00
|
|
|
event,key,duration,volume,timestamp,this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::rtpNewPayload(int payload, unsigned int timestamp)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
XDebug(dbg(),DebugAll,"RTPSession::rtpNewPayload(%d,%u) [%p]",
|
2005-05-10 20:26:01 +00:00
|
|
|
payload,timestamp,this);
|
|
|
|
}
|
|
|
|
|
2008-02-18 14:40:36 +00:00
|
|
|
void RTPSession::rtpNewSSRC(u_int32_t newSsrc,bool marker)
|
2005-07-13 23:45:26 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
XDebug(dbg(),DebugAll,"RTPSession::rtpNewSSRC(%08X,%s) [%p]",
|
2008-02-18 14:40:36 +00:00
|
|
|
newSsrc,String::boolText(marker),this);
|
2005-07-13 23:45:26 +00:00
|
|
|
}
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
RTPSender* RTPSession::createSender()
|
|
|
|
{
|
|
|
|
return new RTPSender(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
RTPReceiver* RTPSession::createReceiver()
|
|
|
|
{
|
|
|
|
return new RTPReceiver(this);
|
|
|
|
}
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
Cipher* RTPSession::createCipher(const String& name, Cipher::Direction dir)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPSession::checkCipher(const String& name)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
void RTPSession::transport(RTPTransport* trans)
|
|
|
|
{
|
2010-04-27 22:20:09 +00:00
|
|
|
if (!trans)
|
|
|
|
sendRtcpBye();
|
2009-11-03 10:49:12 +00:00
|
|
|
UDPSession::transport(trans);
|
|
|
|
if (!m_transport)
|
2005-05-07 23:47:37 +00:00
|
|
|
m_direction = FullStop;
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::sender(RTPSender* send)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::sender(%p) old=%p [%p]",send,m_send,this);
|
2005-05-07 23:47:37 +00:00
|
|
|
if (send == m_send)
|
|
|
|
return;
|
2010-04-27 22:20:09 +00:00
|
|
|
sendRtcpBye();
|
2005-05-07 23:47:37 +00:00
|
|
|
RTPSender* tmp = m_send;
|
|
|
|
m_send = send;
|
|
|
|
if (tmp)
|
|
|
|
delete tmp;
|
2008-11-26 17:50:43 +00:00
|
|
|
if (m_send && m_secure) {
|
|
|
|
RTPSecure* sec = m_secure;
|
|
|
|
m_secure = 0;
|
|
|
|
m_send->security(sec);
|
|
|
|
}
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::receiver(RTPReceiver* recv)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::receiver(%p) old=%p [%p]",recv,m_recv,this);
|
2005-05-07 23:47:37 +00:00
|
|
|
if (recv == m_recv)
|
|
|
|
return;
|
|
|
|
RTPReceiver* tmp = m_recv;
|
|
|
|
m_recv = recv;
|
|
|
|
if (tmp)
|
|
|
|
delete tmp;
|
2013-10-10 14:38:42 +00:00
|
|
|
if (m_recv)
|
|
|
|
m_recv->m_warnSeq = m_warnSeq;
|
2005-05-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
2008-11-26 17:50:43 +00:00
|
|
|
void RTPSession::security(RTPSecure* secure)
|
|
|
|
{
|
|
|
|
if (m_send)
|
|
|
|
m_send->security(secure);
|
|
|
|
else if (secure != m_secure) {
|
|
|
|
TelEngine::destruct(m_secure);
|
|
|
|
m_secure = secure;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
bool RTPSession::direction(Direction dir)
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::direction(%d) old=%d [%p]",dir,m_direction,this);
|
2005-05-07 23:47:37 +00:00
|
|
|
if ((dir != FullStop) && !m_transport)
|
|
|
|
return false;
|
2005-06-17 18:09:07 +00:00
|
|
|
|
|
|
|
if (dir & RecvOnly) {
|
|
|
|
if (!m_recv)
|
|
|
|
receiver(createReceiver());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
receiver(0);
|
|
|
|
|
|
|
|
if (dir & SendOnly) {
|
|
|
|
if (!m_send)
|
|
|
|
sender(createSender());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sender(0);
|
|
|
|
|
2005-05-07 23:47:37 +00:00
|
|
|
m_direction = dir;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-05-10 20:26:01 +00:00
|
|
|
bool RTPSession::dataPayload(int type)
|
|
|
|
{
|
|
|
|
if (m_recv || m_send) {
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::dataPayload(%d) [%p]",type,this);
|
2005-05-10 20:26:01 +00:00
|
|
|
bool ok = (!m_recv) || m_recv->dataPayload(type);
|
|
|
|
return ((!m_send) || m_send->dataPayload(type)) && ok;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPSession::eventPayload(int type)
|
|
|
|
{
|
|
|
|
if (m_recv || m_send) {
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::eventPayload(%d) [%p]",type,this);
|
2005-05-10 20:26:01 +00:00
|
|
|
bool ok = (!m_recv) || m_recv->eventPayload(type);
|
|
|
|
return ((!m_send) || m_send->eventPayload(type)) && ok;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool RTPSession::silencePayload(int type)
|
|
|
|
{
|
|
|
|
if (m_recv || m_send) {
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::silencePayload(%d) [%p]",type,this);
|
2005-05-10 20:26:01 +00:00
|
|
|
bool ok = (!m_recv) || m_recv->silencePayload(type);
|
|
|
|
return ((!m_send) || m_send->silencePayload(type)) && ok;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-03-03 18:52:40 +00:00
|
|
|
void RTPSession::getStats(String& stats) const
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession::getStats() tx=%p rx=%p [%p]",m_send,m_recv,this);
|
2010-03-03 18:52:40 +00:00
|
|
|
if (m_send) {
|
|
|
|
stats.append("PS=",",") << m_send->ioPackets();
|
|
|
|
stats << ",OS=" << m_send->ioOctets();
|
|
|
|
}
|
|
|
|
if (m_recv) {
|
|
|
|
stats.append("PR=",",") << m_recv->ioPackets();
|
|
|
|
stats << ",OR=" << m_recv->ioOctets();
|
|
|
|
stats << ",PL=" << m_recv->ioPacketsLost();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-27 22:20:09 +00:00
|
|
|
void RTPSession::setReports(int interval)
|
|
|
|
{
|
|
|
|
if (interval > 0 && m_transport && m_transport->rtcpSock()->valid()) {
|
|
|
|
if (interval < 500)
|
|
|
|
interval = 500;
|
|
|
|
else if (interval > 60000)
|
|
|
|
interval = 60000;
|
2011-06-29 11:19:02 +00:00
|
|
|
m_reportInterval = interval * (u_int64_t)1000 + (Random::random() % 20000);
|
2010-04-27 22:20:09 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
m_reportInterval = 0;
|
|
|
|
m_reportTime = 0;
|
|
|
|
}
|
|
|
|
|
2010-11-03 16:27:30 +00:00
|
|
|
void RTPSession::getStats(NamedList& stats) const
|
|
|
|
{
|
|
|
|
if (m_send)
|
|
|
|
m_send->stats(stats);
|
|
|
|
if (m_recv)
|
|
|
|
m_recv->stats(stats);
|
|
|
|
stats.setParam("wrongsrc",String(m_wrongSrc));
|
|
|
|
}
|
|
|
|
|
2010-04-27 22:20:09 +00:00
|
|
|
static void store32(unsigned char* buf, unsigned int& len, u_int32_t val)
|
|
|
|
{
|
|
|
|
buf[len++] = (unsigned char)(val >> 24);
|
|
|
|
buf[len++] = (unsigned char)(val >> 16);
|
|
|
|
buf[len++] = (unsigned char)(val >> 8);
|
|
|
|
buf[len++] = (unsigned char)(val & 0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::sendRtcpReport(const Time& when)
|
|
|
|
{
|
|
|
|
if (!((m_send || m_recv) && m_transport && m_transport->rtcpSock()->valid()))
|
|
|
|
return;
|
|
|
|
unsigned char buf[52];
|
|
|
|
buf[0] = 0x80; // RC=0
|
|
|
|
buf[1] = 0xc9; // RR
|
|
|
|
buf[2] = 0;
|
|
|
|
unsigned int len = 8;
|
|
|
|
if (m_send && m_send->ioPackets()) {
|
|
|
|
// Include a sender report
|
|
|
|
buf[1] = 0xc8; // SR
|
|
|
|
// NTP timestamp
|
2013-08-07 11:24:10 +00:00
|
|
|
store32(buf,len,(uint32_t)(2208988800 + (when.usec() / 1000000)));
|
|
|
|
store32(buf,len,(uint32_t)(((when.usec() % 1000000) << 32) / 1000000));
|
2010-04-27 22:20:09 +00:00
|
|
|
// RTP timestamp
|
|
|
|
store32(buf,len,m_send->tsLast());
|
|
|
|
// Packet and octet counters
|
|
|
|
store32(buf,len,m_send->ioPackets());
|
|
|
|
store32(buf,len,m_send->ioOctets());
|
|
|
|
}
|
|
|
|
if (m_recv && m_recv->ioPackets()) {
|
|
|
|
// Add a single receiver report
|
|
|
|
buf[0] |= 0x01; // RC=1
|
|
|
|
store32(buf,len,m_recv->ssrc());
|
|
|
|
u_int32_t lost = m_recv->ioPacketsLost();
|
|
|
|
u_int32_t lostf = 0xff & (lost * 255 / (lost + m_recv->ioPackets()));
|
|
|
|
store32(buf,len,(lost & 0xffffff) | (lostf << 24));
|
2013-08-07 11:24:10 +00:00
|
|
|
store32(buf,len,(uint32_t)m_recv->fullSeq());
|
2010-04-27 22:20:09 +00:00
|
|
|
// TODO: Compute and store Jitter, LSR and DLSR
|
|
|
|
store32(buf,len,0);
|
|
|
|
store32(buf,len,0);
|
|
|
|
store32(buf,len,0);
|
|
|
|
}
|
|
|
|
// Don't send a RR with no receiver report blocks...
|
|
|
|
if (len <= 8)
|
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession sending RTCP Report [%p]",this);
|
2010-04-27 22:20:09 +00:00
|
|
|
unsigned int lptr = 4;
|
|
|
|
store32(buf,lptr,(m_send ? m_send->ssrcInit() : 0));
|
|
|
|
buf[3] = (len - 1) / 4; // same as ((len + 3) / 4) - 1
|
|
|
|
static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,len);
|
|
|
|
}
|
|
|
|
|
|
|
|
void RTPSession::sendRtcpBye()
|
|
|
|
{
|
|
|
|
if (!(m_send && m_transport && m_transport->rtcpSock()->valid()))
|
|
|
|
return;
|
|
|
|
u_int32_t ssrc = m_send->ssrc();
|
|
|
|
if (!ssrc)
|
|
|
|
return;
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"RTPSession sending RTCP Bye [%p]",this);
|
2010-04-27 22:20:09 +00:00
|
|
|
// SSRC was initialized if we sent at least one RTP or RTCP packet
|
|
|
|
unsigned char buf[8];
|
|
|
|
buf[0] = 0x81;
|
|
|
|
buf[1] = 0xcb;
|
|
|
|
buf[2] = 0;
|
|
|
|
buf[3] = 1; // len = 2 x 32bit
|
|
|
|
buf[4] = (unsigned char)(ssrc >> 24);
|
|
|
|
buf[5] = (unsigned char)(ssrc >> 16);
|
|
|
|
buf[6] = (unsigned char)(ssrc >> 8);
|
|
|
|
buf[7] = (unsigned char)(0xff & ssrc);
|
|
|
|
static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,8);
|
|
|
|
}
|
|
|
|
|
2014-02-05 11:42:17 +00:00
|
|
|
void RTPSession::incWrongSrc()
|
2010-11-03 16:27:30 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
XDebug(dbg(),DebugAll,"RTPSession::incWrongSrc() [%p]",this);
|
2010-11-03 16:27:30 +00:00
|
|
|
m_wrongSrc++;
|
|
|
|
}
|
2009-11-03 10:49:12 +00:00
|
|
|
|
2011-03-29 09:38:21 +00:00
|
|
|
|
2020-07-21 07:39:54 +00:00
|
|
|
UDPTLSession::UDPTLSession(u_int16_t maxLen, u_int8_t maxSec, DebugEnabler* dbg, const char* traceId)
|
|
|
|
: UDPSession(dbg,traceId), Mutex(true,"UDPTLSession"),
|
2011-03-29 09:38:21 +00:00
|
|
|
m_rxSeq(0xffff), m_txSeq(0xffff),
|
2009-11-03 10:49:12 +00:00
|
|
|
m_maxLen(maxLen), m_maxSec(maxSec),
|
|
|
|
m_warn(true)
|
2008-04-10 16:35:20 +00:00
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(this->dbg(),DebugInfo,"UDPTLSession::UDPTLSession(%u,%u) [%p]",maxLen,maxSec,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
if (m_maxLen < 96)
|
|
|
|
m_maxLen = 96;
|
|
|
|
else if (m_maxLen > 1492)
|
|
|
|
m_maxLen = 1492;
|
|
|
|
}
|
|
|
|
|
|
|
|
UDPTLSession::~UDPTLSession()
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
DDebug(dbg(),DebugInfo,"UDPTLSession::~UDPTLSession() [%p]",this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void UDPTLSession::timerTick(const Time& when)
|
|
|
|
{
|
|
|
|
if (m_timeoutInterval) {
|
|
|
|
if (m_timeoutTime) {
|
|
|
|
if (when >= m_timeoutTime) {
|
|
|
|
// rearm timeout next time we get a packet
|
|
|
|
m_timeoutTime = INF_TIMEOUT;
|
|
|
|
timeout(0xffff == m_rxSeq);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
m_timeoutTime = when + m_timeoutInterval;
|
2008-04-10 16:35:20 +00:00
|
|
|
}
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RTPTransport* UDPTLSession::createTransport()
|
|
|
|
{
|
2020-07-21 07:39:54 +00:00
|
|
|
RTPTransport* trans = new RTPTransport(RTPTransport::UDPTL,dbg(),m_traceId);
|
2009-11-03 10:49:12 +00:00
|
|
|
trans->group(group());
|
|
|
|
return trans;
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPTLSession::rtpData(const void* data, int len)
|
|
|
|
{
|
|
|
|
if ((len < 6) || !data)
|
|
|
|
return;
|
2008-04-10 16:35:20 +00:00
|
|
|
m_timeoutTime = 0;
|
2009-11-03 10:49:12 +00:00
|
|
|
const unsigned char* pd = (const unsigned char*)data;
|
|
|
|
int pLen = pd[2];
|
|
|
|
if (pLen > (len-5)) {
|
|
|
|
// primary IFP does not fit in packet
|
|
|
|
if ((m_rxSeq == 0xffff) && ((pd[0] & 0xc0) == 0x80) && m_warn) {
|
|
|
|
m_warn = false;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"Receiving RTP instead of UDPTL [%p]",this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
u_int16_t seq = pd[1] + (((u_int16_t)pd[0]) << 8);
|
|
|
|
// substraction with overflow
|
|
|
|
int16_t ds = seq - m_rxSeq;
|
|
|
|
if ((m_rxSeq == 0xffff) && (seq != 0)) {
|
|
|
|
// received sequence does not start at zero
|
|
|
|
if ((pd[0] & 0xc0) == 0x80) {
|
|
|
|
if (m_warn) {
|
|
|
|
m_warn = false;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"Receiving RTP instead of UDPTL [%p]",this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ds = 1;
|
|
|
|
}
|
|
|
|
if (ds < 0) {
|
|
|
|
// received old packet
|
|
|
|
if (m_warn) {
|
|
|
|
m_warn = false;
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL received SEQ %u while current is %u [%p]",seq,m_rxSeq,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_warn = true;
|
|
|
|
if (ds > 1) {
|
|
|
|
// some packets were lost, try to recover
|
|
|
|
if (0 == pd[pLen+3])
|
|
|
|
// recover from secondary IFPs
|
|
|
|
recoverSec(pd+pLen+5,len-pLen-5,seq-1,pd[pLen+4]);
|
|
|
|
}
|
|
|
|
m_rxSeq = seq;
|
|
|
|
udptlRecv(pd+3,pLen,seq,false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void UDPTLSession::recoverSec(const unsigned char* data, int len, u_int16_t seq, int nSec)
|
|
|
|
{
|
|
|
|
if ((nSec <= 0) || (len <= 1))
|
|
|
|
return;
|
|
|
|
if ((int16_t)(seq - m_rxSeq) <= 0)
|
|
|
|
return;
|
|
|
|
int sLen = data[0];
|
|
|
|
if (sLen >= len)
|
|
|
|
return;
|
|
|
|
// recursively recover from remaining secondaries
|
|
|
|
recoverSec(data+sLen+1,len-sLen-1,seq-1,nSec-1);
|
|
|
|
int16_t ds = seq - m_rxSeq;
|
|
|
|
switch (ds) {
|
|
|
|
case 1:
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugMild,"UDPTL lost IFP with SEQ %u [%p]",m_rxSeq+1,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
break;
|
|
|
|
default:
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL lost IFPs with SEQ %u-%u [%p]",m_rxSeq+1,seq-1,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugInfo,"UDPTL recovered IFP with SEQ %u [%p]",seq,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
m_rxSeq = seq;
|
|
|
|
udptlRecv(data+1,sLen,seq,true);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UDPTLSession::udptlSend(const void* data, int len, u_int16_t seq)
|
|
|
|
{
|
|
|
|
if (!(UDPSession::transport() && data && len))
|
|
|
|
return false;
|
2011-03-29 09:38:21 +00:00
|
|
|
Lock lck(this);
|
2009-11-03 10:49:12 +00:00
|
|
|
int pl = len + 5;
|
|
|
|
if ((len > 255) || (pl > m_maxLen)) {
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL could not send IFP with len=%d [%p]",len,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
m_txQueue.clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// substraction with overflow
|
|
|
|
int16_t ds = seq - m_txSeq;
|
|
|
|
if (ds != 0) {
|
|
|
|
if (ds != 1) {
|
2020-07-21 07:39:54 +00:00
|
|
|
TraceDebug(m_traceId,dbg(),DebugInfo,"UDPTL sending SEQ %u while current is %u [%p]",seq,m_txSeq,this);
|
2009-11-03 10:49:12 +00:00
|
|
|
m_txQueue.clear();
|
|
|
|
}
|
|
|
|
if (m_maxSec)
|
|
|
|
m_txQueue.insert(new DataBlock(const_cast<void*>(data),len));
|
|
|
|
}
|
|
|
|
DataBlock buf(0,m_maxLen);
|
|
|
|
unsigned char* pd = buf.data(0,6);
|
|
|
|
if (!pd)
|
|
|
|
return false;
|
|
|
|
pd[0] = (seq >> 8) & 0xff;
|
|
|
|
pd[1] = seq & 0xff;
|
|
|
|
pd[2] = len & 0xff;
|
|
|
|
::memcpy(pd+3,data,len);
|
|
|
|
pd[len+3] = 0; // secondary IFPs
|
|
|
|
int nSec = 0;
|
|
|
|
for (ObjList* l = m_txQueue.skipNext(); l; l = l->skipNext()) {
|
|
|
|
// truncate the TX queue when reaching maximum packet length or IFP count
|
|
|
|
if (nSec >= m_maxSec) {
|
|
|
|
l->clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
DataBlock* d = static_cast<DataBlock*>(l->get());
|
|
|
|
if ((pl+d->length()+1) > m_maxLen) {
|
|
|
|
l->clear();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
pd[pl] = d->length() & 0xff;
|
|
|
|
::memcpy(pd+pl+1,d->data(),d->length());
|
|
|
|
pl += d->length()+1;
|
|
|
|
nSec++;
|
|
|
|
}
|
|
|
|
pd[len+4] = nSec;
|
|
|
|
m_txSeq = seq;
|
|
|
|
static_cast<RTPProcessor*>(UDPSession::transport())->rtpData(pd,pl);
|
|
|
|
return true;
|
2008-04-10 16:35:20 +00:00
|
|
|
}
|
|
|
|
|
2005-05-02 18:31:05 +00:00
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|