4 * H.323 RTP protocol handler
8 * Copyright (c) 1999-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 * Contributor(s): ______________________________________.
27 * Revision 1.34 2006/01/26 03:38:54 shorne
28 * Added transport capability exchange
30 * Revision 1.33 2005/06/21 06:46:35 csoutheren
31 * Add ability to create capabilities without codecs for external RTP interface
33 * Revision 1.32 2005/01/03 14:03:42 csoutheren
34 * Added new configure options and ability to disable/enable modules
36 * Revision 1.31 2005/01/03 06:26:09 csoutheren
37 * Added extensive support for disabling code modules at compile time
39 * Revision 1.30 2004/11/25 07:38:59 csoutheren
40 * Ensured that external TCP address translation is performed when using STUN to handle UDP
42 * Revision 1.29 2004/07/03 05:47:54 rjongbloed
43 * Added virtual function for determining RTP payload type used in an H.323 channel,
44 * also some added bullet proofing for exception conditions, thanks Guilhem Tardy
46 * Revision 1.28 2004/04/03 08:28:07 csoutheren
47 * Remove pseudo-RTTI and replaced with real RTTI
49 * Revision 1.27 2003/10/27 06:03:39 csoutheren
50 * Added support for QoS
51 * Thanks to Henry Harrison of AliceStreet
53 * Revision 1.26 2003/02/07 00:28:24 robertj
54 * Changed function to virtual to help in using external multiicast RTP stacks.
56 * Revision 1.25 2003/02/05 06:32:10 robertj
57 * Fixed non-stun symmetric NAT support recently broken.
59 * Revision 1.24 2003/02/05 01:55:14 robertj
60 * Fixed setting of correct address in OLC's when STUN is used.
62 * Revision 1.23 2003/02/04 07:06:41 robertj
65 * Revision 1.22 2002/11/19 01:47:26 robertj
66 * Included canonical name in RTP statistics returned in IRR
68 * Revision 1.21 2002/10/08 13:08:21 robertj
69 * Changed for IPv6 support, thanks Sébastien Josset.
71 * Revision 1.20 2002/08/05 10:03:47 robertj
72 * Cosmetic changes to normalise the usage of pragma interface/implementation.
74 * Revision 1.19 2002/07/02 10:02:32 robertj
75 * Added H323TransportAddress::GetIpAddress() so don't have to provide port
76 * when you don't need it as in GetIpAndPort(),.
78 * Revision 1.18 2002/06/24 08:07:49 robertj
79 * Fixed setting of H.225.0 logical channel parameter silenceSuppression field
80 * to correctly indicate if codec is going to stop sending RTP on silence.
82 * Revision 1.17 2002/05/28 06:27:23 robertj
83 * Split UDP (for RAS) from RTP port bases.
84 * Added current port variable so cycles around the port range specified which
85 * fixes some wierd problems on some platforms, thanks Federico Pinna
87 * Revision 1.16 2001/10/02 02:06:23 robertj
88 * Fixed CIsco IOS compatibility, yet again!.
90 * Revision 1.15 2001/10/02 01:53:53 robertj
91 * Fixed CIsco IOS compatibility, again.
93 * Revision 1.14 2001/08/06 03:08:57 robertj
94 * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
96 * Revision 1.13 2001/02/09 05:13:56 craigs
97 * Added pragma implementation to (hopefully) reduce the executable image size
100 * Revision 1.12 2001/01/25 07:27:16 robertj
101 * Major changes to add more flexible OpalMediaFormat class to normalise
102 * all information about media types, especially codecs.
104 * Revision 1.11 2000/12/18 08:59:20 craigs
105 * Added ability to set ports
107 * Revision 1.10 2000/09/22 00:32:34 craigs
108 * Added extra logging
109 * Fixed problems with no fastConnect with tunelling
111 * Revision 1.9 2000/08/31 08:15:41 robertj
112 * Added support for dynamic RTP payload types in H.245 OpenLogicalChannel negotiations.
114 * Revision 1.8 2000/08/23 14:27:04 craigs
115 * Added prototype support for Microsoft GSM codec
117 * Revision 1.7 2000/07/12 13:06:49 robertj
118 * Removed test for sessionID in OLC, just trace a warning instead of abandoning connection.
120 * Revision 1.6 2000/07/11 19:36:43 robertj
121 * Fixed silenceSuppression field in OLC only to be included on transmitter.
123 * Revision 1.5 2000/05/23 12:57:37 robertj
124 * Added ability to change IP Type Of Service code from applications.
126 * Revision 1.4 2000/05/02 04:32:27 robertj
127 * Fixed copyright notice comment.
129 * Revision 1.3 2000/04/05 03:17:32 robertj
130 * Added more RTP statistics gathering and H.245 round trip delay calculation.
132 * Revision 1.2 2000/01/20 05:57:46 robertj
133 * Added extra flexibility in receiving incorrectly formed OpenLogicalChannel PDU's
135 * Revision 1.1 1999/12/23 23:02:36 robertj
136 * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
143 #pragma implementation "h323rtp.h"
156 /////////////////////////////////////////////////////////////////////////////
158 H323_RTP_Session::H323_RTP_Session(const H323Connection
& conn
)
164 void H323_RTP_Session::OnTxStatistics(const RTP_Session
& session
) const
166 connection
.OnRTPStatistics(session
);
170 void H323_RTP_Session::OnRxStatistics(const RTP_Session
& session
) const
172 connection
.OnRTPStatistics(session
);
176 /////////////////////////////////////////////////////////////////////////////
178 H323_RTP_UDP::H323_RTP_UDP(const H323Connection
& conn
,
181 : H323_RTP_Session(conn
),
184 const H323Transport
& transport
= connection
.GetControlChannel();
185 PIPSocket::Address localAddress
;
186 transport
.GetLocalAddress().GetIpAddress(localAddress
);
188 H323EndPoint
& endpoint
= connection
.GetEndPoint();
190 PIPSocket::Address remoteAddress
;
191 transport
.GetRemoteAddress().GetIpAddress(remoteAddress
);
194 PNatMethod
* meth
= endpoint
.GetPreferedNatMethod(remoteAddress
);
197 WORD firstPort
= endpoint
.GetRtpIpPortPair();
198 WORD nextPort
= firstPort
;
199 while (!rtp
.Open(localAddress
,
201 endpoint
.GetRtpIpTypeofService(),
208 nextPort
= endpoint
.GetRtpIpPortPair();
209 if (nextPort
== firstPort
)
213 localAddress
= rtp
.GetLocalAddress();
214 endpoint
.InternalTranslateTCPAddress(localAddress
, remoteAddress
);
215 rtp
.SetLocalAddress(localAddress
);
219 BOOL
H323_RTP_UDP::OnSendingPDU(const H323_RTPChannel
& channel
,
220 H245_H2250LogicalChannelParameters
& param
) const
222 PTRACE(3, "RTP\tOnSendingPDU");
224 param
.m_sessionID
= rtp
.GetSessionID();
226 param
.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaGuaranteedDelivery
);
227 param
.m_mediaGuaranteedDelivery
= FALSE
;
229 // unicast must have mediaControlChannel
230 param
.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel
);
231 H323TransportAddress
mediaControlAddress(rtp
.GetLocalAddress(), rtp
.GetLocalControlPort());
232 mediaControlAddress
.SetPDU(param
.m_mediaControlChannel
);
234 if (channel
.GetDirection() == H323Channel::IsReceiver
) {
236 param
.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel
);
237 H323TransportAddress
mediaAddress(rtp
.GetLocalAddress(), rtp
.GetLocalDataPort());
238 mediaAddress
.SetPDU(param
.m_mediaChannel
);
241 #ifndef NO_H323_AUDIO_CODECS
242 // Set flag for we are going to stop sending audio on silence
243 H323Codec
* codec
= channel
.GetCodec();
246 PIsDescendant(codec
, H323AudioCodec
) &&
247 channel
.GetDirection() != H323Channel::IsReceiver
) {
248 param
.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_silenceSuppression
);
249 param
.m_silenceSuppression
= ((H323AudioCodec
*)codec
)->GetSilenceDetectionMode() != H323AudioCodec::NoSilenceDetection
;
253 // Set dynamic payload type, if is one
254 int rtpPayloadType
= channel
.GetRTPPayloadType();
255 if (rtpPayloadType
>= RTP_DataFrame::DynamicBase
&& rtpPayloadType
<= RTP_DataFrame::MaxPayloadType
) {
256 param
.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType
);
257 param
.m_dynamicRTPPayloadType
= rtpPayloadType
;
262 if (WriteTransportCapPDU(param
.m_transportCapability
,channel
)) {
263 param
.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_transportCapability
);
270 void H323_RTP_UDP::OnSendingAckPDU(const H323_RTPChannel
& channel
,
271 H245_H2250LogicalChannelAckParameters
& param
) const
273 PTRACE(3, "RTP\tOnSendingAckPDU");
275 // set mediaControlChannel
276 param
.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel
);
277 H323TransportAddress
mediaControlAddress(rtp
.GetLocalAddress(), rtp
.GetLocalControlPort());
278 mediaControlAddress
.SetPDU(param
.m_mediaControlChannel
);
281 param
.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel
);
282 H323TransportAddress
mediaAddress(rtp
.GetLocalAddress(), rtp
.GetLocalDataPort());
283 mediaAddress
.SetPDU(param
.m_mediaChannel
);
285 // Set dynamic payload type, if is one
286 int rtpPayloadType
= channel
.GetRTPPayloadType();
287 if (rtpPayloadType
>= RTP_DataFrame::DynamicBase
&& rtpPayloadType
<= RTP_DataFrame::MaxPayloadType
) {
288 param
.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType
);
289 param
.m_dynamicRTPPayloadType
= rtpPayloadType
;
294 BOOL
H323_RTP_UDP::ExtractTransport(const H245_TransportAddress
& pdu
,
296 unsigned & errorCode
)
298 if (pdu
.GetTag() != H245_TransportAddress::e_unicastAddress
) {
299 PTRACE(1, "RTP_UDP\tOnly unicast supported at this time");
300 errorCode
= H245_OpenLogicalChannelReject_cause::e_multicastChannelNotAllowed
;
304 H323TransportAddress transAddr
= pdu
;
306 PIPSocket::Address ip
;
308 if (transAddr
.GetIpAndPort(ip
, port
))
309 return rtp
.SetRemoteSocketInfo(ip
, port
, isDataPort
);
315 BOOL
H323_RTP_UDP::OnReceivedPDU(H323_RTPChannel
& channel
,
316 const H245_H2250LogicalChannelParameters
& param
,
317 unsigned & errorCode
)
319 if (param
.m_sessionID
!= rtp
.GetSessionID()) {
320 PTRACE(1, "RTP_UDP\tOpen of " << channel
<< " with invalid session: " << param
.m_sessionID
);
321 errorCode
= H245_OpenLogicalChannelReject_cause::e_invalidSessionID
;
327 if (param
.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel
)) {
328 if (!ExtractTransport(param
.m_mediaControlChannel
, FALSE
, errorCode
)) {
329 PTRACE(1, "RTP_UDP\tFailed to extract mediaControl transport for " << channel
);
335 if (param
.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaChannel
)) {
336 if (ok
&& channel
.GetDirection() == H323Channel::IsReceiver
)
337 PTRACE(3, "RTP_UDP\tIgnoring media transport for " << channel
);
338 else if (!ExtractTransport(param
.m_mediaChannel
, TRUE
, errorCode
)) {
339 PTRACE(1, "RTP_UDP\tFailed to extract media transport for " << channel
);
345 if (param
.HasOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType
))
346 channel
.SetDynamicRTPPayloadType(param
.m_dynamicRTPPayloadType
);
350 if (param
.HasOptionalField(H245_H2250LogicalChannelParameters::e_transportCapability
)) {
351 H245_TransportCapability trans
= param
.m_transportCapability
;
352 ReadTransportCapPDU(trans
,channel
);
359 PTRACE(1, "RTP_UDP\tNo mediaChannel or mediaControlChannel specified for " << channel
);
360 errorCode
= H245_OpenLogicalChannelReject_cause::e_unspecified
;
365 BOOL
H323_RTP_UDP::OnReceivedAckPDU(H323_RTPChannel
& channel
,
366 const H245_H2250LogicalChannelAckParameters
& param
)
368 if (!param
.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_sessionID
)) {
369 PTRACE(1, "RTP_UDP\tNo session specified");
372 if (param
.m_sessionID
!= rtp
.GetSessionID()) {
373 PTRACE(1, "RTP_UDP\tAck for invalid session: " << param
.m_sessionID
);
376 if (!param
.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel
)) {
377 PTRACE(1, "RTP_UDP\tNo mediaControlChannel specified");
382 if (!ExtractTransport(param
.m_mediaControlChannel
, FALSE
, errorCode
))
385 if (!param
.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel
)) {
386 PTRACE(1, "RTP_UDP\tNo mediaChannel specified");
390 if (!ExtractTransport(param
.m_mediaChannel
, TRUE
, errorCode
))
393 if (param
.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType
))
394 channel
.SetDynamicRTPPayloadType(param
.m_dynamicRTPPayloadType
);
400 void H323_RTP_UDP::OnSendRasInfo(H225_RTPSession
& info
)
402 info
.m_sessionId
= rtp
.GetSessionID();
403 info
.m_ssrc
= rtp
.GetSyncSourceOut();
404 info
.m_cname
= rtp
.GetCanonicalName();
406 const H323Transport
& transport
= connection
.GetControlChannel();
408 transport
.SetUpTransportPDU(info
.m_rtpAddress
.m_recvAddress
, rtp
.GetLocalDataPort());
409 H323TransportAddress
ta1(rtp
.GetRemoteAddress(), rtp
.GetRemoteDataPort());
410 ta1
.SetPDU(info
.m_rtpAddress
.m_sendAddress
);
412 transport
.SetUpTransportPDU(info
.m_rtcpAddress
.m_recvAddress
, rtp
.GetLocalControlPort());
413 H323TransportAddress
ta2(rtp
.GetRemoteAddress(), rtp
.GetRemoteDataPort());
414 ta2
.SetPDU(info
.m_rtcpAddress
.m_sendAddress
);
418 BOOL
H323_RTP_UDP::WriteTransportCapPDU(H245_TransportCapability
& cap
,
419 const H323_RTPChannel
& channel
) const
421 if (!PUDPSocket::SupportQoS(rtp
.GetLocalAddress()))
424 PQoS
& qos
= rtp
.GetQOS();
425 cap
.IncludeOptionalField(H245_TransportCapability::e_qOSCapabilities
);
426 H245_ArrayOf_QOSCapability
& QoSs
= cap
.m_qOSCapabilities
;
428 H245_QOSCapability
* Cap
= new H245_QOSCapability();
429 Cap
->IncludeOptionalField(H245_QOSCapability::e_rsvpParameters
);
430 H245_RSVPParameters
& rsvp
= Cap
->m_rsvpParameters
;
432 if (channel
.GetDirection() == H323Channel::IsReceiver
) { /// If Reply don't have to send body
436 rsvp
.IncludeOptionalField(H245_RSVPParameters::e_qosMode
);
437 H245_QOSMode
& mode
= rsvp
.m_qosMode
;
438 if (qos
.GetServiceType() == SERVICETYPE_GUARANTEED
)
439 mode
.SetTag(H245_QOSMode::e_guaranteedQOS
);
441 mode
.SetTag(H245_QOSMode::e_controlledLoad
);
443 rsvp
.IncludeOptionalField(H245_RSVPParameters::e_tokenRate
);
444 rsvp
.m_tokenRate
= qos
.GetTokenRate();
445 rsvp
.IncludeOptionalField(H245_RSVPParameters::e_bucketSize
);
446 rsvp
.m_bucketSize
= qos
.GetTokenBucketSize();
447 rsvp
.HasOptionalField(H245_RSVPParameters::e_peakRate
);
448 rsvp
.m_peakRate
= qos
.GetPeakBandwidth();
454 void H323_RTP_UDP::ReadTransportCapPDU(const H245_TransportCapability
& cap
,
455 H323_RTPChannel
& channel
)
457 if (!PUDPSocket::SupportQoS(rtp
.GetLocalAddress()))
459 if (!cap
.HasOptionalField(H245_TransportCapability::e_qOSCapabilities
))
461 H245_ArrayOf_QOSCapability QoSs
= cap
.m_qOSCapabilities
;
462 for (PINDEX i
=0; i
< QoSs
.GetSize(); i
++) {
463 H245_QOSCapability
& QoS
= QoSs
[i
];
464 if (!QoS
.HasOptionalField(H245_QOSCapability::e_rsvpParameters
))
466 H245_RSVPParameters
& rsvp
= QoS
.m_rsvpParameters
;
467 if (channel
.GetDirection() != H323Channel::IsReceiver
) {
471 PQoS
& qos
= rtp
.GetQOS();
472 if (rsvp
.HasOptionalField(H245_RSVPParameters::e_qosMode
)) {
473 H245_QOSMode
& mode
= rsvp
.m_qosMode
;
474 if (mode
.GetTag() == H245_QOSMode::e_guaranteedQOS
) {
475 qos
.SetWinServiceType(SERVICETYPE_GUARANTEED
);
476 qos
.SetDSCP(PQoS::guaranteedDSCP
);
478 qos
.SetWinServiceType(SERVICETYPE_CONTROLLEDLOAD
);
479 qos
.SetDSCP(PQoS::controlledLoadDSCP
);
482 if (rsvp
.HasOptionalField(H245_RSVPParameters::e_tokenRate
))
483 qos
.SetAvgBytesPerSec(rsvp
.m_tokenRate
);
484 if (rsvp
.HasOptionalField(H245_RSVPParameters::e_bucketSize
))
485 qos
.SetMaxFrameBytes(rsvp
.m_bucketSize
);
486 if (rsvp
.HasOptionalField(H245_RSVPParameters::e_peakRate
))
487 qos
.SetPeakBytesPerSec(rsvp
.m_peakRate
);
491 /////////////////////////////////////////////////////////////////////////////