Skip to content

Commit

Permalink
Add transport-cc (#1814)
Browse files Browse the repository at this point in the history
  • Loading branch information
lodoyun authored Jun 13, 2022
1 parent f9fca4e commit ad1ac9f
Show file tree
Hide file tree
Showing 32 changed files with 1,282 additions and 347 deletions.
1 change: 1 addition & 0 deletions erizo/src/erizo/MediaDefinitions.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ struct DataPacket {
std::string rid;
unsigned int clock_rate = 0;
bool is_padding;
std::optional<uint16_t> transport_sequence_number;
};

class Monitor {
Expand Down
11 changes: 8 additions & 3 deletions erizo/src/erizo/WebRtcConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "bandwidth/StreamPriorityBWDistributor.h"
#include "bandwidth/TargetVideoBWDistributor.h"
#include "rtp/RtpHeaders.h"
#include "rtp/SenderBandwidthEstimationHandler.h"
#include "rtp/BandwidthEstimationHandler.h"
#include "rtp/RtpPaddingManagerHandler.h"
#include "rtp/RtpUtils.h"
Expand Down Expand Up @@ -133,10 +132,9 @@ void WebRtcConnection::initializePipeline() {
pipeline_->addService(stats_);

pipeline_->addFront(std::make_shared<ConnectionPacketReader>(this));

pipeline_->addFront(std::make_shared<BandwidthEstimationHandler>());

pipeline_->addFront(std::make_shared<SenderBandwidthEstimationHandler>());

pipeline_->addFront(std::make_shared<RtpPaddingManagerHandler>());

pipeline_->addFront(std::make_shared<ConnectionPacketWriter>(this));
Expand Down Expand Up @@ -994,6 +992,13 @@ void WebRtcConnection::onREMBFromTransport(RtcpHeader *chead, Transport *transpo
}
});
}
if (chead->getREMBNumSSRC() == 0) { // Generated by SenderBandwidthEstimation when using transportcc
forEachMediaStream([&streams] (const std::shared_ptr<MediaStream> &media_stream) {
if (!media_stream->isPublisher()) {
streams.push_back(media_stream);
}
});
}

distributor_->distribute(chead->getREMBBitRate(), chead->getSSRC(), streams, transport);
}
Expand Down
1 change: 1 addition & 0 deletions erizo/src/erizo/WebRtcConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "./MediaDefinitions.h"
#include "./Transport.h"
#include "./Stats.h"
#include "rtp/SenderBandwidthEstimationHandler.h"
#include "bandwidth/BandwidthDistributionAlgorithm.h"
#include "bandwidth/BwDistributionConfig.h"
#include "pipeline/Pipeline.h"
Expand Down
4 changes: 3 additions & 1 deletion erizo/src/erizo/media/SyntheticInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ int SyntheticInput::deliverFeedback_(std::shared_ptr<DataPacket> fb_packet) {
switch (chead->packettype) {
case RTCP_RTP_Feedback_PT:
// NACKs are already handled by MediaStream. RRs won't be handled.
total_packets_nacked_++;
if (chead->isNACK()) {
total_packets_nacked_++;
}
break;
case RTCP_PS_Feedback_PT:
switch (chead->getBlockCount()) {
Expand Down
76 changes: 39 additions & 37 deletions erizo/src/erizo/rtp/RtcpAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -148,48 +148,50 @@ int RtcpAggregator::analyzeFeedback(char *buf, int len) {
break;
case RTCP_RTP_Feedback_PT:
{
ELOG_DEBUG("RTP FB: Usually NACKs: %u, partNum %d", chead->getBlockCount(), partNum);
ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp());
// We analyze NACK to avoid sending repeated NACKs
blp = chead->getNackBlp();
theData->shouldSendNACK = false;
std::pair<std::set<uint32_t>::iterator, bool> ret;
ret = theData->nackedPackets_.insert(chead->getNackPid());
if (ret.second) {
ELOG_DEBUG("We received PID NACK for unacked packet %u", chead->getNackPid());
theData->shouldSendNACK = true;
} else {
if (theData->nackedPackets_.size() >= MAP_NACK_SIZE) {
while (theData->nackedPackets_.size() >= MAP_NACK_SIZE) {
theData->nackedPackets_.erase(theData->nackedPackets_.begin());
if (chead->isNACK()) {
ELOG_DEBUG("RTP FB - NACKs: %u, partNum %d", chead->getBlockCount(), partNum);
ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp());
// We analyze NACK to avoid sending repeated NACKs
blp = chead->getNackBlp();
theData->shouldSendNACK = false;
std::pair<std::set<uint32_t>::iterator, bool> ret;
ret = theData->nackedPackets_.insert(chead->getNackPid());
if (ret.second) {
ELOG_DEBUG("We received PID NACK for unacked packet %u", chead->getNackPid());
theData->shouldSendNACK = true;
} else {
if (theData->nackedPackets_.size() >= MAP_NACK_SIZE) {
while (theData->nackedPackets_.size() >= MAP_NACK_SIZE) {
theData->nackedPackets_.erase(theData->nackedPackets_.begin());
}
}
ELOG_DEBUG("We received PID NACK for ALREADY acked packet %u", chead->getNackPid());
}
ELOG_DEBUG("We received PID NACK for ALREADY acked packet %u", chead->getNackPid());
}
if (blp != 0) {
for (int i = 0; i < 16; i++) {
currentNackPos = blp & 0x0001;
blp = blp >> 1;

if (currentNackPos == 1) {
lostPacketSeq = chead->getNackPid() + 1 + i;
ret = theData->nackedPackets_.insert(lostPacketSeq);
if (ret.second) {
ELOG_DEBUG("We received NACK for unacked packet %u", lostPacketSeq);
} else {
ELOG_DEBUG("We received NACK for ALREADY acked packet %u", lostPacketSeq);
if (blp != 0) {
for (int i = 0; i < 16; i++) {
currentNackPos = blp & 0x0001;
blp = blp >> 1;

if (currentNackPos == 1) {
lostPacketSeq = chead->getNackPid() + 1 + i;
ret = theData->nackedPackets_.insert(lostPacketSeq);
if (ret.second) {
ELOG_DEBUG("We received NACK for unacked packet %u", lostPacketSeq);
} else {
ELOG_DEBUG("We received NACK for ALREADY acked packet %u", lostPacketSeq);
}
theData->shouldSendNACK |=ret.second;
}
theData->shouldSendNACK |=ret.second;
}
}
}
if (theData->shouldSendNACK) {
ELOG_DEBUG("Will send NACK");
theData->nackSeqnum = chead->getNackPid();
theData->nackBlp = chead->getNackBlp();
theData->requestRr = true;
} else {
ELOG_DEBUG("I'm ignoring a NACK");
if (theData->shouldSendNACK) {
ELOG_DEBUG("Will send NACK");
theData->nackSeqnum = chead->getNackPid();
theData->nackBlp = chead->getNackBlp();
theData->requestRr = true;
} else {
ELOG_DEBUG("I'm ignoring a NACK");
}
}
}
break;
Expand Down
2 changes: 1 addition & 1 deletion erizo/src/erizo/rtp/RtcpForwarder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ int RtcpForwarder::analyzeFeedback(char *buf, int len) {
}
break;
case RTCP_RTP_Feedback_PT:
ELOG_DEBUG("RTP FB: Usually NACKs: %u, currentBlock %d", chead->getBlockCount(), currentBlock);
ELOG_DEBUG("RTP FB - NACKs: %u, currentBlock %d", chead->getBlockCount(), currentBlock);
ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp());
// We analyze NACK to avoid sending repeated NACKs
break;
Expand Down
51 changes: 50 additions & 1 deletion erizo/src/erizo/rtp/RtpExtensionProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ namespace erizo {
DEFINE_LOGGER(RtpExtensionProcessor, "rtp.RtpExtensionProcessor");

RtpExtensionProcessor::RtpExtensionProcessor(const std::vector<erizo::ExtMap> ext_mappings) :
ext_mappings_{ext_mappings}, video_orientation_{kVideoRotation_0} {
ext_mappings_{ext_mappings}, video_orientation_{kVideoRotation_0}, external_transportcc_id_video_{0} {
translationMap_["urn:ietf:params:rtp-hdrext:ssrc-audio-level"] = SSRC_AUDIO_LEVEL;
translationMap_["http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time"] = ABS_SEND_TIME;
translationMap_["urn:ietf:params:rtp-hdrext:toffset"] = TOFFSET;
Expand All @@ -34,6 +34,10 @@ void RtpExtensionProcessor::setSdpInfo(std::shared_ptr<SdpInfo> theInfo) {
const ExtMap& map = theInfo->extMapVector[i];
std::map<std::string, uint8_t>::iterator it;
if (isValidExtension(map.uri)) {
if (map.mediaType == VIDEO_TYPE &&
map.uri == "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01") {
external_transportcc_id_video_ = map.value;
}
setExtension(map.mediaType, map.value, RTPExtensions((*translationMap_.find(map.uri)).second));
} else {
ELOG_WARN("Unsupported extension %s", map.uri.c_str());
Expand Down Expand Up @@ -65,6 +69,7 @@ bool RtpExtensionProcessor::isValidExtension(std::string uri) {
uint32_t RtpExtensionProcessor::processRtpExtensions(std::shared_ptr<DataPacket> p) {
const RtpHeader* head = reinterpret_cast<const RtpHeader*>(p->data);
uint32_t len = p->length;
bool processed_transport_seqnum = false;
std::array<RTPExtensions, 15> extMap;
if (head->getExtension()) {
switch (p->type) {
Expand Down Expand Up @@ -114,13 +119,23 @@ uint32_t RtpExtensionProcessor::processRtpExtensions(std::shared_ptr<DataPacket>
case VIDEO_ORIENTATION:
processVideoOrientation(ext_buffer);
break;
case TRANSPORT_CC:
if (p->transport_sequence_number) {
processTransportCc(ext_buffer, p->transport_sequence_number.value());
processed_transport_seqnum = true;
}
break;
case UNKNOWN: // padding
default:
break;
}
}
ext_buffer = ext_buffer + current_ext_length + 2;
current_place = current_place + current_ext_length + 2;
}
if (external_transportcc_id_video_ && !processed_transport_seqnum && p->transport_sequence_number) {
addTransportCc(p);
}
}
}
return len;
Expand Down Expand Up @@ -164,6 +179,7 @@ uint32_t RtpExtensionProcessor::removeMidAndRidExtensions(std::shared_ptr<DataPa
break;
case ABS_SEND_TIME:
case VIDEO_ORIENTATION:
case TRANSPORT_CC:
default:
break;
}
Expand All @@ -180,6 +196,39 @@ std::string RtpExtensionProcessor::getMid() {
return mid_;
}

uint32_t RtpExtensionProcessor::addTransportCc(std::shared_ptr<DataPacket> p) {
const RtpHeader* head = reinterpret_cast<const RtpHeader*>(p->data);
if (head->getHeaderLength() >= p->length) {
ELOG_WARN("headerLength: %u is bigger than packet length %d, potentially malformed packet, ispadding: %d",
head->getHeaderLength(), p->length, p->is_padding);
return 0;
}
char new_buffer[1500];
memcpy(reinterpret_cast<char*>(new_buffer), reinterpret_cast<char*>(p->data), head->getHeaderLength());
char* end_header = reinterpret_cast<char*>(new_buffer) + head->getHeaderLength();
RtpHeader* new_head = reinterpret_cast<RtpHeader*>(new_buffer);
new_head->setExtLength(head->getExtLength() + 1);

memset(end_header, 0, 4);
TransportCcExtension* transport_extension = reinterpret_cast<TransportCcExtension*>(end_header);
transport_extension->setId(external_transportcc_id_video_);
transport_extension->setLength(1);
transport_extension->setSeqNumber(p->transport_sequence_number.value());
end_header+=4;
char* payload = reinterpret_cast<char*>(p->data) + head->getHeaderLength();
memcpy(end_header, payload, p->length - head->getHeaderLength());
uint32_t new_length = p->length + 4;
p->length = new_length;
memcpy(p->data, new_buffer, new_length);
return 0;
}

uint32_t RtpExtensionProcessor::processTransportCc(char* buf, uint16_t new_seq_num) {
TransportCcExtension* transport_extension = reinterpret_cast<TransportCcExtension*>(buf);
transport_extension->setSeqNumber(new_seq_num);
return 0;
}

uint32_t RtpExtensionProcessor::processMid(char* buf) {
GenericOneByteExtension* header = new GenericOneByteExtension(buf);
mid_ = std::string(header->getData());
Expand Down
6 changes: 5 additions & 1 deletion erizo/src/erizo/rtp/RtpExtensionProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
namespace erizo {

enum RTPExtensions {
UNKNOWN = 0,
UNKNOWN = 0, // usually padding
SSRC_AUDIO_LEVEL, // urn:ietf:params:rtp-hdrext:ssrc-audio-level
ABS_SEND_TIME, // http:// www.webrtc.org/experiments/rtp-hdrext/abs-send-time
TOFFSET, // urn:ietf:params:rtp-hdrext:toffset
Expand Down Expand Up @@ -58,11 +58,15 @@ class RtpExtensionProcessor{
VideoRotation video_orientation_;
std::string mid_;
std::string rid_;
uint16_t external_transportcc_id_video_;

uint32_t processAbsSendTime(char* buf);
uint32_t processVideoOrientation(char* buf);
uint32_t processRid(char* buf);
uint32_t processMid(char* buf);
uint32_t stripExtension(char* buf, int len);
uint32_t addTransportCc(std::shared_ptr<DataPacket> p);
uint32_t processTransportCc(char* buf, uint16_t new_seq_num);
};

} // namespace erizo
Expand Down
39 changes: 39 additions & 0 deletions erizo/src/erizo/rtp/RtpHeaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ namespace erizo {
#define RTCP_SLI_FMT 2
#define RTCP_FIR_FMT 4
#define RTCP_AFB 15
#define RTCP_NACK_FMT 1
#define RTCP_TRANSPORT_WIDE_FEEDBACK_FMT 15

#define VP8_90000_PT 100 // VP8 Video Codec
#define RED_90000_PT 116 // REDundancy (RFC 2198)
Expand Down Expand Up @@ -210,6 +212,37 @@ class GenericOneByteExtension {
return data;
}
};
// 0 1 2 3
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | 0xBE | 0xDE | length=1 |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
// | ID | L=1 |transport-wide sequence number | zero padding |
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
class TransportCcExtension {
public:
uint32_t length:4;
uint32_t id:4;
uint32_t data:16;
inline uint8_t getId() {
return id;
}
inline uint8_t getLength() {
return length;
}
inline void setId(uint8_t new_id) {
id = new_id;
}
inline void setLength(uint8_t new_length) {
length = new_length;
}
inline uint16_t getSeqNumber() {
return ntohs(data);
}
inline void setSeqNumber(uint16_t seqnum) {
data = htons(seqnum);
}
};

class VideoOrientation {
public:
Expand Down Expand Up @@ -453,6 +486,12 @@ class RtcpHeader {
inline bool isSDES() {
return packettype == RTCP_SDES_PT;
}
inline bool isNACK() {
return packettype == RTCP_RTP_Feedback_PT && blockcount == RTCP_NACK_FMT;
}
inline bool isTransportWideFeedback() {
return packettype == RTCP_RTP_Feedback_PT && blockcount == RTCP_TRANSPORT_WIDE_FEEDBACK_FMT;
}
inline bool isREMB() {
return packettype == RTCP_PS_Feedback_PT && blockcount == RTCP_AFB;
}
Expand Down
14 changes: 8 additions & 6 deletions erizo/src/erizo/rtp/RtpPaddingManagerHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,19 +107,19 @@ void RtpPaddingManagerHandler::recalculatePaddingRate() {

int64_t media_bitrate = total["videoBitrate"].value();
int64_t estimated_bandwidth = total["senderBitrateEstimation"].value();
int64_t estimated_target = total["senderBitrateEstimationTarget"].value();

int64_t target_bitrate = getTotalTargetBitrate();

if (target_bitrate == 0) {
target_bitrate = kInitialBitrate;
}

int64_t target_padding_bitrate = std::max(target_bitrate - media_bitrate, int64_t(0));
bool remb_sharp_drop = estimated_bandwidth < last_estimated_bandwidth_*kBweSharpDropThreshold;
if (current_mode_ == PaddingManagerMode::RECOVER) { // if in recover mode any drop will stop it
remb_sharp_drop = estimated_bandwidth < last_estimated_bandwidth_;
}
int64_t available_bitrate = std::max(estimated_bandwidth - media_bitrate, int64_t(0));
int64_t available_bitrate = std::max(estimated_target - media_bitrate, int64_t(0));

ELOG_DEBUG("Is sharp drop? last_estimated*k %f, new_estimated %u", last_estimated_bandwidth_*kBweSharpDropThreshold,
estimated_bandwidth);
Expand All @@ -142,15 +142,16 @@ void RtpPaddingManagerHandler::recalculatePaddingRate() {
switch (current_mode_) {
case PaddingManagerMode::START:
{
available_bitrate = std::max(estimated_bandwidth*kStartModeFactor - media_bitrate, static_cast<double>(0));
// when using rembs estimated_bandwidth == estimated_target, in that case we use kStartModeFactor for START
target_padding_bitrate = std::max(static_cast<int64_t>(estimated_bandwidth*kStartModeFactor - media_bitrate),
target_padding_bitrate);
target_padding_bitrate = std::min(target_padding_bitrate, available_bitrate); // never send more than max
break;
}
case PaddingManagerMode::STABLE:
{
can_recover_ = true;
target_padding_bitrate = std::min(target_padding_bitrate,
static_cast<int64_t>(available_bitrate*kStableModeAvailableFactor));
target_padding_bitrate = std::min(target_padding_bitrate, available_bitrate);
bool has_unnasigned_bitrate = false;
bool has_connection_target_bitrate = connection_->getConnectionTargetBw() > 0;
bool estimated_is_high_enough = estimated_bandwidth > (target_bitrate * kBitrateComparisonMargin);
Expand Down Expand Up @@ -178,11 +179,12 @@ void RtpPaddingManagerHandler::recalculatePaddingRate() {
}

ELOG_DEBUG("Padding stats: target_bitrate %lu, target_padding_bitrate %lu, current_mode_ %u "
"estimated_bitrate %lu, media_bitrate: %lu, available_bw: %lu",
"estimated_bitrate %lu, estimated_target %lu, media_bitrate: %lu, available_bw: %lu",
target_bitrate,
target_padding_bitrate,
current_mode_,
estimated_bandwidth,
estimated_target,
media_bitrate,
available_bitrate,
current_mode_);
Expand Down
Loading

0 comments on commit ad1ac9f

Please sign in to comment.