← Back to Blog

VoiceBlender v0.15.0 Released

releasesipwebrtcdenoisetrunkssecuritynat

VoiceBlender v0.15.0 is out. Most of it is about running in real networks: trunks that peer by IP address, deployments behind NAT, WebRTC clients that change network mid-call, and SIP ports exposed to the internet.

A second denoiser: GTCRN

denoise_gtcrn is a new noise suppression filter next to the RNNoise-based denoise. On 8 and 16 kHz telephony audio it uses less than half the CPU and removes more noise. RNNoise is still the better choice for 48 kHz rooms and for AMD in very heavy noise. The details and measurements are in a separate post.

IP-IP trunks

Until now a SIP trunk had to register with the upstream. A new trunk type, ip_ip, describes a peer at a fixed address: a carrier trunk, an SBC or another PBX.

  • Calls go to a fixed peer_uri, with optional digest credentials.
  • Inbound calls are matched to the trunk by source address (inbound_sources).
  • An optional OPTIONS ping tracks whether the peer is answering.
curl -X POST http://localhost:8080/v1/sip/trunks \
  -H 'Content-Type: application/json' \
  -d '{
    "type": "ip_ip",
    "ip_ip": {
      "peer_uri": "sip:203.0.113.10:5060",
      "inbound_sources": ["198.51.100.0/24"],
      "options_ping_interval_seconds": 30
    }
  }'

ICE restart for WebRTC legs

A WebRTC leg no longer dies the moment its network path breaks, for example when a phone moves from Wi-Fi to mobile data. After 5 seconds without media the leg emits leg.ice_interrupted and stays up. The client then has 25 seconds to send a new offer to POST /v1/legs/{id}/ice-restart (or the webrtc_ice_restart VSI command). leg.ice_restored fires when media is back. Both timeouts are configurable.

SIP allowlist and inbound ring timeout

Two settings for SIP ports that face the internet:

  • SIP_ALLOWED_IPS is a list of addresses and CIDR ranges that SIP requests are accepted from, on UDP, TCP and TLS. Anything else is dropped with no SIP response, so a scanner only sees a timeout.
  • SIP_INBOUND_RING_TIMEOUT_SECONDS (default 180) releases inbound calls that are never answered and never cancelled. Before, such a call could hold its leg forever.

Running behind NAT and in Docker

In a Docker bridge network VoiceBlender used to advertise the container’s own address, which nothing outside the host can reach. Calls connected, but the peer’s hangup never arrived. SIP_LOCAL_NETS fixes the common mixed case: peers on the listed networks are given the LAN address, and everyone else gets SIP_EXTERNAL_IP. One instance can now serve a carrier and LAN phones together. The new “Docker and NAT” section in the configuration guide covers the options.

Custom headers on transfers

POST /v1/legs/{id}/transfer accepts refer_to_headers. They are embedded in the Refer-To URI, so the peer copies them into the INVITE it sends to the transfer target. This is how you pass a conversation ID through a blind transfer. It was tested against a Genesys Cloud BYOC trunk.

Behaviour changes to know about

  • Outbound ring_timeout now defaults to 60 seconds. It was unlimited before. Send 0 to keep the old behaviour.
  • Deleting a room cancels outbound calls still ringing towards it. They end with reason room_deleted.
  • Inbound custom headers are matched in any case. x-foo and p-asserted-identity are now picked up as well as X-Foo, and reported exactly as received, so look them up case-insensitively.

Fixes worth calling out

  • The Contact header follows the INVITE’s transport (;transport=tcp, ;transport=tls or sips:), so in-dialog requests come back the right way
  • telephone-event is picked at the selected codec’s clock rate, so PCMU gets /8000 even when the peer lists /48000 first
  • a=rtcp-mux is answered only when it was offered
  • WebRTC and WhatsApp legs are removed when the peer closes its media connection (DTLS close), with the new peer_closed and dtls_failed disconnect reasons

Also new since v0.12.0

The last release post here covered v0.12.0, so here is a short summary of what v0.13.0 and v0.14.0 added.

v0.13.0 (September 2026)

  • Outbound SIP proxy. REGISTERs and INVITEs can be sent through a proxy, set server-wide with SIP_OUTBOUND_PROXY, per trunk, or per call.
  • Speechmatics STT, as another speech-to-text provider.
  • Custom data on legs. Attach your own JSON to a leg with custom_data. It is repeated on every event for that leg, and can be changed during the call over REST or VSI.
  • Mixer fix for any packet size. A peer sending 10 ms or 30 ms RTP packets used to lose half of its audio in the mix, recordings and transcription. From Andreas Granig (@agranig).
  • Rooms transcribe and record every audio source, not only leg participants. Also from Andreas Granig.
  • Click-free WebSocket audio. Audio sent in over WebSocket, LiveKit and MoQ no longer drifts against the mixer clock, which had caused a click roughly once a second.
  • Fixes for RTP port reuse, the Contact URI on outgoing REGISTERs, TLS URI parsing, and SIPREC metadata checks (@agranig). Dan Jenkins co-authored fixes for agent audio pacing and WhatsApp call routing.

v0.14.0 (September 2026)

  • Audio filters. A per-leg chain of filters on incoming audio: denoise (RNNoise), bandpass, gain, pitch, robotic and vocoder. The denoise work has its own post.
  • About a third less CPU per room. The resampler’s inner loop is now AVX2 assembly on amd64 and NEON on arm64, and the mixer and RTP paths reuse their buffers. No API or configuration changes.
  • Comfort noise per room. It can now be turned on or off for each room.
  • app_id in more places. It is now on ringing events for outbound trunk calls and on inbound registrations.
  • Better compatibility with SIP proxies (rport, and REGISTER routing through an outbound proxy).
  • The configuration reference moved from the README to CONFIGURATION.md.

Upgrading

go get github.com/VoiceBlender/voiceblender@v0.15.0
go build -o voiceblender ./cmd/voiceblender

Full changelog: v0.14.0…v0.15.0, or everything since v0.12.0.

Check the API Documentation for the trunk, ICE restart and transfer options.

Questions or feedback? Come say hi in our Discord - issues and PRs very welcome.