From 753fb265750149f88b059daa9b5ffc67bcf3fc7a Mon Sep 17 00:00:00 2001 From: shijing xian Date: Mon, 29 Jun 2026 15:04:13 +0800 Subject: [PATCH 1/6] set x-google-start-bitrate for all codecs and default to MaintainResolution --- libwebrtc/src/rtp_parameters.rs | 44 +++++++ livekit/src/room/options.rs | 114 +++++++++++++++++- .../src/room/participant/local_participant.rs | 20 +++ livekit/src/rtc_engine/peer_transport.rs | 70 +++++++++-- 4 files changed, 234 insertions(+), 14 deletions(-) diff --git a/libwebrtc/src/rtp_parameters.rs b/libwebrtc/src/rtp_parameters.rs index 4c02a7231..caebd1f43 100644 --- a/libwebrtc/src/rtp_parameters.rs +++ b/libwebrtc/src/rtp_parameters.rs @@ -22,6 +22,20 @@ pub enum Priority { High, } +/// Controls how the encoder degrades quality when bandwidth is constrained. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +pub enum DegradationPreference { + /// Degrade framerate to maintain resolution. + MaintainFramerate, + /// Degrade resolution to maintain framerate. + MaintainResolution, + /// Balance between framerate and resolution degradation. + #[default] + Balanced, + /// Disable degradation preference (not recommended). + Disabled, +} + #[derive(Debug, Clone)] pub struct RtpHeaderExtensionParameters { pub uri: String, @@ -43,6 +57,36 @@ pub struct RtpParameters { pub(crate) degradation_preference: i32, } +impl RtpParameters { + /// Sets the degradation preference for this RTP sender. + /// + /// This controls how the encoder trades off between resolution and framerate + /// when bandwidth is constrained. + pub fn set_degradation_preference(&mut self, preference: DegradationPreference) { + self.has_degradation_preference = true; + self.degradation_preference = match preference { + DegradationPreference::Disabled => 0, + DegradationPreference::MaintainFramerate => 1, + DegradationPreference::MaintainResolution => 2, + DegradationPreference::Balanced => 3, + }; + } + + /// Gets the current degradation preference, if set. + pub fn degradation_preference(&self) -> Option { + if !self.has_degradation_preference { + return None; + } + Some(match self.degradation_preference { + 0 => DegradationPreference::Disabled, + 1 => DegradationPreference::MaintainFramerate, + 2 => DegradationPreference::MaintainResolution, + 3 => DegradationPreference::Balanced, + _ => DegradationPreference::Balanced, + }) + } +} + /// Mirrors webrtc_sys RtcpFeedback for round-trip fidelity. #[derive(Debug, Clone, Default)] pub(crate) struct CodecFeedback { diff --git a/livekit/src/room/options.rs b/livekit/src/room/options.rs index c36ae1725..c41d6c154 100644 --- a/livekit/src/room/options.rs +++ b/livekit/src/room/options.rs @@ -17,6 +17,9 @@ use livekit_protocol as proto; use crate::prelude::*; +// Re-export DegradationPreference for users +pub use libwebrtc::rtp_parameters::DegradationPreference; + /// Preferred backend for video encoding when publishing a video track. pub use libwebrtc::rtp_sender::VideoEncoderBackend; @@ -136,6 +139,16 @@ pub struct TrackPublishOptions { /// encoding is produced and that mode is forwarded to libwebrtc to /// enable true SVC for VP9/AV1. Has no effect for VP8/H264. pub scalability_mode: Option, + /// Controls how the encoder trades off between resolution and framerate + /// when bandwidth is constrained. + /// + /// - `MaintainResolution`: Prioritizes resolution, drops frames if needed + /// - `MaintainFramerate`: Prioritizes framerate, reduces resolution if needed + /// - `Balanced`: Balances between both + /// + /// If not set, the SDK will use a smart default based on the track source + /// and resolution (MaintainResolution for screenshare or video >= 540p). + pub degradation_preference: Option, } impl Default for TrackPublishOptions { @@ -154,10 +167,36 @@ impl Default for TrackPublishOptions { frame_metadata_features: FrameMetadataFeatures::default(), video_encoder: VideoEncoderBackend::Auto, scalability_mode: None, + degradation_preference: None, } } } +/// Returns the appropriate degradation preference for a video track. +/// +/// If the user explicitly set a preference in `TrackPublishOptions`, that is returned. +/// Otherwise, defaults to `MaintainResolution` for all video tracks. +/// +/// `MaintainResolution` ensures video clarity is preserved during bandwidth constraints +/// by dropping frames rather than reducing resolution. This prevents the "blurry video" +/// issue that users commonly report during initial connection or network fluctuations. +/// +/// Users who prefer smoother video over clarity can explicitly set `Balanced` or +/// `MaintainFramerate` in their `TrackPublishOptions`. +pub fn get_default_degradation_preference( + options: &TrackPublishOptions, + _height: u32, +) -> DegradationPreference { + // Return user's explicit choice if set + if let Some(pref) = options.degradation_preference { + return pref; + } + + // Default to MaintainResolution for all video tracks to prevent blurry video + // during bandwidth ramp-up or network constraints + DegradationPreference::MaintainResolution +} + impl VideoPreset { pub const fn new(width: u32, height: u32, max_bitrate: u64, max_framerate: f64) -> Self { Self { width, height, encoding: VideoEncoding { max_bitrate, max_framerate } } @@ -515,10 +554,83 @@ pub mod screenshare { #[cfg(test)] mod tests { - use super::{TrackPublishOptions, VideoEncoderBackend}; + use super::{ + get_default_degradation_preference, DegradationPreference, TrackPublishOptions, + VideoEncoderBackend, + }; + use crate::prelude::TrackSource; #[test] fn track_publish_options_default_encoder_is_auto() { assert_eq!(TrackPublishOptions::default().video_encoder, VideoEncoderBackend::Auto); } + + #[test] + fn degradation_preference_defaults_to_none() { + assert_eq!(TrackPublishOptions::default().degradation_preference, None); + } + + #[test] + fn degradation_preference_defaults_to_maintain_resolution() { + // All sources should default to MaintainResolution + let camera_options = TrackPublishOptions { + source: TrackSource::Camera, + ..Default::default() + }; + let screenshare_options = TrackPublishOptions { + source: TrackSource::Screenshare, + ..Default::default() + }; + let default_options = TrackPublishOptions::default(); + + assert_eq!( + get_default_degradation_preference(&camera_options, 1080), + DegradationPreference::MaintainResolution + ); + assert_eq!( + get_default_degradation_preference(&screenshare_options, 1080), + DegradationPreference::MaintainResolution + ); + assert_eq!( + get_default_degradation_preference(&default_options, 720), + DegradationPreference::MaintainResolution + ); + assert_eq!( + get_default_degradation_preference(&default_options, 360), + DegradationPreference::MaintainResolution + ); + } + + #[test] + fn degradation_preference_respects_explicit_user_choice() { + // User explicitly sets MaintainFramerate + let options = TrackPublishOptions { + degradation_preference: Some(DegradationPreference::MaintainFramerate), + ..Default::default() + }; + assert_eq!( + get_default_degradation_preference(&options, 1080), + DegradationPreference::MaintainFramerate + ); + + // User explicitly sets Balanced + let options = TrackPublishOptions { + degradation_preference: Some(DegradationPreference::Balanced), + ..Default::default() + }; + assert_eq!( + get_default_degradation_preference(&options, 1080), + DegradationPreference::Balanced + ); + + // User explicitly sets Disabled + let options = TrackPublishOptions { + degradation_preference: Some(DegradationPreference::Disabled), + ..Default::default() + }; + assert_eq!( + get_default_degradation_preference(&options, 1080), + DegradationPreference::Disabled + ); + } } diff --git a/livekit/src/room/participant/local_participant.rs b/livekit/src/room/participant/local_participant.rs index 12c4ddad9..c3d7f00c6 100644 --- a/livekit/src/room/participant/local_participant.rs +++ b/livekit/src/room/participant/local_participant.rs @@ -433,6 +433,26 @@ impl LocalParticipant { track.set_transceiver(Some(transceiver)); + // Set degradation preference for video tracks + if let LocalTrack::Video(video_track) = &track { + let resolution = video_track.rtc_source().video_resolution(); + let degradation_pref = + options::get_default_degradation_preference(&options, resolution.height); + if let Some(sender) = track.transceiver().map(|t| t.sender()) { + let mut params = sender.parameters(); + params.set_degradation_preference(degradation_pref); + if let Err(e) = sender.set_parameters(params) { + log::warn!("Failed to set degradation preference: {:?}", e); + } else { + log::debug!( + "Set degradation preference to {:?} for video track (height={})", + degradation_pref, + resolution.height + ); + } + } + } + if let LocalTrack::Video(video_track) = &track { let has_timing_subscribers = video_track.has_publish_timing_subscribers(); if needs_video_sender_transformer(&options, has_timing_subscribers) { diff --git a/livekit/src/rtc_engine/peer_transport.rs b/livekit/src/rtc_engine/peer_transport.rs index 78804d051..384a0d01b 100644 --- a/livekit/src/rtc_engine/peer_transport.rs +++ b/livekit/src/rtc_engine/peer_transport.rs @@ -299,6 +299,15 @@ impl PeerTransport { munged } + /// Check if a codec string represents a video codec that should get start bitrate hint. + fn is_video_codec(codec: &str) -> bool { + codec.starts_with("VP8/90000") + || codec.starts_with("VP9/90000") + || codec.starts_with("AV1/90000") + || codec.starts_with("H264/90000") + || codec.starts_with("H265/90000") + } + fn munge_x_google_start_bitrate(sdp: &str, start_bitrate_kbps: u32) -> String { // Detect what line ending the original SDP uses let uses_crlf = sdp.contains("\r\n"); @@ -308,7 +317,7 @@ impl PeerTransport { let lines: Vec<&str> = if uses_crlf { sdp.split("\r\n").collect() } else { sdp.split('\n').collect() }; - // 1) Find VP9/AV1 payload types + // 1) Find all video codec payload types (VP8, VP9, AV1, H264, H265) let mut target_pts: Vec<&str> = Vec::new(); for line in &lines { let l = line.trim(); @@ -316,9 +325,7 @@ impl PeerTransport { let mut it = rest.split_whitespace(); let pt = it.next().unwrap_or(""); let codec = it.next().unwrap_or(""); - if (codec.starts_with("VP9/90000") || codec.starts_with("AV1/90000")) - && !pt.is_empty() - { + if Self::is_video_codec(codec) && !pt.is_empty() { target_pts.push(pt); } } @@ -426,9 +433,13 @@ impl PeerTransport { } } - let is_vp9 = sdp.contains(" VP9/90000"); - let is_av1 = sdp.contains(" AV1/90000"); - if is_vp9 || is_av1 { + // Apply x-google-start-bitrate for all video codecs to improve initial quality + let has_video = sdp.contains(" VP8/90000") + || sdp.contains(" VP9/90000") + || sdp.contains(" AV1/90000") + || sdp.contains(" H264/90000") + || sdp.contains(" H265/90000"); + if has_video { if let Some(start_kbps) = Self::compute_start_bitrate_kbps(inner.max_send_bitrate_bps) { log::info!( "Applying x-google-start-bitrate={} kbps (ultimate_bps={:?})", @@ -438,7 +449,7 @@ impl PeerTransport { let munged = Self::munge_x_google_start_bitrate(&sdp, start_kbps); if munged != sdp { - log::info!("SDP munged successfully (VP9/AV1)"); + log::info!("SDP munged successfully for video codec"); match SessionDescription::parse(&munged, offer.sdp_type()) { Ok(parsed) => offer = parsed, Err(e) => log::warn!( @@ -466,7 +477,21 @@ mod tests { use super::PeerTransport; #[test] - fn no_vp9_or_av1_is_noop() { + fn no_video_codec_is_noop() { + // Audio-only SDP should not be modified + let sdp = "v=0\n\ +o=- 0 0 IN IP4 127.0.0.1\n\ +s=-\n\ +t=0 0\n\ +m=audio 9 UDP/TLS/RTP/SAVPF 111\n\ +a=rtpmap:111 opus/48000/2\n\ +a=fmtp:111 minptime=10;useinbandfec=1\n"; + let out = PeerTransport::munge_x_google_start_bitrate(sdp, 3200); + assert_eq!(out, sdp, "should not change SDP if no video codec present"); + } + + #[test] + fn vp8_with_fmtp_appends_start_bitrate() { let sdp = "v=0\n\ o=- 0 0 IN IP4 127.0.0.1\n\ s=-\n\ @@ -475,7 +500,26 @@ m=video 9 UDP/TLS/RTP/SAVPF 96\n\ a=rtpmap:96 VP8/90000\n\ a=fmtp:96 some=param\n"; let out = PeerTransport::munge_x_google_start_bitrate(sdp, 3200); - assert_eq!(out, sdp, "should not change SDP if no VP9/AV1 present"); + assert!( + out.contains("a=fmtp:96 some=param;x-google-start-bitrate=3200\n"), + "VP8 fmtp should get x-google-start-bitrate appended" + ); + } + + #[test] + fn h264_with_fmtp_appends_start_bitrate() { + let sdp = "v=0\n\ +o=- 0 0 IN IP4 127.0.0.1\n\ +s=-\n\ +t=0 0\n\ +m=video 9 UDP/TLS/RTP/SAVPF 102\n\ +a=rtpmap:102 H264/90000\n\ +a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f\n"; + let out = PeerTransport::munge_x_google_start_bitrate(sdp, 4000); + assert!( + out.contains("a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f;x-google-start-bitrate=4000\n"), + "H264 fmtp should get x-google-start-bitrate appended" + ); } #[test] @@ -546,7 +590,7 @@ a=fmtp:98 profile-id=0"; // <- no final \r\n } #[test] - fn multiple_pts_vp9_and_av1_only_mutate_matching_fmtp_lines() { + fn multiple_video_codecs_all_get_munged() { let sdp = "v=0\n\ o=- 0 0 IN IP4 127.0.0.1\n\ s=-\n\ @@ -559,8 +603,8 @@ a=fmtp:96 foo=bar\n\ a=fmtp:98 profile-id=0\n\ a=fmtp:104 x-google-start-bitrate=1111;baz=qux\n"; let out = PeerTransport::munge_x_google_start_bitrate(sdp, 2222); - // VP8 fmtp should be unchanged - assert!(out.contains("a=fmtp:96 foo=bar\n")); + // VP8 fmtp should get appended + assert!(out.contains("a=fmtp:96 foo=bar;x-google-start-bitrate=2222\n")); // VP9 fmtp should get appended assert!(out.contains("a=fmtp:98 profile-id=0;x-google-start-bitrate=2222\n")); // AV1 fmtp should get replaced From 903dc56c618852e7a204986cb918c1eabde961d9 Mon Sep 17 00:00:00 2001 From: shijing xian Date: Mon, 29 Jun 2026 15:56:42 +0800 Subject: [PATCH 2/6] added ffi changes --- livekit-ffi/protocol/room.proto | 15 +++++++++++++++ livekit-ffi/src/conversion/room.rs | 18 ++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/livekit-ffi/protocol/room.proto b/livekit-ffi/protocol/room.proto index fc3006cc7..6225cce92 100644 --- a/livekit-ffi/protocol/room.proto +++ b/livekit-ffi/protocol/room.proto @@ -323,6 +323,9 @@ message TrackPublishOptions { optional string scalability_mode = 11; // Preferred encoder backend to use when publishing a video track. optional VideoEncoderBackend video_encoder = 12; + // Controls how the encoder trades off between resolution and framerate + // when bandwidth is constrained. Default is MAINTAIN_RESOLUTION. + optional DegradationPreference degradation_preference = 13; } enum VideoEncoderBackend { @@ -334,6 +337,18 @@ enum VideoEncoderBackend { ENCODER_BACKEND_VIDEOTOOLBOX = 5; } +// Controls how the encoder degrades quality when bandwidth is constrained. +enum DegradationPreference { + // Balance between framerate and resolution degradation. + DEGRADATION_PREFERENCE_BALANCED = 0; + // Degrade framerate to maintain resolution. + DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE = 1; + // Degrade resolution to maintain framerate (drop frames to keep clarity). + DEGRADATION_PREFERENCE_MAINTAIN_RESOLUTION = 2; + // Disable degradation preference. + DEGRADATION_PREFERENCE_DISABLED = 3; +} + enum IceTransportType { TRANSPORT_RELAY = 0; TRANSPORT_NOHOST = 1; diff --git a/livekit-ffi/src/conversion/room.rs b/livekit-ffi/src/conversion/room.rs index 9cdf873d8..e8b4905bc 100644 --- a/livekit-ffi/src/conversion/room.rs +++ b/livekit-ffi/src/conversion/room.rs @@ -19,8 +19,8 @@ use livekit::{ E2eeOptions, EncryptionType, }, options::{ - AudioEncoding, FrameMetadataFeatures, TrackPublishOptions, VideoEncoderBackend, - VideoEncoding, + AudioEncoding, DegradationPreference, FrameMetadataFeatures, TrackPublishOptions, + VideoEncoderBackend, VideoEncoding, }, prelude::*, webrtc::{ @@ -66,6 +66,19 @@ fn video_encoder_from_proto(backend: Option) -> Option } } +fn degradation_preference_from_proto(pref: Option) -> Option { + match pref.and_then(|value| proto::DegradationPreference::try_from(value).ok())? { + proto::DegradationPreference::Balanced => Some(DegradationPreference::Balanced), + proto::DegradationPreference::MaintainFramerate => { + Some(DegradationPreference::MaintainFramerate) + } + proto::DegradationPreference::MaintainResolution => { + Some(DegradationPreference::MaintainResolution) + } + proto::DegradationPreference::Disabled => Some(DegradationPreference::Disabled), + } +} + impl From for proto::EncryptionState { fn from(value: EncryptionState) -> Self { match value { @@ -338,6 +351,7 @@ impl From for TrackPublishOptions { video_encoder: video_encoder_from_proto(opts.video_encoder) .unwrap_or(default_publish_options.video_encoder), scalability_mode: opts.scalability_mode, + degradation_preference: degradation_preference_from_proto(opts.degradation_preference), } } } From 27e9b41d15584959d7573c455ff418c238a81cb0 Mon Sep 17 00:00:00 2001 From: shijing xian Date: Mon, 29 Jun 2026 18:09:13 +0800 Subject: [PATCH 3/6] update the start_bitrate multiplier to 0.9 --- livekit/src/rtc_engine/peer_transport.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/livekit/src/rtc_engine/peer_transport.rs b/livekit/src/rtc_engine/peer_transport.rs index 384a0d01b..18a1285e9 100644 --- a/livekit/src/rtc_engine/peer_transport.rs +++ b/livekit/src/rtc_engine/peer_transport.rs @@ -183,8 +183,11 @@ impl PeerTransport { if ultimate_kbps == 0 { return None; } - // JS / Flutter uses ~70% of ultimate; 100% is also reasonable per feedback. - let start_kbps = (ultimate_kbps as f64 * 0.7).round() as u32; + // Use 90% of target bitrate as start bitrate for all codecs. + // Why 90%: Gives ~10% headroom for bandwidth estimation while starting close to target. + // Why same for all codecs: Target bitrate already accounts for codec efficiency + // (e.g., users set lower targets for VP9/AV1 knowing they're more efficient). + let start_kbps = (ultimate_kbps as f64 * 0.9).round() as u32; // A low start-bitrate hint is more likely to hurt than help for VP9/AV1. // If the max is too low, don't inject a start-bitrate hint at all. From ac2f359a29933a7b89ccd506a889cd41cf8d9751 Mon Sep 17 00:00:00 2001 From: shijing xian Date: Mon, 29 Jun 2026 18:09:35 +0800 Subject: [PATCH 4/6] added changeset --- .changeset/improve-initial-video-quality.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .changeset/improve-initial-video-quality.md diff --git a/.changeset/improve-initial-video-quality.md b/.changeset/improve-initial-video-quality.md new file mode 100644 index 000000000..7f7b301e4 --- /dev/null +++ b/.changeset/improve-initial-video-quality.md @@ -0,0 +1,13 @@ +--- +livekit: minor +livekit-ffi: minor +libwebrtc: minor +--- + +Improve initial video quality by setting `x-google-start-bitrate` SDP hint for all video codecs (VP8, VP9, AV1, H264, H265) and defaulting to `MaintainResolution` degradation preference. + +This addresses the issue where video starts blurry for several seconds before improving, by: +1. Telling WebRTC's bandwidth estimator to start at 70% of target bitrate instead of ramping up from ~300kbps +2. Preferring frame drops over resolution reduction when bandwidth is constrained + +The `DegradationPreference` option is now exposed via FFI for Python, C++, Unity, and Node SDKs. From e10087b1d13e91a91f74d5cb520d8d3b7a436a0a Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 29 Jun 2026 10:10:14 +0000 Subject: [PATCH 5/6] generated protobuf --- livekit-ffi-node-bindings/proto/room_pb.d.ts | 43 ++++++++++++++++++++ livekit-ffi-node-bindings/proto/room_pb.js | 17 ++++++++ 2 files changed, 60 insertions(+) diff --git a/livekit-ffi-node-bindings/proto/room_pb.d.ts b/livekit-ffi-node-bindings/proto/room_pb.d.ts index 265b8b8af..debfb9112 100644 --- a/livekit-ffi-node-bindings/proto/room_pb.d.ts +++ b/livekit-ffi-node-bindings/proto/room_pb.d.ts @@ -127,6 +127,41 @@ export declare enum VideoEncoderBackend { ENCODER_BACKEND_VIDEOTOOLBOX = 5, } +/** + * Controls how the encoder degrades quality when bandwidth is constrained. + * + * @generated from enum livekit.proto.DegradationPreference + */ +export declare enum DegradationPreference { + /** + * Balance between framerate and resolution degradation. + * + * @generated from enum value: DEGRADATION_PREFERENCE_BALANCED = 0; + */ + BALANCED = 0, + + /** + * Degrade framerate to maintain resolution. + * + * @generated from enum value: DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE = 1; + */ + MAINTAIN_FRAMERATE = 1, + + /** + * Degrade resolution to maintain framerate (drop frames to keep clarity). + * + * @generated from enum value: DEGRADATION_PREFERENCE_MAINTAIN_RESOLUTION = 2; + */ + MAINTAIN_RESOLUTION = 2, + + /** + * Disable degradation preference. + * + * @generated from enum value: DEGRADATION_PREFERENCE_DISABLED = 3; + */ + DISABLED = 3, +} + /** * @generated from enum livekit.proto.IceTransportType */ @@ -1873,6 +1908,14 @@ export declare class TrackPublishOptions extends Message { */ videoEncoder?: VideoEncoderBackend; + /** + * Controls how the encoder trades off between resolution and framerate + * when bandwidth is constrained. Default is MAINTAIN_RESOLUTION. + * + * @generated from field: optional livekit.proto.DegradationPreference degradation_preference = 13; + */ + degradationPreference?: DegradationPreference; + constructor(data?: PartialMessage); static readonly runtime: typeof proto2; diff --git a/livekit-ffi-node-bindings/proto/room_pb.js b/livekit-ffi-node-bindings/proto/room_pb.js index 1cde1dbb4..bac5cfa49 100644 --- a/livekit-ffi-node-bindings/proto/room_pb.js +++ b/livekit-ffi-node-bindings/proto/room_pb.js @@ -68,6 +68,21 @@ const VideoEncoderBackend = /*@__PURE__*/ proto2.makeEnum( ], ); +/** + * Controls how the encoder degrades quality when bandwidth is constrained. + * + * @generated from enum livekit.proto.DegradationPreference + */ +const DegradationPreference = /*@__PURE__*/ proto2.makeEnum( + "livekit.proto.DegradationPreference", + [ + {no: 0, name: "DEGRADATION_PREFERENCE_BALANCED", localName: "BALANCED"}, + {no: 1, name: "DEGRADATION_PREFERENCE_MAINTAIN_FRAMERATE", localName: "MAINTAIN_FRAMERATE"}, + {no: 2, name: "DEGRADATION_PREFERENCE_MAINTAIN_RESOLUTION", localName: "MAINTAIN_RESOLUTION"}, + {no: 3, name: "DEGRADATION_PREFERENCE_DISABLED", localName: "DISABLED"}, + ], +); + /** * @generated from enum livekit.proto.IceTransportType */ @@ -733,6 +748,7 @@ const TrackPublishOptions = /*@__PURE__*/ proto2.makeMessageType( { no: 10, name: "frame_metadata_features", kind: "enum", T: proto2.getEnumType(FrameMetadataFeature), repeated: true }, { no: 11, name: "scalability_mode", kind: "scalar", T: 9 /* ScalarType.STRING */, opt: true }, { no: 12, name: "video_encoder", kind: "enum", T: proto2.getEnumType(VideoEncoderBackend), opt: true }, + { no: 13, name: "degradation_preference", kind: "enum", T: proto2.getEnumType(DegradationPreference), opt: true }, ], ); @@ -1635,6 +1651,7 @@ const DataTrackUnpublished = /*@__PURE__*/ proto2.makeMessageType( exports.SimulateScenarioKind = SimulateScenarioKind; exports.VideoEncoderBackend = VideoEncoderBackend; +exports.DegradationPreference = DegradationPreference; exports.IceTransportType = IceTransportType; exports.ContinualGatheringPolicy = ContinualGatheringPolicy; exports.ConnectionQuality = ConnectionQuality; From 1e2a4c146e6290a020b6a7010ae69f28a659cc2e Mon Sep 17 00:00:00 2001 From: shijing xian Date: Tue, 30 Jun 2026 10:03:20 +0800 Subject: [PATCH 6/6] run cargo fmt --- livekit/src/room/options.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/livekit/src/room/options.rs b/livekit/src/room/options.rs index c41d6c154..e91c0789a 100644 --- a/livekit/src/room/options.rs +++ b/livekit/src/room/options.rs @@ -573,14 +573,10 @@ mod tests { #[test] fn degradation_preference_defaults_to_maintain_resolution() { // All sources should default to MaintainResolution - let camera_options = TrackPublishOptions { - source: TrackSource::Camera, - ..Default::default() - }; - let screenshare_options = TrackPublishOptions { - source: TrackSource::Screenshare, - ..Default::default() - }; + let camera_options = + TrackPublishOptions { source: TrackSource::Camera, ..Default::default() }; + let screenshare_options = + TrackPublishOptions { source: TrackSource::Screenshare, ..Default::default() }; let default_options = TrackPublishOptions::default(); assert_eq!(