Revert "Refactors BitrateProber with unit types and absolute probe time."
This reverts commit 739a5b3692880cb6b41ae620fb9e755c39b044b1. Reason for revert: Speculate revert due to perf alerts. Original change's description: > Refactors BitrateProber with unit types and absolute probe time. > > Using unit types improves readability and some conversion in PacedSender > can be removed. > > TimeUntilNextProbe() is replaced by NextProbeTime(), so returning an > absolute time rather than a delta. This fits better with the upcoming > TaskQueue based pacer, and is also what is already stored internally > in BitrateProber. > > Bug: webrtc:10809 > Change-Id: I5a4e289d2b53e99d3c0a2f4b36a966dba759d5cf > Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158743 > Commit-Queue: Erik Språng <sprang@webrtc.org> > Reviewed-by: Sebastian Jansson <srte@webrtc.org> > Cr-Commit-Position: refs/heads/master@{#29670} TBR=sprang@webrtc.org,srte@webrtc.org # Not skipping CQ checks because original CL landed > 1 day ago. Bug: webrtc:10809 Change-Id: Ic0ad7d45031bf33c24583dfde308bdd8087a62aa Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158799 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29682}
This commit is contained in:
@ -28,7 +28,7 @@ namespace {
|
|||||||
// we have a min probe packet size of 200 bytes.
|
// we have a min probe packet size of 200 bytes.
|
||||||
constexpr size_t kMinProbePacketSize = 200;
|
constexpr size_t kMinProbePacketSize = 200;
|
||||||
|
|
||||||
constexpr TimeDelta kProbeClusterTimeout = TimeDelta::Seconds<5>();
|
constexpr int64_t kProbeClusterTimeoutMs = 5000;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -55,7 +55,7 @@ BitrateProber::~BitrateProber() {
|
|||||||
|
|
||||||
BitrateProber::BitrateProber(const WebRtcKeyValueConfig& field_trials)
|
BitrateProber::BitrateProber(const WebRtcKeyValueConfig& field_trials)
|
||||||
: probing_state_(ProbingState::kDisabled),
|
: probing_state_(ProbingState::kDisabled),
|
||||||
next_probe_time_(Timestamp::PlusInfinity()),
|
next_probe_time_ms_(-1),
|
||||||
total_probe_count_(0),
|
total_probe_count_(0),
|
||||||
total_failed_probe_count_(0),
|
total_failed_probe_count_(0),
|
||||||
config_(&field_trials) {
|
config_(&field_trials) {
|
||||||
@ -85,31 +85,32 @@ void BitrateProber::OnIncomingPacket(size_t packet_size) {
|
|||||||
packet_size >=
|
packet_size >=
|
||||||
std::min<size_t>(RecommendedMinProbeSize(), kMinProbePacketSize)) {
|
std::min<size_t>(RecommendedMinProbeSize(), kMinProbePacketSize)) {
|
||||||
// Send next probe right away.
|
// Send next probe right away.
|
||||||
next_probe_time_ = Timestamp::MinusInfinity();
|
next_probe_time_ms_ = -1;
|
||||||
probing_state_ = ProbingState::kActive;
|
probing_state_ = ProbingState::kActive;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitrateProber::CreateProbeCluster(DataRate bitrate,
|
void BitrateProber::CreateProbeCluster(int bitrate_bps,
|
||||||
Timestamp now,
|
int64_t now_ms,
|
||||||
int cluster_id) {
|
int cluster_id) {
|
||||||
RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
|
RTC_DCHECK(probing_state_ != ProbingState::kDisabled);
|
||||||
RTC_DCHECK_GT(bitrate, DataRate::Zero());
|
RTC_DCHECK_GT(bitrate_bps, 0);
|
||||||
|
|
||||||
total_probe_count_++;
|
total_probe_count_++;
|
||||||
while (!clusters_.empty() &&
|
while (!clusters_.empty() &&
|
||||||
now - clusters_.front().created_at > kProbeClusterTimeout) {
|
now_ms - clusters_.front().time_created_ms > kProbeClusterTimeoutMs) {
|
||||||
clusters_.pop();
|
clusters_.pop();
|
||||||
total_failed_probe_count_++;
|
total_failed_probe_count_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProbeCluster cluster;
|
ProbeCluster cluster;
|
||||||
cluster.created_at = now;
|
cluster.time_created_ms = now_ms;
|
||||||
cluster.pace_info.probe_cluster_min_probes = config_.min_probe_packets_sent;
|
cluster.pace_info.probe_cluster_min_probes = config_.min_probe_packets_sent;
|
||||||
cluster.pace_info.probe_cluster_min_bytes =
|
cluster.pace_info.probe_cluster_min_bytes =
|
||||||
(bitrate * config_.min_probe_duration.Get()).bytes();
|
static_cast<int32_t>(static_cast<int64_t>(bitrate_bps) *
|
||||||
|
config_.min_probe_duration->ms() / 8000);
|
||||||
RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0);
|
RTC_DCHECK_GE(cluster.pace_info.probe_cluster_min_bytes, 0);
|
||||||
cluster.pace_info.send_bitrate_bps = bitrate.bps();
|
cluster.pace_info.send_bitrate_bps = bitrate_bps;
|
||||||
cluster.pace_info.probe_cluster_id = cluster_id;
|
cluster.pace_info.probe_cluster_id = cluster_id;
|
||||||
clusters_.push(cluster);
|
clusters_.push(cluster);
|
||||||
|
|
||||||
@ -123,21 +124,23 @@ void BitrateProber::CreateProbeCluster(DataRate bitrate,
|
|||||||
probing_state_ = ProbingState::kInactive;
|
probing_state_ = ProbingState::kInactive;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp BitrateProber::NextProbeTime(Timestamp now) const {
|
int BitrateProber::TimeUntilNextProbe(int64_t now_ms) {
|
||||||
// Probing is not active or probing is already complete.
|
// Probing is not active or probing is already complete.
|
||||||
if (probing_state_ != ProbingState::kActive || clusters_.empty()) {
|
if (probing_state_ != ProbingState::kActive || clusters_.empty())
|
||||||
return Timestamp::PlusInfinity();
|
return -1;
|
||||||
|
|
||||||
|
int time_until_probe_ms = 0;
|
||||||
|
if (next_probe_time_ms_ >= 0) {
|
||||||
|
time_until_probe_ms = next_probe_time_ms_ - now_ms;
|
||||||
|
if (time_until_probe_ms < -config_.max_probe_delay->ms()) {
|
||||||
|
RTC_DLOG(LS_WARNING) << "Probe delay too high"
|
||||||
|
<< " (next_ms:" << next_probe_time_ms_
|
||||||
|
<< ", now_ms: " << now_ms << ")";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next_probe_time_.IsFinite() &&
|
return std::max(time_until_probe_ms, 0);
|
||||||
now - next_probe_time_ > config_.max_probe_delay.Get()) {
|
|
||||||
RTC_DLOG(LS_WARNING) << "Probe delay too high"
|
|
||||||
<< " (next_ms:" << next_probe_time_.ms()
|
|
||||||
<< ", now_ms: " << now.ms() << ")";
|
|
||||||
return Timestamp::PlusInfinity();
|
|
||||||
}
|
|
||||||
|
|
||||||
return next_probe_time_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PacedPacketInfo BitrateProber::CurrentCluster() const {
|
PacedPacketInfo BitrateProber::CurrentCluster() const {
|
||||||
@ -157,19 +160,19 @@ size_t BitrateProber::RecommendedMinProbeSize() const {
|
|||||||
config_.min_probe_delta->ms() / (8 * 1000);
|
config_.min_probe_delta->ms() / (8 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BitrateProber::ProbeSent(Timestamp now, size_t bytes) {
|
void BitrateProber::ProbeSent(int64_t now_ms, size_t bytes) {
|
||||||
RTC_DCHECK(probing_state_ == ProbingState::kActive);
|
RTC_DCHECK(probing_state_ == ProbingState::kActive);
|
||||||
RTC_DCHECK_GT(bytes, 0);
|
RTC_DCHECK_GT(bytes, 0);
|
||||||
|
|
||||||
if (!clusters_.empty()) {
|
if (!clusters_.empty()) {
|
||||||
ProbeCluster* cluster = &clusters_.front();
|
ProbeCluster* cluster = &clusters_.front();
|
||||||
if (cluster->sent_probes == 0) {
|
if (cluster->sent_probes == 0) {
|
||||||
RTC_DCHECK(cluster->started_at.IsInfinite());
|
RTC_DCHECK_EQ(cluster->time_started_ms, -1);
|
||||||
cluster->started_at = now;
|
cluster->time_started_ms = now_ms;
|
||||||
}
|
}
|
||||||
cluster->sent_bytes += static_cast<int>(bytes);
|
cluster->sent_bytes += static_cast<int>(bytes);
|
||||||
cluster->sent_probes += 1;
|
cluster->sent_probes += 1;
|
||||||
next_probe_time_ = CalculateNextProbeTime(*cluster);
|
next_probe_time_ms_ = GetNextProbeTime(*cluster);
|
||||||
if (cluster->sent_bytes >= cluster->pace_info.probe_cluster_min_bytes &&
|
if (cluster->sent_bytes >= cluster->pace_info.probe_cluster_min_bytes &&
|
||||||
cluster->sent_probes >= cluster->pace_info.probe_cluster_min_probes) {
|
cluster->sent_probes >= cluster->pace_info.probe_cluster_min_probes) {
|
||||||
RTC_HISTOGRAM_COUNTS_100000("WebRTC.BWE.Probing.ProbeClusterSizeInBytes",
|
RTC_HISTOGRAM_COUNTS_100000("WebRTC.BWE.Probing.ProbeClusterSizeInBytes",
|
||||||
@ -177,7 +180,7 @@ void BitrateProber::ProbeSent(Timestamp now, size_t bytes) {
|
|||||||
RTC_HISTOGRAM_COUNTS_100("WebRTC.BWE.Probing.ProbesPerCluster",
|
RTC_HISTOGRAM_COUNTS_100("WebRTC.BWE.Probing.ProbesPerCluster",
|
||||||
cluster->sent_probes);
|
cluster->sent_probes);
|
||||||
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.Probing.TimePerProbeCluster",
|
RTC_HISTOGRAM_COUNTS_10000("WebRTC.BWE.Probing.TimePerProbeCluster",
|
||||||
(now - cluster->started_at).ms());
|
now_ms - cluster->time_started_ms);
|
||||||
|
|
||||||
clusters_.pop();
|
clusters_.pop();
|
||||||
}
|
}
|
||||||
@ -186,17 +189,16 @@ void BitrateProber::ProbeSent(Timestamp now, size_t bytes) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp BitrateProber::CalculateNextProbeTime(
|
int64_t BitrateProber::GetNextProbeTime(const ProbeCluster& cluster) {
|
||||||
const ProbeCluster& cluster) const {
|
|
||||||
RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0);
|
RTC_CHECK_GT(cluster.pace_info.send_bitrate_bps, 0);
|
||||||
RTC_CHECK(cluster.started_at.IsFinite());
|
RTC_CHECK_GE(cluster.time_started_ms, 0);
|
||||||
|
|
||||||
// Compute the time delta from the cluster start to ensure probe bitrate stays
|
// Compute the time delta from the cluster start to ensure probe bitrate stays
|
||||||
// close to the target bitrate. Result is in milliseconds.
|
// close to the target bitrate. Result is in milliseconds.
|
||||||
DataSize sent_bytes = DataSize::bytes(cluster.sent_bytes);
|
int64_t delta_ms =
|
||||||
DataRate send_bitrate = DataRate::bps(cluster.pace_info.send_bitrate_bps);
|
(8000ll * cluster.sent_bytes + cluster.pace_info.send_bitrate_bps / 2) /
|
||||||
TimeDelta delta = sent_bytes / send_bitrate;
|
cluster.pace_info.send_bitrate_bps;
|
||||||
return cluster.started_at + delta;
|
return cluster.time_started_ms + delta_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -61,12 +61,11 @@ class BitrateProber {
|
|||||||
|
|
||||||
// Create a cluster used to probe for |bitrate_bps| with |num_probes| number
|
// Create a cluster used to probe for |bitrate_bps| with |num_probes| number
|
||||||
// of probes.
|
// of probes.
|
||||||
void CreateProbeCluster(DataRate bitrate, Timestamp now, int cluster_id);
|
void CreateProbeCluster(int bitrate_bps, int64_t now_ms, int cluster_id);
|
||||||
|
|
||||||
// Returns the at which the next probe should be sent to get accurate probing.
|
// Returns the number of milliseconds until the next probe should be sent to
|
||||||
// If probing is not desired at this time, Timestamp::PlusInfinity() will be
|
// get accurate probing.
|
||||||
// returned.
|
int TimeUntilNextProbe(int64_t now_ms);
|
||||||
Timestamp NextProbeTime(Timestamp now) const;
|
|
||||||
|
|
||||||
// Information about the current probing cluster.
|
// Information about the current probing cluster.
|
||||||
PacedPacketInfo CurrentCluster() const;
|
PacedPacketInfo CurrentCluster() const;
|
||||||
@ -79,7 +78,7 @@ class BitrateProber {
|
|||||||
// multiple packets per probe, this call would be made at the end of sending
|
// multiple packets per probe, this call would be made at the end of sending
|
||||||
// the last packet in probe. |probe_size| is the total size of all packets
|
// the last packet in probe. |probe_size| is the total size of all packets
|
||||||
// in probe.
|
// in probe.
|
||||||
void ProbeSent(Timestamp now, size_t probe_size);
|
void ProbeSent(int64_t now_ms, size_t probe_size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class ProbingState {
|
enum class ProbingState {
|
||||||
@ -102,12 +101,12 @@ class BitrateProber {
|
|||||||
|
|
||||||
int sent_probes = 0;
|
int sent_probes = 0;
|
||||||
int sent_bytes = 0;
|
int sent_bytes = 0;
|
||||||
Timestamp created_at = Timestamp::MinusInfinity();
|
int64_t time_created_ms = -1;
|
||||||
Timestamp started_at = Timestamp::MinusInfinity();
|
int64_t time_started_ms = -1;
|
||||||
int retries = 0;
|
int retries = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Timestamp CalculateNextProbeTime(const ProbeCluster& cluster) const;
|
int64_t GetNextProbeTime(const ProbeCluster& cluster);
|
||||||
|
|
||||||
ProbingState probing_state_;
|
ProbingState probing_state_;
|
||||||
|
|
||||||
@ -117,7 +116,7 @@ class BitrateProber {
|
|||||||
std::queue<ProbeCluster> clusters_;
|
std::queue<ProbeCluster> clusters_;
|
||||||
|
|
||||||
// Time the next probe should be sent when in kActive state.
|
// Time the next probe should be sent when in kActive state.
|
||||||
Timestamp next_probe_time_;
|
int64_t next_probe_time_ms_;
|
||||||
|
|
||||||
int total_probe_count_;
|
int total_probe_count_;
|
||||||
int total_failed_probe_count_;
|
int total_failed_probe_count_;
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
|
|
||||||
#include "modules/pacing/bitrate_prober.h"
|
#include "modules/pacing/bitrate_prober.h"
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "test/gtest.h"
|
#include "test/gtest.h"
|
||||||
|
|
||||||
namespace webrtc {
|
namespace webrtc {
|
||||||
@ -21,18 +19,17 @@ TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) {
|
|||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
|
|
||||||
Timestamp now = Timestamp::ms(0);
|
int64_t now_ms = 0;
|
||||||
const Timestamp start_time = now;
|
EXPECT_EQ(-1, prober.TimeUntilNextProbe(now_ms));
|
||||||
EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
|
|
||||||
|
|
||||||
const DataRate kTestBitrate1 = DataRate::kbps(900);
|
const int kTestBitrate1 = 900000;
|
||||||
const DataRate kTestBitrate2 = DataRate::kbps(1800);
|
const int kTestBitrate2 = 1800000;
|
||||||
const int kClusterSize = 5;
|
const int kClusterSize = 5;
|
||||||
const int kProbeSize = 1000;
|
const int kProbeSize = 1000;
|
||||||
const TimeDelta kMinProbeDuration = TimeDelta::ms(15);
|
const int kMinProbeDurationMs = 15;
|
||||||
|
|
||||||
prober.CreateProbeCluster(kTestBitrate1, now, 0);
|
prober.CreateProbeCluster(kTestBitrate1, now_ms, 0);
|
||||||
prober.CreateProbeCluster(kTestBitrate2, now, 1);
|
prober.CreateProbeCluster(kTestBitrate2, now_ms, 1);
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
|
|
||||||
prober.OnIncomingPacket(kProbeSize);
|
prober.OnIncomingPacket(kProbeSize);
|
||||||
@ -40,40 +37,39 @@ TEST(BitrateProberTest, VerifyStatesAndTimeBetweenProbes) {
|
|||||||
EXPECT_EQ(0, prober.CurrentCluster().probe_cluster_id);
|
EXPECT_EQ(0, prober.CurrentCluster().probe_cluster_id);
|
||||||
|
|
||||||
// First packet should probe as soon as possible.
|
// First packet should probe as soon as possible.
|
||||||
EXPECT_EQ(Timestamp::MinusInfinity(), prober.NextProbeTime(now));
|
EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
|
||||||
|
|
||||||
for (int i = 0; i < kClusterSize; ++i) {
|
for (int i = 0; i < kClusterSize; ++i) {
|
||||||
now = std::max(now, prober.NextProbeTime(now));
|
now_ms += prober.TimeUntilNextProbe(now_ms);
|
||||||
EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
|
EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
|
||||||
EXPECT_EQ(0, prober.CurrentCluster().probe_cluster_id);
|
EXPECT_EQ(0, prober.CurrentCluster().probe_cluster_id);
|
||||||
prober.ProbeSent(now, kProbeSize);
|
prober.ProbeSent(now_ms, kProbeSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_GE(now - start_time, kMinProbeDuration);
|
EXPECT_GE(now_ms, kMinProbeDurationMs);
|
||||||
// Verify that the actual bitrate is withing 10% of the target.
|
// Verify that the actual bitrate is withing 10% of the target.
|
||||||
DataRate bitrate =
|
double bitrate = kProbeSize * (kClusterSize - 1) * 8 * 1000.0 / now_ms;
|
||||||
DataSize::bytes(kProbeSize * (kClusterSize - 1)) / (now - start_time);
|
|
||||||
EXPECT_GT(bitrate, kTestBitrate1 * 0.9);
|
EXPECT_GT(bitrate, kTestBitrate1 * 0.9);
|
||||||
EXPECT_LT(bitrate, kTestBitrate1 * 1.1);
|
EXPECT_LT(bitrate, kTestBitrate1 * 1.1);
|
||||||
|
|
||||||
now = std::max(now, prober.NextProbeTime(now));
|
now_ms += prober.TimeUntilNextProbe(now_ms);
|
||||||
Timestamp probe2_started = now;
|
int64_t probe2_started = now_ms;
|
||||||
|
|
||||||
for (int i = 0; i < kClusterSize; ++i) {
|
for (int i = 0; i < kClusterSize; ++i) {
|
||||||
now = std::max(now, prober.NextProbeTime(now));
|
now_ms += prober.TimeUntilNextProbe(now_ms);
|
||||||
EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
|
EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
|
||||||
EXPECT_EQ(1, prober.CurrentCluster().probe_cluster_id);
|
EXPECT_EQ(1, prober.CurrentCluster().probe_cluster_id);
|
||||||
prober.ProbeSent(now, kProbeSize);
|
prober.ProbeSent(now_ms, kProbeSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that the actual bitrate is withing 10% of the target.
|
// Verify that the actual bitrate is withing 10% of the target.
|
||||||
TimeDelta duration = now - probe2_started;
|
int duration = now_ms - probe2_started;
|
||||||
EXPECT_GE(duration, kMinProbeDuration);
|
EXPECT_GE(duration, kMinProbeDurationMs);
|
||||||
bitrate = DataSize::bytes(kProbeSize * (kClusterSize - 1)) / duration;
|
bitrate = kProbeSize * (kClusterSize - 1) * 8 * 1000.0 / duration;
|
||||||
EXPECT_GT(bitrate, kTestBitrate2 * 0.9);
|
EXPECT_GT(bitrate, kTestBitrate2 * 0.9);
|
||||||
EXPECT_LT(bitrate, kTestBitrate2 * 1.1);
|
EXPECT_LT(bitrate, kTestBitrate2 * 1.1);
|
||||||
|
|
||||||
EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
|
EXPECT_EQ(-1, prober.TimeUntilNextProbe(now_ms));
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,23 +77,23 @@ TEST(BitrateProberTest, DoesntProbeWithoutRecentPackets) {
|
|||||||
const FieldTrialBasedConfig config;
|
const FieldTrialBasedConfig config;
|
||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
|
|
||||||
Timestamp now = Timestamp::Zero();
|
int64_t now_ms = 0;
|
||||||
EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
|
EXPECT_EQ(-1, prober.TimeUntilNextProbe(now_ms));
|
||||||
|
|
||||||
prober.CreateProbeCluster(DataRate::kbps(900), now, 0);
|
prober.CreateProbeCluster(900000, now_ms, 0);
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
|
|
||||||
prober.OnIncomingPacket(1000);
|
prober.OnIncomingPacket(1000);
|
||||||
EXPECT_TRUE(prober.IsProbing());
|
EXPECT_TRUE(prober.IsProbing());
|
||||||
EXPECT_EQ(now, std::max(now, prober.NextProbeTime(now)));
|
EXPECT_EQ(0, prober.TimeUntilNextProbe(now_ms));
|
||||||
prober.ProbeSent(now, 1000);
|
prober.ProbeSent(now_ms, 1000);
|
||||||
// Let time pass, no large enough packets put into prober.
|
// Let time pass, no large enough packets put into prober.
|
||||||
now += TimeDelta::seconds(6);
|
now_ms += 6000;
|
||||||
EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
|
EXPECT_EQ(-1, prober.TimeUntilNextProbe(now_ms));
|
||||||
// Check that legacy behaviour where prober is reset in TimeUntilNextProbe is
|
// Check that legacy behaviour where prober is reset in TimeUntilNextProbe is
|
||||||
// no longer there. Probes are no longer retried if they are timed out.
|
// no longer there. Probes are no longer retried if they are timed out.
|
||||||
prober.OnIncomingPacket(1000);
|
prober.OnIncomingPacket(1000);
|
||||||
EXPECT_EQ(prober.NextProbeTime(now), Timestamp::PlusInfinity());
|
EXPECT_EQ(-1, prober.TimeUntilNextProbe(now_ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BitrateProberTest, DoesntInitializeProbingForSmallPackets) {
|
TEST(BitrateProberTest, DoesntInitializeProbingForSmallPackets) {
|
||||||
@ -115,12 +111,11 @@ TEST(BitrateProberTest, VerifyProbeSizeOnHighBitrate) {
|
|||||||
const FieldTrialBasedConfig config;
|
const FieldTrialBasedConfig config;
|
||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
|
|
||||||
const DataRate kHighBitrate = DataRate::kbps(10000); // 10 Mbps
|
constexpr unsigned kHighBitrateBps = 10000000; // 10 Mbps
|
||||||
|
|
||||||
prober.CreateProbeCluster(kHighBitrate, Timestamp::ms(0), /*cluster_id=*/0);
|
prober.CreateProbeCluster(kHighBitrateBps, 0, /*cluster_id=*/0);
|
||||||
// Probe size should ensure a minimum of 1 ms interval.
|
// Probe size should ensure a minimum of 1 ms interval.
|
||||||
EXPECT_GT(prober.RecommendedMinProbeSize(),
|
EXPECT_GT(prober.RecommendedMinProbeSize(), kHighBitrateBps / 8000);
|
||||||
(kHighBitrate * TimeDelta::ms(1)).bytes<size_t>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
|
TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
|
||||||
@ -128,15 +123,14 @@ TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
|
|||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
// Even when probing at a low bitrate we expect a minimum number
|
// Even when probing at a low bitrate we expect a minimum number
|
||||||
// of packets to be sent.
|
// of packets to be sent.
|
||||||
const DataRate kBitrate = DataRate::kbps(100);
|
constexpr int kBitrateBps = 100000; // 100 kbps
|
||||||
const int kPacketSizeBytes = 1000;
|
constexpr int kPacketSizeBytes = 1000;
|
||||||
|
|
||||||
Timestamp now = Timestamp::ms(0);
|
prober.CreateProbeCluster(kBitrateBps, 0, 0);
|
||||||
prober.CreateProbeCluster(kBitrate, now, 0);
|
|
||||||
prober.OnIncomingPacket(kPacketSizeBytes);
|
prober.OnIncomingPacket(kPacketSizeBytes);
|
||||||
for (int i = 0; i < 5; ++i) {
|
for (int i = 0; i < 5; ++i) {
|
||||||
EXPECT_TRUE(prober.IsProbing());
|
EXPECT_TRUE(prober.IsProbing());
|
||||||
prober.ProbeSent(now, kPacketSizeBytes);
|
prober.ProbeSent(0, kPacketSizeBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
@ -145,17 +139,16 @@ TEST(BitrateProberTest, MinumumNumberOfProbingPackets) {
|
|||||||
TEST(BitrateProberTest, ScaleBytesUsedForProbing) {
|
TEST(BitrateProberTest, ScaleBytesUsedForProbing) {
|
||||||
const FieldTrialBasedConfig config;
|
const FieldTrialBasedConfig config;
|
||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
const DataRate kBitrate = DataRate::kbps(10000); // 10 Mbps.
|
constexpr int kBitrateBps = 10000000; // 10 Mbps
|
||||||
const int kPacketSizeBytes = 1000;
|
constexpr int kPacketSizeBytes = 1000;
|
||||||
const int kExpectedBytesSent = (kBitrate * TimeDelta::ms(15)).bytes();
|
constexpr int kExpectedBytesSent = kBitrateBps * 15 / 8000;
|
||||||
|
|
||||||
Timestamp now = Timestamp::ms(0);
|
prober.CreateProbeCluster(kBitrateBps, 0, /*cluster_id=*/0);
|
||||||
prober.CreateProbeCluster(kBitrate, now, /*cluster_id=*/0);
|
|
||||||
prober.OnIncomingPacket(kPacketSizeBytes);
|
prober.OnIncomingPacket(kPacketSizeBytes);
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
while (bytes_sent < kExpectedBytesSent) {
|
while (bytes_sent < kExpectedBytesSent) {
|
||||||
ASSERT_TRUE(prober.IsProbing());
|
ASSERT_TRUE(prober.IsProbing());
|
||||||
prober.ProbeSent(now, kPacketSizeBytes);
|
prober.ProbeSent(0, kPacketSizeBytes);
|
||||||
bytes_sent += kPacketSizeBytes;
|
bytes_sent += kPacketSizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,17 +158,16 @@ TEST(BitrateProberTest, ScaleBytesUsedForProbing) {
|
|||||||
TEST(BitrateProberTest, HighBitrateProbing) {
|
TEST(BitrateProberTest, HighBitrateProbing) {
|
||||||
const FieldTrialBasedConfig config;
|
const FieldTrialBasedConfig config;
|
||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
const DataRate kBitrate = DataRate::kbps(1000000); // 1 Gbps.
|
constexpr int kBitrateBps = 1000000000; // 1 Gbps.
|
||||||
const int kPacketSizeBytes = 1000;
|
constexpr int kPacketSizeBytes = 1000;
|
||||||
const int kExpectedBytesSent = (kBitrate * TimeDelta::ms(15)).bytes();
|
constexpr int kExpectedBytesSent = (kBitrateBps / 8000) * 15;
|
||||||
|
|
||||||
Timestamp now = Timestamp::ms(0);
|
prober.CreateProbeCluster(kBitrateBps, 0, 0);
|
||||||
prober.CreateProbeCluster(kBitrate, now, 0);
|
|
||||||
prober.OnIncomingPacket(kPacketSizeBytes);
|
prober.OnIncomingPacket(kPacketSizeBytes);
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
while (bytes_sent < kExpectedBytesSent) {
|
while (bytes_sent < kExpectedBytesSent) {
|
||||||
ASSERT_TRUE(prober.IsProbing());
|
ASSERT_TRUE(prober.IsProbing());
|
||||||
prober.ProbeSent(now, kPacketSizeBytes);
|
prober.ProbeSent(0, kPacketSizeBytes);
|
||||||
bytes_sent += kPacketSizeBytes;
|
bytes_sent += kPacketSizeBytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,28 +177,28 @@ TEST(BitrateProberTest, HighBitrateProbing) {
|
|||||||
TEST(BitrateProberTest, ProbeClusterTimeout) {
|
TEST(BitrateProberTest, ProbeClusterTimeout) {
|
||||||
const FieldTrialBasedConfig config;
|
const FieldTrialBasedConfig config;
|
||||||
BitrateProber prober(config);
|
BitrateProber prober(config);
|
||||||
const DataRate kBitrate = DataRate::kbps(300);
|
constexpr int kBitrateBps = 300000; // 300 kbps
|
||||||
const int kSmallPacketSize = 20;
|
constexpr int kSmallPacketSize = 20;
|
||||||
// Expecting two probe clusters of 5 packets each.
|
// Expecting two probe clusters of 5 packets each.
|
||||||
const int kExpectedBytesSent = 20 * 2 * 5;
|
constexpr int kExpectedBytesSent = 20 * 2 * 5;
|
||||||
const TimeDelta kTimeout = TimeDelta::ms(5000);
|
constexpr int64_t kTimeoutMs = 5000;
|
||||||
|
|
||||||
Timestamp now = Timestamp::ms(0);
|
int64_t now_ms = 0;
|
||||||
prober.CreateProbeCluster(kBitrate, now, /*cluster_id=*/0);
|
prober.CreateProbeCluster(kBitrateBps, now_ms, /*cluster_id=*/0);
|
||||||
prober.OnIncomingPacket(kSmallPacketSize);
|
prober.OnIncomingPacket(kSmallPacketSize);
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
now += kTimeout;
|
now_ms += kTimeoutMs;
|
||||||
prober.CreateProbeCluster(kBitrate / 10, now, /*cluster_id=*/1);
|
prober.CreateProbeCluster(kBitrateBps / 10, now_ms, /*cluster_id=*/1);
|
||||||
prober.OnIncomingPacket(kSmallPacketSize);
|
prober.OnIncomingPacket(kSmallPacketSize);
|
||||||
EXPECT_FALSE(prober.IsProbing());
|
EXPECT_FALSE(prober.IsProbing());
|
||||||
now += TimeDelta::ms(1);
|
now_ms += 1;
|
||||||
prober.CreateProbeCluster(kBitrate / 10, now, /*cluster_id=*/2);
|
prober.CreateProbeCluster(kBitrateBps / 10, now_ms, /*cluster_id=*/2);
|
||||||
prober.OnIncomingPacket(kSmallPacketSize);
|
prober.OnIncomingPacket(kSmallPacketSize);
|
||||||
EXPECT_TRUE(prober.IsProbing());
|
EXPECT_TRUE(prober.IsProbing());
|
||||||
int bytes_sent = 0;
|
int bytes_sent = 0;
|
||||||
while (bytes_sent < kExpectedBytesSent) {
|
while (bytes_sent < kExpectedBytesSent) {
|
||||||
ASSERT_TRUE(prober.IsProbing());
|
ASSERT_TRUE(prober.IsProbing());
|
||||||
prober.ProbeSent(now, kSmallPacketSize);
|
prober.ProbeSent(0, kSmallPacketSize);
|
||||||
bytes_sent += kSmallPacketSize;
|
bytes_sent += kSmallPacketSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ PacedSender::PacedSender(Clock* clock,
|
|||||||
static_cast<PacingController::PacketSender*>(this),
|
static_cast<PacingController::PacketSender*>(this),
|
||||||
event_log,
|
event_log,
|
||||||
field_trials),
|
field_trials),
|
||||||
clock_(clock),
|
|
||||||
packet_router_(packet_router),
|
packet_router_(packet_router),
|
||||||
process_thread_(process_thread) {
|
process_thread_(process_thread) {
|
||||||
if (process_thread_)
|
if (process_thread_)
|
||||||
@ -137,9 +136,9 @@ int64_t PacedSender::TimeUntilNextProcess() {
|
|||||||
.ms();
|
.ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp next_probe = pacing_controller_.NextProbeTime();
|
auto next_probe = pacing_controller_.TimeUntilNextProbe();
|
||||||
if (next_probe != Timestamp::PlusInfinity()) {
|
if (next_probe) {
|
||||||
return std::max(TimeDelta::Zero(), next_probe - clock_->CurrentTime()).ms();
|
return next_probe->ms();
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeDelta min_packet_limit = TimeDelta::ms(5);
|
const TimeDelta min_packet_limit = TimeDelta::ms(5);
|
||||||
|
@ -165,7 +165,6 @@ class PacedSender : public Module,
|
|||||||
rtc::CriticalSection critsect_;
|
rtc::CriticalSection critsect_;
|
||||||
PacingController pacing_controller_ RTC_GUARDED_BY(critsect_);
|
PacingController pacing_controller_ RTC_GUARDED_BY(critsect_);
|
||||||
|
|
||||||
Clock* const clock_;
|
|
||||||
PacketRouter* const packet_router_;
|
PacketRouter* const packet_router_;
|
||||||
ProcessThread* const process_thread_;
|
ProcessThread* const process_thread_;
|
||||||
};
|
};
|
||||||
|
@ -123,7 +123,7 @@ PacingController::PacingController(Clock* clock,
|
|||||||
PacingController::~PacingController() = default;
|
PacingController::~PacingController() = default;
|
||||||
|
|
||||||
void PacingController::CreateProbeCluster(DataRate bitrate, int cluster_id) {
|
void PacingController::CreateProbeCluster(DataRate bitrate, int cluster_id) {
|
||||||
prober_.CreateProbeCluster(bitrate, CurrentTime(), cluster_id);
|
prober_.CreateProbeCluster(bitrate.bps(), CurrentTime().ms(), cluster_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PacingController::Pause() {
|
void PacingController::Pause() {
|
||||||
@ -233,10 +233,10 @@ TimeDelta PacingController::OldestPacketWaitTime() const {
|
|||||||
void PacingController::EnqueuePacketInternal(
|
void PacingController::EnqueuePacketInternal(
|
||||||
std::unique_ptr<RtpPacketToSend> packet,
|
std::unique_ptr<RtpPacketToSend> packet,
|
||||||
int priority) {
|
int priority) {
|
||||||
|
Timestamp now = CurrentTime();
|
||||||
prober_.OnIncomingPacket(packet->payload_size());
|
prober_.OnIncomingPacket(packet->payload_size());
|
||||||
|
|
||||||
// TODO(sprang): Make sure tests respect this, replace with DCHECK.
|
// TODO(sprang): Make sure tests respect this, replace with DCHECK.
|
||||||
Timestamp now = CurrentTime();
|
|
||||||
if (packet->capture_time_ms() < 0) {
|
if (packet->capture_time_ms() < 0) {
|
||||||
packet->set_capture_time_ms(now.ms());
|
packet->set_capture_time_ms(now.ms());
|
||||||
}
|
}
|
||||||
@ -272,26 +272,19 @@ bool PacingController::ShouldSendKeepalive(Timestamp now) const {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp PacingController::NextProbeTime() {
|
absl::optional<TimeDelta> PacingController::TimeUntilNextProbe() {
|
||||||
if (!prober_.IsProbing()) {
|
if (!prober_.IsProbing()) {
|
||||||
return Timestamp::PlusInfinity();
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp now = CurrentTime();
|
TimeDelta time_delta =
|
||||||
Timestamp probe_time = prober_.NextProbeTime(now);
|
TimeDelta::ms(prober_.TimeUntilNextProbe(CurrentTime().ms()));
|
||||||
if (probe_time.IsInfinite()) {
|
if (time_delta > TimeDelta::Zero() ||
|
||||||
return probe_time;
|
(time_delta == TimeDelta::Zero() && !probing_send_failure_)) {
|
||||||
|
return time_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (probe_time > now) {
|
return absl::nullopt;
|
||||||
return probe_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (probing_send_failure_ || now - probe_time > TimeDelta::Zero()) {
|
|
||||||
return Timestamp::PlusInfinity();
|
|
||||||
}
|
|
||||||
|
|
||||||
return probe_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeDelta PacingController::TimeElapsedSinceLastProcess() const {
|
TimeDelta PacingController::TimeElapsedSinceLastProcess() const {
|
||||||
@ -407,7 +400,7 @@ void PacingController::ProcessPackets() {
|
|||||||
if (is_probing) {
|
if (is_probing) {
|
||||||
probing_send_failure_ = data_sent == DataSize::Zero();
|
probing_send_failure_ = data_sent == DataSize::Zero();
|
||||||
if (!probing_send_failure_) {
|
if (!probing_send_failure_) {
|
||||||
prober_.ProbeSent(CurrentTime(), data_sent.bytes());
|
prober_.ProbeSent(CurrentTime().ms(), data_sent.bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,11 +118,10 @@ class PacingController {
|
|||||||
// effect.
|
// effect.
|
||||||
void SetProbingEnabled(bool enabled);
|
void SetProbingEnabled(bool enabled);
|
||||||
|
|
||||||
// Time at which next probe should be sent. If this value is set, it should be
|
// Time until next probe should be sent. If this value is set, it should be
|
||||||
// respected - i.e. don't call ProcessPackets() before this specified time as
|
// respected - i.e. don't call ProcessPackets() before this specified time as
|
||||||
// that can have unintended side effects.
|
// that can have unintended side effects.
|
||||||
// If no scheduled probe, Timestamp::PlusInifinity() is returned.
|
absl::optional<TimeDelta> TimeUntilNextProbe();
|
||||||
Timestamp NextProbeTime();
|
|
||||||
|
|
||||||
// Time since ProcessPackets() was last executed.
|
// Time since ProcessPackets() was last executed.
|
||||||
TimeDelta TimeElapsedSinceLastProcess() const;
|
TimeDelta TimeElapsedSinceLastProcess() const;
|
||||||
|
@ -246,9 +246,9 @@ class PacingControllerTest : public ::testing::Test {
|
|||||||
TimeDelta::Zero());
|
TimeDelta::Zero());
|
||||||
}
|
}
|
||||||
|
|
||||||
Timestamp next_probe = pacer_->NextProbeTime();
|
auto next_probe = pacer_->TimeUntilNextProbe();
|
||||||
if (next_probe != Timestamp::PlusInfinity()) {
|
if (next_probe) {
|
||||||
return std::max(TimeDelta::Zero(), next_probe - clock_.CurrentTime());
|
return *next_probe;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimeDelta min_packet_limit = TimeDelta::ms(5);
|
const TimeDelta min_packet_limit = TimeDelta::ms(5);
|
||||||
|
Reference in New Issue
Block a user