fix: stop ringing on other devices when call is answered or rejected
When a user is logged in on multiple devices, all devices ring on an incoming call. Previously, accepting or rejecting on one device left the others still ringing. Now, acceptCall() and rejectCall() also publish a self-addressed gift-wrapped event (to the user's own pubkey) so other devices receive it and transition out of the IncomingCall state. Added ANSWERED_ELSEWHERE end reason and handling in onCallAnswered/onCallRejected for IncomingCall state. https://claude.ai/code/session_01X9juzyPYWqxRMCgDWEw8R1
This commit is contained in:
+33
-3
@@ -108,6 +108,12 @@ class CallManager(
|
||||
_state.value = CallState.Connecting(current.callId, current.callerPubKey, current.callType)
|
||||
cancelTimeout()
|
||||
publishEvent(result.wrap)
|
||||
|
||||
// Notify other devices of this user that the call was answered here.
|
||||
// This gift-wraps an answer event to our own pubkey so other logged-in
|
||||
// devices see it and stop ringing.
|
||||
val selfNotify = factory.createCallAnswer(sdpAnswer, signer.pubKey, current.callId, signer)
|
||||
publishEvent(selfNotify.wrap)
|
||||
}
|
||||
|
||||
suspend fun rejectCall() {
|
||||
@@ -117,6 +123,10 @@ class CallManager(
|
||||
val result = factory.createReject(current.callerPubKey, current.callId, signer = signer)
|
||||
transitionToEnded(current.callId, current.callerPubKey, EndReason.REJECTED)
|
||||
publishEvent(result.wrap)
|
||||
|
||||
// Notify other devices of this user that the call was rejected here.
|
||||
val selfNotify = factory.createReject(signer.pubKey, current.callId, signer = signer)
|
||||
publishEvent(selfNotify.wrap)
|
||||
}
|
||||
|
||||
fun onCallAnswered(event: CallAnswerEvent) {
|
||||
@@ -131,6 +141,12 @@ class CallManager(
|
||||
onAnswerReceived?.invoke(event)
|
||||
}
|
||||
|
||||
is CallState.IncomingCall -> {
|
||||
// Another device of this user answered the call — stop ringing.
|
||||
if (callId != current.callId) return
|
||||
transitionToEnded(current.callId, current.callerPubKey, EndReason.ANSWERED_ELSEWHERE)
|
||||
}
|
||||
|
||||
is CallState.Connected -> {
|
||||
// Renegotiation answer (e.g., peer accepted our video upgrade offer)
|
||||
if (callId != current.callId) return
|
||||
@@ -145,10 +161,24 @@ class CallManager(
|
||||
|
||||
fun onCallRejected(event: CallRejectEvent) {
|
||||
val current = _state.value
|
||||
if (current !is CallState.Offering) return
|
||||
if (event.callId() != current.callId) return
|
||||
val callId = event.callId()
|
||||
|
||||
transitionToEnded(current.callId, current.peerPubKey, EndReason.PEER_REJECTED)
|
||||
when (current) {
|
||||
is CallState.Offering -> {
|
||||
if (callId != current.callId) return
|
||||
transitionToEnded(current.callId, current.peerPubKey, EndReason.PEER_REJECTED)
|
||||
}
|
||||
|
||||
is CallState.IncomingCall -> {
|
||||
// Another device of this user rejected the call — stop ringing.
|
||||
if (callId != current.callId) return
|
||||
transitionToEnded(current.callId, current.callerPubKey, EndReason.REJECTED)
|
||||
}
|
||||
|
||||
else -> {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onIceCandidate(event: CallIceCandidateEvent) {
|
||||
|
||||
@@ -68,4 +68,5 @@ enum class EndReason {
|
||||
ERROR,
|
||||
PEER_HANGUP,
|
||||
PEER_REJECTED,
|
||||
ANSWERED_ELSEWHERE,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user