最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

全球快播:[issues] webrtc 接入SRS丢包率不正确问题

来源:博客园


(相关资料图)

目录
  • [issues] webrtc 接入SRS丢包率不正确问题
    • 原因和解决方法
    • srs增加rtx
      • SDP协商
      • 构建RTX包

[issues] webrtc 接入SRS丢包率不正确问题

原因和解决方法

直接原因: SRS暂不支持RTX通道发送nack重传包,重传包以media形式发送,sdk没有区分开来,没有将nack重传包计入丢包统计,得到的实际丢包率远低于实际丢包率

解决方法:

  • 1.StreamStatisticianImpl::UpdateOutOfOrder->IsRetransmitOfOldPacket 优化计算重传包函数,可以根据重传包达到时间与RTT比较,将时差长的包计入丢包,粗略计算丢包率。

  • 2.srs 增加rtx 通道发送nack,需要修改SDP协商部分,和rtx编码封包nack重传包.

srs增加rtx

这里简单过来拉流端增加方法

RTX在webrtc SDK里面视频是默认打开RTX的[M88],SRS没有支持,需要先在SRS SDP协商里面解析和分配rtx相关字段.

SDP协商

SrsRtcConnection::negotiate_play_capability 里面分配 rtx_ssrc_, rtx_pt, rtx_apt。其他还有 FID ssrc_groups

// TODO: FIXME: set audio_payload rtcp_fbs_,    // according by whether downlink is support transport algorithms.    // TODO: FIXME: if we support downlink RTX, MUST assign rtx_ssrc_, rtx_pt, rtx_apt    // not support rtx    vector rtx_pts = remote_media_desc.find_media_with_encoding_name("rtx");    if (true) {        //srs_freep(track->rtx_);        //track->rtx_ssrc_ = 0;        track->rtx_ssrc_ = SrsRtcSSRCGenerator::instance()->generate_ssrc();        for (size_t i = 0; i < rtx_pts.size(); i++) {            SrsMediaPayloadType rtx_pt = rtx_pts.at(i);            uint8_t pt = ::atol(rtx_pt.format_specific_param_.substr(4, 3).c_str());            if (track->media_->pt_ == pt) {                if (!track->rtx_) {                    track->rtx_ = new SrsCodecPayload();                }                track->rtx_->pt_of_publisher_ = track->rtx_->pt_;                track->rtx_->pt_ = rtx_pt.payload_type_;                track->rtx_->sample_ = rtx_pt.clock_rate_;                ((SrsRtxPayloadDes*)(track->rtx_))->apt_ = pt;//::atol(rtx_pt.format_specific_param_.c_str());                break;            }        }    }

sdp 协商调试后,sdk 收到的sdp rtx部分大致长这个样子:

a=rtpmap:101 rtx/90000a=fmtp:101 apt=100a=ssrc-group:FID 5333335 5333336a=ssrc:5333335 cname:15817311631_8010a=ssrc:5333335 msid:stream_id video_labela=ssrc:5333335 mslabel:stream_ida=ssrc:5333335 label:video_labela=ssrc:5333336 cname:15817311631_8010a=ssrc:5333336 msid:stream_id video_labela=ssrc:5333336 mslabel:stream_ida=ssrc:5333336 label:video_labela=candidate:0 1 udp 2130706431 192.168.6.54 8000 typ host generation 0

构建RTX包

rtx构建很简单,新定义个 SrsRtpRtxPayload, rtp头重写下type 序列号等, payload copy一下 头两个字节写media 的序列号, 对照着SDK里面加,打印下hex调试下即可。

// RTX Payload.class SrsRtpRtxPayload : public ISrsRtpPayloader{public:    char* payload;    int size;    uint16_t sequence_number;public:    SrsRtpRtxPayload();    virtual ~SrsRtpRtxPayload();// interface ISrsRtpPayloaderpublic:    virtual uint64_t nb_bytes();    virtual srs_error_t encode(SrsBuffer* buf);    virtual srs_error_t decode(SrsBuffer* buf);    virtual ISrsRtpPayloader* copy();};SrsRtpPacket* SrsRtcSendTrack::build_rtx_packet(    SrsRtpPacket* packet) {        SrsRtpPacket* rtx_packet;    SrsRtcTrackDescription* track_desc = get_rtc_track_desc();    SrsRtxPayloadDes* rtx_desc = (SrsRtxPayloadDes*)(track_desc->rtx_);    uint8_t pt = packet->header.get_payload_type();    uint8_t ppt = rtx_desc->pt_;    uint8_t apt = rtx_desc->apt_;    rtx_packet = packet->copy_with_no_payload();    rtx_packet->header = packet->header;    rtx_packet->header.set_payload_type(ppt);    static uint16_t sequence_number_rtx_ = 1234; //only test    rtx_packet->header.set_sequence(sequence_number_rtx_++);    rtx_packet->header.set_ssrc(track_desc->rtx_ssrc_);        char buf[kRtpPacketSize];    SrsBuffer* stream = new SrsBuffer(buf, sizeof(buf));    SrsAutoFree(SrsBuffer, stream);    packet->payload()->encode(stream);        SrsRtpRtxPayload* rtx_payload = new SrsRtpRtxPayload();    rtx_payload->decode(stream);    rtx_payload->sequence_number = packet->header.get_sequence();    rtx_packet->set_payload(rtx_payload, SrsRtspPacketPayloadTypeRTX);    rtx_packet->retransmission_ = true;    return rtx_packet;}

关键词: