Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement new padding manager calculation algorithm #1810

Merged
merged 7 commits into from
May 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions erizo/src/erizo/WebRtcConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ void WebRtcConnection::initializeStats() {
log_stats_->getNode().insertStat("bwe", CumulativeStat{0});
log_stats_->getNode().insertStat("bwDistributionAlgorithm", StringStat{""});
log_stats_->getNode().insertStat("bwPriorityStrategy", StringStat{""});
log_stats_->getNode().insertStat("paddingMode", CumulativeStat{0});

std::weak_ptr<WebRtcConnection> weak_this = shared_from_this();
worker_->scheduleEvery([weak_this] () {
Expand Down Expand Up @@ -178,6 +179,7 @@ void WebRtcConnection::printStats() {
log_stats_->getNode().insertStat("connectionQualityLevel",
CumulativeStat(getConnectionQualityLevel()));
transferMediaStats("bwe", "total", "senderBitrateEstimation");
transferMediaStats("paddingMode", "total", "paddingMode");

ELOG_INFOT(ConnectionStatsLogger, "%s", log_stats_->getStats());
}
Expand Down
2 changes: 1 addition & 1 deletion erizo/src/erizo/rtp/BandwidthEstimationHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ void BandwidthEstimationHandler::read(Context *ctx, std::shared_ptr<DataPacket>
RtpHeader *head = reinterpret_cast<RtpHeader*> (packet->data);
int64_t arrival_time_ms = packet->received_time_ms;
arrival_time_ms = clock_->TimeInMilliseconds() - (ClockUtils::timePointToMs(clock::now()) - arrival_time_ms);
size_t payload_size = packet->length - head->getHeaderLength();
size_t payload_size = packet->length;
pickEstimatorFromHeader();
rbe_->IncomingPacket(arrival_time_ms, payload_size, header_);
} else {
Expand Down
175 changes: 126 additions & 49 deletions erizo/src/erizo/rtp/RtpPaddingManagerHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,19 @@ namespace erizo {
DEFINE_LOGGER(RtpPaddingManagerHandler, "rtp.RtpPaddingManagerHandler");

static constexpr duration kStatsPeriod = std::chrono::milliseconds(100);
constexpr duration RtpPaddingManagerHandler::kMinDurationToSendPaddingAfterBweDecrease;
constexpr duration RtpPaddingManagerHandler::kMaxDurationInRecoveryFromBwe;
static constexpr double kBitrateComparisonMargin = 1.1;
static constexpr uint64_t kInitialBitrate = 300000;
static constexpr uint64_t kUnnasignedBitrateMargin = 50000;
static constexpr uint64_t kUnnasignedBitrateMargin = 200000;

RtpPaddingManagerHandler::RtpPaddingManagerHandler(std::shared_ptr<erizo::Clock> the_clock) :
initialized_{false},
clock_{the_clock},
last_rate_calculation_time_{clock_->now()},
last_mode_change_{clock_->now()},
connection_{nullptr},
last_estimated_bandwidth_{0} {
last_estimated_bandwidth_{0},
can_recover_{true},
current_mode_{PaddingManagerMode::START} {
}

void RtpPaddingManagerHandler::enable() {
Expand Down Expand Up @@ -53,6 +54,8 @@ void RtpPaddingManagerHandler::notifyUpdate() {
MovingIntervalRateStat{std::chrono::milliseconds(100), 30, 8., clock_});
stats_->getNode()["total"].insertStat("videoBitrate",
MovingIntervalRateStat{std::chrono::milliseconds(100), 30, 8., clock_});
stats_->getNode()["total"].insertStat("paddingMode",
CumulativeStat{current_mode_});
}

if (!connection_) {
Expand Down Expand Up @@ -83,6 +86,11 @@ void RtpPaddingManagerHandler::write(Context *ctx, std::shared_ptr<DataPacket> p
ctx->fireWrite(packet);
}

PaddingManagerMode RtpPaddingManagerHandler::getCurrentPaddingMode() {
ELOG_DEBUG("Getting current padding mode - %u", current_mode_);
return current_mode_;
}

void RtpPaddingManagerHandler::recalculatePaddingRate() {
if (!isTimeToCalculateBitrate()) {
return;
Expand All @@ -107,62 +115,130 @@ void RtpPaddingManagerHandler::recalculatePaddingRate() {
}

int64_t target_padding_bitrate = std::max(target_bitrate - media_bitrate, int64_t(0));
int64_t available_bw = std::max(estimated_bandwidth - media_bitrate, int64_t(0));

target_padding_bitrate = std::min(target_padding_bitrate, available_bw);

bool estimated_is_high_enough = estimated_bandwidth > (target_bitrate * kBitrateComparisonMargin);
bool has_unnasigned_bitrate = false;
bool has_connection_target_bitrate = connection_->getConnectionTargetBw() > 0;
if (stats_->getNode()["total"].hasChild("unnasignedBitrate")) {
has_unnasigned_bitrate =
stats_->getNode()["total"]["unnasignedBitrate"].value() > kUnnasignedBitrateMargin &&
!has_connection_target_bitrate;
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_;
}
if (estimated_is_high_enough || has_unnasigned_bitrate) {
target_padding_bitrate = 0;
int64_t available_bitrate = std::max(estimated_bandwidth - media_bitrate, int64_t(0));

ELOG_DEBUG("Is sharp drop? last_estimated*k %f, new_estimated %u", last_estimated_bandwidth_*kBweSharpDropThreshold,
estimated_bandwidth);
// Maybe Trigger Hold Mode
if (remb_sharp_drop) {
estimated_before_drop_ = last_estimated_bandwidth_;
ELOG_DEBUG("%s Detected sharp BWE drop, estimated_before_drop_: %lu, estimated_bandwidth: %u",
connection_->toLog(), estimated_before_drop_, estimated_bandwidth);
if (current_mode_ == PaddingManagerMode::RECOVER) {
ELOG_DEBUG("%s, Sharp drop in recover mode", connection_->toLog());
can_recover_ = false;
}
forceModeSwitch(PaddingManagerMode::HOLD);
}

bool remb_is_decreasing = estimated_bandwidth < last_estimated_bandwidth_;
last_estimated_bandwidth_ = estimated_bandwidth;
double step = 1.0;
duration time_since_bwe_decreased_ = clock_->now() - last_time_bwe_decreased_;
if (remb_is_decreasing) {
ELOG_DEBUG("%s Remb is decreasing", connection_->toLog());
target_padding_bitrate = 0;
last_time_bwe_decreased_ = clock_->now();
} else if (time_since_bwe_decreased_ < kMinDurationToSendPaddingAfterBweDecrease) {
ELOG_DEBUG("%s Backoff up period time since %d, min %d",
connection_->toLog(),
std::chrono::duration_cast<std::chrono::milliseconds>(time_since_bwe_decreased_).count(),
std::chrono::duration_cast<std::chrono::milliseconds>(kMinDurationToSendPaddingAfterBweDecrease).count());
target_padding_bitrate = 0;
} else if (time_since_bwe_decreased_ >= kMinDurationToSendPaddingAfterBweDecrease) {
step = static_cast<double>(time_since_bwe_decreased_.count()) / kMaxDurationInRecoveryFromBwe.count();
ELOG_DEBUG("%s Ramping up period time since %d, min %d, max %d, calculated step %f",
connection_->toLog(),
std::chrono::duration_cast<std::chrono::milliseconds>(time_since_bwe_decreased_).count(),
std::chrono::duration_cast<std::chrono::milliseconds>(kMinDurationToSendPaddingAfterBweDecrease).count(),
std::chrono::duration_cast<std::chrono::milliseconds>(kMaxDurationInRecoveryFromBwe).count(),
step);
step = std::min(step, 1.0);
target_padding_bitrate = target_padding_bitrate * step;

// Check if it's time to change mode
maybeTriggerTimedModeChanges();

switch (current_mode_) {
case PaddingManagerMode::START:
{
available_bitrate = std::max(estimated_bandwidth*kStartModeFactor - media_bitrate, static_cast<double>(0));
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));
bool has_unnasigned_bitrate = false;
bool has_connection_target_bitrate = connection_->getConnectionTargetBw() > 0;
bool estimated_is_high_enough = estimated_bandwidth > (target_bitrate * kBitrateComparisonMargin);
if (stats_->getNode()["total"].hasChild("unnasignedBitrate")) {
has_unnasigned_bitrate =
stats_->getNode()["total"]["unnasignedBitrate"].value() > kUnnasignedBitrateMargin &&
!has_connection_target_bitrate;
}
if (estimated_is_high_enough || has_unnasigned_bitrate) {
target_padding_bitrate = 0;
}
break;
}
case PaddingManagerMode::HOLD:
{
target_padding_bitrate = 0;
break;
}
case PaddingManagerMode::RECOVER:
{
available_bitrate = std::max(estimated_before_drop_*kRecoverBweFactor - media_bitrate, static_cast<double>(0));
target_padding_bitrate = std::min(available_bitrate, target_bitrate);
break;
}
}

ELOG_DEBUG("%s Calculated: target %d, bwe %d, last_bwe %d, media %d, target %d, bwe enough %d"
" step %f, remb_is_decreasing %d",
connection_->toLog(),
ELOG_DEBUG("Padding stats: target_bitrate %lu, target_padding_bitrate %lu, current_mode_ %u "
"estimated_bitrate %lu, media_bitrate: %lu, available_bw: %lu",
target_bitrate,
target_padding_bitrate,
current_mode_,
estimated_bandwidth,
last_estimated_bandwidth_,
media_bitrate,
target_bitrate,
estimated_is_high_enough,
step,
remb_is_decreasing);
available_bitrate,
current_mode_);

distributeTotalTargetPaddingBitrate(target_padding_bitrate);
}

void RtpPaddingManagerHandler::forceModeSwitch(PaddingManagerMode new_mode) {
ELOG_DEBUG("%s switching mode, current_mode_ %u, new_mode %u, ms since last change %lu",
connection_->toLog(),
current_mode_,
new_mode,
std::chrono::duration_cast<std::chrono::milliseconds>(clock_->now() - last_mode_change_));
current_mode_ = new_mode;
last_mode_change_ = clock_->now();
stats_->getNode()["total"].insertStat("paddingMode",
CumulativeStat{current_mode_});
}

void RtpPaddingManagerHandler::maybeTriggerTimedModeChanges() {
duration time_in_current_mode = clock_->now() - last_mode_change_;
switch (current_mode_) {
case PaddingManagerMode::START:
{
if (time_in_current_mode > kMaxDurationInStartMode) {
ELOG_DEBUG("%s Start mode is over, switching to stable", connection_->toLog());
forceModeSwitch(PaddingManagerMode::STABLE);
}
break;
}
case PaddingManagerMode::STABLE:
break;
case PaddingManagerMode::HOLD:
{
if (time_in_current_mode > kMaxDurationInHoldMode) {
if (can_recover_) {
ELOG_DEBUG("%s Hold mode is over, switching to recover", connection_->toLog());
forceModeSwitch(PaddingManagerMode::RECOVER);
} else {
ELOG_DEBUG("%s Hold mode is over, switching to stable", connection_->toLog());
forceModeSwitch(PaddingManagerMode::STABLE);
}
}
break;
}
case PaddingManagerMode::RECOVER:
{
if (time_in_current_mode > kMaxDurationInRecoverMode) {
ELOG_DEBUG("%s Recover is successful, switching to stable", connection_->toLog());
forceModeSwitch(PaddingManagerMode::STABLE);
}
break;
}
}
}

void RtpPaddingManagerHandler::distributeTotalTargetPaddingBitrate(int64_t bitrate) {
size_t num_streams = 0;
connection_->forEachMediaStream([&num_streams]
Expand All @@ -182,6 +258,7 @@ void RtpPaddingManagerHandler::distributeTotalTargetPaddingBitrate(int64_t bitra
if (!media_stream->canSendPadding()) {
return;
}
ELOG_DEBUG("Setting Target %u", bitrate_per_stream);
media_stream->setTargetPaddingBitrate(bitrate_per_stream);
});
}
Expand Down
24 changes: 22 additions & 2 deletions erizo/src/erizo/rtp/RtpPaddingManagerHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,25 @@ namespace erizo {

class WebRtcConnection;

enum PaddingManagerMode {
START = 0,
STABLE = 1,
HOLD = 2,
RECOVER = 3
};


class RtpPaddingManagerHandler: public Handler, public std::enable_shared_from_this<RtpPaddingManagerHandler> {
DECLARE_LOGGER();

public:
static constexpr duration kMinDurationToSendPaddingAfterBweDecrease = std::chrono::seconds(5);
static constexpr duration kMaxDurationInRecoveryFromBwe = std::chrono::seconds(30);
static constexpr duration kMaxDurationInStartMode = std::chrono::seconds(15);
static constexpr duration kMaxDurationInRecoverMode = std::chrono::seconds(10);
static constexpr duration kMaxDurationInHoldMode = std::chrono::seconds(5);
static constexpr double kBweSharpDropThreshold = 0.66;
static constexpr double kStartModeFactor = 3;
static constexpr double kRecoverBweFactor = 0.85;
static constexpr double kStableModeAvailableFactor = 1.1;
explicit RtpPaddingManagerHandler(std::shared_ptr<erizo::Clock> the_clock = std::make_shared<erizo::SteadyClock>());

void enable() override;
Expand All @@ -33,21 +46,28 @@ class RtpPaddingManagerHandler: public Handler, public std::enable_shared_from_t
void read(Context *ctx, std::shared_ptr<DataPacket> packet) override;
void write(Context *ctx, std::shared_ptr<DataPacket> packet) override;
void notifyUpdate() override;
PaddingManagerMode getCurrentPaddingMode();

private:
bool isTimeToCalculateBitrate();
void recalculatePaddingRate();
void distributeTotalTargetPaddingBitrate(int64_t bitrate);
int64_t getTotalTargetBitrate();
void maybeTriggerTimedModeChanges();
void forceModeSwitch(PaddingManagerMode new_mode);

private:
bool initialized_;
std::shared_ptr<erizo::Clock> clock_;
time_point last_rate_calculation_time_;
time_point last_time_bwe_decreased_;
time_point last_mode_change_;
uint64_t estimated_before_drop_;
WebRtcConnection* connection_;
std::shared_ptr<Stats> stats_;
int64_t last_estimated_bandwidth_;
bool can_recover_;
PaddingManagerMode current_mode_;
};

} // namespace erizo
Expand Down
5 changes: 5 additions & 0 deletions erizo/src/erizo/rtp/SenderBandwidthEstimantionHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ namespace erizo {

DEFINE_LOGGER(SenderBandwidthEstimationHandler, "rtp.SenderBandwidthEstimationHandler");

const uint16_t SenderBandwidthEstimationHandler::kMaxSrListSize;
const uint32_t SenderBandwidthEstimationHandler::kStartSendBitrate;
const uint32_t SenderBandwidthEstimationHandler::kMinSendBitrate;
const uint32_t SenderBandwidthEstimationHandler::kMinSendBitrateLimit;
const uint32_t SenderBandwidthEstimationHandler::kMaxSendBitrate;
constexpr duration SenderBandwidthEstimationHandler::kMinUpdateEstimateInterval;

SenderBandwidthEstimationHandler::SenderBandwidthEstimationHandler(std::shared_ptr<Clock> the_clock) :
Expand Down
Loading