RTP monitoring project.
  • C++ 88.7%
  • CMake 4.9%
  • Dockerfile 2.9%
  • C 1.8%
  • Shell 1.7%
Find a file
2021-09-16 20:31:16 +02:00
src Enabled SO_REUSEADDR on multicast listening socket 2021-09-16 20:30:49 +02:00
.dockerignore Implemented out of order logging 2021-02-09 11:45:23 +01:00
.gitignore Lots of changes. 2019-09-04 13:38:53 +02:00
.gitlab-ci.yml Disabled gitlab CI/CD build 2021-09-16 20:31:16 +02:00
build.sh Commented out counter wrap logging. Added armv7 build target 2021-08-25 13:14:56 +02:00
CMakeLists.txt Fixed logging. Fixed code warnings. Updated build script 2021-08-25 10:10:55 +02:00
config.dist.ini Added configuration. Added statsd stats. 2018-02-14 16:12:41 +01:00
Dockerfile Minor changes 2021-09-09 21:35:50 +02:00
README.md Implemented out of order logging 2021-02-09 11:45:23 +01:00

RTP monitor

This project contains code to monitor RTP multicast streams. Currently it compiles on both MacOS and Linux. On Linux, the binary will be statically linked to make redistribution between different distribution versions and such easier.

Purpose

When you're running an IPTV platform and distribute IPTV streams over multicast, at some point you're going to want to monitor loss on such streams in various parts of your network. When you're using RTP streams, this tool is useful for monitoring such loss.

Loss is measured by comparing the sequence numbers in the RTP headers. For each packet read, it registers the current RTP sequence number. If in the following packet, the sequence number is not previous+1, it is considered lost. The RTP sequence number is actually a 16 bit counter. Usually, the counter wraps within a minute and if that happens, it won't be considered as a lost packet.

The loss statistics will be sent to the configured statsd host.

Building rtpmon

Install cmake if not installed yet. Then run the following commands:

cmake .
cmake --build .

External dependencies

The following libraries need to be installed in order to build rtpmon:

  • libev version 4.22 or higher
  • boost version 1.62 or higher
  • log4cpp version 1.1.2 or higher

Other code

In this code, external code has been included:

Configuration file format

rtpmon uses an ini configuration file to read the configuration from. Example:

[network]
interface=eth0
; Also possible:
;interface=1.2.3.4

[statsd]
host=192.168.0.1
port=8125
ident=rtphost.

[groups]
224.0.252.129:7258=discovery_channel
224.0.251.105:8210=national_geographic

Configuration items explained:

  • network.interface: the interface name or IP address on which the multicast group joins need to be done.
  • statsd.host: the statsd host to send the stats to
  • statsd.port: the statsd port to send the stats to (only udp!)
  • stats.ident: will be prepended to the statsd key.
  • groups.mcastip:port: a list of multicast group addresses and the statsd identifier.

Statsd

As indicated in the previous paragraphs, stats will be sent to a statsd host. When loss occurs, a UDP statsd packet will be sent to the configured host and port.

For example, when loss occurs on a group identified by 'discovery_channel' as in the example configuration and the statsd ident is set to 'rtphost.', the amount of lost packets will be sent as:

rtphost.discovery_channel:50|c

So, rtpmon sends the stats as a counter.

Known bugs and limitations

Losing packets at startup

rtpmon first joins all configured groups, and then stats the libev event loop. As the group joining process takes some time, some packets may be considered lost in the startup phase.

Single threadedness

The amount of streams monitored is highly dependent on the CPU power. rtpmon is a single threaded process and so all data is read in one thread.

I've run the process on an 1.6 GHz Atoms processor with about 50 Mbits of multicast traffic and the CPU usage was below 40%.

In a later version I may split up the group joins in different processes or threads.

Apologies

In no way I consider myself a C++ programmer. Before this project I created a Python version which hit the CPU limit with less than 50 Mbit of multicast streams. So I needed the performance and decided it'd be a good idea to get up to speed with C++ and build this project with it.

So my apologies if this code contains anti-patterns or stupidities otherwise. I welcome any patches.