[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;
}
作者 —— 靑い空゛
出处:http://www.cnblogs.com/ailumiyana/
除特别注明外,本站所有文章均为靑い空゛原创,欢迎转载分享,但请注明出处。
出处:http://www.cnblogs.com/ailumiyana/
除特别注明外,本站所有文章均为靑い空゛原创,欢迎转载分享,但请注明出处。