Skip to content

[VID-1412] Add WebRTC transcoder fields to the SFU protocol - #2156

Draft
atoppi wants to merge 6 commits into
mainfrom
feature/vid-1412-webrtc-transcode-mode-fields
Draft

atoppi wants to merge 6 commits into
mainfrom
feature/vid-1412-webrtc-transcode-mode-fields

Conversation

@atoppi

@atoppi atoppi commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Ticket

Summary

SFU protocol fields for the WebRTC transcoder egress: a broadcaster publishes a single high-quality layer, a transcoder egress joins the call, subscribes to it, and republishes the full simulcast ladder that ordinary subscribers receive.

  • JoinRequest.webrtc_transcode_mode: the broadcaster asks to publish for transcoding. The SFU only honours it with a signed claim in the token.
  • JoinRequest.transcode_of_user_id / transcode_of_user_session_id: the transcoder names the publisher and the one publisher session it serves. Each publishing session (second tab, reconnect whose old session has not timed out) gets its own transcoder.
  • Participant.webrtc_transcode_mode / transcode_of_user_session_id: let a client pair the raw broadcaster with its transcoder and render one tile instead of a broadcaster it can never play.
  • Participant.announced_tracks: what a participant declared for each published track (size, bitrate, frame rate per layer). The transcoder relays the top layer untouched and needs the broadcaster's announcement to describe it honestly.
  • ParticipantSource.PARTICIPANT_SOURCE_WEBRTC_TRANSCODED: the source of the republished ladder.

All additions are new fields / enum values; no existing field changes meaning.

Related

  • video-sfu: GetStream/video-sfu#1753 (pinned to this branch until release)
  • kit: GetStream/kit#1097 (bus events)

🤖 Generated with Claude Code

atoppi and others added 5 commits August 31, 2026 14:10
…Request

Adds the two join-time signals needed for WebRTC broadcaster mode, where a
broadcaster publishes a single high-quality layer and a transcoder egress
republishes the quality ladder into the same call.

- JoinRequest.webrtc_transcode_mode marks a publisher as transcode-mode. The
  SFU hides such a publisher from every subscriber that is not a WebRTC
  transcoder egress, so viewers only ever see the transcoded ladder.
- JoinRequest.transcode_of_user_id is set by the transcoder egress and names
  the publisher it transcodes, so the SFU can keep a creator from being
  subscribed to its own transcode while still allowing co-hosts to subscribe
  to each other's.
- ParticipantSource gains PARTICIPANT_SOURCE_WEBRTC_TRANSCODED, informational
  only, so clients can tell a stream is server-transcoded.

Generated code refreshed with ./generate.sh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The flag reaches the SFU on JoinRequest but stopped there: models.Participant
carries source, so a client can tell that a participant is a transcoder egress,
but nothing said which participants are the raw broadcasters it stands in for.

A client that can see both - and one that pairs them into a single tile - needs
to know. Carried on the participant rather than the track, so it is available
from the roster in JoinResponse, from participant_joined and participant_left,
and from the participant that track_published optionally carries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
transcode_of_user_id names a user, and a user can be in a call more than once -
a second tab, or a reconnect whose old session has not timed out. Every rule
built on it therefore covers all of them at once: a transcoder cannot be told
which session is its own, and a publisher is refused its own transcode even from
a session that is not the one being transcoded.

The session id narrows both. Carried on the join request so the SFU can hold it
against the transcoder, and on the participant so a client can pair a transcoder
with the exact session it stands in for rather than rendering a raw broadcaster
beside the transcoder that carries its media.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
published_tracks says which track types are live, not what they were announced
as. A subscriber that republishes what it receives needs the rest: a WebRTC
transcoder egress relays the broadcaster's top layer untouched, and can only
describe it honestly by repeating what the broadcaster announced for it.

On Participant rather than TrackPublished, because Participant reaches a
subscriber both in call_state at join and on the event for a later publish. The
event alone would miss a track already live, which for a transcoder is the
usual case.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@atoppi
atoppi marked this pull request as draft October 19, 2026 08:58

This branch has not been deployed

No deployments
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