Skip to content

Change default degradation preference by video source - #991

Open
xianshijing-lk wants to merge 2 commits into
mainfrom
sxian/CLT-3068/change_default_degrade_preference_mode_based_on_video_source
Open

Change default degradation preference by video source#991
xianshijing-lk wants to merge 2 commits into
mainfrom
sxian/CLT-3068/change_default_degrade_preference_mode_based_on_video_source

Conversation

@xianshijing-lk

Copy link
Copy Markdown
Contributor

Summary

  • Default video degradation preference by track source when degradationPreference is not explicitly set.
  • Camera tracks now default to MAINTAIN_FRAMERATE.
  • Screen share tracks now default to MAINTAIN_RESOLUTION.
  • Other video sources default to BALANCED.
  • Preserve explicit degradationPreference overrides.
  • Add tests for camera and screen share defaults.

Testing

  • git diff --check
  • Focused Gradle test attempted, but compile failed due existing generated protocol reference issues (AGENT_ERROR, PUBLISH_DATA_TRACK_RESPONSE, clientProtocol, etc.).

@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b3cf152

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
client-sdk-android Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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

Copy link
Copy Markdown

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

@xianshijing-lk xianshijing-lk left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@adrian-niculescu @davidliu , I broke down default degradation preference changes from #973 to keep the discussion more focused.

Please review this PR.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Diffuse output:

OLD: diffuse-source-file
NEW: livekit-android-sdk-release.aar

 AAR      │ old      │ new      │ diff     
──────────┼──────────┼──────────┼──────────
      jar │  2.7 MiB │  2.7 MiB │ +1.5 KiB 
 manifest │  1.5 KiB │  1.5 KiB │      0 B 
 lint-jar │ 12.7 KiB │ 12.7 KiB │      0 B 
    other │  1.9 KiB │  1.9 KiB │      0 B 
──────────┼──────────┼──────────┼──────────
    total │  2.7 MiB │  2.7 MiB │ +1.5 KiB 

 JAR     │ old   │ new   │ diff       
─────────┼───────┼───────┼────────────
 classes │  1504 │  1505 │ +1 (+1 -0) 
 methods │ 20222 │ 20225 │ +3 (+7 -4) 
  fields │  5166 │  5174 │ +8 (+8 -0)
AAR
 size    │ diff     │ path          
─────────┼──────────┼───────────────
 2.7 MiB │ +1.5 KiB │ ∆ classes.jar 
─────────┼──────────┼───────────────
 2.7 MiB │ +1.5 KiB │ (total)
JAR
CLASSES:

   old  │ new  │ diff       
  ──────┼──────┼────────────
   1504 │ 1505 │ +1 (+1 -0) 
  
  + io.livekit.android.room.participant.LocalParticipantKt_WhenMappings
  

METHODS:

   old   │ new   │ diff       
  ───────┼───────┼────────────
   20222 │ 20225 │ +3 (+7 -4) 
  
  + io.livekit.android.room.participant.LocalParticipant access_publishTrackImpl_negotiate(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, Track_Source, LocalParticipant_PublishListener, Continuation) → Object
  + io.livekit.android.room.participant.LocalParticipant publishTrackImpl_negotiate(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, Track_Source, LocalParticipant_PublishListener, Continuation) → Object
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4 <init>(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, Track_Source, LocalParticipant_PublishListener, LivekitRtc_AddTrackRequest_Builder, Continuation)
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4_negotiateJob_1 <init>(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, Track_Source, LocalParticipant_PublishListener, Continuation)
  + io.livekit.android.room.participant.LocalParticipantKt access_getDefaultDegradationPreference(Track_Source) → RtpParameters_DegradationPreference
  + io.livekit.android.room.participant.LocalParticipantKt getDefaultDegradationPreference(Track_Source) → RtpParameters_DegradationPreference
  + io.livekit.android.room.participant.LocalParticipantKt_WhenMappings <clinit>()
  
  - io.livekit.android.room.participant.LocalParticipant access_publishTrackImpl_negotiate(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, LocalParticipant_PublishListener, Continuation) → Object
  - io.livekit.android.room.participant.LocalParticipant publishTrackImpl_negotiate(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, LocalParticipant_PublishListener, Continuation) → Object
  - io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4 <init>(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, LocalParticipant_PublishListener, LivekitRtc_AddTrackRequest_Builder, Continuation)
  - io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4_negotiateJob_1 <init>(LocalParticipant, Ref_ObjectRef, Track, Ref_ObjectRef, String, LocalParticipant_PublishListener, Continuation)
  

FIELDS:

   old  │ new  │ diff       
  ──────┼──────┼────────────
   5166 │ 5174 │ +8 (+8 -0) 
  
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_1 L_6: Object
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4 _trackSource: Track_Source
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_4_negotiateJob_1 _trackSource: Track_Source
  + io.livekit.android.room.participant.LocalParticipant_publishTrackImpl_negotiate_1 L_6: Object
  + io.livekit.android.room.participant.LocalParticipantKt_WhenMappings _EnumSwitchMapping_0: int[]
  + livekit.org.webrtc.RtpParameters_DegradationPreference BALANCED: RtpParameters_DegradationPreference
  + livekit.org.webrtc.RtpParameters_DegradationPreference MAINTAIN_FRAMERATE: RtpParameters_DegradationPreference
  + livekit.org.webrtc.RtpParameters_DegradationPreference MAINTAIN_RESOLUTION: RtpParameters_DegradationPreference

@adrian-niculescu adrian-niculescu 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.

The backup codec sender never gets the preference.

publishAdditionalCodecForTrack creates a second transceiver over the same rtcTrack and never touches sender.parameters, so that sender keeps resolving implicitly from the native source's is_screencast. Consequences:

  • Camera and screen share stay media-equivalent across the two encoders as long as options.source agrees with track.options.isScreencast. A screencast-backed track published with source = CAMERA now diverges: primary MAINTAIN_FRAMERATE, backup MAINTAIN_RESOLUTION.
  • An application-supplied degradationPreference reaches the primary encoder only.
  • The new BALANCED fallback reaches the primary encoder only.

The explicit-override half predates this PR and JS has the same gap, but this PR is what makes a resolved preference a value worth carrying, so applying it to the backup sender belongs here.

return when (source) {
Track.Source.CAMERA -> RtpParameters.DegradationPreference.MAINTAIN_FRAMERATE
Track.Source.SCREEN_SHARE -> RtpParameters.DegradationPreference.MAINTAIN_RESOLUTION
else -> RtpParameters.DegradationPreference.BALANCED

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.

A custom feed published with VideoTrackPublishOptions(source = Track.Source.UNKNOWN) lands here, and this overwrites what libwebrtc would have derived from the native source: a screencast-backed track goes MAINTAIN_RESOLUTION to BALANCED, a camera-like one MAINTAIN_FRAMERATE to BALANCED. track.options.isScreencast already carries that information. BALANCED is also the mode libwebrtc keeps behind the WebRTC-Video-BalancedDegradation field trial, with the in-tree note that it "needs to be tuned first".

Proposal:

private fun getDefaultDegradationPreference(source: Track.Source): RtpParameters.DegradationPreference? {
    return when (source) {
        Track.Source.CAMERA -> RtpParameters.DegradationPreference.MAINTAIN_FRAMERATE
        Track.Source.SCREEN_SHARE -> RtpParameters.DegradationPreference.MAINTAIN_RESOLUTION
        else -> null
    }
}

The KDoc bullet above changes with it. Not a blocker: JS made the same BALANCED choice deliberately, so if this is cross-SDK alignment it stands, but the argument applies there too.

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.

3 participants