Tidied some trace logs to assure all have a category (bit before a tab character...
[opal/cbnco.git] / src / rtp / rtp.cxx
blob5ba41488c3eb99a9503e633f4452a36513f3310c
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 2.58 2007/04/02 05:51:34 rjongbloed
31 * Tidied some trace logs to assure all have a category (bit before a tab character) set.
33 * Revision 2.57 2007/03/29 23:53:39 rjongbloed
34 * Fixed log message about swallowing UDP packets so only prints out
35 * if non-zero packets were swallowed.
37 * Revision 2.56 2007/03/29 05:07:34 csoutheren
38 * Removed annoying comment
40 * Revision 2.55 2007/03/28 05:26:11 csoutheren
41 * Add virtual function to wait for incoming data
42 * Swallow RTP packets that arrive on the socket before session starts
44 * Revision 2.54 2007/03/20 02:32:09 csoutheren
45 * Don't send BYE twice or when channel is closed
47 * Revision 2.53 2007/03/12 23:05:14 csoutheren
48 * Fix typo and increase readability
50 * Revision 2.52 2007/03/08 04:36:25 csoutheren
51 * Add flag to close RTP session when RTCP BYE received
53 * Revision 2.51 2007/03/01 03:31:25 csoutheren
54 * Remove spurious zero bytes from the end of RTCP SDES packets
55 * Fix format of RTCP BYE packets
57 * Revision 2.50 2007/02/23 08:06:20 csoutheren
58 * More implementation of ZRTP (not yet complete)
60 * Revision 2.49 2007/02/20 21:35:45 csoutheren
61 * Fixed stupid typo in RTP open
63 * Revision 2.48 2007/02/20 04:26:57 csoutheren
64 * Ensure outgoing and incoming SSRC are set for SRTP sessions
65 * Fixed problem with sending secure RTCP packets
67 * Revision 2.47 2007/02/12 02:44:27 csoutheren
68 * Start of support for ZRTP
70 * Revision 2.47 2007/02/10 07:08:41 craigs
71 * Start of support for ZRTP
73 * Revision 2.46 2006/12/08 04:12:12 csoutheren
74 * Applied 1589274 - better rtp error handling of malformed rtcp packet
75 * Thanks to frederich
77 * Revision 2.45 2006/11/29 06:31:59 csoutheren
78 * Add support fort RTP BYE
80 * Revision 2.44 2006/11/20 03:37:13 csoutheren
81 * Allow optional inclusion of RTP aggregation
83 * Revision 2.43 2006/11/10 12:40:30 csoutheren
84 * Fix RTP payload extension size calculation
85 * Thanks to Viktor Krikun
87 * Revision 2.42 2006/10/28 16:40:28 dsandras
88 * Fixed SIP reinvite without breaking H.323 calls.
90 * Revision 2.41 2006/10/24 04:18:28 csoutheren
91 * Added support for encrypted RTCP
93 * Revision 2.40 2006/09/28 07:42:18 csoutheren
94 * Merge of useful SRTP implementation
96 * Revision 2.39 2006/09/08 05:12:26 csoutheren
97 * Reverted previous patch as this breaks H.323 calls
99 * Revision 2.38 2006/09/05 06:18:23 csoutheren
100 * Start bringing in SRTP code for libSRTP
102 * Revision 2.37 2006/08/29 18:39:21 dsandras
103 * Added function to better deal with reinvites.
105 * Revision 2.36 2006/08/28 00:03:00 csoutheren
106 * Applied 1545095 - RTP destructors patch
107 * Thanks to Drazen Dimoti
109 * Revision 2.35 2006/08/21 05:24:36 csoutheren
110 * Add extra trace log to allow tracking of NAT detection
112 * Revision 2.34 2006/08/03 04:57:12 csoutheren
113 * Port additional NAT handling logic from OpenH323 and extend into OpalConnection class
115 * Revision 2.33 2006/07/28 10:41:51 rjongbloed
116 * Fixed DevStudio 2005 warnings on time_t conversions.
118 * Revision 2.32 2006/06/22 00:26:26 csoutheren
119 * Fix formatting
121 * Revision 2.31 2006/06/05 20:12:48 dsandras
122 * Prevent infinite loop when being unable to write to the control port of the
123 * RTP session. Fixes Ekiga #339306.
125 * Revision 2.30 2006/04/30 16:41:14 dsandras
126 * Allow exactly one sequence change after a call to SetRemoteSocketInfo. Fixes
127 * Ekiga bug #339866.
129 * Revision 2.29 2006/03/28 11:20:22 dsandras
130 * If STUN can not create a socket pair for RTP/RTCP, create separate sockets
131 * and continue. At worse, RTCP won't be received. The SIP part could reuse
132 * the RTCP port (different from RTP port + 1) in its SDP if required.
134 * Revision 2.28 2006/02/02 07:03:44 csoutheren
135 * Added extra logging of first outgoing RTP packet
137 * Revision 2.27 2006/01/24 23:31:07 dsandras
138 * Fixed bug.
140 * Revision 2.26 2006/01/22 21:53:23 dsandras
141 * Fail when STUN needs to be used and can not be used.
143 * Revision 2.25 2005/12/30 14:29:15 dsandras
144 * Removed the assumption that the jitter will contain a 8 kHz signal.
146 * Revision 2.24 2005/11/29 11:50:20 dsandras
147 * Use PWaitAndSignal so that it works even if no AddSession follows the UseSession. Added missing ignoreOtherSources check.
149 * Revision 2.23 2005/11/22 22:37:57 dsandras
150 * Reverted the previous change as the bug was triggered by a change in PWLIB.
152 * Revision 2.22 2005/11/20 20:56:35 dsandras
153 * Allow UseSession to be used and fail without requiring a consecutive AddSession.
155 * Revision 2.21 2005/10/20 20:27:38 dsandras
156 * Better handling of dynamic RTP session IP address changes.
158 * Revision 2.20 2005/08/04 17:17:08 dsandras
159 * Fixed remote address change of an established RTP Session.
161 * Revision 2.19 2005/04/11 17:34:57 dsandras
162 * Added support for dynamic sequence changes in case of Re-INVITE.
164 * Revision 2.18 2005/04/10 21:17:05 dsandras
165 * Added support for remote address and SyncSource changes during an active RTP Session.
167 * Revision 2.17 2005/01/16 23:07:35 csoutheren
168 * Fixed problem with IPv6 INADDR_ANY
170 * Revision 2.16 2004/04/26 05:37:13 rjongbloed
171 * Allowed for selectable auto deletion of RTP user data attached to an RTP session.
173 * Revision 2.15 2004/03/02 10:02:46 rjongbloed
174 * Added check for unusual error in reading UDP socket, thanks Michael Smith
176 * Revision 2.14 2004/03/02 09:57:54 rjongbloed
177 * Fixed problems with recent changes to RTP UseSession() function which broke it for H.323
179 * Revision 2.13 2004/02/19 10:47:06 rjongbloed
180 * Merged OpenH323 version 1.13.1 changes.
182 * Revision 2.12 2003/01/07 04:39:53 robertj
183 * Updated to OpenH323 v1.11.2
185 * Revision 2.11 2002/11/10 11:33:20 robertj
186 * Updated to OpenH323 v1.10.3
188 * Revision 2.10 2002/10/09 04:28:10 robertj
189 * Added session ID to soem trace logs, thanks Ted Szoczei
191 * Revision 2.9 2002/09/04 06:01:49 robertj
192 * Updated to OpenH323 v1.9.6
194 * Revision 2.8 2002/07/01 04:56:33 robertj
195 * Updated to OpenH323 v1.9.1
197 * Revision 2.7 2002/04/10 03:10:39 robertj
198 * Added referential (container) copy functions to session manager class.
200 * Revision 2.6 2002/02/11 09:32:13 robertj
201 * Updated to openH323 v1.8.0
203 * Revision 2.5 2002/01/14 06:35:58 robertj
204 * Updated to OpenH323 v1.7.9
206 * Revision 2.4 2002/01/14 02:24:06 robertj
207 * Fixed possible divide by zero error in statistics.
209 * Revision 2.3 2001/12/07 08:52:28 robertj
210 * Used new const PWaitAndSignal
212 * Revision 2.2 2001/11/14 06:20:40 robertj
213 * Changed sending of control channel reports to be timer based.
215 * Revision 2.1 2001/10/05 00:22:14 robertj
216 * Updated to PWLib 1.2.0 and OpenH323 1.7.0
218 * Revision 2.0 2001/07/27 15:48:25 robertj
219 * Conversion of OpenH323 to Open Phone Abstraction Library (OPAL)
221 * Revision 1.92 2004/02/09 11:17:50 rjongbloed
222 * Improved check for compound RTCP packets so does not possibly acess
223 * memory beyond that allocated in packet. Pointed out by Paul Slootman
225 * Revision 1.91 2003/10/28 22:35:21 dereksmithies
226 * Fix warning about possible use of unitialized variable.
228 * Revision 1.90 2003/10/27 06:03:39 csoutheren
229 * Added support for QoS
230 * Thanks to Henry Harrison of AliceStreet
232 * Revision 1.89 2003/10/09 09:47:45 csoutheren
233 * Fixed problem with re-opening RTP half-channels under unusual
234 * circumstances. Thanks to Damien Sandras
236 * Revision 1.88 2003/05/02 04:57:47 robertj
237 * Added header extension support to RTP data frame class.
239 * Revision 1.87 2003/02/07 00:30:21 robertj
240 * Changes for bizarre usage of RTP code outside of scope of H.323 specs.
242 * Revision 1.86 2003/02/04 23:50:06 robertj
243 * Changed trace log for RTP session creation to show local address.
245 * Revision 1.85 2003/02/04 07:06:42 robertj
246 * Added STUN support.
248 * Revision 1.84 2003/01/07 06:32:22 robertj
249 * Fixed faint possibility of getting an error on UDP write caused by ICMP
250 * unreachable being received when no UDP read is active on the socket. Then
251 * the UDP write gets the error stopping transmission.
253 * Revision 1.83 2002/11/19 01:48:00 robertj
254 * Allowed get/set of canonical anme and tool name.
256 * Revision 1.82 2002/11/05 03:32:04 robertj
257 * Added session ID to trace logs.
258 * Fixed possible extra wait exiting RTP read loop on close.
260 * Revision 1.81 2002/11/05 01:55:50 robertj
261 * Added comments about strange mutex usage.
263 * Revision 1.80 2002/10/31 00:47:07 robertj
264 * Enhanced jitter buffer system so operates dynamically between minimum and
265 * maximum values. Altered API to assure app writers note the change!
267 * Revision 1.79 2002/09/26 04:01:49 robertj
268 * Fixed calculation of fraction of packets lost in RR, thanks Awais Ali
270 * Revision 1.78 2002/09/03 06:15:32 robertj
271 * Added copy constructor/operator for session manager.
273 * Revision 1.77 2002/08/05 10:03:48 robertj
274 * Cosmetic changes to normalise the usage of pragma interface/implementation.
276 * Revision 1.76 2002/07/23 06:28:16 robertj
277 * Added statistics call back on first sent or received RTP packet, helps with,
278 * for example, detecting if remote endpoint has started to send audio.
280 * Revision 1.75 2002/05/28 02:37:55 robertj
281 * Fixed reading data out of RTCP compound statements.
283 * Revision 1.74 2002/05/21 07:12:39 robertj
284 * Fixed 100% CPU usage loop for checkin on sending RTCP data if
285 * have no RTP data transferred at all.
287 * Revision 1.73 2002/05/02 05:58:28 robertj
288 * Changed the mechanism for sending RTCP reports so that they will continue
289 * to be sent regardless of if there is any actual data traffic.
290 * Added support for compound RTCP statements for sender and receiver reports.
292 * Revision 1.72 2002/04/18 05:48:58 robertj
293 * Fixed problem with new SSRC value being ignored after RTP session has
294 * been restarted, thanks "Jacky".
296 * Revision 1.71 2002/02/09 02:33:49 robertj
297 * Improved payload type docuemntation and added Cisco CN.
299 * Revision 1.70 2001/12/20 04:34:56 robertj
300 * Fixed display of some of the unknown RTP types.
302 * Revision 1.69 2001/09/12 07:48:05 robertj
303 * Fixed various problems with tracing.
305 * Revision 1.68 2001/09/11 00:21:24 robertj
306 * Fixed missing stack sizes in endpoint for cleaner thread and jitter thread.
308 * Revision 1.67 2001/09/10 08:24:04 robertj
309 * Fixed setting of destination RTP address so works with endpoints that
310 * do not get the OLC packets quite right.
312 * Revision 1.66 2001/07/11 03:23:54 robertj
313 * Bug fixed where every 65536 PDUs the session thinks it is the first PDU again.
315 * Revision 1.65 2001/07/06 06:32:24 robertj
316 * Added flag and checks for RTP data having specific SSRC.
317 * Changed transmitter IP address check so is based on first received
318 * PDU instead of expecting it to come from the host we are sending to.
320 * Revision 1.64 2001/06/04 13:43:44 robertj
321 * Fixed I/O block breaker code if RTP session is bound to INADDR_ANY interface.
323 * Revision 1.63 2001/06/04 11:37:50 robertj
324 * Added thread safe enumeration functions of RTP sessions.
325 * Added member access functions to UDP based RTP sessions.
327 * Revision 1.62 2001/05/24 01:12:23 robertj
328 * Fixed sender report timestamp field, thanks Johan Gnosspelius
330 * Revision 1.61 2001/05/08 05:28:02 yurik
331 * No ifdef _WIN32_WCE anymore - 3+ version of SDK allows it
333 * Revision 1.60 2001/04/24 06:15:50 robertj
334 * Added work around for strange Cisco bug which suddenly starts sending
335 * RTP packets beginning at a difference sequence number base.
337 * Revision 1.59 2001/04/02 23:58:24 robertj
338 * Added jitter calculation to RTP session.
339 * Added trace of statistics.
341 * Revision 1.58 2001/03/20 07:24:05 robertj
342 * Changed RTP SDES to have simple host name instead of attempting a
343 * reverse DNS lookup on IP address as badly configured DNS can cause
344 * a 30 second delay before audio is sent.
346 * Revision 1.57 2001/03/15 05:45:45 robertj
347 * Changed, yet again, the setting of RTP info to allow for Cisco idosyncracies.
349 * Revision 1.56 2001/02/21 08:08:26 robertj
350 * Added more debugging.
352 * Revision 1.55 2001/02/09 05:13:56 craigs
353 * Added pragma implementation to (hopefully) reduce the executable image size
354 * under Linux
356 * Revision 1.54 2001/01/28 07:06:59 yurik
357 * WinCE-port - avoid using of IP_TOS
359 * Revision 1.53 2000/12/18 08:59:20 craigs
360 * Added ability to set ports
362 * Revision 1.52 2000/09/25 22:27:40 robertj
363 * Fixed uninitialised variable for lastRRSequenceNumber
365 * Revision 1.51 2000/09/25 01:53:20 robertj
366 * Fixed MSVC warnings.
368 * Revision 1.50 2000/09/25 01:44:13 robertj
369 * Fixed possible race condition on shutdown of RTP session with jitter buffer.
371 * Revision 1.49 2000/09/22 00:32:34 craigs
372 * Added extra logging
373 * Fixed problems with no fastConnect with tunelling
375 * Revision 1.48 2000/09/21 02:06:07 craigs
376 * Added handling for endpoints that return conformant, but useless, RTP address
377 * and port numbers
379 * Revision 1.47 2000/08/17 00:42:39 robertj
380 * Fixed RTP Goodbye message reason string parsing, thanks Thien Nguyen.
382 * Revision 1.46 2000/05/30 10:35:41 robertj
383 * Fixed GNU compiler warning.
385 * Revision 1.45 2000/05/30 06:52:26 robertj
386 * Fixed problem with Cisco restarting sequence numbers when changing H.323 logical channels.
388 * Revision 1.44 2000/05/23 12:57:37 robertj
389 * Added ability to change IP Type Of Service code from applications.
391 * Revision 1.43 2000/05/12 00:27:35 robertj
392 * Fixed bug in UseSession() that caused asserts on BSD and possible race condition everywhere.
394 * Revision 1.42 2000/05/04 11:52:35 robertj
395 * Added Packets Too Late statistics, requiring major rearrangement of jitter
396 * buffer code, not also changes semantics of codec Write() function slightly.
398 * Revision 1.41 2000/05/02 04:32:27 robertj
399 * Fixed copyright notice comment.
401 * Revision 1.40 2000/05/01 01:01:49 robertj
402 * Added flag for what to do with out of orer packets (use if jitter, don't if not).
404 * Revision 1.39 2000/04/30 03:55:09 robertj
405 * Improved the RTCP messages, epecially reports
407 * Revision 1.38 2000/04/28 12:56:39 robertj
408 * Fixed transmission of SDES record in RTCP channel.
410 * Revision 1.37 2000/04/19 01:50:05 robertj
411 * Improved debugging messages.
413 * Revision 1.36 2000/04/13 18:07:39 robertj
414 * Fixed missing mutex release causing possible deadlocks.
416 * Revision 1.35 2000/04/10 17:40:05 robertj
417 * Fixed debug output of RTP payload types to allow for unknown numbers.
419 * Revision 1.34 2000/04/05 04:09:24 robertj
420 * Fixed portability problem with max() macro.
422 * Revision 1.33 2000/04/05 03:17:32 robertj
423 * Added more RTP statistics gathering and H.245 round trip delay calculation.
425 * Revision 1.32 2000/04/03 18:15:44 robertj
426 * Added "fractional" part of RTCP status NTP timestamp field.
428 * Revision 1.31 2000/03/23 02:54:57 robertj
429 * Added sending of SDES control packets.
431 * Revision 1.30 2000/03/20 20:53:42 robertj
432 * Fixed problem with being able to reopen for reading an RTP_Session (Cisco compatibilty)
434 * Revision 1.29 2000/03/04 12:32:23 robertj
435 * Added setting of TOS field in IP header to get poor mans QoS on some routers.
437 * Revision 1.28 2000/02/29 13:00:13 robertj
438 * Added extra statistic display for RTP packets out of order.
440 * Revision 1.27 2000/02/29 02:13:56 robertj
441 * Fixed RTP receive of both control and data, ignores ECONNRESET/ECONNREFUSED errors.
443 * Revision 1.26 2000/02/27 10:56:24 robertj
444 * Fixed error in code allowing non-consecutive RTP port numbers coming from broken stacks, thanks Vassili Leonov.
446 * Revision 1.25 2000/02/17 12:07:44 robertj
447 * Used ne wPWLib random number generator after finding major problem in MSVC rand().
449 * Revision 1.24 2000/01/29 07:10:20 robertj
450 * Fixed problem with RTP transmit to host that is not yet ready causing the
451 * receive side to die with ECONNRESET, thanks Ian MacDonald
453 * Revision 1.23 2000/01/20 05:57:46 robertj
454 * Added extra flexibility in receiving incorrectly formed OpenLogicalChannel PDU's
456 * Revision 1.22 2000/01/14 00:31:40 robertj
457 * Bug fix for RTP port allocation (MSVC optimised version), Thanks to Ian MacDonald.
459 * Revision 1.21 1999/12/30 09:14:49 robertj
460 * Changed payload type functions to use enum.
462 * Revision 1.20 1999/12/23 23:02:36 robertj
463 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
465 * Revision 1.19 1999/11/29 04:50:11 robertj
466 * Added adaptive threshold calculation to silence detection.
468 * Revision 1.18 1999/11/22 00:09:59 robertj
469 * Fixed error in RTP transmit rewrite for ternary state, didn't transmit at all!
471 * Revision 1.17 1999/11/20 05:35:48 robertj
472 * Fixed possibly I/O block in RTP read loops.
474 * Revision 1.16 1999/11/19 13:13:31 robertj
475 * Fixed Windows 95 compatibility issue in shutdown of RTP reading.
477 * Revision 1.15 1999/11/19 10:23:16 robertj
478 * Fixed local binding of socket to correct address on multi-homes systems.
480 * Revision 1.14 1999/11/19 09:17:15 robertj
481 * Fixed problems with aycnhronous shut down of logical channels.
483 * Revision 1.13 1999/11/17 03:49:51 robertj
484 * Added RTP statistics display.
486 * Revision 1.12 1999/11/14 11:41:07 robertj
487 * Added access functions to RTP statistics.
489 * Revision 1.11 1999/10/18 23:55:11 robertj
490 * Fixed bug in setting contributing sources, length put into wrong spot in PDU header
492 * Revision 1.10 1999/09/21 14:10:04 robertj
493 * Removed warnings when no tracing enabled.
495 * Revision 1.9 1999/09/05 00:58:37 robertj
496 * Removed requirement that OpenLogicalChannalAck sessionId match original OLC.
498 * Revision 1.8 1999/09/03 02:17:50 robertj
499 * Added more debugging
501 * Revision 1.7 1999/08/31 12:34:19 robertj
502 * Added gatekeeper support.
504 * Revision 1.6 1999/07/16 02:13:54 robertj
505 * Slowed down the control channel statistics packets.
507 * Revision 1.5 1999/07/13 09:53:24 robertj
508 * Fixed some problems with jitter buffer and added more debugging.
510 * Revision 1.4 1999/07/09 06:09:52 robertj
511 * Major implementation. An ENORMOUS amount of stuff added everywhere.
513 * Revision 1.3 1999/06/22 13:49:40 robertj
514 * Added GSM support and further RTP protocol enhancements.
516 * Revision 1.2 1999/06/14 08:42:52 robertj
517 * Fixed bug in dropped packets display was negative.
519 * Revision 1.1 1999/06/14 06:12:25 robertj
520 * Changes for using RTP sessions correctly in H323 Logical Channel context
524 #include <ptlib.h>
526 #ifdef __GNUC__
527 #pragma implementation "rtp.h"
528 #endif
530 #include <rtp/rtp.h>
532 #include <rtp/jitter.h>
533 #include <ptclib/random.h>
534 #include <ptclib/pstun.h>
535 #include <opal/connection.h>
537 #define new PNEW
540 const unsigned SecondsFrom1900to1970 = (70*365+17)*24*60*60U;
542 #define UDP_BUFFER_SIZE 32768
544 #define MIN_HEADER_SIZE 12
546 namespace PWLibStupidLinkerHacks {
547 extern int opalLoader;
549 static class InstantiateMe
551 public:
552 InstantiateMe()
554 opalLoader = 1;
556 } instance;
558 }; // namespace PWLibStupidLinkerHacks
560 /////////////////////////////////////////////////////////////////////////////
562 RTP_DataFrame::RTP_DataFrame(PINDEX sz)
563 : PBYTEArray(MIN_HEADER_SIZE+sz)
565 payloadSize = sz;
566 theArray[0] = '\x80';
570 RTP_DataFrame::RTP_DataFrame(const BYTE * data, PINDEX len)
571 : PBYTEArray(data, len)
573 payloadSize = len - GetHeaderSize();
576 void RTP_DataFrame::SetExtension(BOOL ext)
578 if (ext)
579 theArray[0] |= 0x10;
580 else
581 theArray[0] &= 0xef;
585 void RTP_DataFrame::SetMarker(BOOL m)
587 if (m)
588 theArray[1] |= 0x80;
589 else
590 theArray[1] &= 0x7f;
594 void RTP_DataFrame::SetPayloadType(PayloadTypes t)
596 PAssert(t <= 0x7f, PInvalidParameter);
598 theArray[1] &= 0x80;
599 theArray[1] |= t;
603 DWORD RTP_DataFrame::GetContribSource(PINDEX idx) const
605 PAssert(idx < GetContribSrcCount(), PInvalidParameter);
606 return ((PUInt32b *)&theArray[MIN_HEADER_SIZE])[idx];
610 void RTP_DataFrame::SetContribSource(PINDEX idx, DWORD src)
612 PAssert(idx <= 15, PInvalidParameter);
614 if (idx >= GetContribSrcCount()) {
615 BYTE * oldPayload = GetPayloadPtr();
616 theArray[0] &= 0xf0;
617 theArray[0] |= idx+1;
618 SetSize(GetHeaderSize()+payloadSize);
619 memmove(GetPayloadPtr(), oldPayload, payloadSize);
622 ((PUInt32b *)&theArray[MIN_HEADER_SIZE])[idx] = src;
626 PINDEX RTP_DataFrame::GetHeaderSize() const
628 PINDEX sz = MIN_HEADER_SIZE + 4*GetContribSrcCount();
630 if (GetExtension())
631 sz += 4 + GetExtensionSize();
633 return sz;
637 int RTP_DataFrame::GetExtensionType() const
639 if (GetExtension())
640 return *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount()];
642 return -1;
646 void RTP_DataFrame::SetExtensionType(int type)
648 if (type < 0)
649 SetExtension(FALSE);
650 else {
651 if (!GetExtension())
652 SetExtensionSize(0);
653 *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount()] = (WORD)type;
658 PINDEX RTP_DataFrame::GetExtensionSize() const
660 if (GetExtension())
661 return *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 2] * 4;
663 return 0;
667 BOOL RTP_DataFrame::SetExtensionSize(PINDEX sz)
669 if (!SetMinSize(MIN_HEADER_SIZE + 4*GetContribSrcCount() + 4+4*sz + payloadSize))
670 return FALSE;
672 SetExtension(TRUE);
673 *(PUInt16b *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 2] = (WORD)sz;
674 return TRUE;
678 BYTE * RTP_DataFrame::GetExtensionPtr() const
680 if (GetExtension())
681 return (BYTE *)&theArray[MIN_HEADER_SIZE + 4*GetContribSrcCount() + 4];
683 return NULL;
687 BOOL RTP_DataFrame::SetPayloadSize(PINDEX sz)
689 payloadSize = sz;
690 return SetMinSize(GetHeaderSize()+payloadSize);
694 #if PTRACING
695 static const char * const PayloadTypesNames[RTP_DataFrame::LastKnownPayloadType] = {
696 "PCMU",
697 "FS1016",
698 "G721",
699 "GSM",
700 "G7231",
701 "DVI4_8k",
702 "DVI4_16k",
703 "LPC",
704 "PCMA",
705 "G722",
706 "L16_Stereo",
707 "L16_Mono",
708 "G723",
709 "CN",
710 "MPA",
711 "G728",
712 "DVI4_11k",
713 "DVI4_22k",
714 "G729",
715 "CiscoCN",
716 NULL, NULL, NULL, NULL, NULL,
717 "CelB",
718 "JPEG",
719 NULL, NULL, NULL, NULL,
720 "H261",
721 "MPV",
722 "MP2T",
723 "H263"
726 ostream & operator<<(ostream & o, RTP_DataFrame::PayloadTypes t)
728 if ((PINDEX)t < PARRAYSIZE(PayloadTypesNames) && PayloadTypesNames[t] != NULL)
729 o << PayloadTypesNames[t];
730 else
731 o << "[pt=" << (int)t << ']';
732 return o;
735 #endif
738 /////////////////////////////////////////////////////////////////////////////
740 RTP_ControlFrame::RTP_ControlFrame(PINDEX sz)
741 : PBYTEArray(sz)
743 compoundOffset = 0;
744 payloadSize = 0;
748 void RTP_ControlFrame::SetCount(unsigned count)
750 PAssert(count < 32, PInvalidParameter);
751 theArray[compoundOffset] &= 0xe0;
752 theArray[compoundOffset] |= count;
756 void RTP_ControlFrame::SetPayloadType(unsigned t)
758 PAssert(t < 256, PInvalidParameter);
759 theArray[compoundOffset+1] = (BYTE)t;
762 PINDEX RTP_ControlFrame::GetCompoundSize() const
764 // transmitted length is the offset of the last compound block
765 // plus the compound length of the last block
766 return compoundOffset + *(PUInt16b *)&theArray[compoundOffset+2]*4;
769 void RTP_ControlFrame::SetPayloadSize(PINDEX sz)
771 payloadSize = sz;
773 // compound size is in words, rounded up to nearest word
774 PINDEX compoundSize = (payloadSize + 3) & ~3;
775 PAssert(compoundSize <= 0xffff, PInvalidParameter);
777 // make sure buffer is big enough for previous packets plus packet header plus payload
778 SetMinSize(compoundOffset + 4 + 4*(compoundSize));
780 // put the new compound size into the packet (always at offset 2)
781 *(PUInt16b *)&theArray[compoundOffset+2] = (WORD)(compoundSize / 4);
784 BYTE * RTP_ControlFrame::GetPayloadPtr() const
786 // payload for current packet is always one DWORD after the current compound start
787 if ((GetPayloadSize() == 0) || ((compoundOffset + 4) >= GetSize()))
788 return NULL;
789 return (BYTE *)(theArray + compoundOffset + 4);
792 BOOL RTP_ControlFrame::ReadNextPacket()
794 // skip over current packet
795 compoundOffset += GetPayloadSize() + 4;
797 // see if another packet is feasible
798 if (compoundOffset + 4 > GetSize())
799 return FALSE;
801 // check if payload size for new packet is legal
802 return compoundOffset + GetPayloadSize() + 4 <= GetSize();
806 BOOL RTP_ControlFrame::StartNewPacket()
808 // allocate storage for new packet header
809 if (!SetMinSize(compoundOffset + 4))
810 return FALSE;
812 theArray[compoundOffset] = '\x80'; // Set version 2
813 theArray[compoundOffset+1] = 0; // Set payload type to illegal
814 theArray[compoundOffset+2] = 0; // Set payload size to zero
815 theArray[compoundOffset+3] = 0;
817 // payload is now zero bytes
818 payloadSize = 0;
819 SetPayloadSize(payloadSize);
821 return TRUE;
824 void RTP_ControlFrame::EndPacket()
826 // all packets must align to DWORD boundaries
827 while (((4 + payloadSize) & 3) != 0) {
828 theArray[compoundOffset + 4 + payloadSize - 1] = 0;
829 ++payloadSize;
832 compoundOffset += 4 + payloadSize;
833 payloadSize = 0;
836 void RTP_ControlFrame::StartSourceDescription(DWORD src)
838 // extend payload to include SSRC + END
839 SetPayloadSize(payloadSize + 4 + 1);
840 SetPayloadType(RTP_ControlFrame::e_SourceDescription);
841 SetCount(GetCount()+1); // will be incremented automatically
843 // get ptr to new item SDES
844 BYTE * payload = GetPayloadPtr();
845 *(PUInt32b *)payload = src;
846 payload[4] = e_END;
850 void RTP_ControlFrame::AddSourceDescriptionItem(unsigned type, const PString & data)
852 // get ptr to new item, remembering that END was inserted previously
853 BYTE * payload = GetPayloadPtr() + payloadSize - 1;
855 // length of new item
856 PINDEX dataLength = data.GetLength();
858 // add storage for new item (note that END has already been included)
859 SetPayloadSize(payloadSize + 1 + 1 + dataLength);
861 // insert new item
862 payload[0] = (BYTE)type;
863 payload[1] = (BYTE)dataLength;
864 memcpy(payload+2, (const char *)data, dataLength);
866 // insert new END
867 payload[2+dataLength] = (BYTE)e_END;
871 void RTP_ControlFrame::ReceiverReport::SetLostPackets(unsigned packets)
873 lost[0] = (BYTE)(packets >> 16);
874 lost[1] = (BYTE)(packets >> 8);
875 lost[2] = (BYTE)packets;
879 /////////////////////////////////////////////////////////////////////////////
881 void RTP_UserData::OnTxStatistics(const RTP_Session & /*session*/) const
886 void RTP_UserData::OnRxStatistics(const RTP_Session & /*session*/) const
891 /////////////////////////////////////////////////////////////////////////////
893 RTP_Session::RTP_Session(
894 PHandleAggregator * _aggregator,
895 unsigned id, RTP_UserData * data, BOOL autoDelete)
896 : canonicalName(PProcess::Current().GetUserName()),
897 toolName(PProcess::Current().GetName()),
898 reportTimeInterval(0, 12), // Seconds
899 reportTimer(reportTimeInterval),
900 aggregator(_aggregator)
902 PAssert(id > 0 && id < 256, PInvalidParameter);
903 sessionID = (BYTE)id;
905 referenceCount = 1;
906 userData = data;
907 autoDeleteUserData = autoDelete;
908 jitter = NULL;
910 ignoreOtherSources = TRUE;
911 ignoreOutOfOrderPackets = TRUE;
912 ignorePayloadTypeChanges = TRUE;
913 syncSourceOut = PRandom::Number();
914 syncSourceIn = 0;
915 allowSyncSourceInChange = FALSE;
916 allowRemoteTransmitAddressChange = FALSE;
917 allowSequenceChange = FALSE;
918 txStatisticsInterval = 100; // Number of data packets between tx reports
919 rxStatisticsInterval = 100; // Number of data packets between rx reports
920 lastSentSequenceNumber = (WORD)PRandom::Number();
921 expectedSequenceNumber = 0;
922 lastRRSequenceNumber = 0;
923 consecutiveOutOfOrderPackets = 0;
925 packetsSent = 0;
926 rtcpPacketsSent = 0;
927 octetsSent = 0;
928 packetsReceived = 0;
929 octetsReceived = 0;
930 packetsLost = 0;
931 packetsOutOfOrder = 0;
932 averageSendTime = 0;
933 maximumSendTime = 0;
934 minimumSendTime = 0;
935 averageReceiveTime = 0;
936 maximumReceiveTime = 0;
937 minimumReceiveTime = 0;
938 jitterLevel = 0;
939 maximumJitterLevel = 0;
941 txStatisticsCount = 0;
942 rxStatisticsCount = 0;
943 averageSendTimeAccum = 0;
944 maximumSendTimeAccum = 0;
945 minimumSendTimeAccum = 0xffffffff;
946 averageReceiveTimeAccum = 0;
947 maximumReceiveTimeAccum = 0;
948 minimumReceiveTimeAccum = 0xffffffff;
949 packetsLostSinceLastRR = 0;
950 lastTransitTime = 0;
952 lastReceivedPayloadType = RTP_DataFrame::MaxPayloadType;
954 closeOnBye = FALSE;
955 byeSent = FALSE;
958 RTP_Session::~RTP_Session()
960 PTRACE_IF(2, packetsSent != 0 || packetsReceived != 0,
961 "RTP\tFinal statistics:\n"
962 " packetsSent = " << packetsSent << "\n"
963 " octetsSent = " << octetsSent << "\n"
964 " averageSendTime = " << averageSendTime << "\n"
965 " maximumSendTime = " << maximumSendTime << "\n"
966 " minimumSendTime = " << minimumSendTime << "\n"
967 " packetsReceived = " << packetsReceived << "\n"
968 " octetsReceived = " << octetsReceived << "\n"
969 " packetsLost = " << packetsLost << "\n"
970 " packetsTooLate = " << GetPacketsTooLate() << "\n"
971 " packetsOutOfOrder = " << packetsOutOfOrder << "\n"
972 " averageReceiveTime= " << averageReceiveTime << "\n"
973 " maximumReceiveTime= " << maximumReceiveTime << "\n"
974 " minimumReceiveTime= " << minimumReceiveTime << "\n"
975 " averageJitter = " << (jitterLevel >> 7) << "\n"
976 " maximumJitter = " << (maximumJitterLevel >> 7)
978 delete jitter;
979 if (autoDeleteUserData)
980 delete userData;
983 void RTP_Session::SendBYE()
985 if (byeSent)
986 return;
988 byeSent = TRUE;
990 RTP_ControlFrame report;
992 // if any packets sent, put in a non-zero report
993 // else put in a zero report
994 if (packetsSent != 0 || rtcpPacketsSent != 0)
995 InsertReportPacket(report);
996 else {
997 // Send empty RR as nothing has happened
998 report.StartNewPacket();
999 report.SetPayloadType(RTP_ControlFrame::e_ReceiverReport);
1000 report.SetPayloadSize(4); // length is SSRC
1001 report.SetCount(0);
1003 // add the SSRC to the start of the payload
1004 BYTE * payload = report.GetPayloadPtr();
1005 *(PUInt32b *)payload = syncSourceOut;
1006 report.EndPacket();
1009 const char * reasonStr = "session ending";
1011 // insert BYE
1012 report.StartNewPacket();
1013 report.SetPayloadType(RTP_ControlFrame::e_Goodbye);
1014 report.SetPayloadSize(4+1+strlen(reasonStr)); // length is SSRC + reasonLen + reason
1016 BYTE * payload = report.GetPayloadPtr();
1018 // one SSRC
1019 report.SetCount(1);
1020 *(PUInt32b *)payload = syncSourceOut;
1022 // insert reason
1023 payload[4] = (BYTE)strlen(reasonStr);
1024 memcpy((char *)(payload+5), reasonStr, payload[4]);
1026 report.EndPacket();
1027 WriteControl(report);
1030 PString RTP_Session::GetCanonicalName() const
1032 PWaitAndSignal mutex(reportMutex);
1033 PString s = canonicalName;
1034 s.MakeUnique();
1035 return s;
1039 void RTP_Session::SetCanonicalName(const PString & name)
1041 PWaitAndSignal mutex(reportMutex);
1042 canonicalName = name;
1046 PString RTP_Session::GetToolName() const
1048 PWaitAndSignal mutex(reportMutex);
1049 PString s = toolName;
1050 s.MakeUnique();
1051 return s;
1055 void RTP_Session::SetToolName(const PString & name)
1057 PWaitAndSignal mutex(reportMutex);
1058 toolName = name;
1062 void RTP_Session::SetUserData(RTP_UserData * data, BOOL autoDelete)
1064 if (autoDeleteUserData)
1065 delete userData;
1066 userData = data;
1067 autoDeleteUserData = autoDelete;
1071 void RTP_Session::SetJitterBufferSize(unsigned minJitterDelay,
1072 unsigned maxJitterDelay,
1073 unsigned timeUnits,
1074 PINDEX stackSize)
1076 if (minJitterDelay == 0 && maxJitterDelay == 0) {
1077 delete jitter;
1078 jitter = NULL;
1080 else if (jitter != NULL)
1081 jitter->SetDelay(minJitterDelay, maxJitterDelay);
1082 else {
1083 SetIgnoreOutOfOrderPackets(FALSE);
1084 jitter = new RTP_JitterBuffer(*this, minJitterDelay, maxJitterDelay, timeUnits, stackSize);
1085 jitter->Resume(aggregator);
1090 unsigned RTP_Session::GetJitterBufferSize() const
1092 return jitter != NULL ? jitter->GetJitterTime() : 0;
1095 unsigned RTP_Session::GetJitterTimeUnits() const
1097 return jitter != NULL ? jitter->GetTimeUnits() : 0;
1101 BOOL RTP_Session::ReadBufferedData(DWORD timestamp, RTP_DataFrame & frame)
1103 if (jitter != NULL)
1104 return jitter->ReadData(timestamp, frame);
1105 else
1106 return ReadData(frame, TRUE);
1110 void RTP_Session::SetTxStatisticsInterval(unsigned packets)
1112 txStatisticsInterval = PMAX(packets, 2);
1113 txStatisticsCount = 0;
1114 averageSendTimeAccum = 0;
1115 maximumSendTimeAccum = 0;
1116 minimumSendTimeAccum = 0xffffffff;
1120 void RTP_Session::SetRxStatisticsInterval(unsigned packets)
1122 rxStatisticsInterval = PMAX(packets, 2);
1123 rxStatisticsCount = 0;
1124 averageReceiveTimeAccum = 0;
1125 maximumReceiveTimeAccum = 0;
1126 minimumReceiveTimeAccum = 0xffffffff;
1130 void RTP_Session::AddReceiverReport(RTP_ControlFrame::ReceiverReport & receiver)
1132 receiver.ssrc = syncSourceIn;
1133 receiver.SetLostPackets(packetsLost);
1135 if (expectedSequenceNumber > lastRRSequenceNumber)
1136 receiver.fraction = (BYTE)((packetsLostSinceLastRR<<8)/(expectedSequenceNumber - lastRRSequenceNumber));
1137 else
1138 receiver.fraction = 0;
1139 packetsLostSinceLastRR = 0;
1141 receiver.last_seq = lastRRSequenceNumber;
1142 lastRRSequenceNumber = expectedSequenceNumber;
1144 receiver.jitter = jitterLevel >> 4; // Allow for rounding protection bits
1146 // The following have not been calculated yet.
1147 receiver.lsr = 0;
1148 receiver.dlsr = 0;
1150 PTRACE(3, "RTP\tSentReceiverReport:"
1151 " ssrc=" << receiver.ssrc
1152 << " fraction=" << (unsigned)receiver.fraction
1153 << " lost=" << receiver.GetLostPackets()
1154 << " last_seq=" << receiver.last_seq
1155 << " jitter=" << receiver.jitter
1156 << " lsr=" << receiver.lsr
1157 << " dlsr=" << receiver.dlsr);
1161 RTP_Session::SendReceiveStatus RTP_Session::OnSendData(RTP_DataFrame & frame)
1163 PTimeInterval tick = PTimer::Tick(); // Timestamp set now
1165 frame.SetSequenceNumber(++lastSentSequenceNumber);
1166 frame.SetSyncSource(syncSourceOut);
1168 PTRACE_IF(2, packetsSent == 0, "RTP\tFirst sent data:"
1169 " ver=" << frame.GetVersion()
1170 << " pt=" << frame.GetPayloadType()
1171 << " psz=" << frame.GetPayloadSize()
1172 << " m=" << frame.GetMarker()
1173 << " x=" << frame.GetExtension()
1174 << " seq=" << frame.GetSequenceNumber()
1175 << " ts=" << frame.GetTimestamp()
1176 << " src=" << frame.GetSyncSource()
1177 << " ccnt=" << frame.GetContribSrcCount());
1179 if (packetsSent != 0 && !frame.GetMarker()) {
1180 // Only do statistics on subsequent packets
1181 DWORD diff = (tick - lastSentPacketTime).GetInterval();
1183 averageSendTimeAccum += diff;
1184 if (diff > maximumSendTimeAccum)
1185 maximumSendTimeAccum = diff;
1186 if (diff < minimumSendTimeAccum)
1187 minimumSendTimeAccum = diff;
1188 txStatisticsCount++;
1191 lastSentTimestamp = frame.GetTimestamp();
1192 lastSentPacketTime = tick;
1194 octetsSent += frame.GetPayloadSize();
1195 packetsSent++;
1197 // Call the statistics call-back on the first PDU with total count == 1
1198 if (packetsSent == 1 && userData != NULL)
1199 userData->OnTxStatistics(*this);
1201 if (!SendReport())
1202 return e_AbortTransport;
1204 if (txStatisticsCount < txStatisticsInterval)
1205 return e_ProcessPacket;
1207 txStatisticsCount = 0;
1209 averageSendTime = averageSendTimeAccum/txStatisticsInterval;
1210 maximumSendTime = maximumSendTimeAccum;
1211 minimumSendTime = minimumSendTimeAccum;
1213 averageSendTimeAccum = 0;
1214 maximumSendTimeAccum = 0;
1215 minimumSendTimeAccum = 0xffffffff;
1217 PTRACE(2, "RTP\tTransmit statistics: "
1218 " packets=" << packetsSent <<
1219 " octets=" << octetsSent <<
1220 " avgTime=" << averageSendTime <<
1221 " maxTime=" << maximumSendTime <<
1222 " minTime=" << minimumSendTime
1225 if (userData != NULL)
1226 userData->OnTxStatistics(*this);
1228 return e_ProcessPacket;
1231 RTP_Session::SendReceiveStatus RTP_Session::OnSendControl(RTP_ControlFrame & /*frame*/, PINDEX & /*len*/)
1233 rtcpPacketsSent++;
1234 return e_ProcessPacket;
1237 RTP_Session::SendReceiveStatus RTP_Session::OnReceiveData(RTP_DataFrame & frame)
1239 // Check that the PDU is the right version
1240 if (frame.GetVersion() != RTP_DataFrame::ProtocolVersion)
1241 return e_IgnorePacket; // Non fatal error, just ignore
1243 // Check if expected payload type
1244 if (lastReceivedPayloadType == RTP_DataFrame::MaxPayloadType)
1245 lastReceivedPayloadType = frame.GetPayloadType();
1247 if (lastReceivedPayloadType != frame.GetPayloadType() && !ignorePayloadTypeChanges) {
1249 PTRACE(4, "RTP\tReceived payload type " << frame.GetPayloadType() << ", but was expecting " << lastReceivedPayloadType);
1250 return e_IgnorePacket;
1253 // Check for if a control packet rather than data packet.
1254 if (frame.GetPayloadType() > RTP_DataFrame::MaxPayloadType)
1255 return e_IgnorePacket; // Non fatal error, just ignore
1257 PTimeInterval tick = PTimer::Tick(); // Get timestamp now
1259 // Have not got SSRC yet, so grab it now
1260 if (syncSourceIn == 0)
1261 syncSourceIn = frame.GetSyncSource();
1263 // Check packet sequence numbers
1264 if (packetsReceived == 0) {
1265 expectedSequenceNumber = (WORD)(frame.GetSequenceNumber() + 1);
1266 PTRACE(2, "RTP\tFirst receive data:"
1267 " ver=" << frame.GetVersion()
1268 << " pt=" << frame.GetPayloadType()
1269 << " psz=" << frame.GetPayloadSize()
1270 << " m=" << frame.GetMarker()
1271 << " x=" << frame.GetExtension()
1272 << " seq=" << frame.GetSequenceNumber()
1273 << " ts=" << frame.GetTimestamp()
1274 << " src=" << frame.GetSyncSource()
1275 << " ccnt=" << frame.GetContribSrcCount());
1277 else {
1278 if (!ignoreOtherSources && frame.GetSyncSource() != syncSourceIn) {
1279 if (allowSyncSourceInChange) {
1280 syncSourceIn = frame.GetSyncSource();
1281 allowSyncSourceInChange = FALSE;
1283 else {
1284 PTRACE(2, "RTP\tPacket from SSRC=" << frame.GetSyncSource() << " ignored, expecting SSRC=" << syncSourceIn);
1285 return e_IgnorePacket; // Non fatal error, just ignore
1289 WORD sequenceNumber = frame.GetSequenceNumber();
1290 if (sequenceNumber == expectedSequenceNumber) {
1291 expectedSequenceNumber++;
1292 consecutiveOutOfOrderPackets = 0;
1293 // Only do statistics on packets after first received in talk burst
1294 if (!frame.GetMarker()) {
1295 DWORD diff = (tick - lastReceivedPacketTime).GetInterval();
1297 averageReceiveTimeAccum += diff;
1298 if (diff > maximumReceiveTimeAccum)
1299 maximumReceiveTimeAccum = diff;
1300 if (diff < minimumReceiveTimeAccum)
1301 minimumReceiveTimeAccum = diff;
1302 rxStatisticsCount++;
1304 // The following has the implicit assumption that something that has jitter
1305 // is an audio codec and thus is in 8kHz timestamp units.
1306 diff *= 8;
1307 long variance = diff - lastTransitTime;
1308 lastTransitTime = diff;
1309 if (variance < 0)
1310 variance = -variance;
1311 jitterLevel += variance - ((jitterLevel+8) >> 4);
1312 if (jitterLevel > maximumJitterLevel)
1313 maximumJitterLevel = jitterLevel;
1316 else if (allowSequenceChange) {
1317 expectedSequenceNumber = (WORD) (sequenceNumber + 1);
1318 allowSequenceChange = FALSE;
1320 else if (sequenceNumber < expectedSequenceNumber) {
1321 PTRACE(3, "RTP\tOut of order packet, received "
1322 << sequenceNumber << " expected " << expectedSequenceNumber
1323 << " ssrc=" << syncSourceIn);
1324 packetsOutOfOrder++;
1326 // Check for Cisco bug where sequence numbers suddenly start incrementing
1327 // from a different base.
1328 if (++consecutiveOutOfOrderPackets > 10) {
1329 expectedSequenceNumber = (WORD)(sequenceNumber + 1);
1330 PTRACE(1, "RTP\tAbnormal change of sequence numbers, adjusting to expect " << expectedSequenceNumber << " ssrc=" << syncSourceIn);
1333 if (ignoreOutOfOrderPackets)
1334 return e_IgnorePacket; // Non fatal error, just ignore
1336 else {
1337 unsigned dropped = sequenceNumber - expectedSequenceNumber;
1338 packetsLost += dropped;
1339 packetsLostSinceLastRR += dropped;
1340 PTRACE(3, "RTP\tDropped " << dropped << " packet(s) at " << sequenceNumber
1341 << ", ssrc=" << syncSourceIn);
1342 expectedSequenceNumber = (WORD)(sequenceNumber + 1);
1343 consecutiveOutOfOrderPackets = 0;
1347 lastReceivedPacketTime = tick;
1349 octetsReceived += frame.GetPayloadSize();
1350 packetsReceived++;
1352 // Call the statistics call-back on the first PDU with total count == 1
1353 if (packetsReceived == 1 && userData != NULL)
1354 userData->OnRxStatistics(*this);
1356 if (!SendReport())
1357 return e_AbortTransport;
1359 if (rxStatisticsCount < rxStatisticsInterval)
1360 return e_ProcessPacket;
1362 rxStatisticsCount = 0;
1364 averageReceiveTime = averageReceiveTimeAccum/rxStatisticsInterval;
1365 maximumReceiveTime = maximumReceiveTimeAccum;
1366 minimumReceiveTime = minimumReceiveTimeAccum;
1368 averageReceiveTimeAccum = 0;
1369 maximumReceiveTimeAccum = 0;
1370 minimumReceiveTimeAccum = 0xffffffff;
1372 PTRACE(4, "RTP\tReceive statistics: "
1373 " packets=" << packetsReceived <<
1374 " octets=" << octetsReceived <<
1375 " lost=" << packetsLost <<
1376 " tooLate=" << GetPacketsTooLate() <<
1377 " order=" << packetsOutOfOrder <<
1378 " avgTime=" << averageReceiveTime <<
1379 " maxTime=" << maximumReceiveTime <<
1380 " minTime=" << minimumReceiveTime <<
1381 " jitter=" << (jitterLevel >> 7) <<
1382 " maxJitter=" << (maximumJitterLevel >> 7)
1385 if (userData != NULL)
1386 userData->OnRxStatistics(*this);
1388 return e_ProcessPacket;
1391 BOOL RTP_Session::InsertReportPacket(RTP_ControlFrame & report)
1393 // No packets sent yet, so only set RR
1394 if (packetsSent == 0) {
1396 // Send RR as we are not transmitting
1397 report.StartNewPacket();
1398 report.SetPayloadType(RTP_ControlFrame::e_ReceiverReport);
1399 report.SetPayloadSize(4 + sizeof(RTP_ControlFrame::ReceiverReport)); // length is SSRC of packet sender plus RR
1400 report.SetCount(1);
1401 BYTE * payload = report.GetPayloadPtr();
1403 // add the SSRC to the start of the payload
1404 *(PUInt32b *)payload = syncSourceOut;
1406 // add the RR after the SSRC
1407 AddReceiverReport(*(RTP_ControlFrame::ReceiverReport *)(payload+4));
1409 else
1411 // send SR and RR
1412 report.StartNewPacket();
1413 report.SetPayloadType(RTP_ControlFrame::e_SenderReport);
1414 report.SetPayloadSize(4 + sizeof(RTP_ControlFrame::SenderReport)); // length is SSRC of packet sender plus SR
1415 report.SetCount(0);
1416 BYTE * payload = report.GetPayloadPtr();
1418 // add the SSRC to the start of the payload
1419 *(PUInt32b *)payload = syncSourceOut;
1421 // add the SR after the SSRC
1422 RTP_ControlFrame::SenderReport * sender = (RTP_ControlFrame::SenderReport *)(payload+4);
1423 PTime now;
1424 sender->ntp_sec = (DWORD)(now.GetTimeInSeconds()+SecondsFrom1900to1970); // Convert from 1970 to 1900
1425 sender->ntp_frac = now.GetMicrosecond()*4294; // Scale microseconds to "fraction" from 0 to 2^32
1426 sender->rtp_ts = lastSentTimestamp;
1427 sender->psent = packetsSent;
1428 sender->osent = octetsSent;
1430 PTRACE(3, "RTP\tSentSenderReport: "
1431 " ssrc=" << syncSourceOut
1432 << " ntp=" << sender->ntp_sec << '.' << sender->ntp_frac
1433 << " rtp=" << sender->rtp_ts
1434 << " psent=" << sender->psent
1435 << " osent=" << sender->osent);
1437 if (syncSourceIn != 0) {
1438 report.SetPayloadSize(4 + sizeof(RTP_ControlFrame::SenderReport) + sizeof(RTP_ControlFrame::ReceiverReport));
1439 report.SetCount(1);
1440 AddReceiverReport(*(RTP_ControlFrame::ReceiverReport *)(payload+4+sizeof(RTP_ControlFrame::SenderReport)));
1444 report.EndPacket();
1446 // Wait a fuzzy amount of time so things don't get into lock step
1447 int interval = (int)reportTimeInterval.GetMilliSeconds();
1448 int third = interval/3;
1449 interval += PRandom::Number()%(2*third);
1450 interval -= third;
1451 reportTimer = interval;
1453 return TRUE;
1456 BOOL RTP_Session::SendReport()
1458 PWaitAndSignal mutex(reportMutex);
1460 if (reportTimer.IsRunning())
1461 return TRUE;
1463 // Have not got anything yet, do nothing
1464 if (packetsSent == 0 && packetsReceived == 0) {
1465 reportTimer = reportTimeInterval;
1466 return TRUE;
1469 RTP_ControlFrame report;
1471 InsertReportPacket(report);
1473 // Add the SDES part to compound RTCP packet
1474 PTRACE(2, "RTP\tSending SDES: " << canonicalName);
1475 report.StartNewPacket();
1477 report.SetCount(0); // will be incremented automatically
1478 report.StartSourceDescription (syncSourceOut);
1479 report.AddSourceDescriptionItem(RTP_ControlFrame::e_CNAME, canonicalName);
1480 report.AddSourceDescriptionItem(RTP_ControlFrame::e_TOOL, toolName);
1481 report.EndPacket();
1483 BOOL stat = WriteControl(report);
1485 return stat;
1489 static RTP_Session::ReceiverReportArray
1490 BuildReceiverReportArray(const RTP_ControlFrame & frame, PINDEX offset)
1492 RTP_Session::ReceiverReportArray reports;
1494 const RTP_ControlFrame::ReceiverReport * rr = (const RTP_ControlFrame::ReceiverReport *)(frame.GetPayloadPtr()+offset);
1495 for (PINDEX repIdx = 0; repIdx < (PINDEX)frame.GetCount(); repIdx++) {
1496 RTP_Session::ReceiverReport * report = new RTP_Session::ReceiverReport;
1497 report->sourceIdentifier = rr->ssrc;
1498 report->fractionLost = rr->fraction;
1499 report->totalLost = rr->GetLostPackets();
1500 report->lastSequenceNumber = rr->last_seq;
1501 report->jitter = rr->jitter;
1502 report->lastTimestamp = (PInt64)(DWORD)rr->lsr;
1503 report->delay = ((PInt64)rr->dlsr << 16)/1000;
1504 reports.SetAt(repIdx, report);
1505 rr++;
1508 return reports;
1512 RTP_Session::SendReceiveStatus RTP_Session::OnReceiveControl(RTP_ControlFrame & frame)
1514 do {
1515 BYTE * payload = frame.GetPayloadPtr();
1516 unsigned size = frame.GetPayloadSize();
1517 if ((payload == NULL) || (size == 0) || ((payload + size) > (frame.GetPointer() + frame.GetSize()))){
1518 /* TODO: 1.shall we test for a maximum size ? Indeed but what's the value ? *
1519 2. what's the correct exit status ? */
1520 PTRACE(2, "RTP\tOnReceiveControl invalid frame");
1522 break;
1524 switch (frame.GetPayloadType()) {
1525 case RTP_ControlFrame::e_SenderReport :
1526 if (size >= sizeof(RTP_ControlFrame::SenderReport)) {
1527 SenderReport sender;
1528 sender.sourceIdentifier = *(const PUInt32b *)payload;
1529 const RTP_ControlFrame::SenderReport & sr = *(const RTP_ControlFrame::SenderReport *)(payload+4);
1530 sender.realTimestamp = PTime(sr.ntp_sec-SecondsFrom1900to1970, sr.ntp_frac/4294);
1531 sender.rtpTimestamp = sr.rtp_ts;
1532 sender.packetsSent = sr.psent;
1533 sender.octetsSent = sr.osent;
1534 OnRxSenderReport(sender,
1535 BuildReceiverReportArray(frame, sizeof(RTP_ControlFrame::SenderReport)));
1537 else {
1538 PTRACE(2, "RTP\tSenderReport packet truncated");
1540 break;
1542 case RTP_ControlFrame::e_ReceiverReport :
1543 if (size >= 4)
1544 OnRxReceiverReport(*(const PUInt32b *)payload,
1545 BuildReceiverReportArray(frame, sizeof(PUInt32b)));
1546 else {
1547 PTRACE(2, "RTP\tReceiverReport packet truncated");
1549 break;
1551 case RTP_ControlFrame::e_SourceDescription :
1552 if (size >= frame.GetCount()*sizeof(RTP_ControlFrame::SourceDescription)) {
1553 SourceDescriptionArray descriptions;
1554 const RTP_ControlFrame::SourceDescription * sdes = (const RTP_ControlFrame::SourceDescription *)payload;
1555 PINDEX srcIdx;
1556 for (srcIdx = 0; srcIdx < (PINDEX)frame.GetCount(); srcIdx++) {
1557 descriptions.SetAt(srcIdx, new SourceDescription(sdes->src));
1558 const RTP_ControlFrame::SourceDescription::Item * item = sdes->item;
1559 unsigned uiSizeCurrent = 0; /* current size of the items already parsed */
1560 while ((item != NULL) && (item->type != RTP_ControlFrame::e_END)) {
1561 descriptions[srcIdx].items.SetAt(item->type, PString(item->data, item->length));
1562 uiSizeCurrent += item->GetLengthTotal();
1563 // PTRACE(2,"RTP\tSourceDescription item " << item << ", current size = " << uiSizeCurrent);
1565 /* avoid reading where GetNextItem() shall not */
1566 if (uiSizeCurrent >= size){
1567 PTRACE(2,"RTP\tSourceDescription end of items");
1568 item = NULL;
1569 break;
1570 } else {
1571 item = item->GetNextItem();
1574 /* RTP_ControlFrame::e_END doesn't have a length field, so do NOT call item->GetNextItem()
1575 otherwise it reads over the buffer */
1576 if((item == NULL) ||
1577 (item->type == RTP_ControlFrame::e_END) ||
1578 ((sdes = (const RTP_ControlFrame::SourceDescription *)item->GetNextItem()) == NULL)){
1579 break;
1582 OnRxSourceDescription(descriptions);
1584 else {
1585 PTRACE(2, "RTP\tSourceDescription packet truncated");
1587 break;
1589 case RTP_ControlFrame::e_Goodbye :
1591 unsigned count = frame.GetCount()*4;
1592 if ((size >= 4) && (count > 0)) {
1593 PString str;
1595 if (size > count){
1596 if((payload[count] + sizeof(DWORD) /*SSRC*/ + sizeof(unsigned char) /* length */) <= size){
1597 str = PString((const char *)(payload+count+1), payload[count]);
1598 } else {
1599 PTRACE(2, "RTP\tGoodbye packet invalid");
1602 PDWORDArray sources(frame.GetCount());
1603 for (PINDEX i = 0; i < (PINDEX)frame.GetCount(); i++){
1604 sources[i] = ((const PUInt32b *)payload)[i];
1606 OnRxGoodbye(sources, str);
1608 else {
1609 PTRACE(2, "RTP\tGoodbye packet truncated");
1611 if (closeOnBye) {
1612 PTRACE(2, "RTP\tGoodbye packet closing transport");
1613 return e_AbortTransport;
1615 break;
1618 case RTP_ControlFrame::e_ApplDefined :
1619 if (size >= 4) {
1620 PString str((const char *)(payload+4), 4);
1621 OnRxApplDefined(str, frame.GetCount(), *(const PUInt32b *)payload,
1622 payload+8, frame.GetPayloadSize()-8);
1624 else {
1625 PTRACE(2, "RTP\tApplDefined packet truncated");
1627 break;
1629 default :
1630 PTRACE(2, "RTP\tUnknown control payload type: " << frame.GetPayloadType());
1632 } while (frame.ReadNextPacket());
1634 return e_ProcessPacket;
1638 void RTP_Session::OnRxSenderReport(const SenderReport & PTRACE_PARAM(sender),
1639 const ReceiverReportArray & PTRACE_PARAM(reports))
1641 #if PTRACING
1642 PTRACE(3, "RTP\tOnRxSenderReport: " << sender);
1643 for (PINDEX i = 0; i < reports.GetSize(); i++)
1644 PTRACE(3, "RTP\tOnRxSenderReport RR: " << reports[i]);
1645 #endif
1649 void RTP_Session::OnRxReceiverReport(DWORD PTRACE_PARAM(src),
1650 const ReceiverReportArray & PTRACE_PARAM(reports))
1652 #if PTRACING
1653 PTRACE(3, "RTP\tOnReceiverReport: ssrc=" << src);
1654 for (PINDEX i = 0; i < reports.GetSize(); i++)
1655 PTRACE(3, "RTP\tOnReceiverReport RR: " << reports[i]);
1656 #endif
1660 void RTP_Session::OnRxSourceDescription(const SourceDescriptionArray & PTRACE_PARAM(description))
1662 #if PTRACING
1663 for (PINDEX i = 0; i < description.GetSize(); i++)
1664 PTRACE(3, "RTP\tOnSourceDescription: " << description[i]);
1665 #endif
1669 void RTP_Session::OnRxGoodbye(const PDWORDArray & PTRACE_PARAM(src), const PString & PTRACE_PARAM(reason))
1671 PTRACE(3, "RTP\tOnGoodbye: \"" << reason << "\" srcs=" << src);
1675 void RTP_Session::OnRxApplDefined(const PString & PTRACE_PARAM(type),
1676 unsigned PTRACE_PARAM(subtype), DWORD PTRACE_PARAM(src),
1677 const BYTE * /*data*/, PINDEX PTRACE_PARAM(size))
1679 PTRACE(3, "RTP\tOnApplDefined: \"" << type << "\"-" << subtype
1680 << " " << src << " [" << size << ']');
1684 void RTP_Session::ReceiverReport::PrintOn(ostream & strm) const
1686 strm << "ssrc=" << sourceIdentifier
1687 << " fraction=" << fractionLost
1688 << " lost=" << totalLost
1689 << " last_seq=" << lastSequenceNumber
1690 << " jitter=" << jitter
1691 << " lsr=" << lastTimestamp
1692 << " dlsr=" << delay;
1696 void RTP_Session::SenderReport::PrintOn(ostream & strm) const
1698 strm << "ssrc=" << sourceIdentifier
1699 << " ntp=" << realTimestamp.AsString("yyyy/M/d-h:m:s.uuuu")
1700 << " rtp=" << rtpTimestamp
1701 << " psent=" << packetsSent
1702 << " osent=" << octetsSent;
1706 void RTP_Session::SourceDescription::PrintOn(ostream & strm) const
1708 static const char * const DescriptionNames[RTP_ControlFrame::NumDescriptionTypes] = {
1709 "END", "CNAME", "NAME", "EMAIL", "PHONE", "LOC", "TOOL", "NOTE", "PRIV"
1712 strm << "ssrc=" << sourceIdentifier;
1713 for (PINDEX i = 0; i < items.GetSize(); i++) {
1714 strm << "\n item[" << i << "]: type=";
1715 unsigned typeNum = items.GetKeyAt(i);
1716 if (typeNum < PARRAYSIZE(DescriptionNames))
1717 strm << DescriptionNames[typeNum];
1718 else
1719 strm << typeNum;
1720 strm << " data=\""
1721 << items.GetDataAt(i)
1722 << '"';
1727 DWORD RTP_Session::GetPacketsTooLate() const
1729 return jitter != NULL ? jitter->GetPacketsTooLate() : 0;
1733 /////////////////////////////////////////////////////////////////////////////
1735 RTP_SessionManager::RTP_SessionManager()
1737 enumerationIndex = P_MAX_INDEX;
1741 RTP_SessionManager::RTP_SessionManager(const RTP_SessionManager & sm)
1742 : sessions(sm.sessions)
1744 enumerationIndex = P_MAX_INDEX;
1748 RTP_SessionManager & RTP_SessionManager::operator=(const RTP_SessionManager & sm)
1750 PWaitAndSignal m1(mutex);
1751 PWaitAndSignal m2(sm.mutex);
1752 sessions = sm.sessions;
1753 return *this;
1757 RTP_Session * RTP_SessionManager::UseSession(unsigned sessionID)
1759 PWaitAndSignal m(mutex);
1761 RTP_Session * session = sessions.GetAt(sessionID);
1762 if (session == NULL)
1763 return NULL;
1765 PTRACE(3, "RTP\tFound existing session " << sessionID);
1766 session->IncrementReference();
1768 return session;
1772 void RTP_SessionManager::AddSession(RTP_Session * session)
1774 PWaitAndSignal m(mutex);
1776 if (session != NULL) {
1777 PTRACE(2, "RTP\tAdding session " << *session);
1778 sessions.SetAt(session->GetSessionID(), session);
1783 void RTP_SessionManager::ReleaseSession(unsigned sessionID,
1784 BOOL clearAll)
1786 PTRACE(2, "RTP\tReleasing session " << sessionID);
1788 mutex.Wait();
1790 while (sessions.Contains(sessionID)) {
1791 if (sessions[sessionID].DecrementReference()) {
1792 PTRACE(3, "RTP\tDeleting session " << sessionID);
1793 sessions[sessionID].SetJitterBufferSize(0, 0);
1794 sessions.SetAt(sessionID, NULL);
1796 if (!clearAll)
1797 break;
1800 mutex.Signal();
1804 RTP_Session * RTP_SessionManager::GetSession(unsigned sessionID) const
1806 PWaitAndSignal wait(mutex);
1807 if (!sessions.Contains(sessionID))
1808 return NULL;
1810 PTRACE(3, "RTP\tFound existing session " << sessionID);
1811 return &sessions[sessionID];
1815 RTP_Session * RTP_SessionManager::First()
1817 mutex.Wait();
1819 enumerationIndex = 0;
1820 return Next();
1824 RTP_Session * RTP_SessionManager::Next()
1826 if (enumerationIndex < sessions.GetSize())
1827 return &sessions.GetDataAt(enumerationIndex++);
1829 Exit();
1830 return NULL;
1834 void RTP_SessionManager::Exit()
1836 enumerationIndex = P_MAX_INDEX;
1837 mutex.Signal();
1841 /////////////////////////////////////////////////////////////////////////////
1843 static void SetMinBufferSize(PUDPSocket & sock, int buftype)
1845 int sz = 0;
1846 if (sock.GetOption(buftype, sz)) {
1847 if (sz >= UDP_BUFFER_SIZE)
1848 return;
1851 if (!sock.SetOption(buftype, UDP_BUFFER_SIZE)) {
1852 PTRACE(1, "RTP_UDP\tSetOption(" << buftype << ") failed: " << sock.GetErrorText());
1857 RTP_UDP::RTP_UDP(PHandleAggregator * _aggregator, unsigned id, BOOL _remoteIsNAT)
1858 : RTP_Session(_aggregator, id),
1859 remoteAddress(0),
1860 remoteTransmitAddress(0),
1861 remoteIsNAT(_remoteIsNAT)
1863 PTRACE(4, "RTP_UDP\tRTP session created with NAT flag set to " << remoteIsNAT);
1864 remoteDataPort = 0;
1865 remoteControlPort = 0;
1866 shutdownRead = FALSE;
1867 shutdownWrite = FALSE;
1868 dataSocket = NULL;
1869 controlSocket = NULL;
1870 appliedQOS = FALSE;
1874 RTP_UDP::~RTP_UDP()
1876 Close(TRUE);
1877 Close(FALSE);
1879 // We need to do this to make sure that the sockets are not
1880 // deleted before select decides there is no more data coming
1881 // over them and exits the reading thread.
1882 if (jitter)
1883 PAssert(jitter->WaitForTermination(10000), "Jitter buffer thread did not terminate");
1885 delete dataSocket;
1886 delete controlSocket;
1890 void RTP_UDP::ApplyQOS(const PIPSocket::Address & addr)
1892 if (controlSocket != NULL)
1893 controlSocket->SetSendAddress(addr,GetRemoteControlPort());
1894 if (dataSocket != NULL)
1895 dataSocket->SetSendAddress(addr,GetRemoteDataPort());
1896 appliedQOS = TRUE;
1900 BOOL RTP_UDP::ModifyQOS(RTP_QOS * rtpqos)
1902 BOOL retval = FALSE;
1904 if (rtpqos == NULL)
1905 return retval;
1907 if (controlSocket != NULL)
1908 retval = controlSocket->ModifyQoSSpec(&(rtpqos->ctrlQoS));
1910 if (dataSocket != NULL)
1911 retval &= dataSocket->ModifyQoSSpec(&(rtpqos->dataQoS));
1913 appliedQOS = FALSE;
1914 return retval;
1917 BOOL RTP_UDP::Open(PIPSocket::Address _localAddress,
1918 WORD portBase, WORD portMax,
1919 BYTE tos,
1920 PSTUNClient * stun,
1921 RTP_QOS * rtpQos)
1923 first = TRUE;
1924 // save local address
1925 localAddress = _localAddress;
1927 localDataPort = (WORD)(portBase&0xfffe);
1928 localControlPort = (WORD)(localDataPort + 1);
1930 delete dataSocket;
1931 delete controlSocket;
1932 dataSocket = NULL;
1933 controlSocket = NULL;
1935 byeSent = FALSE;
1937 PQoS * dataQos = NULL;
1938 PQoS * ctrlQos = NULL;
1939 if (rtpQos != NULL) {
1940 dataQos = &(rtpQos->dataQoS);
1941 ctrlQos = &(rtpQos->ctrlQoS);
1944 // allow for special case of portBase == 0 or portMax == 0, which indicates a shared RTP session
1945 if ((portBase != 0) || (portMax != 0)) {
1946 if (stun != NULL) {
1947 if (stun->CreateSocketPair(dataSocket, controlSocket)) {
1948 dataSocket->GetLocalAddress(localAddress, localDataPort);
1949 controlSocket->GetLocalAddress(localAddress, localControlPort);
1951 else {
1952 PTRACE(1, "RTP\tSTUN could not create RTP/RTCP socket pair; trying to create RTP socket anyway.");
1953 if (stun->CreateSocket(dataSocket)) {
1954 dataSocket->GetLocalAddress(localAddress, localDataPort);
1956 else {
1957 PTRACE(1, "RTP\tSTUN could not create RTP socket either.");
1958 return FALSE;
1960 if (stun->CreateSocket(controlSocket)) {
1961 controlSocket->GetLocalAddress(localAddress, localControlPort);
1966 if (dataSocket == NULL || controlSocket == NULL) {
1967 dataSocket = new PUDPSocket(dataQos);
1968 controlSocket = new PUDPSocket(ctrlQos);
1969 while (!dataSocket->Listen(localAddress, 1, localDataPort) ||
1970 !controlSocket->Listen(localAddress, 1, localControlPort)) {
1971 dataSocket->Close();
1972 controlSocket->Close();
1973 if ((localDataPort > portMax) || (localDataPort > 0xfffd))
1974 return FALSE; // If it ever gets to here the OS has some SERIOUS problems!
1975 localDataPort += 2;
1976 localControlPort += 2;
1980 # ifndef __BEOS__
1981 // Set the IP Type Of Service field for prioritisation of media UDP packets
1982 // through some Cisco routers and Linux boxes
1983 if (!dataSocket->SetOption(IP_TOS, tos, IPPROTO_IP)) {
1984 PTRACE(1, "RTP_UDP\tCould not set TOS field in IP header: " << dataSocket->GetErrorText());
1987 // Increase internal buffer size on media UDP sockets
1988 SetMinBufferSize(*dataSocket, SO_RCVBUF);
1989 SetMinBufferSize(*dataSocket, SO_SNDBUF);
1990 SetMinBufferSize(*controlSocket, SO_RCVBUF);
1991 SetMinBufferSize(*controlSocket, SO_SNDBUF);
1992 # endif
1995 shutdownRead = FALSE;
1996 shutdownWrite = FALSE;
1998 if (canonicalName.Find('@') == P_MAX_INDEX)
1999 canonicalName += '@' + GetLocalHostName();
2001 PTRACE(2, "RTP_UDP\tSession " << sessionID << " created: "
2002 << localAddress << ':' << localDataPort << '-' << localControlPort
2003 << " ssrc=" << syncSourceOut);
2006 return TRUE;
2010 void RTP_UDP::Reopen(BOOL reading)
2012 if (reading)
2013 shutdownRead = FALSE;
2014 else
2015 shutdownWrite = FALSE;
2019 void RTP_UDP::Close(BOOL reading)
2021 if (!shutdownRead && !shutdownWrite)
2022 SendBYE();
2024 if (reading) {
2025 if (!shutdownRead) {
2026 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Shutting down read.");
2027 syncSourceIn = 0;
2028 shutdownRead = TRUE;
2029 if (dataSocket != NULL && controlSocket != NULL) {
2030 PIPSocket::Address addr;
2031 controlSocket->GetLocalAddress(addr);
2032 if (addr.IsAny())
2033 PIPSocket::GetHostAddress(addr);
2034 dataSocket->WriteTo("", 1, addr, controlSocket->GetPort());
2038 else {
2039 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Shutting down write.");
2040 shutdownWrite = TRUE;
2045 PString RTP_UDP::GetLocalHostName()
2047 return PIPSocket::GetHostName();
2051 BOOL RTP_UDP::SetRemoteSocketInfo(PIPSocket::Address address, WORD port, BOOL isDataPort)
2053 if (remoteIsNAT) {
2054 PTRACE(3, "RTP_UDP\tIgnoring remote socket info as remote is behind NAT");
2055 return TRUE;
2058 PTRACE(3, "RTP_UDP\tSetRemoteSocketInfo: session=" << sessionID << ' '
2059 << (isDataPort ? "data" : "control") << " channel, "
2060 "new=" << address << ':' << port << ", "
2061 "local=" << localAddress << ':' << localDataPort << '-' << localControlPort << ", "
2062 "remote=" << remoteAddress << ':' << remoteDataPort << '-' << remoteControlPort);
2064 if (localAddress == address && remoteAddress == address && (isDataPort ? localDataPort : localControlPort) == port)
2065 return TRUE;
2067 remoteAddress = address;
2069 allowSyncSourceInChange = TRUE;
2070 allowRemoteTransmitAddressChange = TRUE;
2071 allowSequenceChange = TRUE;
2073 if (isDataPort) {
2074 remoteDataPort = port;
2075 if (remoteControlPort == 0 || allowRemoteTransmitAddressChange)
2076 remoteControlPort = (WORD)(port + 1);
2078 else {
2079 remoteControlPort = port;
2080 if (remoteDataPort == 0 || allowRemoteTransmitAddressChange)
2081 remoteDataPort = (WORD)(port - 1);
2084 if (!appliedQOS)
2085 ApplyQOS(remoteAddress);
2087 return remoteAddress != 0 && port != 0;
2091 BOOL RTP_UDP::ReadData(RTP_DataFrame & frame, BOOL loop)
2093 do {
2094 int selectStatus = WaitForPDU(*dataSocket, *controlSocket, reportTimer);
2096 if (shutdownRead) {
2097 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Read shutdown.");
2098 shutdownRead = FALSE;
2099 return FALSE;
2102 switch (selectStatus) {
2103 case -2 :
2104 if (ReadControlPDU() == e_AbortTransport)
2105 return FALSE;
2106 break;
2108 case -3 :
2109 if (ReadControlPDU() == e_AbortTransport)
2110 return FALSE;
2111 // Then do -1 case
2113 case -1 :
2114 switch (ReadDataPDU(frame)) {
2115 case e_ProcessPacket :
2116 if (!shutdownRead)
2117 return TRUE;
2118 case e_IgnorePacket :
2119 break;
2120 case e_AbortTransport :
2121 return FALSE;
2123 break;
2125 case 0 :
2126 if (!SendReport())
2127 return FALSE;
2128 break;
2130 case PSocket::Interrupted:
2131 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Interrupted.");
2132 return FALSE;
2134 default :
2135 PTRACE(1, "RTP_UDP\tSession " << sessionID << ", Select error: "
2136 << PChannel::GetErrorText((PChannel::Errors)selectStatus));
2137 return FALSE;
2139 } while (loop);
2141 frame.SetSize(0);
2142 return TRUE;
2145 int RTP_UDP::WaitForPDU(PUDPSocket & dataSocket, PUDPSocket & controlSocket, const PTimeInterval & timeout)
2147 if (first) {
2148 BYTE buffer[1500];
2149 PINDEX count = 0;
2150 do {
2151 switch (PSocket::Select(dataSocket, controlSocket, PTimeInterval(0))) {
2152 case -2:
2153 controlSocket.Read(buffer, sizeof(buffer));
2154 ++count;
2155 break;
2157 case -3:
2158 controlSocket.Read(buffer, sizeof(buffer));
2159 ++count;
2160 case -1:
2161 dataSocket.Read(buffer, sizeof(buffer));
2162 ++count;
2163 break;
2164 case 0:
2165 first = FALSE;
2166 break;
2168 } while (first);
2169 PTRACE_IF(2, count > 0, "RTP_UDP\tSwallowed " << count << " RTP packets on startup");
2172 return PSocket::Select(dataSocket, controlSocket, timeout);
2175 RTP_Session::SendReceiveStatus RTP_UDP::ReadDataOrControlPDU(PUDPSocket & socket,
2176 PBYTEArray & frame,
2177 BOOL fromDataChannel)
2179 #if PTRACING
2180 const char * channelName = fromDataChannel ? "Data" : "Control";
2181 #endif
2182 PIPSocket::Address addr;
2183 WORD port;
2185 if (socket.ReadFrom(frame.GetPointer(2048), 2048, addr, port)) {
2186 if (ignoreOtherSources) {
2187 // If remote address never set from higher levels, then try and figure
2188 // it out from the first packet received.
2189 if (!remoteAddress.IsValid()) {
2190 remoteAddress = addr;
2191 PTRACE(4, "RTP\tSet remote address from first " << channelName
2192 << " PDU from " << addr << ':' << port);
2194 if (fromDataChannel) {
2195 if (remoteDataPort == 0)
2196 remoteDataPort = port;
2198 else {
2199 if (remoteControlPort == 0)
2200 remoteControlPort = port;
2203 if (!remoteTransmitAddress.IsValid())
2204 remoteTransmitAddress = addr;
2205 else if (allowRemoteTransmitAddressChange && remoteAddress == addr) {
2206 remoteTransmitAddress = addr;
2207 allowRemoteTransmitAddressChange = FALSE;
2209 else if (remoteTransmitAddress != addr && !allowRemoteTransmitAddressChange && !ignoreOtherSources) {
2210 PTRACE(1, "RTP_UDP\tSession " << sessionID << ", "
2211 << channelName << " PDU from incorrect host, "
2212 " is " << addr << " should be " << remoteTransmitAddress);
2213 return RTP_Session::e_IgnorePacket;
2216 if (remoteAddress.IsValid() && !appliedQOS)
2217 ApplyQOS(remoteAddress);
2219 return RTP_Session::e_ProcessPacket;
2222 switch (socket.GetErrorNumber()) {
2223 case ECONNRESET :
2224 case ECONNREFUSED :
2225 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", "
2226 << channelName << " port on remote not ready.");
2227 return RTP_Session::e_IgnorePacket;
2229 case EAGAIN :
2230 // Shouldn't happen, but it does.
2231 return RTP_Session::e_IgnorePacket;
2233 default:
2234 PTRACE(1, "RTP_UDP\t" << channelName << " read error ("
2235 << socket.GetErrorNumber(PChannel::LastReadError) << "): "
2236 << socket.GetErrorText(PChannel::LastReadError));
2237 return RTP_Session::e_AbortTransport;
2242 RTP_Session::SendReceiveStatus RTP_UDP::ReadDataPDU(RTP_DataFrame & frame)
2244 SendReceiveStatus status = ReadDataOrControlPDU(*dataSocket, frame, TRUE);
2245 if (status != e_ProcessPacket)
2246 return status;
2248 // Check received PDU is big enough
2249 PINDEX pduSize = dataSocket->GetLastReadCount();
2250 if (pduSize < RTP_DataFrame::MinHeaderSize || pduSize < frame.GetHeaderSize()) {
2251 PTRACE(2, "RTP_UDP\tSession " << sessionID
2252 << ", Received data packet too small: " << pduSize << " bytes");
2253 return e_IgnorePacket;
2256 frame.SetPayloadSize(pduSize - frame.GetHeaderSize());
2257 return OnReceiveData(frame);
2261 RTP_Session::SendReceiveStatus RTP_UDP::ReadControlPDU()
2263 RTP_ControlFrame frame(2048);
2265 SendReceiveStatus status = ReadDataOrControlPDU(*controlSocket, frame, FALSE);
2266 if (status != e_ProcessPacket)
2267 return status;
2269 PINDEX pduSize = controlSocket->GetLastReadCount();
2270 if (pduSize < 4 || pduSize < 4+frame.GetPayloadSize()) {
2271 PTRACE(2, "RTP_UDP\tSession " << sessionID
2272 << ", Received control packet too small: " << pduSize << " bytes");
2273 return e_IgnorePacket;
2276 frame.SetSize(pduSize);
2277 return OnReceiveControl(frame);
2281 BOOL RTP_UDP::WriteData(RTP_DataFrame & frame)
2283 if (shutdownWrite) {
2284 PTRACE(3, "RTP_UDP\tSession " << sessionID << ", Write shutdown.");
2285 shutdownWrite = FALSE;
2286 return FALSE;
2289 // Trying to send a PDU before we are set up!
2290 if (!remoteAddress.IsValid() || remoteDataPort == 0)
2291 return TRUE;
2293 switch (OnSendData(frame)) {
2294 case e_ProcessPacket :
2295 break;
2296 case e_IgnorePacket :
2297 return TRUE;
2298 case e_AbortTransport :
2299 return FALSE;
2302 while (!dataSocket->WriteTo(frame.GetPointer(),
2303 frame.GetHeaderSize()+frame.GetPayloadSize(),
2304 remoteAddress, remoteDataPort)) {
2305 switch (dataSocket->GetErrorNumber()) {
2306 case ECONNRESET :
2307 case ECONNREFUSED :
2308 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", data port on remote not ready.");
2309 break;
2311 default:
2312 PTRACE(1, "RTP_UDP\tSession " << sessionID
2313 << ", Write error on data port ("
2314 << dataSocket->GetErrorNumber(PChannel::LastWriteError) << "): "
2315 << dataSocket->GetErrorText(PChannel::LastWriteError));
2316 return FALSE;
2320 return TRUE;
2324 BOOL RTP_UDP::WriteControl(RTP_ControlFrame & frame)
2326 // Trying to send a PDU before we are set up!
2327 if (!remoteAddress.IsValid() || remoteControlPort == 0)
2328 return TRUE;
2330 PINDEX len = frame.GetCompoundSize();
2331 switch (OnSendControl(frame, len)) {
2332 case e_ProcessPacket :
2333 break;
2334 case e_IgnorePacket :
2335 return TRUE;
2336 case e_AbortTransport :
2337 return FALSE;
2340 while (!controlSocket->WriteTo(frame.GetPointer(), len,
2341 remoteAddress, remoteControlPort)) {
2342 switch (controlSocket->GetErrorNumber()) {
2343 case ECONNRESET :
2344 case ECONNREFUSED :
2345 PTRACE(2, "RTP_UDP\tSession " << sessionID << ", control port on remote not ready.");
2346 break;
2348 default:
2349 PTRACE(1, "RTP_UDP\tSession " << sessionID
2350 << ", Write error on control port ("
2351 << controlSocket->GetErrorNumber(PChannel::LastWriteError) << "): "
2352 << controlSocket->GetErrorText(PChannel::LastWriteError));
2353 return FALSE;
2357 return TRUE;
2360 /////////////////////////////////////////////////////////////////////////////
2362 SecureRTP_UDP::SecureRTP_UDP(PHandleAggregator * _aggregator, unsigned id, BOOL remoteIsNAT)
2363 : RTP_UDP(_aggregator, id, remoteIsNAT)
2366 securityParms = NULL;
2369 SecureRTP_UDP::~SecureRTP_UDP()
2371 delete securityParms;
2374 void SecureRTP_UDP::SetSecurityMode(OpalSecurityMode * newParms)
2376 if (securityParms != NULL)
2377 delete securityParms;
2378 securityParms = newParms;
2381 OpalSecurityMode * SecureRTP_UDP::GetSecurityParms() const
2383 return securityParms;
2386 /////////////////////////////////////////////////////////////////////////////