At the heart of the code is the RTPSession object. It provides handles to all the other data structures used internally, namely the RTP receiver thread, the database of participants, the thread that calls the application when new data is available, and the associated RTCP session. Developers that want to use this library should only have to know about 1) the RTPSession object and associated methods, 2) a subset of the Participant object, 3) the DataFrame object, and 4) implement the callback interface RtpAppIntf.
Attempts have been made to maintain a relatively small footprint. Therefore the library only includes code from the standard Java libraries provided by Sun Microsystems. The only exception is the JDOM parser, used in the XML demonstration applications, but most people will not use this anyway. To run applications using jlibrtp one needs the Sun Microsystems Java Runtime Environment version 1.5.0 or newer. The code does not rely on any features that are specific to any platform and is written entirely in Java.
It is somewhat difficult to implement RTP in Java. The language does not support unsigned integers, which RTP uses lots of. Instead 64 bit longs are used internally, which are converted to byte-arrays before transmission.
The RTPSession object handles the sending of data synchronously. The idea is that packets should be spaced out, in time, as much as possible. On the receiving end there is a single thread listening on the specified UDP port or multicast group. Once a packet is received it is parsed, a number of tests applied and then put into the packet buffer of the corresponding participant. The receiver thread is then blocked until the next packet arrives.
The packet buffer is a linked list. It (optionally) reorders packets that arrive out of order and can (optionally) recombine multiple packets into frames based on sequence numbers. A separate thread, called the AppCallerThread, is signaled every time a packet is added to a buffer. It then loops over all the participants that we expect to receive packets from and calls the receiveData() method, which is implemented by the application. This call is also synchronous by design, but can easily be made asynchronous by the application developer.
The participant database is implemented as one hashtables, keyed by SSRC, and a linked list containing unicast receivers. In unicast sessions, unknown senders are created in cases where we receive packets from sources that the application for some reason has not added as participants. Attempts are made to match participants, which the application adds later, to the unknown senders based on ip address. Note that a unicast participant will live in both the hashtable and the list if (s)he is both a recipient and a sender. In multicast sessions the list is not used.
The application developer specifies whether packets from unknown sources should be rejected, which is the default in unicast sessions, or handed to the application.
RTCP is optional and will not be used if the participant does not provide a valid socket for RTCP when the application initializes the session.
Most of the data structures are held on the RTCPSession object. When the session starts, which happens when the callback interface is registered, two separate threads are launched.
The RTCP receiver thread spends most of the time blocked by the socket, waiting for the next RTCP packet. When one arrives, the compound packet is parsed and the individual RTCP packets decoded. Each packet type is represented by a unique clas, but they are all subclasses of RtcpPkt. SDES packets automatically update the participant database, all other packets are examined in a separate step. If the application has registered a RTCPAppIntf (RTCP callback interface) then it is notified also.
The RTCP sender thread loops over the participant database, determines the types of RTCP messages that are appropriate and assembles a compound packet. Application specific packets are held in a queue and included in the next RTCP packet going to that participant. When the packet has been sent the delay until the RTCP packet is calculated, and the thread then goes to to sleep for that amount of time.
If RFC 4585 is used by the application then it has the opportunity to wake up the sleeping RTCP sender thread. The thread will accept the feedback packet and perform the calculations to determine when this packet can be sent. The operation is asynchronous, but should be reasonably fast if the system is not overloaded.
Return to jlibrtp report.