From a0b56bcc5dbb2b1d73bed656974e23a3f60616b1 Mon Sep 17 00:00:00 2001 From: David Chen Date: Fri, 28 Aug 2026 18:49:13 -0700 Subject: [PATCH] Guard short TWCC extensions in FEC packets --- pkg/sfu/buffer/buffer.go | 2 +- pkg/sfu/buffer/buffer_fec_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/pkg/sfu/buffer/buffer.go b/pkg/sfu/buffer/buffer.go index 462373acf..5e83541a3 100644 --- a/pkg/sfu/buffer/buffer.go +++ b/pkg/sfu/buffer/buffer.go @@ -468,7 +468,7 @@ func (b *Buffer) writeFEC(fecPkt *rtp.Packet, arrivalTime int64) { // publisher send side BWE sees the FEC packets acked. The repair stream // shares the media m-line, extension ids match the primary stream. if b.twcc != nil && b.twccExtID != 0 { - if ext := fecPkt.GetExtension(b.twccExtID); ext != nil { + if ext := fecPkt.GetExtension(b.twccExtID); len(ext) >= 2 { b.twcc.Push(fecPkt.SSRC, binary.BigEndian.Uint16(ext[0:2]), arrivalTime, fecPkt.Marker) } } diff --git a/pkg/sfu/buffer/buffer_fec_test.go b/pkg/sfu/buffer/buffer_fec_test.go index 435b3c1e2..39c37eb9e 100644 --- a/pkg/sfu/buffer/buffer_fec_test.go +++ b/pkg/sfu/buffer/buffer_fec_test.go @@ -24,6 +24,8 @@ import ( "github.com/pion/webrtc/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/livekit/mediatransportutil/pkg/twcc" ) const ( @@ -289,6 +291,32 @@ func TestBufferFECIgnoresUnexpectedPayloadType(t *testing.T) { assert.EqualValues(t, 0, stats.PacketsRecovered) } +func TestBufferFECIgnoresShortTWCCExtension(t *testing.T) { + factory := NewFactoryOfBufferFactory(500, 200).CreateBufferFactory() + + primary := factory.GetOrNew(packetio.RTPBufferPacket, fecTestMediaSSRC).(*Buffer) + fecBuff := factory.GetOrNew(packetio.RTPBufferPacket, fecTestFECSSRC).(*Buffer) + factory.SetFECPair(fecTestFECSSRC, fecTestMediaSSRC) + bindFECTestBuffer(t, primary) + + const twccExtID = 3 + primary.SetTWCCAndExtID(twcc.NewTransportWideCCResponder(), twccExtID) + + fecPacket := rtp.Packet{ + Header: rtp.Header{ + Version: 2, + PayloadType: fecTestFECPT, + SequenceNumber: 1, + SSRC: fecTestFECSSRC, + }, + Payload: []byte{0}, + } + require.NoError(t, fecPacket.SetExtension(twccExtID, []byte{1})) + + writePacket(t, fecBuff, &fecPacket) + assert.EqualValues(t, 1, primary.FECDecoderStats().FECPacketsDiscarded) +} + func TestBufferFECNACKSuppression(t *testing.T) { // a recovered packet must clear the pending NACK for its sequence number factory := NewFactoryOfBufferFactory(500, 200).CreateBufferFactory()