Add parameter to control the pacer's burst outside of field trials.
BurstyPacer is currently controlled via field trials. In order for Chrome to be able to have burst without relying on a field trial, this parameter is added. When all burst experiments have concluded we may be able to have a hardcoded constant instead, but for now the parameter is added to RTCConfiguration. NOTRY=True Bug: chromium:1354491 Change-Id: I386c1651dbbcbf309c15ea3d3380cf8f632b5429 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/283420 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Henrik Boström <hbos@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38621}
This commit is contained in:
parent
b21c979691
commit
cf2856b01c
@ -695,6 +695,9 @@ class RTC_EXPORT PeerConnectionInterface : public rtc::RefCountInterface {
|
||||
|
||||
PortAllocatorConfig port_allocator_config;
|
||||
|
||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
||||
absl::optional<TimeDelta> pacer_burst_interval;
|
||||
|
||||
//
|
||||
// Don't forget to update operator== if adding something.
|
||||
//
|
||||
|
||||
@ -31,6 +31,7 @@ RtpTransportConfig CallConfig::ExtractTransportConfig() const {
|
||||
network_state_predictor_factory;
|
||||
transportConfig.task_queue_factory = task_queue_factory;
|
||||
transportConfig.trials = trials;
|
||||
transportConfig.pacer_burst_interval = pacer_burst_interval;
|
||||
|
||||
return transportConfig;
|
||||
}
|
||||
|
||||
@ -78,6 +78,9 @@ struct CallConfig {
|
||||
rtp_transport_controller_send_factory = nullptr;
|
||||
|
||||
Metronome* metronome = nullptr;
|
||||
|
||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
||||
absl::optional<TimeDelta> pacer_burst_interval;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
@ -44,6 +44,9 @@ struct RtpTransportConfig {
|
||||
// Key-value mapping of internal configurations to apply,
|
||||
// e.g. field trials.
|
||||
const FieldTrialsView* trials = nullptr;
|
||||
|
||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
||||
absl::optional<TimeDelta> pacer_burst_interval;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -89,7 +89,8 @@ RtpTransportControllerSend::RtpTransportControllerSend(
|
||||
NetworkControllerFactoryInterface* controller_factory,
|
||||
const BitrateConstraints& bitrate_config,
|
||||
TaskQueueFactory* task_queue_factory,
|
||||
const FieldTrialsView& trials)
|
||||
const FieldTrialsView& trials,
|
||||
absl::optional<TimeDelta> pacer_burst_interval)
|
||||
: clock_(clock),
|
||||
event_log_(event_log),
|
||||
task_queue_factory_(task_queue_factory),
|
||||
@ -101,7 +102,8 @@ RtpTransportControllerSend::RtpTransportControllerSend(
|
||||
trials,
|
||||
task_queue_factory,
|
||||
pacer_settings_.holdback_window.Get(),
|
||||
pacer_settings_.holdback_packets.Get()),
|
||||
pacer_settings_.holdback_packets.Get(),
|
||||
pacer_burst_interval),
|
||||
observer_(nullptr),
|
||||
controller_factory_override_(controller_factory),
|
||||
controller_factory_fallback_(
|
||||
|
||||
@ -57,7 +57,8 @@ class RtpTransportControllerSend final
|
||||
NetworkControllerFactoryInterface* controller_factory,
|
||||
const BitrateConstraints& bitrate_config,
|
||||
TaskQueueFactory* task_queue_factory,
|
||||
const FieldTrialsView& trials);
|
||||
const FieldTrialsView& trials,
|
||||
absl::optional<TimeDelta> pacer_burst_interval);
|
||||
~RtpTransportControllerSend() override;
|
||||
|
||||
RtpTransportControllerSend(const RtpTransportControllerSend&) = delete;
|
||||
|
||||
@ -28,7 +28,7 @@ class RtpTransportControllerSendFactory
|
||||
return std::make_unique<RtpTransportControllerSend>(
|
||||
clock, config.event_log, config.network_state_predictor_factory,
|
||||
config.network_controller_factory, config.bitrate_config,
|
||||
config.task_queue_factory, *config.trials);
|
||||
config.task_queue_factory, *config.trials, config.pacer_burst_interval);
|
||||
}
|
||||
|
||||
virtual ~RtpTransportControllerSendFactory() {}
|
||||
|
||||
@ -135,7 +135,8 @@ class RtpVideoSenderTestFixture {
|
||||
nullptr,
|
||||
bitrate_config_,
|
||||
time_controller_.GetTaskQueueFactory(),
|
||||
field_trials ? *field_trials : field_trials_),
|
||||
field_trials ? *field_trials : field_trials_,
|
||||
absl::nullopt),
|
||||
stats_proxy_(time_controller_.GetClock(),
|
||||
config_,
|
||||
VideoEncoderConfig::ContentType::kRealtimeVideo,
|
||||
|
||||
@ -57,7 +57,8 @@ TaskQueuePacedSender::TaskQueuePacedSender(
|
||||
const FieldTrialsView& field_trials,
|
||||
TaskQueueFactory* task_queue_factory,
|
||||
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),
|
||||
bursty_pacer_flags_(field_trials),
|
||||
slacked_pacer_flags_(field_trials),
|
||||
@ -85,6 +86,12 @@ TaskQueuePacedSender::TaskQueuePacedSender(
|
||||
burst = slacked_burst;
|
||||
}
|
||||
}
|
||||
// Burst can also be controlled via the `burst_interval` argument.
|
||||
if (burst_interval.has_value() &&
|
||||
(!burst.has_value() || burst.value() < burst_interval.value())) {
|
||||
burst = burst_interval;
|
||||
}
|
||||
|
||||
if (burst.has_value()) {
|
||||
pacing_controller_.SetSendBurstInterval(burst.value());
|
||||
}
|
||||
|
||||
@ -39,16 +39,25 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender {
|
||||
public:
|
||||
static const int kNoPacketHoldback;
|
||||
|
||||
// The pacer can be configured using `field_trials` or specified parameters.
|
||||
//
|
||||
// The `hold_back_window` parameter sets a lower bound on time to sleep if
|
||||
// there is currently a pacer queue and packets can't immediately be
|
||||
// processed. Increasing this reduces thread wakeups at the expense of higher
|
||||
// latency.
|
||||
TaskQueuePacedSender(Clock* clock,
|
||||
PacingController::PacketSender* packet_sender,
|
||||
const FieldTrialsView& field_trials,
|
||||
TaskQueueFactory* task_queue_factory,
|
||||
TimeDelta max_hold_back_window,
|
||||
int max_hold_back_window_in_packets);
|
||||
//
|
||||
// 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.
|
||||
TaskQueuePacedSender(
|
||||
Clock* clock,
|
||||
PacingController::PacketSender* packet_sender,
|
||||
const FieldTrialsView& field_trials,
|
||||
TaskQueueFactory* task_queue_factory,
|
||||
TimeDelta max_hold_back_window,
|
||||
int max_hold_back_window_in_packets,
|
||||
absl::optional<TimeDelta> burst_interval = absl::nullopt);
|
||||
|
||||
~TaskQueuePacedSender() override;
|
||||
|
||||
|
||||
@ -253,6 +253,53 @@ TEST_P(TaskQueuePacedSenderTest, PacesPackets) {
|
||||
EXPECT_NEAR((end_time - start_time).ms<double>(), 1000.0, 50.0);
|
||||
}
|
||||
|
||||
// Same test as above, but with 0.5s of burst applied.
|
||||
TEST_P(TaskQueuePacedSenderTest, PacesPacketsWithBurst) {
|
||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||
MockPacketRouter packet_router;
|
||||
ScopedKeyValueConfig trials(GetParam());
|
||||
TaskQueuePacedSender pacer(time_controller.GetClock(), &packet_router, trials,
|
||||
time_controller.GetTaskQueueFactory(),
|
||||
PacingController::kMinSleepTime,
|
||||
TaskQueuePacedSender::kNoPacketHoldback,
|
||||
// Half a second of bursting.
|
||||
TimeDelta::Seconds(0.5));
|
||||
|
||||
// Insert a number of packets, covering one second.
|
||||
static constexpr size_t kPacketsToSend = 42;
|
||||
SequenceChecker sequence_checker;
|
||||
pacer.SetPacingRates(
|
||||
DataRate::BitsPerSec(kDefaultPacketSize * 8 * kPacketsToSend),
|
||||
DataRate::Zero());
|
||||
pacer.EnsureStarted();
|
||||
pacer.EnqueuePackets(
|
||||
GeneratePackets(RtpPacketMediaType::kVideo, kPacketsToSend));
|
||||
|
||||
// Expect all of them to be sent.
|
||||
size_t packets_sent = 0;
|
||||
Timestamp end_time = Timestamp::PlusInfinity();
|
||||
EXPECT_CALL(packet_router, SendPacket)
|
||||
.WillRepeatedly([&](std::unique_ptr<RtpPacketToSend> packet,
|
||||
const PacedPacketInfo& cluster_info) {
|
||||
++packets_sent;
|
||||
if (packets_sent == kPacketsToSend) {
|
||||
end_time = time_controller.GetClock()->CurrentTime();
|
||||
}
|
||||
EXPECT_EQ(sequence_checker.IsCurrent(), UsingWorkerThread(GetParam()));
|
||||
});
|
||||
|
||||
const Timestamp start_time = time_controller.GetClock()->CurrentTime();
|
||||
|
||||
// Packets should be sent over a period of close to 1s. Expect a little
|
||||
// lower than this since initial probing is a bit quicker.
|
||||
time_controller.AdvanceTime(TimeDelta::Seconds(1));
|
||||
EXPECT_EQ(packets_sent, kPacketsToSend);
|
||||
ASSERT_TRUE(end_time.IsFinite());
|
||||
// Because of half a second of burst, what would normally have been paced over
|
||||
// ~1 second now takes ~0.5 seconds.
|
||||
EXPECT_NEAR((end_time - start_time).ms<double>(), 500.0, 50.0);
|
||||
}
|
||||
|
||||
TEST_P(TaskQueuePacedSenderTest, ReschedulesProcessOnRateChange) {
|
||||
GlobalSimulatedTimeController time_controller(Timestamp::Millis(1234));
|
||||
MockPacketRouter packet_router;
|
||||
|
||||
@ -343,6 +343,7 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
webrtc::VpnPreference vpn_preference;
|
||||
std::vector<rtc::NetworkMask> vpn_list;
|
||||
PortAllocatorConfig port_allocator_config;
|
||||
absl::optional<TimeDelta> pacer_burst_interval;
|
||||
};
|
||||
static_assert(sizeof(stuff_being_tested_for_equality) == sizeof(*this),
|
||||
"Did you add something to RTCConfiguration and forget to "
|
||||
@ -409,7 +410,8 @@ bool PeerConnectionInterface::RTCConfiguration::operator==(
|
||||
vpn_preference == o.vpn_preference && vpn_list == o.vpn_list &&
|
||||
port_allocator_config.min_port == o.port_allocator_config.min_port &&
|
||||
port_allocator_config.max_port == o.port_allocator_config.max_port &&
|
||||
port_allocator_config.flags == o.port_allocator_config.flags;
|
||||
port_allocator_config.flags == o.port_allocator_config.flags &&
|
||||
pacer_burst_interval == o.pacer_burst_interval;
|
||||
}
|
||||
|
||||
bool PeerConnectionInterface::RTCConfiguration::operator!=(
|
||||
|
||||
@ -242,9 +242,10 @@ PeerConnectionFactory::CreatePeerConnectionOrError(
|
||||
|
||||
const FieldTrialsView* trials =
|
||||
dependencies.trials ? dependencies.trials.get() : &field_trials();
|
||||
std::unique_ptr<Call> call =
|
||||
worker_thread()->BlockingCall([this, &event_log, trials] {
|
||||
return CreateCall_w(event_log.get(), *trials);
|
||||
std::unique_ptr<Call> call = worker_thread()->BlockingCall(
|
||||
[this, &event_log, trials,
|
||||
pacer_burst_interval = configuration.pacer_burst_interval] {
|
||||
return CreateCall_w(event_log.get(), *trials, pacer_burst_interval);
|
||||
});
|
||||
|
||||
auto result = PeerConnection::Create(context_, options_, std::move(event_log),
|
||||
@ -303,7 +304,8 @@ std::unique_ptr<RtcEventLog> PeerConnectionFactory::CreateRtcEventLog_w() {
|
||||
|
||||
std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
|
||||
RtcEventLog* event_log,
|
||||
const FieldTrialsView& field_trials) {
|
||||
const FieldTrialsView& field_trials,
|
||||
absl::optional<TimeDelta> pacer_burst_interval) {
|
||||
RTC_DCHECK_RUN_ON(worker_thread());
|
||||
|
||||
webrtc::Call::Config call_config(event_log, network_thread());
|
||||
@ -346,6 +348,7 @@ std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
|
||||
call_config.rtp_transport_controller_send_factory =
|
||||
transport_controller_send_factory_.get();
|
||||
call_config.metronome = metronome_.get();
|
||||
call_config.pacer_burst_interval = pacer_burst_interval;
|
||||
return std::unique_ptr<Call>(
|
||||
context_->call_factory()->CreateCall(call_config));
|
||||
}
|
||||
|
||||
@ -136,8 +136,10 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface {
|
||||
bool IsTrialEnabled(absl::string_view key) const;
|
||||
|
||||
std::unique_ptr<RtcEventLog> CreateRtcEventLog_w();
|
||||
std::unique_ptr<Call> CreateCall_w(RtcEventLog* event_log,
|
||||
const FieldTrialsView& field_trials);
|
||||
std::unique_ptr<Call> CreateCall_w(
|
||||
RtcEventLog* event_log,
|
||||
const FieldTrialsView& field_trials,
|
||||
absl::optional<TimeDelta> pacer_burst_interval);
|
||||
|
||||
rtc::scoped_refptr<ConnectionContext> context_;
|
||||
PeerConnectionFactoryInterface::Options options_
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user