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
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): ______________________________________.
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
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
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
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
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
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
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
527 #pragma implementation "rtp.h"
532 #include <rtp/jitter.h>
533 #include <ptclib/random.h>
534 #include <ptclib/pstun.h>
535 #include <opal/connection.h>
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
558 }; // namespace PWLibStupidLinkerHacks
560 /////////////////////////////////////////////////////////////////////////////
562 RTP_DataFrame::RTP_DataFrame(PINDEX sz
)
563 : PBYTEArray(MIN_HEADER_SIZE
+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
)
585 void RTP_DataFrame::SetMarker(BOOL m
)
594 void RTP_DataFrame::SetPayloadType(PayloadTypes t
)
596 PAssert(t
<= 0x7f, PInvalidParameter
);
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();
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();
631 sz
+= 4 + GetExtensionSize();
637 int RTP_DataFrame::GetExtensionType() const
640 return *(PUInt16b
*)&theArray
[MIN_HEADER_SIZE
+ 4*GetContribSrcCount()];
646 void RTP_DataFrame::SetExtensionType(int type
)
653 *(PUInt16b
*)&theArray
[MIN_HEADER_SIZE
+ 4*GetContribSrcCount()] = (WORD
)type
;
658 PINDEX
RTP_DataFrame::GetExtensionSize() const
661 return *(PUInt16b
*)&theArray
[MIN_HEADER_SIZE
+ 4*GetContribSrcCount() + 2] * 4;
667 BOOL
RTP_DataFrame::SetExtensionSize(PINDEX sz
)
669 if (!SetMinSize(MIN_HEADER_SIZE
+ 4*GetContribSrcCount() + 4+4*sz
+ payloadSize
))
673 *(PUInt16b
*)&theArray
[MIN_HEADER_SIZE
+ 4*GetContribSrcCount() + 2] = (WORD
)sz
;
678 BYTE
* RTP_DataFrame::GetExtensionPtr() const
681 return (BYTE
*)&theArray
[MIN_HEADER_SIZE
+ 4*GetContribSrcCount() + 4];
687 BOOL
RTP_DataFrame::SetPayloadSize(PINDEX sz
)
690 return SetMinSize(GetHeaderSize()+payloadSize
);
695 static const char * const PayloadTypesNames
[RTP_DataFrame::LastKnownPayloadType
] = {
716 NULL
, NULL
, NULL
, NULL
, NULL
,
719 NULL
, NULL
, NULL
, NULL
,
726 ostream
& operator<<(ostream
& o
, RTP_DataFrame::PayloadTypes t
)
728 if ((PINDEX
)t
< PARRAYSIZE(PayloadTypesNames
) && PayloadTypesNames
[t
] != NULL
)
729 o
<< PayloadTypesNames
[t
];
731 o
<< "[pt=" << (int)t
<< ']';
738 /////////////////////////////////////////////////////////////////////////////
740 RTP_ControlFrame::RTP_ControlFrame(PINDEX sz
)
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
)
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()))
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())
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))
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
819 SetPayloadSize(payloadSize
);
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;
832 compoundOffset
+= 4 + payloadSize
;
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
;
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
);
862 payload
[0] = (BYTE
)type
;
863 payload
[1] = (BYTE
)dataLength
;
864 memcpy(payload
+2, (const char *)data
, dataLength
);
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
;
907 autoDeleteUserData
= autoDelete
;
910 ignoreOtherSources
= TRUE
;
911 ignoreOutOfOrderPackets
= TRUE
;
912 ignorePayloadTypeChanges
= TRUE
;
913 syncSourceOut
= PRandom::Number();
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;
931 packetsOutOfOrder
= 0;
935 averageReceiveTime
= 0;
936 maximumReceiveTime
= 0;
937 minimumReceiveTime
= 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;
952 lastReceivedPayloadType
= RTP_DataFrame::MaxPayloadType
;
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)
979 if (autoDeleteUserData
)
983 void RTP_Session::SendBYE()
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
);
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
1003 // add the SSRC to the start of the payload
1004 BYTE
* payload
= report
.GetPayloadPtr();
1005 *(PUInt32b
*)payload
= syncSourceOut
;
1009 const char * reasonStr
= "session ending";
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();
1020 *(PUInt32b
*)payload
= syncSourceOut
;
1023 payload
[4] = (BYTE
)strlen(reasonStr
);
1024 memcpy((char *)(payload
+5), reasonStr
, payload
[4]);
1027 WriteControl(report
);
1030 PString
RTP_Session::GetCanonicalName() const
1032 PWaitAndSignal
mutex(reportMutex
);
1033 PString s
= canonicalName
;
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
;
1055 void RTP_Session::SetToolName(const PString
& name
)
1057 PWaitAndSignal
mutex(reportMutex
);
1062 void RTP_Session::SetUserData(RTP_UserData
* data
, BOOL autoDelete
)
1064 if (autoDeleteUserData
)
1067 autoDeleteUserData
= autoDelete
;
1071 void RTP_Session::SetJitterBufferSize(unsigned minJitterDelay
,
1072 unsigned maxJitterDelay
,
1076 if (minJitterDelay
== 0 && maxJitterDelay
== 0) {
1080 else if (jitter
!= NULL
)
1081 jitter
->SetDelay(minJitterDelay
, maxJitterDelay
);
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
)
1104 return jitter
->ReadData(timestamp
, frame
);
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
));
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.
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();
1197 // Call the statistics call-back on the first PDU with total count == 1
1198 if (packetsSent
== 1 && userData
!= NULL
)
1199 userData
->OnTxStatistics(*this);
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*/)
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());
1278 if (!ignoreOtherSources
&& frame
.GetSyncSource() != syncSourceIn
) {
1279 if (allowSyncSourceInChange
) {
1280 syncSourceIn
= frame
.GetSyncSource();
1281 allowSyncSourceInChange
= FALSE
;
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.
1307 long variance
= diff
- lastTransitTime
;
1308 lastTransitTime
= diff
;
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
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();
1352 // Call the statistics call-back on the first PDU with total count == 1
1353 if (packetsReceived
== 1 && userData
!= NULL
)
1354 userData
->OnRxStatistics(*this);
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
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));
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
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);
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
));
1440 AddReceiverReport(*(RTP_ControlFrame::ReceiverReport
*)(payload
+4+sizeof(RTP_ControlFrame::SenderReport
)));
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
);
1451 reportTimer
= interval
;
1456 BOOL
RTP_Session::SendReport()
1458 PWaitAndSignal
mutex(reportMutex
);
1460 if (reportTimer
.IsRunning())
1463 // Have not got anything yet, do nothing
1464 if (packetsSent
== 0 && packetsReceived
== 0) {
1465 reportTimer
= reportTimeInterval
;
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
);
1483 BOOL stat
= WriteControl(report
);
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
);
1512 RTP_Session::SendReceiveStatus
RTP_Session::OnReceiveControl(RTP_ControlFrame
& frame
)
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");
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
)));
1538 PTRACE(2, "RTP\tSenderReport packet truncated");
1542 case RTP_ControlFrame::e_ReceiverReport
:
1544 OnRxReceiverReport(*(const PUInt32b
*)payload
,
1545 BuildReceiverReportArray(frame
, sizeof(PUInt32b
)));
1547 PTRACE(2, "RTP\tReceiverReport packet truncated");
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
;
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");
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
)){
1582 OnRxSourceDescription(descriptions
);
1585 PTRACE(2, "RTP\tSourceDescription packet truncated");
1589 case RTP_ControlFrame::e_Goodbye
:
1591 unsigned count
= frame
.GetCount()*4;
1592 if ((size
>= 4) && (count
> 0)) {
1596 if((payload
[count
] + sizeof(DWORD
) /*SSRC*/ + sizeof(unsigned char) /* length */) <= size
){
1597 str
= PString((const char *)(payload
+count
+1), payload
[count
]);
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
);
1609 PTRACE(2, "RTP\tGoodbye packet truncated");
1612 PTRACE(2, "RTP\tGoodbye packet closing transport");
1613 return e_AbortTransport
;
1618 case RTP_ControlFrame::e_ApplDefined
:
1620 PString
str((const char *)(payload
+4), 4);
1621 OnRxApplDefined(str
, frame
.GetCount(), *(const PUInt32b
*)payload
,
1622 payload
+8, frame
.GetPayloadSize()-8);
1625 PTRACE(2, "RTP\tApplDefined packet truncated");
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
))
1642 PTRACE(3, "RTP\tOnRxSenderReport: " << sender
);
1643 for (PINDEX i
= 0; i
< reports
.GetSize(); i
++)
1644 PTRACE(3, "RTP\tOnRxSenderReport RR: " << reports
[i
]);
1649 void RTP_Session::OnRxReceiverReport(DWORD
PTRACE_PARAM(src
),
1650 const ReceiverReportArray
& PTRACE_PARAM(reports
))
1653 PTRACE(3, "RTP\tOnReceiverReport: ssrc=" << src
);
1654 for (PINDEX i
= 0; i
< reports
.GetSize(); i
++)
1655 PTRACE(3, "RTP\tOnReceiverReport RR: " << reports
[i
]);
1660 void RTP_Session::OnRxSourceDescription(const SourceDescriptionArray
& PTRACE_PARAM(description
))
1663 for (PINDEX i
= 0; i
< description
.GetSize(); i
++)
1664 PTRACE(3, "RTP\tOnSourceDescription: " << description
[i
]);
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
];
1721 << items
.GetDataAt(i
)
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
;
1757 RTP_Session
* RTP_SessionManager::UseSession(unsigned sessionID
)
1759 PWaitAndSignal
m(mutex
);
1761 RTP_Session
* session
= sessions
.GetAt(sessionID
);
1762 if (session
== NULL
)
1765 PTRACE(3, "RTP\tFound existing session " << sessionID
);
1766 session
->IncrementReference();
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
,
1786 PTRACE(2, "RTP\tReleasing session " << sessionID
);
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
);
1804 RTP_Session
* RTP_SessionManager::GetSession(unsigned sessionID
) const
1806 PWaitAndSignal
wait(mutex
);
1807 if (!sessions
.Contains(sessionID
))
1810 PTRACE(3, "RTP\tFound existing session " << sessionID
);
1811 return &sessions
[sessionID
];
1815 RTP_Session
* RTP_SessionManager::First()
1819 enumerationIndex
= 0;
1824 RTP_Session
* RTP_SessionManager::Next()
1826 if (enumerationIndex
< sessions
.GetSize())
1827 return &sessions
.GetDataAt(enumerationIndex
++);
1834 void RTP_SessionManager::Exit()
1836 enumerationIndex
= P_MAX_INDEX
;
1841 /////////////////////////////////////////////////////////////////////////////
1843 static void SetMinBufferSize(PUDPSocket
& sock
, int buftype
)
1846 if (sock
.GetOption(buftype
, sz
)) {
1847 if (sz
>= UDP_BUFFER_SIZE
)
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
),
1860 remoteTransmitAddress(0),
1861 remoteIsNAT(_remoteIsNAT
)
1863 PTRACE(4, "RTP_UDP\tRTP session created with NAT flag set to " << remoteIsNAT
);
1865 remoteControlPort
= 0;
1866 shutdownRead
= FALSE
;
1867 shutdownWrite
= FALSE
;
1869 controlSocket
= NULL
;
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.
1883 PAssert(jitter
->WaitForTermination(10000), "Jitter buffer thread did not terminate");
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());
1900 BOOL
RTP_UDP::ModifyQOS(RTP_QOS
* rtpqos
)
1902 BOOL retval
= FALSE
;
1907 if (controlSocket
!= NULL
)
1908 retval
= controlSocket
->ModifyQoSSpec(&(rtpqos
->ctrlQoS
));
1910 if (dataSocket
!= NULL
)
1911 retval
&= dataSocket
->ModifyQoSSpec(&(rtpqos
->dataQoS
));
1917 BOOL
RTP_UDP::Open(PIPSocket::Address _localAddress
,
1918 WORD portBase
, WORD portMax
,
1924 // save local address
1925 localAddress
= _localAddress
;
1927 localDataPort
= (WORD
)(portBase
&0xfffe);
1928 localControlPort
= (WORD
)(localDataPort
+ 1);
1931 delete controlSocket
;
1933 controlSocket
= NULL
;
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)) {
1947 if (stun
->CreateSocketPair(dataSocket
, controlSocket
)) {
1948 dataSocket
->GetLocalAddress(localAddress
, localDataPort
);
1949 controlSocket
->GetLocalAddress(localAddress
, localControlPort
);
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
);
1957 PTRACE(1, "RTP\tSTUN could not create RTP socket either.");
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!
1976 localControlPort
+= 2;
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
);
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
);
2010 void RTP_UDP::Reopen(BOOL reading
)
2013 shutdownRead
= FALSE
;
2015 shutdownWrite
= FALSE
;
2019 void RTP_UDP::Close(BOOL reading
)
2021 if (!shutdownRead
&& !shutdownWrite
)
2025 if (!shutdownRead
) {
2026 PTRACE(3, "RTP_UDP\tSession " << sessionID
<< ", Shutting down read.");
2028 shutdownRead
= TRUE
;
2029 if (dataSocket
!= NULL
&& controlSocket
!= NULL
) {
2030 PIPSocket::Address addr
;
2031 controlSocket
->GetLocalAddress(addr
);
2033 PIPSocket::GetHostAddress(addr
);
2034 dataSocket
->WriteTo("", 1, addr
, controlSocket
->GetPort());
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
)
2054 PTRACE(3, "RTP_UDP\tIgnoring remote socket info as remote is behind NAT");
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
)
2067 remoteAddress
= address
;
2069 allowSyncSourceInChange
= TRUE
;
2070 allowRemoteTransmitAddressChange
= TRUE
;
2071 allowSequenceChange
= TRUE
;
2074 remoteDataPort
= port
;
2075 if (remoteControlPort
== 0 || allowRemoteTransmitAddressChange
)
2076 remoteControlPort
= (WORD
)(port
+ 1);
2079 remoteControlPort
= port
;
2080 if (remoteDataPort
== 0 || allowRemoteTransmitAddressChange
)
2081 remoteDataPort
= (WORD
)(port
- 1);
2085 ApplyQOS(remoteAddress
);
2087 return remoteAddress
!= 0 && port
!= 0;
2091 BOOL
RTP_UDP::ReadData(RTP_DataFrame
& frame
, BOOL loop
)
2094 int selectStatus
= WaitForPDU(*dataSocket
, *controlSocket
, reportTimer
);
2097 PTRACE(3, "RTP_UDP\tSession " << sessionID
<< ", Read shutdown.");
2098 shutdownRead
= FALSE
;
2102 switch (selectStatus
) {
2104 if (ReadControlPDU() == e_AbortTransport
)
2109 if (ReadControlPDU() == e_AbortTransport
)
2114 switch (ReadDataPDU(frame
)) {
2115 case e_ProcessPacket
:
2118 case e_IgnorePacket
:
2120 case e_AbortTransport
:
2130 case PSocket::Interrupted
:
2131 PTRACE(3, "RTP_UDP\tSession " << sessionID
<< ", Interrupted.");
2135 PTRACE(1, "RTP_UDP\tSession " << sessionID
<< ", Select error: "
2136 << PChannel::GetErrorText((PChannel::Errors
)selectStatus
));
2145 int RTP_UDP::WaitForPDU(PUDPSocket
& dataSocket
, PUDPSocket
& controlSocket
, const PTimeInterval
& timeout
)
2151 switch (PSocket::Select(dataSocket
, controlSocket
, PTimeInterval(0))) {
2153 controlSocket
.Read(buffer
, sizeof(buffer
));
2158 controlSocket
.Read(buffer
, sizeof(buffer
));
2161 dataSocket
.Read(buffer
, sizeof(buffer
));
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
,
2177 BOOL fromDataChannel
)
2180 const char * channelName
= fromDataChannel
? "Data" : "Control";
2182 PIPSocket::Address addr
;
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
;
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()) {
2225 PTRACE(2, "RTP_UDP\tSession " << sessionID
<< ", "
2226 << channelName
<< " port on remote not ready.");
2227 return RTP_Session::e_IgnorePacket
;
2230 // Shouldn't happen, but it does.
2231 return RTP_Session::e_IgnorePacket
;
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
)
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
)
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
;
2289 // Trying to send a PDU before we are set up!
2290 if (!remoteAddress
.IsValid() || remoteDataPort
== 0)
2293 switch (OnSendData(frame
)) {
2294 case e_ProcessPacket
:
2296 case e_IgnorePacket
:
2298 case e_AbortTransport
:
2302 while (!dataSocket
->WriteTo(frame
.GetPointer(),
2303 frame
.GetHeaderSize()+frame
.GetPayloadSize(),
2304 remoteAddress
, remoteDataPort
)) {
2305 switch (dataSocket
->GetErrorNumber()) {
2308 PTRACE(2, "RTP_UDP\tSession " << sessionID
<< ", data port on remote not ready.");
2312 PTRACE(1, "RTP_UDP\tSession " << sessionID
2313 << ", Write error on data port ("
2314 << dataSocket
->GetErrorNumber(PChannel::LastWriteError
) << "): "
2315 << dataSocket
->GetErrorText(PChannel::LastWriteError
));
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)
2330 PINDEX len
= frame
.GetCompoundSize();
2331 switch (OnSendControl(frame
, len
)) {
2332 case e_ProcessPacket
:
2334 case e_IgnorePacket
:
2336 case e_AbortTransport
:
2340 while (!controlSocket
->WriteTo(frame
.GetPointer(), len
,
2341 remoteAddress
, remoteControlPort
)) {
2342 switch (controlSocket
->GetErrorNumber()) {
2345 PTRACE(2, "RTP_UDP\tSession " << sessionID
<< ", control port on remote not ready.");
2349 PTRACE(1, "RTP_UDP\tSession " << sessionID
2350 << ", Write error on control port ("
2351 << controlSocket
->GetErrorNumber(PChannel::LastWriteError
) << "): "
2352 << controlSocket
->GetErrorText(PChannel::LastWriteError
));
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 /////////////////////////////////////////////////////////////////////////////