#define MS_CLASS "RTC::SenderBandwidthEstimator"
#include "RTC/SenderBandwidthEstimator.hpp"
#include "DepLibUV.hpp"
#include "Logger.hpp"
namespace RTC
{
static constexpr uint16_t MaxSentInfoAge{ 2000u }; static constexpr float DefaultRtt{ 100 };
SenderBandwidthEstimator::SenderBandwidthEstimator(
RTC::SenderBandwidthEstimator::Listener* listener, uint32_t initialAvailableBitrate)
: listener(listener), initialAvailableBitrate(initialAvailableBitrate), rtt(DefaultRtt),
sendTransmission(1000u), sendTransmissionTrend(0.15f)
{
MS_TRACE();
}
SenderBandwidthEstimator::~SenderBandwidthEstimator()
{
MS_TRACE();
}
void SenderBandwidthEstimator::TransportConnected()
{
MS_TRACE();
this->availableBitrate = this->initialAvailableBitrate;
this->lastAvailableBitrateEventAtMs = DepLibUV::GetTimeMs();
}
void SenderBandwidthEstimator::TransportDisconnected()
{
MS_TRACE();
this->availableBitrate = 0u;
this->sentInfos.clear();
this->cummulativeResult.Reset();
}
void SenderBandwidthEstimator::RtpPacketSent(const SentInfo& sentInfo)
{
MS_TRACE();
auto nowMs = sentInfo.sentAtMs;
auto it = this->sentInfos.lower_bound(sentInfo.wideSeq - MaxSentInfoAge + 1);
this->sentInfos.erase(this->sentInfos.begin(), it);
this->sentInfos[sentInfo.wideSeq] = sentInfo;
this->sendTransmission.Update(sentInfo.size, nowMs);
auto sendBitrate = this->sendTransmission.GetRate(nowMs);
this->sendTransmissionTrend.Update(sendBitrate, nowMs);
}
void SenderBandwidthEstimator::ReceiveRtcpTransportFeedback(
const RTC::RTCP::FeedbackRtpTransportPacket* feedback)
{
MS_TRACE();
auto nowMs = DepLibUV::GetTimeMs();
const uint64_t elapsedMs = nowMs - this->cummulativeResult.GetStartedAtMs();
if (elapsedMs > 1000u)
{
this->cummulativeResult.Reset();
}
for (auto& result : feedback->GetPacketResults())
{
if (!result.received)
{
continue;
}
const uint16_t wideSeq = result.sequenceNumber;
auto it = this->sentInfos.find(wideSeq);
if (it == this->sentInfos.end())
{
MS_WARN_DEV("received packet not present in sent infos [wideSeq:%" PRIu16 "]", wideSeq);
continue;
}
auto& sentInfo = it->second;
if (!sentInfo.isProbation)
{
this->cummulativeResult.AddPacket(
sentInfo.size, static_cast<int64_t>(sentInfo.sentAtMs), result.receivedAtMs);
}
else
{
this->probationCummulativeResult.AddPacket(
sentInfo.size, static_cast<int64_t>(sentInfo.sentAtMs), result.receivedAtMs);
}
}
if (this->probationCummulativeResult.GetNumPackets() >= 2u)
{
EstimateAvailableBitrate(this->probationCummulativeResult);
this->probationCummulativeResult.Reset();
}
else
{
this->probationCummulativeResult.Reset();
}
if (elapsedMs >= 100u && this->cummulativeResult.GetNumPackets() >= 20u)
{
EstimateAvailableBitrate(this->cummulativeResult);
this->cummulativeResult.Reset();
}
}
void SenderBandwidthEstimator::EstimateAvailableBitrate(CummulativeResult& cummulativeResult)
{
MS_TRACE();
auto previousAvailableBitrate = this->availableBitrate;
const double ratio = static_cast<double>(cummulativeResult.GetReceiveBitrate()) /
static_cast<double>(cummulativeResult.GetSendBitrate());
auto bitrate =
std::min<uint32_t>(cummulativeResult.GetReceiveBitrate(), cummulativeResult.GetSendBitrate());
if (0.75f <= ratio && ratio <= 1.25f)
{
if (bitrate > this->availableBitrate)
{
this->availableBitrate = bitrate;
MS_DEBUG_DEV("BWE UP [ratio:%f, availableBitrate:%" PRIu32 "]", ratio, this->availableBitrate);
}
}
else
{
if (bitrate < this->availableBitrate)
{
this->availableBitrate = bitrate;
MS_DEBUG_DEV(
"BWE DOWN [ratio:%f, availableBitrate:%" PRIu32 "]", ratio, this->availableBitrate);
}
}
this->listener->OnSenderBandwidthEstimatorAvailableBitrate(
this, this->availableBitrate, previousAvailableBitrate);
}
void SenderBandwidthEstimator::UpdateRtt(float rtt)
{
MS_TRACE();
this->rtt = rtt;
}
uint32_t SenderBandwidthEstimator::GetAvailableBitrate() const
{
MS_TRACE();
return this->availableBitrate;
}
void SenderBandwidthEstimator::RescheduleNextAvailableBitrateEvent()
{
MS_TRACE();
this->lastAvailableBitrateEventAtMs = DepLibUV::GetTimeMs();
}
void SenderBandwidthEstimator::CummulativeResult::AddPacket(
size_t size, int64_t sentAtMs, int64_t receivedAtMs)
{
MS_TRACE();
if (this->numPackets == 0u)
{
this->firstPacketSentAtMs = sentAtMs;
this->firstPacketReceivedAtMs = receivedAtMs;
this->lastPacketSentAtMs = sentAtMs;
this->lastPacketReceivedAtMs = receivedAtMs;
}
else
{
if (sentAtMs < this->firstPacketSentAtMs)
{
this->firstPacketSentAtMs = sentAtMs;
}
if (receivedAtMs < this->firstPacketReceivedAtMs)
{
this->firstPacketReceivedAtMs = receivedAtMs;
}
if (sentAtMs > this->lastPacketSentAtMs)
{
this->lastPacketSentAtMs = sentAtMs;
}
if (receivedAtMs > this->lastPacketReceivedAtMs)
{
this->lastPacketReceivedAtMs = receivedAtMs;
}
}
this->numPackets++;
this->totalSize += size;
}
void SenderBandwidthEstimator::CummulativeResult::Reset()
{
MS_TRACE();
this->numPackets = 0u;
this->totalSize = 0u;
this->firstPacketSentAtMs = 0u;
this->lastPacketSentAtMs = 0u;
this->firstPacketReceivedAtMs = 0u;
this->lastPacketReceivedAtMs = 0u;
}
}