Files
livekit/pkg/sfu/packetqueue.go
2020-10-23 23:01:35 -07:00

125 lines
2.4 KiB
Go

package sfu
import (
//"github.com/pion/ion-sfu/pkg/log"
"github.com/pion/rtcp"
"github.com/pion/rtp"
)
type queue struct {
pkts []*rtp.Packet
ssrc uint32
head int
tail int
size int
headSN uint16
counter int
duration uint32
onLost func(nack *rtcp.TransportLayerNack)
}
func (q *queue) AddPacket(pkt *rtp.Packet, latest bool) {
if !latest {
q.set(int(q.headSN-pkt.SequenceNumber), pkt)
return
}
diff := pkt.SequenceNumber - q.headSN
q.headSN = pkt.SequenceNumber
for i := uint16(1); i < diff; i++ {
q.push(nil)
q.counter++
}
q.counter++
q.push(pkt)
if q.counter >= 7 {
if n := q.nack(); n != nil && q.onLost != nil {
q.onLost(&rtcp.TransportLayerNack{
MediaSSRC: q.ssrc,
Nacks: []rtcp.NackPair{*n},
})
}
q.clean()
q.counter -= 5
}
}
func (q *queue) GetPacket(sn uint16) *rtp.Packet {
return q.get(int(q.headSN - sn))
}
func (q *queue) push(pkt *rtp.Packet) {
q.resize()
q.head = (q.head - 1) & (len(q.pkts) - 1)
q.pkts[q.head] = pkt
q.size++
}
func (q *queue) shift() {
if q.size <= 0 {
return
}
q.tail = (q.tail - 1) & (len(q.pkts) - 1)
q.pkts[q.tail] = nil
q.size--
}
func (q *queue) last() *rtp.Packet {
return q.pkts[(q.tail-1)&(len(q.pkts)-1)]
}
func (q *queue) get(i int) *rtp.Packet {
if i < 0 || i >= q.size {
return nil
}
return q.pkts[(q.head+i)&(len(q.pkts)-1)]
}
func (q *queue) set(i int, pkt *rtp.Packet) {
if i < 0 || i >= q.size {
//log.Warnf("warn: %v:", errPacketTooOld)
return
}
q.pkts[(q.head+i)&(len(q.pkts)-1)] = pkt
}
func (q *queue) resize() {
if len(q.pkts) == 0 {
q.pkts = make([]*rtp.Packet, 128)
return
}
if q.size == len(q.pkts) {
newBuf := make([]*rtp.Packet, q.size<<1)
if q.tail > q.head {
copy(newBuf, q.pkts[q.head:q.tail])
} else {
n := copy(newBuf, q.pkts[q.head:])
copy(newBuf[n:], q.pkts[:q.tail])
}
q.head = 0
q.tail = q.size
q.pkts = newBuf
}
}
func (q *queue) nack() *rtcp.NackPair {
for i := 0; i < 5; i++ {
if q.get(q.counter-i-1) == nil {
blp := uint16(0)
for j := 1; j < q.counter-i; j++ {
if q.get(q.counter-i-j-1) == nil {
blp |= 1 << (j - 1)
}
}
return &rtcp.NackPair{PacketID: q.headSN - uint16(q.counter-i-1), LostPackets: rtcp.PacketBitmap(blp)}
}
}
return nil
}
func (q *queue) clean() {
last := q.last()
for q.size > 120 && (last == nil || q.pkts[q.head].Timestamp-last.Timestamp > q.duration) {
q.shift()
}
}