From 5df2b8075749af1a4d8107f71485b4e2bd222716 Mon Sep 17 00:00:00 2001 From: gongluck Date: Sun, 12 May 2024 18:15:11 +0800 Subject: [PATCH] =?UTF-8?q?Nack=E7=9B=B8=E5=85=B3=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E5=8F=AF=E9=85=8D=E7=BD=AE=E5=8C=96=20(#3510=20#3507)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 18 +++++++++++ webrtc/Nack.cpp | 61 +++++++++++++++++++++++++++++++------- webrtc/Nack.h | 12 -------- webrtc/WebRtcTransport.cpp | 8 ++++- 4 files changed, 76 insertions(+), 23 deletions(-) diff --git a/conf/config.ini b/conf/config.ini index 872d2d32..89800db2 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -367,6 +367,24 @@ start_bitrate=0 max_bitrate=0 min_bitrate=0 +#nack接收端 +#Nack缓存包最早时间间隔 +maxNackMS=5000 +#Nack包检查间隔(包数量) +rtpCacheCheckInterval=100 + +#nack发送端 +#最大保留的rtp丢包状态个数 +nackMaxSize=2048 +#rtp丢包状态最长保留时间 +nackMaxMS=3000 +#nack最多请求重传次数 +nackMaxCount=15 +#nack重传频率,rtt的倍数 +nackIntervalRatio=1.0 +#nack包中rtp个数,减小此值可以让nack包响应更灵敏 +nackRtpSize=8 + [srt] #srt播放推流、播放超时时间,单位秒 timeoutSec=5 diff --git a/webrtc/Nack.cpp b/webrtc/Nack.cpp index 6197117e..4fd1f101 100644 --- a/webrtc/Nack.cpp +++ b/webrtc/Nack.cpp @@ -9,24 +9,56 @@ */ #include "Nack.h" +#include "Common/config.h" using namespace std; using namespace toolkit; namespace mediakit { -static constexpr uint32_t kMaxNackMS = 5 * 1000; -static constexpr uint32_t kRtpCacheCheckInterval = 100; +// RTC配置项目 +namespace Rtc { +#define RTC_FIELD "rtc." +//~ nack接收端 +// Nack缓存包最早时间间隔 +const string kMaxNackMS = RTC_FIELD "maxNackMS"; +// Nack包检查间隔(包数量) +const string kRtpCacheCheckInterval = RTC_FIELD "rtpCacheCheckInterval"; +//~ nack发送端 +//最大保留的rtp丢包状态个数 +const string kNackMaxSize = RTC_FIELD "nackMaxSize"; +// rtp丢包状态最长保留时间 +const string kNackMaxMS = RTC_FIELD "nackMaxMS"; +// nack最多请求重传次数 +const string kNackMaxCount = RTC_FIELD "nackMaxCount"; +// nack重传频率,rtt的倍数 +const string kNackIntervalRatio = RTC_FIELD "nackIntervalRatio"; +// nack包中rtp个数,减小此值可以让nack包响应更灵敏 +const string kNackRtpSize = RTC_FIELD "nackRtpSize"; + +static onceToken token([]() { + mINI::Instance()[kMaxNackMS] = 5 * 1000; + mINI::Instance()[kRtpCacheCheckInterval] = 100; + mINI::Instance()[kNackMaxSize] = 2048; + mINI::Instance()[kNackMaxMS] = 3 * 1000; + mINI::Instance()[kNackMaxCount] = 15; + mINI::Instance()[kNackIntervalRatio] = 1.0f; + mINI::Instance()[kNackRtpSize] = 8; +}); + +} // namespace Rtc void NackList::pushBack(RtpPacket::Ptr rtp) { auto seq = rtp->getSeq(); _nack_cache_seq.emplace_back(seq); _nack_cache_pkt.emplace(seq, std::move(rtp)); - if (++_cache_ms_check < kRtpCacheCheckInterval) { + GET_CONFIG(uint32_t, rtpcache_checkinterval, Rtc::kRtpCacheCheckInterval); + if (++_cache_ms_check < rtpcache_checkinterval) { return; } _cache_ms_check = 0; - while (getCacheMS() >= kMaxNackMS) { + GET_CONFIG(uint32_t, maxnackms, Rtc::kMaxNackMS); + while (getCacheMS() >= maxnackms) { // 需要清除部分nack缓存 popFront(); } @@ -148,10 +180,13 @@ void NackContext::makeNack(uint16_t max_seq, bool flush) { eraseFrontSeq(); // 最多生成5个nack包,防止seq大幅跳跃导致一直循环 auto max_nack = 5u; + GET_CONFIG(uint32_t, nack_rtpsize, Rtc::kNackRtpSize); + // kNackRtpSize must between 0 and 16 + nack_rtpsize = std::min(nack_rtpsize, FCI_NACK::kBitSize); while (_nack_seq != max_seq && max_nack--) { // 一次不能发送超过16+1个rtp的状态 uint16_t nack_rtp_count = std::min(FCI_NACK::kBitSize, max_seq - (uint16_t)(_nack_seq + 1)); - if (!flush && nack_rtp_count < kNackRtpSize) { + if (!flush && nack_rtp_count < nack_rtpsize) { // 非flush状态下,seq个数不足以发送一次nack break; } @@ -206,7 +241,9 @@ void NackContext::clearNackStatus(uint16_t seq) { _nack_send_status.erase(it); // 限定rtt在合理有效范围内 - _rtt = max(10, min(rtt, kNackMaxMS / kNackMaxCount)); + GET_CONFIG(uint32_t, nack_maxms, Rtc::kNackMaxMS); + GET_CONFIG(uint32_t, nack_maxcount, Rtc::kNackMaxCount); + _rtt = max(10, min(rtt, nack_maxms / nack_maxcount)); } void NackContext::recordNack(const FCI_NACK &nack) { @@ -222,7 +259,8 @@ void NackContext::recordNack(const FCI_NACK &nack) { ++i; } // 记录太多了,移除一部分早期的记录 - while (_nack_send_status.size() > kNackMaxSize) { + GET_CONFIG(uint32_t, nack_maxsize, Rtc::kNackMaxSize); + while (_nack_send_status.size() > nack_maxsize) { _nack_send_status.erase(_nack_send_status.begin()); } } @@ -230,13 +268,16 @@ void NackContext::recordNack(const FCI_NACK &nack) { uint64_t NackContext::reSendNack() { set nack_rtp; auto now = getCurrentMillisecond(); + GET_CONFIG(uint32_t, nack_maxms, Rtc::kNackMaxMS); + GET_CONFIG(uint32_t, nack_maxcount, Rtc::kNackMaxCount); + GET_CONFIG(float, nack_intervalratio, Rtc::kNackIntervalRatio); for (auto it = _nack_send_status.begin(); it != _nack_send_status.end();) { - if (now - it->second.first_stamp > kNackMaxMS) { + if (now - it->second.first_stamp > nack_maxms) { // 该rtp丢失太久了,不再要求重传 it = _nack_send_status.erase(it); continue; } - if (now - it->second.update_stamp < kNackIntervalRatio * _rtt) { + if (now - it->second.update_stamp < nack_intervalratio * _rtt) { // 距离上次nack不足2倍的rtt,不用再发送nack ++it; continue; @@ -245,7 +286,7 @@ uint64_t NackContext::reSendNack() { nack_rtp.emplace(it->first); // 更新nack发送时间戳 it->second.update_stamp = now; - if (++(it->second.nack_count) == kNackMaxCount) { + if (++(it->second.nack_count) == nack_maxcount) { // nack次数太多,移除之 it = _nack_send_status.erase(it); continue; diff --git a/webrtc/Nack.h b/webrtc/Nack.h index b0cd22b4..8ed98be9 100644 --- a/webrtc/Nack.h +++ b/webrtc/Nack.h @@ -41,18 +41,6 @@ class NackContext { public: using Ptr = std::shared_ptr; using onNack = std::function; - //最大保留的rtp丢包状态个数 - static constexpr auto kNackMaxSize = 2048; - // rtp丢包状态最长保留时间 - static constexpr auto kNackMaxMS = 3 * 1000; - // nack最多请求重传10次 - static constexpr auto kNackMaxCount = 15; - // nack重传频率,rtt的倍数 - static constexpr auto kNackIntervalRatio = 1.0f; - // nack包中rtp个数,减小此值可以让nack包响应更灵敏 - static constexpr auto kNackRtpSize = 8; - - static_assert(kNackRtpSize >=0 && kNackRtpSize <= FCI_NACK::kBitSize, "NackContext::kNackRtpSize must between 0 and 16"); NackContext(); diff --git a/webrtc/WebRtcTransport.cpp b/webrtc/WebRtcTransport.cpp index 768c543e..3d2aaa68 100644 --- a/webrtc/WebRtcTransport.cpp +++ b/webrtc/WebRtcTransport.cpp @@ -57,6 +57,9 @@ const string kMinBitrate = RTC_FIELD "min_bitrate"; // 数据通道设置 const string kDataChannelEcho = RTC_FIELD "datachannel_echo"; +// rtp丢包状态最长保留时间 +const string kNackMaxMS = RTC_FIELD "nackMaxMS"; + static onceToken token([]() { mINI::Instance()[kTimeOutSec] = 15; mINI::Instance()[kExternIP] = ""; @@ -69,6 +72,8 @@ static onceToken token([]() { mINI::Instance()[kMinBitrate] = 0; mINI::Instance()[kDataChannelEcho] = true; + + mINI::Instance()[kNackMaxMS] = 3 * 1000; }); } // namespace RTC @@ -800,7 +805,8 @@ public: _on_nack = std::move(on_nack); setOnSorted(std::move(cb)); //设置jitter buffer参数 - RtpTrackImp::setParams(1024, NackContext::kNackMaxMS, 512); + GET_CONFIG(uint32_t, nack_maxms, Rtc::kNackMaxMS); + RtpTrackImp::setParams(1024, nack_maxms, 512); _nack_ctx.setOnNack([this](const FCI_NACK &nack) { onNack(nack); }); }