Skip to content

Add LocalTrackPublication.set(videoPublishOptions:) to update encodings without republishing - #1096

Open
tarsyang wants to merge 1 commit into
livekit:mainfrom
tarsyang:feat/publication-set-video-publish-options
Open

Add LocalTrackPublication.set(videoPublishOptions:) to update encodings without republishing#1096
tarsyang wants to merge 1 commit into
livekit:mainfrom
tarsyang:feat/publication-set-video-publish-options

Conversation

@tarsyang

Copy link
Copy Markdown

Motivation

Publish options are fixed at publish time.
LocalParticipant.set(source:enabled:) returns the existing
publication (unmute path) without applying newly passed
publishOptions, so the only way to change encoding parameters of a
published video track (e.g. lowering maxBitrate while the device is
under thermal pressure, then restoring it) is a full unpublish +
republish. That drops frames, churns the subscriber side, and re-runs
capture setup.

The SDK already updates sender encodings live when capture dimensions
change (recomputeSenderParameters()), so the machinery exists; it has
no public entry point.

API

public func set(videoPublishOptions options: VideoPublishOptions) throws

on LocalTrackPublication:

  • Stores the new options on the track, re-computes encodings for the
    current capture dimensions, applies them to the RTP sender, and
    reports the updated layers to the server (sendUpdateVideoLayers),
    same as the dimensions-change path.
  • The encoding layer structure is fixed at publish time: options that
    would produce a different layer count or rid set (e.g. toggling
    simulcast) throw .invalidState. Without the guard such options
    would deactivate every non-matching layer in
    recomputeSenderParameters()'s rid-matched merge.
  • Throws .invalidState when the publication is not a local video
    track, the participant or room is no longer available, the RTP sender
    is not available, or capture dimensions are not resolved yet.
  • Only per-layer encoding parameters (isActive,
    scaleResolutionDownBy, maxBitrate, maxFps) are re-applied;
    codec preferences, scalability mode, and degradationPreference
    remain as published (documented on the API).

Testing

  • New e2e SetVideoPublishOptionsTests (local livekit-server --dev):
    maxBitrate of a published non-simulcast camera-source track changes
    from 1.7 Mbps to 1.2 Mbps on the live sender without republishing
    (same publication sid, still a single publication), and toggling
    simulcast is rejected with .invalidState.
  • Verified the update test fails when the recompute step is removed.
  • Built for iOS Simulator and macOS.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

… updates

Publish options are currently fixed at publish time: set(source:enabled:)
returns the existing publication (unmute) without applying the new
captureOptions/publishOptions, so the only way to change encoding
parameters (e.g. lowering maxBitrate under thermal pressure) is a full
unpublish + republish, which drops frames and churns subscribers.

The SDK already re-applies encodings live when capture dimensions change
(recomputeSenderParameters). This exposes that path as a public API:
set(videoPublishOptions:) stores the new options on the track,
re-computes encodings for the current dimensions, applies them to the
RTP sender, and reports the updated layers to the server.

The encoding layer structure is fixed at publish time: options that
would produce a different layer count or rid set (e.g. toggling
simulcast) throw .invalidState.
@tarsyang
tarsyang force-pushed the feat/publication-set-video-publish-options branch from a43bd1a to 70880ec Compare August 20, 2026 17:49
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