fix(calls): only cancel-push unanswered calls; add native-call telemetry

- Re-ring on disconnect: sendCallCancel now only fires for UNANSWERED calls. An answered
  call ends via the WS event on both (awake) sides; a cancel push was re-ringing the
  device that just hung up.
- Native-call telemetry (temporary): the plugin fires callConnected/callError on its
  LiveKit connection; the WebView reports nc-answer/nc-connected/nc-error/nc-end/
  nc-outgoing to /api/push-debug so we can see from server logs whether the native room
  actually connects (no device console available). Served — no rebuild needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-30 17:20:32 +05:30
parent 3ac5b6e7bd
commit 2d3ab3dbd3
2 changed files with 13 additions and 4 deletions
+9 -2
View File
@@ -3799,15 +3799,21 @@ async function setupNativeCall(){
// the in-app invite. Track answered rooms so end vs decline is signalled correctly.
const _nativeAnswered = new Set();
NC.addListener('answerCall', (d)=>{ try{
pdbg('nc-answer', { room:(d&&d.room)||'', hasUrl:!!(d&&d.livekitUrl), hasToken:!!(d&&d.livekitToken) });
if(!d||!d.room) return;
_nativeAnswered.add(d.room);
dismissCallInvite(d.room);
postJSON('/api/calls/answered',{ room:d.room }).catch(()=>{});
}catch(e){ console.warn('[callkit] answer failed', e); } });
}catch(e){ pdbg('nc-answer-err', { err:String((e&&e.message)||e) }); } });
// TEMP native-call telemetry: the plugin fires these on its LiveKit connection so we can see, from server
// logs, whether the native room actually connected (no device console available).
NC.addListener('callConnected', ()=>{ pdbg('nc-connected'); });
NC.addListener('callError', (e)=>{ pdbg('nc-error', { err:(e&&e.error)||'' }); });
// Ended/declined on the CallKit screen (or the plugin ended it on remote hang-up). Tell the server: END an
// answered call, DECLINE one that was still ringing.
NC.addListener('endCall', (d)=>{ try{
const room=d&&d.room; if(!room) return;
const room=d&&d.room; pdbg('nc-end', { room:room||'', answered:_nativeAnswered.has(room) });
if(!room) return;
dismissCallInvite(room);
if(_nativeAnswered.has(room)){ _nativeAnswered.delete(room); postJSON('/api/calls/end',{ room }).catch(()=>{}); }
else { postJSON('/api/calls/decline',{ room }).catch(()=>{}); }
@@ -3819,6 +3825,7 @@ async function setupNativeCall(){
async function callkitReportOutgoing(uuid, room, kind, peerName, hasVideo){
const NC=nativeCallPlugin(); if(!NC||!uuid) return;
let tk={}; try{ tk=await postJSON('/api/meetings/token',{ room }); }catch(_){}
pdbg('nc-outgoing', { room, hasUrl:!!(tk&&tk.url), hasToken:!!(tk&&tk.token) });
try{ NC.reportOutgoingCall({ callUUID:uuid, room, kind:kind||'dm', peerName:peerName||'Call', hasVideo:!!hasVideo, url:tk.url||'', token:tk.token||'' }); }catch(_){}
}
// End the CallKit call (remote hung up / we left / call ended). Safe no-op off-CallKit.