[issues] webrtc 接入SRS丟包率不正確問題

[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<SrsMediaPayloadType> 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/90000
a=fmtp:101 apt=100
a=ssrc-group:FID 5333335 5333336
a=ssrc:5333335 cname:15817311631_8010
a=ssrc:5333335 msid:stream_id video_label
a=ssrc:5333335 mslabel:stream_id
a=ssrc:5333335 label:video_label
a=ssrc:5333336 cname:15817311631_8010
a=ssrc:5333336 msid:stream_id video_label
a=ssrc:5333336 mslabel:stream_id
a=ssrc:5333336 label:video_label
a=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 ISrsRtpPayloader
public:
    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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章