Skip to content

DRAFT: mid-based track resolution + preallocated receive media sections - #1112

Draft
xianshijing-lk wants to merge 1 commit into
sxian/CLT-3302/bundle-the-publisher-offer-with-the-joinrequest-offer-with-joinfrom
sxian/CLT-3303/pre-add-receive-media-sections-to-the-initial-publisher-offer
Draft

DRAFT: mid-based track resolution + preallocated receive media sections#1112
xianshijing-lk wants to merge 1 commit into
sxian/CLT-3302/bundle-the-publisher-offer-with-the-joinrequest-offer-with-joinfrom
sxian/CLT-3303/pre-add-receive-media-sections-to-the-initial-publisher-offer

Conversation

@xianshijing-lk

Copy link
Copy Markdown
Contributor

Draft — blocked on a server-side gap. Do not merge. Opened so the implementation and the findings are visible to whoever picks up the SFU conversation.

Stacked on #1111. CLT-3303 (ticket 3) + the prerequisite that turned out to be needed.

What this contains

A — mid-based track resolution. Stores the server's mid → track SID mapping from each session description on the publisher Transport, plumbs it through SignalClientDelegate.didReceiveAnswer, and attaches received media from the answer handler. Matches mid_to_track_id handling in rust-sdks (rtc_session.rs:1345-1348, room/mod.rs:1340-1350), which Swift has never implemented — the field exists in the protos with zero references in Sources/.

B — preallocate 3 audio + 3 video recvonly sections in the initial offer, matching initialMediaSectionsAudio/Video in client-sdk-js and add_recv_media_sections(pc, 3, 3) in rust-sdks. Plus a guard against renegotiating on a zero-count MediaSectionsRequirement.

Why it is blocked

B does not work against either server tested:

Server Result
livekit-server 1.13.1 (local) audioTrack(V1), reconnect(V1) fail — remote track never attaches
Staging Cloud Same two, plus dataChannel(V1) times out

All dual-PC cases pass in both. The failure is specific to single PC with preallocation.

Mechanism, established by instrumenting the wire:

  1. The client offers 6 recvonly sections.
  2. The server answers them with no a=msid (verified: msids: []), because no track is bound yet.
  3. libwebrtc creates receivers for the negotiated sections and fires didAddTrack ×6 with one synthesized UUID stream shared across them.
  4. When a track is later published, no further event arrives — no TR_… track id, no PA_…|TR_… stream, ever.

Normally the binding is delivered by: subscription → server sends MediaSectionsRequirement → client offers → server's answer stamps the msid. Preallocation makes the server compute "0 more sections needed", so it sends (0,0) and never triggers the renegotiation that would stamp the msid. The section stays bound to nothing.

A cannot rescue this either: instrumentation shows the subscriber's midToTrackID is empty on every answer (map=[:] ×25). The populated maps observed belong to clients that are publishing — they map a client's own send sections, not its subscriptions.

So the information needed to identify the media never reaches the client through any channel. This needs a server-side change, not a client one.

What is verified

A validates green standalone. Before enabling B, A alone passed 9/9 E2E, both PC modes against livekit-server 1.13.1. So the resolution path is sound; it is simply inert against current servers, since the mapping is empty for exactly the subscriptions it would resolve.

No dual-PC impact. Every new path is single-PC gated:

Change Reaches dual PC?
addRecvMediaSections via EarlyPublisher.make ❌ single-PC only by construction
addRecvMediaSections via the requirement handler ❌ pre-existing .publisherOnly guard
Zero-requirement guard ❌ same guard
attachReceivedMedia if publisher.singlePCMode
Warning → debug downgrade shared path, but evaluates to .warning in dual PC — identical output

Confirmed empirically: every V0 (Dual PC) case passes on both servers.

Open question for the SFU team

client-sdk-js and rust-sdks both preallocate 3/3 against this same server family. Either browsers re-fire ontrack when a section gains a track (making this native-libwebrtc-specific, consistent with JS skipping preallocation on React Native and citing livekit/rust-sdks#1151), or Rust hits the same wall and it is not covered by its tests. Worth confirming before any client-side follow-up.

If picked up later

Splitting A and B into separate PRs is the better shape — A is independently verifiable against the working path, which is how the failure here was isolated to B. They are together only because that was requested.

🤖 Generated with Claude Code

Not for review. A validates green on its own against livekit-server 1.13.1;
B fails because that server never binds tracks to client-preallocated
sections. Parked pending verification against a newer server / Cloud.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant