call: stop the ring on a user's other devices when one answers (answered-elsewhere)
A user signed in on two devices (iPhone + Android) rang on both. When they
answered on Android, the iPhone kept ringing: markDmAnswered only emitted a
WS 'call-taken', which never reaches a backgrounded/killed device ringing on
CallKit (no live socket).
Now markDmAnswered also pushes a native cancel to the answerer's OTHER
devices. The device that actually answered is skipped via exceptToken (its own
call-push token) — critical on iOS, where a cancel would end the just-answered
CallKit call; Android's cancel branch never tears down a live call anyway.
- push.sendCallCancel(userId, uuid, { exceptToken, reason }) — skips the
answering device's token; existing 2-arg callers unchanged.
- calls.markDmAnswered(room, userId, exceptToken) — fires the cancel.
- POST /api/calls/answered now takes deviceToken.
- home.html: the native answerCall handler POSTs /api/calls/answered with this
device's own token (ios-voip or fcm), so native/LiveKit calls (which bypass
the mesh) are marked answered and siblings stop ringing.
Server + web only — no native build needed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
aa794102c3
commit
08eff043ec
4 files changed
+36
-11
No files matched your search
+7
-1
@@ -171,7 +171,7 @@ async function endDmCallByRoom(room, silent) {
|
||||
|
||||
// Mark a 1:1 call answered when the callee (anyone other than the caller) joins its room, so the end
|
||||
// message shows a real duration (from answer) and the unanswered timeout stands down.
|
||||
function markDmAnswered(room, userId) {
|
||||
function markDmAnswered(room, userId, exceptToken) {
|
||||
const key = roomToDmCall.get(room); if (!key) return;
|
||||
const call = dmCalls.get(key); if (!call) return;
|
||||
if (userId && userId !== call.startedBy && !call.answered) {
|
||||
@@ -183,6 +183,12 @@ function markDmAnswered(room, userId) {
|
||||
// caller's UI from "ringing" to "connected".
|
||||
try { CHAT.pushToUser(userId, { type: 'call-taken', room, uuid: call.uuid }); } catch (_) {}
|
||||
try { CHAT.pushToUser(call.startedBy, { type: 'call-answered', room, uuid: call.uuid, by: userId }); } catch (_) {}
|
||||
// ...but call-taken is WS-only; a backgrounded/killed sibling device ringing via CallKit/FCM has no live
|
||||
// socket, so it keeps ringing. Push a native cancel to the answerer's OTHER devices (answered-elsewhere).
|
||||
// exceptToken = the token of the device that actually answered — never cancel it (on iOS a cancel would end
|
||||
// the just-answered call). Android's cancel branch never tears down a live call, so a stray cancel there is
|
||||
// harmless; the exclusion still avoids a pointless FCM round-trip.
|
||||
try { PUSH.sendCallCancel(userId, call.uuid, { exceptToken, reason: 'answered' }); } catch (_) {}
|
||||
}
|
||||
}
|
||||
// When a user's chat socket (re)connects, re-send any call they're currently being rung into. The
|
||||
|
||||
Reference in new issue
Block a user