Spent two days last week debugging what looked like a softphone issue. Calls would connect cleanly, both sides could see the call was active, but audio only flowed in one direction. Sometimes caller could hear receiver, sometimes the opposite. Inconsistent across users.
My first instinct, like most people's, was to blame the softphone. Switched clients. Same problem. Switched again. Same problem. That's when I realized I was debugging the wrong layer.
What was actually happening
SIP was working perfectly the whole time. Signaling went through, both endpoints negotiated codecs, the call set up cleanly. The break was in the media layer. RTP packets were getting dropped in one direction because of NAT timeouts on the user's home router.
Here's the sequence:
- Call connects, both sides exchange ICE candidates
- RTP starts flowing in both directions
- NAT on one side creates a temporary mapping for the inbound RTP
- NAT mapping expires (some routers do this in 30 seconds)
- The other side keeps sending RTP packets to a closed door
- One-way audio. SIP still thinks everything is fine.
This pattern shows up everywhere. Mobile VoIP deployments. Browser-based WebRTC calling. White-label softphones. The protocol layer doesn't matter. NAT will eat your RTP if the mapping isn't kept alive.
Things that actually fix it
A few patterns that work, depending on your setup:
RTP keep-alives: Send a small RTP packet every 20-30 seconds even when nobody's talking. Keeps the NAT mapping open. Crude but reliable.
ICE with TURN fallback: If STUN can't establish a peer connection, route through a TURN server. Adds some latency but solves NAT problems definitively. Run coturn or use a managed TURN service.
SBC in the path: A Session Border Controller sits between your softphone and the public network, handling NAT and media relay properly. Most production VoIP deployments end up doing this regardless of how their SIP softphone is configured.
Symmetric RTP: Configure the softphone client to send RTP from the same port it receives on. Helps in restrictive NAT setups.
Mental model shift
The shift that made this easier for me was treating SIP and RTP as two completely separate things that happen to ride together. SIP working fine tells you nothing about whether RTP is going to work. They're different protocols with different problems.
Now when I see one-way audio reports, the first thing I check is RTP path. NAT, firewalls, SBC config. The SIP softphone itself is almost never the actual problem, even when it looks like it is.
For mobile specifically
Mobile makes this worse. Cellular NAT is aggressive. Wi-Fi to cellular handoffs reset NAT mappings. Background apps lose their RTP path entirely if they aren't kept alive properly with push notifications.
This is why a lot of white-label softphone providers (Tragofone, Acrobits, CounterPath among others) ship dedicated push-driven architectures and RTP keep-alive defaults rather than expecting the client to maintain a persistent connection. Tragofone in particular handles this through their VoIP softphone with built-in push notifications approach, which is one of the cleaner implementations I've seen in production.
Top comments (0)