feat(call): per-peer 30s invite timeout and per-peer status in video grid
Two changes that tighten how the caller-side UX handles slow or unresponsive callees in a group call: 1. Per-peer 30-second invite timeout Previously the caller used a single 60-second call-wide timeout: if *any* peer answered within the window the timer was cancelled and slow peers could remain "ringing" indefinitely. For a mid-call invite there was no timeout at all — the invitee stayed in pendingPeerPubKeys forever, burning a PeerConnection on the caller side and keeping the invitee's device ringing. CallManager now schedules an independent 30-second timer for every peer in pendingPeerPubKeys (or Offering.peerPubKeys in the initial offer phase). The timer is started when the peer is added to pending — in beginOffering, initiateCall and invitePeer — and is cancelled when the peer answers (onCallAnswered), rejects (onCallRejected) or hangs up (onPeerHangup). On expiry the peer is dropped from the group, a CallHangup is published to them so their device stops ringing, and onPeerLeft fires so CallController can dispose the per-peer PeerConnection. If the drop leaves the caller with zero connected and zero pending peers, the call ends with EndReason.TIMEOUT. Callee ringing still uses the 60-second CALL_TIMEOUT_MS in onIncomingCallEvent; the two timers now serve distinct roles. New constant CallManager.PEER_INVITE_TIMEOUT_MS = 30_000L. NIP-AC.md "Event Lifecycle" documents both timers. 2. Per-peer "Calling..." status in the video grid The shared "Waiting for others to join…" banner across the top of ConnectedCallUI is removed. PeerVideoGrid now takes a pendingPeerPubKeys set and, for each peer still pending, routes rendering through PeerAvatarCell with a "Calling…" status line under the username — so it's obvious *which* participants the call is waiting on, not just *that* it's waiting. A peer in pending never shows as a video cell even if a stale track is still in the map, because they haven't actually answered yet. The voice-only path in ConnectedCallUI now also uses PeerVideoGrid (with empty tracks/active-video) instead of the single GroupCallPictures + GroupCallNames stack, so the per-peer status behavior is consistent for audio calls. Tests added in CallManagerTest: - perPeerTimeoutEndsP2PCallWhenBobNeverAnswers - perPeerTimeoutDropsSlowCalleeFromGroupCall - perPeerTimeoutIsCancelledOnAnswer - perPeerTimeoutDropsMidCallInviteeWhenNoAnswer - perPeerTimeoutIsCancelledOnReject - perPeerTimeoutEndsCallWhenAllCalleesIgnore All existing CallManagerTest cases still pass unchanged. https://claude.ai/code/session_01XSPDbahLwHs9sdF5XfRvHB
This commit is contained in:
@@ -480,7 +480,8 @@ This NIP does not mandate specific STUN or TURN servers. Clients SHOULD:
|
||||
|
||||
- The `call-id` tag MUST be a UUID that is unique per call session. All signaling events for the same call share the same `call-id`.
|
||||
- Signaling data is ephemeral and has no long-term value. Using kind `21059` (ephemeral gift wrap) signals to relays that these events are transient and SHOULD NOT be persisted.
|
||||
- Clients SHOULD implement a ringing timeout (e.g., 60 seconds). If no answer is received, the call transitions to a "timed out" state.
|
||||
- **Callee ringing timeout**: Clients SHOULD implement a ringing timeout (e.g., 60 seconds) on the callee side. If the user does not accept within the window, the call transitions to a "timed out" state.
|
||||
- **Caller per-peer invite timeout**: On the caller side in a group call, clients SHOULD track an independent per-peer invite timer (e.g., 30 seconds) for every peer in `pendingPeerPubKeys` (or for every peer in `Offering.peerPubKeys`, which is implicitly pending). When a peer's timer fires without an answer, the caller drops that peer from the current group call, publishes a `CallHangup` (kind 25053) addressed to them (so their device stops ringing), and continues the call with the remaining peers. If the resulting state has zero connected peers and zero pending peers, the call ends with `TIMEOUT`. The same timer is started when inviting a new peer mid-call. This ensures slow or unavailable peers do not stall the rest of the mesh.
|
||||
- After a call ends, the call state SHOULD auto-reset to idle after a brief display period (e.g., 2 seconds) to ensure the client is ready for subsequent calls.
|
||||
|
||||
### WebRTC Configuration
|
||||
|
||||
Reference in New Issue
Block a user