From 01bf96855dae30a951cd11e208bc8d8fb50629ab Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Mon, 23 Jun 2025 12:45:13 -0700 Subject: [PATCH] SVC with RID -> spatial layer mapping (#3754) * SVC with RID -> spatial layer mapping There are cases where an SVC track comes in with a RID. As there is no RID announced in SDP, it maps to invalid layer. Seems to happen with older browsers. * test --- pkg/service/wire_gen.go | 14 +++++++------- pkg/sfu/buffer/videolayerutils.go | 13 +++++++++++++ pkg/sfu/receiver.go | 9 +++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/pkg/service/wire_gen.go b/pkg/service/wire_gen.go index e95eb875d..9d34228ac 100644 --- a/pkg/service/wire_gen.go +++ b/pkg/service/wire_gen.go @@ -89,23 +89,23 @@ func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*Live } rtcEgressLauncher := NewEgressLauncher(egressClient, ioInfoService, objectStore) topicFormatter := rpc.NewTopicFormatter() - v, err := rpc.NewTypedRoomClient(clientParams) + roomClient, err := rpc.NewTypedRoomClient(clientParams) if err != nil { return nil, err } - v2, err := rpc.NewTypedParticipantClient(clientParams) + participantClient, err := rpc.NewTypedParticipantClient(clientParams) if err != nil { return nil, err } - roomService, err := NewRoomService(limitConfig, apiConfig, router, roomAllocator, objectStore, rtcEgressLauncher, topicFormatter, v, v2) + roomService, err := NewRoomService(limitConfig, apiConfig, router, roomAllocator, objectStore, rtcEgressLauncher, topicFormatter, roomClient, participantClient) if err != nil { return nil, err } - v3, err := rpc.NewTypedAgentDispatchInternalClient(clientParams) + agentDispatchInternalClient, err := rpc.NewTypedAgentDispatchInternalClient(clientParams) if err != nil { return nil, err } - agentDispatchService := NewAgentDispatchService(v3, topicFormatter, roomAllocator, router) + agentDispatchService := NewAgentDispatchService(agentDispatchInternalClient, topicFormatter, roomAllocator, router) egressService := NewEgressService(egressClient, rtcEgressLauncher, ioInfoService, roomService) ingressConfig := getIngressConfig(conf) ingressClient, err := rpc.NewIngressClient(clientParams) @@ -120,11 +120,11 @@ func InitializeServer(conf *config.Config, currentNode routing.LocalNode) (*Live } sipService := NewSIPService(sipConfig, nodeID, messageBus, sipClient, sipStore, roomService, telemetryService) rtcService := NewRTCService(conf, roomAllocator, router, telemetryService) - v4, err := rpc.NewTypedRTCRestParticipantClient(clientParams) + rtcRestParticipantClient, err := rpc.NewTypedRTCRestParticipantClient(clientParams) if err != nil { return nil, err } - serviceRTCRestService, err := NewRTCRestService(conf, router, roomAllocator, clientParams, topicFormatter, v4) + serviceRTCRestService, err := NewRTCRestService(conf, router, roomAllocator, clientParams, topicFormatter, rtcRestParticipantClient) if err != nil { return nil, err } diff --git a/pkg/sfu/buffer/videolayerutils.go b/pkg/sfu/buffer/videolayerutils.go index 73af99e59..1b6b3ff2e 100644 --- a/pkg/sfu/buffer/videolayerutils.go +++ b/pkg/sfu/buffer/videolayerutils.go @@ -351,6 +351,19 @@ func GetSpatialLayerForRid(rid string, ti *livekit.TrackInfo) int32 { if len(ti.Layers) == 1 { // single layer without RID return 0 + } else if len(ti.Layers) > 1 { + // RID present in codec, but not specified via signalling + // (happens with older browsers setting a rid for SVC codecs) + hasRid := false + for _, layer := range ti.Layers { + if layer.Rid != "" { + hasRid = true + break + } + } + if !hasRid { + return 0 + } } return InvalidLayerSpatial diff --git a/pkg/sfu/receiver.go b/pkg/sfu/receiver.go index 645146ab1..f4cbd1a9b 100644 --- a/pkg/sfu/receiver.go +++ b/pkg/sfu/receiver.go @@ -43,6 +43,7 @@ var ( ErrDownTrackAlreadyExist = errors.New("DownTrack already exist") ErrBufferNotFound = errors.New("buffer not found") ErrDuplicateLayer = errors.New("duplicate layer") + ErrInvalidLayer = errors.New("invalid layer") ) // -------------------------------------- @@ -384,6 +385,14 @@ func (w *WebRTCReceiver) AddUpTrack(track TrackRemote, buff *buffer.Buffer) erro if w.Kind() == webrtc.RTPCodecTypeVideo && !w.isSVC { layer = buffer.GetSpatialLayerForRid(track.RID(), w.trackInfo.Load()) } + if layer < 0 { + w.logger.Warnw( + "invalid layer", nil, + "rid", track.RID(), + "trackInfo", logger.Proto(w.trackInfo.Load()), + ) + return ErrInvalidLayer + } buff.SetLogger(w.logger.WithValues("layer", layer)) buff.SetAudioLevelParams(audio.AudioLevelParams{ Config: w.audioConfig.AudioLevelConfig,