Utilise new MergeSym feature to no longer overwrite the source .DEF file when buildin...
[openh323.git] / src / h323rtp.cxx
blob5d5aa9aaa2089e07d2b7c48971bec18a37471a9a
1 /*
2 * h323rtp.cxx
4 * H.323 RTP protocol handler
6 * Open H323 Library
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
18 * under the License.
20 * The Original Code is Open H323 Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
26 * $Log$
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
63 * Added STUN support.
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
98 * under Linux
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.
140 #include <ptlib.h>
142 #ifdef __GNUC__
143 #pragma implementation "h323rtp.h"
144 #endif
146 #include "h323rtp.h"
148 #include "h323ep.h"
149 #include "h225.h"
150 #include "h245.h"
153 #define new PNEW
156 /////////////////////////////////////////////////////////////////////////////
158 H323_RTP_Session::H323_RTP_Session(const H323Connection & conn)
159 : connection(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,
179 RTP_UDP & rtp_udp,
180 RTP_QOS * rtpQos)
181 : H323_RTP_Session(conn),
182 rtp(rtp_udp)
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);
193 #ifdef P_STUN
194 PNatMethod * meth = endpoint.GetPreferedNatMethod(remoteAddress);
195 #endif
197 WORD firstPort = endpoint.GetRtpIpPortPair();
198 WORD nextPort = firstPort;
199 while (!rtp.Open(localAddress,
200 nextPort, nextPort,
201 endpoint.GetRtpIpTypeofService(),
202 #ifdef P_STUN
203 meth,
204 #else
205 NULL,
206 #endif
207 rtpQos)) {
208 nextPort = endpoint.GetRtpIpPortPair();
209 if (nextPort == firstPort)
210 return;
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) {
235 // set mediaChannel
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();
245 if (codec != NULL &&
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;
251 #endif
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;
260 // GQoS
261 #if P_HAS_QOS
262 if (WriteTransportCapPDU(param.m_transportCapability,channel)) {
263 param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_transportCapability);
265 #endif
266 return TRUE;
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);
280 // set mediaChannel
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,
295 BOOL isDataPort,
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;
301 return FALSE;
304 H323TransportAddress transAddr = pdu;
306 PIPSocket::Address ip;
307 WORD port;
308 if (transAddr.GetIpAndPort(ip, port))
309 return rtp.SetRemoteSocketInfo(ip, port, isDataPort);
311 return FALSE;
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;
322 return FALSE;
325 BOOL ok = FALSE;
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);
330 return FALSE;
332 ok = TRUE;
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);
340 return FALSE;
342 ok = TRUE;
345 if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType))
346 channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
348 // GQoS
349 #if P_HAS_QOS
350 if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_transportCapability)) {
351 H245_TransportCapability trans = param.m_transportCapability;
352 ReadTransportCapPDU(trans,channel);
354 #endif
356 if (ok)
357 return TRUE;
359 PTRACE(1, "RTP_UDP\tNo mediaChannel or mediaControlChannel specified for " << channel);
360 errorCode = H245_OpenLogicalChannelReject_cause::e_unspecified;
361 return FALSE;
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");
378 return FALSE;
381 unsigned errorCode;
382 if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode))
383 return FALSE;
385 if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel)) {
386 PTRACE(1, "RTP_UDP\tNo mediaChannel specified");
387 return FALSE;
390 if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode))
391 return FALSE;
393 if (param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType))
394 channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
396 return TRUE;
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);
417 #if P_HAS_QOS
418 BOOL H323_RTP_UDP::WriteTransportCapPDU(H245_TransportCapability & cap,
419 const H323_RTPChannel & channel) const
421 if (!PUDPSocket::SupportQoS(rtp.GetLocalAddress()))
422 return FALSE;
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
433 rtp.EnableGQoS();
434 return TRUE;
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);
440 else
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();
450 QoSs.Append(Cap);
451 return TRUE;
454 void H323_RTP_UDP::ReadTransportCapPDU(const H245_TransportCapability & cap,
455 H323_RTPChannel & channel)
457 if (!PUDPSocket::SupportQoS(rtp.GetLocalAddress()))
458 return;
459 if (!cap.HasOptionalField(H245_TransportCapability::e_qOSCapabilities))
460 return;
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))
465 return;
466 H245_RSVPParameters & rsvp = QoS.m_rsvpParameters;
467 if (channel.GetDirection() != H323Channel::IsReceiver) {
468 rtp.EnableGQoS();
469 return;
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);
477 } else {
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);
490 #endif
491 /////////////////////////////////////////////////////////////////////////////