The product is a library that implements the Real-Time Transport Protocol (RTP), a well-established standard for streaming media across IP-based networks, in Java. The purpose of this library is to make it easy for application developers to create applications for peer to peer streaming of audio, video and other data. In addition, developers will need a protocol to establish contact with peers, such as the Session Initialization Protocol (SIP).
The library accepts any kind of binary data in bytes. The code can handle packet parsing and reordering, maintains a participant database and the control connection (RTCP) associated with the protocol. The application is notified of received data through a callback-interface. The library supports IPv4, IPv6 and multicast. It does currently not support encryption, and should not be used in cases where confidentiality is important.
The work described in this report, as well as the the report itself, is based on work that I did in collaboration with Vaishnav Janardhan in the fall semester in 2006 for Prof. Schulzrinne's class VoIP Security. In this project I have replaced all the RTCP code and greatly improved upon it, fixed bugs, provided better callback interfaces and implemented a profile with feedback. Every aspect of the library has been completely documented using JavaDoc.
Jlibrtp implements the Real-time Transport Protocol (RTP, RFC 3550)[1] and partially Real-time Transport Control Protocol with RTCP-Based Feedback (RFC 4585)[2]. It is an alternative to the RTP stack provided by Sun Microsystems (R) in the Java Media Framework (JMF)[3], the difference is that it attempts to provide application developers with a much simpler application programming interface (API).
To use jlibrtp, developers must instantiate a copy of the RTPSession class and provide a class that implements the callback interface RTPAppIntf. The RTPSession object is a container for the data structures required by the library, and starts the threads used for receiving and parsing packets. The program can use simple methods to add peers, participants that send or receive packets, to the session. The callback interface is called whenever the stack has data ready for the application, and it is up to the developer to decide what to do with the binary data.
The code is licensed under the GNU Lesser General Public License (LGPL) [4], developers are therefore free to change functionality or provide a richer API if the current implementation does not meet their needs.
The Java Media Framework provides much of the same functionality as jlibrtp, but requires the application developer to do considerably more work and the code cannot easily be modified to accommodate special needs.
There are several RTP stacks available in C and C++, including GNU Telephony's ccRTP[5], but these are generally not of interest for Java developers because the cross-platform capabilities are lost when integrating such code.
RTP is often used to refer to both the data (RTP packets) and the associated signaling protocol, RTCP (Real-Time Transport Control Protocol). Less sophisticated applications are generally only concerned with the data. RTCP provides functionality to monitor the flow of data and generates statistics for both senders and receivers. This information can be used to limit the bandwidth used, by detecting the loss of packets. Clients could for example switch to a more compact encoding scheme so that everyone in a session is able to keep up.
The two sub-protocols operate on separate UDP ports (uni- or multicast), both of which must be communicated to peers through a medium like SIP (Session Initialization Protocol).
For readability the documentation of the architecture has been moved into a separate document.
Please refer to the automatically generated JavaDocs for the complete documentation of the library.
The API for regular "end-developers", those who do not intend to tinker with jlibrtp, consists only of the public objects and methods. A set of JavaDocs excluding protected items can be found here, to make it easier for beginners.
The library is bundled with six small applications for demonstration purposes. Users are encouraged to open and modify the mentioned programs. Certain parameters (such as audio-format) have been hardcoded intentionally to limit the number of parameters (and sources of confusion) that are needed. Running the program without any parameters explains the required parameters.
The simplest programs are validateCcrtp.CCRTPReceiver and validateCcrtp.CCRTPSender. Their original purpose was to test communication with equivalent programs bundled with ccRTP. The first one will simply print the contents of received RTP packets, whereas the latter accepts an input string and an integer that describes how many times the string should be transmitted. RTCP is enabled in these sessions.
For testing sound you need to either to have 8 kHz, 16 bit PCM Unsigned, mono file or changed the source code. Note that Java may lock the audio device, meaning that you can only run the sender or the receiver application on that machine. The sender uses the an audio output line to time the transmission of packets, tests have shown that pausing the thread is not sufficiently accurate to do this.
The biggest applications are the XML Packet Recorder and XML Packet Player. They rely on JDOM[6] to handle the XML and produce documents that can be opened in almost any webbrowser. The actual data in the RTP packets is saved in hex and these tools can be useful for debugging purposes, both when it comes to jlibrtp and other applications. Note that, when playing the XML file, all packets are sent to a single destination. The player will transmit the packet with approximately the same spacing as they were received with.
I wrote simple test programs to evaluate the performance of the library and the Java virtual machine on my 2.0 GHz Core 2 Duo, running Linux 2.6.20 (32 bit).
One test was to simply encode and transmit a string of 160 bytes 100 000 to the local loopback interface. This took between 1250 and 1420 ms, yielding a throughput of 91 mbps. Quadrupling the payload size to 640 bytes only increases the running time to 2000 ms, providing 256 mbps. While these numbers cannot be assumed to be accurate, they strongly suggest that jlibrtp's performance will be sufficient for many applications.
Since it was difficult to measure the decoding of packets using a real application I calculated packet parsing separately. Decoding a 640 byte packet 100 000 times completed consistently in less than 125 ms. This result, implying approximately 4 Gbps, made me very suspicious, but the results appear to be correct. Encoding takes about the same amount of time. It is technically feasible, since in either case the bulk of the work is done single System.arraycopy(), the equivalent of a memcpy.
It is difficult to test interoperability, especially with commercial offerings, without a complete program that understands how to establish sessions and decode data. My tests have therefore consisted of recording sessions between Ekiga and Linphone clients and replaying them towards jlibrtp. While this is inconclusive, it suggests that jlibrtp is at least capable of handling incoming packets correctly.
Using the demonstration programs bundled with ccRTP, and creating equivalent samples for jlibrtp, I have verified that these two stacks work well together. The tests are bidirectional and include the most commonly encountered RTCP packets (SR, RR, SDES and BYE).
For the same reason, that it is difficult to create realistic tests without a complete application, the feedback profile remains largely untested at this point.
The soundSender and soundReceiver demo programs were initially based on "Java play WAV sound file", a tutorial on AnyExample.com[7]. Except for this, all code is original work written by me.