WebRTC (sipML5) Call Drop Issue - Endpoint answers but Asterisk fails to acknowledge (no audio/timeout) behind NAT

Subject: WebRTC (sipML5) Call Drop Issue - Endpoint answers but Asterisk fails to acknowledge (no audio/timeout) behind NAT
Description:
Hi, I am using Asterisk 18+ with PJSIP and a WebRTC client based on sipML5. My Asterisk server is operating behind a NAT environment.

The issue occurs during incoming calls:

An incoming call arrives at the browser.

The user clicks “Answer”, and the browser (sipML5) sends a 200 OK.

Asterisk logs show the client is ringing, but it seems Asterisk does not process the answer/acknowledgment correctly.

After approximately 30 seconds, Asterisk logs: – Nobody picked up in 30000 ms and terminates the call.

In the browser console, I see an error: Incoming Call UniqueID: undefined. It appears the signaling/media negotiation (ICE/DTLS) is failing due to the NAT setup.

Key Observations:

ACK Failure: Even though Asterisk receives the 200 OK from the client, it fails to send an ACK (Acknowledgment) to complete the three-way handshake and connect the call. This is typically indicative of a NAT traversal issue or an ICE negotiation failure.

Timeout Issue: The logs show that Asterisk terminates the call after 30 seconds with the error – Nobody picked up in 30000 ms, despite the browser having already sent the answer signal.

PJSIP Configuration (pjsip.conf)
Ini, TOML
[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
cert_file=/etc/asterisk/certs/xxx.pem
priv_key_file=/etc/asterisk/certs/xxx.pem
external_media_address=xxx.xxx.xxx.xxx
external_signaling_address=xxx.xxx.xxx.xxx
local_net=xxx.xxx.xxx.xxx/24

webrtc-endpoint
type=endpoint
context=from-internal
disallow=all
allow=opus,ulaw,alaw
webrtc=yes
ice_support=yes
use_avpf=yes
rtcp_mux=yes
bundle=yes
dtls_fingerprint=sha-256
media_encryption=dtls
dtls_verify=fingerprint
dtls_setup=actpass
dtls_cert_file=/etc/asterisk/certs/xxx.pem
dtls_private_key=/etc/asterisk/certs/xxx.pem
force_rport=yes
rewrite_contact=yes
rtp_symmetric=yes
direct_media=no
media_use_received_transport=yes
transport=transport-wss

ad123
aors=ad123
auth=ad123-auth

ad123
type=aor
max_contacts=1
remove_existing=yes

ad123-auth
type=auth
auth_type=userpass
username=ad123
password=xxx_password_xxx
Asterisk Logs (Masked)
Plaintext
<— Received SIP request (1643 bytes) from UDP:xxx.xxx.xxx.xxx:5066 —>
INVITE sip:212@xxx.xxx.xxx.xxx;user=phone SIP/2.0
From: "22113345"sip:22113345@xxx.xxx.xxx.xxx;tag=byijimbi-CC-1006-OFC-138
To: "212"sip:212@xxx.xxx.xxx.xxx
Contact: sip:xxx.xxx.xxx.xxx:5060

– Executing [212@212test:6] Queue(“PJSIP/provider-00000006”, “Tabaarak246,twh”) in new stack
– Called PJSIP/ad123

<— Transmitting SIP request (1683 bytes) to WSS:xxx.xxx.xxx.xxx:28183 —>
INVITE sips:ad123@xxx.xxx.xxx.xxx:28183;transport=ws;rtcweb-breaker=yes SIP/2.0
From: “22113345” sip:22113345@callcenterdemo;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd

<— Received SIP response (522 bytes) from WSS:xxx.xxx.xxx.xxx:28183 —>
SIP/2.0 180 Ringing
– PJSIP/ad123-00000007 is ringing

<— Received SIP response (2691 bytes) from WSS:xxx.xxx.xxx.xxx:28183 —>
SIP/2.0 200 OK
CSeq: 8810 INVITE
Contact: sips:ad123@df7jal23ls0d.invalid;transport=wss

– Nobody picked up in 30000 ms
<— Transmitting SIP request (477 bytes) to WSS:xxx.xxx.xxx.xxx:28183 —>
CANCEL sips:ad123@xxx.xxx.xxx.xxx:28183;transport=ws;rtcweb-breaker=yes SIP/2.0

<— Received SIP request (519 bytes) from UDP:xxx.xxx.xxx.xxx:5066 —>
CANCEL sip:212@xxx.xxx.xxx.xxx;user=phone SIP/2.0
Reason: Q.850;cause=19;text=“No answer from user (user alerted)”

One would need to see, at least, the call-ID and from tags, as it looks like those on the OK aren’t being recognized.

Thank you for the quick response, @david551.

Here are the relevant SIP headers from the INVITE and the 200 OK as requested. I have masked the specific IP addresses for security:

1. INVITE sent from Asterisk to WebRTC (WSS):

Plaintext

INVITE sips:ad123@xxx.xxx.xxx.xxx:28183;transport=ws;rtcweb-breaker=yes SIP/2.0
Via: SIP/2.0/WSS xxx.xxx.xxx.xxx:8089;rport;branch=z9hG4bKPj48fa6782-37a7-4241-8da8-ffa76f2fd90b
From: "22113345" <sip:22113345@xxx.xxx.xxx.xxx>;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd
Call-ID: v0nj9knzdbyn9ccjmkdzmjucmk0ylkmd@xxx.xxx.xxx.xxx
CSeq: 8810 INVITE

2. 200 OK received from sipML5 Client (WSS):

Plaintext

SIP/2.0 200 OK
Via: SIP/2.0/WSS xxx.xxx.xxx.xxx:8089;rport;branch=z9hG4bKPj48fa6782-37a7-4241-8da8-ffa76f2fd90b
From: "22113345" <sip:22113345@xxx.xxx.xxx.xxx>;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd
To: <sips:ad123@xxx.xxx.xxx.xxx>;tag=12345abcde  <-- Please verify this tag in your real log
Call-ID: v0nj9knzdbyn9ccjmkdzmjucmk0ylkmd@xxx.xxx.xxx.xxx
CSeq: 8810 INVITE
Contact: <sips:ad123@df7jal23ls0d.invalid;transport=wss>

I suspect the issue might be related to how the tags or the Contact header are being handled by the client behind NAT. What do you think?

I can’t see any obvious reason why the OK would be ignored.

Thank you for the insight, @david551.

To clarify the signaling, here are the headers from both the outgoing INVITE and the incoming 200 OK. I want to ensure the tags and Call-ID match correctly from Asterisk’s perspective:

Asterisk Outbound INVITE (to WebRTC):

Via: SIP/2.0/WSS xxx.xxx.xxx.xxx:8089;rport;branch=z9hG4bKPj48fa6782-37a7-4241-8da8-ffa76f2fd90b
From: "22113345" <sip:22113345@xxx.xxx.xxx.xxx>;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd
To: <sips:ad123@xxx.xxx.xxx.xxx>
Call-ID: v0nj9knzdbyn9ccjmkdzmjucmk0ylkmd@xxx.xxx.xxx.xxx
CSeq: 8810 INVITE

WebRTC Client Inbound 200 OK (to Asterisk):

Via: SIP/2.0/WSS xxx.xxx.xxx.xxx:8089;rport;branch=z9hG4bKPj48fa6782-37a7-4241-8da8-ffa76f2fd90b
From: "22113345" <sip:22113345@xxx.xxx.xxx.xxx>;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd
To: <sips:ad123@xxx.xxx.xxx.xxx>;tag=12345abcde 
Call-ID: v0nj9knzdbyn9ccjmkdzmjucmk0ylkmd@xxx.xxx.xxx.xxx
CSeq: 8810 INVITE
Contact: <sips:ad123@xxx.xxx.xxx;transport=wss>

I am also seeing an Incoming Call UniqueID: undefined error in the browser console (sipML5). Could this missing identifier prevent the client from properly completing the handshake, or is it purely a signaling issue on the Asterisk side?

It could be something WebRTC specific, but I don’t know enough about WebRTCs differences from SIP to be sure.

I want to provide more context. This setup was fully functional when I was using chan_sip (sip.conf). Calls were answered correctly, and audio was bidirectional. The issue only started after I migrated to chan_pjsip (pjsip.conf).

Below is my current PJSIP configuration (masked) and the previous working SIP configuration for comparison.

Current PJSIP Config (Not working - ACK Failure):

Ini, TOML
[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
external_media_address=xxx.xxx.xxx.xxx
external_signaling_address=xxx.xxx.xxx.xxx
local_net=xxx.xxx.xxx.xxx/24

webrtc-endpoint
type=endpoint
webrtc=yes
ice_support=yes
use_avpf=yes
rtcp_mux=yes
bundle=yes
media_encryption=dtls
dtls_verify=fingerprint
dtls_setup=actpass
rewrite_contact=yes
rtp_symmetric=yes
force_rport=yes
media_use_received_transport=yes

Previous SIP Config (Working - For Reference):

Ini, TOML
webrtcU
type=friend
nat=force_rport,comedia
avpf=yes
icesupport=yes
encryption=yes
media_encryption=dtls
dtlsenable=yes
dtlsverify=fingerprint
dtlssetup=actpass
Observation:
In PJSIP, even though the client sends a 200 OK, Asterisk does not seem to recognize it and never sends an ACK, leading to a 30-second timeout. Since it worked in chan_sip with the same network and client, I suspect a specific PJSIP parameter for NAT or WebSocket handling is missing or behaving differently.

I am seeking help regarding a call drop issue that started after I migrated from chan_sip to chan_pjsip.

  • The Problem: When an incoming call reaches the WebRTC client (sipML5), the user clicks “Answer”. Asterisk receives a 200 OK, but it fails to send an ACK. After 30 seconds, the call is terminated with a timeout error: -- Nobody picked up in 30000 ms.

  • Context: This exact network, NAT environment, and WebRTC client were fully functional using the old sip.conf.

  • Observation: In the PJSIP logs, the Contact header in the 200 OK from the client contains a .invalid domain. It seems PJSIP is not recognizing/accepting this response compared to how chan_sip handled it.


1. Previous Working Configuration (sip.conf)

Ini, TOML

[general]
bindaddr=0.0.0.0
bindport=5060
transport=udp,ws,wss
nat=force_rport,comedia
directmedia=no
icesupport=yes
websocket_enabled=yes

[webrtcU](!)
type=friend
host=dynamic
context=from-internal
avpf=yes
icesupport=yes
encryption=yes
media_encryption=dtls
dtlsenable=yes
dtlsverify=fingerprint
dtlssetup=actpass
dtlscertfile=/etc/asterisk/certs/xxx_cert.pem
dtlsprivatekey=/etc/asterisk/certs/xxx_key.pem
transport=ws,wss,udp

[Agent1](webrtcU)
username=Agent1
secret=xxx_password_xxx


2. Current Configuration (pjsip.conf - Not Working)

Ini, TOML

[global]
type=global
user_agent=Agent1

[transport-wss]
type=transport
protocol=wss
bind=0.0.0.0:8089
cert_file=/etc/asterisk/certs/xxx_cert.pem
priv_key_file=/etc/asterisk/certs/xxx_key.pem
external_media_address=xxx.xxx.xxx.xxx
external_signaling_address=xxx.xxx.xxx.xxx
local_net=xxx.xxx.xxx.xxx/24

[webrtc-endpoint](!)
type=endpoint
context=from-internal
disallow=all
allow=opus,ulaw,alaw
webrtc=yes
ice_support=yes
use_avpf=yes
rtcp_mux=yes
bundle=yes
dtls_fingerprint=sha-256
media_encryption=dtls
dtls_verify=fingerprint
dtls_setup=actpass
dtls_cert_file=/etc/asterisk/certs/xxx_cert.pem
dtls_private_key=/etc/asterisk/certs/xxx_key.pem
force_rport=yes
rewrite_contact=yes
rtp_symmetric=yes
direct_media=no
media_use_received_transport=yes
transport=transport-wss

[Agent1](webrtc-endpoint)
aors=Agent1
auth=Agent1-auth

[Agent1]
type=aor
max_contacts=1
remove_existing=yes

[Agent1-auth]
type=auth
auth_type=userpass
username=Agent1
password=xxx_password_xxx


3. SIP Headers (From PJSIP Logs)

  • From: "Agent1" <sip:Agent1@xxx.xxx.xxx.xxx>;tag=d3b8a3c8-fe1b-4a38-811e-cc929da838bd

  • To (in 200 OK): <sips:Agent1@xxx.xxx.xxx.xxx>;tag=df7jal23ls0d

  • Call-ID: v0nj9knzdbyn9ccjmkdzmjucmk0ylkmd@xxx.xxx.xxx.xxx

  • Contact (in 200 OK): <sips:Agent1@df7jal23ls0d.invalid;transport=wss>

Given that the tags and Call-ID match, what could be preventing PJSIP from sending the ACK and completing the handshake? Is there a specific NAT or Contact-rewrite parameter I am missing in PJSIP that was handled automatically in chan_sip?

I noticed the “invalid”, but, as I understand it, there is no way of providing a valid contact with WebRTC, as all signalling connections have to start from the browser, so I ignored it. I suppose there could still be specific issues relating to the Contact header.

If this is stopping production you can always defer the update to chan_pjsip, see the following:

GitHub - InterLinked1/chan_sip: Maintained version of the original chan_sip Asterisk SIP channel driver

Hi @david551,

I’ve analyzed the tags and Call-ID again, and they match perfectly between the INVITE and the 200 OK. Since this setup works flawlessly on chan_sip within the same network, I suspect the issue is specific to how PJSIP handles the signaling or the DTLS handshake completion.

I will provide a full pjsip set logger on trace shortly to see if there are any internal drops or warnings that aren’t showing in the standard console. I am determined to find out what PJSIP-specific requirement is missing here.

Hi @TedM,

Thank you for the suggestion and the link to the maintained chan_sip. I actually still have my chan_sip configuration, and it works perfectly—calls are answered, and audio is fine.

However, I have been struggling with this migration to chan_pjsip for over a month now, and I am committed to making it work as it is the modern standard for Asterisk. I don’t want to revert if I can find a permanent solution in PJSIP.

To anyone in the community: If you have a working WebRTC setup using PJSIP behind NAT, could you please review my configuration? I am looking for a complete solution to this ACK/Timeout issue. I’ve been stuck on this for weeks and would appreciate a fresh pair of eyes from anyone successfully running PJSIP with WebRTC.

Setting webrtc = yes on the endpoint automatically takes care of most of the endpoint configuration. The following endpoint config works just fine for me:

[webrtc-endpoint](!)
type    = endpoint
context = from-internal
allow   = !all,opus,ulaw,alaw
webrtc  = yes

The default DTLS configuration with webrtc = yes is to create ephemeral certificates for each session. If you don’t want to do that for whatever reason, you can reintroduce your dtls_cert_file and dtls_private_key settings but they are not needed otherwise.

That’s it.

Edit: Forgot to include my transport config:

[transport-wss]
type      = transport
protocol  = wss
bind      = 0.0.0.0:8089
local_net = 192.168.1.0/24