Skip to content

Commit 9a64f88

Browse files
Merge branch 'v0.24'
2 parents 86e531c + 51c8d9f commit 9a64f88

5 files changed

Lines changed: 135 additions & 58 deletions

File tree

include/rtc/rtp.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,8 +279,15 @@ struct RTC_CPP_EXPORT RtcpRemb {
279279
void setBitrate(unsigned int numSSRC, unsigned int in_bitrate);
280280
SSRC getSSRC(int num) const;
281281
void setSSRC(int num, SSRC newSsrc);
282-
unsigned int getNumSSRC() const;
282+
bool hasValidId() const;
283+
int getSSRCCount() const;
283284
unsigned int getBitrate() const;
285+
286+
// Deprecated
287+
[[deprecated("use setSSRC")]] void setSsrc(int num, SSRC newSssrc);
288+
[[deprecated("use getSSRCCount")]] unsigned int getNumSSRC() const;
289+
[[deprecated("use getSSRCCount")]] unsigned int getNumSSRC();
290+
unsigned int getBitrate();
284291
};
285292

286293
struct RTC_CPP_EXPORT RtcpPli {

src/impl/peerconnection.cpp

Lines changed: 53 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -570,65 +570,76 @@ void PeerConnection::dispatchMedia([[maybe_unused]] message_ptr message) {
570570
if (message->type == Message::Control) {
571571
std::set<uint32_t> ssrcs;
572572
size_t offset = 0;
573-
while ((sizeof(RtcpHeader) + offset) <= message->size()) {
573+
while (offset + sizeof(RtcpHeader) <= message->size()) {
574574
auto header = reinterpret_cast<RtcpHeader *>(message->data() + offset);
575-
if (header->lengthInBytes() > message->size() - offset) {
575+
size_t length = header->lengthInBytes();
576+
if (offset + length > message->size()) {
576577
COUNTER_MEDIA_TRUNCATED++;
577578
break;
578579
}
579-
offset += header->lengthInBytes();
580-
if (header->payloadType() == 205) {
581-
auto rtcpfb = reinterpret_cast<RtcpFbHeader *>(header);
582-
ssrcs.insert(rtcpfb->packetSenderSSRC());
583-
ssrcs.insert(rtcpfb->mediaSourceSSRC());
584-
} else if (header->payloadType() == 206) {
585-
auto rtcpfb = reinterpret_cast<RtcpFbHeader *>(header);
586-
ssrcs.insert(rtcpfb->packetSenderSSRC());
587-
if (header->reportCount() == 15 && header->lengthInBytes() >= sizeof(RtcpRemb)) {
588-
auto remb = reinterpret_cast<RtcpRemb *>(header);
589-
unsigned numSsrc = remb->getNumSSRC();
590-
if (RtcpRemb::SizeWithSSRCs(numSsrc) > message->size() + header->lengthInBytes() - offset) {
580+
switch(header->payloadType()) {
581+
case 200: // SR
582+
if (length >= sizeof(RtcpSr)) {
583+
auto rtcpsr = reinterpret_cast<RtcpSr *>(header);
584+
ssrcs.insert(rtcpsr->senderSSRC());
585+
for (int i = 0; i < rtcpsr->header.reportCount(); ++i)
586+
if (const auto *reportBlock = rtcpsr->getReportBlock(i))
587+
ssrcs.insert(reportBlock->getSSRC());
588+
}
589+
break;
590+
591+
case 201: // RR
592+
if (length >= sizeof(RtcpRr)) {
593+
auto rtcprr = reinterpret_cast<RtcpRr *>(header);
594+
ssrcs.insert(rtcprr->senderSSRC());
595+
for (int i = 0; i < rtcprr->header.reportCount(); ++i)
596+
if (const auto *reportBlock = rtcprr->getReportBlock(i))
597+
ssrcs.insert(reportBlock->getSSRC());
598+
}
599+
break;
600+
601+
case 202: // SDES
602+
if (length >= sizeof(RtcpSdes)) {
603+
auto sdes = reinterpret_cast<RtcpSdes *>(header);
604+
if (!sdes->isValid()) {
605+
PLOG_WARNING << "RTCP SDES packet is invalid";
591606
continue;
592607
}
593-
if (remb->_id[0] == 'R' && remb->_id[1] == 'E' && remb->_id[2] == 'M' && remb->_id[3] == 'B') {
594-
for (unsigned i = 0; i < numSsrc; i++) {
595-
ssrcs.insert(remb->getSSRC(i));
596-
}
597-
continue;
608+
for (unsigned int i = 0; i < sdes->chunksCount(); i++) {
609+
auto chunk = sdes->getChunk(i);
610+
ssrcs.insert(chunk->ssrc());
598611
}
599612
}
600-
ssrcs.insert(rtcpfb->mediaSourceSSRC());
601-
} else if (header->payloadType() == 200) {
602-
auto rtcpsr = reinterpret_cast<RtcpSr *>(header);
603-
ssrcs.insert(rtcpsr->senderSSRC());
604-
for (int i = 0; i < rtcpsr->header.reportCount(); ++i)
605-
if (const auto *reportBlock = rtcpsr->getReportBlock(i))
606-
ssrcs.insert(reportBlock->getSSRC());
607-
} else if (header->payloadType() == 201) {
608-
auto rtcprr = reinterpret_cast<RtcpRr *>(header);
609-
ssrcs.insert(rtcprr->senderSSRC());
610-
for (int i = 0; i < rtcprr->header.reportCount(); ++i)
611-
if (const auto *reportBlock = rtcprr->getReportBlock(i))
612-
ssrcs.insert(reportBlock->getSSRC());
613-
} else if (header->payloadType() == 202) {
614-
auto sdes = reinterpret_cast<RtcpSdes *>(header);
615-
if (!sdes->isValid()) {
616-
PLOG_WARNING << "RTCP SDES packet is invalid";
617-
continue;
618-
}
619-
for (unsigned int i = 0; i < sdes->chunksCount(); i++) {
620-
auto chunk = sdes->getChunk(i);
621-
ssrcs.insert(chunk->ssrc());
613+
break;
614+
615+
616+
case 205: // FB
617+
case 206:
618+
if (length >= sizeof(RtcpFbHeader)) {
619+
auto rtcpfb = reinterpret_cast<RtcpFbHeader *>(header);
620+
ssrcs.insert(rtcpfb->packetSenderSSRC());
621+
ssrcs.insert(rtcpfb->mediaSourceSSRC());
622+
if (header->payloadType() == 206 && header->reportCount() == 15 &&
623+
length >= sizeof(RtcpRemb)) {
624+
auto remb = reinterpret_cast<RtcpRemb *>(header);
625+
if (remb->hasValidId())
626+
for (int i = 0; i < remb->getSSRCCount(); ++i)
627+
ssrcs.insert(remb->getSSRC(i));
628+
}
622629
}
623-
} else {
630+
break;
631+
632+
default:
624633
// PT=203 == Goodbye
625634
// PT=204 == Application Specific
626635
// PT=207 == Extended Report
627636
if (header->payloadType() != 203 && header->payloadType() != 204 &&
628637
header->payloadType() != 207) {
629638
COUNTER_UNKNOWN_PACKET_TYPE++;
630639
}
640+
break;
631641
}
642+
offset += header->lengthInBytes();
632643
}
633644

634645
if (!ssrcs.empty()) {

src/rembhandler.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#include "rembhandler.hpp"
1010
#include "rtp.hpp"
1111

12+
#include "impl/internals.hpp"
13+
1214
#ifdef _WIN32
1315
#include <winsock2.h>
1416
#else
@@ -24,18 +26,21 @@ RembHandler::RembHandler(std::function<void(unsigned int)> onRemb) : mOnRemb(onR
2426
void RembHandler::incoming(message_vector &messages, [[maybe_unused]] const message_callback &send) {
2527
for (const auto &message : messages) {
2628
size_t offset = 0;
27-
while ((sizeof(RtcpHeader) + offset) <= message->size()) {
29+
while (offset + sizeof(RtcpHeader) <= message->size()) {
2830
auto header = reinterpret_cast<RtcpHeader *>(message->data() + offset);
29-
uint8_t payload_type = header->payloadType();
31+
size_t length = header->lengthInBytes();
32+
if (offset + length > message->size())
33+
break;
3034

31-
if (payload_type == 206 && header->reportCount() == 15 && header->lengthInBytes() >= sizeof(RtcpRemb)) {
35+
if (header->payloadType() == 206 && header->reportCount() == 15 && length >= sizeof(RtcpRemb)) {
3236
if (offset + sizeof(RtcpRemb) > message->size())
3337
break;
3438

3539
auto remb = reinterpret_cast<RtcpRemb *>(message->data() + offset);
36-
37-
if (remb->_id[0] == 'R' && remb->_id[1] == 'E' && remb->_id[2] == 'M' && remb->_id[3] == 'B') {
38-
mOnRemb(remb->getBitrate());
40+
if (remb->hasValidId()) {
41+
unsigned int bitrate = remb->getBitrate();
42+
PLOG_DEBUG << "Got REMB, bitrate=" << bitrate;
43+
mOnRemb(bitrate);
3944
break;
4045
}
4146
}

src/rtp.cpp

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -597,30 +597,56 @@ void RtcpRemb::setBitrate(unsigned int numSSRC, unsigned int in_bitrate) {
597597
}
598598

599599
// "length" in packet is one less than the number of 32 bit words in the packet.
600-
header.header.setLength(uint16_t((offsetof(RtcpRemb, _ssrcs) / sizeof(uint32_t)) - 1 + numSSRC));
600+
header.header.setLength(uint16_t((offsetof(RtcpRemb, _ssrcs) / sizeof(uint32_t)) + numSSRC - 1));
601601

602602
_bitrate = htonl((numSSRC << (32u - 8u)) | (exp << (32u - 8u - 6u)) | in_bitrate);
603603
}
604604

605-
SSRC RtcpRemb::getSSRC(int num) const {
606-
if (num < 0 || static_cast<unsigned>(num) >= getNumSSRC())
605+
SSRC RtcpRemb::getSSRC(int num) const {
606+
if (num < 0 || num >= getSSRCCount())
607607
throw std::out_of_range("SSRC num out of range");
608608
return ntohl(_ssrcs[num]);
609609
}
610610
void RtcpRemb::setSSRC(int num, SSRC newSsrc) {
611-
if (num < 0 || static_cast<unsigned>(num) >= getNumSSRC())
611+
if (num < 0 || num >= getSSRCCount())
612612
throw std::out_of_range("SSRC num out of range");
613613
_ssrcs[num] = htonl(newSsrc);
614614
}
615615

616-
unsigned int RtcpRemb::getNumSSRC() const { return ntohl(_bitrate) >> 24u; }
616+
bool RtcpRemb::hasValidId() const {
617+
return _id[0] == 'R' && _id[1] == 'E' && _id[2] == 'M' && _id[3] == 'B';
618+
}
619+
620+
int RtcpRemb::getSSRCCount() const {
621+
return std::min(
622+
int(ntohl(_bitrate) >> 24u),
623+
std::max(int(header.header.length() + 1 - offsetof(RtcpRemb, _ssrcs) / sizeof(uint32_t)), 0));
624+
}
617625

618626
unsigned int RtcpRemb::getBitrate() const {
619627
uint32_t br = ntohl(_bitrate);
620628
uint8_t exp = (br << 8u) >> 26u;
621629
return (br & 0x3FFFF) * static_cast<unsigned int>(pow(2, exp));
622630
}
623631

632+
void RtcpRemb::setSsrc(int num, SSRC newSsrc) {
633+
if (num < 0 || num >= getSSRCCount())
634+
throw std::out_of_range("SSRC num out of range");
635+
_ssrcs[num] = htonl(newSsrc);
636+
}
637+
638+
unsigned int RtcpRemb::getNumSSRC() const {
639+
return unsigned(getSSRCCount());
640+
}
641+
642+
unsigned int RtcpRemb::getNumSSRC() {
643+
return unsigned(getSSRCCount());
644+
}
645+
646+
unsigned int RtcpRemb::getBitrate() {
647+
return std::as_const(*this).getBitrate();
648+
}
649+
624650
unsigned int RtcpPli::Size() { return sizeof(RtcpFbHeader); }
625651

626652
void RtcpPli::preparePacket(SSRC messageSSRC) {

test/track.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ TestResult test_track() {
137137
media2.setBitrate(3000);
138138
media2.addSSRC(2468, "video-send");
139139

140-
// NOTE: Overwriting the old shared_ptr for t1 will cause it's respective
141-
// track to be dropped (so it's SSRCs won't be on the description next time)
140+
// NOTE: Overwriting the old shared_ptr for t1 will cause the respective
141+
// track to be dropped (so its SSRCs won't be on the description next time)
142142
t1 = pc1.addTrack(media2);
143143

144144
pc1.setLocalDescription();
@@ -151,14 +151,16 @@ TestResult test_track() {
151151
if (!at2 || !at2->isOpen() || !t1->isOpen())
152152
return TestResult(false, "Renegotiated track is not open");
153153

154+
#if RTC_ENABLE_MEDIA
155+
// RTP test
154156
std::vector<std::byte> payload = {std::byte{0}, std::byte{1}, std::byte{2}, std::byte{3}};
155157
std::vector<std::byte> rtpRaw(sizeof(RtpHeader) + payload.size());
156158
auto *rtp = reinterpret_cast<RtpHeader *>(rtpRaw.data());
159+
rtp->preparePacket();
157160
rtp->setPayloadType(96);
158161
rtp->setSeqNumber(1);
159162
rtp->setTimestamp(3000);
160163
rtp->setSsrc(2468);
161-
rtp->preparePacket();
162164
std::memcpy(rtpRaw.data() + sizeof(RtpHeader), payload.data(), payload.size());
163165

164166
if (!t1->send(rtpRaw.data(), rtpRaw.size())) {
@@ -167,7 +169,7 @@ TestResult test_track() {
167169

168170
// wait for an RTP packet to be received
169171
auto future = recvRtpPromise.get_future();
170-
if (future.wait_for(5s) == std::future_status::timeout) {
172+
if (future.wait_for(2s) == std::future_status::timeout) {
171173
throw runtime_error("Didn't receive RTP packet on pc2");
172174
}
173175

@@ -181,6 +183,32 @@ TestResult test_track() {
181183
throw runtime_error("Received RTP packet is different than the packet that was sent");
182184
}
183185

186+
// RTCP REMB test
187+
std::promise<unsigned int> rembPromise;
188+
t1->setMediaHandler(make_shared<RembHandler>([&rembPromise](unsigned int bitrate) {
189+
rembPromise.set_value(bitrate);
190+
}));
191+
192+
std::vector<std::byte> rtcpRembRaw(RtcpRemb::SizeWithSSRCs(2));
193+
auto *rtcpRemb = reinterpret_cast<RtcpRemb*>(rtcpRembRaw.data());
194+
rtcpRemb->preparePacket(6666, 2, 1000000);
195+
rtcpRemb->setSSRC(0, 2468);
196+
rtcpRemb->setSSRC(1, 2469);
197+
if (!t2->send(rtcpRembRaw.data(), rtcpRembRaw.size())) {
198+
throw runtime_error("Couldn't send RTCP REMB message");
199+
}
200+
201+
auto rembFuture = rembPromise.get_future();
202+
if (rembFuture.wait_for(2s) == std::future_status::timeout) {
203+
throw runtime_error("Didn't receive REMB message");
204+
}
205+
206+
unsigned int bitrate = rembFuture.get();
207+
if (bitrate != 1000000) {
208+
throw runtime_error("Incorrect bitrate in REMB message");
209+
}
210+
#endif
211+
184212
// Delay close of peer 2 to check closing works properly
185213
pc1.close();
186214
this_thread::sleep_for(1s);

0 commit comments

Comments
 (0)