/* * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved. * * This file is part of ZLMediaKit(https://github.com/ZLMediaKit/ZLMediaKit). * * Use of this source code is governed by MIT license that can be found in the * LICENSE file in the root of the source tree. All contributing project authors * may be found in the AUTHORS file in the root of the source tree. */ #ifndef ZLMEDIAKIT_NACK_H #define ZLMEDIAKIT_NACK_H #include "Rtsp/Rtsp.h" #include "Rtcp/RtcpFCI.h" class NackList { public: NackList() = default; ~NackList() = default; void pushBack(mediakit::RtpPacket::Ptr rtp); void forEach(const mediakit::FCI_NACK &nack, const std::function &cb); private: void popFront(); uint32_t getCacheMS(); int64_t getRtpStamp(uint16_t seq); mediakit::RtpPacket::Ptr *getRtp(uint16_t seq); private: uint32_t _cache_ms_check = 0; std::deque _nack_cache_seq; std::unordered_map _nack_cache_pkt; }; class NackContext { public: using Ptr = std::shared_ptr; using onNack = std::function; //最大保留的rtp丢包状态个数 static constexpr auto kNackMaxSize = 1024; //rtp丢包状态最长保留时间 static constexpr auto kNackMaxMS = 3 * 1000; //nack最多请求重传10次 static constexpr auto kNackMaxCount = 10; //nack重传频率,rtt的倍数 static constexpr auto kNackIntervalRatio = 2.0f; NackContext() = default; ~NackContext() = default; void received(uint16_t seq, bool is_rtx = false); void setOnNack(onNack cb); uint64_t reSendNack(); private: void eraseFrontSeq(); void doNack(const mediakit::FCI_NACK &nack, bool record_nack); void recordNack(const mediakit::FCI_NACK &nack); void onRtx(uint16_t seq); private: int _rtt = 50; onNack _cb; std::set _seq; uint16_t _last_max_seq = 0; struct NackStatus{ uint64_t first_stamp; uint64_t update_stamp; int nack_count = 0; }; std::map _nack_send_status; }; #endif //ZLMEDIAKIT_NACK_H