Developing multimedia applications with DCCP

DCCP GStreamer Plugin

GStreamer is a plugin-based framework, and each plugin contains elements. Each of these elements provides a specific function – such as encoding, displaying, or rendering data – as well as the ability to read from or write to files. By combining and linking those elements, the programmer can build a pipeline for performing more complex functions. For example, it is possible to create a pipeline for reading from an MP3 file, decoding its contents, and playing the MP3.

Figure 1 represents a GStreamer pipeline composed by three elements. Data flows from Element 1 to Element 2 and finally to Element 3. Element 1 is the source element, which is responsible for providing data to the pipeline, whereas Element 3 is responsible for consuming data from the pipeline. Between the source element and the sink element, the pipeline is permitted to use other elements, such as Element 2 (shown in Figure 1). These intermediary elements are responsible for processing and modifying the content as the data passes along the pipeline.

Figure 1: GStreamer Pipeline with three elements: a file reader, an MP3 encoder, and a DCCP transmitter.

We developed the DCCP plugin for GStreamer to deal with data transmission using the DCCP protocol. This plug-in has four elements: dccpserversrc, dccpserversink, dccpclientsrc, and dccpclientsink.

The source elements (dccpserversrc and dccpclientsrc) are responsible for reading data from a DCCP socket and pushing it into the pipeline, and the sink elements (dccpserversink and dccpclientsink) are responsible for receiving data from the pipeline and writing it to a DCCP socket.

The dccpserversrc and the dccpserversink elements behave as the server, but only dccpserversink can transmit and only dccpserversrc can receive data. When the server element is initialized, it stays in a wait mode, which means the plugin is able to accept a new connection from a client element. The dccpclientsink element can connect to dccp-serversrc, and dccpclientsrc can connect to dccpserversink.

If you want to send data from the server to the client, you need to use dccpclientsrc and dccpserversink elements. To send data from the client to server, you need to use the dccpclientsink and dccpserversrc elements.

GStreamer's gst-launch command supports the creation of pipelines, and it is also used to debug plugins.

The basic syntax is:

gst-launch <gst-launch parameters> <element> <element parameters> ! <element> <element parameters> ! <element> <element parameters> ...

Note the ! character that links the plug-in elements, which is similar to the character "|" in the Linux shell prompt. This means that the output of an element is the input to the next specified plugin element.

As an example of the gst-launch command, consider two pipelines to transmit an MP3 stream over the network with DCCP: One works as a DCCP server that streams an MP3 audio file, and the second pipeline is associated with a DCCP client that connects to the remote DCCP server and reproduces the audio content transmitted by the server.

To make the example work, you must install GStreamer. In this case, you need the GStreamer-Core, Gst-Base-Plugins, and Gst-Ugly-Plugins packages. Do not worry about the GStreamer installation; GStreamer is a widely used framework available in many Linux package systems for a variety of distributions, such as Debian, Gentoo, Mandriva, Red Hat, and Ubuntu. Once you perform the GStreamer installation, the last step is to compile and install the DCCP Plugin for GStreamer (see the box titled "Installing the GStreamer DCCP Plugin").

The following gst-launch example runs a server accepting DCCP connections. Once a client connects, the server starts to stream the audio file named yourmusic.mp3. Note that you can specify the CCID with the ccid parameter.

gst-launch -v filesrc location=yourmusic.mp3 ! mp3parse ! dccpserversink port=9011 ccid=2

This pipeline initializes the server in DCCP port 9011. The server will be waiting for a client to connect to it. When the connection occurs, the server starts to transmit the MP3 stream using CCID-2. The mp3parse element is responsible for transmitting a stream. To see more information about mp3parse and the other parameters that are available, run gst-inspect dccpserversink.

Next, start the corresponding client:

gst-launch -v dccpclientsrc host=localhost port=9011 ccid=2 ! decodebin ! alsasink

This GStreamer pipeline initializes the client and connects to the host localhost in port 9011. Once connected, the client starts to receive the MP3 stream, decodes the stream using the decodebin element, and pipes the stream to the alsasink element, which reproduces the multimedia content in the default audio output device.

Installing the GStreamer DCCP Plugin

The DCCP plugin for GStreamer is part of the DCCP and E-Phone project for the Nokia maemo platform [11]. After you have downloaded the plugin [12], run the following commands:

./autogen --prefix=/usr
make
make install

Multimedia Application

Now it is time to write a complete multimedia application using the DCCP plug-in. The next example is for readers who want to use a programming language and embed the DCCP plugin into their applications. I'll create the pipeline shown in the previous examples, but this time through the C programming language and GObject, a programming library available for GStreamer application and plugin development.

Start by initializing the GStreamer settings, as shown in Listing 3. Note that Listing 3 also defines GstElements filesrc, mp3parse, and dccpserversink.

The next step is to instantiate a bus callback function to listen to GStreamer pipeline events. A bus is a system that takes care of forwarding messages from the pipeline to the application. The idea is to set up a message handler on the bus that leads the application to control the pipeline when necessary. Put the function shown in Listing 4 above the main function defined in Listing 3.

Listing 3

Initializing (gst_dccp_server.c)

01  #include <string.h>
02  #include <math.h>
03  #include <gst/gst.h>
04
05 int main (int argc, char **argv) {
06      GMainLoop *loop;
07      GstElement *pipeline, *filesrc, *mp3parse, *dccpserversink;
08      GstBus *bus;
09
10     /* initialize GStreamer */
11      gst_init (&argc, &argv);
12      loop = g_main_loop_new (NULL, FALSE);
13
14     /* check input arguments */
15      if (argc != 3) {
16          g_print ("Usage: %s port mp3file_location\n", argv[0]);
17          return -1;
18      }
19      return 0;
20  }

Listing 4

GStreamer Bus (gst_dccp_server.c)

01 static gboolean bus_event_callback (GstBus *bus, GstMessage *msg, gpointer data){
02
03      GMainLoop *loop = (GMainLoop *) data;
04
05     switch (GST_MESSAGE_TYPE (msg)) {
06      case GST_MESSAGE_EOS:
07          g_print ("End-of-stream\n");
08          g_main_loop_quit (loop);
09          break;
10      case GST_MESSAGE_ERROR: {
11          gchar *debug;
12          GError *err;
13          gst_message_parse_error (msg, &err, &debug);
14          g_free (debug);
15          g_print ("Error: %s\n", err->message);
16          g_error_free (err);
17          g_main_loop_quit (loop);
18          break;
19      }
20      default:
21          break;
22      }
23
24     return TRUE;
25  }

Every time an event occurs in the pipeline, GStreamer calls the gboolean bus_call function. For example, if you implement a GUI interface for your application, you can show a message announcing the end of the stream or deactivate the GUI stop button when the type of the GStreamer bus message is GST_MESSAGE_EOS. Now comes the most important part of this example – defining the elements and building the GStreamer pipeline. Insert the code shown in Listing 5 into the main function (after checking the parameter count).

Listing 5

GStreamer Elements

01      /* defining elements */
02      pipeline = gst_pipeline_new ("dccp-audio-sender");
03      filesrc = gst_element_factory_make ("filesrc", "file-source");
04      mp3parse = gst_element_factory_make ("mp3parse", "mp3parse");
05      dccpserversink = gst_element_factory_make ("dccpserversink", "server-sink");

Listing 5 first instantiates a new pipeline, dccp-audio-sender, which can be used for future references in the code. Then the code instantiates the filesrc element with the name file-source. This element will be used to read the specified MP3 file as an argument of the application. Use the same process to instantiate the elements mp3parse and dccpserversink. Once all the necessary elements are instantiated, certify that all are properly loaded. For this case, proceed as shown in Listing 6.

Listing 6

Verifying Elements

01      if (!pipeline || !filesrc || !mp3parse || !dccpserversink) {
02          g_print ("One or more elements could not be instantiated\n");
03          return -1;
04      }

The next step is to set the respective element parameters, as shown in Listing 7. For this application, we need to set two parameters: the port, where the server will listen and accept client connection from, and the audio file path, represented by the parameter location.

Listing 7

Setting Parameters

01      g_object_set (G_OBJECT (dccpserversink), "port", atoi(argv[1]), NULL);
02      g_object_set (G_OBJECT (filesrc), "location", argv[2], NULL);

Once all the elements are instantiated and the parameters are defined, it is time to attach the bus callback defined in Listing 4 to the bus of the pipeline. Also, you need to add the elements to the pipeline and link them (Listing 8). Listing 9 shows how to execute the pipeline. Note that GStreamer runs in a main loop (line 5). This means that when this main loop finishes – for example, when the user types Ctrl+C – it is necessary to do some clean up (lines 9 and 11). The easiest part is to compile the server application – just run the following command, which will link the GStreamer libs with the example application:

gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) gst_dccp_server.c -o gst_dccp_server

To run the gst_dccp_server application, enter the following command:

./gst_dccp_server 9011 yourmusic.mp3

Note that the example uses port 9011, which the server will use to open the DCCP socket and transmit the stream through the network to the remote DCCP client.

Listing 8

Attaching bus_event_callback

01      bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
02      gst_bus_add_watch (bus, bus_event_callback, loop);
03      gst_object_unref (bus);
04
05     gst_bin_add_many (GST_BIN (pipeline), filesrc, mp3parse, dccpserversink, NULL);
06      /* Link the elements at the pipeline */
07      gst_element_link_many (filesrc, mp3parse, dccpserversink, NULL);

Listing 9

Executing the Pipeline

01      /* Now set to playing and iterate. */
02      g_print ("Setting to PLAYING\n");
03      gst_element_set_state (pipeline, GST_STATE_PLAYING);
04      g_print ("Running\n");
05      g_main_loop_run (loop); // start the GStreamer main loop
06
07     /* clean up nicely */
08      g_print ("Returned, stopping playback\n");
09      gst_element_set_state (pipeline, GST_STATE_NULL);
10      g_print ("Deleting pipeline\n");
11      gst_object_unref (GST_OBJECT (pipeline));

Now it is time to build a corresponding client application that acts just like the gst-launch client command discussed previously. The DCCP client application is similar to the server application (Listing 10). Basically, you must initialize GStreamer, check command-line parameters, instantiate the necessary elements, and link them to build the GStreamer pipeline.

Listing 10

DCCP Client Application

01  #include <string.h>
02  #include <math.h>
03  #include <gst/gst.h>
04
05 static gboolean bus_event_callback (GstBus *bus, GstMessage *msg, gpointer data){
06
07      GMainLoop *loop = (GMainLoop *) data;
08
09     switch (GST_MESSAGE_TYPE (msg)) {
10      case GST_MESSAGE_EOS:
11          g_print ("End-of-stream\n");
12          g_main_loop_quit (loop);
13          break;
14      case GST_MESSAGE_ERROR: {
15          gchar *debug;
16          GError *err;
17          gst_message_parse_error (msg, &err, &debug);
18          g_free (debug);
19          g_print ("Error: %s\n", err->message);
20          g_error_free (err);
21          g_main_loop_quit (loop);
22          break;
23      }
24      default:
25          break;
26      }
27
28     return TRUE;
29  }
30
31 int main (int argc, char *argv) {
32      GMainLoop *loop;
33      GstElement *pipeline, *dccpclientsrc, *decodebin, *alsasink;
34      GstBus *bus;
35
36     /* initialize GStreamer */
37      gst_init (&argc, &argv);
38      loop = g_main_loop_new (NULL, FALSE);
39
40     /* check input arguments */
41      if (argc != 3) {
42          g_print ("Usage: %s serverHost serverPort\n", argv[0]);
43          return -1;
44      }
45
46     /* create elements */
47      pipeline = gst_pipeline_new ("audio-sender");
48      dccpclientsrc = gst_element_factory_make ("dccpclientsrc", "client-source");
49      decodebin = gst_element_factory_make ("decodebin", "decodebin");
50      alsasink = gst_element_factory_make ("alsasink", "alsa-sink");
51
52     if (!pipeline || !alsasink || !decodebin || !dccpclientsrc) {
53          g_print ("One or more elements could not be instantiated\n");
54          return -1;
55      }
56
57     // set the host and the port where the server is listening
58      g_object_set (G_OBJECT (dccpclientsrc), "host", argv[1], NULL);
59      g_object_set (G_OBJECT (dccpclientsrc), "port", atoi(argv[2]), NULL);
60
61     /* put all elements in a bin */
62      gst_bin_add_many (GST_BIN (pipeline), dccpclientsrc, decodebin, alsasink, NULL);
63
64     gst_element_link_many (dccpclientsrc, decodebin, alsasink, NULL);
65
66     bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
67      gst_bus_add_watch (bus, bus_event_callback, loop);
68      gst_object_unref (bus);
69
70     /* Now set to playing and iterate. */
71      g_print ("Setting to PLAYING\n");
72      gst_element_set_state (pipeline, GST_STATE_PLAYING);
73      g_print ("Running\n");
74      g_main_loop_run (loop);
75
76     /* clean up nicely */
77      g_print ("Returned, stopping playback\n");
78      gst_element_set_state (pipeline, GST_STATE_NULL);
79      g_print ("Deleting pipeline\n");
80      gst_object_unref (GST_OBJECT (pipeline));
81
82     return 0;
83  }

Finally, to compile and run the client application, enter the following command:

gcc -Wall $(pkg-config --cflags --libs gstreamer-0.10) gst_dccp_client.c -o gst_dccp_client ./<applicationName> localhost 9011

Conclusion

I've presented the basic concepts of DCCP – how to enable DCCP in Linux, and how to build a DCCP-based application using the GStreamer DCCP plugin. Network analysis and testing applications, such as TTCP, tcpdump, and Wireshark already provide support for the DCCP protocol, and multimedia tools such as the open source VLC player accommodate DCCP streaming. As multimedia developers become aware of its benefits, you can expect to hear more about DCCP in the coming years.

Infos

  1. RFC 4340: Datagram Congestion Control Protocol (DCCP)
  2. Leandro M. Sales, Hyggo O. Almeida, Angelo Perkusich and Marcello Sales Jr: "On the Performance of TCP, UDP, and DCCP over 802.11g Networks." In Proceedings of the SAC 2008 23rd ACM Symposium on Applied Computing Fortaleza, CE, Brazil, pages 2074-2080, 1 2008.
  3. RFC 4341: "Profile for Datagram Congestion Control Protocol (DCCP) Congestion Control ID 2: TCP-like Congestion Control"
  4. RFC 4342: "Profile for Datagram Congestion Control Protocol (DCCP) Congestion Control ID 3: TCP-Friendly Rate Control (TFRC)"
  5. RFC 3448: "TCP Friendly Rate Control (TFRC): Protocol Specification"
  6. DCCP Git Repository: http://git://eden-feed.erg.abdn.ac.uk/dccp_exp
  7. DCCP on Linux wiki: http://www.linux-foundation.org/en/Net:DCCP
  8. Linux kernel documentation: http://www.kernel.org/doc/
  9. IPerf: http://www.erg.abdn.ac.uk/users/gerrit/dccp/apps/#iperf
  10. GStreamer: http://gstreamer.freedesktop.org/
  11. Maemo: http://www.maemo.org/
  12. DCCP plugin for GStreamer: https://garage.maemo.org/frs/?group_id=297

The Author

Leandro Melo de Sales has enjoyed Linux since 1997 and has contributed to DCCP in Linux since 2006, focusing mainly on embedded devices. He maintains DCCP for the Nokia maemo platform and is working on DCCP CCID-4 congestion control and a DCCP-based VoIP client. Leandro works at the Embedded Systems and Pervasive Computing Lab/UFCG, which is supported by Nokia Institute of Technology, Brazil. Thanks to the other authors who contributed: Angelo Perkusich, Arnaldo Carvalho, Erivaldo Xavier, Felipe Coutinho, Hyggo Almeida , Marcello Júnior, and Thiago Santos.

Read full article as PDF:

058-062_dccp.pdf  (789.27 kB)

Related content

  • Dotnet Scripting with Boo

    Boo is a scripting language tailor-made for Mono and .NET. This haunting mixture of Python and C# may be just what you need to get started with the .NET framework.

  • Perl: A Gaim Plugin

    The Gaim project offers an instant messenger client that speaks a large number of protocols. We’ll show you how to extend Gaim with Perl plugins.

  • Stable Clutter: GUI Library Achieves Version 1.0.0

    The Clutter project has made available version 1.0.0 of its user interface library. Clutter is not only the basis for the Moblin GUI, but the foundation for the upcoming GNOME 3.0 interface.

  • The Cloud's Role in HPC

    Cloud computing is most definitely here, but does it have a role in HPC? We discuss changes in HPC that could be solved effectively by cloud computing.

  • aKademy 2007

    Around 300 KDE developers met in Glasgow, Scotland, for this year’s aKademy KDE conference.

comments powered by Disqus

Direct Download

Read full article as PDF:

058-062_dccp.pdf  (789.27 kB)

News

njobs Europe
What:
Where:
Country:
Njobs Netherlands Njobs Deutschland Njobs United Kingdom Njobs Italia Njobs France Njobs Espana Njobs Poland
Njobs Austria Njobs Denmark Njobs Belgium Njobs Czech Republic Njobs Mexico Njobs India Njobs Colombia