Skip to content

Commit 07acbfd

Browse files
Add RtcpNackRequester
1 parent 3ebd1ea commit 07acbfd

File tree

3 files changed

+134
-0
lines changed

3 files changed

+134
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ set(LIBDATACHANNEL_SOURCES
9494
${CMAKE_CURRENT_SOURCE_DIR}/src/h265rtpdepacketizer.cpp
9595
${CMAKE_CURRENT_SOURCE_DIR}/src/h265nalunit.cpp
9696
${CMAKE_CURRENT_SOURCE_DIR}/src/av1rtppacketizer.cpp
97+
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackrequester.cpp
9798
${CMAKE_CURRENT_SOURCE_DIR}/src/rtcpnackresponder.cpp
9899
${CMAKE_CURRENT_SOURCE_DIR}/src/rtp.cpp
99100
${CMAKE_CURRENT_SOURCE_DIR}/src/capi.cpp

include/rtc/rtcpnackrequester.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright (c) 2025 kaizhi-singtown
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
#ifndef RTC_RTCP_NACK_RESPONDER_H
10+
#define RTC_RTCP_NACK_RESPONDER_H
11+
12+
#if RTC_ENABLE_MEDIA
13+
14+
#include "mediahandler.hpp"
15+
#include "rtp.hpp"
16+
17+
#include <set>
18+
#include <unordered_map>
19+
20+
namespace rtc {
21+
22+
class RTC_CPP_EXPORT RtcpNackRequester final : public MediaHandler {
23+
public:
24+
SSRC ssrc;
25+
size_t jitterSize;
26+
size_t nackWaitMs;
27+
28+
RtcpNackRequester(SSRC ssrc, size_t jitterSize = 5, size_t nackWaitMs = 50);
29+
void incoming(message_vector &messages, const message_callback &send) override;
30+
31+
private:
32+
uint16_t expectSequence = 0;
33+
std::chrono::steady_clock::time_point nackWaitUntil;
34+
35+
std::unordered_map<uint16_t, message_ptr> receivePackets;
36+
std::set<uint16_t> lostSequenceNumbers;
37+
38+
message_ptr nackMesssage(uint16_t sequence);
39+
};
40+
41+
} // namespace rtc
42+
43+
#endif /* RTC_ENABLE_MEDIA */
44+
45+
#endif /* RTC_RTCP_NACK_RESPONDER_H */

src/rtcpnackrequester.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* Copyright (c) 2020 kaizhi-singtown
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*/
8+
9+
#if RTC_ENABLE_MEDIA
10+
11+
#include "rtcpnackrequester.hpp"
12+
#include "rtp.hpp"
13+
14+
#include "impl/internals.hpp"
15+
16+
namespace rtc {
17+
18+
RtcpNackRequester::RtcpNackRequester(SSRC ssrc, size_t jitterSize, size_t nackWaitMs)
19+
: ssrc(ssrc), jitterSize(jitterSize), nackWaitMs(nackWaitMs) {}
20+
21+
void RtcpNackRequester::incoming(message_vector &messages, const message_callback &send) {
22+
message_vector result;
23+
for (const auto &message : messages) {
24+
if (message->type != Message::Binary) {
25+
result.push_back(message);
26+
continue;
27+
}
28+
29+
if (message->size() < sizeof(RtpHeader)) {
30+
result.push_back(message);
31+
continue;
32+
}
33+
34+
auto rtp = reinterpret_cast<RtpHeader *>(message->data());
35+
uint16_t seqNo = rtp->seqNumber();
36+
lostSequenceNumbers.erase(seqNo);
37+
38+
if (expectSequence == 0) {
39+
expectSequence = seqNo;
40+
}
41+
if ((int16_t)(seqNo - expectSequence) >= 0) {
42+
receivePackets[seqNo] = message;
43+
}
44+
}
45+
46+
while (receivePackets.size() > jitterSize) {
47+
bool alreadyReceived = receivePackets.count(expectSequence) > 0;
48+
if (alreadyReceived) {
49+
auto packet = receivePackets[expectSequence];
50+
result.push_back(packet);
51+
receivePackets.erase(expectSequence);
52+
expectSequence++;
53+
continue;
54+
} else {
55+
bool alreadySentNack = lostSequenceNumbers.count(expectSequence) > 0;
56+
auto now = std::chrono::steady_clock::now();
57+
if (alreadySentNack) {
58+
if (now >= nackWaitUntil) {
59+
PLOG_VERBOSE << "Skip NACK for lost packet: " << expectSequence;
60+
expectSequence++;
61+
}
62+
} else {
63+
PLOG_VERBOSE << "Sending NACK for lost packet: " << expectSequence;
64+
lostSequenceNumbers.insert(expectSequence);
65+
nackWaitUntil = now + std::chrono::milliseconds(nackWaitMs);
66+
send(nackMesssage(expectSequence));
67+
}
68+
break;
69+
}
70+
}
71+
messages.swap(result);
72+
}
73+
74+
message_ptr RtcpNackRequester::nackMesssage(uint16_t sequence) {
75+
unsigned int fciCount = 0;
76+
uint16_t fciPID = 0;
77+
78+
message_ptr message = make_message(RtcpNack::Size(1), Message::Control);
79+
auto *nack = reinterpret_cast<RtcpNack *>(message->data());
80+
nack->preparePacket(ssrc, 1);
81+
nack->addMissingPacket(&fciCount, &fciPID, sequence);
82+
83+
return message;
84+
}
85+
86+
} // namespace rtc
87+
88+
#endif /* RTC_ENABLE_MEDIA */

0 commit comments

Comments
 (0)