mirror of
https://github.com/livekit/livekit.git
synced 2026-04-26 17:27:33 +00:00
* Separate from ion-sfu changes: 1. extract pkg/buffer, twcc, sfu, relay, stats, logger 2. to solve cycle import, move ion-sfu/pkg/logger to pkg/sfu/logger 3. replace pion/ion-sfu => ./ reason: will change import pion/ion-sfu/pkg/* to livekit-server/pkg/* after this pr merged. Just not change any code in this pr, because it will confused with the separate code from ion-sfu in review. * Move code from ion-sfu to pkg/sfu * fix build error for resovle conflict Co-authored-by: cnderrauber <zengjie9004@gmail.com>
347 lines
7.9 KiB
Go
347 lines
7.9 KiB
Go
package twcc
|
|
|
|
import (
|
|
"math/rand"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/pion/rtcp"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestTransportWideCC_writeRunLengthChunk(t1 *testing.T) {
|
|
type fields struct {
|
|
len uint16
|
|
}
|
|
type args struct {
|
|
symbol uint16
|
|
runLength uint16
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
wantErr bool
|
|
wantBytes []byte
|
|
}{
|
|
{
|
|
name: "Must not return error",
|
|
|
|
args: args{
|
|
symbol: rtcp.TypeTCCPacketNotReceived,
|
|
runLength: 221,
|
|
},
|
|
wantErr: false,
|
|
wantBytes: []byte{0, 0xdd},
|
|
}, {
|
|
name: "Must set run length after padding",
|
|
fields: fields{
|
|
len: 1,
|
|
},
|
|
args: args{
|
|
symbol: rtcp.TypeTCCPacketReceivedWithoutDelta,
|
|
runLength: 24,
|
|
},
|
|
wantBytes: []byte{0, 0x60, 0x18},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t1.Run(tt.name, func(t1 *testing.T) {
|
|
t := &Responder{
|
|
len: tt.fields.len,
|
|
}
|
|
t.writeRunLengthChunk(tt.args.symbol, tt.args.runLength)
|
|
assert.Equal(t1, tt.wantBytes, t.payload[:t.len])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTransportWideCC_writeStatusSymbolChunk(t1 *testing.T) {
|
|
type fields struct {
|
|
len uint16
|
|
}
|
|
type args struct {
|
|
symbolSize uint16
|
|
symbolList []uint16
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
wantBytes []byte
|
|
}{
|
|
{
|
|
name: "Must not return error",
|
|
args: args{
|
|
symbolSize: rtcp.TypeTCCSymbolSizeOneBit,
|
|
symbolList: []uint16{rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived},
|
|
},
|
|
wantBytes: []byte{0x9F, 0x1C},
|
|
},
|
|
{
|
|
name: "Must set symbol chunk after padding",
|
|
fields: fields{
|
|
len: 1,
|
|
},
|
|
args: args{
|
|
symbolSize: rtcp.TypeTCCSymbolSizeTwoBit,
|
|
symbolList: []uint16{
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedWithoutDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived},
|
|
},
|
|
wantBytes: []byte{0x0, 0xcd, 0x50},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t1.Run(tt.name, func(t1 *testing.T) {
|
|
t := &Responder{
|
|
len: tt.fields.len,
|
|
}
|
|
for i, v := range tt.args.symbolList {
|
|
t.createStatusSymbolChunk(tt.args.symbolSize, v, i)
|
|
}
|
|
t.writeStatusSymbolChunk(tt.args.symbolSize)
|
|
assert.Equal(t1, tt.wantBytes, t.payload[:t.len])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTransportWideCC_writeDelta(t1 *testing.T) {
|
|
a := -32768
|
|
type fields struct {
|
|
deltaLen uint16
|
|
}
|
|
type args struct {
|
|
deltaType uint16
|
|
delta uint16
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want []byte
|
|
}{
|
|
{
|
|
name: "Must set correct small delta",
|
|
args: args{
|
|
deltaType: rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
delta: 255,
|
|
},
|
|
want: []byte{0xff},
|
|
},
|
|
{
|
|
name: "Must set correct small delta with padding",
|
|
fields: fields{
|
|
deltaLen: 1,
|
|
},
|
|
args: args{
|
|
deltaType: rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
delta: 255,
|
|
},
|
|
want: []byte{0, 0xff},
|
|
},
|
|
{
|
|
name: "Must set correct large delta",
|
|
args: args{
|
|
deltaType: rtcp.TypeTCCPacketReceivedLargeDelta,
|
|
delta: 32767,
|
|
},
|
|
want: []byte{0x7F, 0xFF},
|
|
},
|
|
{
|
|
name: "Must set correct large delta with padding",
|
|
fields: fields{
|
|
deltaLen: 1,
|
|
},
|
|
args: args{
|
|
deltaType: rtcp.TypeTCCPacketReceivedLargeDelta,
|
|
delta: uint16(a),
|
|
},
|
|
want: []byte{0, 0x80, 0x00},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t1.Run(tt.name, func(t1 *testing.T) {
|
|
t := &Responder{
|
|
deltaLen: tt.fields.deltaLen,
|
|
}
|
|
t.writeDelta(tt.args.deltaType, tt.args.delta)
|
|
assert.Equal(t1, tt.want, t.deltas[:t.deltaLen])
|
|
assert.Equal(t1, tt.fields.deltaLen+tt.args.deltaType, t.deltaLen)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTransportWideCC_writeHeader(t1 *testing.T) {
|
|
type fields struct {
|
|
tccPktCtn uint8
|
|
sSSRC uint32
|
|
mSSRC uint32
|
|
}
|
|
type args struct {
|
|
bSN uint16
|
|
packetCount uint16
|
|
refTime uint32
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want []byte
|
|
}{
|
|
{
|
|
name: "Must construct correct header",
|
|
fields: fields{
|
|
tccPktCtn: 23,
|
|
sSSRC: 4195875351,
|
|
mSSRC: 1124282272,
|
|
},
|
|
args: args{
|
|
bSN: 153,
|
|
packetCount: 1,
|
|
refTime: 4057090,
|
|
},
|
|
want: []byte{
|
|
0xfa, 0x17, 0xfa, 0x17,
|
|
0x43, 0x3, 0x2f, 0xa0,
|
|
0x0, 0x99, 0x0, 0x1,
|
|
0x3d, 0xe8, 0x2, 0x17},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
tt := tt
|
|
t1.Run(tt.name, func(t1 *testing.T) {
|
|
t := &Responder{
|
|
pktCtn: tt.fields.tccPktCtn,
|
|
sSSRC: tt.fields.sSSRC,
|
|
mSSRC: tt.fields.mSSRC,
|
|
}
|
|
t.writeHeader(tt.args.bSN, tt.args.packetCount, tt.args.refTime)
|
|
assert.Equal(t1, tt.want, t.payload[0:16])
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTccPacket(t1 *testing.T) {
|
|
want := []byte{
|
|
0xfa, 0x17, 0xfa, 0x17,
|
|
0x43, 0x3, 0x2f, 0xa0,
|
|
0x0, 0x99, 0x0, 0x1,
|
|
0x3d, 0xe8, 0x2, 0x17,
|
|
0x60, 0x18, 0x0, 0xdd,
|
|
0x9F, 0x1C, 0xcd, 0x50,
|
|
}
|
|
|
|
delta := []byte{
|
|
0xff, 0x80, 0xaa,
|
|
}
|
|
|
|
symbol1 := []uint16{rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived}
|
|
symbol2 := []uint16{
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketReceivedWithoutDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketReceivedSmallDelta,
|
|
rtcp.TypeTCCPacketNotReceived,
|
|
rtcp.TypeTCCPacketNotReceived}
|
|
|
|
t := &Responder{
|
|
pktCtn: 23,
|
|
sSSRC: 4195875351,
|
|
mSSRC: 1124282272,
|
|
}
|
|
t.writeHeader(153, 1, 4057090)
|
|
t.writeRunLengthChunk(rtcp.TypeTCCPacketReceivedWithoutDelta, 24)
|
|
t.writeRunLengthChunk(rtcp.TypeTCCPacketNotReceived, 221)
|
|
for i, v := range symbol1 {
|
|
t.createStatusSymbolChunk(rtcp.TypeTCCSymbolSizeOneBit, v, i)
|
|
}
|
|
t.writeStatusSymbolChunk(rtcp.TypeTCCSymbolSizeOneBit)
|
|
for i, v := range symbol2 {
|
|
t.createStatusSymbolChunk(rtcp.TypeTCCSymbolSizeTwoBit, v, i)
|
|
}
|
|
t.writeStatusSymbolChunk(rtcp.TypeTCCSymbolSizeTwoBit)
|
|
t.deltaLen = uint16(len(delta))
|
|
assert.Equal(t1, want, t.payload[:24])
|
|
|
|
pLen := t.len + t.deltaLen + 4
|
|
pad := pLen%4 != 0
|
|
for pLen%4 != 0 {
|
|
pLen++
|
|
}
|
|
hdr := rtcp.Header{
|
|
Padding: pad,
|
|
Length: (pLen / 4) - 1,
|
|
Count: rtcp.FormatTCC,
|
|
Type: rtcp.TypeTransportSpecificFeedback,
|
|
}
|
|
assert.Equal(t1, int(pLen), len(want)+3+4+1)
|
|
hb, _ := hdr.Marshal()
|
|
pkt := make([]byte, pLen)
|
|
copy(pkt, hb)
|
|
assert.Equal(t1, hb, pkt[:len(hb)])
|
|
copy(pkt[4:], t.payload[:t.len])
|
|
assert.Equal(t1, append(hb, t.payload[:t.len]...), pkt[:len(hb)+int(t.len)])
|
|
copy(pkt[4+t.len:], delta[:t.deltaLen])
|
|
assert.Equal(t1, delta, pkt[len(hb)+int(t.len):len(pkt)-1])
|
|
var ss rtcp.TransportLayerCC
|
|
err := ss.Unmarshal(pkt)
|
|
assert.NoError(t1, err)
|
|
|
|
assert.Equal(t1, hdr, ss.Header)
|
|
|
|
}
|
|
|
|
func BenchmarkBuildPacket(b *testing.B) {
|
|
rand.Seed(time.Now().UnixNano())
|
|
b.ReportAllocs()
|
|
n := 1 + rand.Intn(4-1+1)
|
|
var twcc Responder
|
|
tm := time.Now()
|
|
for i := 1; i < 100; i++ {
|
|
tm := tm.Add(time.Duration(60*n) * time.Millisecond)
|
|
twcc.extInfo = append(twcc.extInfo, rtpExtInfo{
|
|
ExtTSN: uint32(i),
|
|
Timestamp: tm.UnixNano(),
|
|
})
|
|
}
|
|
for i := 0; i < b.N; i++ {
|
|
_ = twcc.buildTransportCCPacket()
|
|
}
|
|
}
|