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 >
Wrap
C/C++ Source or Header
|
2003-02-06
|
13KB
|
369 lines
/*
* h323rtp.cxx
*
* H.323 RTP protocol handler
*
* Open H323 Library
*
* Copyright (c) 1999-2000 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Open H323 Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Contributor(s): ______________________________________.
*
* $Log: h323rtp.cxx,v $
* Revision 1.26 2003/02/07 00:28:24 robertj
* Changed function to virtual to help in using external multiicast RTP stacks.
*
* Revision 1.25 2003/02/05 06:32:10 robertj
* Fixed non-stun symmetric NAT support recently broken.
*
* Revision 1.24 2003/02/05 01:55:14 robertj
* Fixed setting of correct address in OLC's when STUN is used.
*
* Revision 1.23 2003/02/04 07:06:41 robertj
* Added STUN support.
*
* Revision 1.22 2002/11/19 01:47:26 robertj
* Included canonical name in RTP statistics returned in IRR
*
* Revision 1.21 2002/10/08 13:08:21 robertj
* Changed for IPv6 support, thanks SΘbastien Josset.
*
* Revision 1.20 2002/08/05 10:03:47 robertj
* Cosmetic changes to normalise the usage of pragma interface/implementation.
*
* Revision 1.19 2002/07/02 10:02:32 robertj
* Added H323TransportAddress::GetIpAddress() so don't have to provide port
* when you don't need it as in GetIpAndPort(),.
*
* Revision 1.18 2002/06/24 08:07:49 robertj
* Fixed setting of H.225.0 logical channel parameter silenceSuppression field
* to correctly indicate if codec is going to stop sending RTP on silence.
*
* Revision 1.17 2002/05/28 06:27:23 robertj
* Split UDP (for RAS) from RTP port bases.
* Added current port variable so cycles around the port range specified which
* fixes some wierd problems on some platforms, thanks Federico Pinna
*
* Revision 1.16 2001/10/02 02:06:23 robertj
* Fixed CIsco IOS compatibility, yet again!.
*
* Revision 1.15 2001/10/02 01:53:53 robertj
* Fixed CIsco IOS compatibility, again.
*
* Revision 1.14 2001/08/06 03:08:57 robertj
* Fission of h323.h to h323ep.h & h323con.h, h323.h now just includes files.
*
* Revision 1.13 2001/02/09 05:13:56 craigs
* Added pragma implementation to (hopefully) reduce the executable image size
* under Linux
*
* Revision 1.12 2001/01/25 07:27:16 robertj
* Major changes to add more flexible OpalMediaFormat class to normalise
* all information about media types, especially codecs.
*
* Revision 1.11 2000/12/18 08:59:20 craigs
* Added ability to set ports
*
* Revision 1.10 2000/09/22 00:32:34 craigs
* Added extra logging
* Fixed problems with no fastConnect with tunelling
*
* Revision 1.9 2000/08/31 08:15:41 robertj
* Added support for dynamic RTP payload types in H.245 OpenLogicalChannel negotiations.
*
* Revision 1.8 2000/08/23 14:27:04 craigs
* Added prototype support for Microsoft GSM codec
*
* Revision 1.7 2000/07/12 13:06:49 robertj
* Removed test for sessionID in OLC, just trace a warning instead of abandoning connection.
*
* Revision 1.6 2000/07/11 19:36:43 robertj
* Fixed silenceSuppression field in OLC only to be included on transmitter.
*
* Revision 1.5 2000/05/23 12:57:37 robertj
* Added ability to change IP Type Of Service code from applications.
*
* Revision 1.4 2000/05/02 04:32:27 robertj
* Fixed copyright notice comment.
*
* Revision 1.3 2000/04/05 03:17:32 robertj
* Added more RTP statistics gathering and H.245 round trip delay calculation.
*
* Revision 1.2 2000/01/20 05:57:46 robertj
* Added extra flexibility in receiving incorrectly formed OpenLogicalChannel PDU's
*
* Revision 1.1 1999/12/23 23:02:36 robertj
* File reorganision for separating RTP from H.323 and creation of LID for VPB support.
*
*/
#include <ptlib.h>
#ifdef __GNUC__
#pragma implementation "h323rtp.h"
#endif
#include "h323rtp.h"
#include "h323ep.h"
#include "h225.h"
#include "h245.h"
#define new PNEW
/////////////////////////////////////////////////////////////////////////////
H323_RTP_Session::H323_RTP_Session(const H323Connection & conn)
: connection(conn)
{
}
void H323_RTP_Session::OnTxStatistics(const RTP_Session & session) const
{
connection.OnRTPStatistics(session);
}
void H323_RTP_Session::OnRxStatistics(const RTP_Session & session) const
{
connection.OnRTPStatistics(session);
}
/////////////////////////////////////////////////////////////////////////////
H323_RTP_UDP::H323_RTP_UDP(const H323Connection & conn, RTP_UDP & rtp_udp)
: H323_RTP_Session(conn),
rtp(rtp_udp)
{
const H323Transport & transport = connection.GetControlChannel();
PIPSocket::Address localAddress;
transport.GetLocalAddress().GetIpAddress(localAddress);
H323EndPoint & endpoint = connection.GetEndPoint();
PIPSocket::Address remoteAddress;
transport.GetRemoteAddress().GetIpAddress(remoteAddress);
PSTUNClient * stun = endpoint.GetSTUN(remoteAddress);
WORD firstPort = endpoint.GetRtpIpPortPair();
WORD nextPort = firstPort;
while (!rtp.Open(localAddress,
nextPort, nextPort,
endpoint.GetRtpIpTypeofService(),
stun)) {
nextPort = endpoint.GetRtpIpPortPair();
if (nextPort == firstPort)
return;
}
localAddress = rtp.GetLocalAddress();
endpoint.TranslateTCPAddress(localAddress, remoteAddress);
rtp.SetLocalAddress(localAddress);
}
BOOL H323_RTP_UDP::OnSendingPDU(const H323_RTPChannel & channel,
H245_H2250LogicalChannelParameters & param) const
{
PTRACE(3, "RTP\tOnSendingPDU");
param.m_sessionID = rtp.GetSessionID();
param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaGuaranteedDelivery);
param.m_mediaGuaranteedDelivery = FALSE;
// unicast must have mediaControlChannel
param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel);
H323TransportAddress mediaControlAddress(rtp.GetLocalAddress(), rtp.GetLocalControlPort());
mediaControlAddress.SetPDU(param.m_mediaControlChannel);
if (channel.GetDirection() == H323Channel::IsReceiver) {
// set mediaChannel
param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
H323TransportAddress mediaAddress(rtp.GetLocalAddress(), rtp.GetLocalDataPort());
mediaAddress.SetPDU(param.m_mediaChannel);
}
H323Codec * codec = channel.GetCodec();
if (codec != NULL) {
// Set flag for we are going to stop sending audio on silence
if (codec->IsDescendant(H323AudioCodec::Class()) && channel.GetDirection() != H323Channel::IsReceiver) {
param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_silenceSuppression);
param.m_silenceSuppression = ((H323AudioCodec*)codec)->GetSilenceDetectionMode() != H323AudioCodec::NoSilenceDetection;
}
// Set dynamic payload type, if is one
int rtpPayloadType = codec->GetMediaFormat().GetPayloadType();
if (rtpPayloadType >= RTP_DataFrame::DynamicBase) {
param.IncludeOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType);
param.m_dynamicRTPPayloadType = rtpPayloadType;
}
}
return TRUE;
}
void H323_RTP_UDP::OnSendingAckPDU(const H323_RTPChannel & channel,
H245_H2250LogicalChannelAckParameters & param) const
{
PTRACE(3, "RTP\tOnSendingAckPDU");
// set mediaControlChannel
param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel);
H323TransportAddress mediaControlAddress(rtp.GetLocalAddress(), rtp.GetLocalControlPort());
mediaControlAddress.SetPDU(param.m_mediaControlChannel);
// set mediaChannel
param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel);
H323TransportAddress mediaAddress(rtp.GetLocalAddress(), rtp.GetLocalDataPort());
mediaAddress.SetPDU(param.m_mediaChannel);
// Set dynamic payload type, if is one
H323Codec * codec = channel.GetCodec();
if (codec != NULL) {
int rtpPayloadType = channel.GetCodec()->GetMediaFormat().GetPayloadType();
if (rtpPayloadType >= RTP_DataFrame::DynamicBase) {
param.IncludeOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType);
param.m_dynamicRTPPayloadType = rtpPayloadType;
}
}
}
BOOL H323_RTP_UDP::ExtractTransport(const H245_TransportAddress & pdu,
BOOL isDataPort,
unsigned & errorCode)
{
if (pdu.GetTag() != H245_TransportAddress::e_unicastAddress) {
PTRACE(1, "RTP_UDP\tOnly unicast supported at this time");
errorCode = H245_OpenLogicalChannelReject_cause::e_multicastChannelNotAllowed;
return FALSE;
}
H323TransportAddress transAddr = pdu;
PIPSocket::Address ip;
WORD port;
if (transAddr.GetIpAndPort(ip, port))
return rtp.SetRemoteSocketInfo(ip, port, isDataPort);
return FALSE;
}
BOOL H323_RTP_UDP::OnReceivedPDU(H323_RTPChannel & channel,
const H245_H2250LogicalChannelParameters & param,
unsigned & errorCode)
{
if (param.m_sessionID != rtp.GetSessionID()) {
PTRACE(1, "RTP_UDP\tOpen of " << channel << " with invalid session: " << param.m_sessionID);
errorCode = H245_OpenLogicalChannelReject_cause::e_invalidSessionID;
return FALSE;
}
BOOL ok = FALSE;
if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaControlChannel)) {
if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode)) {
PTRACE(1, "RTP_UDP\tFailed to extract mediaControl transport for " << channel);
return FALSE;
}
ok = TRUE;
}
if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_mediaChannel)) {
if (ok && channel.GetDirection() == H323Channel::IsReceiver)
PTRACE(3, "RTP_UDP\tIgnoring media transport for " << channel);
else if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode)) {
PTRACE(1, "RTP_UDP\tFailed to extract media transport for " << channel);
return FALSE;
}
ok = TRUE;
}
if (param.HasOptionalField(H245_H2250LogicalChannelParameters::e_dynamicRTPPayloadType))
channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
if (ok)
return TRUE;
PTRACE(1, "RTP_UDP\tNo mediaChannel or mediaControlChannel specified for " << channel);
errorCode = H245_OpenLogicalChannelReject_cause::e_unspecified;
return FALSE;
}
BOOL H323_RTP_UDP::OnReceivedAckPDU(H323_RTPChannel & channel,
const H245_H2250LogicalChannelAckParameters & param)
{
if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_sessionID)) {
PTRACE(1, "RTP_UDP\tNo session specified");
}
if (param.m_sessionID != rtp.GetSessionID()) {
PTRACE(1, "RTP_UDP\tAck for invalid session: " << param.m_sessionID);
}
if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaControlChannel)) {
PTRACE(1, "RTP_UDP\tNo mediaControlChannel specified");
return FALSE;
}
unsigned errorCode;
if (!ExtractTransport(param.m_mediaControlChannel, FALSE, errorCode))
return FALSE;
if (!param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_mediaChannel)) {
PTRACE(1, "RTP_UDP\tNo mediaChannel specified");
return FALSE;
}
if (!ExtractTransport(param.m_mediaChannel, TRUE, errorCode))
return FALSE;
if (param.HasOptionalField(H245_H2250LogicalChannelAckParameters::e_dynamicRTPPayloadType))
channel.SetDynamicRTPPayloadType(param.m_dynamicRTPPayloadType);
return TRUE;
}
void H323_RTP_UDP::OnSendRasInfo(H225_RTPSession & info)
{
info.m_sessionId = rtp.GetSessionID();
info.m_ssrc = rtp.GetSyncSourceOut();
info.m_cname = rtp.GetCanonicalName();
const H323Transport & transport = connection.GetControlChannel();
transport.SetUpTransportPDU(info.m_rtpAddress.m_recvAddress, rtp.GetLocalDataPort());
H323TransportAddress ta1(rtp.GetRemoteAddress(), rtp.GetRemoteDataPort());
ta1.SetPDU(info.m_rtpAddress.m_sendAddress);
transport.SetUpTransportPDU(info.m_rtcpAddress.m_recvAddress, rtp.GetLocalControlPort());
H323TransportAddress ta2(rtp.GetRemoteAddress(), rtp.GetRemoteDataPort());
ta2.SetPDU(info.m_rtcpAddress.m_sendAddress);
}
/////////////////////////////////////////////////////////////////////////////