Per default set PacingController burst interval to 40ms
PacingController per default use a burst interval of 40ms. The behaviour can still be overriden by using the method SetSendBurstInterval. Bug: chromium:1354491 Change-Id: Ie3513109e88e9832dff47380c482ed6d943a2f2b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/311102 Reviewed-by: Henrik Boström <hbos@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Per Kjellander <perkj@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41254}
This commit is contained in:
parent
9d9d03b3f9
commit
b202bc1db2
@ -688,6 +688,7 @@ class RTC_EXPORT PeerConnectionInterface : public webrtc::RefCountInterface {
|
|||||||
PortAllocatorConfig port_allocator_config;
|
PortAllocatorConfig port_allocator_config;
|
||||||
|
|
||||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
||||||
|
// TODO(hbos): Deprecated, Remove once Chromium is not setting it.
|
||||||
absl::optional<TimeDelta> pacer_burst_interval;
|
absl::optional<TimeDelta> pacer_burst_interval;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
@ -453,7 +453,7 @@ class Call final : public webrtc::Call,
|
|||||||
bool is_started_ RTC_GUARDED_BY(worker_thread_) = false;
|
bool is_started_ RTC_GUARDED_BY(worker_thread_) = false;
|
||||||
|
|
||||||
// Sequence checker for outgoing network traffic. Could be the network thread.
|
// Sequence checker for outgoing network traffic. Could be the network thread.
|
||||||
// Could also be a pacer owned thread or TQ such as the TaskQueuePacedSender.
|
// Could also be a pacer owned thread or TQ such as the TaskQueueSender.
|
||||||
RTC_NO_UNIQUE_ADDRESS SequenceChecker sent_packet_sequence_checker_;
|
RTC_NO_UNIQUE_ADDRESS SequenceChecker sent_packet_sequence_checker_;
|
||||||
absl::optional<rtc::SentPacket> last_sent_packet_
|
absl::optional<rtc::SentPacket> last_sent_packet_
|
||||||
RTC_GUARDED_BY(sent_packet_sequence_checker_);
|
RTC_GUARDED_BY(sent_packet_sequence_checker_);
|
||||||
|
|||||||
@ -31,7 +31,6 @@ RtpTransportConfig CallConfig::ExtractTransportConfig() const {
|
|||||||
network_state_predictor_factory;
|
network_state_predictor_factory;
|
||||||
transportConfig.task_queue_factory = task_queue_factory;
|
transportConfig.task_queue_factory = task_queue_factory;
|
||||||
transportConfig.trials = trials;
|
transportConfig.trials = trials;
|
||||||
transportConfig.pacer_burst_interval = pacer_burst_interval;
|
|
||||||
|
|
||||||
return transportConfig;
|
return transportConfig;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,9 +79,6 @@ struct CallConfig {
|
|||||||
|
|
||||||
Metronome* metronome = nullptr;
|
Metronome* metronome = nullptr;
|
||||||
|
|
||||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
|
||||||
absl::optional<TimeDelta> pacer_burst_interval;
|
|
||||||
|
|
||||||
// Enables send packet batching from the egress RTP sender.
|
// Enables send packet batching from the egress RTP sender.
|
||||||
bool enable_send_packet_batching = false;
|
bool enable_send_packet_batching = false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -44,9 +44,6 @@ struct RtpTransportConfig {
|
|||||||
// Key-value mapping of internal configurations to apply,
|
// Key-value mapping of internal configurations to apply,
|
||||||
// e.g. field trials.
|
// e.g. field trials.
|
||||||
const FieldTrialsView* trials = nullptr;
|
const FieldTrialsView* trials = nullptr;
|
||||||
|
|
||||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
|
||||||
absl::optional<TimeDelta> pacer_burst_interval;
|
|
||||||
};
|
};
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
|
||||||
|
|||||||
@ -80,12 +80,7 @@ RtpTransportControllerSend::RtpTransportControllerSend(
|
|||||||
task_queue_(TaskQueueBase::Current()),
|
task_queue_(TaskQueueBase::Current()),
|
||||||
bitrate_configurator_(config.bitrate_config),
|
bitrate_configurator_(config.bitrate_config),
|
||||||
pacer_started_(false),
|
pacer_started_(false),
|
||||||
pacer_(clock,
|
pacer_(clock, &packet_router_, *config.trials, TimeDelta::Millis(5), 3),
|
||||||
&packet_router_,
|
|
||||||
*config.trials,
|
|
||||||
TimeDelta::Millis(5),
|
|
||||||
3,
|
|
||||||
config.pacer_burst_interval),
|
|
||||||
observer_(nullptr),
|
observer_(nullptr),
|
||||||
controller_factory_override_(config.network_controller_factory),
|
controller_factory_override_(config.network_controller_factory),
|
||||||
controller_factory_fallback_(
|
controller_factory_fallback_(
|
||||||
|
|||||||
@ -1092,7 +1092,7 @@ TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) {
|
|||||||
|
|
||||||
// Set a very low bitrate.
|
// Set a very low bitrate.
|
||||||
test.router()->OnBitrateUpdated(
|
test.router()->OnBitrateUpdated(
|
||||||
CreateBitrateAllocationUpdate(/*rate_bps=*/30'000),
|
CreateBitrateAllocationUpdate(/*rate_bps=*/10'000),
|
||||||
/*framerate=*/30);
|
/*framerate=*/30);
|
||||||
|
|
||||||
// Create and send a large keyframe.
|
// Create and send a large keyframe.
|
||||||
@ -1119,7 +1119,7 @@ TEST(RtpVideoSenderTest, ClearsPendingPacketsOnInactivation) {
|
|||||||
EXPECT_FALSE(packet.Marker());
|
EXPECT_FALSE(packet.Marker());
|
||||||
}
|
}
|
||||||
EXPECT_GT(transmittedPayload, DataSize::Zero());
|
EXPECT_GT(transmittedPayload, DataSize::Zero());
|
||||||
EXPECT_LT(transmittedPayload, DataSize::Bytes(kImageSizeBytes / 4));
|
EXPECT_LT(transmittedPayload, DataSize::Bytes(kImageSizeBytes / 3));
|
||||||
|
|
||||||
// Record the RTP timestamp of the first frame.
|
// Record the RTP timestamp of the first frame.
|
||||||
const uint32_t first_frame_timestamp = sent_packets[0].Timestamp();
|
const uint32_t first_frame_timestamp = sent_packets[0].Timestamp();
|
||||||
|
|||||||
@ -73,7 +73,7 @@ PacingController::PacingController(Clock* clock,
|
|||||||
keyframe_flushing_(
|
keyframe_flushing_(
|
||||||
IsEnabled(field_trials_, "WebRTC-Pacer-KeyframeFlushing")),
|
IsEnabled(field_trials_, "WebRTC-Pacer-KeyframeFlushing")),
|
||||||
transport_overhead_per_packet_(DataSize::Zero()),
|
transport_overhead_per_packet_(DataSize::Zero()),
|
||||||
send_burst_interval_(TimeDelta::Zero()),
|
send_burst_interval_(kDefaultBurstInterval),
|
||||||
last_timestamp_(clock_->CurrentTime()),
|
last_timestamp_(clock_->CurrentTime()),
|
||||||
paused_(false),
|
paused_(false),
|
||||||
media_debt_(DataSize::Zero()),
|
media_debt_(DataSize::Zero()),
|
||||||
|
|||||||
@ -25,6 +25,7 @@
|
|||||||
#include "api/transport/field_trial_based_config.h"
|
#include "api/transport/field_trial_based_config.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "api/units/data_size.h"
|
#include "api/units/data_size.h"
|
||||||
|
#include "api/units/time_delta.h"
|
||||||
#include "modules/pacing/bitrate_prober.h"
|
#include "modules/pacing/bitrate_prober.h"
|
||||||
#include "modules/pacing/interval_budget.h"
|
#include "modules/pacing/interval_budget.h"
|
||||||
#include "modules/pacing/prioritized_packet_queue.h"
|
#include "modules/pacing/prioritized_packet_queue.h"
|
||||||
@ -92,6 +93,10 @@ class PacingController {
|
|||||||
// the send burst interval.
|
// the send burst interval.
|
||||||
// Ex: max send burst interval = 63Kb / 10Mbit/s = 50ms.
|
// Ex: max send burst interval = 63Kb / 10Mbit/s = 50ms.
|
||||||
static constexpr DataSize kMaxBurstSize = DataSize::Bytes(63 * 1000);
|
static constexpr DataSize kMaxBurstSize = DataSize::Bytes(63 * 1000);
|
||||||
|
// The pacer is allowed to send enqued packets in bursts and can build up a
|
||||||
|
// packet "debt" that correspond to approximately the send rate during
|
||||||
|
// the burst interval.
|
||||||
|
static constexpr TimeDelta kDefaultBurstInterval = TimeDelta::Millis(40);
|
||||||
|
|
||||||
PacingController(Clock* clock,
|
PacingController(Clock* clock,
|
||||||
PacketSender* packet_sender,
|
PacketSender* packet_sender,
|
||||||
|
|||||||
@ -427,6 +427,7 @@ TEST_F(PacingControllerTest, BudgetAffectsAudioInTrial) {
|
|||||||
DataRate pacing_rate =
|
DataRate pacing_rate =
|
||||||
DataRate::BitsPerSec(kPacketSize / 3 * 8 * kProcessIntervalsPerSecond);
|
DataRate::BitsPerSec(kPacketSize / 3 * 8 * kProcessIntervalsPerSecond);
|
||||||
pacer.SetPacingRates(pacing_rate, DataRate::Zero());
|
pacer.SetPacingRates(pacing_rate, DataRate::Zero());
|
||||||
|
pacer.SetSendBurstInterval(TimeDelta::Zero());
|
||||||
// Video fills budget for following process periods.
|
// Video fills budget for following process periods.
|
||||||
pacer.EnqueuePacket(video_.BuildNextPacket(kPacketSize));
|
pacer.EnqueuePacket(video_.BuildNextPacket(kPacketSize));
|
||||||
EXPECT_CALL(callback_, SendPacket).Times(1);
|
EXPECT_CALL(callback_, SendPacket).Times(1);
|
||||||
@ -484,7 +485,7 @@ TEST_F(PacingControllerTest, FirstSentPacketTimeIsSet) {
|
|||||||
EXPECT_EQ(kStartTime, pacer->FirstSentPacketTime());
|
EXPECT_EQ(kStartTime, pacer->FirstSentPacketTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PacingControllerTest, QueueAndPacePackets) {
|
TEST_F(PacingControllerTest, QueueAndPacePacketsWithZeroBurstPeriod) {
|
||||||
const uint32_t kSsrc = 12345;
|
const uint32_t kSsrc = 12345;
|
||||||
uint16_t sequence_number = 1234;
|
uint16_t sequence_number = 1234;
|
||||||
const DataSize kPackeSize = DataSize::Bytes(250);
|
const DataSize kPackeSize = DataSize::Bytes(250);
|
||||||
@ -495,6 +496,7 @@ TEST_F(PacingControllerTest, QueueAndPacePackets) {
|
|||||||
const size_t kPacketsToSend = (kSendInterval * kTargetRate).bytes() *
|
const size_t kPacketsToSend = (kSendInterval * kTargetRate).bytes() *
|
||||||
kPaceMultiplier / kPackeSize.bytes();
|
kPaceMultiplier / kPackeSize.bytes();
|
||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
|
pacer->SetSendBurstInterval(TimeDelta::Zero());
|
||||||
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
||||||
|
|
||||||
for (size_t i = 0; i < kPacketsToSend; ++i) {
|
for (size_t i = 0; i < kPacketsToSend; ++i) {
|
||||||
@ -536,30 +538,30 @@ TEST_F(PacingControllerTest, PaceQueuedPackets) {
|
|||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
||||||
|
|
||||||
// Due to the multiplicative factor we can send 5 packets during a send
|
const size_t packets_to_send_per_burst_interval =
|
||||||
// interval. (network capacity * multiplier / (8 bits per byte *
|
(kTargetRate * kPaceMultiplier * PacingController::kDefaultBurstInterval)
|
||||||
// (packet size * #send intervals per second)
|
.bytes() /
|
||||||
const size_t packets_to_send_per_interval =
|
kPacketSize;
|
||||||
kTargetRate.bps() * kPaceMultiplier / (8 * kPacketSize * 200);
|
for (size_t i = 0; i < packets_to_send_per_burst_interval; ++i) {
|
||||||
for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
|
|
||||||
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++, clock_.TimeInMilliseconds(),
|
sequence_number++, clock_.TimeInMilliseconds(),
|
||||||
kPacketSize);
|
kPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t j = 0; j < packets_to_send_per_interval * 10; ++j) {
|
for (size_t j = 0; j < packets_to_send_per_burst_interval * 10; ++j) {
|
||||||
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kVideo, ssrc,
|
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++,
|
sequence_number++,
|
||||||
clock_.TimeInMilliseconds(), kPacketSize));
|
clock_.TimeInMilliseconds(), kPacketSize));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(packets_to_send_per_interval + packets_to_send_per_interval * 10,
|
EXPECT_EQ(packets_to_send_per_burst_interval +
|
||||||
|
packets_to_send_per_burst_interval * 10,
|
||||||
pacer->QueueSizePackets());
|
pacer->QueueSizePackets());
|
||||||
|
|
||||||
while (pacer->QueueSizePackets() > packets_to_send_per_interval * 10) {
|
while (pacer->QueueSizePackets() > packets_to_send_per_burst_interval * 10) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
EXPECT_EQ(pacer->QueueSizePackets(), packets_to_send_per_interval * 10);
|
EXPECT_EQ(pacer->QueueSizePackets(), packets_to_send_per_burst_interval * 10);
|
||||||
EXPECT_CALL(callback_, SendPadding).Times(0);
|
EXPECT_CALL(callback_, SendPadding).Times(0);
|
||||||
|
|
||||||
EXPECT_CALL(callback_, SendPacket(ssrc, _, _, false, false))
|
EXPECT_CALL(callback_, SendPacket(ssrc, _, _, false, false))
|
||||||
@ -582,12 +584,12 @@ TEST_F(PacingControllerTest, PaceQueuedPackets) {
|
|||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
|
|
||||||
// Send some more packet, just show that we can..?
|
// Send some more packet, just show that we can..?
|
||||||
for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
|
for (size_t i = 0; i < packets_to_send_per_burst_interval; ++i) {
|
||||||
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++, clock_.TimeInMilliseconds(), 250);
|
sequence_number++, clock_.TimeInMilliseconds(), 250);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(packets_to_send_per_interval, pacer->QueueSizePackets());
|
EXPECT_EQ(packets_to_send_per_burst_interval, pacer->QueueSizePackets());
|
||||||
for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
|
for (size_t i = 0; i < packets_to_send_per_burst_interval; ++i) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
@ -641,19 +643,23 @@ TEST_F(PacingControllerTest,
|
|||||||
TEST_F(PacingControllerTest, Padding) {
|
TEST_F(PacingControllerTest, Padding) {
|
||||||
uint32_t ssrc = 12345;
|
uint32_t ssrc = 12345;
|
||||||
uint16_t sequence_number = 1234;
|
uint16_t sequence_number = 1234;
|
||||||
const size_t kPacketSize = 250;
|
const size_t kPacketSize = 1000;
|
||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, kTargetRate);
|
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, kTargetRate);
|
||||||
|
|
||||||
const size_t kPacketsToSend = 20;
|
const size_t kPacketsToSend = 30;
|
||||||
for (size_t i = 0; i < kPacketsToSend; ++i) {
|
for (size_t i = 0; i < kPacketsToSend; ++i) {
|
||||||
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++, clock_.TimeInMilliseconds(),
|
sequence_number++, clock_.TimeInMilliseconds(),
|
||||||
kPacketSize);
|
kPacketSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int expected_bursts =
|
||||||
|
floor(DataSize::Bytes(pacer->QueueSizePackets() * kPacketSize) /
|
||||||
|
(kPaceMultiplier * kTargetRate) /
|
||||||
|
PacingController::kDefaultBurstInterval);
|
||||||
const TimeDelta expected_pace_time =
|
const TimeDelta expected_pace_time =
|
||||||
DataSize::Bytes(pacer->QueueSizePackets() * kPacketSize) /
|
(expected_bursts - 1) * PacingController::kDefaultBurstInterval;
|
||||||
(kPaceMultiplier * kTargetRate);
|
|
||||||
EXPECT_CALL(callback_, SendPadding).Times(0);
|
EXPECT_CALL(callback_, SendPadding).Times(0);
|
||||||
// Only the media packets should be sent.
|
// Only the media packets should be sent.
|
||||||
Timestamp start_time = clock_.CurrentTime();
|
Timestamp start_time = clock_.CurrentTime();
|
||||||
@ -663,7 +669,7 @@ TEST_F(PacingControllerTest, Padding) {
|
|||||||
}
|
}
|
||||||
const TimeDelta actual_pace_time = clock_.CurrentTime() - start_time;
|
const TimeDelta actual_pace_time = clock_.CurrentTime() - start_time;
|
||||||
EXPECT_LE((actual_pace_time - expected_pace_time).Abs(),
|
EXPECT_LE((actual_pace_time - expected_pace_time).Abs(),
|
||||||
PacingController::kMinSleepTime);
|
PacingController::kDefaultBurstInterval);
|
||||||
|
|
||||||
// Pacing media happens at 2.5x, but padding was configured with 1.0x
|
// Pacing media happens at 2.5x, but padding was configured with 1.0x
|
||||||
// factor. We have to wait until the padding debt is gone before we start
|
// factor. We have to wait until the padding debt is gone before we start
|
||||||
@ -766,8 +772,8 @@ TEST_F(PacingControllerTest, VerifyAverageBitrateVaryingMediaPayload) {
|
|||||||
media_payload));
|
media_payload));
|
||||||
media_bytes += media_payload;
|
media_bytes += media_payload;
|
||||||
}
|
}
|
||||||
|
AdvanceTimeUntil(std::min(clock_.CurrentTime() + TimeDelta::Millis(20),
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
pacer->NextSendTime()));
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -805,20 +811,18 @@ TEST_F(PacingControllerTest, Priority) {
|
|||||||
|
|
||||||
// Expect all high and normal priority to be sent out first.
|
// Expect all high and normal priority to be sent out first.
|
||||||
EXPECT_CALL(callback_, SendPadding).Times(0);
|
EXPECT_CALL(callback_, SendPadding).Times(0);
|
||||||
|
testing::Sequence s;
|
||||||
EXPECT_CALL(callback_, SendPacket(ssrc, _, capture_time_ms, _, _))
|
EXPECT_CALL(callback_, SendPacket(ssrc, _, capture_time_ms, _, _))
|
||||||
.Times(packets_to_send_per_interval + 1);
|
.Times(packets_to_send_per_interval + 1)
|
||||||
|
.InSequence(s);
|
||||||
|
EXPECT_CALL(callback_, SendPacket(ssrc_low_priority, _,
|
||||||
|
capture_time_ms_low_priority, _, _))
|
||||||
|
.InSequence(s);
|
||||||
|
|
||||||
while (pacer->QueueSizePackets() > 1) {
|
while (pacer->QueueSizePackets() > 0) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_EQ(1u, pacer->QueueSizePackets());
|
|
||||||
|
|
||||||
EXPECT_CALL(callback_, SendPacket(ssrc_low_priority, _,
|
|
||||||
capture_time_ms_low_priority, _, _));
|
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
|
||||||
pacer->ProcessPackets();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PacingControllerTest, RetransmissionPriority) {
|
TEST_F(PacingControllerTest, RetransmissionPriority) {
|
||||||
@ -829,23 +833,22 @@ TEST_F(PacingControllerTest, RetransmissionPriority) {
|
|||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
||||||
|
|
||||||
// Due to the multiplicative factor we can send 5 packets during a send
|
const size_t packets_to_send_per_burst_interval =
|
||||||
// interval. (network capacity * multiplier / (8 bits per byte *
|
(kTargetRate * kPaceMultiplier * PacingController::kDefaultBurstInterval)
|
||||||
// (packet size * #send intervals per second)
|
.bytes() /
|
||||||
const size_t packets_to_send_per_interval =
|
250;
|
||||||
kTargetRate.bps() * kPaceMultiplier / (8 * 250 * 200);
|
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
EXPECT_EQ(0u, pacer->QueueSizePackets());
|
EXPECT_EQ(0u, pacer->QueueSizePackets());
|
||||||
|
|
||||||
// Alternate retransmissions and normal packets.
|
// Alternate retransmissions and normal packets.
|
||||||
for (size_t i = 0; i < packets_to_send_per_interval; ++i) {
|
for (size_t i = 0; i < packets_to_send_per_burst_interval; ++i) {
|
||||||
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kVideo, ssrc,
|
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++, capture_time_ms, 250));
|
sequence_number++, capture_time_ms, 250));
|
||||||
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kRetransmission, ssrc,
|
pacer->EnqueuePacket(BuildPacket(RtpPacketMediaType::kRetransmission, ssrc,
|
||||||
sequence_number++,
|
sequence_number++,
|
||||||
capture_time_ms_retransmission, 250));
|
capture_time_ms_retransmission, 250));
|
||||||
}
|
}
|
||||||
EXPECT_EQ(2 * packets_to_send_per_interval, pacer->QueueSizePackets());
|
EXPECT_EQ(2 * packets_to_send_per_burst_interval, pacer->QueueSizePackets());
|
||||||
|
|
||||||
// Expect all retransmissions to be sent out first despite having a later
|
// Expect all retransmissions to be sent out first despite having a later
|
||||||
// capture time.
|
// capture time.
|
||||||
@ -853,19 +856,19 @@ TEST_F(PacingControllerTest, RetransmissionPriority) {
|
|||||||
EXPECT_CALL(callback_, SendPacket(_, _, _, false, _)).Times(0);
|
EXPECT_CALL(callback_, SendPacket(_, _, _, false, _)).Times(0);
|
||||||
EXPECT_CALL(callback_,
|
EXPECT_CALL(callback_,
|
||||||
SendPacket(ssrc, _, capture_time_ms_retransmission, true, _))
|
SendPacket(ssrc, _, capture_time_ms_retransmission, true, _))
|
||||||
.Times(packets_to_send_per_interval);
|
.Times(packets_to_send_per_burst_interval);
|
||||||
|
|
||||||
while (pacer->QueueSizePackets() > packets_to_send_per_interval) {
|
while (pacer->QueueSizePackets() > packets_to_send_per_burst_interval) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
EXPECT_EQ(packets_to_send_per_interval, pacer->QueueSizePackets());
|
EXPECT_EQ(packets_to_send_per_burst_interval, pacer->QueueSizePackets());
|
||||||
|
|
||||||
// Expect the remaining (non-retransmission) packets to be sent.
|
// Expect the remaining (non-retransmission) packets to be sent.
|
||||||
EXPECT_CALL(callback_, SendPadding).Times(0);
|
EXPECT_CALL(callback_, SendPadding).Times(0);
|
||||||
EXPECT_CALL(callback_, SendPacket(_, _, _, true, _)).Times(0);
|
EXPECT_CALL(callback_, SendPacket(_, _, _, true, _)).Times(0);
|
||||||
EXPECT_CALL(callback_, SendPacket(ssrc, _, capture_time_ms, false, _))
|
EXPECT_CALL(callback_, SendPacket(ssrc, _, capture_time_ms, false, _))
|
||||||
.Times(packets_to_send_per_interval);
|
.Times(packets_to_send_per_burst_interval);
|
||||||
|
|
||||||
while (pacer->QueueSizePackets() > 0) {
|
while (pacer->QueueSizePackets() > 0) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
@ -890,13 +893,13 @@ TEST_F(PacingControllerTest, HighPrioDoesntAffectBudget) {
|
|||||||
sequence_number++, capture_time_ms, kPacketSize);
|
sequence_number++, capture_time_ms, kPacketSize);
|
||||||
}
|
}
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
|
EXPECT_EQ(pacer->QueueSizePackets(), 0u);
|
||||||
// Low prio packets does affect the budget.
|
// Low prio packets does affect the budget.
|
||||||
// Due to the multiplicative factor we can send 5 packets during a send
|
const size_t kPacketsToSendPerBurstInterval =
|
||||||
// interval. (network capacity * multiplier / (8 bits per byte *
|
(kTargetRate * kPaceMultiplier * PacingController::kDefaultBurstInterval)
|
||||||
// (packet size * #send intervals per second)
|
.bytes() /
|
||||||
const size_t kPacketsToSendPerInterval =
|
kPacketSize;
|
||||||
kTargetRate.bps() * kPaceMultiplier / (8 * kPacketSize * 200);
|
for (size_t i = 0; i < kPacketsToSendPerBurstInterval; ++i) {
|
||||||
for (size_t i = 0; i < kPacketsToSendPerInterval; ++i) {
|
|
||||||
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, ssrc,
|
||||||
sequence_number++, clock_.TimeInMilliseconds(),
|
sequence_number++, clock_.TimeInMilliseconds(),
|
||||||
kPacketSize);
|
kPacketSize);
|
||||||
@ -904,16 +907,16 @@ TEST_F(PacingControllerTest, HighPrioDoesntAffectBudget) {
|
|||||||
|
|
||||||
// Send all packets and measure pace time.
|
// Send all packets and measure pace time.
|
||||||
Timestamp start_time = clock_.CurrentTime();
|
Timestamp start_time = clock_.CurrentTime();
|
||||||
|
EXPECT_EQ(pacer->NextSendTime(), clock_.CurrentTime());
|
||||||
while (pacer->QueueSizePackets() > 0) {
|
while (pacer->QueueSizePackets() > 0) {
|
||||||
AdvanceTimeUntil(pacer->NextSendTime());
|
AdvanceTimeUntil(pacer->NextSendTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Measure pacing time. Expect only low-prio packets to affect this.
|
// Measure pacing time.
|
||||||
TimeDelta pacing_time = clock_.CurrentTime() - start_time;
|
TimeDelta pacing_time = clock_.CurrentTime() - start_time;
|
||||||
TimeDelta expected_pacing_time =
|
// All packets sent in one burst since audio packets are not accounted for.
|
||||||
DataSize::Bytes(kPacketsToSendPerInterval * kPacketSize) /
|
TimeDelta expected_pacing_time = TimeDelta::Zero();
|
||||||
(kTargetRate * kPaceMultiplier);
|
|
||||||
EXPECT_NEAR(pacing_time.us<double>(), expected_pacing_time.us<double>(),
|
EXPECT_NEAR(pacing_time.us<double>(), expected_pacing_time.us<double>(),
|
||||||
PacingController::kMinSleepTime.us<double>());
|
PacingController::kMinSleepTime.us<double>());
|
||||||
}
|
}
|
||||||
@ -965,6 +968,7 @@ TEST_F(PacingControllerTest, DoesNotAllowOveruseAfterCongestion) {
|
|||||||
auto now_ms = [this] { return clock_.TimeInMilliseconds(); };
|
auto now_ms = [this] { return clock_.TimeInMilliseconds(); };
|
||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
pacer->SetPacingRates(kTargetRate * kPaceMultiplier, DataRate::Zero());
|
||||||
|
pacer->SetSendBurstInterval(TimeDelta::Zero());
|
||||||
EXPECT_CALL(callback_, SendPadding).Times(0);
|
EXPECT_CALL(callback_, SendPadding).Times(0);
|
||||||
// The pacing rate is low enough that the budget should not allow two packets
|
// The pacing rate is low enough that the budget should not allow two packets
|
||||||
// to be sent in a row.
|
// to be sent in a row.
|
||||||
@ -1853,6 +1857,7 @@ TEST_F(PacingControllerTest, AccountsForAudioEnqueueTime) {
|
|||||||
// Audio not paced, but still accounted for in budget.
|
// Audio not paced, but still accounted for in budget.
|
||||||
pacer->SetAccountForAudioPackets(true);
|
pacer->SetAccountForAudioPackets(true);
|
||||||
pacer->SetPacingRates(kPacingDataRate, kPaddingDataRate);
|
pacer->SetPacingRates(kPacingDataRate, kPaddingDataRate);
|
||||||
|
pacer->SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Enqueue two audio packets, advance clock to where one packet
|
// Enqueue two audio packets, advance clock to where one packet
|
||||||
// should have drained the buffer already, has they been sent
|
// should have drained the buffer already, has they been sent
|
||||||
@ -1898,13 +1903,12 @@ TEST_F(PacingControllerTest, NextSendTimeAccountsForPadding) {
|
|||||||
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(),
|
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(),
|
||||||
PacingController::kPausedProcessInterval);
|
PacingController::kPausedProcessInterval);
|
||||||
|
|
||||||
// Enqueue a new packet, that can't be sent until previous buffer has
|
// Enqueue a new packet, that can be sent immediately due to default burst
|
||||||
// drained.
|
// rate is 40ms.
|
||||||
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, kSsrc,
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, kSsrc,
|
||||||
sequnce_number++, clock_.TimeInMilliseconds(),
|
sequnce_number++, clock_.TimeInMilliseconds(),
|
||||||
kPacketSize.bytes());
|
kPacketSize.bytes());
|
||||||
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(), kPacketPacingTime);
|
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(), TimeDelta::Zero());
|
||||||
clock_.AdvanceTime(kPacketPacingTime);
|
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
::testing::Mock::VerifyAndClearExpectations(&callback_);
|
::testing::Mock::VerifyAndClearExpectations(&callback_);
|
||||||
|
|
||||||
@ -1916,11 +1920,13 @@ TEST_F(PacingControllerTest, NextSendTimeAccountsForPadding) {
|
|||||||
// previous debt has cleared. Since padding was disabled before, there
|
// previous debt has cleared. Since padding was disabled before, there
|
||||||
// currently is no padding debt.
|
// currently is no padding debt.
|
||||||
pacer->SetPacingRates(kPacingDataRate, kPacingDataRate / 2);
|
pacer->SetPacingRates(kPacingDataRate, kPacingDataRate / 2);
|
||||||
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(), kPacketPacingTime);
|
EXPECT_EQ(pacer->QueueSizePackets(), 0u);
|
||||||
|
EXPECT_LT(pacer->NextSendTime() - clock_.CurrentTime(),
|
||||||
|
PacingController::kDefaultBurstInterval);
|
||||||
|
|
||||||
// Advance time, expect padding.
|
// Advance time, expect padding.
|
||||||
EXPECT_CALL(callback_, SendPadding).WillOnce(Return(kPacketSize.bytes()));
|
EXPECT_CALL(callback_, SendPadding).WillOnce(Return(kPacketSize.bytes()));
|
||||||
clock_.AdvanceTime(kPacketPacingTime);
|
clock_.AdvanceTime(pacer->NextSendTime() - clock_.CurrentTime());
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
::testing::Mock::VerifyAndClearExpectations(&callback_);
|
::testing::Mock::VerifyAndClearExpectations(&callback_);
|
||||||
|
|
||||||
@ -1933,7 +1939,7 @@ TEST_F(PacingControllerTest, NextSendTimeAccountsForPadding) {
|
|||||||
pacer->EnqueuePacket(
|
pacer->EnqueuePacket(
|
||||||
BuildPacket(RtpPacketMediaType::kVideo, kSsrc, sequnce_number++,
|
BuildPacket(RtpPacketMediaType::kVideo, kSsrc, sequnce_number++,
|
||||||
clock_.TimeInMilliseconds(), kPacketSize.bytes()));
|
clock_.TimeInMilliseconds(), kPacketSize.bytes()));
|
||||||
EXPECT_EQ(pacer->NextSendTime() - clock_.CurrentTime(), kPacketPacingTime);
|
EXPECT_EQ(pacer->NextSendTime(), clock_.CurrentTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(PacingControllerTest, PaddingTargetAccountsForPaddingRate) {
|
TEST_F(PacingControllerTest, PaddingTargetAccountsForPaddingRate) {
|
||||||
@ -2011,8 +2017,8 @@ TEST_F(PacingControllerTest, SendsFecPackets) {
|
|||||||
TEST_F(PacingControllerTest, GapInPacingDoesntAccumulateBudget) {
|
TEST_F(PacingControllerTest, GapInPacingDoesntAccumulateBudget) {
|
||||||
const uint32_t kSsrc = 12345;
|
const uint32_t kSsrc = 12345;
|
||||||
uint16_t sequence_number = 1234;
|
uint16_t sequence_number = 1234;
|
||||||
const DataSize kPackeSize = DataSize::Bytes(250);
|
const DataSize kPackeSize = DataSize::Bytes(1000);
|
||||||
const TimeDelta kPacketSendTime = TimeDelta::Millis(15);
|
const TimeDelta kPacketSendTime = TimeDelta::Millis(25);
|
||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
|
|
||||||
pacer->SetPacingRates(kPackeSize / kPacketSendTime,
|
pacer->SetPacingRates(kPackeSize / kPacketSendTime,
|
||||||
@ -2028,15 +2034,20 @@ TEST_F(PacingControllerTest, GapInPacingDoesntAccumulateBudget) {
|
|||||||
// Advance time kPacketSendTime past where the media debt should be 0.
|
// Advance time kPacketSendTime past where the media debt should be 0.
|
||||||
clock_.AdvanceTime(2 * kPacketSendTime);
|
clock_.AdvanceTime(2 * kPacketSendTime);
|
||||||
|
|
||||||
// Enqueue two new packets. Expect only one to be sent one ProcessPackets().
|
// Enqueue three new packets. Expect only two to be sent one ProcessPackets()
|
||||||
|
// since the default burst interval is 40ms.
|
||||||
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, kSsrc,
|
||||||
|
sequence_number++, clock_.TimeInMilliseconds(),
|
||||||
|
kPackeSize.bytes());
|
||||||
|
SendAndExpectPacket(pacer.get(), RtpPacketMediaType::kVideo, kSsrc,
|
||||||
|
sequence_number++, clock_.TimeInMilliseconds(),
|
||||||
|
kPackeSize.bytes());
|
||||||
|
EXPECT_CALL(callback_, SendPacket(kSsrc, sequence_number + 1, _, _, _))
|
||||||
|
.Times(0);
|
||||||
pacer->EnqueuePacket(
|
pacer->EnqueuePacket(
|
||||||
BuildPacket(RtpPacketMediaType::kVideo, kSsrc, sequence_number + 1,
|
BuildPacket(RtpPacketMediaType::kVideo, kSsrc, sequence_number + 1,
|
||||||
clock_.TimeInMilliseconds(), kPackeSize.bytes()));
|
clock_.TimeInMilliseconds(), kPackeSize.bytes()));
|
||||||
pacer->EnqueuePacket(
|
|
||||||
BuildPacket(RtpPacketMediaType::kVideo, kSsrc, sequence_number + 2,
|
|
||||||
clock_.TimeInMilliseconds(), kPackeSize.bytes()));
|
|
||||||
EXPECT_CALL(callback_, SendPacket(kSsrc, sequence_number + 1,
|
|
||||||
clock_.TimeInMilliseconds(), false, false));
|
|
||||||
pacer->ProcessPackets();
|
pacer->ProcessPackets();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2044,6 +2055,7 @@ TEST_F(PacingControllerTest, HandlesSubMicrosecondSendIntervals) {
|
|||||||
static constexpr DataSize kPacketSize = DataSize::Bytes(1);
|
static constexpr DataSize kPacketSize = DataSize::Bytes(1);
|
||||||
static constexpr TimeDelta kPacketSendTime = TimeDelta::Micros(1);
|
static constexpr TimeDelta kPacketSendTime = TimeDelta::Micros(1);
|
||||||
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
auto pacer = std::make_unique<PacingController>(&clock_, &callback_, trials_);
|
||||||
|
pacer->SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Set pacing rate such that a packet is sent in 0.5us.
|
// Set pacing rate such that a packet is sent in 0.5us.
|
||||||
pacer->SetPacingRates(/*pacing_rate=*/2 * kPacketSize / kPacketSendTime,
|
pacer->SetPacingRates(/*pacing_rate=*/2 * kPacketSize / kPacketSendTime,
|
||||||
|
|||||||
@ -17,35 +17,19 @@
|
|||||||
#include "api/task_queue/pending_task_safety_flag.h"
|
#include "api/task_queue/pending_task_safety_flag.h"
|
||||||
#include "api/transport/network_types.h"
|
#include "api/transport/network_types.h"
|
||||||
#include "rtc_base/checks.h"
|
#include "rtc_base/checks.h"
|
||||||
#include "rtc_base/experiments/field_trial_parser.h"
|
|
||||||
#include "rtc_base/experiments/field_trial_units.h"
|
|
||||||
#include "rtc_base/trace_event.h"
|
#include "rtc_base/trace_event.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr const char* kBurstyPacerFieldTrial = "WebRTC-BurstyPacer";
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
const int TaskQueuePacedSender::kNoPacketHoldback = -1;
|
const int TaskQueuePacedSender::kNoPacketHoldback = -1;
|
||||||
|
|
||||||
TaskQueuePacedSender::BurstyPacerFlags::BurstyPacerFlags(
|
|
||||||
const FieldTrialsView& field_trials)
|
|
||||||
: burst("burst") {
|
|
||||||
ParseFieldTrial({&burst}, field_trials.Lookup(kBurstyPacerFieldTrial));
|
|
||||||
}
|
|
||||||
|
|
||||||
TaskQueuePacedSender::TaskQueuePacedSender(
|
TaskQueuePacedSender::TaskQueuePacedSender(
|
||||||
Clock* clock,
|
Clock* clock,
|
||||||
PacingController::PacketSender* packet_sender,
|
PacingController::PacketSender* packet_sender,
|
||||||
const FieldTrialsView& field_trials,
|
const FieldTrialsView& field_trials,
|
||||||
TimeDelta max_hold_back_window,
|
TimeDelta max_hold_back_window,
|
||||||
int max_hold_back_window_in_packets,
|
int max_hold_back_window_in_packets)
|
||||||
absl::optional<TimeDelta> burst_interval)
|
|
||||||
: clock_(clock),
|
: clock_(clock),
|
||||||
bursty_pacer_flags_(field_trials),
|
|
||||||
max_hold_back_window_(max_hold_back_window),
|
max_hold_back_window_(max_hold_back_window),
|
||||||
max_hold_back_window_in_packets_(max_hold_back_window_in_packets),
|
max_hold_back_window_in_packets_(max_hold_back_window_in_packets),
|
||||||
pacing_controller_(clock, packet_sender, field_trials),
|
pacing_controller_(clock, packet_sender, field_trials),
|
||||||
@ -56,17 +40,6 @@ TaskQueuePacedSender::TaskQueuePacedSender(
|
|||||||
include_overhead_(false),
|
include_overhead_(false),
|
||||||
task_queue_(TaskQueueBase::Current()) {
|
task_queue_(TaskQueueBase::Current()) {
|
||||||
RTC_DCHECK_GE(max_hold_back_window_, PacingController::kMinSleepTime);
|
RTC_DCHECK_GE(max_hold_back_window_, PacingController::kMinSleepTime);
|
||||||
// There are multiple field trials that can affect burst. If multiple bursts
|
|
||||||
// are specified we pick the largest of the values.
|
|
||||||
absl::optional<TimeDelta> burst = bursty_pacer_flags_.burst.GetOptional();
|
|
||||||
// If not overriden by an experiment, the burst is specified by the
|
|
||||||
// `burst_interval` argument.
|
|
||||||
if (!burst.has_value()) {
|
|
||||||
burst = burst_interval;
|
|
||||||
}
|
|
||||||
if (burst.has_value()) {
|
|
||||||
pacing_controller_.SetSendBurstInterval(burst.value());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskQueuePacedSender::~TaskQueuePacedSender() {
|
TaskQueuePacedSender::~TaskQueuePacedSender() {
|
||||||
@ -74,6 +47,11 @@ TaskQueuePacedSender::~TaskQueuePacedSender() {
|
|||||||
is_shutdown_ = true;
|
is_shutdown_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TaskQueuePacedSender::SetSendBurstInterval(TimeDelta burst_interval) {
|
||||||
|
RTC_DCHECK_RUN_ON(task_queue_);
|
||||||
|
pacing_controller_.SetSendBurstInterval(burst_interval);
|
||||||
|
}
|
||||||
|
|
||||||
void TaskQueuePacedSender::EnsureStarted() {
|
void TaskQueuePacedSender::EnsureStarted() {
|
||||||
RTC_DCHECK_RUN_ON(task_queue_);
|
RTC_DCHECK_RUN_ON(task_queue_);
|
||||||
is_started_ = true;
|
is_started_ = true;
|
||||||
|
|||||||
@ -45,23 +45,21 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender {
|
|||||||
// processed. Increasing this reduces thread wakeups at the expense of higher
|
// processed. Increasing this reduces thread wakeups at the expense of higher
|
||||||
// latency.
|
// latency.
|
||||||
//
|
//
|
||||||
// If the `burst_interval` parameter is set, the pacer is allowed to build up
|
|
||||||
// a packet "debt" that correspond to approximately the send rate during the
|
|
||||||
// specified interval. This greatly reduced wake ups by not pacing packets
|
|
||||||
// within the allowed burst budget.
|
|
||||||
//
|
|
||||||
// The taskqueue used when constructing a TaskQueuePacedSender will also be
|
// The taskqueue used when constructing a TaskQueuePacedSender will also be
|
||||||
// used for pacing.
|
// used for pacing.
|
||||||
TaskQueuePacedSender(
|
TaskQueuePacedSender(Clock* clock,
|
||||||
Clock* clock,
|
|
||||||
PacingController::PacketSender* packet_sender,
|
PacingController::PacketSender* packet_sender,
|
||||||
const FieldTrialsView& field_trials,
|
const FieldTrialsView& field_trials,
|
||||||
TimeDelta max_hold_back_window,
|
TimeDelta max_hold_back_window,
|
||||||
int max_hold_back_window_in_packets,
|
int max_hold_back_window_in_packets);
|
||||||
absl::optional<TimeDelta> burst_interval = absl::nullopt);
|
|
||||||
|
|
||||||
~TaskQueuePacedSender() override;
|
~TaskQueuePacedSender() override;
|
||||||
|
|
||||||
|
// The pacer is allowed to send enqued packets in bursts and can build up a
|
||||||
|
// packet "debt" that correspond to approximately the send rate during
|
||||||
|
// 'burst_interval'.
|
||||||
|
void SetSendBurstInterval(TimeDelta burst_interval);
|
||||||
|
|
||||||
// Ensure that necessary delayed tasks are scheduled.
|
// Ensure that necessary delayed tasks are scheduled.
|
||||||
void EnsureStarted();
|
void EnsureStarted();
|
||||||
|
|
||||||
@ -145,15 +143,6 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender {
|
|||||||
Stats GetStats() const;
|
Stats GetStats() const;
|
||||||
|
|
||||||
Clock* const clock_;
|
Clock* const clock_;
|
||||||
struct BurstyPacerFlags {
|
|
||||||
// Parses `kBurstyPacerFieldTrial`. Example:
|
|
||||||
// --force-fieldtrials=WebRTC-BurstyPacer/burst:20ms/
|
|
||||||
explicit BurstyPacerFlags(const FieldTrialsView& field_trials);
|
|
||||||
// If set, the pacer is allowed to build up a packet "debt" that correspond
|
|
||||||
// to approximately the send rate during the specified interval.
|
|
||||||
FieldTrialOptional<TimeDelta> burst;
|
|
||||||
};
|
|
||||||
const BurstyPacerFlags bursty_pacer_flags_;
|
|
||||||
|
|
||||||
// The holdback window prevents too frequent delayed MaybeProcessPackets()
|
// The holdback window prevents too frequent delayed MaybeProcessPackets()
|
||||||
// calls. These are only applicable if `allow_low_precision` is false.
|
// calls. These are only applicable if `allow_low_precision` is false.
|
||||||
|
|||||||
@ -11,6 +11,7 @@
|
|||||||
#include "modules/pacing/task_queue_paced_sender.h"
|
#include "modules/pacing/task_queue_paced_sender.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <any>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -24,6 +25,7 @@
|
|||||||
#include "api/units/data_rate.h"
|
#include "api/units/data_rate.h"
|
||||||
#include "api/units/data_size.h"
|
#include "api/units/data_size.h"
|
||||||
#include "api/units/time_delta.h"
|
#include "api/units/time_delta.h"
|
||||||
|
#include "modules/pacing/pacing_controller.h"
|
||||||
#include "modules/pacing/packet_router.h"
|
#include "modules/pacing/packet_router.h"
|
||||||
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
||||||
#include "test/gmock.h"
|
#include "test/gmock.h"
|
||||||
@ -33,6 +35,9 @@
|
|||||||
|
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::AtLeast;
|
using ::testing::AtLeast;
|
||||||
|
using ::testing::AtMost;
|
||||||
|
using ::testing::Lt;
|
||||||
|
using ::testing::NiceMock;
|
||||||
using ::testing::Return;
|
using ::testing::Return;
|
||||||
using ::testing::SaveArg;
|
using ::testing::SaveArg;
|
||||||
|
|
||||||
@ -167,7 +172,8 @@ TEST(TaskQueuePacedSenderTest, PacesPacketsWithBurst) {
|
|||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
PacingController::kMinSleepTime,
|
PacingController::kMinSleepTime,
|
||||||
TaskQueuePacedSender::kNoPacketHoldback,
|
TaskQueuePacedSender::kNoPacketHoldback);
|
||||||
|
pacer.SetSendBurstInterval(
|
||||||
// Half a second of bursting.
|
// Half a second of bursting.
|
||||||
TimeDelta::Seconds(0.5));
|
TimeDelta::Seconds(0.5));
|
||||||
|
|
||||||
@ -262,7 +268,7 @@ TEST(TaskQueuePacedSenderTest, ReschedulesProcessOnRateChange) {
|
|||||||
|
|
||||||
TEST(TaskQueuePacedSenderTest, SendsAudioImmediately) {
|
TEST(TaskQueuePacedSenderTest, SendsAudioImmediately) {
|
||||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||||
MockPacketRouter packet_router;
|
NiceMock<MockPacketRouter> packet_router;
|
||||||
ScopedKeyValueConfig trials;
|
ScopedKeyValueConfig trials;
|
||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
@ -270,21 +276,16 @@ TEST(TaskQueuePacedSenderTest, SendsAudioImmediately) {
|
|||||||
TaskQueuePacedSender::kNoPacketHoldback);
|
TaskQueuePacedSender::kNoPacketHoldback);
|
||||||
|
|
||||||
const DataRate kPacingDataRate = DataRate::KilobitsPerSec(125);
|
const DataRate kPacingDataRate = DataRate::KilobitsPerSec(125);
|
||||||
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
|
||||||
const TimeDelta kPacketPacingTime = kPacketSize / kPacingDataRate;
|
|
||||||
|
|
||||||
pacer.SetPacingRates(kPacingDataRate, DataRate::Zero());
|
pacer.SetPacingRates(kPacingDataRate, DataRate::Zero());
|
||||||
pacer.EnsureStarted();
|
pacer.EnsureStarted();
|
||||||
|
|
||||||
// Add some initial video packets, only one should be sent.
|
// Add some initial video packets. Not all should be sent immediately.
|
||||||
EXPECT_CALL(packet_router, SendPacket);
|
EXPECT_CALL(packet_router, SendPacket).Times(AtMost(9));
|
||||||
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kVideo, 10));
|
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kVideo, 10));
|
||||||
time_controller.AdvanceTime(TimeDelta::Zero());
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
||||||
::testing::Mock::VerifyAndClearExpectations(&packet_router);
|
::testing::Mock::VerifyAndClearExpectations(&packet_router);
|
||||||
|
|
||||||
// Advance time, but still before next packet should be sent.
|
|
||||||
time_controller.AdvanceTime(kPacketPacingTime / 2);
|
|
||||||
|
|
||||||
// Insert an audio packet, it should be sent immediately.
|
// Insert an audio packet, it should be sent immediately.
|
||||||
EXPECT_CALL(packet_router, SendPacket);
|
EXPECT_CALL(packet_router, SendPacket);
|
||||||
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kAudio, 1));
|
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kAudio, 1));
|
||||||
@ -295,12 +296,13 @@ TEST(TaskQueuePacedSenderTest, SendsAudioImmediately) {
|
|||||||
TEST(TaskQueuePacedSenderTest, SleepsDuringCoalscingWindow) {
|
TEST(TaskQueuePacedSenderTest, SleepsDuringCoalscingWindow) {
|
||||||
const TimeDelta kCoalescingWindow = TimeDelta::Millis(5);
|
const TimeDelta kCoalescingWindow = TimeDelta::Millis(5);
|
||||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||||
MockPacketRouter packet_router;
|
NiceMock<MockPacketRouter> packet_router;
|
||||||
ScopedKeyValueConfig trials;
|
ScopedKeyValueConfig trials;
|
||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
kCoalescingWindow,
|
kCoalescingWindow,
|
||||||
TaskQueuePacedSender::kNoPacketHoldback);
|
TaskQueuePacedSender::kNoPacketHoldback);
|
||||||
|
pacer.SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Set rates so one packet adds one ms of buffer level.
|
// Set rates so one packet adds one ms of buffer level.
|
||||||
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
||||||
@ -310,9 +312,9 @@ TEST(TaskQueuePacedSenderTest, SleepsDuringCoalscingWindow) {
|
|||||||
pacer.SetPacingRates(kPacingDataRate, DataRate::Zero());
|
pacer.SetPacingRates(kPacingDataRate, DataRate::Zero());
|
||||||
pacer.EnsureStarted();
|
pacer.EnsureStarted();
|
||||||
|
|
||||||
// Add 10 packets. The first should be sent immediately since the buffers
|
// Add 10 packets. The first burst should be sent immediately since the
|
||||||
// are clear.
|
// buffers are clear.
|
||||||
EXPECT_CALL(packet_router, SendPacket);
|
EXPECT_CALL(packet_router, SendPacket).Times(AtMost(9));
|
||||||
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kVideo, 10));
|
pacer.EnqueuePackets(GeneratePackets(RtpPacketMediaType::kVideo, 10));
|
||||||
time_controller.AdvanceTime(TimeDelta::Zero());
|
time_controller.AdvanceTime(TimeDelta::Zero());
|
||||||
::testing::Mock::VerifyAndClearExpectations(&packet_router);
|
::testing::Mock::VerifyAndClearExpectations(&packet_router);
|
||||||
@ -370,11 +372,12 @@ TEST(TaskQueuePacedSenderTest, SchedulesProbeAtSentTime) {
|
|||||||
ScopedKeyValueConfig trials(
|
ScopedKeyValueConfig trials(
|
||||||
"WebRTC-Bwe-ProbingBehavior/min_probe_delta:1ms/");
|
"WebRTC-Bwe-ProbingBehavior/min_probe_delta:1ms/");
|
||||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||||
MockPacketRouter packet_router;
|
NiceMock<MockPacketRouter> packet_router;
|
||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
PacingController::kMinSleepTime,
|
PacingController::kMinSleepTime,
|
||||||
TaskQueuePacedSender::kNoPacketHoldback);
|
TaskQueuePacedSender::kNoPacketHoldback);
|
||||||
|
pacer.SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Set rates so one packet adds 4ms of buffer level.
|
// Set rates so one packet adds 4ms of buffer level.
|
||||||
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
||||||
@ -504,11 +507,12 @@ TEST(TaskQueuePacedSenderTest, PacketBasedCoalescing) {
|
|||||||
const int kPacketBasedHoldback = 5;
|
const int kPacketBasedHoldback = 5;
|
||||||
|
|
||||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||||
MockPacketRouter packet_router;
|
NiceMock<MockPacketRouter> packet_router;
|
||||||
ScopedKeyValueConfig trials;
|
ScopedKeyValueConfig trials;
|
||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
kFixedCoalescingWindow, kPacketBasedHoldback);
|
kFixedCoalescingWindow, kPacketBasedHoldback);
|
||||||
|
pacer.SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Set rates so one packet adds one ms of buffer level.
|
// Set rates so one packet adds one ms of buffer level.
|
||||||
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
||||||
@ -559,6 +563,7 @@ TEST(TaskQueuePacedSenderTest, FixedHoldBackHasPriorityOverPackets) {
|
|||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
kFixedCoalescingWindow, kPacketBasedHoldback);
|
kFixedCoalescingWindow, kPacketBasedHoldback);
|
||||||
|
pacer.SetSendBurstInterval(TimeDelta::Zero());
|
||||||
|
|
||||||
// Set rates so one packet adds one ms of buffer level.
|
// Set rates so one packet adds one ms of buffer level.
|
||||||
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
const DataSize kPacketSize = DataSize::Bytes(kDefaultPacketSize);
|
||||||
@ -691,7 +696,7 @@ TEST(TaskQueuePacedSenderTest, PostedPacketsNotSendFromRemovePacketsForSsrc) {
|
|||||||
TEST(TaskQueuePacedSenderTest, Stats) {
|
TEST(TaskQueuePacedSenderTest, Stats) {
|
||||||
static constexpr Timestamp kStartTime = Timestamp::Millis(1234);
|
static constexpr Timestamp kStartTime = Timestamp::Millis(1234);
|
||||||
GlobalSimulatedTimeController time_controller(kStartTime);
|
GlobalSimulatedTimeController time_controller(kStartTime);
|
||||||
MockPacketRouter packet_router;
|
NiceMock<MockPacketRouter> packet_router;
|
||||||
ScopedKeyValueConfig trials;
|
ScopedKeyValueConfig trials;
|
||||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||||
|
|
||||||
@ -708,7 +713,8 @@ TEST(TaskQueuePacedSenderTest, Stats) {
|
|||||||
// Allowed `QueueSizeData` and `ExpectedQueueTime` deviation.
|
// Allowed `QueueSizeData` and `ExpectedQueueTime` deviation.
|
||||||
static constexpr size_t kAllowedPacketsDeviation = 1;
|
static constexpr size_t kAllowedPacketsDeviation = 1;
|
||||||
static constexpr DataSize kAllowedQueueSizeDeviation =
|
static constexpr DataSize kAllowedQueueSizeDeviation =
|
||||||
DataSize::Bytes(kDefaultPacketSize * kAllowedPacketsDeviation);
|
DataSize::Bytes(kDefaultPacketSize * kAllowedPacketsDeviation) +
|
||||||
|
kPacingRate * PacingController::kDefaultBurstInterval;
|
||||||
static constexpr TimeDelta kAllowedQueueTimeDeviation =
|
static constexpr TimeDelta kAllowedQueueTimeDeviation =
|
||||||
kAllowedQueueSizeDeviation / kPacingRate;
|
kAllowedQueueSizeDeviation / kPacingRate;
|
||||||
|
|
||||||
|
|||||||
@ -356,7 +356,6 @@ std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
|
|||||||
call_config.rtp_transport_controller_send_factory =
|
call_config.rtp_transport_controller_send_factory =
|
||||||
transport_controller_send_factory_.get();
|
transport_controller_send_factory_.get();
|
||||||
call_config.metronome = metronome_.get();
|
call_config.metronome = metronome_.get();
|
||||||
call_config.pacer_burst_interval = configuration.pacer_burst_interval;
|
|
||||||
return context_->call_factory()->CreateCall(call_config);
|
return context_->call_factory()->CreateCall(call_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -75,7 +75,6 @@ std::unique_ptr<Call> CreateCall(
|
|||||||
call_config.task_queue_factory = time_controller->GetTaskQueueFactory();
|
call_config.task_queue_factory = time_controller->GetTaskQueueFactory();
|
||||||
call_config.network_controller_factory = network_controller_factory;
|
call_config.network_controller_factory = network_controller_factory;
|
||||||
call_config.audio_state = audio_state;
|
call_config.audio_state = audio_state;
|
||||||
call_config.pacer_burst_interval = config.pacer_burst_interval;
|
|
||||||
call_config.trials = config.field_trials;
|
call_config.trials = config.field_trials;
|
||||||
Clock* clock = time_controller->GetClock();
|
Clock* clock = time_controller->GetClock();
|
||||||
return Call::Create(call_config, clock,
|
return Call::Create(call_config, clock,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user