//奔函数用于计算抖动,每次接收到一个rtp包后,都会调用此函数计算抖动。 void RTPReceptionStats ::noteIncomingPacket(u_int16_t seqNum, u_int32_t rtpTimestamp, unsigned timestampFrequency, Boolean useForJitterCalculation, struct timeval& resultPresentationTime, Boolean& resultHasBeenSyncedUsingRTCP, unsigned packetSize) { if (!fHaveSeenInitialSequenceNumber) initSeqNum(seqNum); ++fNumPacketsReceivedSinceLastReset; //上次重置后,接收到的rtp包个数。 ++fTotNumPacketsReceived; //一共接收到的rtp包个数。 u_int32_t prevTotBytesReceived_lo = fTotBytesReceived_lo; //fTotBytesReceived_lo,总共接收到的rtp字节数。 fTotBytesReceived_lo += packetSize; if (fTotBytesReceived_lo < prevTotBytesReceived_lo) { // wrap-around fTotBytesReceived_lo是一个无符号32位整数,当达到最大值后,会从新开始计算。 ++fTotBytesReceived_hi; // 归零次数。 } // Check whether the new sequence number is the highest yet seen: unsigned oldSeqNum = (fHighestExtSeqNumReceived&0xFFFF); //取低16位数据 unsigned seqNumCycle = (fHighestExtSeqNumReceived&0xFFFF0000); //取高16位数据 unsigned seqNumDifference = (unsigned)((int)seqNum-(int)oldSeqNum); unsigned newSeqNum = 0; if (seqNumLT((u_int16_t)oldSeqNum, seqNum)) { //当前序列号大于前一次的序列号,看似是合法的rtp包。但还是要检测是否出现归零的情况。 // This packet was not an old packet received out of order, so check it: if (seqNumDifference >= 0x8000) { //出现归零的情况,0x8000最高位(即16位)上为1,其余位为0,前后序列号差距如此到,假设出现归零的情况。 // The sequence number wrapped around, so start a new cycle: seqNumCycle += 0x10000; } newSeqNum = seqNumCycle|seqNum; // 当前序列号和循坏次数做一个组合。 if (newSeqNum > fHighestExtSeqNumReceived) { //当新的序号比前一次的序列号小时,if语句会有可能为true。 fHighestExtSeqNumReceived = newSeqNum; //新的组合保存到成员变量里面。 } } else if (fTotNumPacketsReceived > 1) { //先前已经接收到了rtp包。有rtp包已经存在。 // This packet was an old packet received out of order if ((int)seqNumDifference >= 0x8000) {//出现归零的情况,0x8000最高位(即16位)上为1,其余位为0,前后序列号差距如此到,假设出现归零的情况。 // The sequence number wrapped around, so switch to an old cycle: seqNumCycle -= 0x10000; //上次出现了一次归零的情况,所以这里要把循坏次数减一。 } //这里的代码,上面出现过,见上面的解释。 newSeqNum = seqNumCycle|seqNum; if (newSeqNum < fBaseExtSeqNumReceived) { fBaseExtSeqNumReceived = newSeqNum; } } // Record the inter-packet delay struct timeval timeNow; gettimeofday(&timeNow, NULL); if (fLastPacketReceptionTime.tv_sec != 0 || fLastPacketReceptionTime.tv_usec != 0) { unsigned gap //计算rtp包的时间间隔。单位:一百万分之一秒,微秒,1/1000000秒。 = (timeNow.tv_sec - fLastPacketReceptionTime.tv_sec)*MILLION + timeNow.tv_usec - fLastPacketReceptionTime.tv_usec; if (gap > fMaxInterPacketGapUS) { //记录出现过的最大rtp包时间间隔。 fMaxInterPacketGapUS = gap; } if (gap < fMinInterPacketGapUS) { //记录出现过的最小rtp包时间间隔。 fMinInterPacketGapUS = gap; } fTotalInterPacketGaps.tv_usec += gap; //fTotalInterPacketGaps,两个rtp包到达的时间间隔累计。 if (fTotalInterPacketGaps.tv_usec >= MILLION) { //数学计算,进1。 ++fTotalInterPacketGaps.tv_sec; fTotalInterPacketGaps.tv_usec -= MILLION; } } fLastPacketReceptionTime = timeNow; //fLastPacketReceptionTime,记录rtp包抵达的时间。 // Compute the current ‘jitter‘ using the received packet‘s RTP timestamp, // and the RTP timestamp that would correspond to the current time. // (Use the code from appendix A.8 in the RTP spec.) // Note, however, that we don‘t use this packet if its timestamp is // the same as that of the previous packet (this indicates a multi-packet // fragment), or if we‘ve been explicitly told not to use this packet. /* * 如果当前rtp包时间戳和上一个rtp包时间戳相同,不用此rtp包计算抖动。fPreviousPacketRTPTimestamp==rtpTimestamp。 */ if (useForJitterCalculation && rtpTimestamp != fPreviousPacketRTPTimestamp) { //rtpTimestamp,rtp包头部记录的时间戳。 unsigned arrival = (timestampFrequency*timeNow.tv_sec); arrival += (unsigned) //计算rtp包的理论抵达时间。 ((2.0*timestampFrequency*timeNow.tv_usec + 1000000.0)/2000000); // note: rounding int transit = arrival - rtpTimestamp; //理论和实际的时间差值。 if (fLastTransit == (~0)) fLastTransit = transit; // hack for first time //如果是第一个rtp包。 int d = transit - fLastTransit; //求本次差值和上次差值的差异。 fLastTransit = transit; //把当前差值放到上次差值成员变量里面,下次使用。 if (d < 0) d = -d; //取正数。 fJitter += (1.0/16.0) * ((double)d - fJitter); //计算出抖动值。每次d的权重会越来越低,变体为:( (double)d )/16 + (15.0/16.0)*fJitter。 } // Return the ‘presentation time‘ that corresponds to "rtpTimestamp": //根据rtp头部的时间戳,计算显现时间。 if (fSyncTime.tv_sec == 0 && fSyncTime.tv_usec == 0) { // This is the first timestamp that we‘ve seen, so use the current // ‘wall clock‘ time as the synchronization time. (This will be // corrected later when we receive RTCP SRs.) fSyncTimestamp = rtpTimestamp; //fSyncTimestamp上次的rtp头部时间戳。 fSyncTime = timeNow; //fSyncTime上次计算出来的呈现时间,基于接收端的本地时间,gettimeofday(&timeNow, NULL);。 } int timestampDiff = rtpTimestamp - fSyncTimestamp; //rtp头部时间戳和上次的rtp头部时间戳的差值。 // Note: This works even if the timestamp wraps around // (as long as "int" is 32 bits) //timestampFrequency,采样率,每秒钟采样的数量。 //rtpTimestamp,设备每采样一次,时间戳递增1。 // Divide this by the timestamp frequency to get real time: double timeDiff = timestampDiff/(double)timestampFrequency; //获取前后rtp包的时间差,单位为妙。 // Add this to the ‘sync time‘ to get our result: unsigned const million = 1000000; unsigned seconds, uSeconds; if (timeDiff >= 0.0) { seconds = fSyncTime.tv_sec + (unsigned)(timeDiff); //取秒数。 uSeconds = fSyncTime.tv_usec + (unsigned)((timeDiff - (unsigned)timeDiff)*million); //取微妙数。 if (uSeconds >= million) { uSeconds -= million; ++seconds; } } else { //timeDiff的负数这种情况的处理。 //如果当前rtp包的序列号小于前一次rtp包的序列号,并且它们的时间戳不同,就会有这种负数的情况。 timeDiff = -timeDiff; seconds = fSyncTime.tv_sec - (unsigned)(timeDiff); uSeconds = fSyncTime.tv_usec - (unsigned)((timeDiff - (unsigned)timeDiff)*million); if ((int)uSeconds < 0) { uSeconds += million; --seconds; } } //已经计算出要呈现的时间,通过resultPresentationTime返回时间数值。 resultPresentationTime.tv_sec = seconds; resultPresentationTime.tv_usec = uSeconds; resultHasBeenSyncedUsingRTCP = fHasBeenSynchronized; //估计用于rtcp使用,标示当前的统计数据有没有被rtcp使用。 //记录这次同步的时间戳和时间。 // Save these as the new synchronization timestamp & time: fSyncTimestamp = rtpTimestamp; fSyncTime = resultPresentationTime; fPreviousPacketRTPTimestamp = rtpTimestamp; }
资料:
rtp抖动--RFC3550,附录A.8 https://www.ietf.org/rfc/rfc3550.txt
网络图书--《RTP: Audio and Video for the Internet By Colin Perkings》,见:百度网盘\共享\G:\workspace\download\RTP -- Audio and Video for the Internet By Colin Perkings.pdf
完。
时间: 2024-10-20 03:26:37