Introduce RtpTransportConfig:allow_bandwidht_estimation_probe_without_media
If allow_bandwidht_estimation_probe_without_media is true and a writable video rtp stream with RTX exist, a probe can be sent immediately without waiting for a large media packet. Bug: webrtc:14928 Change-Id: Ie2204734f9fe3e6bff9aed4a1f7f8995956d35cb Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/336000 Commit-Queue: Per Kjellander <perkj@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41626}
This commit is contained in:
parent
89db1c5827
commit
98db63cfb6
@ -38,6 +38,10 @@ struct RtpTransportConfig {
|
||||
|
||||
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
|
||||
absl::optional<TimeDelta> pacer_burst_interval;
|
||||
|
||||
// A bandwith estimation probe may be sent on a writable Rtp stream that have
|
||||
// RTX configured. It can be sent without first sending media packets.
|
||||
bool allow_bandwidth_estimation_probe_without_media = false;
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
|
||||
@ -70,6 +70,8 @@ bool IsRelayed(const rtc::NetworkRoute& route) {
|
||||
RtpTransportControllerSend::RtpTransportControllerSend(
|
||||
const RtpTransportConfig& config)
|
||||
: env_(config.env),
|
||||
allow_bandwidth_estimation_probe_without_media_(
|
||||
config.allow_bandwidth_estimation_probe_without_media),
|
||||
task_queue_(TaskQueueBase::Current()),
|
||||
bitrate_configurator_(config.bitrate_config),
|
||||
pacer_started_(false),
|
||||
@ -165,6 +167,9 @@ void RtpTransportControllerSend::RegisterSendingRtpStream(
|
||||
// Allow pacer to send packets using this module.
|
||||
packet_router_.AddSendRtpModule(&rtp_module,
|
||||
/*remb_candidate=*/true);
|
||||
pacer_.SetAllowProbeWithoutMediaPacket(
|
||||
allow_bandwidth_estimation_probe_without_media_ &&
|
||||
packet_router_.SupportsRtxPayloadPadding());
|
||||
}
|
||||
|
||||
void RtpTransportControllerSend::DeRegisterSendingRtpStream(
|
||||
@ -182,6 +187,9 @@ void RtpTransportControllerSend::DeRegisterSendingRtpStream(
|
||||
if (rtp_module.FlexfecSsrc().has_value()) {
|
||||
pacer_.RemovePacketsForSsrc(*rtp_module.FlexfecSsrc());
|
||||
}
|
||||
pacer_.SetAllowProbeWithoutMediaPacket(
|
||||
allow_bandwidth_estimation_probe_without_media_ &&
|
||||
packet_router_.SupportsRtxPayloadPadding());
|
||||
}
|
||||
|
||||
void RtpTransportControllerSend::UpdateControlState() {
|
||||
|
||||
@ -150,6 +150,7 @@ class RtpTransportControllerSend final
|
||||
|
||||
const Environment env_;
|
||||
SequenceChecker sequence_checker_;
|
||||
const bool allow_bandwidth_estimation_probe_without_media_;
|
||||
TaskQueueBase* task_queue_;
|
||||
PacketRouter packet_router_;
|
||||
std::vector<std::unique_ptr<RtpVideoSenderInterface>> video_rtp_senders_
|
||||
|
||||
@ -52,6 +52,18 @@ void BitrateProber::SetEnabled(bool enable) {
|
||||
}
|
||||
}
|
||||
|
||||
void BitrateProber::SetAllowProbeWithoutMediaPacket(bool allow) {
|
||||
config_.allow_start_probing_immediately = allow;
|
||||
MaybeSetActiveState(/*packet_size=*/DataSize::Zero());
|
||||
}
|
||||
|
||||
void BitrateProber::MaybeSetActiveState(DataSize packet_size) {
|
||||
if (ReadyToSetActiveState(packet_size)) {
|
||||
next_probe_time_ = Timestamp::MinusInfinity();
|
||||
probing_state_ = ProbingState::kActive;
|
||||
}
|
||||
}
|
||||
|
||||
bool BitrateProber::ReadyToSetActiveState(DataSize packet_size) const {
|
||||
if (clusters_.empty()) {
|
||||
RTC_DCHECK(probing_state_ == ProbingState::kDisabled ||
|
||||
@ -63,19 +75,19 @@ bool BitrateProber::ReadyToSetActiveState(DataSize packet_size) const {
|
||||
case ProbingState::kActive:
|
||||
return false;
|
||||
case ProbingState::kInactive:
|
||||
// If config_.min_packet_size > 0, a "large enough" packet must be sent
|
||||
// first, before a probe can be generated and sent. Otherwise, send the
|
||||
// probe asap.
|
||||
if (config_.allow_start_probing_immediately) {
|
||||
return true;
|
||||
}
|
||||
// If config_.min_packet_size > 0, a "large enough" packet must be
|
||||
// sent first, before a probe can be generated and sent. Otherwise,
|
||||
// send the probe asap.
|
||||
return packet_size >=
|
||||
std::min(RecommendedMinProbeSize(), config_.min_packet_size.Get());
|
||||
}
|
||||
}
|
||||
|
||||
void BitrateProber::OnIncomingPacket(DataSize packet_size) {
|
||||
if (ReadyToSetActiveState(packet_size)) {
|
||||
next_probe_time_ = Timestamp::MinusInfinity();
|
||||
probing_state_ = ProbingState::kActive;
|
||||
}
|
||||
MaybeSetActiveState(packet_size);
|
||||
}
|
||||
|
||||
void BitrateProber::CreateProbeCluster(
|
||||
@ -101,10 +113,8 @@ void BitrateProber::CreateProbeCluster(
|
||||
cluster.pace_info.probe_cluster_id = cluster_config.id;
|
||||
clusters_.push(cluster);
|
||||
|
||||
if (ReadyToSetActiveState(/*packet_size=*/DataSize::Zero())) {
|
||||
next_probe_time_ = Timestamp::MinusInfinity();
|
||||
probing_state_ = ProbingState::kActive;
|
||||
}
|
||||
MaybeSetActiveState(/*packet_size=*/DataSize::Zero());
|
||||
|
||||
RTC_DCHECK(probing_state_ == ProbingState::kActive ||
|
||||
probing_state_ == ProbingState::kInactive);
|
||||
|
||||
|
||||
@ -38,6 +38,9 @@ struct BitrateProberConfig {
|
||||
// This defines the max min packet size, meaning that on high bitrates
|
||||
// a packet of at least this size is needed to trigger sending a probe.
|
||||
FieldTrialParameter<DataSize> min_packet_size;
|
||||
|
||||
// If true, `min_packet_size` is ignored.
|
||||
bool allow_start_probing_immediately = false;
|
||||
};
|
||||
|
||||
// Note that this class isn't thread-safe by itself and therefore relies
|
||||
@ -48,6 +51,7 @@ class BitrateProber {
|
||||
~BitrateProber() = default;
|
||||
|
||||
void SetEnabled(bool enable);
|
||||
void SetAllowProbeWithoutMediaPacket(bool allow);
|
||||
|
||||
// Returns true if the prober is in a probing session, i.e., it currently
|
||||
// wants packets to be sent out according to the time returned by
|
||||
@ -105,6 +109,8 @@ class BitrateProber {
|
||||
};
|
||||
|
||||
Timestamp CalculateNextProbeTime(const ProbeCluster& cluster) const;
|
||||
|
||||
void MaybeSetActiveState(DataSize packet_size);
|
||||
bool ReadyToSetActiveState(DataSize packet_size) const;
|
||||
|
||||
ProbingState probing_state_;
|
||||
|
||||
@ -252,6 +252,10 @@ void PacingController::SetSendBurstInterval(TimeDelta burst_interval) {
|
||||
send_burst_interval_ = burst_interval;
|
||||
}
|
||||
|
||||
void PacingController::SetAllowProbeWithoutMediaPacket(bool allow) {
|
||||
prober_.SetAllowProbeWithoutMediaPacket(allow);
|
||||
}
|
||||
|
||||
TimeDelta PacingController::ExpectedQueueTime() const {
|
||||
RTC_DCHECK_GT(adjusted_media_rate_, DataRate::Zero());
|
||||
return QueueSizeData() / adjusted_media_rate_;
|
||||
|
||||
@ -160,6 +160,9 @@ class PacingController {
|
||||
// 'burst_interval'.
|
||||
void SetSendBurstInterval(TimeDelta burst_interval);
|
||||
|
||||
// A probe may be sent without first waing for a media packet.
|
||||
void SetAllowProbeWithoutMediaPacket(bool allow);
|
||||
|
||||
// Returns the time when the oldest packet was queued.
|
||||
Timestamp OldestPacketEnqueueTime() const;
|
||||
|
||||
|
||||
@ -1366,10 +1366,9 @@ TEST_F(PacingControllerTest, CanProbeWithPaddingBeforeFirstMediaPacket) {
|
||||
const int kInitialBitrateBps = 300000;
|
||||
|
||||
PacingControllerProbing packet_sender;
|
||||
const test::ExplicitKeyValueConfig trials(
|
||||
"WebRTC-Bwe-ProbingBehavior/min_packet_size:0/");
|
||||
auto pacer =
|
||||
std::make_unique<PacingController>(&clock_, &packet_sender, trials);
|
||||
std::make_unique<PacingController>(&clock_, &packet_sender, trials_);
|
||||
pacer->SetAllowProbeWithoutMediaPacket(true);
|
||||
std::vector<ProbeClusterConfig> probe_clusters = {
|
||||
{.at_time = clock_.CurrentTime(),
|
||||
.target_data_rate = kFirstClusterRate,
|
||||
@ -1393,16 +1392,46 @@ TEST_F(PacingControllerTest, CanProbeWithPaddingBeforeFirstMediaPacket) {
|
||||
EXPECT_GT(packet_sender.padding_packets_sent(), 5);
|
||||
}
|
||||
|
||||
TEST_F(PacingControllerTest, ProbeSentAfterSetAllowProbeWithoutMediaPacket) {
|
||||
const int kInitialBitrateBps = 300000;
|
||||
|
||||
PacingControllerProbing packet_sender;
|
||||
auto pacer =
|
||||
std::make_unique<PacingController>(&clock_, &packet_sender, trials_);
|
||||
std::vector<ProbeClusterConfig> probe_clusters = {
|
||||
{.at_time = clock_.CurrentTime(),
|
||||
.target_data_rate = kFirstClusterRate,
|
||||
.target_duration = TimeDelta::Millis(15),
|
||||
.target_probe_count = 5,
|
||||
.id = 0}};
|
||||
pacer->CreateProbeClusters(probe_clusters);
|
||||
|
||||
pacer->SetPacingRates(
|
||||
DataRate::BitsPerSec(kInitialBitrateBps * kPaceMultiplier),
|
||||
DataRate::Zero());
|
||||
|
||||
pacer->SetAllowProbeWithoutMediaPacket(true);
|
||||
|
||||
Timestamp start = clock_.CurrentTime();
|
||||
Timestamp next_process = pacer->NextSendTime();
|
||||
while (clock_.CurrentTime() < start + TimeDelta::Millis(100) &&
|
||||
next_process.IsFinite()) {
|
||||
AdvanceTimeUntil(next_process);
|
||||
pacer->ProcessPackets();
|
||||
next_process = pacer->NextSendTime();
|
||||
}
|
||||
EXPECT_GT(packet_sender.padding_packets_sent(), 5);
|
||||
}
|
||||
|
||||
TEST_F(PacingControllerTest, CanNotProbeWithPaddingIfGeneratePaddingFails) {
|
||||
// const size_t kPacketSize = 1200;
|
||||
const int kInitialBitrateBps = 300000;
|
||||
|
||||
PacingControllerProbing packet_sender;
|
||||
packet_sender.SetCanGeneratePadding(false);
|
||||
const test::ExplicitKeyValueConfig trials(
|
||||
"WebRTC-Bwe-ProbingBehavior/min_packet_size:0/");
|
||||
auto pacer =
|
||||
std::make_unique<PacingController>(&clock_, &packet_sender, trials);
|
||||
std::make_unique<PacingController>(&clock_, &packet_sender, trials_);
|
||||
pacer->SetAllowProbeWithoutMediaPacket(true);
|
||||
std::vector<ProbeClusterConfig> probe_clusters = {
|
||||
{.at_time = clock_.CurrentTime(),
|
||||
.target_data_rate = kFirstClusterRate,
|
||||
|
||||
@ -65,6 +65,16 @@ void PacketRouter::AddSendRtpModule(RtpRtcpInterface* rtp_module,
|
||||
}
|
||||
}
|
||||
|
||||
bool PacketRouter::SupportsRtxPayloadPadding() const {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
for (RtpRtcpInterface* rtp_module : send_modules_list_) {
|
||||
if (rtp_module->SupportsRtxPayloadPadding()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PacketRouter::AddSendRtpModuleToMap(RtpRtcpInterface* rtp_module,
|
||||
uint32_t ssrc) {
|
||||
RTC_DCHECK_RUN_ON(&thread_checker_);
|
||||
|
||||
@ -50,6 +50,8 @@ class PacketRouter : public PacingController::PacketSender {
|
||||
void AddSendRtpModule(RtpRtcpInterface* rtp_module, bool remb_candidate);
|
||||
void RemoveSendRtpModule(RtpRtcpInterface* rtp_module);
|
||||
|
||||
bool SupportsRtxPayloadPadding() const;
|
||||
|
||||
void AddReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender,
|
||||
bool remb_candidate);
|
||||
void RemoveReceiveRtpModule(RtcpFeedbackSenderInterface* rtcp_sender);
|
||||
|
||||
@ -125,6 +125,31 @@ TEST_F(PacketRouterTest, GeneratePaddingPrioritizesRtx) {
|
||||
packet_router_.RemoveSendRtpModule(&rtp_2);
|
||||
}
|
||||
|
||||
TEST_F(PacketRouterTest, SupportsRtxPayloadPaddingFalseIfNoRtxSendModule) {
|
||||
EXPECT_FALSE(packet_router_.SupportsRtxPayloadPadding());
|
||||
|
||||
NiceMock<MockRtpRtcpInterface> none_rtx_module;
|
||||
ON_CALL(none_rtx_module, SupportsRtxPayloadPadding())
|
||||
.WillByDefault(Return(false));
|
||||
|
||||
packet_router_.AddSendRtpModule(&none_rtx_module, false);
|
||||
EXPECT_FALSE(packet_router_.SupportsRtxPayloadPadding());
|
||||
|
||||
packet_router_.RemoveSendRtpModule(&none_rtx_module);
|
||||
EXPECT_FALSE(packet_router_.SupportsRtxPayloadPadding());
|
||||
}
|
||||
|
||||
TEST_F(PacketRouterTest, SupportsRtxPayloadPaddingTrueIfRtxSendModule) {
|
||||
NiceMock<MockRtpRtcpInterface> rtx_module;
|
||||
ON_CALL(rtx_module, SupportsRtxPayloadPadding()).WillByDefault(Return(true));
|
||||
|
||||
packet_router_.AddSendRtpModule(&rtx_module, false);
|
||||
EXPECT_TRUE(packet_router_.SupportsRtxPayloadPadding());
|
||||
|
||||
packet_router_.RemoveSendRtpModule(&rtx_module);
|
||||
EXPECT_FALSE(packet_router_.SupportsRtxPayloadPadding());
|
||||
}
|
||||
|
||||
TEST_F(PacketRouterTest, GeneratePaddingPrioritizesVideo) {
|
||||
// Two RTP modules. Neither support RTX, both support padding,
|
||||
// but the first one is for audio and second for video.
|
||||
|
||||
@ -52,6 +52,11 @@ void TaskQueuePacedSender::SetSendBurstInterval(TimeDelta burst_interval) {
|
||||
pacing_controller_.SetSendBurstInterval(burst_interval);
|
||||
}
|
||||
|
||||
void TaskQueuePacedSender::SetAllowProbeWithoutMediaPacket(bool allow) {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
pacing_controller_.SetAllowProbeWithoutMediaPacket(allow);
|
||||
}
|
||||
|
||||
void TaskQueuePacedSender::EnsureStarted() {
|
||||
RTC_DCHECK_RUN_ON(task_queue_);
|
||||
is_started_ = true;
|
||||
|
||||
@ -60,6 +60,9 @@ class TaskQueuePacedSender : public RtpPacketPacer, public RtpPacketSender {
|
||||
// 'burst_interval'.
|
||||
void SetSendBurstInterval(TimeDelta burst_interval);
|
||||
|
||||
// A probe may be sent without first waing for a media packet.
|
||||
void SetAllowProbeWithoutMediaPacket(bool allow);
|
||||
|
||||
// Ensure that necessary delayed tasks are scheduled.
|
||||
void EnsureStarted();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user