mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 12:11:36 +08:00
修复webrtc rtp重发列队可能由于rtp时间戳异常导致内存溢出的bug
This commit is contained in:
parent
c6a8118c10
commit
a14e40f8d2
@ -369,13 +369,13 @@ start_bitrate=0
|
|||||||
max_bitrate=0
|
max_bitrate=0
|
||||||
min_bitrate=0
|
min_bitrate=0
|
||||||
|
|
||||||
#nack接收端
|
#nack接收端, rtp发送端,zlm发送rtc流
|
||||||
#Nack缓存包最早时间间隔
|
#rtp重发缓存列队最大长度,单位毫秒
|
||||||
maxNackMS=5000
|
maxRtpCacheMS=5000
|
||||||
#Nack包检查间隔(包数量)
|
#rtp重发缓存列队最大长度,单位个数
|
||||||
rtpCacheCheckInterval=100
|
maxRtpCacheSize=2048
|
||||||
|
|
||||||
#nack发送端
|
#nack发送端,rtp接收端,zlm接收rtc推流
|
||||||
#最大保留的rtp丢包状态个数
|
#最大保留的rtp丢包状态个数
|
||||||
nackMaxSize=2048
|
nackMaxSize=2048
|
||||||
#rtp丢包状态最长保留时间
|
#rtp丢包状态最长保留时间
|
||||||
|
@ -19,12 +19,13 @@ namespace mediakit {
|
|||||||
// RTC配置项目
|
// RTC配置项目
|
||||||
namespace Rtc {
|
namespace Rtc {
|
||||||
#define RTC_FIELD "rtc."
|
#define RTC_FIELD "rtc."
|
||||||
//~ nack接收端
|
//~ nack接收端, rtp发送端
|
||||||
// Nack缓存包最早时间间隔
|
// rtp重发缓存列队最大长度,单位毫秒
|
||||||
const string kMaxNackMS = RTC_FIELD "maxNackMS";
|
const string kMaxRtpCacheMS = RTC_FIELD "maxRtpCacheMS";
|
||||||
// Nack包检查间隔(包数量)
|
// rtp重发缓存列队最大长度,单位个数
|
||||||
const string kRtpCacheCheckInterval = RTC_FIELD "rtpCacheCheckInterval";
|
const string kMaxRtpCacheSize = RTC_FIELD "maxRtpCacheSize";
|
||||||
//~ nack发送端
|
|
||||||
|
//~ nack发送端,rtp接收端
|
||||||
//最大保留的rtp丢包状态个数
|
//最大保留的rtp丢包状态个数
|
||||||
const string kNackMaxSize = RTC_FIELD "nackMaxSize";
|
const string kNackMaxSize = RTC_FIELD "nackMaxSize";
|
||||||
// rtp丢包状态最长保留时间
|
// rtp丢包状态最长保留时间
|
||||||
@ -37,8 +38,8 @@ const string kNackIntervalRatio = RTC_FIELD "nackIntervalRatio";
|
|||||||
const string kNackRtpSize = RTC_FIELD "nackRtpSize";
|
const string kNackRtpSize = RTC_FIELD "nackRtpSize";
|
||||||
|
|
||||||
static onceToken token([]() {
|
static onceToken token([]() {
|
||||||
mINI::Instance()[kMaxNackMS] = 5 * 1000;
|
mINI::Instance()[kMaxRtpCacheMS] = 5 * 1000;
|
||||||
mINI::Instance()[kRtpCacheCheckInterval] = 100;
|
mINI::Instance()[kMaxRtpCacheSize] = 2048;
|
||||||
mINI::Instance()[kNackMaxSize] = 2048;
|
mINI::Instance()[kNackMaxSize] = 2048;
|
||||||
mINI::Instance()[kNackMaxMS] = 3 * 1000;
|
mINI::Instance()[kNackMaxMS] = 3 * 1000;
|
||||||
mINI::Instance()[kNackMaxCount] = 15;
|
mINI::Instance()[kNackMaxCount] = 15;
|
||||||
@ -49,17 +50,26 @@ static onceToken token([]() {
|
|||||||
} // namespace Rtc
|
} // namespace Rtc
|
||||||
|
|
||||||
void NackList::pushBack(RtpPacket::Ptr rtp) {
|
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();
|
auto seq = rtp->getSeq();
|
||||||
_nack_cache_seq.emplace_back(seq);
|
_nack_cache_seq.emplace_back(seq);
|
||||||
_nack_cache_pkt.emplace(seq, std::move(rtp));
|
_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;
|
return;
|
||||||
}
|
}
|
||||||
_cache_ms_check = 0;
|
_cache_ms_check = 0;
|
||||||
GET_CONFIG(uint32_t, maxnackms, Rtc::kMaxNackMS);
|
// 限制rtp缓存最大时长
|
||||||
while (getCacheMS() >= maxnackms) {
|
while (getCacheMS() >= max_rtp_cache_ms) {
|
||||||
// 需要清除部分nack缓存
|
|
||||||
popFront();
|
popFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,13 +106,13 @@ RtpPacket::Ptr *NackList::getRtp(uint16_t seq) {
|
|||||||
|
|
||||||
uint32_t NackList::getCacheMS() {
|
uint32_t NackList::getCacheMS() {
|
||||||
while (_nack_cache_seq.size() > 2) {
|
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) {
|
if (back_stamp == -1) {
|
||||||
_nack_cache_seq.pop_back();
|
_nack_cache_seq.pop_back();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto front_stamp = getRtpStamp(_nack_cache_seq.front());
|
auto front_stamp = getNtpStamp(_nack_cache_seq.front());
|
||||||
if (front_stamp == -1) {
|
if (front_stamp == -1) {
|
||||||
_nack_cache_seq.pop_front();
|
_nack_cache_seq.pop_front();
|
||||||
continue;
|
continue;
|
||||||
@ -111,18 +121,19 @@ uint32_t NackList::getCacheMS() {
|
|||||||
if (back_stamp >= front_stamp) {
|
if (back_stamp >= front_stamp) {
|
||||||
return back_stamp - front_stamp;
|
return back_stamp - front_stamp;
|
||||||
}
|
}
|
||||||
// 很有可能回环了
|
// ntp时间戳回退了,非法数据,丢掉
|
||||||
return back_stamp + (UINT32_MAX - front_stamp);
|
_nack_cache_seq.pop_front();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t NackList::getRtpStamp(uint16_t seq) {
|
int64_t NackList::getNtpStamp(uint16_t seq) {
|
||||||
auto it = _nack_cache_pkt.find(seq);
|
auto it = _nack_cache_pkt.find(seq);
|
||||||
if (it == _nack_cache_pkt.end()) {
|
if (it == _nack_cache_pkt.end()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return it->second->getStampMS(false);
|
// 使用ntp时间戳,不会回退
|
||||||
|
return it->second->getStampMS(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -22,24 +22,11 @@ namespace mediakit {
|
|||||||
|
|
||||||
// RTC配置项目
|
// RTC配置项目
|
||||||
namespace Rtc {
|
namespace Rtc {
|
||||||
|
//~ nack发送端,rtp接收端
|
||||||
//~ nack接收端(rtp发送端)
|
|
||||||
// Nack缓存包最早时间间隔
|
|
||||||
extern const std::string kMaxNackMS;
|
|
||||||
// Nack包检查间隔(包数量)
|
|
||||||
extern const std::string kRtpCacheCheckInterval;
|
|
||||||
|
|
||||||
//~ nack发送端(rtp接收端)
|
|
||||||
// 最大保留的rtp丢包状态个数
|
// 最大保留的rtp丢包状态个数
|
||||||
extern const std::string kNackMaxSize;
|
extern const std::string kNackMaxSize;
|
||||||
// rtp丢包状态最长保留时间
|
// rtp丢包状态最长保留时间
|
||||||
extern const std::string kNackMaxMS;
|
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
|
} // namespace Rtc
|
||||||
|
|
||||||
class NackList {
|
class NackList {
|
||||||
@ -50,7 +37,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
void popFront();
|
void popFront();
|
||||||
uint32_t getCacheMS();
|
uint32_t getCacheMS();
|
||||||
int64_t getRtpStamp(uint16_t seq);
|
int64_t getNtpStamp(uint16_t seq);
|
||||||
RtpPacket::Ptr *getRtp(uint16_t seq);
|
RtpPacket::Ptr *getRtp(uint16_t seq);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -88,7 +75,7 @@ private:
|
|||||||
struct NackStatus {
|
struct NackStatus {
|
||||||
uint64_t first_stamp;
|
uint64_t first_stamp;
|
||||||
uint64_t update_stamp;
|
uint64_t update_stamp;
|
||||||
int nack_count = 0;
|
uint32_t nack_count = 0;
|
||||||
};
|
};
|
||||||
std::map<uint16_t /*seq*/, NackStatus> _nack_send_status;
|
std::map<uint16_t /*seq*/, NackStatus> _nack_send_status;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user