All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.xingshuangs.iot.protocol.rtcp.service.RtcpDataStatistics Maven / Gradle / Ivy

package com.github.xingshuangs.iot.protocol.rtcp.service;


import com.github.xingshuangs.iot.protocol.rtcp.enums.ERtcpSdesItemType;
import com.github.xingshuangs.iot.protocol.rtcp.model.*;
import com.github.xingshuangs.iot.protocol.rtp.model.RtpPackage;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.function.Consumer;

/**
 * RTP接收数据统计
 *
 * @author xingshuang
 */
@Slf4j
@Data
public class RtcpDataStatistics {

    /**
     * 同步源(SSRC of sender):32比特,SR包发送者的同步源标识符。与对应RTP包中的SSRC一样。
     */
    private long sourceId;

    /**
     * 接收的最大序号
     */
    private int highestSequenceNumber = 0;

    /**
     * 从上一次重置之后的包接收数量
     */
    private int packetsReceivedSinceLastReset = 0;

    /**
     * 从上一次重置之后的丢包数量
     */
    private int packetsLostSinceLastReset = 0;

    /**
     * 累计丢包数量
     */
    private int cumulativePacketLost = 0;

    /**
     * 序列号循环被使用次数
     */
    private int sequenceNumberCycles = 0;

    /**
     * 采样总时间
     */
    private long sampleTimestampSum = 0;

    /**
     * 上一次的RTP时间戳
     */
    private long lastRtpTimestamp = 0;

    /**
     * 上一次RTP的SSRC
     */
    private long lastRtpSsrc = 0;

    /**
     * 上一次RTCP发送SR的NTP时间
     */
    private long lastNtpTimeSenderReportReceived = 0;

    /**
     * 上一次接收到的SR的时间
     */
    private long lastTimeRtcpReportReceived = 0;

    /**
     * 上一次接收到RTP的时间,本地当前的时间戳
     */
    private long lastLocalTimeReceiveRtp = 0;

    public RtcpDataStatistics() {
        this.sourceId = System.currentTimeMillis();
    }

    /**
     * 处理RTP数据包
     *
     * @param rtp RTP数据包
     * @param send 回调发送字节数据
     */
    public void processRtpPackage(RtpPackage rtp, Consumer send) {
        if (this.lastRtpSsrc > 0) {
            this.sampleTimestampSum += rtp.getHeader().getTimestamp() - this.lastRtpTimestamp;
            int delta = rtp.getHeader().getSequenceNumber() - this.highestSequenceNumber;
            if (delta > 1) {
                this.cumulativePacketLost += delta - 1;
                this.packetsLostSinceLastReset += delta - 1;
            }
            if (this.cumulativePacketLost > 0x7FFFFF) {
                this.cumulativePacketLost = 0x7FFFFF;
            }
            if (rtp.getHeader().getSequenceNumber() < this.highestSequenceNumber) {
                this.sequenceNumberCycles++;
            }
        }
        this.packetsReceivedSinceLastReset++;
        this.highestSequenceNumber = rtp.getHeader().getSequenceNumber();
        this.lastRtpSsrc = rtp.getHeader().getSsrc();
        this.lastRtpTimestamp = rtp.getHeader().getTimestamp();

        // 第一次接收rtp数据
        if (this.lastLocalTimeReceiveRtp == 0) {
            this.lastLocalTimeReceiveRtp = System.currentTimeMillis();
        }

        // 时间间隔超过5s的发一次RR数据,接收数据报告
        if (System.currentTimeMillis() - this.lastLocalTimeReceiveRtp > 5_000) {
            byte[] receiverAndByteContent = this.createReceiverAndSdesContent();
            send.accept(receiverAndByteContent);
            this.lastLocalTimeReceiveRtp = System.currentTimeMillis();
        }
    }

    /**
     * 重置状态
     */
    public void resetState() {
        this.packetsLostSinceLastReset = 0;
        this.packetsReceivedSinceLastReset = 0;
    }

    /**
     * 处理RTCP数据包
     *
     * @param basePackages rtcp数据包列表
     */
    public void processRtcpPackage(List basePackages) {
        for (RtcpBasePackage rtcp : basePackages) {
            log.debug("RTCP接收[{}]数据,{}", rtcp.getHeader().getPackageType(), rtcp);
            if (rtcp instanceof RtcpSenderReport) {
                this.lastNtpTimeSenderReportReceived = ((RtcpSenderReport) rtcp).getSenderInfo().getMswTimestamp();
                this.lastTimeRtcpReportReceived = System.currentTimeMillis();
            }
        }
    }

    /**
     * 创建接收报告
     *
     * @return RtcpReceiverReport
     */
    public RtcpReceiverReport createReceiverReport() {
        // 丢包率(8bit):丢包率需要转换为0-255的占比;如20%丢包=20%*255=51
        int fractionLost = 0;
        if (this.packetsReceivedSinceLastReset != 0) {
            fractionLost = this.packetsLostSinceLastReset * 256 / this.packetsReceivedSinceLastReset;
        }
        // 期望接收的最大序列号,低16位存储期望最大序列号;高16为翻转次数统计
        long extHighestSequenceNumberReceived = ((long) this.sequenceNumberCycles << 16) | this.highestSequenceNumber;
        // 最后一次接收SR到发送的时延(32bit):DLSR最后一次收到SR包后到发送中间的时延;
        long delaySinceLastTimeSenderReportReceived = 0;
        if (this.lastTimeRtcpReportReceived > 0) {
            delaySinceLastTimeSenderReportReceived = (System.currentTimeMillis() - this.lastTimeRtcpReportReceived) / 1000 * 65536;
        }
        RtcpReceiverReport receiverReport = new RtcpReceiverReport(this.sourceId);
        RtcpReportBlock reportBlock = new RtcpReportBlock();
        reportBlock.setSourceId(this.lastRtpSsrc);
        reportBlock.setFractionLost(fractionLost);
        reportBlock.setCumulativePacketLost(this.cumulativePacketLost);
        reportBlock.setExtHighestSequenceNumberReceived(extHighestSequenceNumberReceived);
        reportBlock.setJitter(0);
        reportBlock.setLastNtpTimeSenderReportReceived(this.lastNtpTimeSenderReportReceived);
        reportBlock.setDelaySinceLastTimeSenderReportReceived(delaySinceLastTimeSenderReportReceived);
        receiverReport.addRtcpReportBlock(reportBlock);
        return receiverReport;
    }

    /**
     * 创建SDES报告
     *
     * @return RtcpSdesReport
     */
    public RtcpSdesReport createSdesReport() {
        RtcpSdesReport sdesReport = new RtcpSdesReport();
        RtcpSdesChunk chunk = new RtcpSdesChunk(this.sourceId);
        RtcpSdesItem item = new RtcpSdesItem();
        item.setType(ERtcpSdesItemType.CNAME);
        item.setText("iot-communication");
        item.setLength(17);
        chunk.addRtcpSdesItem(item);
        sdesReport.addRtcpSdesChunk(chunk);
        return sdesReport;
    }

    /**
     * 创建Byte
     *
     * @return RtcpBye
     */
    public RtcpBye createByte() {
        return new RtcpBye(this.sourceId);
    }

    /**
     * 创建RR内容的报告字节数组
     *
     * @return 字节数组
     */
    public byte[] createReceiverAndSdesContent() {
        RtcpReceiverReport receiverReport = this.createReceiverReport();
        RtcpSdesReport sdesReport = this.createSdesReport();
        log.debug("RTCP发送[{}]数据,{}", receiverReport.getHeader().getPackageType(), receiverReport);
        log.debug("RTCP发送[{}]数据,{}", sdesReport.getHeader().getPackageType(), sdesReport);
        byte[] res = new byte[receiverReport.byteArrayLength() + sdesReport.byteArrayLength()];
        System.arraycopy(receiverReport.toByteArray(), 0, res, 0, receiverReport.byteArrayLength());
        System.arraycopy(sdesReport.toByteArray(), 0, res, receiverReport.byteArrayLength(), sdesReport.byteArrayLength());
        return res;
    }

    /**
     * 创建byte的报告字节数组
     *
     * @return 字节数组
     */
    public byte[] createReceiverAndByteContent() {
        RtcpReceiverReport receiverReport = this.createReceiverReport();
        RtcpBye aByte = this.createByte();
        log.debug("RTCP发送[{}]数据,{}", receiverReport.getHeader().getPackageType(), receiverReport);
        log.debug("RTCP发送[{}]数据,{}", aByte.getHeader().getPackageType(), aByte);
        byte[] res = new byte[receiverReport.byteArrayLength() + aByte.byteArrayLength()];
        System.arraycopy(receiverReport.toByteArray(), 0, res, 0, receiverReport.byteArrayLength());
        System.arraycopy(aByte.toByteArray(), 0, res, receiverReport.byteArrayLength(), aByte.byteArrayLength());
        return res;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy