Simplified throughput estimator
Add interface for AcknowledgedBitrateEstimator Add simplified throughput estimator, implementing the same interface. The choice of estimator implementation can be controlled by a field trial. Bug: webrtc:10274 Change-Id: I6bef090a8a6a1783f3f5750a2ee56189f562a9c8 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158892 Commit-Queue: Björn Terelius <terelius@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Cr-Commit-Position: refs/heads/master@{#29761}
This commit is contained in:
parent
62a19d0798
commit
251b0dcc4f
@ -106,6 +106,8 @@ rtc_library("estimators") {
|
||||
sources = [
|
||||
"acknowledged_bitrate_estimator.cc",
|
||||
"acknowledged_bitrate_estimator.h",
|
||||
"acknowledged_bitrate_estimator_interface.cc",
|
||||
"acknowledged_bitrate_estimator_interface.h",
|
||||
"bitrate_estimator.cc",
|
||||
"bitrate_estimator.h",
|
||||
"delay_increase_detector_interface.h",
|
||||
@ -113,6 +115,8 @@ rtc_library("estimators") {
|
||||
"median_slope_estimator.h",
|
||||
"probe_bitrate_estimator.cc",
|
||||
"probe_bitrate_estimator.h",
|
||||
"robust_throughput_estimator.cc",
|
||||
"robust_throughput_estimator.h",
|
||||
"trendline_estimator.cc",
|
||||
"trendline_estimator.h",
|
||||
]
|
||||
@ -249,6 +253,7 @@ if (rtc_include_tests) {
|
||||
"median_slope_estimator_unittest.cc",
|
||||
"probe_bitrate_estimator_unittest.cc",
|
||||
"probe_controller_unittest.cc",
|
||||
"robust_throughput_estimator_unittest.cc",
|
||||
"send_side_bandwidth_estimation_unittest.cc",
|
||||
"trendline_estimator_unittest.cc",
|
||||
]
|
||||
|
||||
@ -18,11 +18,13 @@
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h"
|
||||
#include "modules/congestion_controller/goog_cc/bitrate_estimator.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class AcknowledgedBitrateEstimator {
|
||||
class AcknowledgedBitrateEstimator
|
||||
: public AcknowledgedBitrateEstimatorInterface {
|
||||
public:
|
||||
AcknowledgedBitrateEstimator(
|
||||
const WebRtcKeyValueConfig* key_value_config,
|
||||
@ -30,14 +32,14 @@ class AcknowledgedBitrateEstimator {
|
||||
|
||||
explicit AcknowledgedBitrateEstimator(
|
||||
const WebRtcKeyValueConfig* key_value_config);
|
||||
~AcknowledgedBitrateEstimator();
|
||||
~AcknowledgedBitrateEstimator() override;
|
||||
|
||||
void IncomingPacketFeedbackVector(
|
||||
const std::vector<PacketResult>& packet_feedback_vector);
|
||||
absl::optional<DataRate> bitrate() const;
|
||||
absl::optional<DataRate> PeekRate() const;
|
||||
void SetAlr(bool in_alr);
|
||||
void SetAlrEndedTime(Timestamp alr_ended_time);
|
||||
const std::vector<PacketResult>& packet_feedback_vector) override;
|
||||
absl::optional<DataRate> bitrate() const override;
|
||||
absl::optional<DataRate> PeekRate() const override;
|
||||
void SetAlr(bool in_alr) override;
|
||||
void SetAlrEndedTime(Timestamp alr_ended_time) override;
|
||||
|
||||
private:
|
||||
absl::optional<Timestamp> alr_ended_time_;
|
||||
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h"
|
||||
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
|
||||
#include "modules/congestion_controller/goog_cc/robust_throughput_estimator.h"
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
constexpr char RobustThroughputEstimatorSettings::kKey[];
|
||||
|
||||
RobustThroughputEstimatorSettings::RobustThroughputEstimatorSettings(
|
||||
const WebRtcKeyValueConfig* key_value_config) {
|
||||
Parser()->Parse(
|
||||
key_value_config->Lookup(RobustThroughputEstimatorSettings::kKey));
|
||||
if (min_packets < 10 || kMaxPackets < min_packets) {
|
||||
RTC_LOG(LS_WARNING) << "Window size must be between 10 and " << kMaxPackets
|
||||
<< " packets";
|
||||
min_packets = 20;
|
||||
}
|
||||
if (window_duration < TimeDelta::ms(100) ||
|
||||
TimeDelta::ms(2000) < window_duration) {
|
||||
RTC_LOG(LS_WARNING) << "Window duration must be between 100 and 2000 ms";
|
||||
window_duration = TimeDelta::ms(500);
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<StructParametersParser>
|
||||
RobustThroughputEstimatorSettings::Parser() {
|
||||
return StructParametersParser::Create("enabled", &enabled, //
|
||||
"reduce_bias", &reduce_bias, //
|
||||
"assume_shared_link",
|
||||
&assume_shared_link, //
|
||||
"min_packets", &min_packets, //
|
||||
"window_duration", &window_duration);
|
||||
}
|
||||
|
||||
AcknowledgedBitrateEstimatorInterface::
|
||||
~AcknowledgedBitrateEstimatorInterface() {}
|
||||
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
AcknowledgedBitrateEstimatorInterface::Create(
|
||||
const WebRtcKeyValueConfig* key_value_config) {
|
||||
RobustThroughputEstimatorSettings simplified_estimator_settings(
|
||||
key_value_config);
|
||||
if (simplified_estimator_settings.enabled) {
|
||||
return std::make_unique<RobustThroughputEstimator>(
|
||||
simplified_estimator_settings);
|
||||
}
|
||||
return std::make_unique<AcknowledgedBitrateEstimator>(key_value_config);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "rtc_base/experiments/struct_parameters_parser.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
struct RobustThroughputEstimatorSettings {
|
||||
static constexpr char kKey[] = "WebRTC-Bwe-RobustThroughputEstimatorSettings";
|
||||
static constexpr size_t kMaxPackets = 500;
|
||||
|
||||
RobustThroughputEstimatorSettings() = delete;
|
||||
explicit RobustThroughputEstimatorSettings(
|
||||
const WebRtcKeyValueConfig* key_value_config);
|
||||
|
||||
bool enabled = false; // Set to true to use RobustThroughputEstimator.
|
||||
|
||||
// The estimator handles delay spikes by removing the largest receive time
|
||||
// gap, but this introduces some bias that may lead to overestimation when
|
||||
// there isn't any delay spike. If |reduce_bias| is true, we instead replace
|
||||
// the largest receive time gap by the second largest. This reduces the bias
|
||||
// at the cost of not completely removing the genuine delay spikes.
|
||||
bool reduce_bias = true;
|
||||
|
||||
// If |assume_shared_link| is false, we ignore the size of the first packet
|
||||
// when computing the receive rate. Otherwise, we remove half of the first
|
||||
// and last packet's sizes.
|
||||
bool assume_shared_link = false;
|
||||
|
||||
// The estimator window keeps at least |min_packets| packets and up to
|
||||
// kMaxPackets received during the last |window_duration|.
|
||||
unsigned min_packets = 20;
|
||||
TimeDelta window_duration = TimeDelta::ms(500);
|
||||
|
||||
std::unique_ptr<StructParametersParser> Parser();
|
||||
};
|
||||
|
||||
class AcknowledgedBitrateEstimatorInterface {
|
||||
public:
|
||||
static std::unique_ptr<AcknowledgedBitrateEstimatorInterface> Create(
|
||||
const WebRtcKeyValueConfig* key_value_config);
|
||||
virtual ~AcknowledgedBitrateEstimatorInterface();
|
||||
|
||||
virtual void IncomingPacketFeedbackVector(
|
||||
const std::vector<PacketResult>& packet_feedback_vector) = 0;
|
||||
virtual absl::optional<DataRate> bitrate() const = 0;
|
||||
virtual absl::optional<DataRate> PeekRate() const = 0;
|
||||
virtual void SetAlr(bool in_alr) = 0;
|
||||
virtual void SetAlrEndedTime(Timestamp alr_ended_time) = 0;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ACKNOWLEDGED_BITRATE_ESTIMATOR_INTERFACE_H_
|
||||
@ -149,7 +149,7 @@ DelayBasedBweTest::DelayBasedBweTest()
|
||||
: field_trial(),
|
||||
clock_(100000000),
|
||||
acknowledged_bitrate_estimator_(
|
||||
std::make_unique<AcknowledgedBitrateEstimator>(&field_trial_config_)),
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_)),
|
||||
probe_bitrate_estimator_(new ProbeBitrateEstimator(nullptr)),
|
||||
bitrate_estimator_(
|
||||
new DelayBasedBwe(&field_trial_config_, nullptr, nullptr)),
|
||||
@ -163,7 +163,7 @@ DelayBasedBweTest::DelayBasedBweTest(const std::string& field_trial_string)
|
||||
std::make_unique<test::ScopedFieldTrials>(field_trial_string)),
|
||||
clock_(100000000),
|
||||
acknowledged_bitrate_estimator_(
|
||||
std::make_unique<AcknowledgedBitrateEstimator>(&field_trial_config_)),
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_)),
|
||||
probe_bitrate_estimator_(new ProbeBitrateEstimator(nullptr)),
|
||||
bitrate_estimator_(
|
||||
new DelayBasedBwe(&field_trial_config_, nullptr, nullptr)),
|
||||
|
||||
@ -169,7 +169,8 @@ class DelayBasedBweTest : public ::testing::Test {
|
||||
field_trial; // Must be initialized first.
|
||||
SimulatedClock clock_; // Time at the receiver.
|
||||
test::TestBitrateObserver bitrate_observer_;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
acknowledged_bitrate_estimator_;
|
||||
const std::unique_ptr<ProbeBitrateEstimator> probe_bitrate_estimator_;
|
||||
std::unique_ptr<DelayBasedBwe> bitrate_estimator_;
|
||||
std::unique_ptr<test::StreamGenerator> stream_generator_;
|
||||
|
||||
@ -23,7 +23,6 @@
|
||||
|
||||
#include "api/units/time_delta.h"
|
||||
#include "logging/rtc_event_log/events/rtc_event_remote_estimate.h"
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
|
||||
#include "modules/congestion_controller/goog_cc/alr_detector.h"
|
||||
#include "modules/congestion_controller/goog_cc/probe_controller.h"
|
||||
#include "modules/remote_bitrate_estimator/include/bwe_defines.h"
|
||||
@ -32,6 +31,7 @@
|
||||
#include "rtc_base/logging.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
namespace {
|
||||
// From RTCPSender video report interval.
|
||||
constexpr TimeDelta kLossUpdateInterval = TimeDelta::Millis<1000>();
|
||||
@ -96,7 +96,7 @@ GoogCcNetworkController::GoogCcNetworkController(NetworkControllerConfig config,
|
||||
event_log_,
|
||||
network_state_predictor_.get())),
|
||||
acknowledged_bitrate_estimator_(
|
||||
std::make_unique<AcknowledgedBitrateEstimator>(key_value_config_)),
|
||||
AcknowledgedBitrateEstimatorInterface::Create(key_value_config_)),
|
||||
initial_config_(config),
|
||||
last_loss_based_target_rate_(*config.constraints.starting_rate),
|
||||
last_pushback_target_rate_(last_loss_based_target_rate_),
|
||||
@ -146,8 +146,8 @@ NetworkControlUpdate GoogCcNetworkController::OnNetworkRouteChange(
|
||||
}
|
||||
}
|
||||
|
||||
acknowledged_bitrate_estimator_.reset(
|
||||
new AcknowledgedBitrateEstimator(key_value_config_));
|
||||
acknowledged_bitrate_estimator_ =
|
||||
AcknowledgedBitrateEstimatorInterface::Create(key_value_config_);
|
||||
probe_bitrate_estimator_.reset(new ProbeBitrateEstimator(event_log_));
|
||||
if (network_estimator_)
|
||||
network_estimator_->OnRouteChange(msg);
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
#include "api/units/data_rate.h"
|
||||
#include "api/units/data_size.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h"
|
||||
#include "modules/congestion_controller/goog_cc/alr_detector.h"
|
||||
#include "modules/congestion_controller/goog_cc/congestion_window_pushback_controller.h"
|
||||
#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
|
||||
@ -100,7 +100,8 @@ class GoogCcNetworkController : public NetworkControllerInterface {
|
||||
std::unique_ptr<NetworkStateEstimator> network_estimator_;
|
||||
std::unique_ptr<NetworkStatePredictor> network_state_predictor_;
|
||||
std::unique_ptr<DelayBasedBwe> delay_based_bwe_;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
acknowledged_bitrate_estimator_;
|
||||
|
||||
absl::optional<NetworkControllerConfig> initial_config_;
|
||||
|
||||
|
||||
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 "modules/congestion_controller/goog_cc/robust_throughput_estimator.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
RobustThroughputEstimator::RobustThroughputEstimator(
|
||||
const RobustThroughputEstimatorSettings& settings)
|
||||
: settings_(settings) {
|
||||
RTC_DCHECK(settings.enabled);
|
||||
}
|
||||
|
||||
RobustThroughputEstimator::~RobustThroughputEstimator() {}
|
||||
|
||||
void RobustThroughputEstimator::IncomingPacketFeedbackVector(
|
||||
const std::vector<PacketResult>& packet_feedback_vector) {
|
||||
RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
|
||||
packet_feedback_vector.end(),
|
||||
PacketResult::ReceiveTimeOrder()));
|
||||
for (const auto& packet : packet_feedback_vector) {
|
||||
// Insert the new packet.
|
||||
window_.push_back(packet);
|
||||
// In most cases, receive timestamps should already be in order, but in the
|
||||
// rare case where feedback packets have been reordered, we do some swaps to
|
||||
// ensure that the window is sorted.
|
||||
for (size_t i = window_.size() - 1;
|
||||
i > 0 && window_[i].receive_time < window_[i - 1].receive_time; i--) {
|
||||
std::swap(window_[i], window_[i - 1]);
|
||||
}
|
||||
// Remove old packets.
|
||||
while (window_.size() > settings_.kMaxPackets ||
|
||||
(window_.size() > settings_.min_packets &&
|
||||
packet.receive_time - window_.front().receive_time >
|
||||
settings_.window_duration)) {
|
||||
window_.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<DataRate> RobustThroughputEstimator::bitrate() const {
|
||||
if (window_.size() < settings_.min_packets)
|
||||
return absl::nullopt;
|
||||
|
||||
TimeDelta largest_recv_gap(TimeDelta::ms(0));
|
||||
TimeDelta second_largest_recv_gap(TimeDelta::ms(0));
|
||||
for (size_t i = 1; i < window_.size(); i++) {
|
||||
// Find receive time gaps
|
||||
TimeDelta gap = window_[i].receive_time - window_[i - 1].receive_time;
|
||||
if (gap > largest_recv_gap) {
|
||||
second_largest_recv_gap = largest_recv_gap;
|
||||
largest_recv_gap = gap;
|
||||
} else if (gap > second_largest_recv_gap) {
|
||||
second_largest_recv_gap = gap;
|
||||
}
|
||||
}
|
||||
|
||||
Timestamp min_send_time = window_[0].sent_packet.send_time;
|
||||
Timestamp max_send_time = window_[0].sent_packet.send_time;
|
||||
Timestamp min_recv_time = window_[0].receive_time;
|
||||
Timestamp max_recv_time = window_[0].receive_time;
|
||||
DataSize data_size = DataSize::bytes(0);
|
||||
for (const auto& packet : window_) {
|
||||
min_send_time = std::min(min_send_time, packet.sent_packet.send_time);
|
||||
max_send_time = std::max(max_send_time, packet.sent_packet.send_time);
|
||||
min_recv_time = std::min(min_recv_time, packet.receive_time);
|
||||
max_recv_time = std::max(max_recv_time, packet.receive_time);
|
||||
data_size += packet.sent_packet.size;
|
||||
data_size += packet.sent_packet.prior_unacked_data;
|
||||
}
|
||||
|
||||
// Suppose a packet of size S is sent every T milliseconds.
|
||||
// A window of N packets would contain N*S bytes, but the time difference
|
||||
// between the first and the last packet would only be (N-1)*T. Thus, we
|
||||
// need to remove one packet.
|
||||
DataSize recv_size = data_size;
|
||||
DataSize send_size = data_size;
|
||||
if (settings_.assume_shared_link) {
|
||||
// Depending on how the bottleneck queue is implemented, a large packet
|
||||
// may delay sending of sebsequent packets, so the delay between packets
|
||||
// i and i+1 depends on the size of both packets. In this case we minimize
|
||||
// the maximum error by removing half of both the first and last packet
|
||||
// size.
|
||||
DataSize first_last_average_size =
|
||||
(window_.front().sent_packet.size +
|
||||
window_.front().sent_packet.prior_unacked_data +
|
||||
window_.back().sent_packet.size +
|
||||
window_.back().sent_packet.prior_unacked_data) /
|
||||
2;
|
||||
recv_size -= first_last_average_size;
|
||||
send_size -= first_last_average_size;
|
||||
} else {
|
||||
// In the simpler case where the delay between packets i and i+1 only
|
||||
// depends on the size of packet i+1, the first packet doesn't give us
|
||||
// any information. Analogously, we assume that the start send time
|
||||
// for the last packet doesn't depend on the size of the packet.
|
||||
recv_size -= (window_.front().sent_packet.size +
|
||||
window_.front().sent_packet.prior_unacked_data);
|
||||
send_size -= (window_.back().sent_packet.size +
|
||||
window_.back().sent_packet.prior_unacked_data);
|
||||
}
|
||||
|
||||
// Remove the largest gap by replacing it by the second largest gap
|
||||
// or the average gap.
|
||||
TimeDelta send_duration = max_send_time - min_send_time;
|
||||
TimeDelta recv_duration = (max_recv_time - min_recv_time) - largest_recv_gap;
|
||||
if (settings_.reduce_bias) {
|
||||
recv_duration += second_largest_recv_gap;
|
||||
} else {
|
||||
recv_duration += recv_duration / (window_.size() - 2);
|
||||
}
|
||||
|
||||
send_duration = std::max(send_duration, TimeDelta::ms(1));
|
||||
recv_duration = std::max(recv_duration, TimeDelta::ms(1));
|
||||
return std::min(send_size / send_duration, recv_size / recv_duration);
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 MODULES_CONGESTION_CONTROLLER_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_
|
||||
#define MODULES_CONGESTION_CONTROLLER_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/transport/network_types.h"
|
||||
#include "api/transport/webrtc_key_value_config.h"
|
||||
#include "api/units/data_rate.h"
|
||||
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator_interface.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
class RobustThroughputEstimator : public AcknowledgedBitrateEstimatorInterface {
|
||||
public:
|
||||
explicit RobustThroughputEstimator(
|
||||
const RobustThroughputEstimatorSettings& settings);
|
||||
~RobustThroughputEstimator() override;
|
||||
|
||||
void IncomingPacketFeedbackVector(
|
||||
const std::vector<PacketResult>& packet_feedback_vector) override;
|
||||
|
||||
absl::optional<DataRate> bitrate() const override;
|
||||
|
||||
absl::optional<DataRate> PeekRate() const override { return bitrate(); }
|
||||
void SetAlr(bool /*in_alr*/) override {}
|
||||
void SetAlrEndedTime(Timestamp /*alr_ended_time*/) override {}
|
||||
|
||||
private:
|
||||
const RobustThroughputEstimatorSettings settings_;
|
||||
std::deque<PacketResult> window_;
|
||||
};
|
||||
|
||||
} // namespace webrtc
|
||||
|
||||
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_ROBUST_THROUGHPUT_ESTIMATOR_H_
|
||||
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright (c) 2019 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 "modules/congestion_controller/goog_cc/robust_throughput_estimator.h"
|
||||
|
||||
#include "api/transport/field_trial_based_config.h"
|
||||
#include "test/field_trial.h"
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
std::vector<PacketResult> CreateFeedbackVector(size_t number_of_packets,
|
||||
DataSize packet_size,
|
||||
TimeDelta send_increment,
|
||||
TimeDelta recv_increment,
|
||||
Timestamp* send_clock,
|
||||
Timestamp* recv_clock,
|
||||
uint16_t* sequence_number) {
|
||||
std::vector<PacketResult> packet_feedback_vector(number_of_packets);
|
||||
for (size_t i = 0; i < number_of_packets; i++) {
|
||||
packet_feedback_vector[i].receive_time = *recv_clock;
|
||||
packet_feedback_vector[i].sent_packet.send_time = *send_clock;
|
||||
packet_feedback_vector[i].sent_packet.sequence_number = *sequence_number;
|
||||
packet_feedback_vector[i].sent_packet.size = packet_size;
|
||||
*send_clock += send_increment;
|
||||
*recv_clock += recv_increment;
|
||||
*sequence_number += 1;
|
||||
}
|
||||
return packet_feedback_vector;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
TEST(RobustThroughputEstimatorTest, SteadyRate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Bwe-RobustThroughputEstimatorSettings/"
|
||||
"enabled:true,assume_shared_link:false,reduce_bias:true,min_packets:10,"
|
||||
"window_duration:100ms/");
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
RobustThroughputEstimatorSettings settings(&field_trial_config);
|
||||
RobustThroughputEstimator throughput_estimator(settings);
|
||||
DataSize packet_size(DataSize::bytes(1000));
|
||||
Timestamp send_clock(Timestamp::ms(100000));
|
||||
Timestamp recv_clock(Timestamp::ms(10000));
|
||||
TimeDelta send_increment(TimeDelta::ms(10));
|
||||
TimeDelta recv_increment(TimeDelta::ms(10));
|
||||
uint16_t sequence_number = 100;
|
||||
std::vector<PacketResult> packet_feedback =
|
||||
CreateFeedbackVector(9, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
EXPECT_FALSE(throughput_estimator.bitrate().has_value());
|
||||
|
||||
packet_feedback =
|
||||
CreateFeedbackVector(11, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
auto throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 100 * 1000.0,
|
||||
0.05 * 100 * 1000.0); // Allow 5% error
|
||||
}
|
||||
|
||||
TEST(RobustThroughputEstimatorTest, DelaySpike) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Bwe-RobustThroughputEstimatorSettings/"
|
||||
"enabled:true,assume_shared_link:false,reduce_bias:true,min_packets:10,"
|
||||
"window_duration:100ms/");
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
RobustThroughputEstimatorSettings settings(&field_trial_config);
|
||||
RobustThroughputEstimator throughput_estimator(settings);
|
||||
DataSize packet_size(DataSize::bytes(1000));
|
||||
Timestamp send_clock(Timestamp::ms(100000));
|
||||
Timestamp recv_clock(Timestamp::ms(10000));
|
||||
TimeDelta send_increment(TimeDelta::ms(10));
|
||||
TimeDelta recv_increment(TimeDelta::ms(10));
|
||||
uint16_t sequence_number = 100;
|
||||
std::vector<PacketResult> packet_feedback =
|
||||
CreateFeedbackVector(20, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
auto throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 100 * 1000.0,
|
||||
0.05 * 100 * 1000.0); // Allow 5% error
|
||||
|
||||
// Delay spike
|
||||
recv_clock += TimeDelta::ms(40);
|
||||
|
||||
// Faster delivery after the gap
|
||||
recv_increment = TimeDelta::ms(2);
|
||||
packet_feedback =
|
||||
CreateFeedbackVector(5, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 100 * 1000.0,
|
||||
0.05 * 100 * 1000.0); // Allow 5% error
|
||||
|
||||
// Delivery at normal rate. This will be capped by the send rate.
|
||||
recv_increment = TimeDelta::ms(10);
|
||||
packet_feedback =
|
||||
CreateFeedbackVector(5, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 100 * 1000.0,
|
||||
0.05 * 100 * 1000.0); // Allow 5% error
|
||||
}
|
||||
|
||||
TEST(RobustThroughputEstimatorTest, CappedByReceiveRate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Bwe-RobustThroughputEstimatorSettings/"
|
||||
"enabled:true,assume_shared_link:false,reduce_bias:true,min_packets:10,"
|
||||
"window_duration:100ms/");
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
RobustThroughputEstimatorSettings settings(&field_trial_config);
|
||||
RobustThroughputEstimator throughput_estimator(settings);
|
||||
DataSize packet_size(DataSize::bytes(1000));
|
||||
Timestamp send_clock(Timestamp::ms(100000));
|
||||
Timestamp recv_clock(Timestamp::ms(10000));
|
||||
TimeDelta send_increment(TimeDelta::ms(10));
|
||||
TimeDelta recv_increment(TimeDelta::ms(40));
|
||||
uint16_t sequence_number = 100;
|
||||
std::vector<PacketResult> packet_feedback =
|
||||
CreateFeedbackVector(20, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
auto throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 25 * 1000.0,
|
||||
0.05 * 25 * 1000.0); // Allow 5% error
|
||||
}
|
||||
|
||||
TEST(RobustThroughputEstimatorTest, CappedBySendRate) {
|
||||
webrtc::test::ScopedFieldTrials field_trials(
|
||||
"WebRTC-Bwe-RobustThroughputEstimatorSettings/"
|
||||
"enabled:true,assume_shared_link:false,reduce_bias:true,min_packets:10,"
|
||||
"window_duration:100ms/");
|
||||
FieldTrialBasedConfig field_trial_config;
|
||||
RobustThroughputEstimatorSettings settings(&field_trial_config);
|
||||
RobustThroughputEstimator throughput_estimator(settings);
|
||||
DataSize packet_size(DataSize::bytes(1000));
|
||||
Timestamp send_clock(Timestamp::ms(100000));
|
||||
Timestamp recv_clock(Timestamp::ms(10000));
|
||||
TimeDelta send_increment(TimeDelta::ms(20));
|
||||
TimeDelta recv_increment(TimeDelta::ms(10));
|
||||
uint16_t sequence_number = 100;
|
||||
std::vector<PacketResult> packet_feedback =
|
||||
CreateFeedbackVector(20, packet_size, send_increment, recv_increment,
|
||||
&send_clock, &recv_clock, &sequence_number);
|
||||
throughput_estimator.IncomingPacketFeedbackVector(packet_feedback);
|
||||
auto throughput = throughput_estimator.bitrate();
|
||||
EXPECT_TRUE(throughput.has_value());
|
||||
EXPECT_NEAR(throughput.value().bytes_per_sec<double>(), 50 * 1000.0,
|
||||
0.05 * 50 * 1000.0); // Allow 5% error
|
||||
}
|
||||
|
||||
} // namespace webrtc*/
|
||||
@ -1269,14 +1269,14 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
FieldTrialBasedConfig field_trial_config_;
|
||||
// The event_log_visualizer should normally not be compiled with
|
||||
// BWE_TEST_LOGGING_COMPILE_TIME_ENABLE since the normal plots won't work.
|
||||
// However, compiling with BWE_TEST_LOGGING, running with --plot_sendside_bwe
|
||||
// However, compiling with BWE_TEST_LOGGING, running with --plot=sendside_bwe
|
||||
// and piping the output to plot_dynamics.py can be used as a hack to get the
|
||||
// internal state of various BWE components. In this case, it is important
|
||||
// we don't instantiate the AcknowledgedBitrateEstimator both here and in
|
||||
// GoogCcNetworkController since that would lead to duplicate outputs.
|
||||
AcknowledgedBitrateEstimator acknowledged_bitrate_estimator(
|
||||
&field_trial_config_,
|
||||
std::make_unique<BitrateEstimator>(&field_trial_config_));
|
||||
std::unique_ptr<AcknowledgedBitrateEstimatorInterface>
|
||||
acknowledged_bitrate_estimator(
|
||||
AcknowledgedBitrateEstimatorInterface::Create(&field_trial_config_));
|
||||
#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
int64_t time_us =
|
||||
std::min({NextRtpTime(), NextRtcpTime(), NextProcessTime()});
|
||||
@ -1321,7 +1321,8 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
feedback_msg->SortedByReceiveTime();
|
||||
if (!feedback.empty()) {
|
||||
#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
acknowledged_bitrate_estimator.IncomingPacketFeedbackVector(feedback);
|
||||
acknowledged_bitrate_estimator->IncomingPacketFeedbackVector(
|
||||
feedback);
|
||||
#endif // !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
for (const PacketResult& packet : feedback)
|
||||
acked_bitrate.Update(packet.sent_packet.size.bytes(),
|
||||
@ -1334,7 +1335,7 @@ void EventLogAnalyzer::CreateSendSideBweSimulationGraph(Plot* plot) {
|
||||
float y = bitrate_bps.value_or(0) / 1000;
|
||||
acked_time_series.points.emplace_back(x, y);
|
||||
#if !(BWE_TEST_LOGGING_COMPILE_TIME_ENABLE)
|
||||
y = acknowledged_bitrate_estimator.bitrate()
|
||||
y = acknowledged_bitrate_estimator->bitrate()
|
||||
.value_or(DataRate::Zero())
|
||||
.kbps();
|
||||
acked_estimate_time_series.points.emplace_back(x, y);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user