![]() |
How to use the OpenH323
ExternalRTP interface Craig Southeren Last updated 27 September 2004 |
| Introduction | |
| Overview | |
| Making a fastStart call | |
| Making a slowStart call | |
| Receiving an incoming call | |
| Implementing an external RTP handler | |
| Other notes | |
| Change history |
OpenH323 is normally used with it's own internal RTP stack implementation to create a self-contained H.323 endpoint. For applications that require the use of an external RTP device, OpenH323 provides the ability to use an ExternalRTP handler.
The actions necessary to create an ExternalRTP handler are fairly simple, but the interactions with fastStart and slowStart media modes are not obvious. This document seeks to document some of these interactions in order to assist people in creating software that uses the ExternalRTP handler interface.
This document assumes a reasonable knowledge of OpenH323, of H.323 and of C++ principles.
The virtual function H323Connection::CreateRealTimeLogicalChannel is called when ever OpenH323 needs to create an RTP session for a H323Connection, regardless of whether the RTP session is implemented by the internal stack or by an external handler. By default, this function will create an RTP session that uses the internal stack, but by overriding this function and returning a descendant of the H323_ExternalRTPChannel class, other types of RTP devices can be easily used. The main reference to date for this has been the documentation associated with this function in the file h323con.h, but these notes are rather sketchy and does not explain all of the details for a complete interface.
The most important detail that is omitted from these notes is that separate RTP sessions are created for each outgoing and incoming stream of data. This is necessary as it each direction is completely independent of the other, and may use different IP addresses, ports and payload codes.
It is helpful to understand how H.323 handles RTP sessions before showing an example of how to use the ExternalRTP handler interface. In particular, the differences in the way RTP sessions are created for slowStart and fastStart connections is very informative, and can help avoid some of the common mistakes and misconceptions in using this interface.
When a terminal makes a call with H.323 fastStart enabled, it will offer multiple capabilities or codecs to the remote endpoint in the SETUP PDU. In order to create these capabilities, the H323Connection::CreateRealTimeLogicalChannel function is called once for each outgoing RTP session that is to be offered. Each call to CreateRealTimeLogicalChannel will be passed the capability information, from which information such as the codec type and RTP payload code can be extracted.
The object instance returned by CreateRealTimeLogicalChannel is descended from the H323_ExternalRTPChannel class, and must have the the IP address and port to be used for the local end of the RTP connection defined using the H323_ExternalRTPChannel::SetExternalAddress function before CreateRealTimeLogicalChannel returns. This is required so that the outgoing capability contain the correct address and port information.
The called endpoint receives a list of fastStart capabilities, and then replies with a fastStart acknowledge that identifies which capability was accepted. This acknowledge will contain the IP address and port of the remote RTP session. Upon receipt of this information, the calling endpoint create a new RTP session corresponding to the incoming RTP stream. All of the outgoing RTP sessions that are no longer needed will be deleted, leaving one RTP session that corresponds to the accepted capability.
The documentation in h323ep.cxx indicates that the H323Connection::OnStartLogicalChannel virtual function can be used to extract the IP address and port of the remote endpoint. While this is true, a more useful function is the Start() virtual function on the H323_ExternalRTPChannel descendant itself. This allows the code associated with handling the remote address to be kept within the new class. Regardless of which method is used, the external IP address and port can be obtained at this time by calling the H323_ExternalRTPChannel::GetRemoteAddress function.
Once the acknowledge has been processed, the active RTP sessions will exist until the call ends, at which time they are deleted.
To summarise, this is what happens during a fastStart call
H323Connection::MakeCall is called
MyExternalRTPChannel constructor is called for first capability
MyExternalRTPChannel constructor is called for 2nd capabilityMyExternalRTPChannel constructor is called for 3rd capability
MyExternalRTPChannel constructor is called for 4th capability
....
MyExternalRTPChannel constructor is called for last capability
FastStart request sent to remote terminal in SETUPFastStart response received from remote terminal (probably in CONNECT)
MyExternalRTPChannel destructor called for 1st unused outgoing session
MyExternalRTPChannel destructor called for 2nd unused outgoing session
MyExternalRTPChannel destructor called for 3rd unused outgoing session
.....
MyExternalRTPChannel destructor called for last unused outgoing sessionMyExternalRTPChannel constructor is called to create incoming session
The remote IP addresses and ports are set in the incoming and outgoing sessions
MyExternalRTPChannel::Start is called on the incoming and outgoing sessions
Call continues
Call is stopped
MyExternalRTPChannel destructor called for the incoming and outgoing sessions
A slowStart call is completely different from fastStart, and is much simpler, because capabilities are negotiated before an RTP session needs to be created. The call flow looks like this:
H323Connection::MakeCall is called
Both terminals negotiate a capability by exchanging TCS messages
MyExternalRTPChannel constructor is called to create the outgoing session
MyExternalRTPChannel constructor is called to create the incoming session
The remote IP addresses and ports are set in the incoming and outgoing sessions
MyExternalRTPChannel::Start is called on the incoming and outgoing session
Call continues
Call is stoppedMyExternalRTPChannel destructor called for the incoming and outgoing sessions
An incoming call (slowStart or fastStart) is identical, and much the same as making a slowStart call, because the endpoint has all of the information it needs to create the RTP sessions:
The call flow looks like this:
H323Connection::OnIncomingCall is called
Both terminals negotiate a capability by exchanging TCS messages
MyExternalRTPChannel constructor is called to create the outgoing session
MyExternalRTPChannel constructor is called to create the incoming session
The remote IP addresses and ports are set in the incoming and outgoing sessions
MyExternalRTPChannel::Start is called on the incoming and outgoing session
Call continues
Call is stoppedMyExternalRTPChannel destructor called for the incoming and outgoing sessions
The first step to using the ExternalRTP handler is to declare a descendant of H323_ExternalRTPChannel as follows:
class MyRTPChannel : public H323_ExternalRTPChannel
{
public:
MyRTPChannel(
const H323Capability & capability,
Directions direction,
unsigned id
)
{
// set the local RTP address and port
PIPSocket::Address addr = local RTP address;
WORD port = local RTP port;
SetExternalAddress(H323TransportAddress(addr, port), H323TransportAddress(addr, port+1));
// get the payload code
OpalMediaFormat format(capability->GetFormatName(), FALSE);
BYTE payloadCode = format.GetPayloadType();
}BOOL Start()
{
// call ancestor always
if (!H323_ExternalRTPChannel::Start())
return FALSE;
// get the remote RTP address and port
PIPSocket::Address addr;
WORD port;
GetRemoteAddress(addr, port);
....do something with remote address here
}protected:
BYTE payloadCode;
};
The next step is to declare the appropriate override of CreateRealTimeLogicalChannel in the H323Connection descendant so that is creates and returns the appropriate ExternalRTP instance;
class MyH323Connection : public H323Connection
{
public:
....
H323Channel * CreateRealTimeLogicalChannel(
const H323Capability & capability,
H323Channel::Directions dir,
unsigned sessionID,
const H245_H2250LogicalChannelParameters * param,
RTP_QOS * rtpqos
}
(
return new MyRTPChannel(*this, capability, dir, sessionID);
)
);
Note that the declaration of the H323Connection::CreateRealTimeLogicalChannel function changed with the introduction of the RTP QoS code in October 2003, which corresponds to OpenH323 v1.13.0 and later. Prior to this version, the rtpqos parameter was not present.
Video
If video is also being used, then the entire process described is duplicated in parallel with the video capabilities, leaving four RTP sessions remaining for the duration of the call. It is also possible that audio may start using the fastStart procedure, while video starts using the slowStart procedure, even within the same call.
Threading
Due to the multi-threaded nature of OpenH323, the functions described above may be called by different threads even during the same call, although the order will be correct.
| 27 September 2004 | Craig Southeren | Added note on change of parameters to the CreateRealTimeLogicalChannel function |
| 6 August 2004 | Craig Southeren | Initial version |
Copyright © 2003-2007 by Post Increment
A.B.N 95 856 785 279
All Rights Reserved
All trademarks and copyrights on this page are owned by their respective owners.