High Performance Backend (HPB) rejects WebRTC offer: "Session is not in the same call"

Support intro

Sorry to hear you’re facing problems :slightly_frowning_face:

help.nextcloud.com is for home/non-enterprise users. If you’re running a business, paid support can be accessed via portal.nextcloud.com where we can ensure your business keeps running smoothly.

In order to help you as quickly as possible, before clicking Create Topic please provide as much of the below as you can. Feel free to use a pastebin service for logs, otherwise either indent short log examples with four spaces:

example

Or for longer, use three backticks above and below the code snippet:

longer
example
here

Some or all of the below information will be requested if it isn’t supplied; for fastest response please provide as much as you can :heart:

Some useful links to gather information about your Nextcloud Talk installation:
Information about Signaling server: /index.php/index.php/settings/admin/talk#signaling_server
Information about TURN server: /index.php/settings/admin/talk#turn_server
Information about STUN server: /index.php/settings/admin/talk#stun_server

Nextcloud version (eg, 24.0.1): (32.0.5)
Talk Server version (eg, 14.0.2): 22.0.8,
Custom Signaling server configured: yes - 2.0.4
Custom TURN server configured: yes
Custom STUN server configured: yes

In case the web version of Nextcloud Talk is involved:
Operating system (eg, Windows/Ubuntu/…): Linux - Ubuntu
Browser name and version (eg, Chrome v101): 144.0.7557

The issue you are facing: Manual WebRTC signaling via Python fails on High Performance Backend (HPB) with session mismatch.

Is this the first time you’ve seen this error? Yes (developing a custom hardware-accelerated streamer).

Steps to replicate it:

  1. Initialize participant via OCS API.

  2. Connect to standalone signaling server via WebSocket.

  3. Send WebRTC Offer from the script.

  4. HPB logs “Session is not in the same call” and ignores the Offer.

The output of your Nextcloud log in Admin > Logging or errors in nextcloud.log in /var/www/:

OCS API calls return 200/201, no errors in Nextcloud logs.

The output of your Apache/nginx/system log in /var/log/____:

hub.go:2695: Session [WebSocket-ID] is not in the same call as session [OCS-ID], not requesting offer

Your browser log if relevant (javascript console log, network log, etc.):

N/A (Using GStreamer/Python as a native client).

Background & Motivation: I am working on a project to bypass current browser limitations regarding video encoding in Nextcloud Talk. Most browsers are still limited in their ability to use advanced hardware encoders (like AV1 via Intel VAAPI) for real-time WebRTC streams. My goal is to “inject” a high-quality, hardware-encoded stream directly from the OS level using GStreamer, bypassing the browser entirely. This allows for much higher efficiency and quality on low-power devices.

The Issue: I am successfully joining the room via OCS and connecting to the signaling WebSocket. However, the HPB (High Performance Backend) rejects the WebRTC offer because it doesn’t seem to link the OCS session with the WebSocket session.

HPB Log Error: hub.go:2695: Session [WebSocket-ID] is not in the same call as session [OCS-ID], not requesting offer

My Signaling Logic:

  1. Joining via OCS:

Python

# Initializing the participant
ocs_call(s, "POST", f"/ocs/v2.php/apps/spreed/api/v4/room/{TOKEN}/participants/active")
ocs_call(s, "POST", f"/ocs/v2.php/apps/spreed/api/v4/call/{TOKEN}", json={"flags": 1})

# Fetching the assigned SessionID
call_data = ocs_call(s, "GET", f"/ocs/v2.php/apps/spreed/api/v4/call/{TOKEN}")
# (I extract the 'sessionId' where actorId == my_user)

  1. WebSocket Authentication:

Python

# I try to pass the sessionid in the URL and the Hello message
ws_url = f"wss://example.com/spreed?sessionid={session_id}"
ws.send(json.dumps({
    "type": "hello",
    "hello": {
        "version": "1.0",
        "features": ["mcu"],
        "auth": {
            "url": "https://example.com",
            "params": {"userid": user, "ticket": ticket, "sessionid": session_id}
        }
    }
}))

  1. Sending the Offer:

Python

# MCU requires roomType: video
msg = {
    "type": "message",
    "message": {
        "recipient": {"type": "room", "id": TOKEN},
        "data": {
            "type": "offer",
            "roomType": "video",
            "payload": {"type": "offer", "sdp": sdp_text}
        }
    }
}

The behavior: The signaling server receives the offer, but instead of routing it to the MCU/Janus, it logs the “not in the same call” error and drops the message. Sometimes, the OCS API even fails to report the sessionId for the participant I just created.

Is there a specific sequence or a hidden parameter required to properly “handshake” an OCS session into a signaling session so the HPB recognizes the client as an active participant of the call?

I’ve managed to dig deeper into the logs and I have some very specific findings. It seems the issue isn’t in the WebRTC negotiation itself, but in the session association within the signaling server.

The good news: The MCU (Janus) is actually responding to my script’s Offer! I can see a valid Answer being generated in the logs: ... to send {"type":"answer", "sid":"...", "payload":{"sdp":"v=0\r\no=- 1232..."}} ...

The problem: The signaling server (HPB) refuses to deliver this Answer to the subscriber, dropping it with a session mismatch error.

Current logs from signaling service:

Plaintext

hub.go:2746: No MCU subscriber found for session [BROWSER_ID] to send {"type":"answer", ...} to [PYTHON_ID]
hub.go:2695: Session [BROWSER_ID] is not in the same call as session [PYTHON_ID], not requesting offer

What I’ve tried so far: I have synchronized the session IDs by:

  1. Fetching the sessionId from OCS (/ocs/v2.php/apps/spreed/api/v4/call/{token}).

  2. Using this exact ID in the POST request to initiate the call.

  3. Passing this ID in the WebSocket hello params and the room.join message.

Despite both sessions being in the same room and authenticated, the HPB still treats them as if they belong to different call instances.

My question remains: How can I programmatically ensure that a native client (GStreamer/Python) is assigned the same internal Room Session ID as the other participants in the call? Is there a specific OCS flag or a WebSocket handshake requirement I am missing to “link” these sessions?