Android app (push/tunnel): audio starts ~1.2 s too late after answering

t.quitsch

Silver Partner
Joined
Apr 21, 2025
Messages
12
Reaction score
3
Hi all,
we have a reproducible issue where the caller's first word is lost after answering a call on the Android app. We measured it over six weeks across two app versions, two audio engines and two network paths. The numbers are very consistent, so here is the full write-up.

Environment
  • 3CX: Hosted, <FQDN>, version <PBX-VERSION>
  • Caller: Yealink T4x/T5x on the LAN (ext. 180 resp. 230), G.722
  • Callee: 3CX Android app, ext. 203
  • Device: Google Pixel 8, Android 17 (API 37), Tensor G3
  • App versions: 20.6.0.20 (test 1), 20.7.0.5 (tests 2 and 3)
  • Connectivity: NOT SIP-registered — push (FCM) + 3CX tunnel
  • Engine config: useTunnelOnly=true, maxJbSize=360, framesPerBurst=320

Verbose logging was enabled for all tests. The tunnel was already up before each call — onTunnelState state=TunnelState(connected=true, secured=true, mediaMode=MediaMode(fastTx=true, fastRx=true)). So no time is spent establishing the tunnel during the call.

Symptom
About a second passes between the answer swipe and audio actually flowing. The caller has already started speaking by then, so their first word is lost.

Measurements from the app logs
Three markers, all read from the same clock, so there is no clock-offset issue:
  • A = IncomingCallsActivity: OnSwipe answer — user answers
  • B = Core.VceLine: makePickupCall destination=..., replaces=... — INVITE leaves the app
  • C = Core.VceCallListener: event=established — 3CX confirms setup
Test 1 — 22 Jun 2026, 08:46 — app 20.6.0.20, audio engine opensl, mobile data
  • A → B: 90 ms
  • B → C: 1.137 s
  • A → C: 1.227 s
Test 2 — 07 Aug 2026, 10:29 — app 20.7.0.5, audio engine oboe, mobile data
  • A → B: 64 ms
  • B → C: 1.146 s
  • A → C: 1.210 s
Test 3 — 07 Aug 2026, 10:39 — app 20.7.0.5, audio engine oboe, Wi-Fi on the same LAN as the PBX
  • A → B: 24 ms
  • B → C: 0.447 s
  • A → C: 0.471 s
Three observations:
  1. The app-internal share is negligible (24–90 ms). The time is spent between the pickup INVITE leaving the app and the PBX confirming.
  2. Switching opensl to oboe changed nothing at all (1.137 s vs 1.146 s). The Android audio layer is not the cause.
  3. The network path accounts for ~700 ms. But 447 ms remain even on Wi-Fi.

pcap timeline (test 1, captured on the PBX)
Times relative to the start of the capture. Only the relevant messages; REGISTER/SUBSCRIBE/NOTIFY omitted.
  • t=31.894 — INVITE sip:203, from Yealink 180
  • t=31.938 — 180 Ringing to the caller; forked to the clients of ext. 203
  • t=32.060 — push sent to the app (server timestamp taken from the push payload)
— user answers —
  • t=35.455 — INVITE with Replaces from the app arrives: 127.0.0.1:5080 → 127.0.0.1:5060, CSeq 19020, User-Agent "3CXPhone for Android 20.6.0.20"
  • t=35.469 — SIP/2.0 407 Proxy Authentication Required, followed by ACK
  • t=35.671 — INVITE CSeq 19021 with Proxy-Authorization — +216 ms for the challenge alone
  • t=35.684 — first tunnel SRTP, PBX → app (192.168.200.32:5090 → x.x.x.x:34640)
  • t=35.752 — 100 Trying
  • t=35.753 — 200 OK
  • t=35.880 — first tunnel SRTP, app → PBX
  • t=35.895 — ACK from the app
  • t=35.969second, internal INVITE to sip:[email protected]:5080, CSeq 2
  • t=36.030 — 200 OK from the bridge, SDP carrying the actual media address
  • t=36.040 — first RTP, PBX → Yealink (G.722)
  • t=36.070 — 200 OK to the calling Yealink
  • t=36.179 — ACK from the Yealink
  • t=36.236 — first RTP, Yealink → PBX
From the pickup INVITE arriving to full two-way audio at the desk phone: 781 ms.
Note that the 216 ms for the 407 challenge is not a local operation — the response has to travel back through the tunnel to the mobile device and return. On mobile data this is the single largest item.

The media path itself is clean
So this does not get written off as a network problem:
  • Codec: G.722 on both legs, no transcoding
  • Packets: 420 (PBX → Yealink), 417 (Yealink → PBX) over ~8.3 s
  • Loss: none
  • Largest gap: 68 ms, single occurrence
The missing audio therefore happens entirely before the first RTP packet, not through packet loss.

Second, independent issue: push latency

From the FcmService: Received PUSH message, sent at ..., now is ... (diff ... ms) lines:
  • 22 Jun 2026: 1517 ms, 1573 ms
  • 07 Aug 2026: 2129 ms, 2142 ms, 2165 ms, 2259 ms
This is just as bad on Wi-Fi as on mobile data, so it does not depend on the local network path. It has also degraded by roughly 600 ms since June. It delays ringing by over two seconds on every inbound call.

Questions
  1. Can the digest challenge (407) on the pickup INVITE be skipped for clients already authenticated through the tunnel? It costs a full extra round trip to the device.
  2. Why is a second INVITE to the 3cxBridge needed after the 200 OK, and could media negotiation be started in parallel with signalling?
  3. Are ~447 ms between pickup INVITE and "established" the expected figure for a push/tunnel client on the same LAN as the PBX, or is ours too high?
  4. Is the ~2.2 s average push delivery time a known issue? Is there anything server-side that affects the send timestamp?
  5. Does useTunnelOnly=true need to apply even when the client is demonstrably on the same network as the PBX? Could this be relaxed per extension?
 
Do you have the same delay if you're already in a call?
Make a call to *777 and while established have the incoming call you mentioned above and see if it has the same delay on answering.