Skip to content

Receiver Reuse During Renegotiation in Mesh Topology #749

@Wandalen

Description

@Wandalen

webrtc-rs fails to properly handle track receivers during SDP renegotiation when the same tracks (SSRCs) appear in multiple negotiation rounds. This causes receivers that are already active to be marked as "NOT HANDLED", breaking media flow in mesh topology scenarios with renegotiation.

Problem Description

Symptoms

During WebRTC renegotiation in mesh topology:

  1. Peers establish initial connections successfully
  2. Tracks flow correctly after initial negotiation
  3. When renegotiation occurs (e.g., adding new tracks, ICE restart)
  4. Existing tracks stop being handled properly
  5. Logs show: "Track NOT HANDLED: mid=X, kind=video, ssrcs=[...]"
  6. Media flow is disrupted despite receivers being active

Root Cause

The start_rtp_receivers() function in peer_connection_internal.rs has logic to check if a receiver has already started receiving:

let receiver = t.receiver().await;
let already_receiving = receiver.have_received().await;

if already_receiving {
    continue; // SKIP this transceiver
}

The Bug: This check does NOT distinguish between:

  1. Initial negotiation: Receiver already receiving → skip it (CORRECT)
  2. Renegotiation: Receiver already receiving → should mark as handled (WRONG - currently skips)

During renegotiation, the same tracks appear in the new SDP offer. The receiver is already active and receiving data. The code incorrectly skips these receivers, marking them as "NOT HANDLED" instead of recognizing they are already properly established.

Why This Happens

Mesh Topology Context:

  • In mesh topology, each peer maintains multiple P2P connections
  • When a new peer joins or leaves, renegotiation occurs
  • The SDP for existing connections includes the same tracks again
  • These tracks have the same SSRCs as before

The Logic Flaw:

// Current behavior (BROKEN):
if receiver.have_received() {
    continue; // Skip - causes track to be unhandled
}
// Start receiver here (never reached for active receivers)

This means active receivers are skipped during renegotiation, never reaching the "track_handled = true" logic.

How to Identify This Issue

Log Signatures

Without Fix:

WARN: Track NOT HANDLED: mid=0, kind=video, ssrcs=[12345]
WARN: Track NOT HANDLED: mid=1, kind=audio, ssrcs=[67890]

These warnings appear during renegotiation for tracks that are actually flowing correctly.

Debugging Steps

  1. Enable verbose logging in start_rtp_receivers()
  2. Trigger renegotiation (add track, ICE restart, etc.)
  3. Check if have_received() returns true for unhandled tracks
  4. Verify the tracks are actually flowing despite "NOT HANDLED" warning

Test Scenario

Setup:

  1. Create mesh topology with 3+ peers (A, B, C)
  2. Establish initial connections with tracks flowing
  3. Trigger renegotiation (e.g., peer A adds a new track)

Without Fix:

  • Existing tracks from B and C marked as "NOT HANDLED"
  • Media flow may be disrupted
  • Renegotiation may fail

With Fix:

  • Existing tracks properly marked as "HANDLED"
  • New tracks started correctly
  • Media flow continues uninterrupted

Testing

Test Cases

  1. Initial negotiation with multiple tracks

    • Verify all tracks marked as HANDLED
    • Verify no duplicate receiver starts
  2. Renegotiation with existing tracks

    • Verify existing tracks marked as HANDLED (not restarted)
    • Verify new tracks properly started
    • Verify media continues flowing for existing tracks
  3. Renegotiation without new tracks (ICE restart)

    • Verify all existing tracks marked as HANDLED
    • Verify no receiver restarts
    • Verify media continues flowing
  4. Mesh topology with 3+ peers

    • Verify initial connections work
    • Add new peer → trigger renegotiation
    • Verify existing peer connections unaffected
    • Verify new peer properly connected

Related Issues

  • Mesh topology connection failures during peer addition/removal
  • "Incoming unhandled RTCP ssrc" warnings (may be related)
  • Media flow interruption during renegotiation
  • Transceiver state management during renegotiation

References

WebRTC Specification

Key Insight from RFC 8829

"When createOffer is called after the session has been established, the
generated description will reflect the current state of the session. The
created offer may reuse existing media descriptions."

This confirms that existing tracks appearing in renegotiation SDPs is expected behavior per the WebRTC specification.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions