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