From a14e40f8d2bdcf1fc6fa6bcfe0d403af9f7e05e9 Mon Sep 17 00:00:00 2001 From: xia-chu <771730766@qq.com> Date: Sun, 21 Jul 2024 19:16:34 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dwebrtc=20rtp=E9=87=8D?= =?UTF-8?q?=E5=8F=91=E5=88=97=E9=98=9F=E5=8F=AF=E8=83=BD=E7=94=B1=E4=BA=8E?= =?UTF-8?q?rtp=E6=97=B6=E9=97=B4=E6=88=B3=E5=BC=82=E5=B8=B8=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=86=85=E5=AD=98=E6=BA=A2=E5=87=BA=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- conf/config.ini | 12 ++++++------ webrtc/Nack.cpp | 49 ++++++++++++++++++++++++++++++------------------- webrtc/Nack.h | 19 +++---------------- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/conf/config.ini b/conf/config.ini index 95d3fa37..3fd805c4 100644 --- a/conf/config.ini +++ b/conf/config.ini @@ -369,13 +369,13 @@ start_bitrate=0 max_bitrate=0 min_bitrate=0 -#nack接收端 -#Nack缓存包最早时间间隔 -maxNackMS=5000 -#Nack包检查间隔(包数量) -rtpCacheCheckInterval=100 +#nack接收端, rtp发送端,zlm发送rtc流 +#rtp重发缓存列队最大长度,单位毫秒 +maxRtpCacheMS=5000 +#rtp重发缓存列队最大长度,单位个数 +maxRtpCacheSize=2048 -#nack发送端 +#nack发送端,rtp接收端,zlm接收rtc推流 #最大保留的rtp丢包状态个数 nackMaxSize=2048 #rtp丢包状态最长保留时间 diff --git a/webrtc/Nack.cpp b/webrtc/Nack.cpp index 4fd1f101..7ee1d245 100644 --- a/webrtc/Nack.cpp +++ b/webrtc/Nack.cpp @@ -19,12 +19,13 @@ namespace mediakit { // RTC配置项目 namespace Rtc { #define RTC_FIELD "rtc." -//~ nack接收端 -// Nack缓存包最早时间间隔 -const string kMaxNackMS = RTC_FIELD "maxNackMS"; -// Nack包检查间隔(包数量) -const string kRtpCacheCheckInterval = RTC_FIELD "rtpCacheCheckInterval"; -//~ nack发送端 +//~ nack接收端, rtp发送端 +// rtp重发缓存列队最大长度,单位毫秒 +const string kMaxRtpCacheMS = RTC_FIELD "maxRtpCacheMS"; +// rtp重发缓存列队最大长度,单位个数 +const string kMaxRtpCacheSize = RTC_FIELD "maxRtpCacheSize"; + +//~ nack发送端,rtp接收端 //最大保留的rtp丢包状态个数 const string kNackMaxSize = RTC_FIELD "nackMaxSize"; // rtp丢包状态最长保留时间 @@ -37,8 +38,8 @@ const string kNackIntervalRatio = RTC_FIELD "nackIntervalRatio"; const string kNackRtpSize = RTC_FIELD "nackRtpSize"; static onceToken token([]() { - mINI::Instance()[kMaxNackMS] = 5 * 1000; - mINI::Instance()[kRtpCacheCheckInterval] = 100; + mINI::Instance()[kMaxRtpCacheMS] = 5 * 1000; + mINI::Instance()[kMaxRtpCacheSize] = 2048; mINI::Instance()[kNackMaxSize] = 2048; mINI::Instance()[kNackMaxMS] = 3 * 1000; mINI::Instance()[kNackMaxCount] = 15; @@ -49,17 +50,26 @@ static onceToken token([]() { } // namespace Rtc void NackList::pushBack(RtpPacket::Ptr rtp) { + GET_CONFIG(uint32_t, max_rtp_cache_ms, Rtc::kMaxRtpCacheMS); + GET_CONFIG(uint32_t, max_rtp_cache_size, Rtc::kMaxRtpCacheSize); + + // 记录rtp auto seq = rtp->getSeq(); _nack_cache_seq.emplace_back(seq); _nack_cache_pkt.emplace(seq, std::move(rtp)); - GET_CONFIG(uint32_t, rtpcache_checkinterval, Rtc::kRtpCacheCheckInterval); - if (++_cache_ms_check < rtpcache_checkinterval) { + + // 限制rtp缓存最大个数 + if (_nack_cache_seq.size() > max_rtp_cache_size) { + popFront(); + } + + if (++_cache_ms_check < 100) { + // 每100个rtp包检测下缓存长度,节省cpu资源 return; } _cache_ms_check = 0; - GET_CONFIG(uint32_t, maxnackms, Rtc::kMaxNackMS); - while (getCacheMS() >= maxnackms) { - // 需要清除部分nack缓存 + // 限制rtp缓存最大时长 + while (getCacheMS() >= max_rtp_cache_ms) { popFront(); } } @@ -96,13 +106,13 @@ RtpPacket::Ptr *NackList::getRtp(uint16_t seq) { uint32_t NackList::getCacheMS() { while (_nack_cache_seq.size() > 2) { - auto back_stamp = getRtpStamp(_nack_cache_seq.back()); + auto back_stamp = getNtpStamp(_nack_cache_seq.back()); if (back_stamp == -1) { _nack_cache_seq.pop_back(); continue; } - auto front_stamp = getRtpStamp(_nack_cache_seq.front()); + auto front_stamp = getNtpStamp(_nack_cache_seq.front()); if (front_stamp == -1) { _nack_cache_seq.pop_front(); continue; @@ -111,18 +121,19 @@ uint32_t NackList::getCacheMS() { if (back_stamp >= front_stamp) { return back_stamp - front_stamp; } - // 很有可能回环了 - return back_stamp + (UINT32_MAX - front_stamp); + // ntp时间戳回退了,非法数据,丢掉 + _nack_cache_seq.pop_front(); } return 0; } -int64_t NackList::getRtpStamp(uint16_t seq) { +int64_t NackList::getNtpStamp(uint16_t seq) { auto it = _nack_cache_pkt.find(seq); if (it == _nack_cache_pkt.end()) { return -1; } - return it->second->getStampMS(false); + // 使用ntp时间戳,不会回退 + return it->second->getStampMS(true); } //////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/webrtc/Nack.h b/webrtc/Nack.h index 276f51e8..08219e2b 100644 --- a/webrtc/Nack.h +++ b/webrtc/Nack.h @@ -22,24 +22,11 @@ namespace mediakit { // RTC配置项目 namespace Rtc { - -//~ nack接收端(rtp发送端) -// Nack缓存包最早时间间隔 -extern const std::string kMaxNackMS; -// Nack包检查间隔(包数量) -extern const std::string kRtpCacheCheckInterval; - -//~ nack发送端(rtp接收端) +//~ nack发送端,rtp接收端 // 最大保留的rtp丢包状态个数 extern const std::string kNackMaxSize; // rtp丢包状态最长保留时间 extern const std::string kNackMaxMS; -// nack最多请求重传次数 -extern const std::string kNackMaxCount; -// nack重传频率,rtt的倍数 -extern const std::string kNackIntervalRatio; -// nack包中rtp个数,减小此值可以让nack包响应更灵敏 -extern const std::string kNackRtpSize; } // namespace Rtc class NackList { @@ -50,7 +37,7 @@ public: private: void popFront(); uint32_t getCacheMS(); - int64_t getRtpStamp(uint16_t seq); + int64_t getNtpStamp(uint16_t seq); RtpPacket::Ptr *getRtp(uint16_t seq); private: @@ -88,7 +75,7 @@ private: struct NackStatus { uint64_t first_stamp; uint64_t update_stamp; - int nack_count = 0; + uint32_t nack_count = 0; }; std::map _nack_send_status; };