You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lal/pkg/rtprtcp/rr_producer.go

144 lines
3.0 KiB
Go

// Copyright 2020, Chef. All rights reserved.
// https://github.com/q191201771/lal
//
// Use of this source code is governed by a MIT-style license
// that can be found in the License file.
//
// Author: Chef (191201771@qq.com)
package rtprtcp
import "time"
// 通过收到的rtp包和rtcp sr包产生rtcp rr包
type RRProducer struct {
senderSSRC uint32
mediaSSRC uint32
clockRate int
maxSeq int32
baseSeq int32
cycles uint32
received uint32
extendedSeq uint32
transit int64
jitter uint32
expectedPrior uint32
receivedPrior uint32
}
func NewRRProducer(clockRate int) *RRProducer {
return &RRProducer{
clockRate: clockRate,
baseSeq: -1,
maxSeq: -1,
transit: -1,
}
}
// 每次收到rtp包都将seq序号传入这个函数
func (r *RRProducer) FeedRTPPacket(seq uint16) {
r.received++
if r.baseSeq == -1 {
r.baseSeq = int32(seq)
}
if r.maxSeq == -1 {
r.maxSeq = int32(seq)
} else {
if CompareSeq(seq, uint16(r.maxSeq)) > 0 {
if seq < uint16(r.maxSeq) {
r.cycles++
}
r.maxSeq = int32(seq)
}
}
r.extendedSeq = (r.cycles << 16) | uint32(r.maxSeq)
}
// 收到sr包时产生rr包
//
// @param lsr: 从sr包中获取见func SR.GetMiddleNTP
// @return: rr包的二进制数据
//
func (r *RRProducer) Produce(lsr uint32) []byte {
if r.baseSeq == -1 {
return nil
}
var lost uint32
expected := r.extendedSeq - uint32(r.baseSeq) + 1
if expected < r.received {
lost = 0
} else {
lost = expected - r.received
}
var fraction uint8
expectedInterval := expected - r.expectedPrior
r.expectedPrior = expected
receivedInterval := r.received - r.receivedPrior
r.receivedPrior = r.received
lostInterval := expectedInterval - receivedInterval
if expectedInterval == 0 || lostInterval <= 0 {
fraction = 0
} else {
fraction = uint8((lostInterval << 8) / expectedInterval)
}
var rr RR
rr.senderSSRC = r.senderSSRC
rr.mediaSSRC = r.mediaSSRC
rr.fraction = fraction
rr.lost = lost
rr.cycles = uint16(r.cycles)
rr.extendedSeq = r.extendedSeq
rr.jitter = r.getJitter()
rr.lsr = lsr
return rr.Pack()
}
// @param timestamp 当前收到的rtp包头中的时间戳
func (r *RRProducer) updateJitter(timestamp uint32) {
// rfc3550 6.4.1 SR: Sender Report RTCP Packet
// rfc3550 A.8 Estimating the Interarrival Jitter
// 当前收到rtp包的本地物理时间
arrival := int64(time.Now().UnixNano() / 1e6)
// 物理时间和包时间的差值,都换算成包时间戳格式
transit := arrival*(int64(r.clockRate)/1000) - int64(timestamp)
// 第一次跳过
if r.transit == -1 {
r.transit = transit
return
}
// 这次差值,和上一次差值相减
d := transit - r.transit
if d < 0 {
d = -d
}
// 一种设置jitter的方式
// set: r.jitter += (float32(1)/16) * (d - r.jitter)
// get: return r.jitter
//
// 另外一种方式
// 对应的get: return r.jitter >> 4
// 注意,右边的计算结果肯定是正数
r.jitter = r.jitter + uint32(d) - ((r.jitter + 8) >> 4)
}
func (r *RRProducer) getJitter() uint32 {
return r.jitter >> 4
}