RTPEngine: Media Proxy for VoIP — NAT Traversal, Transcoding, and SRTP
← All ArticlesHow RTPEngine solves NAT, codec mismatches, and media security in a Kamailio-based VoIP platform, with configuration and capacity reference.
Why a Media Proxy Is Required
Without a media proxy, audio streams travel directly between devices — creating four classes of problems.
In a SIP call, the signaling (call setup, teardown) and the media (RTP audio) travel on separate paths. Without a media proxy, audio goes directly between the calling device and the destination. This causes:
- NAT issues — devices behind NAT advertise private IPs in SDP; the remote party cannot route audio back
- No call recording — audio never touches the platform, so it cannot be captured
- No transcoding — codec mismatches (G.711 vs G.729 vs Opus) cause one-way or silent calls
- Security exposure — media endpoints are visible on the internet, enabling interception and DoS
RTPEngine solves all four by being the anchor point for all audio.
How RTPEngine Works
Kamailio rewrites SDP in SIP messages so all audio flows through RTPEngine ports.
Caller (SIP Phone) RTPEngine Called Party
│ │ │
│── RTP audio (port A) ──►│ │
│ │── RTP audio (port B) ►│
│ │ │
│◄── RTP audio (port A) ──│ │
│ │◄── RTP audio (port B) ─│When a SIP INVITE arrives, Kamailio calls RTPEngine's control API. RTPEngine allocates port pairs (A and B) and tells Kamailio to rewrite the SDP so each party sends audio to RTPEngine instead of each other. RTPEngine then relays audio bidirectionally.
Key Functions
| Function | Description |
|---|---|
| NAT traversal | Anchors media through the platform — eliminates one-way audio behind NAT |
| Codec transcoding | Converts between G.711, G.729, Opus, etc. transparently — caller and called can use different codecs |
| SRTP ↔ RTP | Converts between encrypted (SRTP) and unencrypted (RTP) — enables encryption end-to-end even when one side doesn't support SRTP |
| Call recording | Captures audio streams to disk in real time — both directions, any format |
| DTMF handling | Normalises in-band and RFC 2833 DTMF signals — eliminates DTMF interoperability issues |
| RTP statistics | MOS score, jitter, packet loss per call — exported to monitoring systems |
Configuration
# /etc/rtpengine/rtpengine.conf [rtpengine] interface = <server-public-ip> listen-ng = 127.0.0.1:2223 # Control socket — Kamailio connects here port-min = 30000 port-max = 40000 # 10,000 port pairs = up to 5,000 concurrent calls log-level = 6 recording-dir = /var/spool/rtpengine/recordings
RTPEngine uses one port pair per call direction. With a port range of 30000–40000 (10,000 ports), the server can handle up to 5,000 simultaneous calls. Adjust the range based on your expected concurrent call volume.
Ensure your firewall allows UDP on the port range (30000–40000) from any source. RTP media arrives from diverse client IPs and the exact source port is negotiated per call.
Kamailio Integration
modparam("rtpengine", "rtpengine_sock", "udp:127.0.0.1:2223")
route[RTPENGINE] {
if (is_method("INVITE")) {
# Proxy offer — rewrite SDP to use RTPEngine ports
rtpengine_offer("replace-origin replace-session-connection");
}
if (is_method("BYE") || is_method("CANCEL")) {
# Delete the media session when call ends
rtpengine_delete();
}
}The replace-origin replace-session-connection flags tell RTPEngine to replace both the o= (origin) and c= (connection) lines in the SDP with its own IP address. This is what forces audio to flow through RTPEngine.
Capacity Reference
| Server Spec | G.711 Pass-through | With Transcoding |
|---|---|---|
| 4 core / 8 GB | ~1,000 concurrent calls | ~500 concurrent calls |
| 8 core / 16 GB | ~2,500 concurrent calls | ~1,200 concurrent calls |
| 16 core / 32 GB | ~5,000+ concurrent calls | ~2,500 concurrent calls |
Transcoding (codec conversion) roughly halves capacity because it requires CPU-intensive audio encoding/decoding for every packet. Use pass-through (same codec both sides) wherever possible and reserve transcoding for endpoints that cannot negotiate a common codec.