// 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 }