This article focuses on setting up sipwise rtpegine to proxy rtp traffic from kamailio app server. This is an updated version of the the old article .
RTPengine is a proxy for RTP traffic and other UDP based media traffic over either IPv4 or IPv6. It can even bridge between diff IP networks and interfaces . It can do TOS/QoS field setting. It is Multi-threaded , can advertise different addresses for operation behind NAT.
It bears in-kernel packet forwarding for low-latency and low-CPU performance .
When used with kamailio RTP engine module it adds more features . I wrote an article covering all relevant and important kamailio modules earlier including RTPProxy and RTP engine ;https://telecom.altanai.com/2014/11/18/kamailio-modules/.
There are 3 parts of the source structure in sipwise NGCP ( Next Generation communication Platform) rtpengine :
The userspace daemon and workhorse, minimum requirement for anything to work. Running make will compile the binary, which will be called rtpengine.
Required packages including their development headers are required to compile the daemon:
options for make – with_iptables_option , with_transcoding
with_transcoding=no make
Required for in-kernel packet forwarding. With the iptables development headers installed, issuing make will compile the plugin for iptables and ip6tables. The file will be called libxt_RTPENGINE.so and needs to be copied into the xtables module directory. The location of this directory can be determined through pkg-config xtables –variable=xtlibdir on newer systems, and/or is usually either /lib/xtables/ or /usr/lib/x86_64-linux-gnu/xtables/.
Required for in-kernel packet forwarding. Compilation of the kernel module requires the kernel development headers to be installed in/lib/modules/$VERSION/build/, where $VERSION is the output of the command uname -r.
Successful compilation of the module will produce the file xt_RTPENGINE.ko. The module can be inserted into the running kernel manually through insmod xt_RTPENGINE.ko
It is recommended to copy the module into /lib/modules/$VERSION/updates/, followed by running depmod -a.
After this, the module can be loaded by issuing modprobe xt_RTPENGINE.
Follow instructions on https://gist.github.com/altanai/0d8cadbe6876d545fd63d6b3e79dcf73
Requirements
sudo su apt-get install debhelper iptables-dev libcurl4-openssl-dev libglib2.0-dev libjson-glib-dev libxmlrpc-core-c3-dev libhiredis-dev build-essential:native
for pcap
apt install ibpcap-dev
some ffmpeg pakages like
apt install libavcodec-dev libavfilter-dev libavformat-dev libavresample-dev libavutil-dev
for dpkg
libcrypt-openssl-rsa-perl libdigest-crc-perl libio-multiplex-perl libnet-interface-perl libsystemd-dev markdown
for debhelper>10
vi /etc/apt/sources.list
add line
deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse sudo apt update
check version
apt-cache policy debhelper dh-autoreconf
debhelper:
Installed: 9.20160115ubuntu3
Candidate: 9.20160115ubuntu3
Version table:
10.2.2ubuntu1~ubuntu16.04.1 100
100 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages
100 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages
*** 9.20160115ubuntu3 500
500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
100 /var/lib/dpkg/status
dh-autoreconf:
Installed: (none)
Candidate: 11
Version table:
12~ubuntu16.04.1 100
100 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages
100 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages
11 500
500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial/main amd64 Packages
Force installing the version from backports repo as it have low priority.
sudo apt install dh-autoreconf=12~ubuntu16.04.1 debhelper=10.2.2ubuntu1~ubuntu16.04.1
so now new priority will be
debhelper: Installed: 10.2.2ubuntu1~ubuntu16.04.1 Candidate: 10.2.2ubuntu1~ubuntu16.04.1 Version table: *** 10.2.2ubuntu1~ubuntu16.04.1 100 100 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages 100 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages 100 /var/lib/dpkg/status 9.20160115ubuntu3 500 500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial/main amd64 Packages dh-autoreconf: Installed: 12~ubuntu16.04.1 Candidate: 12~ubuntu16.04.1 Version table: *** 12~ubuntu16.04.1 100 100 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages 100 http://archive.ubuntu.com/ubuntu xenial-backports/main amd64 Packages 100 /var/lib/dpkg/status 11 500 500 http://us-east-1.ec2.archive.ubuntu.com/ubuntu xenial/main amd64 Packages ref :https://askubuntu.com/questions/863221/need-help-building-debhelper-10-2-2-bpo8-from-source
Get sourcecode
cd /usr/local/src git clone https://github.com/sipwise/rtpengine.git
cd rtpengine ./debian/flavors/no_ngcp
use dpkg-checkbuilddeps to find any missing dependices
For missing dependencies
dpkg-checkbuilddeps: error: Unmet build dependencies: libbcg729-dev
remove the encoder for G.729 which is not supported by ffmoeg by exporting varible
export DEB_BUILD_PROFILES="pkg.ngcp-rtpengine.nobcg729"
Ref :ref : https://github.com/sipwise/rtpengine#g729-support
for defaultlibmysqlclient-dev and libiptc-dev
vi debian/control
change from default-libmysqlclient-dev to libmysqlclient-dev, change from libiptcdata-dev to libiptc-dev and install the alternatives such as
apt install libmysqlclient-dev libiptcdata-dev
Generated deb files should be outside the rtpegine home folder
cd ..
dpkg -i ngcp-rtpengine-daemon_7.3.0.0+0~mr7.3.0.0_amd64.deb
dpkg -i ngcp-rtpengine-iptables_7.3.0.0+0~mr7.3.0.0_amd64.deb
dpkg -i ngcp-rtpengine-kernel-dkms_7.3.0.0+0~mr7.3.0.0_all.deb
dpkg -i ngcp-rtpengine-kernel-source_7.3.0.0+0~mr7.3.0.0_all.deb
dpkg -i ngcp-rtpengine-recording-daemon_7.3.0.0+0~mr7.3.0.0_amd64.deb
dpkg -i ngcp-rtpengine-utils_7.3.0.0+0~mr7.3.0.0_all.deb
dpkg -i ngcp-rtpengine_7.3.0.0+0~mr7.3.0.0_all.deb
Manual installation and running all test cases
cd rtpengine
make check
If you dont find a package you are looking for , some alternatives are to do apt-cache search like
apt-cache search libavfilter
libavfilter-dev - FFmpeg library containing media filters - development files
libavfilter-ffmpeg5 - FFmpeg library containing media filters - runtime files
or to search in ubuntu packages web https://packages.ubuntu.com/
rtpegine application options
rtpengine --interface="10.10.10.10" --listen-ng=25061 --listen-cli=25062 --foreground --log-stderr --listen-udp=25060 --listen-tcp=25060
To avoid the overhead involved in processing each individual RTP packet in userspace-only operation, especially as RTP traffic consists of many small packets at high rates, rtpengine provides a kernel module to offload the bulk of the packet forwarding duties from user space to kernel space. This also results in increasing the number of concurrent calls as CPU usage decreases.In-kernel packet forwarding is implemented as an iptables module (x_tables) and has 2 parts – xt_RTPENGINE and plugin to the iptables and ip6tables command-line utilities
Sequence of events for a newly established media stream is then:
The kernel module supports multiple forwarding tables, identified through their ID number , bydefault 0 to 63
Each running instance of the rtpengine daemon controls one such table. To load use
modprobe xt_RTPENGINE and to unload rmmod xt_RTPENGINE,. With the module loaded, a new directory will appear in /proc/, namely /proc/rtpengine/ , containing pseudo-files, control ( to create and delete forwarding tables) and list ( list of currently active forwarding tables)
To manually create a forwarding table with ID 33, the following command can be used:
echo ‘add 43’ > /proc/rtpengine/control
In order for the kernel module to be able to actually forward packets, an iptables rule must be set up to send packets into the module. Each such rule is associated with one forwarding table. In the simplest case, for forwarding table 33, this can be done through:
iptables -I INPUT -p udp -j RTPENGINE –id 33
To restrict the rules to the UDP port range used by rtpengine, e.g. by supplying a parameter like –dport 30000:40000. If the kernel module receives a packet that it doesn’t recognize as belonging to an active media stream, it will simply ignore it and hand it back to the network stack for normal processing.
A typical start-up sequence including in-kernel forwarding might look like this:
modprobe xt_RTPENGINE
iptables -I INPUT -p udp -j RTPENGINE --id 0
ip6tables -I INPUT -p udp -j RTPENGINE --id 0
ensure that the table we want to use doesn’t exist – usually needed after a daemon restart, otherwise will error
echo 'del 0' > /proc/rtpengine/control
start daemon
/usr/sbin/rtpengine --table=0 --interface=10.64.73.31 --interface=2001:db8::4f3:3d \
--listen-ng=127.0.0.1:2223 --tos=184 --pidfile=/run/rtpengine.pid --no-fallback
To run multiple instances of rtpengine on the same machine run multiple instances of the daemon using different command-line options ( local addresses and listening ports), together with multiple different kernel forwarding tables.
For example, if one local network interface has address 10.64.73.31 and another has address 192.168.65.73, then the start-up sequence might look like this:
modprobe xt_RTPENGINE iptables -I INPUT -p udp -d 10.64.73.31 -j RTPENGINE --id 0 iptables -I INPUT -p udp -d 192.168.65.73 -j RTPENGINE --id 1 echo 'del 0' > /proc/rtpengine/control echo 'del 1' > /proc/rtpengine/control
/usr/sbin/rtpengine --table=0 --interface=<ip> \ --listen-ng=127.0.0.1:2223 --tos=184 --pidfile=/run/rtpengine-10.pid --no-fallback /usr/sbin/rtpengine --table=1 --interface=<ip_pvy>\ --listen-ng=127.0.0.1:2224 --tos=184 --pidfile=/run/rtpengine-192.pid --no-fallback
With this setup, the SIP proxy can choose which instance of rtpengine to talk to and thus which local interface to use by sending its control messages to either port 2223 or port 2224.
Currently transcoding is supported for audio streams. Can we turned off with with_transcoding=no option in makeFile
Normally rtpengine leaves codec negotiation up to the clients involved in the call and does not interfere. In this case, if the clients fail to agree on a codec, the call will fail.
transcoding options in the ng control protocol, transcode or ptime . If a codec is requested via the transcode option that was not originally offered, transcoding will be engaged for that call. With transcoding active for a call, all unsupported codecs will be removed from the SDP.
Transcoding happens in userspace only, so in-kernel packet forwarding will not be available for transcoded codecs. Codecs that are supported by both sides will simply be passed through transparently (unless repacketization is active). In-kernel packet forwarding will still be available for these codecs.
codecs supported by rtpengine can be shown with –codecs options
advanced control protocol to pass SDP body from the SIP proxy to the rtpengine daemon, has the body rewritten in the daemon, and then pas back to the SIP proxy to embed into the SIP message. It is based on the bencode standard and runs over UDP transport.
Each message passed between the SIP proxy and the media proxy contains of two parts: message cookie ( to match requests to responses, and retransmission detection) and bencoded dictionary
The dictionary of each request must contain at least one key called command and corresponding value must be a string and determines the type of message. Currently the following commands are defined:
The response dictionary must contain at least one key called result. The value can be either ok (optional key warning) or error( to be accompanied by error-reason ). For the ping command, the additional value pong is allowed.
rtpengine.sample.conf
[rtpengine] table = 0 no-fallback = false for userspace forwarding only: table = -1 // separate multiple interfaces with semicolons: interface = internal/12.23.34.45;external/23.34.45.54 listen-ng = 127.0.0.1:2223 listen-tcp = 25060 listen-udp = 12222 timeout = 60 silent-timeout = 3600 tos = 184 control-tos = 184 delete-delay = 30 final-timeout = 10800 foreground = false pidfile = /run/ngcp-rtpengine-daemon.pid num-threads = 16 port-min = 30000 port-max = 40000 max-sessions = 5000 recording-dir = /var/spool/rtpengine recording-method = proc recording-format = raw redis = 127.0.0.1:6379/5 redis-write = password@x.x.x.x:6379/42 redis-num-threads = 8 no-redis-required = false redis-expires = 86400 redis-allowed-errors = -1 redis-disable-time = 10 redis-cmd-timeout = 0 redis-connect-timeout = 1000 b2b-url = http://127.0.0.1:8090/ xmlrpc-format = 0 log-level = 6 log-stderr = false log-facility = daemon log-facility-cdr = local0 log-facility-rtcp = local1 graphite = 127.0.0.1:9006 graphite-interval = 60 graphite-prefix = foobar. homer = 123.234.345.456:65432 homer-protocol = udp homer-id = 2001 sip-source = false dtls-passive = false
To start the ngcp-rtpengine-daemon service
/etc/init.d/ngcp-rtpengine-daemon start [ ok ] Starting ngcp-rtpengine-daemon (via systemctl): ngcp-rtpengine-daemon.service.
checking status ngcp-rtpengine-daemonservice
# systemctl status ngcp-rtpengine-daemon.service ● ngcp-rtpengine-daemon.service - NGCP RTP/media Proxy Daemon Loaded: loaded (/lib/systemd/system/ngcp-rtpengine-daemon.service; disabled; vendor preset: enabled) Active: active (running) since Thu 2019-04-11 10:16:20 UTC; 24s ago Process: 13751 ExecStopPost=/usr/sbin/ngcp-rtpengine-iptables-setup stop (code=exited, status=0/SUCCESS) Process: 13797 ExecStartPre=/usr/sbin/ngcp-rtpengine-iptables-setup start (code=exited, status=0/SUCCESS) Main PID: 13814 (rtpengine) Tasks: 19 Memory: 10.5M CPU: 102ms CGroup: /system.slice/ngcp-rtpengine-daemon.service └─13814 /usr/sbin/rtpengine -f -E --no-log-timestamps --pidfile /run/ngcp-rtpengine-daemon.pid --config-file /etc/rtpengine/rtpengine.conf --table 0
To start recording service
/etc/init.d/ngcp-rtpengine-recording-daemon start
RTP engine receives command offer
Received command 'offer' from :53888 Dump for 'offer' from :53888: { "sdp":"v=0 o=- 1554978148897419 1 IN IP4 pvt_ip s=Bria 3 release 3.5.5 stamp 71243 c=IN IP4 192.168.1.23 t=0 0 m=audio 50754 RTP/AVP 0 98 101 a=rtpmap:98 ILBC/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-15 a=sendrecv ", "ICE":"remove", "record-call":"yes", "direction":[ "internal", "internal" ], "flags":[ "no-rtcp-attribute" ], "replace":[ "origin", "session-connection" ], "transport-protocol":"RTP/AVP", "call-id":"732597d6-6d96-485b-b6dc-7d93703c1405", "received-from":[ "IP4", "" Creating new call Turning on call recording. Wrote metadata file to temporary path: /var/spool/rtpengine/tmp/ ...
RTP engine receives command delete
Received command 'delete' from :57304 Dump for 'delete' from :57304: { "call-id": "732597d6-6d96-485b-b6dc-7d93703c1405", "received-from": [ "IP4", "" ], "from-tag": "cb8a1e30", "command": "delete" } Deleting call branch 'cb8a1e30' (via-branch '') Call branch 'cb8a1e30' (via-branch '') deleted, no more branches remaining Deleting entire call INFO: [ID="732597d6-6d96-485b-b6dc-7d93703c1405"]: Final packet stats: --- Tag 'cb8a1e30', created 0:05 ago for branch '', in dialogue with '' ------ Media #1 (audio over RTP/AVP) using unknown codec --------- Port :10044 <> :50754, SSRC 0, 0 p, 0 b, 0 e, 5 ts freeing send_timer --------- Port :10045 <> :50755 (RTCP), SSRC 0, 0 p, 0 b, 0 e, 5 ts freeing send_timer --- Tag '', created 0:05 ago for branch '', in dialogue with 'cb8a1e30' ------ Media #1 (audio over RTP/AVP) using unknown codec --------- Port :10032 <> (null):0 , SSRC 0, 0 p, 0 b, 0 e, 5 ts freeing send_timer --------- Port :10033 <> (null):0 (RTCP), SSRC 0, 0 p, 0 b, 0 e, 5 ts freeing send_timer rtpengine: ci=732597d6-6d96-485b-b6dc-7d93703c1405, created_from=:53888, last_signal=1554978149, tos=0, ml0_start_time=1554978149.645290, ml0_end_time=1554978154.822680, ml0_duration=5.177390, ml0_termination=REGULAR, ml0_local_tag=cb8a1e30, ml0_local_tag_type=FROM_TAG, ...