Skip to content
Snippets Groups Projects
Commit aa4a4ec1 authored by Martyn Welch's avatar Martyn Welch Committed by Emanuele Aina
Browse files

Remove traffic control page


The tool described for traffic control, tcmmd, hasn't been available in
Apertis since before v2019. This page therefore describes functionality
which is no longer provided in Apertis, remove it.

Signed-off-by: default avatarMartyn Welch <martyn.welch@collabora.com>
parent 49507c40
No related branches found
No related tags found
1 merge request!39Wip/martyn/website updates
+++
date = "2018-06-06"
weight = 100
title = "Traffic Control"
aliases = [
"/old-wiki/Docs/traffic-control"
]
+++
Traffic control is a technique to control network traffic in order to
optimize or guarantee performance, low-latency, and/or bandwidth.
Apertis includes the daemon **tcmmd** and a demo GStreamer application
**tcdemo**. They show how traffic control helps a multimedia application
can get enough bandwidth for its purpose when competiting with other
downloads.
Ref. chapter 2.11, 3.10 in Multimedia design
# The sources
The [first publicly available version of tcmmd and
tcdemo](http://alban-apinc.blogspot.co.uk/2014/02/traffic-control-for-multimedia-devices.html)
is 0.1.10. The current version of tcmmd and tcdemo in Apertis is 0.1.12.
The [code](https://github.com/alban/tcmmd) is available in git:
`git clone git@github.com:alban/tcmmd.git`
# Test cases
[QA/Test
Cases/traffic-control-tcmmd]( {{< ref "/qa/test_cases/traffic-control-tcmmd.md" >}} )
# How to use it in an application
A multimedia application rendering streamed content wishing to benefit
from traffic control needs to:
- Get the 5-tuple identifying the connection and send it to tcmmd
- Monitor the usage of its downloading queue in the pipeline and
notify tcmmd
The
[tcdemo.c](http://cgit.collabora.com/git/user/alban/tcmmd.git/tree/src/tcdemo.c?id=tcmmd-0.1.10)
can be taken as an example doing this.
## Identify the connection
The application needs to get:
1. the IP source (the same IP visible with the command ifconfig on the
correct interface)
2. the IP destination (the IP of the web server)
3. the TCP source port (usually chosen randomly by the kernel)
4. the TCP destination port (likely to be 80 for http)
The TCP source port is probably the most difficult to get. With the
low-level socket API, there is two different ways to do this:
1. The application can call bind(2) before connect(2) to choose a TCP
source port. This solution allows to install the traffic control
rules before the call to connect(2) triggers the emission and
reception of the first packets on the network. It is a more
difficult solution because it involves more invasive changes in
GStreamer and libsoup.
2. The application can call getsockname(2) after connect(2) to retrieve
the TCP source port assigned automatically by the kernel. This
solution means the first few packets will be exchanged without being
shaped by the traffic control but it does not have a big impact.
Tcdemo implements this solution to avoid more invasive changes in
the souphttpsrc GStreamer element and libsoup. See
[bgo\#721807](https://bugzilla.gnome.org/show_bug.cgi?id=721807).
In an application using GStreamer and libsoup, there are no needs to use
the low-level socket API (bind, connect, getsockname, etc.).
The change in GStreamer adds a "soup-socket" property on the source
GstElement.
- Find the souphttpsrc element:
<code>
`static void`
`source_setup_cb (GstElement *playbin,`
` GstElement *source,`
` DemoData *self);`
`...`
`gint`
`main (gint argc,`
` gchar *argv[])`
`{`
` ...`
` playbin = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (player));`
` g_signal_connect (playbin, "source-setup",`
` G_CALLBACK (source_setup_cb), &self);`
</code>
- Receive notifications for SoupSocket changes:
<code>
`static void`
`update_soup_socket (DemoData *self);`
`...`
`static void`
`source_setup_cb (GstElement *playbin,`
` GstElement *source,`
` DemoData *self)`
`{`
` ...`
` /* Watch the SoupSocket on which current trafic is done */`
` g_signal_connect_swapped (self->source, "notify::soup-socket",`
` G_CALLBACK (update_soup_socket), self);`
</code>
- Get the SoupSocket
<code>
`static void`
`update_soup_socket (DemoData *self)`
`{`
` SoupSocket *socket;`
` g_object_get (self->source, "soup-socket", &socket, NULL);`
</code>
- Get the socket information: IP source/destination, TCP
source/destination port
<code>
` SoupAddress *local_address;`
` SoupAddress *remote_address;`
` local_address = soup_socket_get_local_address (self->socket);`
` remote_address = soup_socket_get_remote_address (self->socket);`
` soup_address_get_physical (local_address);`
` soup_address_get_port (local_address);`
` soup_address_get_physical (remote_address);`
` soup_address_get_port (remote_address);`
</code>
## Monitor the downloading queue
We use ClutterGstPlayback to wrap the GStreamer pipeline in a Clutter
widget. The pipeline contains a GstQueue2 which already emits a
GstMessage of type GST_MESSAGE_BUFFERING on the GStreamer bus. That
message is forwarded by the ClutterGstPlayback object so we can just get
the notification with:
<code>
`ClutterGstPlayback *player;`
`...`
`player = clutter_gst_playback_new ();`
`...`
`g_signal_connect (player, "notify::buffer-fill",`
` G_CALLBACK (buffer_fill_notify_cb), &self);`
</code>
The callback can get the buffer_fill value between 0.0 (0%) and 1.0
(100%):
<code>
`static void`
`buffer_fill_notify_cb (ClutterGstPlayer *player,`
` GParamSpec *param_spec,`
` DemoData *self)`
`{`
` gdouble buffer_fill;`
` g_object_get (player, "buffer-fill", &buffer_fill, NULL);`
</code>
However, after the initial buffering, by default, the notifications get
sent only when the value drops to lower than 10%
([low-percent](http://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-queue2.html#GstQueue2--low-percent)).
Below 10%, the GStreamer queue is almost empty, so this is almost too
late for tcmmd to change the traffic control rules. In order to get
notified sooner, tcdemo changes the low-percent threshold on the
GstQueue2 element:
<code>
`g_object_set (element, "low-percent", 75, NULL);`
</code>
It is also possible to change other parameters on the GstQueue2 at the
same time if desired:
<code>
`g_object_set (element,`
` "low-percent", 75,`
` "max-size-bytes", 4194304,`
` "max-size-buffers", 200,`
` "max-size-time", G_GUINT64_CONSTANT(4000000000),`
` NULL);`
</code>
How to get the reference to the GstQueue2 is more difficult because
ClutterGstPlayback does not provide a direct API for that. Tcdemo
iterates over the GStreamer elements in the pipeline to find it:
<code>
`static void`
`_playbin_set_low_percent (GstBin *playbin)`
`{`
` GstIterator *it;`
` gboolean done;`
` GValue value = { 0, };`
` GstElement *element;`
` it = gst_bin_iterate_recurse (GST_BIN (playbin));`
` done = FALSE;`
` while (!done) {`
` switch (gst_iterator_next (it, &value)) {`
` case GST_ITERATOR_OK:`
` element = GST_ELEMENT (g_value_get_object (&value));`
` /* the pipeline has a GstMultiQueue but it seems GstQueue2 is the one`
` * used here. */`
` if (element &&`
` g_type_from_name ("GstQueue2") == G_TYPE_FROM_INSTANCE (element))`
` {`
` g_print ("- set low-percent on GstQueue2.\n");`
` g_object_set (element,`
` "low-percent", 75,`
` "max-size-bytes", 4194304,`
` "max-size-buffers", 200,`
` "max-size-time", G_GUINT64_CONSTANT(4000000000),`
` NULL);`
` }`
` g_value_unset (&value);`
` break;`
` case GST_ITERATOR_RESYNC:`
` gst_iterator_resync (it);`
` break;`
` case GST_ITERATOR_ERROR:`
` done = TRUE;`
` break;`
` case GST_ITERATOR_DONE:`
` done = TRUE;`
` break;`
` }`
` }`
` gst_iterator_free (it);`
`}`
</code>
It can be called like this:
<code>
`GstElement *playbin;`
`playbin = clutter_gst_player_get_pipeline (CLUTTER_GST_PLAYER (player));`
`_playbin_set_low_percent (GST_BIN (playbin));`
</code>
## Notify tcmmd
tcmmd implements a D-Bus interface defined in
[src/gdbus-tcmmd.xml](http://cgit.collabora.com/git/user/alban/tcmmd.git/tree/src/gdbus-tcmmd.xml?id=tcmmd-0.1.10).
Tcdemo calls two D-Bus methods:
<code>
<method name="SetPolicy">
` `<arg direction="in" type="s" name="src_ip"/>
` `<arg direction="in" type="u" name="src_port"/>
` `<arg direction="in" type="s" name="dest_ip"/>
` `<arg direction="in" type="u" name="dest_port"/>
` `<arg direction="in" type="u" name="bitrate"/>
` `<arg direction="in" type="d" name="buffer_fill"/>
</method>
<method name="UnsetPolicy">
</method>
</code>
Tcdemo uses GDBus and the code generated by gdbus-codegen from the xml
to keep a proxy on tcmmd's D-Bus object:
<code>
`static void`
`got_proxy_cb (GObject *source,`
` GAsyncResult *result,`
` gpointer user_data)`
`{`
` DemoData *self = user_data;`
` GError *error = NULL;`
` self->proxy = tcmmd_managed_connections_proxy_new_for_bus_finish (result,`
` &error);`
` ...`
`}`
`...`
`tcmmd_managed_connections_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,`
` G_DBUS_PROXY_FLAGS_NONE,`
` "org.tcmmd",`
` "/org/tcmmd/ManagedConnections",`
` NULL, got_proxy_cb, &self);`
</code>
SetPolicy is called as soon as the connection details are known from
libsoup:
<code>
` tcmmd_managed_connections_call_set_policy (self->proxy,`
` soup_address_get_physical (local_address),`
` soup_address_get_port (local_address),`
` soup_address_get_physical (remote_address),`
` soup_address_get_port (remote_address),`
` bitrate,`
` self->buffer_fill,`
` NULL, NULL, NULL);`
</code>
bitrate is not used by tcmmd and can be left to zero.
UnsetPolicy must be called when the SoupSocket is not used anymore in
order to remove the traffic control rules and let any traffic go freely:
<code>
`tcmmd_managed_connections_call_unset_policy (self->proxy, NULL, NULL, NULL);`
</code>
If tcdemo leaves the D-Bus system bus, tcdemo removes the traffic
control rules automatically.
# Known limitations
- tcmmd only works on one network interface at a time. It is a problem
with tethering. Also, it selects the interface when it starts and
does not handle interfaces going up and down.
- tcmmd only supports one stream connection at a time. It is a problem
if the user is watching two videos at the same time.
# Presentations
- Linux Plumbers 2014:
[presentation](http://www.linuxplumbersconf.org/2014/ocw/sessions/1923)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment