refactor packet generation for tests into util

This commit is contained in:
David Chen
2026-09-22 15:08:08 -07:00
parent 6c3eba9897
commit 2863bad6bb
2 changed files with 57 additions and 39 deletions
+11 -39
View File
@@ -18,7 +18,6 @@ import (
"crypto/aes"
"crypto/cipher"
"encoding/binary"
"math/rand"
"testing"
"time"
@@ -29,6 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/livekit/livekit-server/pkg/sfu/testutils/rtptest"
"github.com/livekit/mediatransportutil/pkg/twcc"
)
@@ -47,34 +47,6 @@ var flexFECCodec = webrtc.RTPCodecParameters{
PayloadType: webrtc.PayloadType(fecTestFECPT),
}
func fecTestMediaPackets(t *testing.T, baseSN uint16, count int) []rtp.Packet {
t.Helper()
rng := rand.New(rand.NewSource(int64(baseSN)))
pkts := make([]rtp.Packet, 0, count)
for i := 0; i < count; i++ {
payload := make([]byte, 50+rng.Intn(200))
rng.Read(payload)
// valid VP8 payload descriptor (S=1, no extensions) so the video
// packet processing in the buffer accepts the packet
payload[0] = 0x10
sn := baseSN + uint16(i)
pkts = append(pkts, rtp.Packet{
Header: rtp.Header{
Version: 2,
PayloadType: uint8(vp8Codec.PayloadType),
SequenceNumber: sn,
// derive timestamp from the sequence number so windows
// generated separately stay monotonic
Timestamp: 90000 + 3000*uint32(sn),
SSRC: fecTestMediaSSRC,
Marker: i == count-1,
},
Payload: payload,
})
}
return pkts
}
func bindFECTestBuffer(t *testing.T, buff *Buffer) {
t.Helper()
buff.codecType = webrtc.RTPCodecTypeVideo
@@ -193,7 +165,7 @@ func TestBufferFECRecoversDroppedPacket(t *testing.T) {
receivedDelta += received
})
media := fecTestMediaPackets(t, 100, 10)
media := rtptest.GenerateVP8Packets(100, 10, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
encoder := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC)
fecPackets := encoder.EncodeFec(media, 2)
require.NotEmpty(t, fecPackets)
@@ -246,7 +218,7 @@ func TestBufferFECRecoversEncryptedPayload(t *testing.T) {
aead, err := cipher.NewGCM(block)
require.NoError(t, err)
media := fecTestMediaPackets(t, 120, 5)
media := rtptest.GenerateVP8Packets(120, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
plaintexts := make([][]byte, len(media))
for i := range media {
plaintexts[i] = append([]byte("encrypted-video-frame-"), byte(i))
@@ -302,7 +274,7 @@ func TestBufferFECRecoveryCallbackCanReenterBuffer(t *testing.T) {
callbackDone <- struct{}{}
})
media := fecTestMediaPackets(t, 150, 5)
media := rtptest.GenerateVP8Packets(150, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
for i := range media {
writePacket(t, primary, &media[i])
}
@@ -341,7 +313,7 @@ func TestBufferFECPairAfterPackets(t *testing.T) {
bindFECTestBuffer(t, primary)
encoder := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC)
media := fecTestMediaPackets(t, 200, 10)
media := rtptest.GenerateVP8Packets(200, 10, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
fecPackets := encoder.EncodeFec(media, 2)
require.NotEmpty(t, fecPackets)
@@ -370,7 +342,7 @@ func TestBufferFECPairAfterPackets(t *testing.T) {
assert.EqualValues(t, 1, stats.PacketsRecovered)
// the next window recovers normally
media2 := fecTestMediaPackets(t, 210, 10)
media2 := rtptest.GenerateVP8Packets(210, 10, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
fecPackets2 := encoder.EncodeFec(media2, 2)
require.NotEmpty(t, fecPackets2)
@@ -402,7 +374,7 @@ func TestBufferFECCoupledBeforeBuffersExist(t *testing.T) {
fecBuff := factory.GetOrNew(packetio.RTPBufferPacket, fecTestFECSSRC).(*Buffer)
bindFECTestBuffer(t, primary)
media := fecTestMediaPackets(t, 300, 5)
media := rtptest.GenerateVP8Packets(300, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
encoder := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC)
fecPackets := encoder.EncodeFec(media, 1)
require.NotEmpty(t, fecPackets)
@@ -433,7 +405,7 @@ func TestBufferFECSequenceNumberWrap(t *testing.T) {
fecBuff := factory.GetOrNew(packetio.RTPBufferPacket, fecTestFECSSRC).(*Buffer)
bindFECTestBuffer(t, primary)
media := fecTestMediaPackets(t, 65533, 5)
media := rtptest.GenerateVP8Packets(65533, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
for i := range media {
media[i].Timestamp = 90000 + 3000*uint32(i)
}
@@ -463,7 +435,7 @@ func TestBufferFECRecoveryAfterPaddingRemoval(t *testing.T) {
fecBuff := factory.GetOrNew(packetio.RTPBufferPacket, fecTestFECSSRC).(*Buffer)
bindFECTestBuffer(t, primary)
media := fecTestMediaPackets(t, 800, 5)
media := rtptest.GenerateVP8Packets(800, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
fecPackets := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC).EncodeFec(media, 1)
require.Len(t, fecPackets, 1)
@@ -532,7 +504,7 @@ func TestBufferFECIgnoresUnexpectedPayloadType(t *testing.T) {
Codecs: []webrtc.RTPCodecParameters{vp8Codec},
}, vp8Codec.RTPCodecCapability, 0))
media := fecTestMediaPackets(t, 400, 5)
media := rtptest.GenerateVP8Packets(400, 5, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
encoder := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC)
fecPackets := encoder.EncodeFec(media, 1)
require.NotEmpty(t, fecPackets)
@@ -585,7 +557,7 @@ func TestBufferFECNACKSuppression(t *testing.T) {
factory.SetFECPair(fecTestFECSSRC, fecTestMediaSSRC)
bindFECTestBuffer(t, primary)
media := fecTestMediaPackets(t, 700, 10)
media := rtptest.GenerateVP8Packets(700, 10, uint8(vp8Codec.PayloadType), fecTestMediaSSRC)
encoder := pionflexfec.NewFlexEncoder03(fecTestFECPT, fecTestFECSSRC)
fecPackets := encoder.EncodeFec(media, 2)
require.NotEmpty(t, fecPackets)
+46
View File
@@ -0,0 +1,46 @@
// 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.
// 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 rtptest
import (
"math/rand"
"github.com/pion/rtp"
)
// GenerateVP8Packets returns deterministic RTP packets with valid VP8 payload descriptors.
func GenerateVP8Packets(baseSN uint16, count int, payloadType uint8, ssrc uint32) []rtp.Packet {
rng := rand.New(rand.NewSource(int64(baseSN)))
packets := make([]rtp.Packet, 0, count)
for i := 0; i < count; i++ {
payload := make([]byte, 50+rng.Intn(200))
rng.Read(payload)
payload[0] = 0x10
sequenceNumber := baseSN + uint16(i)
packets = append(packets, rtp.Packet{
Header: rtp.Header{
Version: 2,
PayloadType: payloadType,
SequenceNumber: sequenceNumber,
Timestamp: 90000 + 3000*uint32(sequenceNumber),
SSRC: ssrc,
Marker: i == count-1,
},
Payload: payload,
})
}
return packets
}