fix(voip): heal stale SDK socket on warm lock-screen accept#7293
fix(voip): heal stale SDK socket on warm lock-screen accept#7293diegolmello wants to merge 1 commit into
Conversation
When the device stays locked through CallKit accept, the foreground saga never runs (AppState never reaches 'active'), so nothing nudges the SDK to reopen its DDP socket if it went stale during background suspension. The local accept resolves and CallKit shows "connected", but answer SDP and ICE candidates can never reach the peer because send() blocks waiting on a socket that won't reopen on its own. Call checkAndReopen() before each signal send. It is a no-op when the socket is alive; otherwise it triggers the existing reconnect → relogin → resubscribe chain so signaling can flow over a fresh DDP session.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📜 Recent review details⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
🧰 Additional context used📓 Path-based instructions (4)**/*.{js,ts,jsx,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
app/lib/services/voip/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (1)📚 Learning: 2026-04-30T17:07:51.020ZApplied to files:
🔇 Additional comments (1)
WalkthroughA socket-reconnection check is inserted into the media signaling callback to ensure a fresh DDP session exists before sending signaling messages during lock-screen call accepts, preventing stale socket errors. ChangesSocket Reconnection Before Signaling
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~5 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
|
iOS Build Available Rocket.Chat Experimental 4.72.0.108747 |
Proposed changes
When an iOS user has the app warm in the background, locks the device, then accepts an incoming call from the lock screen, the local UI shows the call as connected but the remote peer keeps trying to connect for ~10s and then fails. Killed-app accept (cold start via PushKit) works.
Root cause: the SDK's DDP websocket can go stale during background suspension. On warm lock-screen accept, nothing nudges it back to life:
appHasComeBackToForegroundonly runs onAppState='active'. The device stays locked through CallKit accept, so the saga never fires.reopen()only kicks in on an explicitonCloseevent; iOS suspended sockets often go zombie without firingclose.mediaCall.accept()resolves locally (CallKit shows "connected") but the answer SDP and ICE candidates queued insetSendSignalFn → sdk.methodCall('stream-notify-user', …)block forever inddp.send()waiting on the'open'event.Fix: call
sdk.current?.checkAndReopen?.()before each signal send. It is a no-op when the socket is alive; otherwise it triggers the existing reconnect → relogin (connectedListenerinconnect.ts:112) → resubscribe (subscribeAllinsideddp.login) chain so signaling can flow over a fresh DDP session.Issue(s)
VoIP warm lock-screen accept regression discovered while testing #7283 / #7281 follow-up scenarios.
How to test or reproduce
Before: local CallKit shows connected; remote stays on "calling…" for ~10s and drops.
After: call connects on both ends; audio flows.
Cold-start path (kill app → call → accept from lock screen) should remain unaffected (regression check).
Screenshots
n/a
Types of changes
Checklist
Further comments
A regression test for this exact scenario is hard without an integration harness that simulates iOS suspension + CallKit accept; the bug only manifests on a real device with a Release build (debug attaches the JS debugger which keeps the socket alive). Suggested follow-up: add a unit assertion that
setSendSignalFncallscheckAndReopenbeforemethodCall, plus a manual QA item on the lock-screen accept flow.Stronger alternative considered: full
mediaSessionInstance.reset()+init()onVoipAcceptSucceeded. Rejected for blast radius — the minimal fix is co-located with the actual send site so any background-resume signaling path benefits, not just the iOS warm-locked accept.Summary by CodeRabbit