It was already mentioned in chapter five that RTP is a very useful protocol for transmitting real-time data. To make it easy to use RTP in several applications, I decided to write a library which provides the necessary functionality. This library was given the name JRTPLIB, which stands for ``Jori's RTP Library''. At the time of writing, the latest version of the library is version 2.3.
The RTP library is described in this chapter. First, I will explain what the library can do and then some implementation related issues are discussed. Finally, I will give some reactions of people when the library was made available on the World Wide Web.
The RTP library was made according to the specifications in [30]. It performs several necessary functions automatically, to make using RTP easier for the programmer. The library was written in C++ using an object-oriented approach.
Working with the library, you can easily select to which destinations data packets have to be sent. A destination can be either a unicast or a multicast address. Default values can be set up in case a lot of packets need the same parameters.
To be able to receive packets, you have to call a `poll' function periodically. This will make the library check for incoming RTP and RTCP packets, which are then processed. Functions are provided to be able to join and leave multicast groups. When you are in a multicast group, all packets which are sent to that group will be received1.
You can select one of three receive modes. The first mode simply accepts all incoming packets. The second receive mode accepts only packets coming from user-specified origins. Finally, the last mode accepts all packets except those coming from origins specified by the user.
The incoming RTP and RTCP packets are processed and the resulting information is stored per participant. To access this information you first have to select the appropriate participant. This can be done by either iterating over all participants until the right one is found or by selecting one using its SSRC identifier.
The RTCP protocol is handled entirely internally. Each time you send a RTP packet or poll for incoming packets, the library checks if it is time to send RTCP packets. The time at which RTCP information should be sent is calculated from the number of participants and from the maximum bandwidth RTCP data may occupy, as specified in [30]. As was already mentioned, when you poll for incoming data, any new RTCP packets are processed and the information is stored with the corresponding participant.
For certain events, the user can specify handlers which should be called by the library. A handler is a user-specified function. For example, a user could specify a function which the library should call when a new participant joins the session.
Finally, the user can set its own source description (SDES) information as well as the SDES information of contributing sources. The SDES information about another participant is stored with the other RTCP information about that participant.
The first versions of the library were tested on a Linux and a MS-Windows platform. When the library was made available through the World Wide Web I was able to add support for several other platforms, thanks to the help of many people. Currently, the library is known to work on the following platforms:
Normally, it should be possible to compile the library on other UNIX-like platforms too.
Like I already mentioned, the library was implemented in C++ using an object-oriented approach. In this section, I will first give an overview of the library's structure and next I will discuss some design decisions I made.
The Application Programming Interface (API) of the library consist of four parts:
The RTPSession class is the central part of the library. Through this class, the user can select destinations, send RTP packets, poll for incoming data etc. It also provides a mechanism to ask for information about a participant. This information is stored in an instance of the RTPSourceData class. Received packets are passed to the user as instances of the RTPPacket class. Finally, when an event handler is called, event related information is passed through an argument of the handler, which can be one of several structures.
The first version of the library was quite monolithic: almost all of the library's functionality was implemented in the RTPSession class. After completing the original version, I immediately started a new one, which has led to the current structure. Now, the library is much more modular. The RTPSession class uses several other classes to perform the necessary functions; it merely provides the links between the different components, without actually doing much by itself.
This design is a lot more object-oriented than the original one. This way, the structure of the library is better, the code is easier to read and the library can easily be extended.
The library is intended for the use of RTP in the TCP/IP architecture, so UDP is used to encapsulate the RTP packet. The network routines are implemented through the use of the Berkeley socket routines. These functions are available on most UNIX-like systems and also on MS-Windows platforms by using the WinSock library. Because I used these standard functions, the library can be used on a wide range of platforms.
Since the library is most likely to be used in real-time applications, I have tried to make the library as fast as possible. First of all, I have used hash-tables to store information that is likely to be consulted frequently. For example, the information about participants is stored this way. Also the list of destinations is stored using a hash-table. This allows the destination list to be adapted quickly. This is desirable for VoIP in virtual environments, where the destinations might change.
Calls to dynamically allocate memory are only done when absolutely necessary. For example, when you want to transmit data, a RTP header has to be attached to it. This means that some extra memory is needed. Instead of dynamically allocating it, I use a statically allocated buffer. The size of this buffer is set to the maximum size of an IP packet. The buffer is not declared in the send function, but in the appropriate class. This way, it only has to be created once.
I have also tried to make as little copies of data as possible. This is done by passing pointers to data instead of duplicating it. Finally, many functions are declared `inline', which also makes several functions perform better.
For some applications, it might be desirable to receive data as soon as it comes in. Now, to receive data, the poll function has to be called. But how do you know when to call this function? To solve this problem, you can retrieve the used socket descriptors from the library. This way, you can use these descriptors in a call to `select'2, which can inform you when data is available.
During the first implementation of the library, I have used the `rtpdump' utility to check if the library sent correct packets. The `rtpdump' program was written by H. Schulzrinne, one of the creators of RTP. I have also let several applications send data to each other to see if they were processed correctly. Later, the library has also been tested in the VoIP programs I wrote, where it seemed to be working fine.
At the end of December 1999, I made the library available to the public through the World Wide Web. To announce this, I sent an e-mail to the mailing list `rem-conf@es.net', where topics like VoIP are discussed. This mailing list was suggested by H. Schulzrinne, to whom I asked where I could best make the announcement.
Currently, several people are using the library. Thanks to their responses and suggestions, some improvements were made and the RTP library is now supported on many platforms. They also led to the removal of some bugs in the library.
To be able to give you an idea of what projects the library is being used in, I sent some e-mails to people who are using JRTPLIB, asking them what they were using the it for. Here are the responses I received:
To be able to easily use RTP in several applications, I wrote a library which provides RTP functionality. The library is called JRTPLIB, which stands for ``Jori's RTP Library''. It is written in C++ using an object-oriented approach.
The library makes it easier to send and receive RTP packets. The user can select any number of destinations for the data. Multicasting can be used for efficient distribution of the data. The RTCP functionality is completely handled internally.
The structure of the library is very modular, which makes the source code easy to understand and easily extensible. The Application Programming Interface (API) is relatively simple to use. The use of standard socket functions, makes the library usable on a wide variety of platforms. Several techniques are used to make the library as fast as possible, which is desirable for real-time applications.
After using the library for a while, I decided to make it available on the World Wide Web. This has helped me to improve the support for several platforms.