Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / rtp.cxx
blob630c5ecf63267dfc3adb6cb280f87a1ddf3a7c1c
1 /*
2 * rtp.cxx
4 * RTP protocol handler
6 * Open H323 Library
8 * Copyright (c) 1998-2000 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions of this code were written with the assisance of funding from
25 * Vovida Networks, Inc. http://www.vovida.com.
27 * Contributor(s): ______________________________________.
29 * $Log$
30 * Revision 1.106 2006/01/26 03:35:04 shorne
31 * Added more NAT traversal support
33 * Revision 1.105 2006/01/18 07:46:08 csoutheren
34 * Initial version of RTP aggregation (disabled by default)
36 * Revision 1.104 2005/11/21 21:06:23 shorne
37 * Added GQoS switches
39 * Revision 1.103 2005/08/27 02:06:01 csoutheren
40 * Keep track of time first RTP packet is received
42 * Revision 1.102 2005/01/16 20:39:44 csoutheren
43 * Fixed problem with IPv6 INADDR_ANY
45 * Revision 1.101 2005/01/04 08:08:46 csoutheren
46 * More changes to implement the new configuration methodology, and also to
47 * attack the global static problem
49 * Revision 1.100 2005/01/03 14:03:42 csoutheren
50 * Added new configure options and ability to disable/enable modules
52 * Revision 1.99 2005/01/03 06:26:09 csoutheren
53 * Added extensive support for disabling code modules at compile time
55 * Revision 1.98 2004/07/03 06:51:37 rjongbloed
56 * Added PTRACE_PARAM() macro to fix warnings on parameters used in PTRACE
57 * macros only.
59 * Revision 1.97 2004/05/02 18:49:08 ykiryanov
60 * Removed ifdef BeOS to add functionality
62 * Revision 1.96 2004/04/24 23:58:05 rjongbloed
63 * Fixed GCC 3.4 warning about PAssertNULL
65 * Revision 1.95 2004/04/22 12:38:04 rjongbloed
66 * Removed the RTP QoS class if there is no QoS support in build,
67 * thanks Nick Hoath, ISDN Communications Ltd.
69 * Revision 1.94 2004/04/07 05:31:43 csoutheren
70 * Added ability to receive calls from endpoints behind NAT firewalls
72 * Revision 1.93 2004/03/02 10:02:13 rjongbloed
73 * Added check for unusual error in reading UDP socket, thanks Michael Smith
75 * Revision 1.92 2004/02/09 11:17:50 rjongbloed
76 * Improved check for compound RTCP packets so does not possibly acess
77 * memory beyond that allocated in packet. Pointed out by Paul Slootman
79 * Revision 1.91 2003/10/28 22:35:21 dereksmithies
80 * Fix warning about possible use of unitialized variable.
82 * Revision 1.90 2003/10/27 06:03:39 csoutheren
83 * Added support for QoS
84 * Thanks to Henry Harrison of AliceStreet
86 * Revision 1.89 2003/10/09 09:47:45 csoutheren
87 * Fixed problem with re-opening RTP half-channels under unusual
88 * circumstances. Thanks to Damien Sandras
90 * Revision 1.88 2003/05/02 04:57:47 robertj
91 * Added header extension support to RTP data frame class.
93 * Revision 1.87 2003/02/07 00:30:21 robertj
94 * Changes for bizarre usage of RTP code outside of scope of H.323 specs.
96 * Revision 1.86 2003/02/04 23:50:06 robertj
97 * Changed trace log for RTP session creation to show local address.
99 * Revision 1.85 2003/02/04 07:06:42 robertj
100 * Added STUN support.
102 * Revision 1.84 2003/01/07 06:32:22 robertj
103 * Fixed faint possibility of getting an error on UDP write caused by ICMP
104 * unreachable being received when no UDP read is active on the socket. Then
105 * the UDP write gets the error stopping transmission.
107 * Revision 1.83 2002/11/19 01:48:00 robertj
108 * Allowed get/set of canonical anme and tool name.
110 * Revision 1.82 2002/11/05 03:32:04 robertj
111 * Added session ID to trace logs.
112 * Fixed possible extra wait exiting RTP read loop on close.
114 * Revision 1.81 2002/11/05 01:55:50 robertj
115 * Added comments about strange mutex usage.
117 * Revision 1.80 2002/10/31 00:47:07 robertj
118 * Enhanced jitter buffer system so operates dynamically between minimum and
119 * maximum values. Altered API to assure app writers note the change!
121 * Revision 1.79 2002/09/26 04:01:49 robertj
122 * Fixed calculation of fraction of packets lost in RR, thanks Awais Ali
124 * Revision 1.78 2002/09/03 06:15:32 robertj
125 * Added copy constructor/operator for session manager.
127 * Revision 1.77 2002/08/05 10:03:48 robertj
128 * Cosmetic changes to normalise the usage of pragma interface/implementation.
130 * Revision 1.76 2002/07/23 06:28:16 robertj
131 * Added statistics call back on first sent or received RTP packet, helps with,
132 * for example, detecting if remote endpoint has started to send audio.
134 * Revision 1.75 2002/05/28 02:37:55 robertj
135 * Fixed reading data out of RTCP compound statements.
137 * Revision 1.74 2002/05/21 07:12:39 robertj
138 * Fixed 100% CPU usage loop for checkin on sending RTCP data if
139 * have no RTP data transferred at all.
141 * Revision 1.73 2002/05/02 05:58:28 robertj
142 * Changed the mechanism for sending RTCP reports so that they will continue
143 * to be sent regardless of if there is any actual data traffic.
144 * Added support for compound RTCP statements for sender and receiver reports.
146 * Revision 1.72 2002/04/18 05:48:58 robertj
147 * Fixed problem with new SSRC value being ignored after RTP session has
148 * been restarted, thanks "Jacky".
150 * Revision 1.71 2002/02/09 02:33:49 robertj
151 * Improved payload type docuemntation and added Cisco CN.
153 * Revision 1.70 2001/12/20 04:34:56 robertj
154 * Fixed display of some of the unknown RTP types.
156 * Revision 1.69 2001/09/12 07:48:05 robertj
157 * Fixed various problems with tracing.
159 * Revision 1.68 2001/09/11 00:21:24 robertj
160 * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
162 * Revision 1.67 2001/09/10 08:24:04 robertj
163 * Fixed setting of destination RTP address so works with endpoints that
164 * do not get the OLC packets quite right.
166 * Revision 1.66 2001/07/11 03:23:54 robertj
167 * Bug fixed where every 65536 PDUs the session thinks it is the first PDU again.
169 * Revision 1.65 2001/07/06 06:32:24 robertj
170 * Added flag and checks for RTP data having specific SSRC.
171 * Changed transmitter IP address check so is based on first received
172 * PDU instead of expecting it to come from the host we are sending to.
174 * Revision 1.64 2001/06/04 13:43:44 robertj
175 * Fixed I/O block breaker code if RTP session is bound to INADDR_ANY interface.
177 * Revision 1.63 2001/06/04 11:37:50 robertj
178 * Added thread safe enumeration functions of RTP sessions.
179 * Added member access functions to UDP based RTP sessions.
181 * Revision 1.62 2001/05/24 01:12:23 robertj
182 * Fixed sender report timestamp field, thanks Johan Gnosspelius
184 * Revision 1.61 2001/05/08 05:28:02 yurik
185 * No ifdef _WIN32_WCE anymore - 3+ version of SDK allows it
187 * Revision 1.60 2001/04/24 06:15:50 robertj
188 * Added work around for strange Cisco bug which suddenly starts sending
189 * RTP packets beginning at a difference sequence number base.
191 * Revision 1.59 2001/04/02 23:58:24 robertj
192 * Added jitter calculation to RTP session.
193 * Added trace of statistics.
195 * Revision 1.58 2001/03/20 07:24:05 robertj
196 * Changed RTP SDES to have simple host name instead of attempting a
197 * reverse DNS lookup on IP address as badly configured DNS can cause
198 * a 30 second delay before audio is sent.
200 * Revision 1.57 2001/03/15 05:45:45 robertj
201 * Changed, yet again, the setting of RTP info to allow for Cisco idosyncracies.
203 * Revision 1.56 2001/02/21 08:08:26 robertj
204 * Added more debugging.
206 * Revision 1.55 2001/02/09 05:13:56 craigs
207 * Added pragma implementation to (hopefully) reduce the executable image size
208 * under Linux
210 * Revision 1.54 2001/01/28 07:06:59 yurik
211 * WinCE-port - avoid using of IP_TOS
213 * Revision 1.53 2000/12/18 08:59:20 craigs
214 * Added ability to set ports
216 * Revision 1.52 2000/09/25 22:27:40 robertj
217 * Fixed uninitialised variable for lastRRSequenceNumber
219 * Revision 1.51 2000/09/25 01:53:20 robertj
220 * Fixed MSVC warnings.
222 * Revision 1.50 2000/09/25 01:44:13 robertj
223 * Fixed possible race condition on shutdown of RTP session with jitter buffer.
225 * Revision 1.49 2000/09/22 00:32:34 craigs
226 * Added extra logging
227 * Fixed problems with no fastConnect with tunelling
229 * Revision 1.48 2000/09/21 02:06:07 craigs
230 * Added handling for endpoints that return conformant, but useless, RTP address
231 * and port numbers
233 * Revision 1.47 2000/08/17 00:42:39 robertj
234 * Fixed RTP Goodbye message reason string parsing, thanks Thien Nguyen.
236 * Revision 1.46 2000/05/30 10:35:41 robertj
237 * Fixed GNU compiler warning.
239 * Revision 1.45 2000/05/30 06:52:26 robertj
240 * Fixed problem with Cisco restarting sequence numbers when changing H.323 logical channels.
242 * Revision 1.44 2000/05/23 12:57:37 robertj
243 * Added ability to change IP Type Of Service code from applications.
245 * Revision 1.43 2000/05/12 00:27:35 robertj
246 * Fixed bug in UseSession() that caused asserts on BSD and possible race condition everywhere.
248 * Revision 1.42 2000/05/04 11:52:35 robertj
249 * Added Packets Too Late statistics, requiring major rearrangement of jitter
250 * buffer code, not also changes semantics of codec Write() function slightly.
252 * Revision 1.41 2000/05/02 04:32:27 robertj
253 * Fixed copyright notice comment.
255 * Revision 1.40 2000/05/01 01:01:49 robertj
256 * Added flag for what to do with out of orer packets (use if jitter, don't if not).
258 * Revision 1.39 2000/04/30 03:55:09 robertj
259 * Improved the RTCP messages, epecially reports
261 * Revision 1.38 2000/04/28 12:56:39 robertj
262 * Fixed transmission of SDES record in RTCP channel.
264 * Revision 1.37 2000/04/19 01:50:05 robertj
265 * Improved debugging messages.
267 * Revision 1.36 2000/04/13 18:07:39 robertj
268 * Fixed missing mutex release causing possible deadlocks.
270 * Revision 1.35 2000/04/10 17:40:05 robertj
271 * Fixed debug output of RTP payload types to allow for unknown numbers.
273 * Revision 1.34 2000/04/05 04:09:24 robertj
274 * Fixed portability problem with max() macro.
276 * Revision 1.33 2000/04/05 03:17:32 robertj
277 * Added more RTP statistics gathering and H.245 round trip delay calculation.
279 * Revision 1.32 2000/04/03 18:15:44 robertj
280 * Added "fractional" part of RTCP status NTP timestamp field.
282 * Revision 1.31 2000/03/23 02:54:57 robertj
283 * Added sending of SDES control packets.
285 * Revision 1.30 2000/03/20 20:53:42 robertj
286 * Fixed problem with being able to reopen for reading an RTP_Session (Cisco compatibilty)
288 * Revision 1.29 2000/03/04 12:32:23 robertj
289 * Added setting of TOS field in IP header to get poor mans QoS on some routers.
291 * Revision 1.28 2000/02/29 13:00:13 robertj
292 * Added extra statistic display for RTP packets out of order.
294 * Revision 1.27 2000/02/29 02:13:56 robertj
295 * Fixed RTP receive of both control and data, ignores ECONNRESET/ECONNREFUSED errors.
297 * Revision 1.26 2000/02/27 10:56:24 robertj
298 * Fixed error in code allowing non-consecutive RTP port numbers coming from broken stacks, thanks Vassili Leonov.
300 * Revision 1.25 2000/02/17 12:07:44 robertj
301 * Used ne wPWLib random number generator after finding major problem in MSVC rand().
303 * Revision 1.24 2000/01/29 07:10:20 robertj
304 * Fixed problem with RTP transmit to host that is not yet ready causing the
305 * receive side to die with ECONNRESET, thanks Ian MacDonald
307 * Revision 1.23 2000/01/20 05:57:46 robertj
308 * Added extra flexibility in receiving incorrectly formed OpenLogicalChannel PDU's
310 * Revision 1.22 2000/01/14 00:31:40 robertj
311 * Bug fix for RTP port allocation (MSVC optimised version), Thanks to Ian MacDonald.
313 * Revision 1.21 1999/12/30 09:14:49 robertj
314 * Changed payload type functions to use enum.
316 * Revision 1.20 1999/12/23 23:02:36 robertj
317 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
319 * Revision 1.19 1999/11/29 04:50:11 robertj
320 * Added adaptive threshold calculation to silence detection.
322 * Revision 1.18 1999/11/22 00:09:59 robertj
323 * Fixed error in RTP transmit rewrite for ternary state, didn't transmit at all!
325 * Revision 1.17 1999/11/20 05:35:48 robertj
326 * Fixed possibly I/O block in RTP read loops.
328 * Revision 1.16 1999/11/19 13:13:31 robertj
329 * Fixed Windows 95 compatibility issue in shutdown of RTP reading.
331 * Revision 1.15 1999/11/19 10:23:16 robertj
332 * Fixed local binding of socket to correct address on multi-homes systems.
334 * Revision 1.14 1999/11/19 09:17:15 robertj
335 * Fixed problems with aycnhronous shut down of logical channels.
337 * Revision 1.13 1999/11/17 03:49:51 robertj
338 * Added RTP statistics display.
340 * Revision 1.12 1999/11/14 11:41:07 robertj
341 * Added access functions to RTP statistics.
343 * Revision 1.11 1999/10/18 23:55:11 robertj
344 * Fixed bug in setting contributing sources, length put into wrong spot in PDU header
346 * Revision 1.10 1999/09/21 14:10:04 robertj
347 * Removed warnings when no tracing enabled.
349 * Revision 1.9 1999/09/05 00:58:37 robertj
350 * Removed requirement that OpenLogicalChannalAck sessionId match original OLC.
352 * Revision 1.8 1999/09/03 02:17:50 robertj
353 * Added more debugging
355 * Revision 1.7 1999/08/31 12:34:19 robertj
356 * Added gatekeeper support.
358 * Revision 1.6 1999/07/16 02:13:54 robertj
359 * Slowed down the control channel statistics packets.
361 * Revision 1.5 1999/07/13 09:53:24 robertj
362 * Fixed some problems with jitter buffer and added more debugging.
364 * Revision 1.4 1999/07/09 06:09:52 robertj
365 * Major implementation. An ENORMOUS amount of stuff added everywhere.
367 * Revision 1.3 1999/06/22 13:49:40 robertj
368 * Added GSM support and further RTP protocol enhancements.
370 * Revision 1.2 1999/06/14 08:42:52 robertj
371 * Fixed bug in dropped packets display was negative.
373 * Revision 1.1 1999/06/14 06:12:25 robertj
374 * Changes for using RTP sessions correctly in H323 Logical Channel context
378 #include <ptlib.h>
380 #ifdef __GNUC__
381 #pragma implementation "rtp.h"
382 #endif
384 #include "openh323buildopts.h"
386 #include "rtp.h"
388 #ifndef NO_H323_AUDIO_CODECS
389 #include "jitter.h"
390 #endif
392 #include <ptclib/random.h>
394 #ifdef P_STUN
395 #include <ptclib/pnat.h>
396 #endif
398 #if defined(H323_RTP_AGGREGATE) || defined(H323_SIGNAL_AGGREGATE)
399 #include <ptclib/sockagg.h>
400 #endif
402 #define new PNEW
405 const unsigned SecondsFrom1900to1970 = (70*365+17)*24*60*60U;
407 #define UDP_BUFFER_SIZE 32768
409 #define MIN_HEADER_SIZE 12
412 /////////////////////////////////////////////////////////////////////////////
414 RTP_DataFrame::RTP_DataFrame(PINDEX sz)
415 : PBYTEArray(MIN_HEADER_SIZE+sz)
417 payloadSize = sz;
418 theArray[0] = '\x80';
422 void RTP_DataFrame::SetExtension(BOOL ext)
424 if (ext)
425 theArray[0] |= 0x10;
426 else
427 theArray[0] &= 0xef;
431 void RTP_DataFrame::SetMarker(BOOL m)
433 if (m)
434 theArray[1] |= 0x80;
435 else
436 theArray[1] &= 0x7f;
440 void RTP_DataFrame::SetPayloadType(PayloadTypes t)
442 PAssert(t <= 0x7f, PInvalidParameter);
444 theArray[1] &= 0x80;
445 theArray[1] |= t;
449 DWORD RTP_DataFrame::GetContribSource(PINDEX idx) const
451 PAssert(idx < GetContribSrcCount(), PInvalidParameter);
452 return ((PUInt32b *)&theArray[MIN_HEADER_SIZE])[idx];
456 void RTP_DataFrame::SetContribSource(PINDEX idx, DWORD src)
458 PAssert(idx <= 15, PInvalidParameter);
460 if (idx >= GetContribSrcCount()) {
461 BYTE * oldPayload = GetPayloadPtr();
462 theArray[0] &= 0xf0;
463 theArray[0] |= idx+1;
464 SetSize(GetHeaderSize()+payloadSize);
465 memmove(GetPayloadPtr(), oldPayload, payloadSize);
468 ((PUInt32b *)&theArray[MIN_HEADER_SIZE])[idx] = src;
472 PINDEX RTP_DataFrame::GetHeaderSize() const
474 PINDEX sz = MIN_HEADER_SIZE + 4*GetContribSrcCount();
476 if (GetExtension())
477 sz += 4 + GetExtensionSize();
479 return sz;
483 int RTP_DataFrame::GetExtensionType() const
485 if (GetExtension())
486 return *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount()];
488 return -1;
492 void RTP_DataFrame::SetExtensionType(int type)
494 if (type < 0)
495 SetExtension(FALSE);
496 else {
497 if (!GetExtension())
498 SetExtensionSize(0);
499 *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount()] = (WORD)type;
504 PINDEX RTP_DataFrame::GetExtensionSize() const
506 if (GetExtension())
507 return *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 2];
509 return 0;
513 BOOL RTP_DataFrame::SetExtensionSize(PINDEX sz)
515 if (!SetMinSize(MIN_HEADER_SIZE + 4*GetContribSrcCount() + 4+4*sz + payloadSize))
516 return FALSE;
518 SetExtension(TRUE);
519 *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 2] = (WORD)sz;
520 return TRUE;
524 BYTE * RTP_DataFrame::GetExtensionPtr() const
526 if (GetExtension())
527 return (BYTE *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 4];
529 return NULL;
533 BOOL RTP_DataFrame::SetPayloadSize(PINDEX sz)
535 payloadSize = sz;
536 return SetMinSize(GetHeaderSize()+payloadSize);
540 #if PTRACING
541 static const char * const PayloadTypesNames[RTP_DataFrame::LastKnownPayloadType] = {
542 "PCMU",
543 "FS1016",
544 "G721",
545 "GSM",
546 "G7231",
547 "DVI4_8k",
548 "DVI4_16k",
549 "LPC",
550 "PCMA",
551 "G722",
552 "L16_Stereo",
553 "L16_Mono",
554 "G723",
555 "CN",
556 "MPA",
557 "G728",
558 "DVI4_11k",
559 "DVI4_22k",
560 "G729",
561 "CiscoCN",
562 NULL, NULL, NULL, NULL, NULL,
563 "CelB",
564 "JPEG",
565 NULL, NULL, NULL, NULL,
566 "H261",
567 "MPV",
568 "MP2T",
569 "H263"
572 ostream & operator<<(ostream & o, RTP_DataFrame::PayloadTypes t)
574 if ((PINDEX)t < PARRAYSIZE(PayloadTypesNames) && PayloadTypesNames[t] != NULL)
575 o << PayloadTypesNames[t];
576 else
577 o << "[pt=" << (int)t << ']';
578 return o;
581 #endif
584 /////////////////////////////////////////////////////////////////////////////
586 RTP_ControlFrame::RTP_ControlFrame(PINDEX sz)
587 : PBYTEArray(sz)
589 compoundOffset = 0;
590 compoundSize = 0;
591 theArray[0] = '\x80'; // Set version 2
595 void RTP_ControlFrame::SetCount(unsigned count)
597 PAssert(count < 32, PInvalidParameter);
598 theArray[compoundOffset] &= 0xe0;
599 theArray[compoundOffset] |= count;
603 void RTP_ControlFrame::SetPayloadType(unsigned t)
605 PAssert(t < 256, PInvalidParameter);
606 theArray[compoundOffset+1] = (BYTE)t;
610 void RTP_ControlFrame::SetPayloadSize(PINDEX sz)
612 sz = (sz+3)/4;
613 PAssert(sz <= 0xffff, PInvalidParameter);
615 compoundSize = compoundOffset+4*(sz+1);
616 SetMinSize(compoundSize+1);
617 *(PUInt16b *)&theArray[compoundOffset+2] = (WORD)sz;
621 BOOL RTP_ControlFrame::ReadNextCompound()
623 compoundOffset += GetPayloadSize()+4;
624 if (compoundOffset+4 > GetSize())
625 return FALSE;
626 return compoundOffset+GetPayloadSize()+4 <= GetSize();
630 BOOL RTP_ControlFrame::WriteNextCompound()
632 compoundOffset += GetPayloadSize()+4;
633 if (!SetMinSize(compoundOffset+4))
634 return FALSE;
636 theArray[compoundOffset] = '\x80'; // Set version 2
637 theArray[compoundOffset+1] = 0; // Set payload type to illegal
638 theArray[compoundOffset+2] = 0; // Set payload size to zero
639 theArray[compoundOffset+3] = 0;
640 return TRUE;
644 RTP_ControlFrame::SourceDescription & RTP_ControlFrame::AddSourceDescription(DWORD src)
646 SetPayloadType(RTP_ControlFrame::e_SourceDescription);
648 PINDEX index = GetCount();
649 SetCount(index+1);
651 PINDEX originalPayloadSize = index != 0 ? GetPayloadSize() : 0;
652 SetPayloadSize(originalPayloadSize+sizeof(SourceDescription));
653 SourceDescription & sdes = *(SourceDescription *)(GetPayloadPtr()+originalPayloadSize);
654 sdes.src = src;
655 sdes.item[0].type = e_END;
656 return sdes;
660 RTP_ControlFrame::SourceDescription::Item &
661 RTP_ControlFrame::AddSourceDescriptionItem(SourceDescription & sdes,
662 unsigned type,
663 const PString & data)
665 PINDEX dataLength = data.GetLength();
666 SetPayloadSize(GetPayloadSize()+sizeof(SourceDescription::Item)+dataLength-1);
668 SourceDescription::Item * item = sdes.item;
669 while (item->type != e_END)
670 item = item->GetNextItem();
672 item->type = (BYTE)type;
673 item->length = (BYTE)dataLength;
674 memcpy(item->data, (const char *)data, item->length);
676 item->GetNextItem()->type = e_END;
677 return *item;
681 void RTP_ControlFrame::ReceiverReport::SetLostPackets(unsigned packets)
683 lost[0] = (BYTE)(packets >> 16);
684 lost[1] = (BYTE)(packets >> 8);
685 lost[2] = (BYTE)packets;
689 /////////////////////////////////////////////////////////////////////////////
691 void RTP_UserData::OnTxStatistics(const RTP_Session & /*session*/) const
696 void RTP_UserData::OnRxStatistics(const RTP_Session & /*session*/) const
701 /////////////////////////////////////////////////////////////////////////////
703 RTP_Session::RTP_Session(
704 #ifdef H323_RTP_AGGREGATE
706 PHandleAggregator * _aggregator,
707 #endif
708 unsigned id, RTP_UserData * data)
709 : canonicalName(PProcess::Current().GetUserName()),
710 toolName(PProcess::Current().GetName()),
711 reportTimeInterval(0, 12), // Seconds
712 firstDataReceivedTime(0),
713 reportTimer(reportTimeInterval)
714 #ifdef H323_RTP_AGGREGATE
715 ,aggregator(_aggregator)
716 #endif
718 PAssert(id > 0 && id < 256, PInvalidParameter);
719 sessionID = (BYTE)id;
721 referenceCount = 1;
722 userData = data;
724 #ifndef NO_H323_AUDIO_CODECS
725 jitter = NULL;
726 #endif
728 ignoreOtherSources = TRUE;
729 ignoreOutOfOrderPackets = TRUE;
730 syncSourceOut = PRandom::Number();
731 syncSourceIn = 0;
732 txStatisticsInterval = 100; // Number of data packets between tx reports
733 rxStatisticsInterval = 100; // Number of data packets between rx reports
734 lastSentSequenceNumber = (WORD)PRandom::Number();
735 expectedSequenceNumber = 0;
736 lastRRSequenceNumber = 0;
737 consecutiveOutOfOrderPackets = 0;
739 packetsSent = 0;
740 octetsSent = 0;
741 packetsReceived = 0;
742 octetsReceived = 0;
743 packetsLost = 0;
744 packetsOutOfOrder = 0;
745 averageSendTime = 0;
746 maximumSendTime = 0;
747 minimumSendTime = 0;
748 averageReceiveTime = 0;
749 maximumReceiveTime = 0;
750 minimumReceiveTime = 0;
751 jitterLevel = 0;
752 maximumJitterLevel = 0;
754 txStatisticsCount = 0;
755 rxStatisticsCount = 0;
756 averageSendTimeAccum = 0;
757 maximumSendTimeAccum = 0;
758 minimumSendTimeAccum = 0xffffffff;
759 averageReceiveTimeAccum = 0;
760 maximumReceiveTimeAccum = 0;
761 minimumReceiveTimeAccum = 0xffffffff;
762 packetsLostSinceLastRR = 0;
763 lastTransitTime = 0;
767 RTP_Session::~RTP_Session()
769 PTRACE_IF(2, packetsSent != 0 || packetsReceived != 0,
770 "RTP\tFinal statistics:\n"
771 " packetsSent = " << packetsSent << "\n"
772 " octetsSent = " << octetsSent << "\n"
773 " averageSendTime = " << averageSendTime << "\n"
774 " maximumSendTime = " << maximumSendTime << "\n"
775 " minimumSendTime = " << minimumSendTime << "\n"
776 " packetsReceived = " << packetsReceived << "\n"
777 " octetsReceived = " << octetsReceived << "\n"
778 " packetsLost = " << packetsLost << "\n"
779 " packetsTooLate = " << GetPacketsTooLate() << "\n"
780 " packetsOutOfOrder = " << packetsOutOfOrder << "\n"
781 " averageReceiveTime= " << averageReceiveTime << "\n"
782 " maximumReceiveTime= " << maximumReceiveTime << "\n"
783 " minimumReceiveTime= " << minimumReceiveTime << "\n"
784 " averageJitter = " << (jitterLevel >> 7) << "\n"
785 " maximumJitter = " << (maximumJitterLevel >> 7)
787 delete userData;
789 #ifndef NO_H323_AUDIO_CODECS
790 delete jitter;
791 #endif
795 PString RTP_Session::GetCanonicalName() const
797 PWaitAndSignal mutex(reportMutex);
798 PString s = canonicalName;
799 s.MakeUnique();
800 return s;
804 void RTP_Session::SetCanonicalName(const PString & name)
806 PWaitAndSignal mutex(reportMutex);
807 canonicalName = name;
811 PString RTP_Session::GetToolName() const
813 PWaitAndSignal mutex(reportMutex);
814 PString s = toolName;
815 s.MakeUnique();
816 return s;
820 void RTP_Session::SetToolName(const PString & name)
822 PWaitAndSignal mutex(reportMutex);
823 toolName = name;
827 void RTP_Session::SetUserData(RTP_UserData * data)
829 delete userData;
830 userData = data;
834 void RTP_Session::SetJitterBufferSize(unsigned minJitterDelay,
835 unsigned maxJitterDelay,
836 PINDEX stackSize)
838 if (minJitterDelay == 0 && maxJitterDelay == 0) {
839 #ifndef NO_H323_AUDIO_CODECS
840 delete jitter;
841 jitter = NULL;
842 #endif
844 else if (jitter != NULL) {
845 #ifndef NO_H323_AUDIO_CODECS
846 jitter->SetDelay(minJitterDelay, maxJitterDelay);
847 #endif
849 else {
850 SetIgnoreOutOfOrderPackets(FALSE);
851 #ifndef NO_H323_AUDIO_CODECS
852 jitter = new RTP_JitterBuffer(*this, minJitterDelay, maxJitterDelay, stackSize);
853 jitter->Resume(
854 #ifdef H323_RTP_AGGREGATE
855 aggregator
856 #endif
858 #endif
863 unsigned RTP_Session::GetJitterBufferSize() const
865 return
866 #ifndef NO_H323_AUDIO_CODECS
867 jitter != NULL ? jitter->GetJitterTime() :
868 #endif
873 BOOL RTP_Session::ReadBufferedData(DWORD timestamp, RTP_DataFrame & frame)
875 #ifndef NO_H323_AUDIO_CODECS
876 if (jitter != NULL)
877 return jitter->ReadData(timestamp, frame);
878 else
879 #endif
880 return ReadData(frame, TRUE);
884 void RTP_Session::SetTxStatisticsInterval(unsigned packets)
886 txStatisticsInterval = PMAX(packets, 2);
887 txStatisticsCount = 0;
888 averageSendTimeAccum = 0;
889 maximumSendTimeAccum = 0;
890 minimumSendTimeAccum = 0xffffffff;
894 void RTP_Session::SetRxStatisticsInterval(unsigned packets)
896 rxStatisticsInterval = PMAX(packets, 2);
897 rxStatisticsCount = 0;
898 averageReceiveTimeAccum = 0;
899 maximumReceiveTimeAccum = 0;
900 minimumReceiveTimeAccum = 0xffffffff;
904 void RTP_Session::AddReceiverReport(RTP_ControlFrame::ReceiverReport & receiver)
906 receiver.ssrc = syncSourceIn;
907 receiver.SetLostPackets(packetsLost);
909 if (expectedSequenceNumber > lastRRSequenceNumber)
910 receiver.fraction = (BYTE)((packetsLostSinceLastRR<<8)/(expectedSequenceNumber - lastRRSequenceNumber));
911 else
912 receiver.fraction = 0;
913 packetsLostSinceLastRR = 0;
915 receiver.last_seq = lastRRSequenceNumber;
916 lastRRSequenceNumber = expectedSequenceNumber;
918 receiver.jitter = jitterLevel >> 4; // Allow for rounding protection bits
920 // The following have not been calculated yet.
921 receiver.lsr = 0;
922 receiver.dlsr = 0;
924 PTRACE(3, "RTP\tSentReceiverReport:"
925 " ssrc=" << receiver.ssrc
926 << " fraction=" << (unsigned)receiver.fraction
927 << " lost=" << receiver.GetLostPackets()
928 << " last_seq=" << receiver.last_seq
929 << " jitter=" << receiver.jitter
930 << " lsr=" << receiver.lsr
931 << " dlsr=" << receiver.dlsr);
935 RTP_Session::SendReceiveStatus RTP_Session::OnSendData(RTP_DataFrame & frame)
937 PTimeInterval tick = PTimer::Tick(); // Timestamp set now
939 frame.SetSequenceNumber(++lastSentSequenceNumber);
940 frame.SetSyncSource(syncSourceOut);
942 if (packetsSent != 0 && !frame.GetMarker()) {
943 // Only do statistics on subsequent packets
944 DWORD diff = (tick - lastSentPacketTime).GetInterval();
946 averageSendTimeAccum += diff;
947 if (diff > maximumSendTimeAccum)
948 maximumSendTimeAccum = diff;
949 if (diff < minimumSendTimeAccum)
950 minimumSendTimeAccum = diff;
951 txStatisticsCount++;
954 lastSentTimestamp = frame.GetTimestamp();
955 lastSentPacketTime = tick;
957 octetsSent += frame.GetPayloadSize();
958 packetsSent++;
960 // Call the statistics call-back on the first PDU with total count == 1
961 if (packetsSent == 1 && userData != NULL)
962 userData->OnTxStatistics(*this);
964 if (!SendReport())
965 return e_AbortTransport;
967 if (txStatisticsCount < txStatisticsInterval)
968 return e_ProcessPacket;
970 txStatisticsCount = 0;
972 averageSendTime = averageSendTimeAccum/txStatisticsInterval;
973 maximumSendTime = maximumSendTimeAccum;
974 minimumSendTime = minimumSendTimeAccum;
976 averageSendTimeAccum = 0;
977 maximumSendTimeAccum = 0;
978 minimumSendTimeAccum = 0xffffffff;
980 PTRACE(2, "RTP\tTransmit statistics: "
981 " packets=" << packetsSent <<
982 " octets=" << octetsSent <<
983 " avgTime=" << averageSendTime <<
984 " maxTime=" << maximumSendTime <<
985 " minTime=" << minimumSendTime
988 if (userData != NULL)
989 userData->OnTxStatistics(*this);
991 return e_ProcessPacket;
995 RTP_Session::SendReceiveStatus RTP_Session::OnReceiveData(const RTP_DataFrame & frame)
997 // Check that the PDU is the right version
998 if (frame.GetVersion() != RTP_DataFrame::ProtocolVersion)
999 return e_IgnorePacket; // Non fatal error, just ignore
1001 // Check for if a control packet rather than data packet.
1002 if (frame.GetPayloadType() > RTP_DataFrame::MaxPayloadType)
1003 return e_IgnorePacket; // Non fatal error, just ignore
1005 PTimeInterval tick = PTimer::Tick(); // Get timestamp now
1007 // Have not got SSRC yet, so grab it now
1008 if (syncSourceIn == 0)
1009 syncSourceIn = frame.GetSyncSource();
1011 // Check packet sequence numbers
1012 if (packetsReceived == 0) {
1013 expectedSequenceNumber = (WORD)(frame.GetSequenceNumber() + 1);
1014 firstDataReceivedTime = PTime();
1015 PTRACE(2, "RTP\tFirst data:"
1016 " ver=" << frame.GetVersion()
1017 << " pt=" << frame.GetPayloadType()
1018 << " psz=" << frame.GetPayloadSize()
1019 << " m=" << frame.GetMarker()
1020 << " x=" << frame.GetExtension()
1021 << " seq=" << frame.GetSequenceNumber()
1022 << " ts=" << frame.GetTimestamp()
1023 << " src=" << frame.GetSyncSource()
1024 << " ccnt=" << frame.GetContribSrcCount());
1026 else {
1027 if (ignoreOtherSources && frame.GetSyncSource() != syncSourceIn) {
1028 PTRACE(2, "RTP\tPacket from SSRC=" << frame.GetSyncSource()
1029 << " ignored, expecting SSRC=" << syncSourceIn);
1030 return e_IgnorePacket; // Non fatal error, just ignore
1033 WORD sequenceNumber = frame.GetSequenceNumber();
1034 if (sequenceNumber == expectedSequenceNumber) {
1035 expectedSequenceNumber++;
1036 consecutiveOutOfOrderPackets = 0;
1037 // Only do statistics on packets after first received in talk burst
1038 if (!frame.GetMarker()) {
1039 DWORD diff = (tick - lastReceivedPacketTime).GetInterval();
1041 averageReceiveTimeAccum += diff;
1042 if (diff > maximumReceiveTimeAccum)
1043 maximumReceiveTimeAccum = diff;
1044 if (diff < minimumReceiveTimeAccum)
1045 minimumReceiveTimeAccum = diff;
1046 rxStatisticsCount++;
1048 // The following has the implicit assumption that something that has jitter
1049 // is an audio codec and thus is in 8kHz timestamp units.
1050 diff *= 8;
1051 long variance = diff - lastTransitTime;
1052 lastTransitTime = diff;
1053 if (variance < 0)
1054 variance = -variance;
1055 jitterLevel += variance - ((jitterLevel+8) >> 4);
1056 if (jitterLevel > maximumJitterLevel)
1057 maximumJitterLevel = jitterLevel;
1060 else if (sequenceNumber < expectedSequenceNumber) {
1061 PTRACE(3, "RTP\tOut of order packet, received "
1062 << sequenceNumber << " expected " << expectedSequenceNumber
1063 << " ssrc=" << syncSourceIn);
1064 packetsOutOfOrder++;
1066 // Check for Cisco bug where sequence numbers suddenly start incrementing
1067 // from a different base.
1068 if (++consecutiveOutOfOrderPackets > 10) {
1069 expectedSequenceNumber = (WORD)(sequenceNumber + 1);
1070 PTRACE(1, "RTP\tAbnormal change of sequence numbers, adjusting to expect "
1071 << expectedSequenceNumber << " ssrc=" << syncSourceIn);
1074 if (ignoreOutOfOrderPackets)
1075 return e_IgnorePacket; // Non fatal error, just ignore
1077 else {
1078 unsigned dropped = sequenceNumber - expectedSequenceNumber;
1079 packetsLost += dropped;
1080 packetsLostSinceLastRR += dropped;
1081 PTRACE(3, "RTP\tDropped " << dropped << " packet(s) at " << sequenceNumber
1082 << ", ssrc=" << syncSourceIn);
1083 expectedSequenceNumber = (WORD)(sequenceNumber + 1);
1084 consecutiveOutOfOrderPackets = 0;
1088 lastReceivedPacketTime = tick;
1090 octetsReceived += frame.GetPayloadSize();
1091 packetsReceived++;
1093 // Call the statistics call-back on the first PDU with total count == 1
1094 if (packetsReceived == 1 && userData != NULL)
1095 userData->OnRxStatistics(*this);
1097 if (!SendReport())
1098 return e_AbortTransport;
1100 if (rxStatisticsCount < rxStatisticsInterval)
1101 return e_ProcessPacket;
1103 rxStatisticsCount = 0;
1105 averageReceiveTime = averageReceiveTimeAccum/rxStatisticsInterval;
1106 maximumReceiveTime = maximumReceiveTimeAccum;
1107 minimumReceiveTime = minimumReceiveTimeAccum;
1109 averageReceiveTimeAccum = 0;
1110 maximumReceiveTimeAccum = 0;
1111 minimumReceiveTimeAccum = 0xffffffff;
1113 PTRACE(2, "RTP\tReceive statistics: "
1114 " packets=" << packetsReceived <<
1115 " octets=" << octetsReceived <<
1116 " lost=" << packetsLost <<
1117 " tooLate=" << GetPacketsTooLate() <<
1118 " order=" << packetsOutOfOrder <<
1119 " avgTime=" << averageReceiveTime <<
1120 " maxTime=" << maximumReceiveTime <<
1121 " minTime=" << minimumReceiveTime <<
1122 " jitter=" << (jitterLevel >> 7) <<
1123 " maxJitter=" << (maximumJitterLevel >> 7)
1126 if (userData != NULL)
1127 userData->OnRxStatistics(*this);
1129 return e_ProcessPacket;
1133 BOOL RTP_Session::SendReport()
1135 PWaitAndSignal mutex(reportMutex);
1137 if (reportTimer.IsRunning())
1138 return TRUE;
1140 // Have not got anything yet, do nothing
1141 if (packetsSent == 0 && packetsReceived == 0) {
1142 reportTimer = reportTimeInterval;
1143 return TRUE;
1146 RTP_ControlFrame report;
1148 // No packets sent yet, so only send RR
1149 if (packetsSent == 0) {
1150 // Send RR as we are not transmitting
1151 report.SetPayloadType(RTP_ControlFrame::e_ReceiverReport);
1152 report.SetPayloadSize(4+sizeof(RTP_ControlFrame::ReceiverReport));
1153 report.SetCount(1);
1155 PUInt32b * payload = (PUInt32b *)report.GetPayloadPtr();
1156 *payload = syncSourceOut;
1157 AddReceiverReport(*(RTP_ControlFrame::ReceiverReport *)&payload[1]);
1159 else {
1160 report.SetPayloadType(RTP_ControlFrame::e_SenderReport);
1161 report.SetPayloadSize(sizeof(RTP_ControlFrame::SenderReport));
1163 RTP_ControlFrame::SenderReport * sender =
1164 (RTP_ControlFrame::SenderReport *)report.GetPayloadPtr();
1165 sender->ssrc = syncSourceOut;
1166 PTime now;
1167 sender->ntp_sec = now.GetTimeInSeconds()+SecondsFrom1900to1970; // Convert from 1970 to 1900
1168 sender->ntp_frac = now.GetMicrosecond()*4294; // Scale microseconds to "fraction" from 0 to 2^32
1169 sender->rtp_ts = lastSentTimestamp;
1170 sender->psent = packetsSent;
1171 sender->osent = octetsSent;
1173 PTRACE(3, "RTP\tSentSenderReport: "
1174 " ssrc=" << sender->ssrc
1175 << " ntp=" << sender->ntp_sec << '.' << sender->ntp_frac
1176 << " rtp=" << sender->rtp_ts
1177 << " psent=" << sender->psent
1178 << " osent=" << sender->osent);
1180 if (syncSourceIn != 0) {
1181 report.SetPayloadSize(sizeof(RTP_ControlFrame::SenderReport) +
1182 sizeof(RTP_ControlFrame::ReceiverReport));
1183 report.SetCount(1);
1184 AddReceiverReport(*(RTP_ControlFrame::ReceiverReport *)&sender[1]);
1188 // Add the SDES part to compound RTCP packet
1189 PTRACE(2, "RTP\tSending SDES: " << canonicalName);
1190 report.WriteNextCompound();
1192 RTP_ControlFrame::SourceDescription & sdes = report.AddSourceDescription(syncSourceOut);
1193 report.AddSourceDescriptionItem(sdes, RTP_ControlFrame::e_CNAME, canonicalName);
1194 report.AddSourceDescriptionItem(sdes, RTP_ControlFrame::e_TOOL, toolName);
1196 // Wait a fuzzy amount of time so things don't get into lock step
1197 int interval = (int)reportTimeInterval.GetMilliSeconds();
1198 int third = interval/3;
1199 interval += PRandom::Number()%(2*third);
1200 interval -= third;
1201 reportTimer = interval;
1203 return WriteControl(report);
1207 static RTP_Session::ReceiverReportArray
1208 BuildReceiverReportArray(const RTP_ControlFrame & frame, PINDEX offset)
1210 RTP_Session::ReceiverReportArray reports;
1212 const RTP_ControlFrame::ReceiverReport * rr = (const RTP_ControlFrame::ReceiverReport *)(frame.GetPayloadPtr()+offset);
1213 for (PINDEX repIdx = 0; repIdx < (PINDEX)frame.GetCount(); repIdx++) {
1214 RTP_Session::ReceiverReport * report = new RTP_Session::ReceiverReport;
1215 report->sourceIdentifier = rr->ssrc;
1216 report->fractionLost = rr->fraction;
1217 report->totalLost = rr->GetLostPackets();
1218 report->lastSequenceNumber = rr->last_seq;
1219 report->jitter = rr->jitter;
1220 report->lastTimestamp = (PInt64)(DWORD)rr->lsr;
1221 report->delay = ((PInt64)rr->dlsr << 16)/1000;
1222 reports.SetAt(repIdx, report);
1223 rr++;
1226 return reports;
1230 RTP_Session::SendReceiveStatus RTP_Session::OnReceiveControl(RTP_ControlFrame & frame)
1232 do {
1233 BYTE * payload = frame.GetPayloadPtr();
1234 unsigned size = frame.GetPayloadSize();
1236 switch (frame.GetPayloadType()) {
1237 case RTP_ControlFrame::e_SenderReport :
1238 if (size >= sizeof(RTP_ControlFrame::SenderReport)) {
1239 SenderReport sender;
1240 const RTP_ControlFrame::SenderReport & sr = *(const RTP_ControlFrame::SenderReport *)payload;
1241 sender.sourceIdentifier = sr.ssrc;
1242 sender.realTimestamp = PTime(sr.ntp_sec-SecondsFrom1900to1970, sr.ntp_frac/4294);
1243 sender.rtpTimestamp = sr.rtp_ts;
1244 sender.packetsSent = sr.psent;
1245 sender.octetsSent = sr.osent;
1246 OnRxSenderReport(sender,
1247 BuildReceiverReportArray(frame, sizeof(RTP_ControlFrame::SenderReport)));
1249 else {
1250 PTRACE(2, "RTP\tSenderReport packet truncated");
1252 break;
1254 case RTP_ControlFrame::e_ReceiverReport :
1255 if (size >= 4)
1256 OnRxReceiverReport(*(const PUInt32b *)payload,
1257 BuildReceiverReportArray(frame, sizeof(PUInt32b)));
1258 else {
1259 PTRACE(2, "RTP\tReceiverReport packet truncated");
1261 break;
1263 case RTP_ControlFrame::e_SourceDescription :
1264 if (size >= frame.GetCount()*sizeof(RTP_ControlFrame::SourceDescription)) {
1265 SourceDescriptionArray descriptions;
1266 const RTP_ControlFrame::SourceDescription * sdes = (const RTP_ControlFrame::SourceDescription *)payload;
1267 for (PINDEX srcIdx = 0; srcIdx < (PINDEX)frame.GetCount(); srcIdx++) {
1268 descriptions.SetAt(srcIdx, new SourceDescription(sdes->src));
1269 const RTP_ControlFrame::SourceDescription::Item * item = sdes->item;
1270 while (item->type != RTP_ControlFrame::e_END) {
1271 descriptions[srcIdx].items.SetAt(item->type, PString(item->data, item->length));
1272 item = item->GetNextItem();
1274 sdes = (const RTP_ControlFrame::SourceDescription *)item->GetNextItem();
1276 OnRxSourceDescription(descriptions);
1278 else {
1279 PTRACE(2, "RTP\tSourceDescription packet truncated");
1281 break;
1283 case RTP_ControlFrame::e_Goodbye :
1284 if (size >= 4) {
1285 PString str;
1286 unsigned count = frame.GetCount()*4;
1287 if (size > count)
1288 str = PString((const char *)(payload+count+1), payload[count]);
1289 PDWORDArray sources(count);
1290 for (PINDEX i = 0; i < (PINDEX)count; i++)
1291 sources[i] = ((const PUInt32b *)payload)[i];
1292 OnRxGoodbye(sources, str);
1294 else {
1295 PTRACE(2, "RTP\tGoodbye packet truncated");
1297 break;
1299 case RTP_ControlFrame::e_ApplDefined :
1300 if (size >= 4) {
1301 PString str((const char *)(payload+4), 4);
1302 OnRxApplDefined(str, frame.GetCount(), *(const PUInt32b *)payload,
1303 payload+8, frame.GetPayloadSize()-8);
1305 else {
1306 PTRACE(2, "RTP\tApplDefined packet truncated");
1308 break;
1310 default :
1311 PTRACE(2, "RTP\tUnknown control payload type: " << frame.GetPayloadType());
1313 } while (frame.ReadNextCompound());
1315 return e_ProcessPacket;
1319 void RTP_Session::OnRxSenderReport(const SenderReport & PTRACE_PARAM(sender),
1320 const ReceiverReportArray & PTRACE_PARAM(reports))
1322 #if PTRACING
1323 PTRACE(3, "RTP\tOnRxSenderReport: " << sender);
1324 for (PINDEX i = 0; i < reports.GetSize(); i++)
1325 PTRACE(3, "RTP\tOnRxSenderReport RR: " << reports[i]);
1326 #endif
1330 void RTP_Session::OnRxReceiverReport(DWORD PTRACE_PARAM(src),
1331 const ReceiverReportArray & PTRACE_PARAM(reports))
1333 #if PTRACING
1334 PTRACE(3, "RTP\tOnReceiverReport: ssrc=" << src);
1335 for (PINDEX i = 0; i < reports.GetSize(); i++)
1336 PTRACE(3, "RTP\tOnReceiverReport RR: " << reports[i]);
1337 #endif
1341 void RTP_Session::OnRxSourceDescription(const SourceDescriptionArray & PTRACE_PARAM(description))
1343 #if PTRACING
1344 for (PINDEX i = 0; i < description.GetSize(); i++)
1345 PTRACE(3, "RTP\tOnSourceDescription: " << description[i]);
1346 #endif
1350 void RTP_Session::OnRxGoodbye(const PDWORDArray & PTRACE_PARAM(src),
1351 const PString & PTRACE_PARAM(reason))
1353 PTRACE(3, "RTP\tOnGoodbye: \"" << reason << "\" srcs=" << src);
1357 void RTP_Session::OnRxApplDefined(const PString & PTRACE_PARAM(type),
1358 unsigned PTRACE_PARAM(subtype),
1359 DWORD PTRACE_PARAM(src),
1360 const BYTE * /*data*/, PINDEX PTRACE_PARAM(size))
1362 PTRACE(3, "RTP\tOnApplDefined: \"" << type << "\"-" << subtype
1363 << " " << src << " [" << size << ']');
1367 void RTP_Session::ReceiverReport::PrintOn(ostream & strm) const
1369 strm << "ssrc=" << sourceIdentifier
1370 << " fraction=" << fractionLost
1371 << " lost=" << totalLost
1372 << " last_seq=" << lastSequenceNumber
1373 << " jitter=" << jitter
1374 << " lsr=" << lastTimestamp
1375 << " dlsr=" << delay;
1379 void RTP_Session::SenderReport::PrintOn(ostream & strm) const
1381 strm << "ssrc=" << sourceIdentifier
1382 << " ntp=" << realTimestamp.AsString("yyyy/M/d-h:m:s.uuuu")
1383 << " rtp=" << rtpTimestamp
1384 << " psent=" << packetsSent
1385 << " osent=" << octetsSent;
1389 void RTP_Session::SourceDescription::PrintOn(ostream & strm) const
1391 static const char * const DescriptionNames[RTP_ControlFrame::NumDescriptionTypes] = {
1392 "END", "CNAME", "NAME", "EMAIL", "PHONE", "LOC", "TOOL", "NOTE", "PRIV"
1395 strm << "ssrc=" << sourceIdentifier;
1396 for (PINDEX i = 0; i < items.GetSize(); i++) {
1397 strm << "\n item[" << i << "]: type=";
1398 unsigned typeNum = items.GetKeyAt(i);
1399 if (typeNum < PARRAYSIZE(DescriptionNames))
1400 strm << DescriptionNames[typeNum];
1401 else
1402 strm << typeNum;
1403 strm << " data=\""
1404 << items.GetDataAt(i)
1405 << '"';
1410 DWORD RTP_Session::GetPacketsTooLate() const
1412 return
1413 #ifndef NO_H323_AUDIO_CODECS
1414 jitter != NULL ? jitter->GetPacketsTooLate() :
1415 #endif
1420 /////////////////////////////////////////////////////////////////////////////
1422 RTP_SessionManager::RTP_SessionManager()
1424 enumerationIndex = P_MAX_INDEX;
1428 RTP_SessionManager::RTP_SessionManager(const RTP_SessionManager & sm)
1429 : sessions(sm.sessions)
1431 enumerationIndex = P_MAX_INDEX;
1435 RTP_SessionManager & RTP_SessionManager::operator=(const RTP_SessionManager & sm)
1437 PWaitAndSignal m1(mutex);
1438 PWaitAndSignal m2(sm.mutex);
1439 sessions = sm.sessions;
1440 return *this;
1444 RTP_Session * RTP_SessionManager::UseSession(unsigned sessionID)
1446 mutex.Wait();
1448 RTP_Session * session = sessions.GetAt(sessionID);
1449 if (session == NULL)
1450 return NULL; // Deliberately have not release mutex here! See AddSession.
1452 PTRACE(3, "RTP\tFound existing session " << sessionID);
1453 session->IncrementReference();
1455 mutex.Signal();
1456 return session;
1460 void RTP_SessionManager::AddSession(RTP_Session * session)
1462 if (PAssertNULL(session) != NULL) {
1463 PTRACE(2, "RTP\tAdding session " << *session);
1464 sessions.SetAt(session->GetSessionID(), session);
1467 // The following is the mutex.Signal() that was not done in the UseSession()
1468 mutex.Signal();
1472 void RTP_SessionManager::ReleaseSession(unsigned sessionID)
1474 PTRACE(2, "RTP\tReleasing session " << sessionID);
1476 mutex.Wait();
1478 if (sessions.Contains(sessionID)) {
1479 if (sessions[sessionID].DecrementReference()) {
1480 PTRACE(3, "RTP\tDeleting session " << sessionID);
1481 sessions[sessionID].SetJitterBufferSize(0, 0);
1482 sessions.SetAt(sessionID, NULL);
1486 mutex.Signal();
1490 RTP_Session * RTP_SessionManager::GetSession(unsigned sessionID) const
1492 PWaitAndSignal wait(mutex);
1493 if (!sessions.Contains(sessionID))
1494 return NULL;
1496 PTRACE(3, "RTP\tFound existing session " << sessionID);
1497 return &sessions[sessionID];
1501 RTP_Session * RTP_SessionManager::First()
1503 mutex.Wait();
1505 enumerationIndex = 0;
1506 return Next();
1510 RTP_Session * RTP_SessionManager::Next()
1512 if (enumerationIndex < sessions.GetSize())
1513 return &sessions.GetDataAt(enumerationIndex++);
1515 Exit();
1516 return NULL;
1520 void RTP_SessionManager::Exit()
1522 enumerationIndex = P_MAX_INDEX;
1523 mutex.Signal();
1527 /////////////////////////////////////////////////////////////////////////////
1529 static void SetMinBufferSize(PUDPSocket & sock, int buftype)
1531 int sz = 0;
1532 if (sock.GetOption(buftype, sz)) {
1533 if (sz >= UDP_BUFFER_SIZE)
1534 return;
1537 if (!sock.SetOption(buftype, UDP_BUFFER_SIZE)) {
1538 PTRACE(1, "RTP_UDP\tSetOption(" << buftype << ") failed: " << sock.GetErrorText());
1543 RTP_UDP::RTP_UDP(
1544 #ifdef H323_RTP_AGGREGATE
1545 PHandleAggregator * _aggregator,
1546 #endif
1547 unsigned id, BOOL _remoteIsNAT)
1548 : RTP_Session(
1549 #ifdef H323_RTP_AGGREGATE
1550 _aggregator,
1551 #endif
1552 id),
1553 remoteAddress(0),
1554 remoteTransmitAddress(0),
1555 remoteIsNAT(_remoteIsNAT)
1557 remoteDataPort = 0;
1558 remoteControlPort = 0;
1559 shutdownRead = FALSE;
1560 shutdownWrite = FALSE;
1561 dataSocket = NULL;
1562 controlSocket = NULL;
1563 appliedQOS = FALSE;
1564 enableGQOS = FALSE;
1568 RTP_UDP::~RTP_UDP()
1570 Close(TRUE);
1571 Close(FALSE);
1573 delete dataSocket;
1574 delete controlSocket;
1578 void RTP_UDP::ApplyQOS(const PIPSocket::Address & addr)
1580 if (controlSocket != NULL)
1581 controlSocket->SetSendAddress(addr,GetRemoteControlPort());
1582 if (dataSocket != NULL)
1583 dataSocket->SetSendAddress(addr,GetRemoteDataPort());
1584 appliedQOS = TRUE;
1588 BOOL RTP_UDP::ModifyQOS(RTP_QOS * rtpqos)
1590 BOOL retval = FALSE;
1592 if (rtpqos == NULL)
1593 return retval;
1595 #if P_HAS_QOS
1596 if (controlSocket != NULL)
1597 retval = controlSocket->ModifyQoSSpec(&(rtpqos->ctrlQoS));
1599 if (dataSocket != NULL)
1600 retval &= dataSocket->ModifyQoSSpec(&(rtpqos->dataQoS));
1601 #endif
1603 appliedQOS = FALSE;
1604 return retval;
1607 void RTP_UDP::EnableGQoS()
1609 enableGQOS = TRUE;
1612 #if P_HAS_QOS
1613 PQoS & RTP_UDP::GetQOS()
1615 if (controlSocket != NULL)
1616 return controlSocket->GetQoSSpec();
1618 if (dataSocket != NULL)
1619 return dataSocket->GetQoSSpec();
1621 return *new PQoS();
1623 #endif
1625 BOOL RTP_UDP::Open(PIPSocket::Address _localAddress,
1626 WORD portBase, WORD portMax,
1627 BYTE tos,
1628 #ifdef P_STUN
1629 PNatMethod * meth,
1630 #else
1631 void *,
1632 #endif
1633 RTP_QOS * rtpQos)
1635 // save local address
1636 localAddress = _localAddress;
1638 localDataPort = (WORD)(portBase&0xfffe);
1639 localControlPort = (WORD)(localDataPort + 1);
1641 delete dataSocket;
1642 delete controlSocket;
1643 dataSocket = NULL;
1644 controlSocket = NULL;
1646 PQoS * dataQos = NULL;
1647 PQoS * ctrlQos = NULL;
1648 if (rtpQos != NULL) {
1649 #if P_HAS_QOS
1650 dataQos = &(rtpQos->dataQoS);
1651 ctrlQos = &(rtpQos->ctrlQoS);
1652 #endif
1655 #ifdef P_STUN
1656 if (meth != NULL) {
1657 if (meth->CreateSocketPair(dataSocket, controlSocket)) {
1658 dataSocket->GetLocalAddress(localAddress, localDataPort);
1659 controlSocket->GetLocalAddress(localAddress, localControlPort);
1661 else
1662 PTRACE(1, "RTP\tNAT could not create socket pair!");
1664 #endif
1666 if (dataSocket == NULL || controlSocket == NULL) {
1667 dataSocket = new PUDPSocket(dataQos);
1668 controlSocket = new PUDPSocket(ctrlQos);
1669 while (!dataSocket->Listen(localAddress, 1, localDataPort) ||
1670 !controlSocket->Listen(localAddress, 1, localControlPort)) {
1671 dataSocket->Close();
1672 controlSocket->Close();
1673 if ((localDataPort > portMax) || (localDataPort > 0xfffd))
1674 return FALSE; // If it ever gets to here the OS has some SERIOUS problems!
1675 localDataPort += 2;
1676 localControlPort += 2;
1680 // Set the IP Type Of Service field for prioritisation of media UDP packets
1681 // through some Cisco routers and Linux boxes
1682 if (!dataSocket->SetOption(IP_TOS, tos, IPPROTO_IP)) {
1683 PTRACE(1, "RTP_UDP\tCould not set TOS field in IP header: " << dataSocket->GetErrorText());
1686 // Increase internal buffer size on media UDP sockets
1687 SetMinBufferSize(*dataSocket, SO_RCVBUF);
1688 SetMinBufferSize(*dataSocket, SO_SNDBUF);
1689 SetMinBufferSize(*controlSocket, SO_RCVBUF);
1690 SetMinBufferSize(*controlSocket, SO_SNDBUF);
1692 shutdownRead = FALSE;
1693 shutdownWrite = FALSE;
1695 if (canonicalName.Find('@') == P_MAX_INDEX)
1696 canonicalName += '@' + GetLocalHostName();
1698 PTRACE(2, "RTP_UDP\tSession " << sessionID << " created: "
1699 << localAddress << ':' << localDataPort << '-' << localControlPort
1700 << " ssrc=" << syncSourceOut);
1702 return TRUE;
1706 void RTP_UDP::Reopen(BOOL reading)
1708 if (reading)
1709 shutdownRead = FALSE;
1710 else
1711 shutdownWrite = FALSE;
1715 void RTP_UDP::Close(BOOL reading)
1717 if (reading) {
1718 if (!shutdownRead) {
1719 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Shutting down read.");
1720 syncSourceIn = 0;
1721 shutdownRead = TRUE;
1722 if (dataSocket != NULL && controlSocket != NULL) {
1723 PIPSocket::Address addr;
1724 controlSocket->GetLocalAddress(addr);
1725 if (addr.IsAny())
1726 PIPSocket::GetHostAddress(addr);
1727 dataSocket->WriteTo("", 1, addr, controlSocket->GetPort());
1731 else {
1732 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Shutting down write.");
1733 shutdownWrite = TRUE;
1738 PString RTP_UDP::GetLocalHostName()
1740 return PIPSocket::GetHostName();
1744 BOOL RTP_UDP::SetRemoteSocketInfo(PIPSocket::Address address, WORD port, BOOL isDataPort)
1746 if (remoteIsNAT) {
1747 PTRACE(3, "RTP_UDP\tIgnoring remote socket info as remote is behind NAT");
1748 return TRUE;
1751 PTRACE(3, "RTP_UDP\tSetRemoteSocketInfo: session=" << sessionID << ' '
1752 << (isDataPort ? "data" : "control") << " channel, "
1753 "new=" << address << ':' << port << ", "
1754 "local=" << localAddress << ':' << localDataPort << '-' << localControlPort << ", "
1755 "remote=" << remoteAddress << ':' << remoteDataPort << '-' << remoteControlPort);
1757 if (localAddress == address && (isDataPort ? localDataPort : localControlPort) == port)
1758 return TRUE;
1760 remoteAddress = address;
1762 if (isDataPort) {
1763 remoteDataPort = port;
1764 if (remoteControlPort == 0)
1765 remoteControlPort = (WORD)(port + 1);
1767 else {
1768 remoteControlPort = port;
1769 if (remoteDataPort == 0)
1770 remoteDataPort = (WORD)(port - 1);
1773 if (!appliedQOS)
1774 ApplyQOS(remoteAddress);
1776 return remoteAddress != 0 && port != 0;
1780 BOOL RTP_UDP::ReadData(RTP_DataFrame & frame, BOOL loop)
1782 do {
1783 #ifdef H323_RTP_AGGREGATE
1784 PTime start;
1785 #endif
1786 int selectStatus = PSocket::Select(*dataSocket, *controlSocket, reportTimer);
1787 #ifdef H323_RTP_AGGREGATE
1788 unsigned duration = (unsigned)(PTime() - start).GetMilliSeconds();
1789 if (duration > 50) {
1790 PTRACE(4, "Warning: aggregator read routine was of extended duration = " << duration << " msecs");
1792 #endif
1794 if (shutdownRead) {
1795 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Read shutdown.");
1796 shutdownRead = FALSE;
1797 return FALSE;
1800 switch (selectStatus) {
1801 case -2 :
1802 if (ReadControlPDU() == e_AbortTransport)
1803 return FALSE;
1804 break;
1806 case -3 :
1807 if (ReadControlPDU() == e_AbortTransport)
1808 return FALSE;
1809 // Then do -1 case
1811 case -1 :
1812 switch (ReadDataPDU(frame)) {
1813 case e_ProcessPacket :
1814 if (!shutdownRead)
1815 return TRUE;
1816 case e_IgnorePacket :
1817 break;
1818 case e_AbortTransport :
1819 return FALSE;
1821 break;
1823 case 0 :
1824 PTRACE(5, "RTP_UDP\tSession " << sessionID << ", check for sending report.");
1825 if (!SendReport())
1826 return FALSE;
1827 break;
1829 case PSocket::Interrupted:
1830 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Interrupted.");
1831 return FALSE;
1833 default :
1834 PTRACE(1, "RTP_UDP\tSession " << sessionID << ", Select error: "
1835 << PChannel::GetErrorText((PChannel::Errors)selectStatus));
1836 return FALSE;
1838 } while (loop);
1840 return TRUE;
1844 RTP_Session::SendReceiveStatus RTP_UDP::ReadDataOrControlPDU(PUDPSocket & socket,
1845 PBYTEArray & frame,
1846 BOOL fromDataChannel)
1848 #if PTRACING
1849 const char * channelName = fromDataChannel ? "Data" : "Control";
1850 #endif
1851 PIPSocket::Address addr;
1852 WORD port;
1854 if (socket.ReadFrom(frame.GetPointer(), frame.GetSize(), addr, port)) {
1855 if (ignoreOtherSources) {
1857 // If remote address never set from higher levels, then try and figure
1858 // it out from the first packet received.
1859 if (!remoteAddress.IsValid()) {
1860 remoteAddress = addr;
1861 PTRACE(4, "RTP\tSet remote address from first " << channelName
1862 << " PDU from " << addr << ':' << port);
1864 if (fromDataChannel) {
1865 if (remoteDataPort == 0)
1866 remoteDataPort = port;
1868 else {
1869 if (remoteControlPort == 0)
1870 remoteControlPort = port;
1873 if (!remoteTransmitAddress.IsValid())
1874 remoteTransmitAddress = addr;
1875 else if (remoteTransmitAddress != addr) {
1876 PTRACE(1, "RTP_UDP\tSession " << sessionID << ", "
1877 << channelName << " PDU from incorrect host, "
1878 " is " << addr << " should be " << remoteTransmitAddress);
1879 return RTP_Session::e_IgnorePacket;
1883 if (remoteAddress.IsValid() && !appliedQOS)
1884 ApplyQOS(remoteAddress);
1886 return RTP_Session::e_ProcessPacket;
1889 switch (socket.GetErrorNumber()) {
1890 case ECONNRESET :
1891 case ECONNREFUSED :
1892 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", "
1893 << channelName << " port on remote not ready.");
1894 return RTP_Session::e_IgnorePacket;
1896 case EAGAIN :
1897 // Shouldn't happen, but it does.
1898 return RTP_Session::e_IgnorePacket;
1900 default:
1901 PTRACE(1, "RTP_UDP\t" << channelName << " read error ("
1902 << socket.GetErrorNumber(PChannel::LastReadError) << "): "
1903 << socket.GetErrorText(PChannel::LastReadError));
1904 return RTP_Session::e_AbortTransport;
1909 RTP_Session::SendReceiveStatus RTP_UDP::ReadDataPDU(RTP_DataFrame & frame)
1911 SendReceiveStatus status = ReadDataOrControlPDU(*dataSocket, frame, TRUE);
1912 if (status != e_ProcessPacket)
1913 return status;
1915 // Check received PDU is big enough
1916 PINDEX pduSize = dataSocket->GetLastReadCount();
1917 if (pduSize < RTP_DataFrame::MinHeaderSize || pduSize < frame.GetHeaderSize()) {
1918 PTRACE(2, "RTP_UDP\tSession " << sessionID
1919 << ", Received data packet too small: " << pduSize << " bytes");
1920 return e_IgnorePacket;
1923 frame.SetPayloadSize(pduSize - frame.GetHeaderSize());
1924 return OnReceiveData(frame);
1928 RTP_Session::SendReceiveStatus RTP_UDP::ReadControlPDU()
1930 RTP_ControlFrame frame(2048);
1932 SendReceiveStatus status = ReadDataOrControlPDU(*controlSocket, frame, FALSE);
1933 if (status != e_ProcessPacket)
1934 return status;
1936 PINDEX pduSize = controlSocket->GetLastReadCount();
1937 if (pduSize < 4 || pduSize < 4+frame.GetPayloadSize()) {
1938 PTRACE(2, "RTP_UDP\tSession " << sessionID
1939 << ", Received control packet too small: " << pduSize << " bytes");
1940 return e_IgnorePacket;
1943 frame.SetSize(pduSize);
1944 return OnReceiveControl(frame);
1948 BOOL RTP_UDP::WriteData(RTP_DataFrame & frame)
1950 if (shutdownWrite) {
1951 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Write shutdown.");
1952 shutdownWrite = FALSE;
1953 return FALSE;
1956 // Trying to send a PDU before we are set up!
1957 if (!remoteAddress.IsValid() || remoteDataPort == 0)
1958 return TRUE;
1960 switch (OnSendData(frame)) {
1961 case e_ProcessPacket :
1962 break;
1963 case e_IgnorePacket :
1964 return TRUE;
1965 case e_AbortTransport :
1966 return FALSE;
1969 while (!dataSocket->WriteTo(frame.GetPointer(),
1970 frame.GetHeaderSize()+frame.GetPayloadSize(),
1971 remoteAddress, remoteDataPort)) {
1972 switch (dataSocket->GetErrorNumber()) {
1973 case ECONNRESET :
1974 case ECONNREFUSED :
1975 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", data port on remote not ready.");
1976 break;
1978 default:
1979 PTRACE(1, "RTP_UDP\tSession " << sessionID
1980 << ", Write error on data port ("
1981 << dataSocket->GetErrorNumber(PChannel::LastWriteError) << "): "
1982 << dataSocket->GetErrorText(PChannel::LastWriteError));
1983 return FALSE;
1987 return TRUE;
1991 BOOL RTP_UDP::WriteControl(RTP_ControlFrame & frame)
1993 // Trying to send a PDU before we are set up!
1994 if (!remoteAddress.IsValid() || remoteControlPort == 0)
1995 return TRUE;
1997 while (!controlSocket->WriteTo(frame.GetPointer(), frame.GetCompoundSize(),
1998 remoteAddress, remoteControlPort)) {
1999 switch (controlSocket->GetErrorNumber()) {
2000 case ECONNRESET :
2001 case ECONNREFUSED :
2002 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", control port on remote not ready.");
2003 break;
2005 default:
2006 PTRACE(1, "RTP_UDP\tSession " << sessionID
2007 << ", Write error on control port ("
2008 << controlSocket->GetErrorNumber(PChannel::LastWriteError) << "): "
2009 << controlSocket->GetErrorText(PChannel::LastWriteError));
2013 return TRUE;
2017 /////////////////////////////////////////////////////////////////////////////