From a002337db11b8be9036f9f87e68a3cbba757cd80 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Wed, 29 Apr 2026 22:43:33 +0530 Subject: [PATCH] Legacy TrackInfo.Simulcast flag. (#4493) * Legacy TrackInfo.Simulcast flag. When AddTrack did not send SimulcastCodecs, the legacy `Simulcast` flag was not set. Fix it by setting the flag when a second layer is published. * staticcheck * use the existing PrimaryReceiver function --- pkg/rtc/mediatrack.go | 1 + pkg/rtc/mediatrackreceiver.go | 28 ++++++++++++++++++++++++---- pkg/rtc/participant.go | 3 ++- pkg/sfu/receiver.go | 14 ++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/pkg/rtc/mediatrack.go b/pkg/rtc/mediatrack.go index 56f8b1b0c..bc4238aa9 100644 --- a/pkg/rtc/mediatrack.go +++ b/pkg/rtc/mediatrack.go @@ -564,6 +564,7 @@ func (t *MediaTrack) AddReceiver(receiver *webrtc.RTPReceiver, track sfu.TrackRe return newCodec, false } + t.MediaTrackReceiver.MaybeSetSimulcast() t.MediaTrackReceiver.SetLayerSsrcsForRid(mimeType, track.RID(), uint32(track.SSRC()), 0) if regressCodec { diff --git a/pkg/rtc/mediatrackreceiver.go b/pkg/rtc/mediatrackreceiver.go index 2fa2650bd..f4643af94 100644 --- a/pkg/rtc/mediatrackreceiver.go +++ b/pkg/rtc/mediatrackreceiver.go @@ -649,6 +649,29 @@ func (t *MediaTrackReceiver) updateTrackInfoOfReceivers() { t.MediaTrackSubscriptions.SetMuted(ti.GetMuted()) } +func (t *MediaTrackReceiver) MaybeSetSimulcast() { + // only primary receiver (i.e. receiver at index 0) for legacy use case + primaryReceiver := t.PrimaryReceiver() + if primaryReceiver == nil { + return + } + if wr, ok := primaryReceiver.(*sfu.WebRTCReceiver); !ok || wr.NumUpTracks() < 2 { + return + } + + t.lock.Lock() + trackInfo := t.TrackInfoClone() + if trackInfo.Simulcast { + t.lock.Unlock() + return + } + trackInfo.Simulcast = true + t.trackInfo.Store(trackInfo) + t.lock.Unlock() + + t.updateTrackInfoOfReceivers() +} + func (t *MediaTrackReceiver) SetLayerSsrcsForRid(mimeType mime.MimeType, rid string, ssrc uint32, repairSSRC uint32) { t.lock.Lock() trackInfo := t.TrackInfoClone() @@ -1058,10 +1081,7 @@ func (t *MediaTrackReceiver) GetQualityForDimension(mimeType mime.MimeType, widt if origSize == 0 { for i := len(mediaSizes) - 1; i >= 0; i-- { if mediaSizes[i].Height > 0 { - origSize = mediaSizes[i].Height - if mediaSizes[i].Width < mediaSizes[i].Height { - origSize = mediaSizes[i].Width - } + origSize = min(mediaSizes[i].Width, mediaSizes[i].Height) break } } diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 433da1442..bffda51b6 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -2290,6 +2290,7 @@ func (p *ParticipantImpl) onMediaTrack(rtcTrack *webrtc.TrackRemote, rtpReceiver ) if !isNewTrack && !publishedTrack.HasPendingCodec() && p.IsReady() { + p.dirty.Store(true) p.listener().OnTrackUpdated(p, publishedTrack) } } @@ -2865,7 +2866,7 @@ func (p *ParticipantImpl) addPendingTrackLocked(req *livekit.AddTrackRequest) *l if len(req.SimulcastCodecs) == 0 { // clients not supporting simulcast codecs, synthesise a codec - videoLayerMode := livekit.VideoLayer_MODE_UNUSED + videoLayerMode := livekit.VideoLayer_ONE_SPATIAL_LAYER_PER_STREAM if p.params.ClientInfo.isOBS() { videoLayerMode = livekit.VideoLayer_ONE_SPATIAL_LAYER_PER_STREAM_INCOMPLETE_RTCP_SR } diff --git a/pkg/sfu/receiver.go b/pkg/sfu/receiver.go index a134e16e7..0bc566332 100644 --- a/pkg/sfu/receiver.go +++ b/pkg/sfu/receiver.go @@ -200,6 +200,20 @@ func (w *WebRTCReceiver) AddUpTrack(track TrackRemote, buff *buffer.Buffer) erro return nil } +func (w *WebRTCReceiver) NumUpTracks() int { + numUpTracks := 0 + + w.upTracksMu.Lock() + for _, track := range w.upTracks { + if track != nil { + numUpTracks++ + } + } + w.upTracksMu.Unlock() + + return numUpTracks +} + func (w *WebRTCReceiver) UpdateTrackInfo(ti *livekit.TrackInfo) { w.ReceiverBase.UpdateTrackInfo(ti) w.connectionStats.UpdateMute(ti.GetMuted())