Back to the blog

ProCat Solutions

VoIP, SIP and the PSTN bridge: entering the telecom world

Our first months with SIP telephony: codecs, NAT and RTP pitfalls, SIP trunks, the PSTN bridge, IVR, call routing, WebRTC and call quality metrics.

ProCat Solutions voipsippstnwebrtctelecom
VoIP, SIP and the PSTN bridge: entering the telecom world

Earlier this year we stepped into an area we had only known from the outside: telephony. A customer support system needed to handle inbound and outbound calls, wired into an existing web application. Below is what we learned in the first few months. Anyone who has worked with VoIP for years will find this familiar; anyone looking at it for the first time as a web developer may save a few weeks.

SIP is not HTTP, even if it looks like it

SIP (Session Initiation Protocol) is a text-based request-response protocol with headers and status codes, so as a web developer you assume you understand it. The first surprise is that SIP only deals with setting up and tearing down the call (INVITE, ACK, BYE); the audio itself travels on a completely separate channel, over RTP on top of UDP. The link between the two protocols is the IP address and port described in the SDP, and that is exactly where most of the failures happen.

The second surprise is codecs. G.711 (alaw, mulaw) uses 64 kbit/s uncompressed and every device understands it; G.722 gives wider bandwidth; Opus comes from the WebRTC world and copes well with network jitter. If the two sides cannot agree on a common codec, the call connects and there is silence. If an element in the middle transcodes, it eats CPU and adds latency. You need to know this before sizing infrastructure.

NAT and RTP: where one-way audio is born

The classic failure: the call connects, one party hears the other, the other hears nothing. This is almost always a NAT problem. The private IP address in the SIP message is not reachable from the other side, and the RTP packets end up in the wrong place.

What we consequently check on every deployment:

  • the SIP server’s external address is set explicitly, not guessed from the network interface,
  • the RTP port range (typically several thousand UDP ports) is open on the firewall, and the range on the server matches the firewall rule,
  • SIP components running in Docker use host networking, or the RTP range is explicitly published; port forwarding on a bridge network with several thousand UDP ports is not a good idea,
  • on the WebRTC side there is a STUN server and, when needed, a TURN server, because a browser behind symmetric NAT cannot get out any other way.

Settings like rtp_symmetric and other “trust the address the packet came from” options help a lot, but they do not solve everything.

SIP trunk and PSTN bridge

For our system to call and receive real phone numbers, it needs a connection to the public switched telephone network (PSTN). Today this is almost always provided by an operator over a SIP trunk: we get a SIP account or IP-based authentication, and the operator forwards the calls into the traditional network.

For us, the “PSTN bridge” is the component that sits between our own system (web application, WebRTC clients, audio processing) and the SIP trunk. This layer is responsible for routing calls, normalising number formats (E.164), authentication, and writing call detail records (CDRs). Importantly, the trunk credentials must never reach the client side: the browser registers with the bridge, and the bridge talks to the operator.

A lesson about choosing a trunk: it is worth testing with several providers, because audio quality, call setup time and error-code handling differ significantly, and documentation rarely matches reality.

IVR and call routing

Interactive voice response (IVR) is the “press one for…” experience everyone knows. Technically it is a state machine that plays audio files, waits for DTMF tones, and routes accordingly. A few things that matter in practice:

  • DTMF can arrive in three ways (in-band as audio, as an RFC 2833 RTP event, or as a SIP INFO message), and if two elements of the chain negotiated different ones, the keypress is lost,
  • we keep the IVR menu structure in the application database rather than in the PBX configuration, so the customer can edit it themselves,
  • in call routing, the “nobody picks up” case matters at least as much as a successful connection: voicemail, callback request or forwarding must always be defined.

Connecting call routing to the web application (who is calling, which customer they are, who should get the call) is where telephony meets software development, and where we see the most business value.

Measuring call quality

In telephony, “it works” is not binary. A call can connect and still stutter, lag or echo. What we measure and log on every call:

  • packet loss, jitter and round-trip time from the RTCP reports,
  • call setup time (from INVITE to 200 OK),
  • the reason the call ended (normal, rejected, timeout, network error) with the SIP status code,
  • the estimated MOS value, so trends can be tracked with a single number.

These are stored both as Prometheus metrics and as part of the call record, so when a complaint comes in we can look up exactly what happened.

Telephony is far less forgiving than the web: there is no reload button, and the user hears immediately when something is wrong. That is also what makes it attractive: here the quality of the infrastructure really does matter. In the coming months we will also write about GSM modems and SMS sending, because those came up alongside voice.

QR Code