home *** CD-ROM | disk | FTP | other *** search
/ ftp.muug.mb.ca / 2014.06.ftp.muug.mb.ca.tar / ftp.muug.mb.ca / pub / openh323.tar.gz / openh323.tar / openh323 / src / h323rtp.cxx < prev    next >
C/C++ Source or Header  |  2003-02-06  |  13KB  |  369 lines

  1. /*
  2.  * h323rtp.cxx
  3.  *
  4.  * H.323 RTP protocol handler
  5.  *
  6.  * Open H323 Library
  7.  *
  8.  * Copyright (c) 1999-2000 Equivalence Pty. Ltd.
  9.  *
  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/
  14.  *
  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.
  19.  *
  20.  * The Original Code is Open H323 Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Contributor(s): ______________________________________.
  25.  *
  26.  * $Log: h323rtp.cxx,v $
  27.  * Revision 1.26  2003/02/07 00:28:24  robertj
  28.  * Changed function to virtual to help in using external multiicast RTP stacks.
  29.  *
  30.  * Revision 1.25  2003/02/05 06:32:10  robertj
  31.  * Fixed non-stun symmetric NAT support recently broken.
  32.  *
  33.  * Revision 1.24  2003/02/05 01:55:14  robertj
  34.  * Fixed setting of correct address in OLC's when STUN is used.
  35.  *
  36.  * Revision 1.23  2003/02/04 07:06:41  robertj
  37.  * Added STUN support.
  38.  *
  39.  * Revision 1.22  2002/11/19 01:47:26  robertj
  40.  * Included canonical name in RTP statistics returned in IRR
  41.  *
  42.  * Revision 1.21  2002/10/08 13:08:21  robertj
  43.  * Changed for IPv6 support, thanks SΘbastien Josset.
  44.  *
  45.  * Revision 1.20  2002/08/05 10:03:47  robertj
  46.  * Cosmetic changes to normalise the usage of pragma interface/implementation.
  47.  *
  48.  * Revision 1.19  2002/07/02 10:02:32  robertj
  49.  * Added H323TransportAddress::GetIpAddress() so don't have to provide port
  50.  *   when you don't need it as in GetIpAndPort(),.
  51.  *
  52.  * Revision 1.18  2002/06/24 08:07:49  robertj
  53.  * Fixed setting of H.225.0 logical channel parameter silenceSuppression field
  54.  *   to correctly indicate if codec is going to stop sending RTP on silence.
  55.  *
  56.  * Revision 1.17  2002/05/28 06:27:23  robertj
  57.  * Split UDP (for RAS) from RTP port bases.
  58.  * Added current port variable so cycles around the port range specified which
  59.  *   fixes some wierd problems on some platforms, thanks Federico Pinna
  60.  *
  61.  * Revision 1.16  2001/10/02 02:06:23  robertj
  62.  * Fixed CIsco IOS compatibility, yet again!.
  63.  *
  64.  * Revision 1.15  2001/10/02 01:53:53  robertj
  65.  * Fixed CIsco IOS compatibility, again.
  66.  *
  67.  * Revision 1.14  2001/08/06 03:08:57  robertj
  68.  * Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
  69.  *
  70.  * Revision 1.13  2001/02/09 05:13:56  craigs
  71.  * Added pragma implementation to (hopefully) reduce the executable image size
  72.  * under Linux
  73.  *
  74.  * Revision 1.12  2001/01/25 07:27:16  robertj
  75.  * Major changes to add more flexible OpalMediaFormat class to normalise
  76.  *   all information about media types, especially codecs.
  77.  *
  78.  * Revision 1.11  2000/12/18 08:59:20  craigs
  79.  * Added ability to set ports
  80.  *
  81.  * Revision 1.10  2000/09/22 00:32:34  craigs
  82.  * Added extra logging
  83.  * Fixed problems with no fastConnect with tunelling
  84.  *
  85.  * Revision 1.9  2000/08/31 08:15:41  robertj
  86.  * Added support for dynamic RTP payload types in H.245 OpenLogicalChannel negotiations.
  87.  *
  88.  * Revision 1.8  2000/08/23 14:27:04  craigs
  89.  * Added prototype support for Microsoft GSM codec
  90.  *
  91.  * Revision 1.7  2000/07/12 13:06:49  robertj
  92.  * Removed test for sessionID in OLC, just trace a warning instead of abandoning connection.
  93.  *
  94.  * Revision 1.6  2000/07/11 19:36:43  robertj
  95.  * Fixed silenceSuppression field in OLC only to be included on transmitter.
  96.  *
  97.  * Revision 1.5  2000/05/23 12:57:37  robertj
  98.  * Added ability to change IP Type Of Service code from applications.
  99.  *
  100.  * Revision 1.4  2000/05/02 04:32:27  robertj
  101.  * Fixed copyright notice comment.
  102.  *
  103.  * Revision 1.3  2000/04/05 03:17:32  robertj
  104.  * Added more RTP statistics gathering and H.245 round trip delay calculation.
  105.  *
  106.  * Revision 1.2  2000/01/20 05:57:46  robertj
  107.  * Added extra flexibility in receiving incorrectly formed OpenLogicalChannel PDU's
  108.  *
  109.  * Revision 1.1  1999/12/23 23:02:36  robertj
  110.  * File reorganision for separating RTP from H.323 and creation of LID for VPB support.
  111.  *
  112.  */
  113.  
  114. #include <ptlib.h>
  115.  
  116. #ifdef __GNUC__
  117. #pragma implementation "h323rtp.h"
  118. #endif
  119.  
  120. #include "h323rtp.h"
  121.  
  122. #include "h323ep.h"
  123. #include "h225.h"
  124. #include "h245.h"
  125.  
  126.  
  127. #define new PNEW
  128.  
  129.  
  130. /////////////////////////////////////////////////////////////////////////////
  131.  
  132. H323_RTP_Session::H323_RTP_Session(const H323Connection & conn)
  133.   : connection(conn)
  134. {
  135. }
  136.  
  137.  
  138. void H323_RTP_Session::OnTxStatistics(const RTP_Session & session) const
  139. {
  140.   connection.OnRTPStatistics(session);
  141. }
  142.  
  143.  
  144. void H323_RTP_Session::OnRxStatistics(const RTP_Session & session) const
  145. {
  146.   connection.OnRTPStatistics(session);
  147. }
  148.  
  149.  
  150. /////////////////////////////////////////////////////////////////////////////
  151.  
  152. H323_RTP_UDP::H323_RTP_UDP(const H323Connection & conn, RTP_UDP & rtp_udp)
  153.   : H323_RTP_Session(conn),
  154.     rtp(rtp_udp)
  155. {
  156.   const H323Transport & transport = connection.GetControlChannel();
  157.   PIPSocket::Address localAddress;
  158.   transport.GetLocalAddress().GetIpAddress(localAddress);
  159.  
  160.   H323EndPoint & endpoint = connection.GetEndPoint();
  161.  
  162.   PIPSocket::Address remoteAddress;
  163.   transport.GetRemoteAddress().GetIpAddress(remoteAddress);
  164.   PSTUNClient * stun = endpoint.GetSTUN(remoteAddress);
  165.  
  166.   WORD firstPort = endpoint.GetRtpIpPortPair();
  167.   WORD nextPort = firstPort;
  168.   while (!rtp.Open(localAddress,
  169.                    nextPort, nextPort,
  170.                    endpoint.GetRtpIpTypeofService(),
  171.                    stun)) {
  172.     nextPort = endpoint.GetRtpIpPortPair();
  173.     if (nextPort == firstPort)
  174.       return;
  175.   }
  176.  
  177.   localAddress = rtp.GetLocalAddress();
  178.   endpoint.TranslateTCPAddress(localAddress, remoteAddress);
  179.   rtp.SetLocalAddress(localAddress);
  180. }
  181.  
  182.  
  183. BOOL H323_RTP_UDP::OnSendingPDU(const H323_RTPChannel & channel,
  184.                                 H245_H2250LogicalChannelParameters & param) const
  185. {
  186.   PTRACE(3, "RTP\tOnSendingPDU");
  187.  
  188.   param.m_sessionID = rtp.GetSessionID();
  189.  
  190.   param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaGuaranteedDelivery);
  191.   param.m_mediaGuaranteedDelivery = FALSE;
  192.  
  193.   // unicast must have mediaControlChannel
  194.   param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel);
  195.   H323TransportAddress mediaControlAddress(rtp.GetLocalAddress(), rtp.GetLocalControlPort());
  196.   mediaControlAddress.SetPDU(param.m_mediaControlChannel);
  197.  
  198.   if (channel.GetDirection() == H323Channel::IsReceiver) {
  199.     // set mediaChannel
  200.     param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
  201.     H323TransportAddress mediaAddress(rtp.GetLocalAddress(), rtp.GetLocalDataPort());
  202.     mediaAddress.SetPDU(param.m_mediaChannel);
  203.   }
  204.  
  205.   H323Codec * codec = channel.GetCodec();
  206.   if (codec != NULL) {
  207.     // Set flag for we are going to stop sending audio on silence
  208.     if (codec->IsDescendant(H323AudioCodec::Class()) && channel.GetDirection() != H323Channel::IsReceiver) {
  209.       param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_silenceSuppression);
  210.       param.m_silenceSuppression = ((H323AudioCodec*)codec)->GetSilenceDetectionMode() != H323AudioCodec::NoSilenceDetection;
  211.     }
  212.  
  213.     // Set dynamic payload type, if is one
  214.     int rtpPayloadType = codec->GetMediaFormat().GetPayloadType();
  215.     if (rtpPayloadType >= RTP_DataFrame::DynamicBase) {
  216.       param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType);
  217.       param.m_dynamicRTPPayloadType = rtpPayloadType;
  218.     }
  219.   }
  220.  
  221.   return TRUE;
  222. }
  223.  
  224.  
  225. void H323_RTP_UDP::OnSendingAckPDU(const H323_RTPChannel & channel,
  226.                                    H245_H2250LogicalChannelAckParameters & param) const
  227. {
  228.   PTRACE(3, "RTP\tOnSendingAckPDU");
  229.  
  230.   // set mediaControlChannel
  231.   param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel);
  232.   H323TransportAddress mediaControlAddress(rtp.GetLocalAddress(), rtp.GetLocalControlPort());
  233.   mediaControlAddress.SetPDU(param.m_mediaControlChannel);
  234.  
  235.   // set mediaChannel
  236.   param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
  237.   H323TransportAddress mediaAddress(rtp.GetLocalAddress(), rtp.GetLocalDataPort());
  238.   mediaAddress.SetPDU(param.m_mediaChannel);
  239.  
  240.   // Set dynamic payload type, if is one
  241.   H323Codec * codec = channel.GetCodec();
  242.   if (codec != NULL) {
  243.     int rtpPayloadType = channel.GetCodec()->GetMediaFormat().GetPayloadType();
  244.     if (rtpPayloadType >= RTP_DataFrame::DynamicBase) {
  245.       param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType);
  246.       param.m_dynamicRTPPayloadType = rtpPayloadType;
  247.     }
  248.   }
  249. }
  250.  
  251.  
  252. BOOL H323_RTP_UDP::ExtractTransport(const H245_TransportAddress & pdu,
  253.                                     BOOL isDataPort,
  254.                                     unsigned & errorCode)
  255. {
  256.   if (pdu.GetTag() != H245_TransportAddress::e_unicastAddress) {
  257.     PTRACE(1, "RTP_UDP\tOnly unicast supported at this time");
  258.     errorCode = H245_OpenLogicalChannelReject_cause::e_multicastChannelNotAllowed;
  259.     return FALSE;
  260.   }
  261.  
  262.   H323TransportAddress transAddr = pdu;
  263.  
  264.   PIPSocket::Address ip;
  265.   WORD port;
  266.   if (transAddr.GetIpAndPort(ip, port))
  267.     return rtp.SetRemoteSocketInfo(ip, port, isDataPort);
  268.  
  269.   return FALSE;
  270. }
  271.  
  272.  
  273. BOOL H323_RTP_UDP::OnReceivedPDU(H323_RTPChannel & channel,
  274.                                  const H245_H2250LogicalChannelParameters & param,
  275.                                  unsigned & errorCode)
  276. {
  277.   if (param.m_sessionID != rtp.GetSessionID()) {
  278.     PTRACE(1, "RTP_UDP\tOpen of " << channel << " with invalid session: " << param.m_sessionID);
  279.     errorCode = H245_OpenLogicalChannelReject_cause::e_invalidSessionID;
  280.     return FALSE;
  281.   }
  282.  
  283.   BOOL ok = FALSE;
  284.  
  285.   if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel)) {
  286.     if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode)) {
  287.       PTRACE(1, "RTP_UDP\tFailed to extract mediaControl transport for " << channel);
  288.       return FALSE;
  289.     }
  290.     ok = TRUE;
  291.   }
  292.  
  293.   if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaChannel)) {
  294.     if (ok && channel.GetDirection() == H323Channel::IsReceiver)
  295.       PTRACE(3, "RTP_UDP\tIgnoring media transport for " << channel);
  296.     else if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode)) {
  297.       PTRACE(1, "RTP_UDP\tFailed to extract media transport for " << channel);
  298.       return FALSE;
  299.     }
  300.     ok = TRUE;
  301.   }
  302.  
  303.   if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType))
  304.     channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
  305.  
  306.   if (ok)
  307.     return TRUE;
  308.  
  309.   PTRACE(1, "RTP_UDP\tNo mediaChannel or mediaControlChannel specified for " << channel);
  310.   errorCode = H245_OpenLogicalChannelReject_cause::e_unspecified;
  311.   return FALSE;
  312. }
  313.  
  314.  
  315. BOOL H323_RTP_UDP::OnReceivedAckPDU(H323_RTPChannel & channel,
  316.                                     const H245_H2250LogicalChannelAckParameters & param)
  317. {
  318.   if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_sessionID)) {
  319.     PTRACE(1, "RTP_UDP\tNo session specified");
  320.   }
  321.  
  322.   if (param.m_sessionID != rtp.GetSessionID()) {
  323.     PTRACE(1, "RTP_UDP\tAck for invalid session: " << param.m_sessionID);
  324.   }
  325.  
  326.   if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel)) {
  327.     PTRACE(1, "RTP_UDP\tNo mediaControlChannel specified");
  328.     return FALSE;
  329.   }
  330.  
  331.   unsigned errorCode;
  332.   if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode))
  333.     return FALSE;
  334.  
  335.   if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel)) {
  336.     PTRACE(1, "RTP_UDP\tNo mediaChannel specified");
  337.     return FALSE;
  338.   }
  339.  
  340.   if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode))
  341.     return FALSE;
  342.  
  343.   if (param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType))
  344.     channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
  345.  
  346.   return TRUE;
  347. }
  348.  
  349.  
  350. void H323_RTP_UDP::OnSendRasInfo(H225_RTPSession & info)
  351. {
  352.   info.m_sessionId = rtp.GetSessionID();
  353.   info.m_ssrc = rtp.GetSyncSourceOut();
  354.   info.m_cname = rtp.GetCanonicalName();
  355.  
  356.   const H323Transport & transport = connection.GetControlChannel();
  357.  
  358.   transport.SetUpTransportPDU(info.m_rtpAddress.m_recvAddress, rtp.GetLocalDataPort());
  359.   H323TransportAddress ta1(rtp.GetRemoteAddress(), rtp.GetRemoteDataPort());
  360.   ta1.SetPDU(info.m_rtpAddress.m_sendAddress);
  361.  
  362.   transport.SetUpTransportPDU(info.m_rtcpAddress.m_recvAddress, rtp.GetLocalControlPort());
  363.   H323TransportAddress ta2(rtp.GetRemoteAddress(), rtp.GetRemoteDataPort());
  364.   ta2.SetPDU(info.m_rtcpAddress.m_sendAddress);
  365. }
  366.  
  367.  
  368. /////////////////////////////////////////////////////////////////////////////
  369.