nextcloud / nextcloud/talk-android

Call stuck on "Ringing" forever after reconnect: stale room session is reused, no_such_room error is dropped

Open
#6,549 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug
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):

  1. Join a call from Android (this caches the room session in ApplicationWideCurrentRoomHolder)
  2. Leave the app sitting (backgrounded / stuck in a broken call) long enough that the server reaps the room session — spreed advertises session-ping-limit: 200 and invalidates sessions that stop pinging
  3. 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
  1. CallActivity.joinRoomAndCall() only calls the joinRoom API when the cached session is empty (CallActivity.kt:1557); otherwise it reuses ApplicationWideCurrentRoomHolder.getInstance().session — which may have been reaped server-side.
  2. The HPB rejects the join: {"type":"error","error":{"code":"no_such_room","message":"The user is not invited to this room."}}
  3. WebSocketInstance.processErrorMessage() handles only no_such_session and hello_expected; no_such_room is logged and dropped — no state change, no retry, no event to the UI.
  4. 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_room in 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_found subscriber 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.