Default video degradation preference by track source, including the backup codec - #1155
Merged
hiroshihorie merged 4 commits intoAug 7, 2026
Merged
Conversation
Camera tracks now default to maintaining framerate, screen share tracks to maintaining resolution, and other sources to balanced, instead of every video track defaulting to maintaining resolution. The preference was also only applied to camera and screen share tracks, so custom sources got whatever WebRTC derived implicitly. It is now applied to every video sender. Degradation preference is a sender-level property, and a backup codec publishes over its own sender, so it needs the preference applied separately. Apply the resolved preference there too, and keep every sender in sync when the preference changes after publish. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
xianshijing-lk
requested review from
cloudwebrtc and
hiroshihorie
as code owners
August 7, 2026 07:58
setDegradationPreference now fans out over simulcastCodecs, whose senders are never cleared and can outlive their peer connection. After a full reconnect, rePublishAllTracks reuses the same track object, so the fanout would call setParameters on a sender from the disposed connection and the resulting platform error aborted the whole republish. Catch and warn instead, matching how setPublishingLayers handles the same call.
setDegradationPreference awaits inside the loop over simulcastCodecs, and addSimulcastTrack can insert into the map during that await when the server requests a backup codec. Iterate over a snapshot to avoid a ConcurrentModificationError.
hiroshihorie
approved these changes
Aug 7, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Aligns Flutter with the behavior landed in client-sdk-android (livekit/client-sdk-android#991). Two related changes.
Source-based defaults
Previously every video track fell back to
maintainResolution, and the preference was only applied to camera and screen share tracks at all:Now
getDefaultDegradationPreference(source)resolves camera →maintainFramerate(smoother video for real-time communication), screen share →maintainResolution(clarity matters for text/UI), other →balanced, and it is applied to every video sender. Custom sources previously got whatever WebRTC derived implicitly from the native source;balancedis the preference the WebRTC spec mandates as the default and is the honest choice when the application declined to declare a motion-vs-detail intent.An explicitly set
degradationPreferencestill wins in all cases — the default only fills a null.Backup codec sender
Degradation preference is a property of the sender, not of the track — a top-level field on
RtpParameters, not per-encoding.publishAdditionalCodecForPublicationadds a second transceiver and therefore a second sender, which was never configured, so the backup encoder resolved a preference implicitly and could adapt along a different axis than the primary.Both senders sink from the same video source, so a diverging backup does not just degrade itself — its restriction is merged onto the shared source and affects the primary too.
setDegradationPreferencenow stores the resolved preference and fans out to every sender, andpublishAdditionalCodecForPublicationapplies it to the backup sender once created. Using the track's stored resolved value means the two encoders cannot disagree.Note simulcast is unaffected — all simulcast encodings live under one sender and already share its preference. Only the backup codec is a separate sender.
Tests
test/options/degradation_preference_test.dartcovers the three source mappings. Full suite passes (379 tests),flutter analyze lib/ test/clean,dart formatclean at the repo's 120-column width.Cross-SDK
client-sdk-js gets the backup-sender half in livekit/client-sdk-js#2040 (its source-based defaults already matched). The Rust SDK already resolves the same defaults and has no backup-codec publish path. Swift follows separately.
🤖 Generated with Claude Code