nextcloud / nextcloud/talk-android
Call stuck on "Ringing" forever after reconnect: stale room session is reused, no_such_room error is dropped
Nobody has claimed this yet.
- Dominant language
- Kotlin
- Stars
- 739
- Forks
- 321
- Avg merge
- 14h 59m
- Merged PRs (30d)
- 151
Description
Note: This bug report was heavily assisted by GLM 5.3
Steps to reproduce
Observed live (Android Talk v24.0.3 release and a 25.1.0-alpha QA build, spreed 24.0.4 + HPB/Janus):
- Join a call from Android (this caches the room session in
ApplicationWideCurrentRoomHolder) - Leave the app sitting (backgrounded / stuck in a broken call) long enough that the server reaps the room session — spreed advertises
session-ping-limit: 200and invalidates sessions that stop pinging - Lose and regain connectivity (WiFi ↔ cellular switch), then re-enter the call
Expected behaviour
The app joins the room and the call. If the cached session is stale, it fetches a fresh one via the joinRoom API and continues. If joining genuinely fails, the user gets an error.
Actual behaviour
The call UI shows "Ringing…" forever. Nothing recovers, no error is shown, and no timeout fires.
Root cause analysis
CallActivity.joinRoomAndCall()only calls the joinRoom API when the cached session is empty (CallActivity.kt:1557); otherwise it reusesApplicationWideCurrentRoomHolder.getInstance().session— which may have been reaped server-side.- The HPB rejects the join:
{"type":"error","error":{"code":"no_such_room","message":"The user is not invited to this room."}} WebSocketInstance.processErrorMessage()handles onlyno_such_sessionandhello_expected;no_such_roomis logged and dropped — no state change, no retry, no event to the UI.- The ring timeout (
CallStatus.CALLING_TIMEOUT,CallActivity.kt:2653) is only armed after a successful join (JOINED), so a failed join never times out either.
Evidence
Client (logcat, phone time 12:38:31 — right after a network drop and websocket reconnect):
WebSocketInstance: Sending join room message via websocket
WebSocketInstance: Received error: {"type":"error","error":{"code":"no_such_room","message":"The user is not invited to this room."}}
Earlier the same day, the release build retried a stale join 8 times in 75 seconds (11:23:09–11:24:44), always with the same no_such_room answer — retrying without ever invalidating the cached session.
Server (HPB):
clientsession.go:601: Removed room session 3vUn…: map[error:map[code:no_such_room
message:The user is not invited to this room.] type:error]
hub.go:860: Closing expired session k5l5… (the reaped session the client kept reusing)
Suggested fix
- Handle
no_such_roomin the error path: emit an event to the call UI, invalidate the cached room session (ApplicationWideCurrentRoomHolder+CallActivity.callSession), and re-run the joinRoom API to obtain a fresh session before retrying — once or twice, with the fetch as the retry, not the same stale session in a loop. - If the fresh join also fails, leave the call UI with an error message (never infinite "Ringing").
- Consider arming the calling timeout as soon as the join attempt starts, not only after
JOINED.
Related
- Same unhandled-error family as the
client_not_foundsubscriber failure (separate issue) and the reconnect robustness tracked in #2368.
Device / version info
- Samsung Galaxy S25 Ultra; Android Talk 24.0.3 and 25.1.0 Alpha 02 (QA); Nextcloud 34, spreed 24.0.4, standalone signaling + Janus.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with CallActivity.joinRoomAndCall() around line 1557, ApplicationWideCurrentRoomHolder, and WebSocketInstance.processErrorMessage(); also trace the CALLING_TIMEOUT handling around line 2653. Reproduce the stale-session reconnect flow and trace the no_such_room path. Done means a stale session is refreshed through joinRoom, failures reach the call UI, and the call cannot remain in Ringing forever.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, kotlin
- Domain
- audio-video-rtc, mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100