1 /**
2 * session.cpp
3 * Yet Another RTP Stack
4 * This file is part of the YATE Project http://YATE.null.ro
5 *
6 * Yet Another Telephony Engine - a fully featured software PBX and IVR
7 * Copyright (C) 2004-2014 Null Team
8 *
9 * This software is distributed under multiple licenses;
10 * see the COPYING file in the main directory for licensing
11 * information for this specific distribution.
12 *
13 * This use of this software may be subject to additional restrictions.
14 * See the LEGAL file in the main directory for details.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 */
20
21 #include <yatertp.h>
22
23 #include <string.h>
24 #include <stdlib.h>
25
26 using namespace TelEngine;
27
28 // u_int64_t Infinity
29 #define INF_TIMEOUT ((u_int64_t)(int64_t)-1)
30
31 // How many lost packets mean we lost sequence sync
32 #define SEQ_DESYNC_COUNT 50
33 // How many packets in a row will resync sequence
34 #define SEQ_RESYNC_COUNT 5
35
RTPDebug(RTPSession * session)36 RTPDebug::RTPDebug(RTPSession* session)
37 : m_dbg(0)
38 {
39 if (session)
40 setDebug(session->dbg(),session->dbgTraceId());
41 }
42
43
~RTPBaseIO()44 RTPBaseIO::~RTPBaseIO()
45 {
46 security(0);
47 }
48
dataPayload(int type)49 bool RTPBaseIO::dataPayload(int type)
50 {
51 if ((type >= -1) && (type <= 127)) {
52 m_dataType = type;
53 return true;
54 }
55 return false;
56 }
57
eventPayload(int type)58 bool RTPBaseIO::eventPayload(int type)
59 {
60 if ((type >= -1) && (type <= 127)) {
61 m_eventType = type;
62 return true;
63 }
64 return false;
65 }
66
silencePayload(int type)67 bool RTPBaseIO::silencePayload(int type)
68 {
69 if ((type >= -1) && (type <= 127)) {
70 m_silenceType = type;
71 return true;
72 }
73 return false;
74 }
75
ssrcInit()76 unsigned int RTPBaseIO::ssrcInit()
77 {
78 if (m_ssrcInit) {
79 m_ssrcInit = false;
80 do {
81 m_ssrc = Random::random();
82 } while (0 == m_ssrc);
83 }
84 return m_ssrc;
85 }
86
security(RTPSecure * secure)87 void RTPBaseIO::security(RTPSecure* secure)
88 {
89 DDebug(dbg(),DebugInfo,"RTPBaseIO::security(%p) old=%p [%p]",secure,m_secure,this);
90 if (secure == m_secure)
91 return;
92 RTPSecure* tmp = m_secure;
93 m_secure = 0;
94 if (secure) {
95 secure->owner(this);
96 m_secure = secure;
97 }
98 else
99 secLength(0,0);
100 TelEngine::destruct(tmp);
101 }
102
initDebugData(bool recv,const NamedList & params)103 void RTPBaseIO::initDebugData(bool recv, const NamedList& params)
104 {
105 const String* p = params.getParam(YSTRING("debug_rtp"));
106 if (!p)
107 return;
108 bool on = p->toBoolean();
109 String suff(recv ? "_recv" : "_send");
110 m_debugData = params.getBoolValue("debug_rtp_data" + suff,
111 params.getBoolValue(YSTRING("debug_rtp_data"),on));
112 m_debugEvent = params.getBoolValue("debug_rtp_event" + suff,
113 params.getBoolValue(YSTRING("debug_rtp_event"),on));
114 m_debugDataLevel = params.getIntValue(YSTRING("debug_rtp_level"),DebugAll);
115 if (m_debugDataLevel <= DebugFail)
116 m_debugDataLevel = 1 + DebugFail;
117 }
118
119
~RTPReceiver()120 RTPReceiver::~RTPReceiver()
121 {
122 setDejitter(0);
123 }
124
setDejitter(RTPDejitter * dejitter)125 void RTPReceiver::setDejitter(RTPDejitter* dejitter)
126 {
127 if (dejitter == m_dejitter)
128 return;
129 DDebug(dbg(),DebugInfo,"RTP setting new dejitter %p [%p]",dejitter,this);
130 RTPDejitter* tmp = m_dejitter;
131 m_dejitter = 0;
132 if (tmp) {
133 tmp->group(0);
134 tmp->destruct();
135 }
136 // make the dejitter buffer belong to the same group as the session
137 if (dejitter && m_session)
138 dejitter->group(m_session->group());
139 m_dejitter = dejitter;
140 }
141
rtpData(const void * data,int len)142 void RTPReceiver::rtpData(const void* data, int len)
143 {
144 // trivial check for basic fields validity
145 if ((len < m_secLen + 12) || !data)
146 return;
147 const unsigned char* pc = (const unsigned char*)data;
148 // check protocol version number
149 if ((pc[0] & 0xc0) != 0x80)
150 return;
151 const unsigned char* secPtr = 0;
152 if (m_secLen) {
153 // security info is placed after data and padding
154 len -= m_secLen;
155 secPtr = pc + len;
156 }
157 // check if padding is present and remove it (but remember length)
158 unsigned char padding = 0;
159 if (pc[0] & 0x20) {
160 len -= (padding = pc[len-1]);
161 if (len < 12)
162 return;
163 }
164
165 bool ext = (pc[0] & 0x10) != 0;
166 int cc = pc[0] & 0x0f;
167 bool marker = (pc[1] & 0x80) != 0;
168 int typ = pc[1] & 0x7f;
169 u_int16_t seq = ((u_int16_t)pc[2] << 8) | pc[3];
170 u_int32_t ts = ((u_int32_t)pc[4] << 24) | ((u_int32_t)pc[5] << 16) |
171 ((u_int32_t)pc[6] << 8) | pc[7];
172 u_int32_t ss = ((u_int32_t)pc[8] << 24) | ((u_int32_t)pc[9] << 16) |
173 ((u_int32_t)pc[10] << 8) | pc[11];
174
175 // skip over header and any CSRC
176 pc += 12+(4*cc);
177 len -= 12+(4*cc);
178 // check if extension is present and skip it
179 if (ext) {
180 if (len < 4)
181 return;
182 int xl = ((int)pc[2] << 8) | pc[3];
183 pc += xl+4;
184 len -= xl+4;
185 }
186 if (len < 0)
187 return;
188 if (!len)
189 pc = 0;
190
191 // grab some data at the first packet received or resync
192 if (m_ssrcInit) {
193 m_ssrcInit = false;
194 m_ssrc = ss;
195 m_ts = ts - m_tsLast;
196 m_seq = seq-1;
197 m_seqCount = 0;
198 m_warn = true;
199 if (m_debugData)
200 TraceDebug(m_traceId,dbg(),m_debugDataLevel,"RTP recv INIT SEQ=%u TS=%u TS_LAST=%u [%p]",
201 seq,ts,m_tsLast,this);
202 if (m_dejitter)
203 m_dejitter->clear();
204 }
205
206 if (ss != m_ssrc) {
207 rtpNewSSRC(ss,marker);
208 // check if the SSRC is still unchanged
209 if (ss != m_ssrc) {
210 if (m_warn) {
211 m_warn = false;
212 TraceDebug(m_traceId,dbg(),DebugWarn,"RTP Received SSRC %08X but expecting %08X [%p]",
213 ss,m_ssrc,this);
214 }
215 m_wrongSSRC++;
216 return;
217 }
218 // SSRC accepted, sync sequence and resync the timestamp offset
219 m_seq = seq;
220 m_ts = ts - m_tsLast;
221 m_seqCount = 0;
222 if (m_debugData)
223 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
224 "RTP recv SEQ=%u TS=%u TS_LAST=%u new SSRC accepted, dropping [%p]",
225 seq,ts,m_tsLast,this);
226 if (m_dejitter)
227 m_dejitter->clear();
228 // drop this packet, next packet will come in correctly
229 return;
230 }
231
232 u_int32_t rollover = m_rollover;
233 // compare unsigned to detect rollovers
234 if (seq < m_seq)
235 rollover++;
236 u_int64_t seq48 = rollover;
237 seq48 = (seq48 << 16) | seq;
238
239 // if some security data is present authenticate the packet now
240 if (secPtr && !rtpCheckIntegrity((const unsigned char*)data,len + padding + 12,secPtr + m_mkiLen,ss,seq48)) {
241 if (m_debugData)
242 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
243 "RTP recv SEQ=%u TS=%u TS_LAST=%u integrity check failed, dropping [%p]",
244 seq,ts,m_tsLast,this);
245 return;
246 }
247
248 // substraction with overflow to compute sequence difference
249 int16_t ds = seq - m_seq;
250 if (ds != 1)
251 m_seqLost++;
252 if (ds == 0) {
253 if (m_debugData)
254 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
255 "RTP recv SEQ=%u TS=%u TS_LAST=%u same as our last seq, dropping [%p]",
256 seq,ts,m_tsLast,this);
257 return;
258 }
259
260 // check if we received a packet too much out of sequence
261 // be much more tolerant when authenticating as we cannot resync
262 if ((ds <= -SEQ_DESYNC_COUNT) || ((ds > SEQ_DESYNC_COUNT) && !secPtr)) {
263 m_ioLostPkt++;
264 if (!secPtr) {
265 // try to resync sequence unless we need to authenticate
266 if (m_seqCount++) {
267 if (seq == ++m_seqSync) {
268 // good - packets numbers still in sequence
269 if (m_seqCount >= SEQ_RESYNC_COUNT) {
270 if (m_debugData)
271 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
272 "RTP recv SEQ=%u TS=%u TS_LAST=%u sequence resync from current %u [%p]",
273 seq,ts,m_tsLast,m_seq,this);
274 else
275 TraceDebug(m_traceId,dbg(),DebugNote,"RTP sequence resync: %u -> %u [%p]",m_seq,seq,this);
276 // sync sequence but keep the timestamp offset
277 m_seq = seq;
278 m_seqCount = 0;
279 if (m_warnSeq > 0)
280 m_warn = true;
281 else
282 m_warnSeq = -1;
283 m_syncLost++;
284 if (m_dejitter)
285 m_dejitter->clear();
286 // drop this packet, next packet will come in correctly
287 return;
288 }
289 }
290 else
291 m_seqCount = 0;
292 }
293 else
294 m_seqSync = seq;
295 }
296 if (m_debugData)
297 m_warnSeq = -1;
298 if (m_warnSeq > 0) {
299 if (m_warn) {
300 m_warn = false;
301 TraceDebug(m_traceId,dbg(),DebugWarn,"RTP received SEQ %u while current is %u [%p]",seq,m_seq,this);
302 }
303 }
304 else if (m_warnSeq < 0) {
305 m_warnSeq = 0;
306 TraceDebug(m_traceId,dbg(),DebugInfo,"RTP received SEQ %u while current is %u [%p]",seq,m_seq,this);
307 }
308 return;
309 }
310
311 if (!rtpDecipher(const_cast<unsigned char*>(pc),len + padding,secPtr,ss,seq48))
312 return;
313
314 if (m_debugData) {
315 const char* extra = "";
316 if (m_dejitter)
317 extra = " [DEJITTER]";
318 else if (ds < 1)
319 extra = ", dropping";
320 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
321 "RTP recv payload=%d SEQ=%u (delta=%d) TS=%u TS_LAST %u -> %u%s [%p]",
322 typ,seq,ds,ts,m_tsLast,(ts - m_ts),extra,this);
323 }
324 m_tsLast = ts - m_ts;
325 m_seqCount = 0;
326 m_ioPackets++;
327 m_ioOctets += len;
328 // keep track of the last valid sequence number and timestamp we have seen
329 m_seq = seq;
330 m_rollover = rollover;
331
332 if (m_dejitter) {
333 if (!m_dejitter->rtpRecv(marker,typ,m_tsLast,pc,len))
334 m_ioLostPkt++;
335 return;
336 }
337 if (ds > 1)
338 m_ioLostPkt += (ds - 1);
339 if (ds >= 1)
340 rtpRecv(marker,typ,m_tsLast,pc,len);
341 }
342
rtcpData(const void * data,int len)343 void RTPReceiver::rtcpData(const void* data, int len)
344 {
345 }
346
rtpRecv(bool marker,int payload,unsigned int timestamp,const void * data,int len)347 bool RTPReceiver::rtpRecv(bool marker, int payload, unsigned int timestamp, const void* data, int len)
348 {
349 if ((payload != dataPayload()) && (payload != eventPayload()) && (payload != silencePayload()))
350 rtpNewPayload(payload,timestamp);
351 if (payload == eventPayload())
352 return decodeEvent(marker,timestamp,data,len);
353 if (payload == silencePayload())
354 return decodeSilence(marker,timestamp,data,len);
355 finishEvent(timestamp);
356 if (payload == dataPayload())
357 return rtpRecvData(marker,timestamp,data,len);
358 return false;
359 }
360
rtpRecvData(bool marker,unsigned int timestamp,const void * data,int len)361 bool RTPReceiver::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len)
362 {
363 return m_session && m_session->rtpRecvData(marker,timestamp,data,len);
364 }
365
rtpRecvEvent(int event,char key,int duration,int volume,unsigned int timestamp)366 bool RTPReceiver::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp)
367 {
368 return m_session && m_session->rtpRecvEvent(event,key,duration,volume,timestamp);
369 }
370
rtpNewPayload(int payload,unsigned int timestamp)371 void RTPReceiver::rtpNewPayload(int payload, unsigned int timestamp)
372 {
373 if (m_session)
374 m_session->rtpNewPayload(payload,timestamp);
375 }
376
rtpNewSSRC(u_int32_t newSsrc,bool marker)377 void RTPReceiver::rtpNewSSRC(u_int32_t newSsrc, bool marker)
378 {
379 if (m_session)
380 m_session->rtpNewSSRC(newSsrc,marker);
381 }
382
decodeEvent(bool marker,unsigned int timestamp,const void * data,int len)383 bool RTPReceiver::decodeEvent(bool marker, unsigned int timestamp, const void* data, int len)
384 {
385 // we support only basic RFC2833, no RFC2198 redundancy
386 if (len < 4)
387 return false;
388 const unsigned char* pc = (const unsigned char*)data;
389 for (; len >= 4; len-=4, pc+=4) {
390 int event = pc[0];
391 int vol = pc[1] & 0x3f;
392 bool end = (pc[1] & 0x80) != 0;
393 int duration = ((int)pc[2] << 8) | pc[3];
394 if (m_evTs && (m_evNum >= 0)) {
395 if ((m_evNum != event) && (m_evTs <= timestamp)) {
396 if (m_debugEvent)
397 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
398 "RTP recv ending current event (event/ts changed) event=%d (received=%d) "
399 "ts=%u event_ts=%u duration=%u [%p]",
400 m_evNum,event,timestamp,m_evTs,timestamp - m_evTs,this);
401 pushEvent(m_evNum,timestamp - m_evTs,m_evVol,m_evTs);
402 }
403 }
404 m_evVol = vol;
405 if (m_debugEvent) {
406 const char* oper = "start";
407 if (end)
408 oper = "end";
409 else if (m_evNum >= 0)
410 oper = "update";
411 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
412 "RTP recv event oper=%s event=%d (old=%d) ts=%u event_ts=%u duration=%u [%p]",
413 oper,event,m_evNum,timestamp,m_evTs,duration,this);
414 }
415 if (!end) {
416 m_evTs = timestamp;
417 m_evNum = event;
418 continue;
419 }
420 if (m_evTs > timestamp)
421 return false;
422 // make sure we don't see the same event again
423 m_evTs = timestamp+1;
424 m_evNum = -1;
425 pushEvent(event,duration,vol,timestamp);
426 }
427 return true;
428 }
429
decodeSilence(bool marker,unsigned int timestamp,const void * data,int len)430 bool RTPReceiver::decodeSilence(bool marker, unsigned int timestamp, const void* data, int len)
431 {
432 return false;
433 }
434
finishEvent(unsigned int timestamp)435 void RTPReceiver::finishEvent(unsigned int timestamp)
436 {
437 if ((m_evNum < 0) || !m_evTs)
438 return;
439 int duration = timestamp - m_evTs;
440 if (duration < 10000)
441 return;
442 if (m_debugEvent)
443 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
444 "RTP recv finishing event=%d ts=%u event_ts=%u duration=%u [%p]",
445 m_evNum,timestamp,m_evTs,duration,this);
446 timestamp = m_evTs;
447 m_evTs = 0;
448 pushEvent(m_evNum,duration,m_evVol,timestamp);
449 }
450
pushEvent(int event,int duration,int volume,unsigned int timestamp)451 bool RTPReceiver::pushEvent(int event, int duration, int volume, unsigned int timestamp)
452 {
453 static const char dtmf[] = "0123456789*#ABCDF";
454 char key = (event <= 16) ? dtmf[event] : 0;
455 return rtpRecvEvent(event,key,duration,volume,timestamp);
456 }
457
timerTick(const Time & when)458 void RTPReceiver::timerTick(const Time& when)
459 {
460 }
461
rtpDecipher(unsigned char * data,int len,const void * secData,u_int32_t ssrc,u_int64_t seq)462 bool RTPReceiver::rtpDecipher(unsigned char* data, int len, const void* secData, u_int32_t ssrc, u_int64_t seq)
463 {
464 return (m_secure)
465 ? m_secure->rtpDecipher(data,len,secData,ssrc,seq)
466 : true;
467 }
468
rtpCheckIntegrity(const unsigned char * data,int len,const void * authData,u_int32_t ssrc,u_int64_t seq)469 bool RTPReceiver::rtpCheckIntegrity(const unsigned char* data, int len, const void* authData, u_int32_t ssrc, u_int64_t seq)
470 {
471 return (m_secure)
472 ? m_secure->rtpCheckIntegrity(data,len,authData,ssrc,seq)
473 : true;
474 }
475
stats(NamedList & stat) const476 void RTPReceiver::stats(NamedList& stat) const
477 {
478 if (m_session)
479 stat.setParam("remoteip",m_session->UDPSession::transport()->remoteAddr().host());
480 stat.setParam("lostpkts",String(m_ioLostPkt));
481 stat.setParam("synclost",String(m_syncLost));
482 stat.setParam("wrongssrc",String(m_wrongSSRC));
483 stat.setParam("seqslost",String(m_seqLost));
484 }
485
486
RTPSender(RTPSession * session,bool randomTs)487 RTPSender::RTPSender(RTPSession* session, bool randomTs)
488 : RTPBaseIO(session), m_evTime(0), m_padding(0)
489 {
490 if (randomTs) {
491 m_ts = Random::random() & ~1;
492 // avoid starting sequence numbers too close to zero
493 m_seq = (uint16_t)(2500 + (Random::random() % 60000));
494 }
495 }
496
rtpSend(bool marker,int payload,unsigned int timestamp,const void * data,int len)497 bool RTPSender::rtpSend(bool marker, int payload, unsigned int timestamp, const void* data, int len)
498 {
499 if (m_debugData) {
500 const char* oper = "send";
501 if (!(m_session && m_session->UDPSession::transport()))
502 oper = "not sending";
503 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
504 "RTP %s seq=%u payload=%d ts=%u len=%u [%p]",
505 oper,(m_seq + 1),payload,timestamp,(data ? len : 0),this);
506 }
507
508 if (!(m_session && m_session->UDPSession::transport()))
509 return false;
510
511 if (!data)
512 len = 0;
513 payload &= 0x7f;
514 if (marker || m_ssrcInit)
515 payload |= 0x80;
516 m_tsLast = timestamp;
517 timestamp += m_ts;
518 ssrcInit();
519 m_seq++;
520 if (m_seq == 0)
521 m_rollover++;
522 m_ioPackets++;
523 m_ioOctets += len;
524
525 unsigned char padding = 0;
526 unsigned char byte1 = 0x80;
527 if (m_padding > 1) {
528 padding = len % m_padding;
529 if (padding) {
530 padding = m_padding - padding;
531 byte1 |= 0x20;
532 }
533 }
534
535 m_buffer.resize(len + padding + m_secLen + 12);
536 unsigned char* pc = (unsigned char*)m_buffer.data();
537 if (padding)
538 pc[len + padding + 11] = padding;
539 *pc++ = byte1;
540 *pc++ = payload;
541 *pc++ = (unsigned char)(m_seq >> 8);
542 *pc++ = (unsigned char)(m_seq & 0xff);
543 *pc++ = (unsigned char)(timestamp >> 24);
544 *pc++ = (unsigned char)(timestamp >> 16);
545 *pc++ = (unsigned char)(timestamp >> 8);
546 *pc++ = (unsigned char)(timestamp & 0xff);
547 *pc++ = (unsigned char)(m_ssrc >> 24);
548 *pc++ = (unsigned char)(m_ssrc >> 16);
549 *pc++ = (unsigned char)(m_ssrc >> 8);
550 *pc++ = (unsigned char)(m_ssrc & 0xff);
551 if (data && len) {
552 ::memcpy(pc,data,len);
553 rtpEncipher(pc,len + padding);
554 }
555 if (m_secLen)
556 rtpAddIntegrity((const unsigned char*)m_buffer.data(),len + padding + 12,pc + (len + padding + m_mkiLen));
557 static_cast<RTPProcessor*>(m_session->UDPSession::transport())->rtpData(m_buffer.data(),m_buffer.length());
558 return true;
559 }
560
rtpSendData(bool marker,unsigned int timestamp,const void * data,int len)561 bool RTPSender::rtpSendData(bool marker, unsigned int timestamp, const void* data, int len)
562 {
563 if (dataPayload() < 0)
564 return false;
565 if (sendEventData(timestamp))
566 return true;
567 return rtpSend(marker,dataPayload(),timestamp,data,len);
568 }
569
rtpSendEvent(int event,int duration,int volume,unsigned int timestamp)570 bool RTPSender::rtpSendEvent(int event, int duration, int volume, unsigned int timestamp)
571 {
572 // send as RFC2833 if we have the payload type set
573 if (eventPayload() < 0)
574 return false;
575 if ((duration <= 50) || (duration > 10000))
576 duration = 1600;
577 if (!timestamp)
578 timestamp = m_tsLast;
579 if (m_evTs) {
580 TraceDebug(m_traceId,dbg(),DebugNote,"RFC 2833 overlapped in RTP event %d, session %p, fixing.",
581 event,m_session);
582 // the timestamp must always advance to avoid misdetections
583 if (timestamp == m_evTs)
584 m_tsLast = timestamp = timestamp + 2;
585 // make sure we send an event end packet
586 m_evTime = 0;
587 sendEventData(timestamp);
588 }
589 m_evTs = timestamp;
590 m_evNum = event;
591 m_evVol = volume;
592 m_evTime = duration;
593 m_evSeq = 0;
594 return sendEventData(timestamp);
595 }
596
rtpSendKey(char key,int duration,int volume,unsigned int timestamp)597 bool RTPSender::rtpSendKey(char key, int duration, int volume, unsigned int timestamp)
598 {
599 int event = 0;
600 if ((key >= '0') && (key <= '9'))
601 event = key - '0';
602 else if (key == '*')
603 event = 10;
604 else if (key == '#')
605 event = 11;
606 else if ((key >= 'A') && (key <= 'D'))
607 event = key + 12 - 'A';
608 else if ((key >= 'a') && (key <= 'd'))
609 event = key + 12 - 'a';
610 else if ((key == 'F') || (key == 'f'))
611 event = 16;
612 else
613 return false;
614 return rtpSendEvent(event,duration,volume,timestamp);
615 }
616
sendEventData(unsigned int timestamp)617 bool RTPSender::sendEventData(unsigned int timestamp)
618 {
619 if (m_evTs) {
620 if (eventPayload() < 0) {
621 m_evTs = 0;
622 return false;
623 }
624 if (timestamp <= m_tsLast && m_evSeq) {
625 if (m_debugEvent)
626 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
627 "RTP send event %d timestamp=%u before last ts=%u - ignoring [%p]",
628 m_evNum,timestamp,m_evTs,this);
629 else
630 DDebug(dbg(),DebugNote,
631 "RTP send event %d timestamp=%u before last ts=%u - ignoring [%p]",
632 m_evNum,timestamp,m_evTs,this);
633 return true;
634 }
635 m_evSeq++;
636 int duration = timestamp - m_evTs;
637 char end = (duration >= m_evTime) ? 0x80 : 0x00;
638 if (m_debugEvent)
639 TraceDebug(m_traceId,dbg(),m_debugDataLevel,
640 "RTP send event=%d ts=%u event_ts=%u duration=%u ev_duration=%u ev_seq=%u end=%s [%p]",
641 m_evNum,timestamp,m_evTs,duration,m_evTime,m_evSeq,String::boolText(0 != end),this);
642 if (end)
643 duration = m_evTime;
644 char buf[4];
645 buf[0] = m_evNum;
646 buf[1] = (m_evVol & 0x7f) | end;
647 buf[2] = duration >> 8;
648 buf[3] = duration & 0xff;
649 unsigned int tstamp = m_evTs;
650 if (end) {
651 m_evTs = 0;
652 // repeat the event end packet to increase chances it gets seen
653 if (rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf)))
654 m_seq--;
655 }
656 bool ok = rtpSend(!duration,eventPayload(),tstamp,buf,sizeof(buf));
657 // have to update last timestamp since we sent the event start stamp
658 m_tsLast = timestamp;
659 return ok;
660 }
661 return false;
662 }
663
padding(int chunk)664 bool RTPSender::padding(int chunk)
665 {
666 if ((chunk < 0) || (chunk > 128))
667 return false;
668 m_padding = chunk;
669 return true;
670 }
671
timerTick(const Time & when)672 void RTPSender::timerTick(const Time& when)
673 {
674 }
675
rtpEncipher(unsigned char * data,int len)676 void RTPSender::rtpEncipher(unsigned char* data, int len)
677 {
678 if (m_secure)
679 m_secure->rtpEncipher(data,len);
680 }
681
rtpAddIntegrity(const unsigned char * data,int len,unsigned char * authData)682 void RTPSender::rtpAddIntegrity(const unsigned char* data, int len, unsigned char* authData)
683 {
684 if (m_secure)
685 m_secure->rtpAddIntegrity(data,len,authData);
686 }
687
stats(NamedList & stat) const688 void RTPSender::stats(NamedList& stat) const
689 {
690 }
691
692
UDPSession(DebugEnabler * dbg,const char * traceId)693 UDPSession::UDPSession(DebugEnabler* dbg, const char* traceId)
694 : RTPProcessor(dbg,traceId),
695 m_transport(0), m_timeoutTime(0), m_timeoutInterval(0)
696 {
697 DDebug(this->dbg(),DebugAll,"UDPSession::UDPSession() [%p]",this);
698 }
699
~UDPSession()700 UDPSession::~UDPSession()
701 {
702 DDebug(dbg(),DebugAll,"UDPSession::~UDPSession() [%p]",this);
703 group(0);
704 transport(0);
705 }
706
timeout(bool initial)707 void UDPSession::timeout(bool initial)
708 {
709 DDebug(dbg(),DebugNote,"UDPSession::timeout(%s) [%p]",String::boolText(initial),this);
710 }
711
transport(RTPTransport * trans)712 void UDPSession::transport(RTPTransport* trans)
713 {
714 DDebug(dbg(),DebugInfo,"UDPSession::transport(%p) old=%p [%p]",trans,m_transport,this);
715 if (trans == m_transport)
716 return;
717 TelEngine::destruct(m_transport);
718 m_transport = trans;
719 if (m_transport)
720 m_transport->setProcessor(this);
721 }
722
createTransport()723 RTPTransport* UDPSession::createTransport()
724 {
725 RTPTransport* trans = new RTPTransport(RTPTransport::RTP,dbg(),m_traceId);
726 trans->group(group());
727 return trans;
728 }
729
initGroup(int msec,Thread::Priority prio,const String & affinity)730 bool UDPSession::initGroup(int msec, Thread::Priority prio, const String& affinity)
731 {
732 if (m_group)
733 return true;
734 // try to pick the group from the transport if it has one
735 if (m_transport)
736 group(m_transport->group());
737 if (!m_group)
738 group(new RTPGroup(msec,prio,affinity));
739 if (!m_group)
740 return false;
741 if (m_transport)
742 m_transport->group(m_group);
743 return true;
744 }
745
initTransport()746 bool UDPSession::initTransport()
747 {
748 if (m_transport)
749 return true;
750 transport(createTransport());
751 return (m_transport != 0);
752 }
753
setTimeout(int interval)754 void UDPSession::setTimeout(int interval)
755 {
756 if (interval) {
757 if (interval < 0)
758 interval = 0;
759 // force sane limits: between 500ms and 60s
760 else if (interval < 500)
761 interval = 500;
762 else if (interval > 60000)
763 interval = 60000;
764 }
765 m_timeoutTime = 0;
766 m_timeoutInterval = interval * (u_int64_t)1000;
767 }
768
769
RTPSession(DebugEnabler * dbg,const char * traceId)770 RTPSession::RTPSession(DebugEnabler* dbg, const char* traceId)
771 : UDPSession(dbg,traceId), Mutex(true,"RTPSession"),
772 m_direction(FullStop),
773 m_send(0), m_recv(0), m_secure(0),
774 m_reportTime(0), m_reportInterval(0),
775 m_warnSeq(1)
776 {
777 DDebug(this->dbg(),DebugInfo,"RTPSession::RTPSession() [%p]",this);
778 }
779
~RTPSession()780 RTPSession::~RTPSession()
781 {
782 DDebug(dbg(),DebugInfo,"RTPSession::~RTPSession() [%p]",this);
783 direction(FullStop);
784 group(0);
785 transport(0);
786 TelEngine::destruct(m_secure);
787 }
788
timerTick(const Time & when)789 void RTPSession::timerTick(const Time& when)
790 {
791 if (m_send)
792 static_cast<RTPBaseIO*>(m_send)->timerTick(when);
793 if (m_recv)
794 static_cast<RTPBaseIO*>(m_recv)->timerTick(when);
795
796 if (m_timeoutInterval) {
797 // only check timeout if we have a receiver
798 if (m_timeoutTime && m_recv) {
799 if (when >= m_timeoutTime) {
800 // rearm timeout next time we get a packet
801 m_timeoutTime = INF_TIMEOUT;
802 timeout(0 == m_recv->ssrc());
803 }
804 }
805 else
806 m_timeoutTime = when + m_timeoutInterval;
807 }
808 if (m_reportInterval) {
809 if (when >= m_reportTime) {
810 m_reportTime = when + m_reportInterval;
811 sendRtcpReport(when);
812 }
813 }
814 }
815
rtpData(const void * data,int len)816 void RTPSession::rtpData(const void* data, int len)
817 {
818 if ((m_direction & RecvOnly) == 0)
819 return;
820 if (m_recv) {
821 m_timeoutTime = 0;
822 m_recv->rtpData(data,len);
823 }
824 }
825
rtcpData(const void * data,int len)826 void RTPSession::rtcpData(const void* data, int len)
827 {
828 if ((m_direction & RecvOnly) == 0)
829 return;
830 if (m_recv) {
831 if ((m_timeoutTime != INF_TIMEOUT) || m_recv->ssrc())
832 m_timeoutTime = 0;
833 m_recv->rtcpData(data,len);
834 }
835 }
836
rtpRecvData(bool marker,unsigned int timestamp,const void * data,int len)837 bool RTPSession::rtpRecvData(bool marker, unsigned int timestamp, const void* data, int len)
838 {
839 XDebug(dbg(),DebugAll,"RTPSession::rtpRecv(%s,%u,%p,%d) [%p]",
840 String::boolText(marker),timestamp,data,len,this);
841 return false;
842 }
843
rtpRecvEvent(int event,char key,int duration,int volume,unsigned int timestamp)844 bool RTPSession::rtpRecvEvent(int event, char key, int duration, int volume, unsigned int timestamp)
845 {
846 XDebug(dbg(),DebugAll,"RTPSession::rtpRecvEvent(%d,%02x,%d,%d,%u) [%p]",
847 event,key,duration,volume,timestamp,this);
848 return false;
849 }
850
rtpNewPayload(int payload,unsigned int timestamp)851 void RTPSession::rtpNewPayload(int payload, unsigned int timestamp)
852 {
853 XDebug(dbg(),DebugAll,"RTPSession::rtpNewPayload(%d,%u) [%p]",
854 payload,timestamp,this);
855 }
856
rtpNewSSRC(u_int32_t newSsrc,bool marker)857 void RTPSession::rtpNewSSRC(u_int32_t newSsrc,bool marker)
858 {
859 XDebug(dbg(),DebugAll,"RTPSession::rtpNewSSRC(%08X,%s) [%p]",
860 newSsrc,String::boolText(marker),this);
861 }
862
createSender()863 RTPSender* RTPSession::createSender()
864 {
865 return new RTPSender(this);
866 }
867
createReceiver()868 RTPReceiver* RTPSession::createReceiver()
869 {
870 return new RTPReceiver(this);
871 }
872
createCipher(const String & name,Cipher::Direction dir)873 Cipher* RTPSession::createCipher(const String& name, Cipher::Direction dir)
874 {
875 return 0;
876 }
877
checkCipher(const String & name)878 bool RTPSession::checkCipher(const String& name)
879 {
880 return false;
881 }
882
transport(RTPTransport * trans)883 void RTPSession::transport(RTPTransport* trans)
884 {
885 if (!trans)
886 sendRtcpBye();
887 UDPSession::transport(trans);
888 if (!m_transport)
889 m_direction = FullStop;
890 }
891
sender(RTPSender * send)892 void RTPSession::sender(RTPSender* send)
893 {
894 DDebug(dbg(),DebugInfo,"RTPSession::sender(%p) old=%p [%p]",send,m_send,this);
895 if (send == m_send)
896 return;
897 sendRtcpBye();
898 RTPSender* tmp = m_send;
899 m_send = send;
900 if (tmp)
901 delete tmp;
902 if (m_send && m_secure) {
903 RTPSecure* sec = m_secure;
904 m_secure = 0;
905 m_send->security(sec);
906 }
907 }
908
receiver(RTPReceiver * recv)909 void RTPSession::receiver(RTPReceiver* recv)
910 {
911 DDebug(dbg(),DebugInfo,"RTPSession::receiver(%p) old=%p [%p]",recv,m_recv,this);
912 if (recv == m_recv)
913 return;
914 RTPReceiver* tmp = m_recv;
915 m_recv = recv;
916 if (tmp)
917 delete tmp;
918 if (m_recv)
919 m_recv->m_warnSeq = m_warnSeq;
920 }
921
security(RTPSecure * secure)922 void RTPSession::security(RTPSecure* secure)
923 {
924 if (m_send)
925 m_send->security(secure);
926 else if (secure != m_secure) {
927 TelEngine::destruct(m_secure);
928 m_secure = secure;
929 }
930 }
931
direction(Direction dir)932 bool RTPSession::direction(Direction dir)
933 {
934 DDebug(dbg(),DebugInfo,"RTPSession::direction(%d) old=%d [%p]",dir,m_direction,this);
935 if ((dir != FullStop) && !m_transport)
936 return false;
937
938 if (dir & RecvOnly) {
939 if (!m_recv)
940 receiver(createReceiver());
941 }
942 else
943 receiver(0);
944
945 if (dir & SendOnly) {
946 if (!m_send)
947 sender(createSender());
948 }
949 else
950 sender(0);
951
952 m_direction = dir;
953 return true;
954 }
955
dataPayload(int type)956 bool RTPSession::dataPayload(int type)
957 {
958 if (m_recv || m_send) {
959 DDebug(dbg(),DebugInfo,"RTPSession::dataPayload(%d) [%p]",type,this);
960 bool ok = (!m_recv) || m_recv->dataPayload(type);
961 return ((!m_send) || m_send->dataPayload(type)) && ok;
962 }
963 return false;
964 }
965
eventPayload(int type)966 bool RTPSession::eventPayload(int type)
967 {
968 if (m_recv || m_send) {
969 DDebug(dbg(),DebugInfo,"RTPSession::eventPayload(%d) [%p]",type,this);
970 bool ok = (!m_recv) || m_recv->eventPayload(type);
971 return ((!m_send) || m_send->eventPayload(type)) && ok;
972 }
973 return false;
974 }
975
silencePayload(int type)976 bool RTPSession::silencePayload(int type)
977 {
978 if (m_recv || m_send) {
979 DDebug(dbg(),DebugInfo,"RTPSession::silencePayload(%d) [%p]",type,this);
980 bool ok = (!m_recv) || m_recv->silencePayload(type);
981 return ((!m_send) || m_send->silencePayload(type)) && ok;
982 }
983 return false;
984 }
985
getStats(String & stats) const986 void RTPSession::getStats(String& stats) const
987 {
988 DDebug(dbg(),DebugInfo,"RTPSession::getStats() tx=%p rx=%p [%p]",m_send,m_recv,this);
989 if (m_send) {
990 stats.append("PS=",",") << m_send->ioPackets();
991 stats << ",OS=" << m_send->ioOctets();
992 }
993 if (m_recv) {
994 stats.append("PR=",",") << m_recv->ioPackets();
995 stats << ",OR=" << m_recv->ioOctets();
996 stats << ",PL=" << m_recv->ioPacketsLost();
997 }
998 }
999
setReports(int interval)1000 void RTPSession::setReports(int interval)
1001 {
1002 if (interval > 0 && m_transport && m_transport->rtcpSock()->valid()) {
1003 if (interval < 500)
1004 interval = 500;
1005 else if (interval > 60000)
1006 interval = 60000;
1007 m_reportInterval = interval * (u_int64_t)1000 + (Random::random() % 20000);
1008 }
1009 else
1010 m_reportInterval = 0;
1011 m_reportTime = 0;
1012 }
1013
getStats(NamedList & stats) const1014 void RTPSession::getStats(NamedList& stats) const
1015 {
1016 if (m_send)
1017 m_send->stats(stats);
1018 if (m_recv)
1019 m_recv->stats(stats);
1020 stats.setParam("wrongsrc",String(m_wrongSrc));
1021 }
1022
store32(unsigned char * buf,unsigned int & len,u_int32_t val)1023 static void store32(unsigned char* buf, unsigned int& len, u_int32_t val)
1024 {
1025 buf[len++] = (unsigned char)(val >> 24);
1026 buf[len++] = (unsigned char)(val >> 16);
1027 buf[len++] = (unsigned char)(val >> 8);
1028 buf[len++] = (unsigned char)(val & 0xff);
1029 }
1030
sendRtcpReport(const Time & when)1031 void RTPSession::sendRtcpReport(const Time& when)
1032 {
1033 if (!((m_send || m_recv) && m_transport && m_transport->rtcpSock()->valid()))
1034 return;
1035 unsigned char buf[52];
1036 buf[0] = 0x80; // RC=0
1037 buf[1] = 0xc9; // RR
1038 buf[2] = 0;
1039 unsigned int len = 8;
1040 if (m_send && m_send->ioPackets()) {
1041 // Include a sender report
1042 buf[1] = 0xc8; // SR
1043 // NTP timestamp
1044 store32(buf,len,(uint32_t)(2208988800ULL + (when.usec() / 1000000)));
1045 store32(buf,len,(uint32_t)(((when.usec() % 1000000) << 32) / 1000000));
1046 // RTP timestamp
1047 store32(buf,len,m_send->tsLast());
1048 // Packet and octet counters
1049 store32(buf,len,m_send->ioPackets());
1050 store32(buf,len,m_send->ioOctets());
1051 }
1052 if (m_recv && m_recv->ioPackets()) {
1053 // Add a single receiver report
1054 buf[0] |= 0x01; // RC=1
1055 store32(buf,len,m_recv->ssrc());
1056 u_int32_t lost = m_recv->ioPacketsLost();
1057 u_int32_t lostf = 0xff & (lost * 255 / (lost + m_recv->ioPackets()));
1058 store32(buf,len,(lost & 0xffffff) | (lostf << 24));
1059 store32(buf,len,(uint32_t)m_recv->fullSeq());
1060 // TODO: Compute and store Jitter, LSR and DLSR
1061 store32(buf,len,0);
1062 store32(buf,len,0);
1063 store32(buf,len,0);
1064 }
1065 // Don't send a RR with no receiver report blocks...
1066 if (len <= 8)
1067 return;
1068 DDebug(dbg(),DebugInfo,"RTPSession sending RTCP Report [%p]",this);
1069 unsigned int lptr = 4;
1070 store32(buf,lptr,(m_send ? m_send->ssrcInit() : 0));
1071 buf[3] = (len - 1) / 4; // same as ((len + 3) / 4) - 1
1072 static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,len);
1073 }
1074
sendRtcpBye()1075 void RTPSession::sendRtcpBye()
1076 {
1077 if (!(m_send && m_transport && m_transport->rtcpSock()->valid()))
1078 return;
1079 u_int32_t ssrc = m_send->ssrc();
1080 if (!ssrc)
1081 return;
1082 DDebug(dbg(),DebugInfo,"RTPSession sending RTCP Bye [%p]",this);
1083 // SSRC was initialized if we sent at least one RTP or RTCP packet
1084 unsigned char buf[8];
1085 buf[0] = 0x81;
1086 buf[1] = 0xcb;
1087 buf[2] = 0;
1088 buf[3] = 1; // len = 2 x 32bit
1089 buf[4] = (unsigned char)(ssrc >> 24);
1090 buf[5] = (unsigned char)(ssrc >> 16);
1091 buf[6] = (unsigned char)(ssrc >> 8);
1092 buf[7] = (unsigned char)(0xff & ssrc);
1093 static_cast<RTPProcessor*>(m_transport)->rtcpData(buf,8);
1094 }
1095
incWrongSrc()1096 void RTPSession::incWrongSrc()
1097 {
1098 XDebug(dbg(),DebugAll,"RTPSession::incWrongSrc() [%p]",this);
1099 m_wrongSrc++;
1100 }
1101
1102
UDPTLSession(u_int16_t maxLen,u_int8_t maxSec,DebugEnabler * dbg,const char * traceId)1103 UDPTLSession::UDPTLSession(u_int16_t maxLen, u_int8_t maxSec, DebugEnabler* dbg, const char* traceId)
1104 : UDPSession(dbg,traceId), Mutex(true,"UDPTLSession"),
1105 m_rxSeq(0xffff), m_txSeq(0xffff),
1106 m_maxLen(maxLen), m_maxSec(maxSec),
1107 m_warn(true)
1108 {
1109 DDebug(this->dbg(),DebugInfo,"UDPTLSession::UDPTLSession(%u,%u) [%p]",maxLen,maxSec,this);
1110 if (m_maxLen < 96)
1111 m_maxLen = 96;
1112 else if (m_maxLen > 1492)
1113 m_maxLen = 1492;
1114 }
1115
~UDPTLSession()1116 UDPTLSession::~UDPTLSession()
1117 {
1118 DDebug(dbg(),DebugInfo,"UDPTLSession::~UDPTLSession() [%p]",this);
1119 }
1120
timerTick(const Time & when)1121 void UDPTLSession::timerTick(const Time& when)
1122 {
1123 if (m_timeoutInterval) {
1124 if (m_timeoutTime) {
1125 if (when >= m_timeoutTime) {
1126 // rearm timeout next time we get a packet
1127 m_timeoutTime = INF_TIMEOUT;
1128 timeout(0xffff == m_rxSeq);
1129 }
1130 }
1131 else
1132 m_timeoutTime = when + m_timeoutInterval;
1133 }
1134 }
1135
createTransport()1136 RTPTransport* UDPTLSession::createTransport()
1137 {
1138 RTPTransport* trans = new RTPTransport(RTPTransport::UDPTL,dbg(),m_traceId);
1139 trans->group(group());
1140 return trans;
1141 }
1142
rtpData(const void * data,int len)1143 void UDPTLSession::rtpData(const void* data, int len)
1144 {
1145 if ((len < 6) || !data)
1146 return;
1147 m_timeoutTime = 0;
1148 const unsigned char* pd = (const unsigned char*)data;
1149 int pLen = pd[2];
1150 if (pLen > (len-5)) {
1151 // primary IFP does not fit in packet
1152 if ((m_rxSeq == 0xffff) && ((pd[0] & 0xc0) == 0x80) && m_warn) {
1153 m_warn = false;
1154 TraceDebug(m_traceId,dbg(),DebugWarn,"Receiving RTP instead of UDPTL [%p]",this);
1155 }
1156 return;
1157 }
1158 u_int16_t seq = pd[1] + (((u_int16_t)pd[0]) << 8);
1159 // substraction with overflow
1160 int16_t ds = seq - m_rxSeq;
1161 if ((m_rxSeq == 0xffff) && (seq != 0)) {
1162 // received sequence does not start at zero
1163 if ((pd[0] & 0xc0) == 0x80) {
1164 if (m_warn) {
1165 m_warn = false;
1166 TraceDebug(m_traceId,dbg(),DebugWarn,"Receiving RTP instead of UDPTL [%p]",this);
1167 }
1168 return;
1169 }
1170 ds = 1;
1171 }
1172 if (ds < 0) {
1173 // received old packet
1174 if (m_warn) {
1175 m_warn = false;
1176 TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL received SEQ %u while current is %u [%p]",seq,m_rxSeq,this);
1177 }
1178 return;
1179 }
1180 m_warn = true;
1181 if (ds > 1) {
1182 // some packets were lost, try to recover
1183 if (0 == pd[pLen+3])
1184 // recover from secondary IFPs
1185 recoverSec(pd+pLen+5,len-pLen-5,seq-1,pd[pLen+4]);
1186 }
1187 m_rxSeq = seq;
1188 udptlRecv(pd+3,pLen,seq,false);
1189 }
1190
recoverSec(const unsigned char * data,int len,u_int16_t seq,int nSec)1191 void UDPTLSession::recoverSec(const unsigned char* data, int len, u_int16_t seq, int nSec)
1192 {
1193 if ((nSec <= 0) || (len <= 1))
1194 return;
1195 if ((int16_t)(seq - m_rxSeq) <= 0)
1196 return;
1197 int sLen = data[0];
1198 if (sLen >= len)
1199 return;
1200 // recursively recover from remaining secondaries
1201 recoverSec(data+sLen+1,len-sLen-1,seq-1,nSec-1);
1202 int16_t ds = seq - m_rxSeq;
1203 switch (ds) {
1204 case 1:
1205 break;
1206 case 2:
1207 TraceDebug(m_traceId,dbg(),DebugMild,"UDPTL lost IFP with SEQ %u [%p]",m_rxSeq+1,this);
1208 break;
1209 default:
1210 TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL lost IFPs with SEQ %u-%u [%p]",m_rxSeq+1,seq-1,this);
1211 break;
1212 }
1213 TraceDebug(m_traceId,dbg(),DebugInfo,"UDPTL recovered IFP with SEQ %u [%p]",seq,this);
1214 m_rxSeq = seq;
1215 udptlRecv(data+1,sLen,seq,true);
1216 }
1217
udptlSend(const void * data,int len,u_int16_t seq)1218 bool UDPTLSession::udptlSend(const void* data, int len, u_int16_t seq)
1219 {
1220 if (!(UDPSession::transport() && data && len))
1221 return false;
1222 Lock lck(this);
1223 int pl = len + 5;
1224 if ((len > 255) || (pl > m_maxLen)) {
1225 TraceDebug(m_traceId,dbg(),DebugWarn,"UDPTL could not send IFP with len=%d [%p]",len,this);
1226 m_txQueue.clear();
1227 return false;
1228 }
1229 // substraction with overflow
1230 int16_t ds = seq - m_txSeq;
1231 if (ds != 0) {
1232 if (ds != 1) {
1233 TraceDebug(m_traceId,dbg(),DebugInfo,"UDPTL sending SEQ %u while current is %u [%p]",seq,m_txSeq,this);
1234 m_txQueue.clear();
1235 }
1236 if (m_maxSec)
1237 m_txQueue.insert(new DataBlock(const_cast<void*>(data),len));
1238 }
1239 DataBlock buf(0,m_maxLen);
1240 unsigned char* pd = buf.data(0,6);
1241 if (!pd)
1242 return false;
1243 pd[0] = (seq >> 8) & 0xff;
1244 pd[1] = seq & 0xff;
1245 pd[2] = len & 0xff;
1246 ::memcpy(pd+3,data,len);
1247 pd[len+3] = 0; // secondary IFPs
1248 int nSec = 0;
1249 for (ObjList* l = m_txQueue.skipNext(); l; l = l->skipNext()) {
1250 // truncate the TX queue when reaching maximum packet length or IFP count
1251 if (nSec >= m_maxSec) {
1252 l->clear();
1253 break;
1254 }
1255 DataBlock* d = static_cast<DataBlock*>(l->get());
1256 if ((pl+d->length()+1) > m_maxLen) {
1257 l->clear();
1258 break;
1259 }
1260 pd[pl] = d->length() & 0xff;
1261 ::memcpy(pd+pl+1,d->data(),d->length());
1262 pl += d->length()+1;
1263 nSec++;
1264 }
1265 pd[len+4] = nSec;
1266 m_txSeq = seq;
1267 static_cast<RTPProcessor*>(UDPSession::transport())->rtpData(pd,pl);
1268 return true;
1269 }
1270
1271 /* vi: set ts=8 sw=4 sts=4 noet: */
1272