Reset InterArrival if arrival time clock makes a jump.
Also adds a copy of the BWE test suite to the new DelayBasedBwe class. BUG=webrtc:6079 Review-Url: https://codereview.webrtc.org/2126793002 Cr-Commit-Position: refs/heads/master@{#13428}
This commit is contained in:
parent
154d0de5cd
commit
5e12d36ba7
@ -145,6 +145,9 @@ if (rtc_include_tests) {
|
||||
"bitrate_controller/bitrate_controller_unittest.cc",
|
||||
"bitrate_controller/send_side_bandwidth_estimation_unittest.cc",
|
||||
"congestion_controller/congestion_controller_unittest.cc",
|
||||
"congestion_controller/delay_based_bwe_unittest.cc",
|
||||
"congestion_controller/delay_based_bwe_unittest_helper.cc",
|
||||
"congestion_controller/delay_based_bwe_unittest_helper.h",
|
||||
"media_file/media_file_unittest.cc",
|
||||
"module_common_types_unittest.cc",
|
||||
"pacing/bitrate_prober_unittest.cc",
|
||||
|
||||
@ -131,7 +131,7 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator {
|
||||
// Instantiate RBE for Time Offset or Absolute Send Time extensions.
|
||||
void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
|
||||
if (using_absolute_send_time_) {
|
||||
rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_));
|
||||
rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_));
|
||||
} else {
|
||||
rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_));
|
||||
}
|
||||
@ -205,7 +205,7 @@ CongestionController::~CongestionController() {}
|
||||
|
||||
void CongestionController::Init() {
|
||||
transport_feedback_adapter_.SetBitrateEstimator(
|
||||
new DelayBasedBwe(&transport_feedback_adapter_));
|
||||
new DelayBasedBwe(&transport_feedback_adapter_, clock_));
|
||||
transport_feedback_adapter_.GetBitrateEstimator()->SetMinBitrate(
|
||||
min_bitrate_bps_);
|
||||
}
|
||||
@ -240,8 +240,8 @@ void CongestionController::ResetBweAndBitrates(int bitrate_bps,
|
||||
if (remote_bitrate_estimator_)
|
||||
remote_bitrate_estimator_->SetMinBitrate(min_bitrate_bps);
|
||||
|
||||
RemoteBitrateEstimator* rbe =
|
||||
new RemoteBitrateEstimatorAbsSendTime(&transport_feedback_adapter_);
|
||||
RemoteBitrateEstimator* rbe = new RemoteBitrateEstimatorAbsSendTime(
|
||||
&transport_feedback_adapter_, clock_);
|
||||
transport_feedback_adapter_.SetBitrateEstimator(rbe);
|
||||
rbe->SetMinBitrate(min_bitrate_bps);
|
||||
// TODO(holmer): Trigger a new probe once mid-call probing is implemented.
|
||||
|
||||
@ -68,8 +68,9 @@ void DelayBasedBwe::AddCluster(std::list<Cluster>* clusters, Cluster* cluster) {
|
||||
clusters->push_back(*cluster);
|
||||
}
|
||||
|
||||
DelayBasedBwe::DelayBasedBwe(RemoteBitrateObserver* observer)
|
||||
: observer_(observer),
|
||||
DelayBasedBwe::DelayBasedBwe(RemoteBitrateObserver* observer, Clock* clock)
|
||||
: clock_(clock),
|
||||
observer_(observer),
|
||||
inter_arrival_(),
|
||||
estimator_(),
|
||||
detector_(OverUseDetectorOptions()),
|
||||
@ -203,35 +204,6 @@ void DelayBasedBwe::IncomingPacketFeedbackVector(
|
||||
}
|
||||
}
|
||||
|
||||
void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) {
|
||||
RTC_DCHECK(network_thread_.CalledOnValidThread());
|
||||
if (!header.extension.hasAbsoluteSendTime) {
|
||||
// NOTE! The BitrateEstimatorTest relies on this EXACT log line.
|
||||
LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet "
|
||||
"is missing absolute send time extension!";
|
||||
return;
|
||||
}
|
||||
IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime,
|
||||
payload_size, header.ssrc, PacketInfo::kNotAProbe);
|
||||
}
|
||||
|
||||
void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header,
|
||||
int probe_cluster_id) {
|
||||
RTC_DCHECK(network_thread_.CalledOnValidThread());
|
||||
if (!header.extension.hasAbsoluteSendTime) {
|
||||
// NOTE! The BitrateEstimatorTest relies on this EXACT log line.
|
||||
LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet "
|
||||
"is missing absolute send time extension!";
|
||||
return;
|
||||
}
|
||||
IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime,
|
||||
payload_size, header.ssrc, probe_cluster_id);
|
||||
}
|
||||
|
||||
void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
|
||||
uint32_t send_time_24bits,
|
||||
size_t payload_size,
|
||||
@ -243,13 +215,13 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
|
||||
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
|
||||
int64_t send_time_ms = static_cast<int64_t>(timestamp) * kTimestampToMs;
|
||||
|
||||
int64_t now_ms = arrival_time_ms;
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
// TODO(holmer): SSRCs are only needed for REMB, should be broken out from
|
||||
// here.
|
||||
incoming_bitrate_.Update(payload_size, now_ms);
|
||||
incoming_bitrate_.Update(payload_size, arrival_time_ms);
|
||||
|
||||
if (first_packet_time_ms_ == -1)
|
||||
first_packet_time_ms_ = arrival_time_ms;
|
||||
first_packet_time_ms_ = now_ms;
|
||||
|
||||
uint32_t ts_delta = 0;
|
||||
int64_t t_delta = 0;
|
||||
@ -294,8 +266,9 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
|
||||
if (ProcessClusters(now_ms) == ProbeResult::kBitrateUpdated)
|
||||
update_estimate = true;
|
||||
}
|
||||
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size,
|
||||
&ts_delta, &t_delta, &size_delta)) {
|
||||
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, now_ms,
|
||||
payload_size, &ts_delta, &t_delta,
|
||||
&size_delta)) {
|
||||
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
|
||||
estimator_->Update(t_delta, ts_delta_ms, size_delta, detector_.State());
|
||||
detector_.Detect(estimator_->offset(), ts_delta_ms,
|
||||
@ -309,7 +282,8 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
|
||||
now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) {
|
||||
update_estimate = true;
|
||||
} else if (detector_.State() == kBwOverusing) {
|
||||
rtc::Optional<uint32_t> incoming_rate = incoming_bitrate_.Rate(now_ms);
|
||||
rtc::Optional<uint32_t> incoming_rate =
|
||||
incoming_bitrate_.Rate(arrival_time_ms);
|
||||
if (incoming_rate &&
|
||||
remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) {
|
||||
update_estimate = true;
|
||||
@ -322,7 +296,7 @@ void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
|
||||
// We also have to update the estimate immediately if we are overusing
|
||||
// and the target bitrate is too high compared to what we are receiving.
|
||||
const RateControlInput input(detector_.State(),
|
||||
incoming_bitrate_.Rate(now_ms),
|
||||
incoming_bitrate_.Rate(arrival_time_ms),
|
||||
estimator_->var_noise());
|
||||
remote_rate_.Update(&input, now_ms);
|
||||
target_bitrate_bps = remote_rate_.UpdateBandwidthEstimate(now_ms);
|
||||
|
||||
@ -32,7 +32,7 @@ namespace webrtc {
|
||||
|
||||
class DelayBasedBwe : public RemoteBitrateEstimator {
|
||||
public:
|
||||
explicit DelayBasedBwe(RemoteBitrateObserver* observer);
|
||||
DelayBasedBwe(RemoteBitrateObserver* observer, Clock* clock);
|
||||
virtual ~DelayBasedBwe() {}
|
||||
|
||||
void IncomingPacketFeedbackVector(
|
||||
@ -40,12 +40,9 @@ class DelayBasedBwe : public RemoteBitrateEstimator {
|
||||
|
||||
void IncomingPacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header) override;
|
||||
|
||||
void IncomingPacket(int64_t arrival_time_ms,
|
||||
size_t payload_size,
|
||||
const RTPHeader& header,
|
||||
int probe_cluster_id);
|
||||
const RTPHeader& header) override {
|
||||
RTC_NOTREACHED();
|
||||
}
|
||||
|
||||
// This class relies on Process() being called periodically (at least once
|
||||
// every other second) for streams to be timed out properly. Therefore it
|
||||
@ -126,13 +123,12 @@ class DelayBasedBwe : public RemoteBitrateEstimator {
|
||||
void TimeoutStreams(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_);
|
||||
|
||||
rtc::ThreadChecker network_thread_;
|
||||
Clock* const clock_;
|
||||
RemoteBitrateObserver* const observer_;
|
||||
std::unique_ptr<InterArrival> inter_arrival_;
|
||||
std::unique_ptr<OveruseEstimator> estimator_;
|
||||
OveruseDetector detector_;
|
||||
RateStatistics incoming_bitrate_;
|
||||
std::vector<int> recent_propagation_delta_ms_;
|
||||
std::vector<int64_t> recent_update_time_ms_;
|
||||
std::list<Probe> probes_;
|
||||
size_t total_probes_received_;
|
||||
int64_t first_packet_time_ms_;
|
||||
|
||||
@ -8,116 +8,75 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/pacing/paced_sender.h"
|
||||
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
|
||||
#include "webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class TestDelayBasedBwe : public ::testing::Test, public RemoteBitrateObserver {
|
||||
public:
|
||||
static constexpr int kArrivalTimeClockOffsetMs = 60000;
|
||||
static constexpr int kNumProbes = 5;
|
||||
namespace {
|
||||
|
||||
TestDelayBasedBwe()
|
||||
: bwe_(this), clock_(0), bitrate_updated_(false), latest_bitrate_(0) {}
|
||||
constexpr int kNumProbes = 5;
|
||||
} // namespace
|
||||
|
||||
uint32_t AbsSendTime(int64_t t, int64_t denom) {
|
||||
return (((t << 18) + (denom >> 1)) / denom) & 0x00fffffful;
|
||||
}
|
||||
|
||||
void IncomingPacket(uint32_t ssrc,
|
||||
size_t payload_size,
|
||||
int64_t arrival_time,
|
||||
uint32_t rtp_timestamp,
|
||||
uint32_t absolute_send_time,
|
||||
int probe_cluster_id) {
|
||||
RTPHeader header;
|
||||
memset(&header, 0, sizeof(header));
|
||||
header.ssrc = ssrc;
|
||||
header.timestamp = rtp_timestamp;
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime = absolute_send_time;
|
||||
bwe_.IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs, payload_size,
|
||||
header, probe_cluster_id);
|
||||
}
|
||||
|
||||
void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
|
||||
uint32_t bitrate) {
|
||||
bitrate_updated_ = true;
|
||||
latest_bitrate_ = bitrate;
|
||||
}
|
||||
|
||||
bool bitrate_updated() {
|
||||
bool res = bitrate_updated_;
|
||||
bitrate_updated_ = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
int latest_bitrate() { return latest_bitrate_; }
|
||||
|
||||
DelayBasedBwe bwe_;
|
||||
SimulatedClock clock_;
|
||||
|
||||
private:
|
||||
bool bitrate_updated_;
|
||||
int latest_bitrate_;
|
||||
};
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetection) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetection) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
|
||||
// First burst sent at 8 * 1000 / 10 = 800 kbps.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 0);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 0);
|
||||
}
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
|
||||
// Second burst sent at 8 * 1000 / 5 = 1600 kbps.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(5);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_GT(latest_bitrate(), 1500000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), 1500000u);
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionNonPacedPackets) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionNonPacedPackets) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// First burst sent at 8 * 1000 / 10 = 800 kbps, but with every other packet
|
||||
// not being paced which could mess things up.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(5);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 0);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 0);
|
||||
// Non-paced packet, arriving 5 ms after.
|
||||
clock_.AdvanceTimeMilliseconds(5);
|
||||
IncomingPacket(0, PacedSender::kMinProbePacketSize + 1, now_ms, 90 * now_ms,
|
||||
AbsSendTime(now_ms, 1000), PacketInfo::kNotAProbe);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++,
|
||||
PacedSender::kMinProbePacketSize + 1,
|
||||
PacketInfo::kNotAProbe);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_GT(latest_bitrate(), 800000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), 800000u);
|
||||
}
|
||||
|
||||
// Packets will require 5 ms to be transmitted to the receiver, causing packets
|
||||
// of the second probe to be dispersed.
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionTooHighBitrate) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionTooHighBitrate) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
int64_t send_time_ms = 0;
|
||||
uint16_t seq_num = 0;
|
||||
// First burst sent at 8 * 1000 / 10 = 800 kbps.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
send_time_ms += 10;
|
||||
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 0);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 0);
|
||||
}
|
||||
|
||||
// Second burst sent at 8 * 1000 / 5 = 1600 kbps, arriving at 8 * 1000 / 8 =
|
||||
@ -126,16 +85,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionTooHighBitrate) {
|
||||
clock_.AdvanceTimeMilliseconds(8);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
send_time_ms += 5;
|
||||
IncomingPacket(0, 1000, now_ms, send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_NEAR(latest_bitrate(), 800000, 10000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 800000u, 10000u);
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionSlightlyFasterArrival) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionSlightlyFasterArrival) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// First burst sent at 8 * 1000 / 10 = 800 kbps.
|
||||
// Arriving at 8 * 1000 / 5 = 1600 kbps.
|
||||
int64_t send_time_ms = 0;
|
||||
@ -143,16 +102,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlightlyFasterArrival) {
|
||||
clock_.AdvanceTimeMilliseconds(5);
|
||||
send_time_ms += 10;
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 23);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 23);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_GT(latest_bitrate(), 800000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), 800000u);
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionFasterArrival) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionFasterArrival) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// First burst sent at 8 * 1000 / 10 = 800 kbps.
|
||||
// Arriving at 8 * 1000 / 5 = 1600 kbps.
|
||||
int64_t send_time_ms = 0;
|
||||
@ -160,15 +119,15 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionFasterArrival) {
|
||||
clock_.AdvanceTimeMilliseconds(1);
|
||||
send_time_ms += 10;
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 0);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 0);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(bitrate_updated());
|
||||
EXPECT_FALSE(bitrate_observer_->updated());
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrival) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrival) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// First burst sent at 8 * 1000 / 5 = 1600 kbps.
|
||||
// Arriving at 8 * 1000 / 7 = 1142 kbps.
|
||||
int64_t send_time_ms = 0;
|
||||
@ -176,16 +135,16 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrival) {
|
||||
clock_.AdvanceTimeMilliseconds(7);
|
||||
send_time_ms += 5;
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_NEAR(latest_bitrate(), 1140000, 10000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 1140000u, 10000u);
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrivalHighBitrate) {
|
||||
TEST_F(DelayBasedBweTest, ProbeDetectionSlowerArrivalHighBitrate) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// Burst sent at 8 * 1000 / 1 = 8000 kbps.
|
||||
// Arriving at 8 * 1000 / 2 = 4000 kbps.
|
||||
int64_t send_time_ms = 0;
|
||||
@ -193,39 +152,106 @@ TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrivalHighBitrate) {
|
||||
clock_.AdvanceTimeMilliseconds(2);
|
||||
send_time_ms += 1;
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
|
||||
AbsSendTime(send_time_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, 1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_NEAR(latest_bitrate(), 4000000u, 10000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 4000000u, 10000u);
|
||||
}
|
||||
|
||||
TEST_F(TestDelayBasedBwe, ProbingIgnoresSmallPackets) {
|
||||
TEST_F(DelayBasedBweTest, ProbingIgnoresSmallPackets) {
|
||||
int64_t now_ms = clock_.TimeInMilliseconds();
|
||||
uint16_t seq_num = 0;
|
||||
// Probing with 200 bytes every 10 ms, should be ignored by the probe
|
||||
// detection.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, PacedSender::kMinProbePacketSize, now_ms, 90 * now_ms,
|
||||
AbsSendTime(now_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++,
|
||||
PacedSender::kMinProbePacketSize, 1);
|
||||
}
|
||||
|
||||
EXPECT_FALSE(bitrate_updated());
|
||||
EXPECT_FALSE(bitrate_observer_->updated());
|
||||
|
||||
// Followed by a probe with 1000 bytes packets, should be detected as a
|
||||
// probe.
|
||||
for (int i = 0; i < kNumProbes; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
now_ms = clock_.TimeInMilliseconds();
|
||||
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000), 1);
|
||||
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, 1);
|
||||
}
|
||||
|
||||
// Wait long enough so that we can call Process again.
|
||||
clock_.AdvanceTimeMilliseconds(1000);
|
||||
|
||||
EXPECT_TRUE(bitrate_updated());
|
||||
EXPECT_NEAR(latest_bitrate(), 800000u, 10000);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(bitrate_observer_->latest_bitrate(), 800000u, 10000u);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, InitialBehavior) {
|
||||
InitialBehaviorTestHelper(674840);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, RateIncreaseReordering) {
|
||||
RateIncreaseReorderingTestHelper(674840);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, RateIncreaseRtpTimestamps) {
|
||||
RateIncreaseRtpTimestampsTestHelper(1240);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropOneStream) {
|
||||
CapacityDropTestHelper(1, false, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropPosOffsetChange) {
|
||||
CapacityDropTestHelper(1, false, 200, 30000);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropNegOffsetChange) {
|
||||
CapacityDropTestHelper(1, false, 733, -30000);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropOneStreamWrap) {
|
||||
CapacityDropTestHelper(1, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropTwoStreamsWrap) {
|
||||
CapacityDropTestHelper(2, true, 567, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropThreeStreamsWrap) {
|
||||
CapacityDropTestHelper(3, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropThirteenStreamsWrap) {
|
||||
CapacityDropTestHelper(13, true, 733, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropNineteenStreamsWrap) {
|
||||
CapacityDropTestHelper(19, true, 667, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, CapacityDropThirtyStreamsWrap) {
|
||||
CapacityDropTestHelper(30, true, 667, 0);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, TestTimestampGrouping) {
|
||||
TestTimestampGroupingTestHelper();
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, TestShortTimeoutAndWrap) {
|
||||
// Simulate a client leaving and rejoining the call after 35 seconds. This
|
||||
// will make abs send time wrap, so if streams aren't timed out properly
|
||||
// the next 30 seconds of packets will be out of order.
|
||||
TestWrappingHelper(35);
|
||||
}
|
||||
|
||||
TEST_F(DelayBasedBweTest, TestLongTimeoutAndWrap) {
|
||||
// Simulate a client leaving and rejoining the call after some multiple of
|
||||
// 64 seconds later. This will cause a zero difference in abs send times due
|
||||
// to the wrap, but a big difference in arrival time, if streams aren't
|
||||
// properly timed out.
|
||||
TestWrappingHelper(10 * 64);
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
#include "webrtc/modules/congestion_controller/delay_based_bwe_unittest_helper.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const size_t kMtu = 1200;
|
||||
const uint32_t kAcceptedBitrateErrorBps = 50000;
|
||||
|
||||
// Number of packets needed before we have a valid estimate.
|
||||
const int kNumInitialPackets = 2;
|
||||
|
||||
namespace test {
|
||||
|
||||
void TestBitrateObserver::OnReceiveBitrateChanged(
|
||||
const std::vector<uint32_t>& ssrcs,
|
||||
uint32_t bitrate) {
|
||||
latest_bitrate_ = bitrate;
|
||||
updated_ = true;
|
||||
}
|
||||
|
||||
RtpStream::RtpStream(int fps, int bitrate_bps)
|
||||
: fps_(fps),
|
||||
bitrate_bps_(bitrate_bps),
|
||||
next_rtp_time_(0),
|
||||
sequence_number_(0) {
|
||||
RTC_CHECK_GT(fps_, 0);
|
||||
}
|
||||
|
||||
// Generates a new frame for this stream. If called too soon after the
|
||||
// previous frame, no frame will be generated. The frame is split into
|
||||
// packets.
|
||||
int64_t RtpStream::GenerateFrame(int64_t time_now_us,
|
||||
std::vector<PacketInfo>* packets) {
|
||||
if (time_now_us < next_rtp_time_) {
|
||||
return next_rtp_time_;
|
||||
}
|
||||
RTC_CHECK(packets != NULL);
|
||||
size_t bits_per_frame = (bitrate_bps_ + fps_ / 2) / fps_;
|
||||
size_t n_packets =
|
||||
std::max<size_t>((bits_per_frame + 4 * kMtu) / (8 * kMtu), 1u);
|
||||
size_t payload_size = (bits_per_frame + 4 * n_packets) / (8 * n_packets);
|
||||
for (size_t i = 0; i < n_packets; ++i) {
|
||||
PacketInfo packet(-1, sequence_number_++);
|
||||
packet.send_time_ms = (time_now_us + kSendSideOffsetUs) / 1000;
|
||||
packet.payload_size = payload_size;
|
||||
packet.probe_cluster_id = PacketInfo::kNotAProbe;
|
||||
packets->push_back(packet);
|
||||
}
|
||||
next_rtp_time_ = time_now_us + (1000000 + fps_ / 2) / fps_;
|
||||
return next_rtp_time_;
|
||||
}
|
||||
|
||||
// The send-side time when the next frame can be generated.
|
||||
int64_t RtpStream::next_rtp_time() const {
|
||||
return next_rtp_time_;
|
||||
}
|
||||
|
||||
void RtpStream::set_bitrate_bps(int bitrate_bps) {
|
||||
ASSERT_GE(bitrate_bps, 0);
|
||||
bitrate_bps_ = bitrate_bps;
|
||||
}
|
||||
|
||||
int RtpStream::bitrate_bps() const {
|
||||
return bitrate_bps_;
|
||||
}
|
||||
|
||||
bool RtpStream::Compare(const std::unique_ptr<RtpStream>& lhs,
|
||||
const std::unique_ptr<RtpStream>& rhs) {
|
||||
return lhs->next_rtp_time_ < rhs->next_rtp_time_;
|
||||
}
|
||||
|
||||
StreamGenerator::StreamGenerator(int capacity, int64_t time_now)
|
||||
: capacity_(capacity), prev_arrival_time_us_(time_now) {}
|
||||
|
||||
// Add a new stream.
|
||||
void StreamGenerator::AddStream(RtpStream* stream) {
|
||||
streams_.push_back(std::unique_ptr<RtpStream>(stream));
|
||||
}
|
||||
|
||||
// Set the link capacity.
|
||||
void StreamGenerator::set_capacity_bps(int capacity_bps) {
|
||||
ASSERT_GT(capacity_bps, 0);
|
||||
capacity_ = capacity_bps;
|
||||
}
|
||||
|
||||
// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
|
||||
// is decided by the current allocation ratios.
|
||||
void StreamGenerator::SetBitrateBps(int bitrate_bps) {
|
||||
ASSERT_GE(streams_.size(), 0u);
|
||||
int total_bitrate_before = 0;
|
||||
for (const auto& stream : streams_) {
|
||||
total_bitrate_before += stream->bitrate_bps();
|
||||
}
|
||||
int64_t bitrate_before = 0;
|
||||
int total_bitrate_after = 0;
|
||||
for (const auto& stream : streams_) {
|
||||
bitrate_before += stream->bitrate_bps();
|
||||
int64_t bitrate_after =
|
||||
(bitrate_before * bitrate_bps + total_bitrate_before / 2) /
|
||||
total_bitrate_before;
|
||||
stream->set_bitrate_bps(bitrate_after - total_bitrate_after);
|
||||
total_bitrate_after += stream->bitrate_bps();
|
||||
}
|
||||
ASSERT_EQ(bitrate_before, total_bitrate_before);
|
||||
EXPECT_EQ(total_bitrate_after, bitrate_bps);
|
||||
}
|
||||
|
||||
// TODO(holmer): Break out the channel simulation part from this class to make
|
||||
// it possible to simulate different types of channels.
|
||||
int64_t StreamGenerator::GenerateFrame(std::vector<PacketInfo>* packets,
|
||||
int64_t time_now_us) {
|
||||
RTC_CHECK(packets != NULL);
|
||||
RTC_CHECK(packets->empty());
|
||||
RTC_CHECK_GT(capacity_, 0);
|
||||
auto it =
|
||||
std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
|
||||
(*it)->GenerateFrame(time_now_us, packets);
|
||||
int i = 0;
|
||||
for (PacketInfo& packet : *packets) {
|
||||
int capacity_bpus = capacity_ / 1000;
|
||||
int64_t required_network_time_us =
|
||||
(8 * 1000 * packet.payload_size + capacity_bpus / 2) / capacity_bpus;
|
||||
prev_arrival_time_us_ =
|
||||
std::max(time_now_us + required_network_time_us,
|
||||
prev_arrival_time_us_ + required_network_time_us);
|
||||
packet.arrival_time_ms = prev_arrival_time_us_ / 1000;
|
||||
++i;
|
||||
}
|
||||
it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
|
||||
return std::max((*it)->next_rtp_time(), time_now_us);
|
||||
}
|
||||
} // namespace test
|
||||
|
||||
DelayBasedBweTest::DelayBasedBweTest()
|
||||
: clock_(100000000),
|
||||
bitrate_observer_(new test::TestBitrateObserver),
|
||||
bitrate_estimator_(new DelayBasedBwe(bitrate_observer_.get(), &clock_)),
|
||||
stream_generator_(
|
||||
new test::StreamGenerator(1e6, // Capacity.
|
||||
clock_.TimeInMicroseconds())),
|
||||
arrival_time_offset_ms_(0) {}
|
||||
|
||||
DelayBasedBweTest::~DelayBasedBweTest() {}
|
||||
|
||||
void DelayBasedBweTest::AddDefaultStream() {
|
||||
stream_generator_->AddStream(new test::RtpStream(30, 3e5));
|
||||
}
|
||||
|
||||
const uint32_t DelayBasedBweTest::kDefaultSsrc = 0;
|
||||
|
||||
void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms,
|
||||
int64_t send_time_ms,
|
||||
uint16_t sequence_number,
|
||||
size_t payload_size) {
|
||||
IncomingFeedback(arrival_time_ms, send_time_ms, sequence_number, payload_size,
|
||||
0);
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::IncomingFeedback(int64_t arrival_time_ms,
|
||||
int64_t send_time_ms,
|
||||
uint16_t sequence_number,
|
||||
size_t payload_size,
|
||||
int probe_cluster_id) {
|
||||
RTC_CHECK_GE(arrival_time_ms + arrival_time_offset_ms_, 0);
|
||||
PacketInfo packet(arrival_time_ms + arrival_time_offset_ms_, send_time_ms,
|
||||
sequence_number, payload_size, probe_cluster_id);
|
||||
std::vector<PacketInfo> packets;
|
||||
packets.push_back(packet);
|
||||
bitrate_estimator_->IncomingPacketFeedbackVector(packets);
|
||||
}
|
||||
|
||||
// Generates a frame of packets belonging to a stream at a given bitrate and
|
||||
// with a given ssrc. The stream is pushed through a very simple simulated
|
||||
// network, and is then given to the receive-side bandwidth estimator.
|
||||
// Returns true if an over-use was seen, false otherwise.
|
||||
// The StreamGenerator::updated() should be used to check for any changes in
|
||||
// target bitrate after the call to this function.
|
||||
bool DelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc,
|
||||
uint32_t bitrate_bps) {
|
||||
stream_generator_->SetBitrateBps(bitrate_bps);
|
||||
std::vector<PacketInfo> packets;
|
||||
int64_t next_time_us =
|
||||
stream_generator_->GenerateFrame(&packets, clock_.TimeInMicroseconds());
|
||||
if (packets.empty())
|
||||
return false;
|
||||
|
||||
bool overuse = false;
|
||||
bitrate_observer_->Reset();
|
||||
clock_.AdvanceTimeMicroseconds(1000 * packets.back().arrival_time_ms -
|
||||
clock_.TimeInMicroseconds());
|
||||
for (auto& packet : packets) {
|
||||
RTC_CHECK_GE(packet.arrival_time_ms + arrival_time_offset_ms_, 0);
|
||||
packet.arrival_time_ms += arrival_time_offset_ms_;
|
||||
}
|
||||
bitrate_estimator_->IncomingPacketFeedbackVector(packets);
|
||||
|
||||
if (bitrate_observer_->updated()) {
|
||||
if (bitrate_observer_->latest_bitrate() < bitrate_bps)
|
||||
overuse = true;
|
||||
}
|
||||
|
||||
clock_.AdvanceTimeMicroseconds(next_time_us - clock_.TimeInMicroseconds());
|
||||
return overuse;
|
||||
}
|
||||
|
||||
// Run the bandwidth estimator with a stream of |number_of_frames| frames, or
|
||||
// until it reaches |target_bitrate|.
|
||||
// Can for instance be used to run the estimator for some time to get it
|
||||
// into a steady state.
|
||||
uint32_t DelayBasedBweTest::SteadyStateRun(uint32_t ssrc,
|
||||
int max_number_of_frames,
|
||||
uint32_t start_bitrate,
|
||||
uint32_t min_bitrate,
|
||||
uint32_t max_bitrate,
|
||||
uint32_t target_bitrate) {
|
||||
uint32_t bitrate_bps = start_bitrate;
|
||||
bool bitrate_update_seen = false;
|
||||
// Produce |number_of_frames| frames and give them to the estimator.
|
||||
for (int i = 0; i < max_number_of_frames; ++i) {
|
||||
bool overuse = GenerateAndProcessFrame(ssrc, bitrate_bps);
|
||||
if (overuse) {
|
||||
EXPECT_LT(bitrate_observer_->latest_bitrate(), max_bitrate);
|
||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), min_bitrate);
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
bitrate_update_seen = true;
|
||||
} else if (bitrate_observer_->updated()) {
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
bitrate_observer_->Reset();
|
||||
}
|
||||
if (bitrate_update_seen && bitrate_bps > target_bitrate) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_TRUE(bitrate_update_seen);
|
||||
return bitrate_bps;
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::InitialBehaviorTestHelper(
|
||||
uint32_t expected_converge_bitrate) {
|
||||
const int kFramerate = 50; // 50 fps to avoid rounding errors.
|
||||
const int kFrameIntervalMs = 1000 / kFramerate;
|
||||
uint32_t bitrate_bps = 0;
|
||||
int64_t send_time_ms = 0;
|
||||
uint16_t sequence_number = 0;
|
||||
std::vector<uint32_t> ssrcs;
|
||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
|
||||
EXPECT_EQ(0u, ssrcs.size());
|
||||
clock_.AdvanceTimeMilliseconds(1000);
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
|
||||
EXPECT_FALSE(bitrate_observer_->updated());
|
||||
bitrate_observer_->Reset();
|
||||
clock_.AdvanceTimeMilliseconds(1000);
|
||||
// Inserting packets for 5 seconds to get a valid estimate.
|
||||
for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) {
|
||||
if (i == kNumInitialPackets) {
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_FALSE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
|
||||
EXPECT_EQ(0u, ssrcs.size());
|
||||
EXPECT_FALSE(bitrate_observer_->updated());
|
||||
bitrate_observer_->Reset();
|
||||
}
|
||||
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, kMtu);
|
||||
clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
|
||||
send_time_ms += kFrameIntervalMs;
|
||||
}
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
|
||||
ASSERT_EQ(1u, ssrcs.size());
|
||||
EXPECT_EQ(kDefaultSsrc, ssrcs.front());
|
||||
EXPECT_NEAR(expected_converge_bitrate, bitrate_bps, kAcceptedBitrateErrorBps);
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
bitrate_observer_->Reset();
|
||||
EXPECT_EQ(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
||||
bitrate_estimator_->RemoveStream(kDefaultSsrc);
|
||||
EXPECT_TRUE(bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_bps));
|
||||
ASSERT_EQ(0u, ssrcs.size());
|
||||
EXPECT_EQ(0u, bitrate_bps);
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::RateIncreaseReorderingTestHelper(
|
||||
uint32_t expected_bitrate_bps) {
|
||||
const int kFramerate = 50; // 50 fps to avoid rounding errors.
|
||||
const int kFrameIntervalMs = 1000 / kFramerate;
|
||||
int64_t send_time_ms = 0;
|
||||
uint16_t sequence_number = 0;
|
||||
// Inserting packets for five seconds to get a valid estimate.
|
||||
for (int i = 0; i < 5 * kFramerate + 1 + kNumInitialPackets; ++i) {
|
||||
// TODO(sprang): Remove this hack once the single stream estimator is gone,
|
||||
// as it doesn't do anything in Process().
|
||||
if (i == kNumInitialPackets) {
|
||||
// Process after we have enough frames to get a valid input rate estimate.
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_FALSE(bitrate_observer_->updated()); // No valid estimate.
|
||||
}
|
||||
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, kMtu);
|
||||
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
|
||||
send_time_ms += kFrameIntervalMs;
|
||||
}
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_->latest_bitrate(),
|
||||
kAcceptedBitrateErrorBps);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
|
||||
send_time_ms += 2 * kFrameIntervalMs;
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number + 2, 1000);
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(),
|
||||
send_time_ms - kFrameIntervalMs, sequence_number + 1,
|
||||
1000);
|
||||
sequence_number += 2;
|
||||
}
|
||||
bitrate_estimator_->Process();
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_NEAR(expected_bitrate_bps, bitrate_observer_->latest_bitrate(),
|
||||
kAcceptedBitrateErrorBps);
|
||||
}
|
||||
|
||||
// Make sure we initially increase the bitrate as expected.
|
||||
void DelayBasedBweTest::RateIncreaseRtpTimestampsTestHelper(
|
||||
int expected_iterations) {
|
||||
// This threshold corresponds approximately to increasing linearly with
|
||||
// bitrate(i) = 1.04 * bitrate(i-1) + 1000
|
||||
// until bitrate(i) > 500000, with bitrate(1) ~= 30000.
|
||||
uint32_t bitrate_bps = 30000;
|
||||
int iterations = 0;
|
||||
AddDefaultStream();
|
||||
// Feed the estimator with a stream of packets and verify that it reaches
|
||||
// 500 kbps at the expected time.
|
||||
while (bitrate_bps < 5e5) {
|
||||
bool overuse = GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
|
||||
if (overuse) {
|
||||
EXPECT_GT(bitrate_observer_->latest_bitrate(), bitrate_bps);
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
bitrate_observer_->Reset();
|
||||
} else if (bitrate_observer_->updated()) {
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
bitrate_observer_->Reset();
|
||||
}
|
||||
++iterations;
|
||||
ASSERT_LE(iterations, expected_iterations);
|
||||
}
|
||||
ASSERT_EQ(expected_iterations, iterations);
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::CapacityDropTestHelper(
|
||||
int number_of_streams,
|
||||
bool wrap_time_stamp,
|
||||
uint32_t expected_bitrate_drop_delta,
|
||||
int64_t receiver_clock_offset_change_ms) {
|
||||
const int kFramerate = 30;
|
||||
const int kStartBitrate = 900e3;
|
||||
const int kMinExpectedBitrate = 800e3;
|
||||
const int kMaxExpectedBitrate = 1100e3;
|
||||
const uint32_t kInitialCapacityBps = 1000e3;
|
||||
const uint32_t kReducedCapacityBps = 500e3;
|
||||
|
||||
int steady_state_time = 0;
|
||||
if (number_of_streams <= 1) {
|
||||
steady_state_time = 10;
|
||||
AddDefaultStream();
|
||||
} else {
|
||||
steady_state_time = 10 * number_of_streams;
|
||||
int bitrate_sum = 0;
|
||||
int kBitrateDenom = number_of_streams * (number_of_streams - 1);
|
||||
for (int i = 0; i < number_of_streams; i++) {
|
||||
// First stream gets half available bitrate, while the rest share the
|
||||
// remaining half i.e.: 1/2 = Sum[n/(N*(N-1))] for n=1..N-1 (rounded up)
|
||||
int bitrate = kStartBitrate / 2;
|
||||
if (i > 0) {
|
||||
bitrate = (kStartBitrate * i + kBitrateDenom / 2) / kBitrateDenom;
|
||||
}
|
||||
stream_generator_->AddStream(new test::RtpStream(kFramerate, bitrate));
|
||||
bitrate_sum += bitrate;
|
||||
}
|
||||
ASSERT_EQ(bitrate_sum, kStartBitrate);
|
||||
}
|
||||
|
||||
// Run in steady state to make the estimator converge.
|
||||
stream_generator_->set_capacity_bps(kInitialCapacityBps);
|
||||
uint32_t bitrate_bps = SteadyStateRun(
|
||||
kDefaultSsrc, steady_state_time * kFramerate, kStartBitrate,
|
||||
kMinExpectedBitrate, kMaxExpectedBitrate, kInitialCapacityBps);
|
||||
EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 130000u);
|
||||
bitrate_observer_->Reset();
|
||||
|
||||
// Add an offset to make sure the BWE can handle it.
|
||||
arrival_time_offset_ms_ += receiver_clock_offset_change_ms;
|
||||
|
||||
// Reduce the capacity and verify the decrease time.
|
||||
stream_generator_->set_capacity_bps(kReducedCapacityBps);
|
||||
int64_t overuse_start_time = clock_.TimeInMilliseconds();
|
||||
int64_t bitrate_drop_time = -1;
|
||||
for (int i = 0; i < 100 * number_of_streams; ++i) {
|
||||
GenerateAndProcessFrame(kDefaultSsrc, bitrate_bps);
|
||||
if (bitrate_drop_time == -1 &&
|
||||
bitrate_observer_->latest_bitrate() <= kReducedCapacityBps) {
|
||||
bitrate_drop_time = clock_.TimeInMilliseconds();
|
||||
}
|
||||
if (bitrate_observer_->updated())
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
}
|
||||
|
||||
EXPECT_NEAR(expected_bitrate_drop_delta,
|
||||
bitrate_drop_time - overuse_start_time, 33);
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::TestTimestampGroupingTestHelper() {
|
||||
const int kFramerate = 50; // 50 fps to avoid rounding errors.
|
||||
const int kFrameIntervalMs = 1000 / kFramerate;
|
||||
int64_t send_time_ms = 0;
|
||||
uint16_t sequence_number = 0;
|
||||
// Initial set of frames to increase the bitrate. 6 seconds to have enough
|
||||
// time for the first estimate to be generated and for Process() to be called.
|
||||
for (int i = 0; i <= 6 * kFramerate; ++i) {
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, 1000);
|
||||
|
||||
bitrate_estimator_->Process();
|
||||
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
|
||||
send_time_ms += kFrameIntervalMs;
|
||||
}
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
EXPECT_GE(bitrate_observer_->latest_bitrate(), 400000u);
|
||||
|
||||
// Insert batches of frames which were sent very close in time. Also simulate
|
||||
// capacity over-use to see that we back off correctly.
|
||||
const int kTimestampGroupLength = 15;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
for (int j = 0; j < kTimestampGroupLength; ++j) {
|
||||
// Insert |kTimestampGroupLength| frames with just 1 timestamp ticks in
|
||||
// between. Should be treated as part of the same group by the estimator.
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, 100);
|
||||
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs / kTimestampGroupLength);
|
||||
send_time_ms += 1;
|
||||
}
|
||||
// Increase time until next batch to simulate over-use.
|
||||
clock_.AdvanceTimeMilliseconds(10);
|
||||
send_time_ms += kFrameIntervalMs - kTimestampGroupLength;
|
||||
bitrate_estimator_->Process();
|
||||
}
|
||||
EXPECT_TRUE(bitrate_observer_->updated());
|
||||
// Should have reduced the estimate.
|
||||
EXPECT_LT(bitrate_observer_->latest_bitrate(), 400000u);
|
||||
}
|
||||
|
||||
void DelayBasedBweTest::TestWrappingHelper(int silence_time_s) {
|
||||
const int kFramerate = 100;
|
||||
const int kFrameIntervalMs = 1000 / kFramerate;
|
||||
int64_t send_time_ms = 0;
|
||||
uint16_t sequence_number = 0;
|
||||
|
||||
for (size_t i = 0; i < 3000; ++i) {
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, 1000);
|
||||
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
|
||||
send_time_ms += kFrameIntervalMs;
|
||||
bitrate_estimator_->Process();
|
||||
}
|
||||
uint32_t bitrate_before = 0;
|
||||
std::vector<uint32_t> ssrcs;
|
||||
bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_before);
|
||||
|
||||
clock_.AdvanceTimeMilliseconds(silence_time_s * 1000);
|
||||
send_time_ms += silence_time_s * 1000;
|
||||
bitrate_estimator_->Process();
|
||||
|
||||
for (size_t i = 0; i < 21; ++i) {
|
||||
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
|
||||
sequence_number++, 1000);
|
||||
clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
|
||||
send_time_ms += kFrameIntervalMs;
|
||||
bitrate_estimator_->Process();
|
||||
}
|
||||
uint32_t bitrate_after = 0;
|
||||
bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after);
|
||||
EXPECT_LT(bitrate_after, bitrate_before);
|
||||
}
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_
|
||||
#define WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "webrtc/base/constructormagic.h"
|
||||
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
|
||||
#include "webrtc/system_wrappers/include/clock.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
class TestBitrateObserver : public RemoteBitrateObserver {
|
||||
public:
|
||||
TestBitrateObserver() : updated_(false), latest_bitrate_(0) {}
|
||||
virtual ~TestBitrateObserver() {}
|
||||
|
||||
void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
|
||||
uint32_t bitrate) override;
|
||||
|
||||
void Reset() { updated_ = false; }
|
||||
|
||||
bool updated() const { return updated_; }
|
||||
|
||||
uint32_t latest_bitrate() const { return latest_bitrate_; }
|
||||
|
||||
private:
|
||||
bool updated_;
|
||||
uint32_t latest_bitrate_;
|
||||
};
|
||||
|
||||
class RtpStream {
|
||||
public:
|
||||
enum { kSendSideOffsetUs = 1000000 };
|
||||
|
||||
RtpStream(int fps, int bitrate_bps);
|
||||
|
||||
// Generates a new frame for this stream. If called too soon after the
|
||||
// previous frame, no frame will be generated. The frame is split into
|
||||
// packets.
|
||||
int64_t GenerateFrame(int64_t time_now_us, std::vector<PacketInfo>* packets);
|
||||
|
||||
// The send-side time when the next frame can be generated.
|
||||
int64_t next_rtp_time() const;
|
||||
|
||||
void set_bitrate_bps(int bitrate_bps);
|
||||
|
||||
int bitrate_bps() const;
|
||||
|
||||
static bool Compare(const std::unique_ptr<RtpStream>& lhs,
|
||||
const std::unique_ptr<RtpStream>& rhs);
|
||||
|
||||
private:
|
||||
int fps_;
|
||||
int bitrate_bps_;
|
||||
int64_t next_rtp_time_;
|
||||
uint16_t sequence_number_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RtpStream);
|
||||
};
|
||||
|
||||
class StreamGenerator {
|
||||
public:
|
||||
StreamGenerator(int capacity, int64_t time_now);
|
||||
|
||||
// Add a new stream.
|
||||
void AddStream(RtpStream* stream);
|
||||
|
||||
// Set the link capacity.
|
||||
void set_capacity_bps(int capacity_bps);
|
||||
|
||||
// Divides |bitrate_bps| among all streams. The allocated bitrate per stream
|
||||
// is decided by the initial allocation ratios.
|
||||
void SetBitrateBps(int bitrate_bps);
|
||||
|
||||
// Set the RTP timestamp offset for the stream identified by |ssrc|.
|
||||
void set_rtp_timestamp_offset(uint32_t ssrc, uint32_t offset);
|
||||
|
||||
// TODO(holmer): Break out the channel simulation part from this class to make
|
||||
// it possible to simulate different types of channels.
|
||||
int64_t GenerateFrame(std::vector<PacketInfo>* packets, int64_t time_now_us);
|
||||
|
||||
private:
|
||||
// Capacity of the simulated channel in bits per second.
|
||||
int capacity_;
|
||||
// The time when the last packet arrived.
|
||||
int64_t prev_arrival_time_us_;
|
||||
// All streams being transmitted on this simulated channel.
|
||||
std::vector<std::unique_ptr<RtpStream>> streams_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(StreamGenerator);
|
||||
};
|
||||
} // namespace test
|
||||
|
||||
class DelayBasedBweTest : public ::testing::Test {
|
||||
public:
|
||||
DelayBasedBweTest();
|
||||
virtual ~DelayBasedBweTest();
|
||||
|
||||
protected:
|
||||
void AddDefaultStream();
|
||||
|
||||
// Helpers to insert a single packet into the delay-based BWE.
|
||||
void IncomingFeedback(int64_t arrival_time_ms,
|
||||
int64_t send_time_ms,
|
||||
uint16_t sequence_number,
|
||||
size_t payload_size);
|
||||
void IncomingFeedback(int64_t arrival_time_ms,
|
||||
int64_t send_time_ms,
|
||||
uint16_t sequence_number,
|
||||
size_t payload_size,
|
||||
int probe_cluster_id);
|
||||
|
||||
// Generates a frame of packets belonging to a stream at a given bitrate and
|
||||
// with a given ssrc. The stream is pushed through a very simple simulated
|
||||
// network, and is then given to the receive-side bandwidth estimator.
|
||||
// Returns true if an over-use was seen, false otherwise.
|
||||
// The StreamGenerator::updated() should be used to check for any changes in
|
||||
// target bitrate after the call to this function.
|
||||
bool GenerateAndProcessFrame(uint32_t ssrc, uint32_t bitrate_bps);
|
||||
|
||||
// Run the bandwidth estimator with a stream of |number_of_frames| frames, or
|
||||
// until it reaches |target_bitrate|.
|
||||
// Can for instance be used to run the estimator for some time to get it
|
||||
// into a steady state.
|
||||
uint32_t SteadyStateRun(uint32_t ssrc,
|
||||
int number_of_frames,
|
||||
uint32_t start_bitrate,
|
||||
uint32_t min_bitrate,
|
||||
uint32_t max_bitrate,
|
||||
uint32_t target_bitrate);
|
||||
|
||||
void TestTimestampGroupingTestHelper();
|
||||
|
||||
void TestWrappingHelper(int silence_time_s);
|
||||
|
||||
void InitialBehaviorTestHelper(uint32_t expected_converge_bitrate);
|
||||
void RateIncreaseReorderingTestHelper(uint32_t expected_bitrate);
|
||||
void RateIncreaseRtpTimestampsTestHelper(int expected_iterations);
|
||||
void CapacityDropTestHelper(int number_of_streams,
|
||||
bool wrap_time_stamp,
|
||||
uint32_t expected_bitrate_drop_delta,
|
||||
int64_t receiver_clock_offset_change_ms);
|
||||
|
||||
static const uint32_t kDefaultSsrc;
|
||||
|
||||
SimulatedClock clock_; // Time at the receiver.
|
||||
std::unique_ptr<test::TestBitrateObserver> bitrate_observer_;
|
||||
std::unique_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
||||
std::unique_ptr<test::StreamGenerator> stream_generator_;
|
||||
int64_t arrival_time_offset_ms_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest);
|
||||
};
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_
|
||||
@ -274,6 +274,8 @@
|
||||
'bitrate_controller/send_side_bandwidth_estimation_unittest.cc',
|
||||
'congestion_controller/congestion_controller_unittest.cc',
|
||||
'congestion_controller/delay_based_bwe_unittest.cc',
|
||||
'congestion_controller/delay_based_bwe_unittest_helper.cc',
|
||||
'congestion_controller/delay_based_bwe_unittest_helper.h',
|
||||
'media_file/media_file_unittest.cc',
|
||||
'module_common_types_unittest.cc',
|
||||
'pacing/bitrate_prober_unittest.cc',
|
||||
|
||||
@ -27,10 +27,12 @@ InterArrival::InterArrival(uint32_t timestamp_group_length_ticks,
|
||||
current_timestamp_group_(),
|
||||
prev_timestamp_group_(),
|
||||
timestamp_to_ms_coeff_(timestamp_to_ms_coeff),
|
||||
burst_grouping_(enable_burst_grouping) {}
|
||||
burst_grouping_(enable_burst_grouping),
|
||||
num_consecutive_reordered_packets_(0) {}
|
||||
|
||||
bool InterArrival::ComputeDeltas(uint32_t timestamp,
|
||||
int64_t arrival_time_ms,
|
||||
int64_t system_time_ms,
|
||||
size_t packet_size,
|
||||
uint32_t* timestamp_delta,
|
||||
int64_t* arrival_time_delta_ms,
|
||||
@ -53,13 +55,32 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp,
|
||||
prev_timestamp_group_.timestamp;
|
||||
*arrival_time_delta_ms = current_timestamp_group_.complete_time_ms -
|
||||
prev_timestamp_group_.complete_time_ms;
|
||||
// Check system time differences to see if we have an unproportional jump
|
||||
// in arrival time. In that case reset the inter-arrival computations.
|
||||
int64_t system_time_delta_ms =
|
||||
current_timestamp_group_.last_system_time_ms -
|
||||
prev_timestamp_group_.last_system_time_ms;
|
||||
if (*arrival_time_delta_ms - system_time_delta_ms >=
|
||||
kArrivalTimeOffsetThresholdMs) {
|
||||
LOG(LS_WARNING) << "The arrival time clock offset has changed (diff = "
|
||||
<< *arrival_time_delta_ms - system_time_delta_ms
|
||||
<< " ms), resetting.";
|
||||
Reset();
|
||||
return false;
|
||||
}
|
||||
if (*arrival_time_delta_ms < 0) {
|
||||
// The group of packets has been reordered since receiving its local
|
||||
// arrival timestamp.
|
||||
LOG(LS_WARNING) << "Packets are being reordered on the path from the "
|
||||
"socket to the bandwidth estimator. Ignoring this "
|
||||
"packet for bandwidth estimation.";
|
||||
++num_consecutive_reordered_packets_;
|
||||
if (num_consecutive_reordered_packets_ >= kReorderedResetThreshold) {
|
||||
LOG(LS_WARNING) << "Packets are being reordered on the path from the "
|
||||
"socket to the bandwidth estimator. Ignoring this "
|
||||
"packet for bandwidth estimation, resetting.";
|
||||
Reset();
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
num_consecutive_reordered_packets_ = 0;
|
||||
}
|
||||
assert(*arrival_time_delta_ms >= 0);
|
||||
*packet_size_delta = static_cast<int>(current_timestamp_group_.size) -
|
||||
@ -78,6 +99,7 @@ bool InterArrival::ComputeDeltas(uint32_t timestamp,
|
||||
// Accumulate the frame size.
|
||||
current_timestamp_group_.size += packet_size;
|
||||
current_timestamp_group_.complete_time_ms = arrival_time_ms;
|
||||
current_timestamp_group_.last_system_time_ms = system_time_ms;
|
||||
|
||||
return calculated_deltas;
|
||||
}
|
||||
@ -126,4 +148,10 @@ bool InterArrival::BelongsToBurst(int64_t arrival_time_ms,
|
||||
return propagation_delta_ms < 0 &&
|
||||
arrival_time_delta_ms <= kBurstDeltaThresholdMs;
|
||||
}
|
||||
|
||||
void InterArrival::Reset() {
|
||||
num_consecutive_reordered_packets_ = 0;
|
||||
current_timestamp_group_ = TimestampGroup();
|
||||
prev_timestamp_group_ = TimestampGroup();
|
||||
}
|
||||
} // namespace webrtc
|
||||
|
||||
@ -23,6 +23,11 @@ namespace webrtc {
|
||||
// a client defined rate.
|
||||
class InterArrival {
|
||||
public:
|
||||
// After this many packet groups received out of order InterArrival will
|
||||
// reset, assuming that clocks have made a jump.
|
||||
static constexpr int kReorderedResetThreshold = 3;
|
||||
static constexpr int64_t kArrivalTimeOffsetThresholdMs = 3000;
|
||||
|
||||
// A timestamp group is defined as all packets with a timestamp which are at
|
||||
// most timestamp_group_length_ticks older than the first timestamp in that
|
||||
// group.
|
||||
@ -40,6 +45,7 @@ class InterArrival {
|
||||
// |packet_size_delta| (output) is the computed size delta.
|
||||
bool ComputeDeltas(uint32_t timestamp,
|
||||
int64_t arrival_time_ms,
|
||||
int64_t system_time_ms,
|
||||
size_t packet_size,
|
||||
uint32_t* timestamp_delta,
|
||||
int64_t* arrival_time_delta_ms,
|
||||
@ -61,6 +67,7 @@ class InterArrival {
|
||||
uint32_t first_timestamp;
|
||||
uint32_t timestamp;
|
||||
int64_t complete_time_ms;
|
||||
int64_t last_system_time_ms;
|
||||
};
|
||||
|
||||
// Returns true if the packet with timestamp |timestamp| arrived in order.
|
||||
@ -72,11 +79,14 @@ class InterArrival {
|
||||
|
||||
bool BelongsToBurst(int64_t arrival_time_ms, uint32_t timestamp) const;
|
||||
|
||||
void Reset();
|
||||
|
||||
const uint32_t kTimestampGroupLengthTicks;
|
||||
TimestampGroup current_timestamp_group_;
|
||||
TimestampGroup prev_timestamp_group_;
|
||||
double timestamp_to_ms_coeff_;
|
||||
bool burst_grouping_;
|
||||
int num_consecutive_reordered_packets_;
|
||||
|
||||
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(InterArrival);
|
||||
};
|
||||
|
||||
@ -34,6 +34,8 @@ const double kAstToMs = 1000.0 / static_cast<double>(1 << kInterArrivalShift);
|
||||
class InterArrivalTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
inter_arrival_.reset(
|
||||
new InterArrival(kTimestampGroupLengthUs / 1000, 1.0, true));
|
||||
inter_arrival_rtp_.reset(new InterArrival(
|
||||
MakeRtpTimestamp(kTimestampGroupLengthUs),
|
||||
kRtpTimestampToMs,
|
||||
@ -149,6 +151,8 @@ class InterArrivalTest : public ::testing::Test {
|
||||
timestamp_near);
|
||||
}
|
||||
|
||||
std::unique_ptr<InterArrival> inter_arrival_;
|
||||
|
||||
private:
|
||||
static uint32_t MakeRtpTimestamp(int64_t us) {
|
||||
return static_cast<uint32_t>(static_cast<uint64_t>(us * 90 + 500) / 1000);
|
||||
@ -166,12 +170,9 @@ class InterArrivalTest : public ::testing::Test {
|
||||
uint32_t dummy_timestamp = 101;
|
||||
int64_t dummy_arrival_time_ms = 303;
|
||||
int dummy_packet_size = 909;
|
||||
bool computed = inter_arrival->ComputeDeltas(timestamp,
|
||||
arrival_time_ms,
|
||||
packet_size,
|
||||
&dummy_timestamp,
|
||||
&dummy_arrival_time_ms,
|
||||
&dummy_packet_size);
|
||||
bool computed = inter_arrival->ComputeDeltas(
|
||||
timestamp, arrival_time_ms, arrival_time_ms, packet_size,
|
||||
&dummy_timestamp, &dummy_arrival_time_ms, &dummy_packet_size);
|
||||
EXPECT_EQ(computed, false);
|
||||
EXPECT_EQ(101ul, dummy_timestamp);
|
||||
EXPECT_EQ(303, dummy_arrival_time_ms);
|
||||
@ -188,12 +189,9 @@ class InterArrivalTest : public ::testing::Test {
|
||||
uint32_t delta_timestamp = 101;
|
||||
int64_t delta_arrival_time_ms = 303;
|
||||
int delta_packet_size = 909;
|
||||
bool computed = inter_arrival->ComputeDeltas(timestamp,
|
||||
arrival_time_ms,
|
||||
packet_size,
|
||||
&delta_timestamp,
|
||||
&delta_arrival_time_ms,
|
||||
&delta_packet_size);
|
||||
bool computed = inter_arrival->ComputeDeltas(
|
||||
timestamp, arrival_time_ms, arrival_time_ms, packet_size,
|
||||
&delta_timestamp, &delta_arrival_time_ms, &delta_packet_size);
|
||||
EXPECT_EQ(true, computed);
|
||||
EXPECT_NEAR(expected_timestamp_delta, delta_timestamp, timestamp_near);
|
||||
EXPECT_EQ(expected_arrival_time_delta_ms, delta_arrival_time_ms);
|
||||
@ -419,5 +417,121 @@ TEST_F(InterArrivalTest, RtpTimestampWrapOutOfOrderWithinGroup) {
|
||||
TEST_F(InterArrivalTest, AbsSendTimeWrapOutOfOrderWithinGroup) {
|
||||
WrapTestHelper(kStartAbsSendTimeWrapUs, 1, true);
|
||||
}
|
||||
|
||||
TEST_F(InterArrivalTest, PositiveArrivalTimeJump) {
|
||||
const size_t kPacketSize = 1000;
|
||||
uint32_t send_time_ms = 10000;
|
||||
int64_t arrival_time_ms = 20000;
|
||||
int64_t system_time_ms = 30000;
|
||||
|
||||
uint32_t send_delta;
|
||||
int64_t arrival_delta;
|
||||
int size_delta;
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
|
||||
const int kTimeDeltaMs = 30;
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs + InterArrival::kArrivalTimeOffsetThresholdMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_TRUE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, static_cast<int>(send_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, arrival_delta);
|
||||
EXPECT_EQ(size_delta, 0);
|
||||
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
// The previous arrival time jump should now be detected and cause a reset.
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
|
||||
// The two next packets will not give a valid delta since we're in the initial
|
||||
// state.
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
}
|
||||
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_TRUE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, static_cast<int>(send_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, arrival_delta);
|
||||
EXPECT_EQ(size_delta, 0);
|
||||
}
|
||||
|
||||
TEST_F(InterArrivalTest, NegativeArrivalTimeJump) {
|
||||
const size_t kPacketSize = 1000;
|
||||
uint32_t send_time_ms = 10000;
|
||||
int64_t arrival_time_ms = 20000;
|
||||
int64_t system_time_ms = 30000;
|
||||
|
||||
uint32_t send_delta;
|
||||
int64_t arrival_delta;
|
||||
int size_delta;
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
|
||||
const int kTimeDeltaMs = 30;
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_TRUE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, static_cast<int>(send_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, arrival_delta);
|
||||
EXPECT_EQ(size_delta, 0);
|
||||
|
||||
// Three out of order will fail, after that we will be reset and two more will
|
||||
// fail before we get our first valid delta after the reset.
|
||||
arrival_time_ms -= 1000;
|
||||
for (int i = 0; i < InterArrival::kReorderedResetThreshold + 3; ++i) {
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
// The previous arrival time jump should now be detected and cause a reset.
|
||||
EXPECT_FALSE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
}
|
||||
|
||||
send_time_ms += kTimeDeltaMs;
|
||||
arrival_time_ms += kTimeDeltaMs;
|
||||
system_time_ms += kTimeDeltaMs;
|
||||
EXPECT_TRUE(inter_arrival_->ComputeDeltas(
|
||||
send_time_ms, arrival_time_ms, system_time_ms, kPacketSize, &send_delta,
|
||||
&arrival_delta, &size_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, static_cast<int>(send_delta));
|
||||
EXPECT_EQ(kTimeDeltaMs, arrival_delta);
|
||||
EXPECT_EQ(size_delta, 0);
|
||||
}
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
||||
@ -95,12 +95,9 @@ class OveruseDetectorTest : public ::testing::Test {
|
||||
uint32_t timestamp_delta;
|
||||
int64_t time_delta;
|
||||
int size_delta;
|
||||
if (inter_arrival_->ComputeDeltas(rtp_timestamp,
|
||||
receive_time_ms,
|
||||
packet_size,
|
||||
×tamp_delta,
|
||||
&time_delta,
|
||||
&size_delta)) {
|
||||
if (inter_arrival_->ComputeDeltas(
|
||||
rtp_timestamp, receive_time_ms, receive_time_ms, packet_size,
|
||||
×tamp_delta, &time_delta, &size_delta)) {
|
||||
double timestamp_delta_ms = timestamp_delta / 90.0;
|
||||
overuse_estimator_->Update(time_delta, timestamp_delta_ms, size_delta,
|
||||
overuse_detector_->State());
|
||||
|
||||
@ -79,8 +79,10 @@ bool RemoteBitrateEstimatorAbsSendTime::IsWithinClusterBounds(
|
||||
}
|
||||
|
||||
RemoteBitrateEstimatorAbsSendTime::RemoteBitrateEstimatorAbsSendTime(
|
||||
RemoteBitrateObserver* observer)
|
||||
: observer_(observer),
|
||||
RemoteBitrateObserver* observer,
|
||||
Clock* clock)
|
||||
: clock_(clock),
|
||||
observer_(observer),
|
||||
inter_arrival_(),
|
||||
estimator_(),
|
||||
detector_(OverUseDetectorOptions()),
|
||||
@ -234,18 +236,19 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
||||
uint32_t send_time_24bits,
|
||||
size_t payload_size,
|
||||
uint32_t ssrc) {
|
||||
assert(send_time_24bits < (1ul << 24));
|
||||
RTC_CHECK(send_time_24bits < (1ul << 24));
|
||||
// Shift up send time to use the full 32 bits that inter_arrival works with,
|
||||
// so wrapping works properly.
|
||||
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
|
||||
int64_t send_time_ms = static_cast<int64_t>(timestamp) * kTimestampToMs;
|
||||
|
||||
int64_t now_ms = arrival_time_ms;
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
// TODO(holmer): SSRCs are only needed for REMB, should be broken out from
|
||||
// here.
|
||||
|
||||
// Check if incoming bitrate estimate is valid, and if it needs to be reset.
|
||||
rtc::Optional<uint32_t> incoming_bitrate = incoming_bitrate_.Rate(now_ms);
|
||||
rtc::Optional<uint32_t> incoming_bitrate =
|
||||
incoming_bitrate_.Rate(arrival_time_ms);
|
||||
if (incoming_bitrate) {
|
||||
incoming_bitrate_initialized_ = true;
|
||||
} else if (incoming_bitrate_initialized_) {
|
||||
@ -255,10 +258,10 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
||||
incoming_bitrate_.Reset();
|
||||
incoming_bitrate_initialized_ = false;
|
||||
}
|
||||
incoming_bitrate_.Update(payload_size, now_ms);
|
||||
incoming_bitrate_.Update(payload_size, arrival_time_ms);
|
||||
|
||||
if (first_packet_time_ms_ == -1)
|
||||
first_packet_time_ms_ = arrival_time_ms;
|
||||
first_packet_time_ms_ = now_ms;
|
||||
|
||||
uint32_t ts_delta = 0;
|
||||
int64_t t_delta = 0;
|
||||
@ -300,8 +303,9 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
||||
if (ProcessClusters(now_ms) == ProbeResult::kBitrateUpdated)
|
||||
update_estimate = true;
|
||||
}
|
||||
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size,
|
||||
&ts_delta, &t_delta, &size_delta)) {
|
||||
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, now_ms,
|
||||
payload_size, &ts_delta, &t_delta,
|
||||
&size_delta)) {
|
||||
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
|
||||
estimator_->Update(t_delta, ts_delta_ms, size_delta, detector_.State());
|
||||
detector_.Detect(estimator_->offset(), ts_delta_ms,
|
||||
@ -315,7 +319,8 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
||||
now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) {
|
||||
update_estimate = true;
|
||||
} else if (detector_.State() == kBwOverusing) {
|
||||
rtc::Optional<uint32_t> incoming_rate = incoming_bitrate_.Rate(now_ms);
|
||||
rtc::Optional<uint32_t> incoming_rate =
|
||||
incoming_bitrate_.Rate(arrival_time_ms);
|
||||
if (incoming_rate &&
|
||||
remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) {
|
||||
update_estimate = true;
|
||||
@ -328,7 +333,7 @@ void RemoteBitrateEstimatorAbsSendTime::IncomingPacketInfo(
|
||||
// We also have to update the estimate immediately if we are overusing
|
||||
// and the target bitrate is too high compared to what we are receiving.
|
||||
const RateControlInput input(detector_.State(),
|
||||
incoming_bitrate_.Rate(now_ms),
|
||||
incoming_bitrate_.Rate(arrival_time_ms),
|
||||
estimator_->var_noise());
|
||||
remote_rate_.Update(&input, now_ms);
|
||||
target_bitrate_bps = remote_rate_.UpdateBandwidthEstimate(now_ms);
|
||||
|
||||
@ -68,7 +68,8 @@ struct Cluster {
|
||||
|
||||
class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator {
|
||||
public:
|
||||
explicit RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer);
|
||||
RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer,
|
||||
Clock* clock);
|
||||
virtual ~RemoteBitrateEstimatorAbsSendTime() {}
|
||||
|
||||
void IncomingPacketFeedbackVector(
|
||||
@ -117,6 +118,7 @@ class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator {
|
||||
void TimeoutStreams(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_);
|
||||
|
||||
rtc::ThreadChecker network_thread_;
|
||||
Clock* const clock_;
|
||||
RemoteBitrateObserver* const observer_;
|
||||
std::unique_ptr<InterArrival> inter_arrival_;
|
||||
std::unique_ptr<OveruseEstimator> estimator_;
|
||||
|
||||
@ -20,7 +20,7 @@ class RemoteBitrateEstimatorAbsSendTimeTest :
|
||||
RemoteBitrateEstimatorAbsSendTimeTest() {}
|
||||
virtual void SetUp() {
|
||||
bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime(
|
||||
bitrate_observer_.get()));
|
||||
bitrate_observer_.get(), &clock_));
|
||||
}
|
||||
protected:
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorAbsSendTimeTest);
|
||||
@ -39,31 +39,39 @@ TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, RateIncreaseRtpTimestamps) {
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStream) {
|
||||
CapacityDropTestHelper(1, false, 667);
|
||||
CapacityDropTestHelper(1, false, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropPosOffsetChange) {
|
||||
CapacityDropTestHelper(1, false, 267, 30000);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNegOffsetChange) {
|
||||
CapacityDropTestHelper(1, false, 267, -30000);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropOneStreamWrap) {
|
||||
CapacityDropTestHelper(1, true, 667);
|
||||
CapacityDropTestHelper(1, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropTwoStreamsWrap) {
|
||||
CapacityDropTestHelper(2, true, 633);
|
||||
CapacityDropTestHelper(2, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThreeStreamsWrap) {
|
||||
CapacityDropTestHelper(3, true, 633);
|
||||
CapacityDropTestHelper(3, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirteenStreamsWrap) {
|
||||
CapacityDropTestHelper(13, true, 667);
|
||||
CapacityDropTestHelper(13, true, 667, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropNineteenStreamsWrap) {
|
||||
CapacityDropTestHelper(19, true, 667);
|
||||
CapacityDropTestHelper(19, true, 667, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, CapacityDropThirtyStreamsWrap) {
|
||||
CapacityDropTestHelper(30, true, 667);
|
||||
CapacityDropTestHelper(30, true, 667, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorAbsSendTimeTest, TestTimestampGrouping) {
|
||||
|
||||
@ -109,9 +109,9 @@ void RemoteBitrateEstimatorSingleStream::IncomingPacket(
|
||||
uint32_t timestamp_delta = 0;
|
||||
int64_t time_delta = 0;
|
||||
int size_delta = 0;
|
||||
if (estimator->inter_arrival.ComputeDeltas(rtp_timestamp, arrival_time_ms,
|
||||
payload_size, ×tamp_delta,
|
||||
&time_delta, &size_delta)) {
|
||||
if (estimator->inter_arrival.ComputeDeltas(
|
||||
rtp_timestamp, arrival_time_ms, now_ms, payload_size,
|
||||
×tamp_delta, &time_delta, &size_delta)) {
|
||||
double timestamp_delta_ms = timestamp_delta * kTimestampToMs;
|
||||
estimator->estimator.Update(time_delta, timestamp_delta_ms, size_delta,
|
||||
estimator->detector.State());
|
||||
|
||||
@ -39,31 +39,31 @@ TEST_F(RemoteBitrateEstimatorSingleTest, RateIncreaseRtpTimestamps) {
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStream) {
|
||||
CapacityDropTestHelper(1, false, 633);
|
||||
CapacityDropTestHelper(1, false, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropOneStreamWrap) {
|
||||
CapacityDropTestHelper(1, true, 633);
|
||||
CapacityDropTestHelper(1, true, 633, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropTwoStreamsWrap) {
|
||||
CapacityDropTestHelper(2, true, 767);
|
||||
CapacityDropTestHelper(2, true, 767, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThreeStreamsWrap) {
|
||||
CapacityDropTestHelper(3, true, 567);
|
||||
CapacityDropTestHelper(3, true, 567, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirteenStreamsWrap) {
|
||||
CapacityDropTestHelper(13, true, 567);
|
||||
CapacityDropTestHelper(13, true, 567, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropNineteenStreamsWrap) {
|
||||
CapacityDropTestHelper(19, true, 700);
|
||||
CapacityDropTestHelper(19, true, 700, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, CapacityDropThirtyStreamsWrap) {
|
||||
CapacityDropTestHelper(30, true, 733);
|
||||
CapacityDropTestHelper(30, true, 733, 0);
|
||||
}
|
||||
|
||||
TEST_F(RemoteBitrateEstimatorSingleTest, TestTimestampGrouping) {
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "webrtc/base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
const size_t kMtu = 1200;
|
||||
@ -77,7 +79,7 @@ int64_t RtpStream::GenerateFrame(int64_t time_now_us, PacketList* packets) {
|
||||
}
|
||||
|
||||
// The send-side time when the next frame can be generated.
|
||||
double RtpStream::next_rtp_time() const {
|
||||
int64_t RtpStream::next_rtp_time() const {
|
||||
return next_rtp_time_;
|
||||
}
|
||||
|
||||
@ -116,7 +118,7 @@ bool RtpStream::Compare(const std::pair<uint32_t, RtpStream*>& left,
|
||||
return left.second->next_rtp_time_ < right.second->next_rtp_time_;
|
||||
}
|
||||
|
||||
StreamGenerator::StreamGenerator(int capacity, double time_now)
|
||||
StreamGenerator::StreamGenerator(int capacity, int64_t time_now)
|
||||
: capacity_(capacity),
|
||||
prev_arrival_time_us_(time_now) {}
|
||||
|
||||
@ -187,16 +189,17 @@ int64_t StreamGenerator::GenerateFrame(RtpStream::PacketList* packets,
|
||||
++i;
|
||||
}
|
||||
it = std::min_element(streams_.begin(), streams_.end(), RtpStream::Compare);
|
||||
return (*it).second->next_rtp_time();
|
||||
return std::max((*it).second->next_rtp_time(), time_now_us);
|
||||
}
|
||||
} // namespace testing
|
||||
|
||||
RemoteBitrateEstimatorTest::RemoteBitrateEstimatorTest()
|
||||
: clock_(0),
|
||||
: clock_(100000000),
|
||||
bitrate_observer_(new testing::TestBitrateObserver),
|
||||
stream_generator_(new testing::StreamGenerator(
|
||||
1e6, // Capacity.
|
||||
clock_.TimeInMicroseconds())) {}
|
||||
clock_.TimeInMicroseconds())),
|
||||
arrival_time_offset_ms_(0) {}
|
||||
|
||||
RemoteBitrateEstimatorTest::~RemoteBitrateEstimatorTest() {}
|
||||
|
||||
@ -231,7 +234,8 @@ void RemoteBitrateEstimatorTest::IncomingPacket(uint32_t ssrc,
|
||||
header.timestamp = rtp_timestamp;
|
||||
header.extension.hasAbsoluteSendTime = true;
|
||||
header.extension.absoluteSendTime = absolute_send_time;
|
||||
bitrate_estimator_->IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs,
|
||||
RTC_CHECK_GE(arrival_time + arrival_time_offset_ms_, 0);
|
||||
bitrate_estimator_->IncomingPacket(arrival_time + arrival_time_offset_ms_,
|
||||
payload_size, header);
|
||||
}
|
||||
|
||||
@ -243,6 +247,7 @@ void RemoteBitrateEstimatorTest::IncomingPacket(uint32_t ssrc,
|
||||
// target bitrate after the call to this function.
|
||||
bool RemoteBitrateEstimatorTest::GenerateAndProcessFrame(uint32_t ssrc,
|
||||
uint32_t bitrate_bps) {
|
||||
RTC_DCHECK_GT(bitrate_bps, 0u);
|
||||
stream_generator_->SetBitrateBps(bitrate_bps);
|
||||
testing::RtpStream::PacketList packets;
|
||||
int64_t next_time_us = stream_generator_->GenerateFrame(
|
||||
@ -429,7 +434,8 @@ void RemoteBitrateEstimatorTest::RateIncreaseRtpTimestampsTestHelper(
|
||||
void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
|
||||
int number_of_streams,
|
||||
bool wrap_time_stamp,
|
||||
uint32_t expected_bitrate_drop_delta) {
|
||||
uint32_t expected_bitrate_drop_delta,
|
||||
int64_t receiver_clock_offset_change_ms) {
|
||||
const int kFramerate = 30;
|
||||
const int kStartBitrate = 900e3;
|
||||
const int kMinExpectedBitrate = 800e3;
|
||||
@ -477,6 +483,9 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
|
||||
EXPECT_NEAR(kInitialCapacityBps, bitrate_bps, 130000u);
|
||||
bitrate_observer_->Reset();
|
||||
|
||||
// Add an offset to make sure the BWE can handle it.
|
||||
arrival_time_offset_ms_ += receiver_clock_offset_change_ms;
|
||||
|
||||
// Reduce the capacity and verify the decrease time.
|
||||
stream_generator_->set_capacity_bps(kReducedCapacityBps);
|
||||
int64_t overuse_start_time = clock_.TimeInMilliseconds();
|
||||
@ -487,7 +496,8 @@ void RemoteBitrateEstimatorTest::CapacityDropTestHelper(
|
||||
bitrate_observer_->latest_bitrate() <= kReducedCapacityBps) {
|
||||
bitrate_drop_time = clock_.TimeInMilliseconds();
|
||||
}
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
if (bitrate_observer_->updated())
|
||||
bitrate_bps = bitrate_observer_->latest_bitrate();
|
||||
}
|
||||
|
||||
EXPECT_NEAR(expected_bitrate_drop_delta,
|
||||
|
||||
@ -79,7 +79,7 @@ class RtpStream {
|
||||
int64_t GenerateFrame(int64_t time_now_us, PacketList* packets);
|
||||
|
||||
// The send-side time when the next frame can be generated.
|
||||
double next_rtp_time() const;
|
||||
int64_t next_rtp_time() const;
|
||||
|
||||
// Generates an RTCP packet.
|
||||
RtcpPacket* Rtcp(int64_t time_now_us);
|
||||
@ -112,7 +112,7 @@ class StreamGenerator {
|
||||
public:
|
||||
typedef std::list<RtpStream::RtcpPacket*> RtcpList;
|
||||
|
||||
StreamGenerator(int capacity, double time_now);
|
||||
StreamGenerator(int capacity, int64_t time_now);
|
||||
|
||||
~StreamGenerator();
|
||||
|
||||
@ -203,15 +203,16 @@ class RemoteBitrateEstimatorTest : public ::testing::Test {
|
||||
void RateIncreaseRtpTimestampsTestHelper(int expected_iterations);
|
||||
void CapacityDropTestHelper(int number_of_streams,
|
||||
bool wrap_time_stamp,
|
||||
uint32_t expected_bitrate_drop_delta);
|
||||
uint32_t expected_bitrate_drop_delta,
|
||||
int64_t receiver_clock_offset_change_ms);
|
||||
|
||||
static const uint32_t kDefaultSsrc;
|
||||
static const int kArrivalTimeClockOffsetMs = 60000;
|
||||
|
||||
SimulatedClock clock_; // Time at the receiver.
|
||||
std::unique_ptr<testing::TestBitrateObserver> bitrate_observer_;
|
||||
std::unique_ptr<RemoteBitrateEstimator> bitrate_estimator_;
|
||||
std::unique_ptr<testing::StreamGenerator> stream_generator_;
|
||||
int64_t arrival_time_offset_ms_;
|
||||
|
||||
RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorTest);
|
||||
};
|
||||
|
||||
@ -71,7 +71,7 @@ RembReceiver::RembReceiver(int flow_id, bool plot)
|
||||
recv_stats_(ReceiveStatistics::Create(&clock_)),
|
||||
latest_estimate_bps_(-1),
|
||||
last_feedback_ms_(-1),
|
||||
estimator_(new RemoteBitrateEstimatorAbsSendTime(this)) {
|
||||
estimator_(new RemoteBitrateEstimatorAbsSendTime(this, &clock_)) {
|
||||
std::stringstream ss;
|
||||
ss << "Estimate_" << flow_id_ << "#1";
|
||||
estimate_log_prefix_ = ss.str();
|
||||
|
||||
@ -25,7 +25,7 @@ FullBweSender::FullBweSender(int kbps, BitrateObserver* observer, Clock* clock)
|
||||
BitrateController::CreateBitrateController(clock,
|
||||
observer,
|
||||
&event_log_)),
|
||||
rbe_(new RemoteBitrateEstimatorAbsSendTime(this)),
|
||||
rbe_(new RemoteBitrateEstimatorAbsSendTime(this, clock)),
|
||||
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
|
||||
clock_(clock),
|
||||
send_time_history_(clock_, 10000),
|
||||
|
||||
@ -117,9 +117,9 @@ bool ParseArgsAndSetupEstimator(int argc,
|
||||
switch (extension) {
|
||||
case webrtc::kRtpExtensionAbsoluteSendTime: {
|
||||
*estimator =
|
||||
new webrtc::RemoteBitrateEstimatorAbsSendTime(observer);
|
||||
*estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator";
|
||||
break;
|
||||
new webrtc::RemoteBitrateEstimatorAbsSendTime(observer, clock);
|
||||
*estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator";
|
||||
break;
|
||||
}
|
||||
case webrtc::kRtpExtensionTransmissionTimeOffset: {
|
||||
*estimator =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user