Fix issue with pacing rate after long queue times.
A recent cleanup cl (r36900) had an unintended side-effect. If the queue-time limit is expected to be hit, we adjust the pacing bitrate up to make sure all packets are sent within the nominal time frame. However after that change we stopped adjusting the pacing rate back to normal levels when queue clears - at least not until the next BWE update (which is fairly often - but not immediate). This CL fixes that, and also makes sure whe properly update the adjusted media rate on enqueu, dequeue and set rate calls. Bug: webrtc:10809 Change-Id: If00dc35169f1a1347fea6eb44fdb2868282ed3b7 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/265387 Reviewed-by: Per Kjellander <perkj@webrtc.org> Commit-Queue: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/main@{#37178}
This commit is contained in:
committed by
WebRTC LUCI CQ
parent
da12e10aba
commit
df9e51a190
@ -93,7 +93,8 @@ PacingController::PacingController(Clock* clock,
|
||||
paused_(false),
|
||||
media_debt_(DataSize::Zero()),
|
||||
padding_debt_(DataSize::Zero()),
|
||||
media_rate_(DataRate::Zero()),
|
||||
pacing_rate_(DataRate::Zero()),
|
||||
adjusted_media_rate_(DataRate::Zero()),
|
||||
padding_rate_(DataRate::Zero()),
|
||||
prober_(field_trials_),
|
||||
probing_send_failure_(false),
|
||||
@ -198,21 +199,22 @@ void PacingController::SetPacingRates(DataRate pacing_rate,
|
||||
<< " kbps, padding = " << padding_rate.kbps()
|
||||
<< " kbps.";
|
||||
}
|
||||
media_rate_ = pacing_rate;
|
||||
pacing_rate_ = pacing_rate;
|
||||
padding_rate_ = padding_rate;
|
||||
MaybeUpdateMediaRateDueToLongQueue(CurrentTime());
|
||||
|
||||
RTC_LOG(LS_VERBOSE) << "bwe:pacer_updated pacing_kbps=" << media_rate_.kbps()
|
||||
RTC_LOG(LS_VERBOSE) << "bwe:pacer_updated pacing_kbps=" << pacing_rate_.kbps()
|
||||
<< " padding_budget_kbps=" << padding_rate.kbps();
|
||||
}
|
||||
|
||||
void PacingController::EnqueuePacket(std::unique_ptr<RtpPacketToSend> packet) {
|
||||
RTC_DCHECK(media_rate_ > DataRate::Zero())
|
||||
RTC_DCHECK(pacing_rate_ > DataRate::Zero())
|
||||
<< "SetPacingRate must be called before InsertPacket.";
|
||||
RTC_CHECK(packet->packet_type());
|
||||
|
||||
prober_.OnIncomingPacket(DataSize::Bytes(packet->payload_size()));
|
||||
|
||||
Timestamp now = CurrentTime();
|
||||
const Timestamp now = CurrentTime();
|
||||
if (packet_queue_->Empty()) {
|
||||
// If queue is empty, we need to "fast-forward" the last process time,
|
||||
// so that we don't use passed time as budget for sending the first new
|
||||
@ -228,6 +230,9 @@ void PacingController::EnqueuePacket(std::unique_ptr<RtpPacketToSend> packet) {
|
||||
}
|
||||
packet_queue_->Push(now, std::move(packet));
|
||||
seen_first_packet_ = true;
|
||||
|
||||
// Queue length has increased, check if we need to change the pacing rate.
|
||||
MaybeUpdateMediaRateDueToLongQueue(now);
|
||||
}
|
||||
|
||||
void PacingController::SetAccountForAudioPackets(bool account_for_audio) {
|
||||
@ -249,10 +254,8 @@ void PacingController::SetSendBurstInterval(TimeDelta burst_interval) {
|
||||
}
|
||||
|
||||
TimeDelta PacingController::ExpectedQueueTime() const {
|
||||
RTC_DCHECK_GT(media_rate_, DataRate::Zero());
|
||||
return TimeDelta::Millis(
|
||||
(QueueSizeData().bytes() * 8 * rtc::kNumMillisecsPerSec) /
|
||||
media_rate_.bps());
|
||||
RTC_DCHECK_GT(adjusted_media_rate_, DataRate::Zero());
|
||||
return QueueSizeData() / adjusted_media_rate_;
|
||||
}
|
||||
|
||||
size_t PacingController::QueueSizePackets() const {
|
||||
@ -343,11 +346,11 @@ Timestamp PacingController::NextSendTime() const {
|
||||
return last_send_time_ + kCongestedPacketInterval;
|
||||
}
|
||||
|
||||
if (media_rate_ > DataRate::Zero() && !packet_queue_->Empty()) {
|
||||
if (adjusted_media_rate_ > DataRate::Zero() && !packet_queue_->Empty()) {
|
||||
// If packets are allowed to be sent in a burst, the
|
||||
// debt is allowed to grow up to one packet more than what can be sent
|
||||
// during 'send_burst_period_'.
|
||||
TimeDelta drain_time = media_debt_ / media_rate_;
|
||||
TimeDelta drain_time = media_debt_ / adjusted_media_rate_;
|
||||
next_send_time =
|
||||
last_process_time_ +
|
||||
((send_burst_interval_ > drain_time) ? TimeDelta::Zero() : drain_time);
|
||||
@ -355,9 +358,9 @@ Timestamp PacingController::NextSendTime() const {
|
||||
// If we _don't_ have pending packets, check how long until we have
|
||||
// bandwidth for padding packets. Both media and padding debts must
|
||||
// have been drained to do this.
|
||||
RTC_DCHECK_GT(media_rate_, DataRate::Zero());
|
||||
TimeDelta drain_time =
|
||||
std::max(media_debt_ / media_rate_, padding_debt_ / padding_rate_);
|
||||
RTC_DCHECK_GT(adjusted_media_rate_, DataRate::Zero());
|
||||
TimeDelta drain_time = std::max(media_debt_ / adjusted_media_rate_,
|
||||
padding_debt_ / padding_rate_);
|
||||
|
||||
if (drain_time.IsZero() &&
|
||||
(!media_debt_.IsZero() || !padding_debt_.IsZero())) {
|
||||
@ -380,7 +383,7 @@ Timestamp PacingController::NextSendTime() const {
|
||||
}
|
||||
|
||||
void PacingController::ProcessPackets() {
|
||||
Timestamp now = CurrentTime();
|
||||
const Timestamp now = CurrentTime();
|
||||
Timestamp target_send_time = now;
|
||||
|
||||
if (ShouldSendKeepalive(now)) {
|
||||
@ -420,27 +423,6 @@ void PacingController::ProcessPackets() {
|
||||
TimeDelta elapsed_time = UpdateTimeAndGetElapsed(target_send_time);
|
||||
|
||||
if (elapsed_time > TimeDelta::Zero()) {
|
||||
DataRate target_rate = media_rate_;
|
||||
DataSize queue_size_data = QueueSizeData();
|
||||
if (queue_size_data > DataSize::Zero()) {
|
||||
// Assuming equal size packets and input/output rate, the average packet
|
||||
// has avg_time_left_ms left to get queue_size_bytes out of the queue, if
|
||||
// time constraint shall be met. Determine bitrate needed for that.
|
||||
packet_queue_->UpdateAverageQueueTime(now);
|
||||
if (drain_large_queues_) {
|
||||
TimeDelta avg_time_left =
|
||||
std::max(TimeDelta::Millis(1),
|
||||
queue_time_limit_ - packet_queue_->AverageQueueTime());
|
||||
DataRate min_rate_needed = queue_size_data / avg_time_left;
|
||||
if (min_rate_needed > target_rate) {
|
||||
target_rate = min_rate_needed;
|
||||
RTC_LOG(LS_VERBOSE) << "bwe:large_pacing_queue pacing_rate_kbps="
|
||||
<< target_rate.kbps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
media_rate_ = target_rate;
|
||||
UpdateBudgetWithElapsedTime(elapsed_time);
|
||||
}
|
||||
|
||||
@ -556,6 +538,11 @@ void PacingController::ProcessPackets() {
|
||||
prober_.ProbeSent(CurrentTime(), data_sent);
|
||||
}
|
||||
}
|
||||
|
||||
// Queue length has probably decreased, check if pacing rate needs to updated.
|
||||
// Poll the time again, since we might have enqueued new fec/padding packets
|
||||
// with a later timestamp than `now`.
|
||||
MaybeUpdateMediaRateDueToLongQueue(CurrentTime());
|
||||
}
|
||||
|
||||
DataSize PacingController::PaddingToAdd(DataSize recommended_probe_size,
|
||||
@ -630,7 +617,7 @@ std::unique_ptr<RtpPacketToSend> PacingController::GetPendingPacket(
|
||||
// is not more than would be reduced to zero at the target sent time.
|
||||
// If we allow packets to be sent in a burst, packet are allowed to be
|
||||
// sent early.
|
||||
TimeDelta flush_time = media_debt_ / media_rate_;
|
||||
TimeDelta flush_time = media_debt_ / adjusted_media_rate_;
|
||||
if (now + flush_time > target_send_time) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -656,13 +643,13 @@ void PacingController::OnPacketSent(RtpPacketMediaType packet_type,
|
||||
}
|
||||
|
||||
void PacingController::UpdateBudgetWithElapsedTime(TimeDelta delta) {
|
||||
media_debt_ -= std::min(media_debt_, media_rate_ * delta);
|
||||
media_debt_ -= std::min(media_debt_, adjusted_media_rate_ * delta);
|
||||
padding_debt_ -= std::min(padding_debt_, padding_rate_ * delta);
|
||||
}
|
||||
|
||||
void PacingController::UpdateBudgetWithSentData(DataSize size) {
|
||||
media_debt_ += size;
|
||||
media_debt_ = std::min(media_debt_, media_rate_ * kMaxDebtInTime);
|
||||
media_debt_ = std::min(media_debt_, adjusted_media_rate_ * kMaxDebtInTime);
|
||||
UpdatePaddingBudgetWithSentData(size);
|
||||
}
|
||||
|
||||
@ -675,4 +662,28 @@ void PacingController::SetQueueTimeLimit(TimeDelta limit) {
|
||||
queue_time_limit_ = limit;
|
||||
}
|
||||
|
||||
void PacingController::MaybeUpdateMediaRateDueToLongQueue(Timestamp now) {
|
||||
adjusted_media_rate_ = pacing_rate_;
|
||||
if (!drain_large_queues_) {
|
||||
return;
|
||||
}
|
||||
|
||||
DataSize queue_size_data = QueueSizeData();
|
||||
if (queue_size_data > DataSize::Zero()) {
|
||||
// Assuming equal size packets and input/output rate, the average packet
|
||||
// has avg_time_left_ms left to get queue_size_bytes out of the queue, if
|
||||
// time constraint shall be met. Determine bitrate needed for that.
|
||||
packet_queue_->UpdateAverageQueueTime(now);
|
||||
TimeDelta avg_time_left =
|
||||
std::max(TimeDelta::Millis(1),
|
||||
queue_time_limit_ - packet_queue_->AverageQueueTime());
|
||||
DataRate min_rate_needed = queue_size_data / avg_time_left;
|
||||
if (min_rate_needed > pacing_rate_) {
|
||||
adjusted_media_rate_ = min_rate_needed;
|
||||
RTC_LOG(LS_VERBOSE) << "bwe:large_pacing_queue pacing_rate_kbps="
|
||||
<< pacing_rate_.kbps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
Reference in New Issue
Block a user