From ad157047b716d16a938963c3a67c4acf9e8be3c9 Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 26 Feb 2026 14:41:24 -0800 Subject: [PATCH 1/8] add stripping of user timestamp trailer in SFU for older subscriber SDK versions --- go.mod | 2 + go.sum | 2 - pkg/rtc/mediatrackreceiver.go | 4 + pkg/rtc/subscribedtrack.go | 25 ++--- pkg/rtc/types/interfaces.go | 1 + pkg/rtc/types/protocol_version.go | 6 +- .../typesfakes/fake_local_media_track.go | 63 ++++++++++++ pkg/rtc/types/typesfakes/fake_media_track.go | 63 ++++++++++++ pkg/sfu/downtrack.go | 28 ++++++ pkg/sfu/downtrack_strip_test.go | 95 +++++++++++++++++++ 10 files changed, 275 insertions(+), 14 deletions(-) create mode 100644 pkg/sfu/downtrack_strip_test.go diff --git a/go.mod b/go.mod index b3650196b..89d5b5ecd 100644 --- a/go.mod +++ b/go.mod @@ -156,3 +156,5 @@ require ( google.golang.org/grpc v1.78.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) + +replace github.com/livekit/protocol => ../protocol diff --git a/go.sum b/go.sum index aaad68719..4eee2d18d 100644 --- a/go.sum +++ b/go.sum @@ -177,8 +177,6 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260113174415-2e8ba344fca3 h1:v1Xc/q/547TjLX7Nw5y2vXNnmV0XYFAbhTJrtErQeDA= github.com/livekit/mediatransportutil v0.0.0-20260113174415-2e8ba344fca3/go.mod h1:QBx/KHV6Vv00ggibg/WrOlqrkTciEA2Hc9DGWYr3Q9U= -github.com/livekit/protocol v1.44.1-0.20260211042324-3688e156dc7e h1:5rYmMte7Y50xQphcyFOnTSdTImkmAL0MpTevVwJejpg= -github.com/livekit/protocol v1.44.1-0.20260211042324-3688e156dc7e/go.mod h1:BLJHYHErQTu3+fnmfGrzN6CbHxNYiooFIIYGYxXxotw= github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= github.com/mackerelio/go-osstat v0.2.6 h1:gs4U8BZeS1tjrL08tt5VUliVvSWP26Ai2Ob8Lr7f2i0= diff --git a/pkg/rtc/mediatrackreceiver.go b/pkg/rtc/mediatrackreceiver.go index b1c0152d7..f265772a2 100644 --- a/pkg/rtc/mediatrackreceiver.go +++ b/pkg/rtc/mediatrackreceiver.go @@ -519,6 +519,10 @@ func (t *MediaTrackReceiver) IsEncrypted() bool { return t.TrackInfo().Encryption != livekit.Encryption_NONE } +func (t *MediaTrackReceiver) HasUserTimestamp() bool { + return t.TrackInfo().GetHasUserTimestamp() +} + func (t *MediaTrackReceiver) AddOnClose(f func(isExpectedToResume bool)) { if f == nil { return diff --git a/pkg/rtc/subscribedtrack.go b/pkg/rtc/subscribedtrack.go index 6f566b81e..bcfe6c7c5 100644 --- a/pkg/rtc/subscribedtrack.go +++ b/pkg/rtc/subscribedtrack.go @@ -129,18 +129,21 @@ func NewSubscribedTrack(params SubscribedTrackParams) (*SubscribedTrack, error) if isEncrypted { trailer = params.Subscriber.GetTrailer() } + stripUserTimestamp := params.MediaTrack.HasUserTimestamp() && + !params.Subscriber.ProtocolVersion().SupportsUserTimestampStripping() downTrack, err := sfu.NewDownTrack(sfu.DownTrackParams{ - Codecs: codecs, - IsEncrypted: isEncrypted, - Source: params.MediaTrack.Source(), - Receiver: params.WrappedReceiver, - BufferFactory: params.Subscriber.GetBufferFactory(), - SubID: params.Subscriber.ID(), - StreamID: streamID, - MaxTrack: maxTrack, - PlayoutDelayLimit: params.Subscriber.GetPlayoutDelayConfig(), - Pacer: params.Subscriber.GetPacer(), - Trailer: trailer, + Codecs: codecs, + IsEncrypted: isEncrypted, + Source: params.MediaTrack.Source(), + Receiver: params.WrappedReceiver, + BufferFactory: params.Subscriber.GetBufferFactory(), + SubID: params.Subscriber.ID(), + StreamID: streamID, + MaxTrack: maxTrack, + PlayoutDelayLimit: params.Subscriber.GetPlayoutDelayConfig(), + Pacer: params.Subscriber.GetPacer(), + Trailer: trailer, + StripUserTimestamp: stripUserTimestamp, Logger: LoggerWithTrack( params.Subscriber.GetLogger().WithComponent(sutils.ComponentSub), params.MediaTrack.ID(), diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index ba492a8c3..f901e5619 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -760,6 +760,7 @@ type MediaTrack interface { ClearAllReceivers(isExpectedToResume bool) IsEncrypted() bool + HasUserTimestamp() bool } //counterfeiter:generate . LocalMediaTrack diff --git a/pkg/rtc/types/protocol_version.go b/pkg/rtc/types/protocol_version.go index e7f569854..b97c7bfae 100644 --- a/pkg/rtc/types/protocol_version.go +++ b/pkg/rtc/types/protocol_version.go @@ -16,7 +16,7 @@ package types type ProtocolVersion int -const CurrentProtocol = 16 +const CurrentProtocol = 17 func (v ProtocolVersion) SupportsPackedStreamId() bool { return v > 0 @@ -99,3 +99,7 @@ func (v ProtocolVersion) SupportsNonErrorSignalResponse() bool { func (v ProtocolVersion) SupportsMoving() bool { return v > 15 } + +func (v ProtocolVersion) SupportsUserTimestampStripping() bool { + return v > 16 +} diff --git a/pkg/rtc/types/typesfakes/fake_local_media_track.go b/pkg/rtc/types/typesfakes/fake_local_media_track.go index a06094ec2..81eeebd11 100644 --- a/pkg/rtc/types/typesfakes/fake_local_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_local_media_track.go @@ -146,6 +146,16 @@ type FakeLocalMediaTrack struct { hasSignalCidReturnsOnCall map[int]struct { result1 bool } + HasUserTimestampStub func() bool + hasUserTimestampMutex sync.RWMutex + hasUserTimestampArgsForCall []struct { + } + hasUserTimestampReturns struct { + result1 bool + } + hasUserTimestampReturnsOnCall map[int]struct { + result1 bool + } IDStub func() livekit.TrackID iDMutex sync.RWMutex iDArgsForCall []struct { @@ -1072,6 +1082,59 @@ func (fake *FakeLocalMediaTrack) HasSignalCidReturnsOnCall(i int, result1 bool) }{result1} } +func (fake *FakeLocalMediaTrack) HasUserTimestamp() bool { + fake.hasUserTimestampMutex.Lock() + ret, specificReturn := fake.hasUserTimestampReturnsOnCall[len(fake.hasUserTimestampArgsForCall)] + fake.hasUserTimestampArgsForCall = append(fake.hasUserTimestampArgsForCall, struct { + }{}) + stub := fake.HasUserTimestampStub + fakeReturns := fake.hasUserTimestampReturns + fake.recordInvocation("HasUserTimestamp", []interface{}{}) + fake.hasUserTimestampMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeLocalMediaTrack) HasUserTimestampCallCount() int { + fake.hasUserTimestampMutex.RLock() + defer fake.hasUserTimestampMutex.RUnlock() + return len(fake.hasUserTimestampArgsForCall) +} + +func (fake *FakeLocalMediaTrack) HasUserTimestampCalls(stub func() bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = stub +} + +func (fake *FakeLocalMediaTrack) HasUserTimestampReturns(result1 bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = nil + fake.hasUserTimestampReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeLocalMediaTrack) HasUserTimestampReturnsOnCall(i int, result1 bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = nil + if fake.hasUserTimestampReturnsOnCall == nil { + fake.hasUserTimestampReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.hasUserTimestampReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeLocalMediaTrack) ID() livekit.TrackID { fake.iDMutex.Lock() ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)] diff --git a/pkg/rtc/types/typesfakes/fake_media_track.go b/pkg/rtc/types/typesfakes/fake_media_track.go index 95a4d0649..c815a5dfe 100644 --- a/pkg/rtc/types/typesfakes/fake_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_media_track.go @@ -98,6 +98,16 @@ type FakeMediaTrack struct { getTemporalLayerForSpatialFpsReturnsOnCall map[int]struct { result1 int32 } + HasUserTimestampStub func() bool + hasUserTimestampMutex sync.RWMutex + hasUserTimestampArgsForCall []struct { + } + hasUserTimestampReturns struct { + result1 bool + } + hasUserTimestampReturnsOnCall map[int]struct { + result1 bool + } IDStub func() livekit.TrackID iDMutex sync.RWMutex iDArgsForCall []struct { @@ -742,6 +752,59 @@ func (fake *FakeMediaTrack) GetTemporalLayerForSpatialFpsReturnsOnCall(i int, re }{result1} } +func (fake *FakeMediaTrack) HasUserTimestamp() bool { + fake.hasUserTimestampMutex.Lock() + ret, specificReturn := fake.hasUserTimestampReturnsOnCall[len(fake.hasUserTimestampArgsForCall)] + fake.hasUserTimestampArgsForCall = append(fake.hasUserTimestampArgsForCall, struct { + }{}) + stub := fake.HasUserTimestampStub + fakeReturns := fake.hasUserTimestampReturns + fake.recordInvocation("HasUserTimestamp", []interface{}{}) + fake.hasUserTimestampMutex.Unlock() + if stub != nil { + return stub() + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeMediaTrack) HasUserTimestampCallCount() int { + fake.hasUserTimestampMutex.RLock() + defer fake.hasUserTimestampMutex.RUnlock() + return len(fake.hasUserTimestampArgsForCall) +} + +func (fake *FakeMediaTrack) HasUserTimestampCalls(stub func() bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = stub +} + +func (fake *FakeMediaTrack) HasUserTimestampReturns(result1 bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = nil + fake.hasUserTimestampReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeMediaTrack) HasUserTimestampReturnsOnCall(i int, result1 bool) { + fake.hasUserTimestampMutex.Lock() + defer fake.hasUserTimestampMutex.Unlock() + fake.HasUserTimestampStub = nil + if fake.hasUserTimestampReturnsOnCall == nil { + fake.hasUserTimestampReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.hasUserTimestampReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeMediaTrack) ID() livekit.TrackID { fake.iDMutex.Lock() ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)] diff --git a/pkg/sfu/downtrack.go b/pkg/sfu/downtrack.go index 849b9bad5..759616e00 100644 --- a/pkg/sfu/downtrack.go +++ b/pkg/sfu/downtrack.go @@ -293,6 +293,21 @@ var _ TrackSender = (*DownTrack)(nil) type ReceiverReportListener func(dt *DownTrack, report *rtcp.ReceiverReport) +var userTimestampMagic = [4]byte{'L', 'K', 'T', 'S'} + +const userTimestampTrailerSize = 12 + +func stripUserTimestampTrailer(payload []byte, marker bool) int { + if !marker || len(payload) < userTimestampTrailerSize { + return 0 + } + tail := payload[len(payload)-4:] + if tail[0] == userTimestampMagic[0] && tail[1] == userTimestampMagic[1] && tail[2] == userTimestampMagic[2] && tail[3] == userTimestampMagic[3] { + return userTimestampTrailerSize + } + return 0 +} + type DownTrackParams struct { Codecs []webrtc.RTPCodecParameters IsEncrypted bool @@ -309,6 +324,7 @@ type DownTrackParams struct { RTCPWriter func([]rtcp.Packet) error DisableSenderReportPassThrough bool SupportsCodecChange bool + StripUserTimestamp bool Listener DownTrackListener } @@ -1057,6 +1073,12 @@ func (d *DownTrack) WriteRTP(extPkt *buffer.ExtPacket, layer int32) int32 { } payload = payload[:len(tp.codecBytes)+n] + if d.params.StripUserTimestamp { + if strip := stripUserTimestampTrailer(payload, tp.marker); strip > 0 { + payload = payload[:len(payload)-strip] + } + } + // translate RTP header hdr := RTPHeaderFactory.Get().(*rtp.Header) *hdr = rtp.Header{ @@ -2175,6 +2197,12 @@ func (d *DownTrack) retransmitPacket(epm *extPacketMeta, sourcePkt []byte, isPro payload = payload[:rtxOffset+int(epm.numCodecBytesOut)+len(pkt.Payload)-int(epm.numCodecBytesIn)] } + if d.params.StripUserTimestamp { + if strip := stripUserTimestampTrailer(payload[rtxOffset:], epm.marker); strip > 0 { + payload = payload[:len(payload)-strip] + } + } + headerSize := hdr.MarshalSize() var ( payloadSize, paddingSize int diff --git a/pkg/sfu/downtrack_strip_test.go b/pkg/sfu/downtrack_strip_test.go new file mode 100644 index 000000000..86f2fa0b7 --- /dev/null +++ b/pkg/sfu/downtrack_strip_test.go @@ -0,0 +1,95 @@ +// Copyright 2023 LiveKit, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package sfu + +import ( + "encoding/binary" + "testing" +) + +func makePayloadWithTrailer(videoLen int, timestampUs int64) []byte { + payload := make([]byte, videoLen+userTimestampTrailerSize) + for i := 0; i < videoLen; i++ { + payload[i] = byte(i) + } + binary.BigEndian.PutUint64(payload[videoLen:], uint64(timestampUs)) + copy(payload[videoLen+8:], userTimestampMagic[:]) + return payload +} + +func TestStripUserTimestampTrailer(t *testing.T) { + tests := []struct { + name string + payload []byte + marker bool + wantStrip int + }{ + { + name: "marker set with valid trailer", + payload: makePayloadWithTrailer(20, 1700000000000000), + marker: true, + wantStrip: userTimestampTrailerSize, + }, + { + name: "marker not set with valid trailer", + payload: makePayloadWithTrailer(20, 1700000000000000), + marker: false, + wantStrip: 0, + }, + { + name: "marker set without magic", + payload: make([]byte, 32), + marker: true, + wantStrip: 0, + }, + { + name: "marker set but payload too short", + payload: []byte{0x4C, 0x4B, 0x54, 0x53, 0x00, 0x00, 0x00, 0x00}, + marker: true, + wantStrip: 0, + }, + { + name: "marker set with partial magic mismatch", + payload: func() []byte { + p := makePayloadWithTrailer(20, 1700000000000000) + p[len(p)-1] = 'x' // corrupt 'S' -> 'x' + return p + }(), + marker: true, + wantStrip: 0, + }, + { + name: "exactly trailer size with valid magic", + payload: makePayloadWithTrailer(0, 42), + marker: true, + wantStrip: userTimestampTrailerSize, + }, + { + name: "empty payload", + payload: []byte{}, + marker: true, + wantStrip: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := stripUserTimestampTrailer(tt.payload, tt.marker) + if got != tt.wantStrip { + t.Errorf("stripUserTimestampTrailer() = %d, want %d", got, tt.wantStrip) + } + }) + } +} From d51bd916a07fa05b313f686ab23208e33feb13fe Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 26 Feb 2026 14:48:34 -0800 Subject: [PATCH 2/8] rename for clarity --- pkg/rtc/subscribedtrack.go | 2 +- pkg/rtc/types/protocol_version.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/rtc/subscribedtrack.go b/pkg/rtc/subscribedtrack.go index bcfe6c7c5..c1f59a18a 100644 --- a/pkg/rtc/subscribedtrack.go +++ b/pkg/rtc/subscribedtrack.go @@ -130,7 +130,7 @@ func NewSubscribedTrack(params SubscribedTrackParams) (*SubscribedTrack, error) trailer = params.Subscriber.GetTrailer() } stripUserTimestamp := params.MediaTrack.HasUserTimestamp() && - !params.Subscriber.ProtocolVersion().SupportsUserTimestampStripping() + !params.Subscriber.ProtocolVersion().SupportsUserTimestamp() downTrack, err := sfu.NewDownTrack(sfu.DownTrackParams{ Codecs: codecs, IsEncrypted: isEncrypted, diff --git a/pkg/rtc/types/protocol_version.go b/pkg/rtc/types/protocol_version.go index b97c7bfae..0034c4527 100644 --- a/pkg/rtc/types/protocol_version.go +++ b/pkg/rtc/types/protocol_version.go @@ -100,6 +100,6 @@ func (v ProtocolVersion) SupportsMoving() bool { return v > 15 } -func (v ProtocolVersion) SupportsUserTimestampStripping() bool { +func (v ProtocolVersion) SupportsUserTimestamp() bool { return v > 16 } From f20d322b97c4d9342f0fd1edbd0853ab4ed1c0e2 Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 26 Feb 2026 14:51:49 -0800 Subject: [PATCH 3/8] add comments --- pkg/sfu/downtrack.go | 3 +++ pkg/sfu/downtrack_strip_test.go | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/sfu/downtrack.go b/pkg/sfu/downtrack.go index 759616e00..afed2e203 100644 --- a/pkg/sfu/downtrack.go +++ b/pkg/sfu/downtrack.go @@ -297,6 +297,9 @@ var userTimestampMagic = [4]byte{'L', 'K', 'T', 'S'} const userTimestampTrailerSize = 12 +// stripUserTimestampTrailer returns the number of bytes to strip from the end of +// an RTP payload if it contains a user-timestamp trailer (magic suffix "LKTS"). +// Trailers only appear on marker packets; returns 0 if absent or ineligible. func stripUserTimestampTrailer(payload []byte, marker bool) int { if !marker || len(payload) < userTimestampTrailerSize { return 0 diff --git a/pkg/sfu/downtrack_strip_test.go b/pkg/sfu/downtrack_strip_test.go index 86f2fa0b7..174098613 100644 --- a/pkg/sfu/downtrack_strip_test.go +++ b/pkg/sfu/downtrack_strip_test.go @@ -1,4 +1,4 @@ -// Copyright 2023 LiveKit, Inc. +// Copyright 2026 LiveKit, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -31,9 +31,9 @@ func makePayloadWithTrailer(videoLen int, timestampUs int64) []byte { func TestStripUserTimestampTrailer(t *testing.T) { tests := []struct { - name string - payload []byte - marker bool + name string + payload []byte + marker bool wantStrip int }{ { From 36fb98555e4cb0bca0843d3179f9f5abfd03b88a Mon Sep 17 00:00:00 2001 From: David Chen Date: Thu, 26 Feb 2026 16:49:35 -0800 Subject: [PATCH 4/8] remove local ref for testing --- go.mod | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 89d5b5ecd..7f44f10d4 100644 --- a/go.mod +++ b/go.mod @@ -155,6 +155,4 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect -) - -replace github.com/livekit/protocol => ../protocol +) \ No newline at end of file From b845aa3a9a8b846050a3952fc824184ad755ebb6 Mon Sep 17 00:00:00 2001 From: David Chen Date: Fri, 27 Feb 2026 16:10:40 -0800 Subject: [PATCH 5/8] switch to RTPTrailerFeatures --- pkg/rtc/mediatrackreceiver.go | 4 +- pkg/rtc/participant.go | 29 ++-- pkg/rtc/subscribedtrack.go | 2 +- pkg/rtc/types/interfaces.go | 2 +- .../typesfakes/fake_local_media_track.go | 135 ++++++++++-------- pkg/rtc/types/typesfakes/fake_media_track.go | 79 +++++----- 6 files changed, 135 insertions(+), 116 deletions(-) diff --git a/pkg/rtc/mediatrackreceiver.go b/pkg/rtc/mediatrackreceiver.go index f265772a2..377a6900f 100644 --- a/pkg/rtc/mediatrackreceiver.go +++ b/pkg/rtc/mediatrackreceiver.go @@ -519,8 +519,8 @@ func (t *MediaTrackReceiver) IsEncrypted() bool { return t.TrackInfo().Encryption != livekit.Encryption_NONE } -func (t *MediaTrackReceiver) HasUserTimestamp() bool { - return t.TrackInfo().GetHasUserTimestamp() +func (t *MediaTrackReceiver) HasRTPTrailerFeature(feature livekit.RTPTrailerFeature) bool { + return slices.Contains(t.TrackInfo().GetRtpTrailerFeatures(), feature) } func (t *MediaTrackReceiver) AddOnClose(f func(isExpectedToResume bool)) { diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index a50fa0411..9124ad3b6 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -2819,20 +2819,21 @@ func (p *ParticipantImpl) addPendingTrackLocked(req *livekit.AddTrackRequest) *l } ti := &livekit.TrackInfo{ - Type: req.Type, - Name: req.Name, - Width: req.Width, - Height: req.Height, - Muted: req.Muted, - DisableDtx: req.DisableDtx, - Source: req.Source, - Layers: cloneLayers(req.Layers), - DisableRed: req.DisableRed, - Stereo: req.Stereo, - Encryption: req.Encryption, - Stream: req.Stream, - BackupCodecPolicy: backupCodecPolicy, - AudioFeatures: sutils.DedupeSlice(req.AudioFeatures), + Type: req.Type, + Name: req.Name, + Width: req.Width, + Height: req.Height, + Muted: req.Muted, + DisableDtx: req.DisableDtx, + Source: req.Source, + Layers: cloneLayers(req.Layers), + DisableRed: req.DisableRed, + Stereo: req.Stereo, + Encryption: req.Encryption, + Stream: req.Stream, + BackupCodecPolicy: backupCodecPolicy, + AudioFeatures: sutils.DedupeSlice(req.AudioFeatures), + RtpTrailerFeatures: sutils.DedupeSlice(req.RtpTrailerFeatures), } if req.Stereo && !slices.Contains(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO) { ti.AudioFeatures = append(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO) diff --git a/pkg/rtc/subscribedtrack.go b/pkg/rtc/subscribedtrack.go index c1f59a18a..f213a3307 100644 --- a/pkg/rtc/subscribedtrack.go +++ b/pkg/rtc/subscribedtrack.go @@ -129,7 +129,7 @@ func NewSubscribedTrack(params SubscribedTrackParams) (*SubscribedTrack, error) if isEncrypted { trailer = params.Subscriber.GetTrailer() } - stripUserTimestamp := params.MediaTrack.HasUserTimestamp() && + stripUserTimestamp := params.MediaTrack.HasRTPTrailerFeature(livekit.RTPTrailerFeature_USER_TIMESTAMP) && !params.Subscriber.ProtocolVersion().SupportsUserTimestamp() downTrack, err := sfu.NewDownTrack(sfu.DownTrackParams{ Codecs: codecs, diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index f901e5619..aaaf90f87 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -760,7 +760,7 @@ type MediaTrack interface { ClearAllReceivers(isExpectedToResume bool) IsEncrypted() bool - HasUserTimestamp() bool + HasRTPTrailerFeature(livekit.RTPTrailerFeature) bool } //counterfeiter:generate . LocalMediaTrack diff --git a/pkg/rtc/types/typesfakes/fake_local_media_track.go b/pkg/rtc/types/typesfakes/fake_local_media_track.go index 81eeebd11..0c0826939 100644 --- a/pkg/rtc/types/typesfakes/fake_local_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_local_media_track.go @@ -124,6 +124,17 @@ type FakeLocalMediaTrack struct { getTrackStatsReturnsOnCall map[int]struct { result1 *livekit.RTPStats } + HasRTPTrailerFeatureStub func(livekit.RTPTrailerFeature) bool + hasRTPTrailerFeatureMutex sync.RWMutex + hasRTPTrailerFeatureArgsForCall []struct { + arg1 livekit.RTPTrailerFeature + } + hasRTPTrailerFeatureReturns struct { + result1 bool + } + hasRTPTrailerFeatureReturnsOnCall map[int]struct { + result1 bool + } HasSdpCidStub func(string) bool hasSdpCidMutex sync.RWMutex hasSdpCidArgsForCall []struct { @@ -146,16 +157,6 @@ type FakeLocalMediaTrack struct { hasSignalCidReturnsOnCall map[int]struct { result1 bool } - HasUserTimestampStub func() bool - hasUserTimestampMutex sync.RWMutex - hasUserTimestampArgsForCall []struct { - } - hasUserTimestampReturns struct { - result1 bool - } - hasUserTimestampReturnsOnCall map[int]struct { - result1 bool - } IDStub func() livekit.TrackID iDMutex sync.RWMutex iDArgsForCall []struct { @@ -960,6 +961,67 @@ func (fake *FakeLocalMediaTrack) GetTrackStatsReturnsOnCall(i int, result1 *live }{result1} } +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFeature) bool { + fake.hasRTPTrailerFeatureMutex.Lock() + ret, specificReturn := fake.hasRTPTrailerFeatureReturnsOnCall[len(fake.hasRTPTrailerFeatureArgsForCall)] + fake.hasRTPTrailerFeatureArgsForCall = append(fake.hasRTPTrailerFeatureArgsForCall, struct { + arg1 livekit.RTPTrailerFeature + }{arg1}) + stub := fake.HasRTPTrailerFeatureStub + fakeReturns := fake.hasRTPTrailerFeatureReturns + fake.recordInvocation("HasRTPTrailerFeature", []interface{}{arg1}) + fake.hasRTPTrailerFeatureMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureCallCount() int { + fake.hasRTPTrailerFeatureMutex.RLock() + defer fake.hasRTPTrailerFeatureMutex.RUnlock() + return len(fake.hasRTPTrailerFeatureArgsForCall) +} + +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureCalls(stub func(livekit.RTPTrailerFeature) bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = stub +} + +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureArgsForCall(i int) livekit.RTPTrailerFeature { + fake.hasRTPTrailerFeatureMutex.RLock() + defer fake.hasRTPTrailerFeatureMutex.RUnlock() + argsForCall := fake.hasRTPTrailerFeatureArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureReturns(result1 bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = nil + fake.hasRTPTrailerFeatureReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureReturnsOnCall(i int, result1 bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = nil + if fake.hasRTPTrailerFeatureReturnsOnCall == nil { + fake.hasRTPTrailerFeatureReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.hasRTPTrailerFeatureReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeLocalMediaTrack) HasSdpCid(arg1 string) bool { fake.hasSdpCidMutex.Lock() ret, specificReturn := fake.hasSdpCidReturnsOnCall[len(fake.hasSdpCidArgsForCall)] @@ -1082,59 +1144,6 @@ func (fake *FakeLocalMediaTrack) HasSignalCidReturnsOnCall(i int, result1 bool) }{result1} } -func (fake *FakeLocalMediaTrack) HasUserTimestamp() bool { - fake.hasUserTimestampMutex.Lock() - ret, specificReturn := fake.hasUserTimestampReturnsOnCall[len(fake.hasUserTimestampArgsForCall)] - fake.hasUserTimestampArgsForCall = append(fake.hasUserTimestampArgsForCall, struct { - }{}) - stub := fake.HasUserTimestampStub - fakeReturns := fake.hasUserTimestampReturns - fake.recordInvocation("HasUserTimestamp", []interface{}{}) - fake.hasUserTimestampMutex.Unlock() - if stub != nil { - return stub() - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *FakeLocalMediaTrack) HasUserTimestampCallCount() int { - fake.hasUserTimestampMutex.RLock() - defer fake.hasUserTimestampMutex.RUnlock() - return len(fake.hasUserTimestampArgsForCall) -} - -func (fake *FakeLocalMediaTrack) HasUserTimestampCalls(stub func() bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = stub -} - -func (fake *FakeLocalMediaTrack) HasUserTimestampReturns(result1 bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = nil - fake.hasUserTimestampReturns = struct { - result1 bool - }{result1} -} - -func (fake *FakeLocalMediaTrack) HasUserTimestampReturnsOnCall(i int, result1 bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = nil - if fake.hasUserTimestampReturnsOnCall == nil { - fake.hasUserTimestampReturnsOnCall = make(map[int]struct { - result1 bool - }) - } - fake.hasUserTimestampReturnsOnCall[i] = struct { - result1 bool - }{result1} -} - func (fake *FakeLocalMediaTrack) ID() livekit.TrackID { fake.iDMutex.Lock() ret, specificReturn := fake.iDReturnsOnCall[len(fake.iDArgsForCall)] diff --git a/pkg/rtc/types/typesfakes/fake_media_track.go b/pkg/rtc/types/typesfakes/fake_media_track.go index c815a5dfe..e9ab26c58 100644 --- a/pkg/rtc/types/typesfakes/fake_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_media_track.go @@ -98,14 +98,15 @@ type FakeMediaTrack struct { getTemporalLayerForSpatialFpsReturnsOnCall map[int]struct { result1 int32 } - HasUserTimestampStub func() bool - hasUserTimestampMutex sync.RWMutex - hasUserTimestampArgsForCall []struct { + HasRTPTrailerFeatureStub func(livekit.RTPTrailerFeature) bool + hasRTPTrailerFeatureMutex sync.RWMutex + hasRTPTrailerFeatureArgsForCall []struct { + arg1 livekit.RTPTrailerFeature } - hasUserTimestampReturns struct { + hasRTPTrailerFeatureReturns struct { result1 bool } - hasUserTimestampReturnsOnCall map[int]struct { + hasRTPTrailerFeatureReturnsOnCall map[int]struct { result1 bool } IDStub func() livekit.TrackID @@ -752,17 +753,18 @@ func (fake *FakeMediaTrack) GetTemporalLayerForSpatialFpsReturnsOnCall(i int, re }{result1} } -func (fake *FakeMediaTrack) HasUserTimestamp() bool { - fake.hasUserTimestampMutex.Lock() - ret, specificReturn := fake.hasUserTimestampReturnsOnCall[len(fake.hasUserTimestampArgsForCall)] - fake.hasUserTimestampArgsForCall = append(fake.hasUserTimestampArgsForCall, struct { - }{}) - stub := fake.HasUserTimestampStub - fakeReturns := fake.hasUserTimestampReturns - fake.recordInvocation("HasUserTimestamp", []interface{}{}) - fake.hasUserTimestampMutex.Unlock() +func (fake *FakeMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFeature) bool { + fake.hasRTPTrailerFeatureMutex.Lock() + ret, specificReturn := fake.hasRTPTrailerFeatureReturnsOnCall[len(fake.hasRTPTrailerFeatureArgsForCall)] + fake.hasRTPTrailerFeatureArgsForCall = append(fake.hasRTPTrailerFeatureArgsForCall, struct { + arg1 livekit.RTPTrailerFeature + }{arg1}) + stub := fake.HasRTPTrailerFeatureStub + fakeReturns := fake.hasRTPTrailerFeatureReturns + fake.recordInvocation("HasRTPTrailerFeature", []interface{}{arg1}) + fake.hasRTPTrailerFeatureMutex.Unlock() if stub != nil { - return stub() + return stub(arg1) } if specificReturn { return ret.result1 @@ -770,37 +772,44 @@ func (fake *FakeMediaTrack) HasUserTimestamp() bool { return fakeReturns.result1 } -func (fake *FakeMediaTrack) HasUserTimestampCallCount() int { - fake.hasUserTimestampMutex.RLock() - defer fake.hasUserTimestampMutex.RUnlock() - return len(fake.hasUserTimestampArgsForCall) +func (fake *FakeMediaTrack) HasRTPTrailerFeatureCallCount() int { + fake.hasRTPTrailerFeatureMutex.RLock() + defer fake.hasRTPTrailerFeatureMutex.RUnlock() + return len(fake.hasRTPTrailerFeatureArgsForCall) } -func (fake *FakeMediaTrack) HasUserTimestampCalls(stub func() bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = stub +func (fake *FakeMediaTrack) HasRTPTrailerFeatureCalls(stub func(livekit.RTPTrailerFeature) bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = stub } -func (fake *FakeMediaTrack) HasUserTimestampReturns(result1 bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = nil - fake.hasUserTimestampReturns = struct { +func (fake *FakeMediaTrack) HasRTPTrailerFeatureArgsForCall(i int) livekit.RTPTrailerFeature { + fake.hasRTPTrailerFeatureMutex.RLock() + defer fake.hasRTPTrailerFeatureMutex.RUnlock() + argsForCall := fake.hasRTPTrailerFeatureArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeMediaTrack) HasRTPTrailerFeatureReturns(result1 bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = nil + fake.hasRTPTrailerFeatureReturns = struct { result1 bool }{result1} } -func (fake *FakeMediaTrack) HasUserTimestampReturnsOnCall(i int, result1 bool) { - fake.hasUserTimestampMutex.Lock() - defer fake.hasUserTimestampMutex.Unlock() - fake.HasUserTimestampStub = nil - if fake.hasUserTimestampReturnsOnCall == nil { - fake.hasUserTimestampReturnsOnCall = make(map[int]struct { +func (fake *FakeMediaTrack) HasRTPTrailerFeatureReturnsOnCall(i int, result1 bool) { + fake.hasRTPTrailerFeatureMutex.Lock() + defer fake.hasRTPTrailerFeatureMutex.Unlock() + fake.HasRTPTrailerFeatureStub = nil + if fake.hasRTPTrailerFeatureReturnsOnCall == nil { + fake.hasRTPTrailerFeatureReturnsOnCall = make(map[int]struct { result1 bool }) } - fake.hasUserTimestampReturnsOnCall[i] = struct { + fake.hasRTPTrailerFeatureReturnsOnCall[i] = struct { result1 bool }{result1} } From ee456c47a2b9ad4042538b0bfc8fc096d71f0b43 Mon Sep 17 00:00:00 2001 From: David Chen Date: Mon, 2 Mar 2026 11:54:07 -0800 Subject: [PATCH 6/8] update name to PacketTrailerFeature --- pkg/rtc/mediatrackreceiver.go | 4 +- pkg/rtc/subscribedtrack.go | 2 +- pkg/rtc/types/interfaces.go | 2 +- .../typesfakes/fake_local_media_track.go | 78 +++++++++---------- pkg/rtc/types/typesfakes/fake_media_track.go | 78 +++++++++---------- 5 files changed, 82 insertions(+), 82 deletions(-) diff --git a/pkg/rtc/mediatrackreceiver.go b/pkg/rtc/mediatrackreceiver.go index 377a6900f..bbed7d55b 100644 --- a/pkg/rtc/mediatrackreceiver.go +++ b/pkg/rtc/mediatrackreceiver.go @@ -519,8 +519,8 @@ func (t *MediaTrackReceiver) IsEncrypted() bool { return t.TrackInfo().Encryption != livekit.Encryption_NONE } -func (t *MediaTrackReceiver) HasRTPTrailerFeature(feature livekit.RTPTrailerFeature) bool { - return slices.Contains(t.TrackInfo().GetRtpTrailerFeatures(), feature) +func (t *MediaTrackReceiver) HasPacketTrailerFeature(feature livekit.PacketTrailerFeature) bool { + return slices.Contains(t.TrackInfo().GetPacketTrailerFeatures(), feature) } func (t *MediaTrackReceiver) AddOnClose(f func(isExpectedToResume bool)) { diff --git a/pkg/rtc/subscribedtrack.go b/pkg/rtc/subscribedtrack.go index f213a3307..c76310ce6 100644 --- a/pkg/rtc/subscribedtrack.go +++ b/pkg/rtc/subscribedtrack.go @@ -129,7 +129,7 @@ func NewSubscribedTrack(params SubscribedTrackParams) (*SubscribedTrack, error) if isEncrypted { trailer = params.Subscriber.GetTrailer() } - stripUserTimestamp := params.MediaTrack.HasRTPTrailerFeature(livekit.RTPTrailerFeature_USER_TIMESTAMP) && + stripUserTimestamp := params.MediaTrack.HasPacketTrailerFeature(livekit.PacketTrailerFeature_PTF_USER_TIMESTAMP) && !params.Subscriber.ProtocolVersion().SupportsUserTimestamp() downTrack, err := sfu.NewDownTrack(sfu.DownTrackParams{ Codecs: codecs, diff --git a/pkg/rtc/types/interfaces.go b/pkg/rtc/types/interfaces.go index aaaf90f87..6867246af 100644 --- a/pkg/rtc/types/interfaces.go +++ b/pkg/rtc/types/interfaces.go @@ -760,7 +760,7 @@ type MediaTrack interface { ClearAllReceivers(isExpectedToResume bool) IsEncrypted() bool - HasRTPTrailerFeature(livekit.RTPTrailerFeature) bool + HasPacketTrailerFeature(livekit.PacketTrailerFeature) bool } //counterfeiter:generate . LocalMediaTrack diff --git a/pkg/rtc/types/typesfakes/fake_local_media_track.go b/pkg/rtc/types/typesfakes/fake_local_media_track.go index 0c0826939..9f5205cea 100644 --- a/pkg/rtc/types/typesfakes/fake_local_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_local_media_track.go @@ -124,15 +124,15 @@ type FakeLocalMediaTrack struct { getTrackStatsReturnsOnCall map[int]struct { result1 *livekit.RTPStats } - HasRTPTrailerFeatureStub func(livekit.RTPTrailerFeature) bool - hasRTPTrailerFeatureMutex sync.RWMutex - hasRTPTrailerFeatureArgsForCall []struct { - arg1 livekit.RTPTrailerFeature + HasPacketTrailerFeatureStub func(livekit.PacketTrailerFeature) bool + hasPacketTrailerFeatureMutex sync.RWMutex + hasPacketTrailerFeatureArgsForCall []struct { + arg1 livekit.PacketTrailerFeature } - hasRTPTrailerFeatureReturns struct { + hasPacketTrailerFeatureReturns struct { result1 bool } - hasRTPTrailerFeatureReturnsOnCall map[int]struct { + hasPacketTrailerFeatureReturnsOnCall map[int]struct { result1 bool } HasSdpCidStub func(string) bool @@ -961,16 +961,16 @@ func (fake *FakeLocalMediaTrack) GetTrackStatsReturnsOnCall(i int, result1 *live }{result1} } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFeature) bool { - fake.hasRTPTrailerFeatureMutex.Lock() - ret, specificReturn := fake.hasRTPTrailerFeatureReturnsOnCall[len(fake.hasRTPTrailerFeatureArgsForCall)] - fake.hasRTPTrailerFeatureArgsForCall = append(fake.hasRTPTrailerFeatureArgsForCall, struct { - arg1 livekit.RTPTrailerFeature +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeature(arg1 livekit.PacketTrailerFeature) bool { + fake.hasPacketTrailerFeatureMutex.Lock() + ret, specificReturn := fake.hasPacketTrailerFeatureReturnsOnCall[len(fake.hasPacketTrailerFeatureArgsForCall)] + fake.hasPacketTrailerFeatureArgsForCall = append(fake.hasPacketTrailerFeatureArgsForCall, struct { + arg1 livekit.PacketTrailerFeature }{arg1}) - stub := fake.HasRTPTrailerFeatureStub - fakeReturns := fake.hasRTPTrailerFeatureReturns - fake.recordInvocation("HasRTPTrailerFeature", []interface{}{arg1}) - fake.hasRTPTrailerFeatureMutex.Unlock() + stub := fake.HasPacketTrailerFeatureStub + fakeReturns := fake.hasPacketTrailerFeatureReturns + fake.recordInvocation("HasPacketTrailerFeature", []interface{}{arg1}) + fake.hasPacketTrailerFeatureMutex.Unlock() if stub != nil { return stub(arg1) } @@ -980,44 +980,44 @@ func (fake *FakeLocalMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFea return fakeReturns.result1 } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureCallCount() int { - fake.hasRTPTrailerFeatureMutex.RLock() - defer fake.hasRTPTrailerFeatureMutex.RUnlock() - return len(fake.hasRTPTrailerFeatureArgsForCall) +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeatureCallCount() int { + fake.hasPacketTrailerFeatureMutex.RLock() + defer fake.hasPacketTrailerFeatureMutex.RUnlock() + return len(fake.hasPacketTrailerFeatureArgsForCall) } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureCalls(stub func(livekit.RTPTrailerFeature) bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = stub +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeatureCalls(stub func(livekit.PacketTrailerFeature) bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = stub } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureArgsForCall(i int) livekit.RTPTrailerFeature { - fake.hasRTPTrailerFeatureMutex.RLock() - defer fake.hasRTPTrailerFeatureMutex.RUnlock() - argsForCall := fake.hasRTPTrailerFeatureArgsForCall[i] +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeatureArgsForCall(i int) livekit.PacketTrailerFeature { + fake.hasPacketTrailerFeatureMutex.RLock() + defer fake.hasPacketTrailerFeatureMutex.RUnlock() + argsForCall := fake.hasPacketTrailerFeatureArgsForCall[i] return argsForCall.arg1 } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureReturns(result1 bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = nil - fake.hasRTPTrailerFeatureReturns = struct { +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeatureReturns(result1 bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = nil + fake.hasPacketTrailerFeatureReturns = struct { result1 bool }{result1} } -func (fake *FakeLocalMediaTrack) HasRTPTrailerFeatureReturnsOnCall(i int, result1 bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = nil - if fake.hasRTPTrailerFeatureReturnsOnCall == nil { - fake.hasRTPTrailerFeatureReturnsOnCall = make(map[int]struct { +func (fake *FakeLocalMediaTrack) HasPacketTrailerFeatureReturnsOnCall(i int, result1 bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = nil + if fake.hasPacketTrailerFeatureReturnsOnCall == nil { + fake.hasPacketTrailerFeatureReturnsOnCall = make(map[int]struct { result1 bool }) } - fake.hasRTPTrailerFeatureReturnsOnCall[i] = struct { + fake.hasPacketTrailerFeatureReturnsOnCall[i] = struct { result1 bool }{result1} } diff --git a/pkg/rtc/types/typesfakes/fake_media_track.go b/pkg/rtc/types/typesfakes/fake_media_track.go index e9ab26c58..9591939c0 100644 --- a/pkg/rtc/types/typesfakes/fake_media_track.go +++ b/pkg/rtc/types/typesfakes/fake_media_track.go @@ -98,15 +98,15 @@ type FakeMediaTrack struct { getTemporalLayerForSpatialFpsReturnsOnCall map[int]struct { result1 int32 } - HasRTPTrailerFeatureStub func(livekit.RTPTrailerFeature) bool - hasRTPTrailerFeatureMutex sync.RWMutex - hasRTPTrailerFeatureArgsForCall []struct { - arg1 livekit.RTPTrailerFeature + HasPacketTrailerFeatureStub func(livekit.PacketTrailerFeature) bool + hasPacketTrailerFeatureMutex sync.RWMutex + hasPacketTrailerFeatureArgsForCall []struct { + arg1 livekit.PacketTrailerFeature } - hasRTPTrailerFeatureReturns struct { + hasPacketTrailerFeatureReturns struct { result1 bool } - hasRTPTrailerFeatureReturnsOnCall map[int]struct { + hasPacketTrailerFeatureReturnsOnCall map[int]struct { result1 bool } IDStub func() livekit.TrackID @@ -753,16 +753,16 @@ func (fake *FakeMediaTrack) GetTemporalLayerForSpatialFpsReturnsOnCall(i int, re }{result1} } -func (fake *FakeMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFeature) bool { - fake.hasRTPTrailerFeatureMutex.Lock() - ret, specificReturn := fake.hasRTPTrailerFeatureReturnsOnCall[len(fake.hasRTPTrailerFeatureArgsForCall)] - fake.hasRTPTrailerFeatureArgsForCall = append(fake.hasRTPTrailerFeatureArgsForCall, struct { - arg1 livekit.RTPTrailerFeature +func (fake *FakeMediaTrack) HasPacketTrailerFeature(arg1 livekit.PacketTrailerFeature) bool { + fake.hasPacketTrailerFeatureMutex.Lock() + ret, specificReturn := fake.hasPacketTrailerFeatureReturnsOnCall[len(fake.hasPacketTrailerFeatureArgsForCall)] + fake.hasPacketTrailerFeatureArgsForCall = append(fake.hasPacketTrailerFeatureArgsForCall, struct { + arg1 livekit.PacketTrailerFeature }{arg1}) - stub := fake.HasRTPTrailerFeatureStub - fakeReturns := fake.hasRTPTrailerFeatureReturns - fake.recordInvocation("HasRTPTrailerFeature", []interface{}{arg1}) - fake.hasRTPTrailerFeatureMutex.Unlock() + stub := fake.HasPacketTrailerFeatureStub + fakeReturns := fake.hasPacketTrailerFeatureReturns + fake.recordInvocation("HasPacketTrailerFeature", []interface{}{arg1}) + fake.hasPacketTrailerFeatureMutex.Unlock() if stub != nil { return stub(arg1) } @@ -772,44 +772,44 @@ func (fake *FakeMediaTrack) HasRTPTrailerFeature(arg1 livekit.RTPTrailerFeature) return fakeReturns.result1 } -func (fake *FakeMediaTrack) HasRTPTrailerFeatureCallCount() int { - fake.hasRTPTrailerFeatureMutex.RLock() - defer fake.hasRTPTrailerFeatureMutex.RUnlock() - return len(fake.hasRTPTrailerFeatureArgsForCall) +func (fake *FakeMediaTrack) HasPacketTrailerFeatureCallCount() int { + fake.hasPacketTrailerFeatureMutex.RLock() + defer fake.hasPacketTrailerFeatureMutex.RUnlock() + return len(fake.hasPacketTrailerFeatureArgsForCall) } -func (fake *FakeMediaTrack) HasRTPTrailerFeatureCalls(stub func(livekit.RTPTrailerFeature) bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = stub +func (fake *FakeMediaTrack) HasPacketTrailerFeatureCalls(stub func(livekit.PacketTrailerFeature) bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = stub } -func (fake *FakeMediaTrack) HasRTPTrailerFeatureArgsForCall(i int) livekit.RTPTrailerFeature { - fake.hasRTPTrailerFeatureMutex.RLock() - defer fake.hasRTPTrailerFeatureMutex.RUnlock() - argsForCall := fake.hasRTPTrailerFeatureArgsForCall[i] +func (fake *FakeMediaTrack) HasPacketTrailerFeatureArgsForCall(i int) livekit.PacketTrailerFeature { + fake.hasPacketTrailerFeatureMutex.RLock() + defer fake.hasPacketTrailerFeatureMutex.RUnlock() + argsForCall := fake.hasPacketTrailerFeatureArgsForCall[i] return argsForCall.arg1 } -func (fake *FakeMediaTrack) HasRTPTrailerFeatureReturns(result1 bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = nil - fake.hasRTPTrailerFeatureReturns = struct { +func (fake *FakeMediaTrack) HasPacketTrailerFeatureReturns(result1 bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = nil + fake.hasPacketTrailerFeatureReturns = struct { result1 bool }{result1} } -func (fake *FakeMediaTrack) HasRTPTrailerFeatureReturnsOnCall(i int, result1 bool) { - fake.hasRTPTrailerFeatureMutex.Lock() - defer fake.hasRTPTrailerFeatureMutex.Unlock() - fake.HasRTPTrailerFeatureStub = nil - if fake.hasRTPTrailerFeatureReturnsOnCall == nil { - fake.hasRTPTrailerFeatureReturnsOnCall = make(map[int]struct { +func (fake *FakeMediaTrack) HasPacketTrailerFeatureReturnsOnCall(i int, result1 bool) { + fake.hasPacketTrailerFeatureMutex.Lock() + defer fake.hasPacketTrailerFeatureMutex.Unlock() + fake.HasPacketTrailerFeatureStub = nil + if fake.hasPacketTrailerFeatureReturnsOnCall == nil { + fake.hasPacketTrailerFeatureReturnsOnCall = make(map[int]struct { result1 bool }) } - fake.hasRTPTrailerFeatureReturnsOnCall[i] = struct { + fake.hasPacketTrailerFeatureReturnsOnCall[i] = struct { result1 bool }{result1} } From 4244f3e9d6513a1888b647c60a5409da664f387b Mon Sep 17 00:00:00 2001 From: David Chen Date: Tue, 3 Mar 2026 11:21:33 -0800 Subject: [PATCH 7/8] update to PacketTrailerFeatures --- pkg/rtc/participant.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 9124ad3b6..007b5e910 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -2833,7 +2833,7 @@ func (p *ParticipantImpl) addPendingTrackLocked(req *livekit.AddTrackRequest) *l Stream: req.Stream, BackupCodecPolicy: backupCodecPolicy, AudioFeatures: sutils.DedupeSlice(req.AudioFeatures), - RtpTrailerFeatures: sutils.DedupeSlice(req.RtpTrailerFeatures), + PacketTrailerFeatures: sutils.DedupeSlice(req.PacketTrailerFeatures), } if req.Stereo && !slices.Contains(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO) { ti.AudioFeatures = append(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO) From 7b93f2a25848b854f1b219de110e5c183c08982a Mon Sep 17 00:00:00 2001 From: David Chen Date: Wed, 4 Mar 2026 10:46:17 -0800 Subject: [PATCH 8/8] bump protocol dep version --- go.mod | 6 +++--- go.sum | 10 ++++++---- pkg/rtc/participant.go | 28 ++++++++++++++-------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 7f44f10d4..e21c7c8d4 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/jxskiss/base62 v1.1.0 github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 github.com/livekit/mediatransportutil v0.0.0-20260113174415-2e8ba344fca3 - github.com/livekit/protocol v1.44.1-0.20260211042324-3688e156dc7e + github.com/livekit/protocol v1.45.0 github.com/livekit/psrpc v0.7.1 github.com/mackerelio/go-osstat v0.2.6 github.com/magefile/mage v1.15.0 @@ -74,7 +74,7 @@ require ( go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 // indirect go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect go.opentelemetry.io/otel/trace v1.40.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect golang.org/x/time v0.14.0 // indirect @@ -155,4 +155,4 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20260203192932-546029d2fa20 // indirect google.golang.org/grpc v1.78.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index 4eee2d18d..d9d33737b 100644 --- a/go.sum +++ b/go.sum @@ -177,6 +177,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260113174415-2e8ba344fca3 h1:v1Xc/q/547TjLX7Nw5y2vXNnmV0XYFAbhTJrtErQeDA= github.com/livekit/mediatransportutil v0.0.0-20260113174415-2e8ba344fca3/go.mod h1:QBx/KHV6Vv00ggibg/WrOlqrkTciEA2Hc9DGWYr3Q9U= +github.com/livekit/protocol v1.45.0 h1:e2ubU+rKYegn8f/6SGdKQKVCRfBkK1m0J0Rl5MJmns4= +github.com/livekit/protocol v1.45.0/go.mod h1:63AUi0vQak6Y6gPqSBHLc+ExYTUwEqF/m4b2IRW1iO0= github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= github.com/mackerelio/go-osstat v0.2.6 h1:gs4U8BZeS1tjrL08tt5VUliVvSWP26Ai2Ob8Lr7f2i0= @@ -347,10 +349,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0 h1:Ckwye go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.39.0/go.mod h1:teIFJh5pW2y+AN7riv6IBPX2DuesS3HgP39mwOspKwU= go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= diff --git a/pkg/rtc/participant.go b/pkg/rtc/participant.go index 007b5e910..095f327b5 100644 --- a/pkg/rtc/participant.go +++ b/pkg/rtc/participant.go @@ -2819,20 +2819,20 @@ func (p *ParticipantImpl) addPendingTrackLocked(req *livekit.AddTrackRequest) *l } ti := &livekit.TrackInfo{ - Type: req.Type, - Name: req.Name, - Width: req.Width, - Height: req.Height, - Muted: req.Muted, - DisableDtx: req.DisableDtx, - Source: req.Source, - Layers: cloneLayers(req.Layers), - DisableRed: req.DisableRed, - Stereo: req.Stereo, - Encryption: req.Encryption, - Stream: req.Stream, - BackupCodecPolicy: backupCodecPolicy, - AudioFeatures: sutils.DedupeSlice(req.AudioFeatures), + Type: req.Type, + Name: req.Name, + Width: req.Width, + Height: req.Height, + Muted: req.Muted, + DisableDtx: req.DisableDtx, + Source: req.Source, + Layers: cloneLayers(req.Layers), + DisableRed: req.DisableRed, + Stereo: req.Stereo, + Encryption: req.Encryption, + Stream: req.Stream, + BackupCodecPolicy: backupCodecPolicy, + AudioFeatures: sutils.DedupeSlice(req.AudioFeatures), PacketTrailerFeatures: sutils.DedupeSlice(req.PacketTrailerFeatures), } if req.Stereo && !slices.Contains(ti.AudioFeatures, livekit.AudioTrackFeature_TF_STEREO) {