From 2d3ab3dbd316f49c77b5e06541a23385e170d2df Mon Sep 17 00:00:00 2001 From: sravan Date: Thu, 30 Jul 2026 17:20:32 +0530 Subject: [PATCH] fix(calls): only cancel-push unanswered calls; add native-call telemetry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- server/calls.js | 6 ++++-- server/public/home.html | 11 +++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/server/calls.js b/server/calls.js index 73923d9..bfe1bfb 100644 --- a/server/calls.js +++ b/server/calls.js @@ -145,8 +145,10 @@ async function endDmCallByRoom(room, silent) { call.users.forEach((uid) => { try { CHAT.pushToUser(uid, { type: 'chat-message', message: dto }); } catch (_) {} }); } catch (_) {} call.users.forEach((uid, i) => { try { CHAT.pushToUser(uid, { type: 'dm-call', active: false, uuid: call.uuid, with: call.users[1 - i], room }); } catch (_) {} }); - // Stop any CallKit ring on a killed/backgrounded device (no WS to receive the dm-call above). - try { for (const uid of call.users) PUSH.sendCallCancel(uid, call.uuid); } catch (_) {} + // Stop the CallKit ring on a device that's still RINGING (unanswered) — a killed/asleep callee has no WS + // to receive the dm-call above. For an ANSWERED call both sides are awake (the WS event ends it), and a + // cancel push would re-ring the device that just hung up — so only cancel when it was NOT answered. + if (!call.answered) { try { for (const uid of call.users) PUSH.sendCallCancel(uid, call.uuid); } catch (_) {} } // Missed-call banner to the callee (a plain notification, like a phone's missed call) when the call ended // UNANSWERED — timeout or the caller hung up before pickup. Skipped on decline (silent): they chose to. if (!silent && !call.answered) { diff --git a/server/public/home.html b/server/public/home.html index 162bc12..7bbfe93 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -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.