Removes redundant delay based bwe.

This removes the legacy DelayBasedBwe to reduce code redundancy and
avoid the risk of applying changes on only one version.

Bug: webrtc:8415
Change-Id: I88aba03adbb77ee0ff0a97a8b3be6ddf028af48a
Reviewed-on: https://webrtc-review.googlesource.com/85364
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23798}
This commit is contained in:
Sebastian Jansson
2018-07-02 09:25:25 +02:00
committed by Commit Bot
parent e0eda662ef
commit 04b18cb365
19 changed files with 18 additions and 1399 deletions

View File

@ -37,7 +37,7 @@ rtc_static_library("bitrate_controller") {
"../../system_wrappers", "../../system_wrappers",
"../../system_wrappers:field_trial_api", "../../system_wrappers:field_trial_api",
"../../system_wrappers:metrics_api", "../../system_wrappers:metrics_api",
"../congestion_controller:delay_based_bwe", "../congestion_controller/goog_cc:delay_based_bwe",
"../pacing", "../pacing",
"../remote_bitrate_estimator:remote_bitrate_estimator", "../remote_bitrate_estimator:remote_bitrate_estimator",
"../rtp_rtcp", "../rtp_rtcp",

View File

@ -17,7 +17,7 @@
#include <map> #include <map>
#include "modules/congestion_controller/delay_based_bwe.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
#include "modules/include/module.h" #include "modules/include/module.h"
#include "modules/pacing/paced_sender.h" #include "modules/pacing/paced_sender.h"
#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"

View File

@ -36,7 +36,6 @@ rtc_static_library("congestion_controller") {
} }
deps = [ deps = [
":delay_based_bwe",
":transport_feedback", ":transport_feedback",
"..:module_api", "..:module_api",
"../..:webrtc_common", "../..:webrtc_common",
@ -50,6 +49,7 @@ rtc_static_library("congestion_controller") {
"../pacing", "../pacing",
"../remote_bitrate_estimator", "../remote_bitrate_estimator",
"../rtp_rtcp:rtp_rtcp_format", "../rtp_rtcp:rtp_rtcp_format",
"goog_cc:delay_based_bwe",
"goog_cc:estimators", "goog_cc:estimators",
] ]
@ -75,39 +75,11 @@ rtc_static_library("transport_feedback") {
] ]
} }
rtc_source_set("delay_based_bwe") {
configs += [ ":bwe_test_logging" ]
sources = [
"delay_based_bwe.cc",
"delay_based_bwe.h",
]
deps = [
"../../:typedefs",
"../../logging:rtc_event_bwe",
"../../logging:rtc_event_log_api",
"../../rtc_base:checks",
"../../rtc_base:rtc_base_approved",
"../../system_wrappers:field_trial_api",
"../../system_wrappers:metrics_api",
"../pacing",
"../remote_bitrate_estimator",
"goog_cc:estimators",
]
if (!build_with_chromium && is_clang) {
# Suppress warnings from the Chromium Clang plugin (bugs.webrtc.org/163).
suppressed_configs += [ "//build/config/clang:find_bad_constructs" ]
}
}
if (rtc_include_tests) { if (rtc_include_tests) {
rtc_source_set("congestion_controller_unittests") { rtc_source_set("congestion_controller_unittests") {
testonly = true testonly = true
sources = [ sources = [
"delay_based_bwe_unittest.cc",
"delay_based_bwe_unittest_helper.cc",
"delay_based_bwe_unittest_helper.h",
"probe_controller_unittest.cc", "probe_controller_unittest.cc",
"receive_side_congestion_controller_unittest.cc", "receive_side_congestion_controller_unittest.cc",
"send_side_congestion_controller_unittest.cc", "send_side_congestion_controller_unittest.cc",
@ -115,7 +87,6 @@ if (rtc_include_tests) {
] ]
deps = [ deps = [
":congestion_controller", ":congestion_controller",
":delay_based_bwe",
":mock_congestion_controller", ":mock_congestion_controller",
":transport_feedback", ":transport_feedback",
"../../logging:mocks", "../../logging:mocks",

View File

@ -1,324 +0,0 @@
/*
* 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 "modules/congestion_controller/delay_based_bwe.h"
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <string>
#include "logging/rtc_event_log/events/rtc_event_bwe_update_delay_based.h"
#include "logging/rtc_event_log/rtc_event_log.h"
#include "modules/congestion_controller/goog_cc/trendline_estimator.h"
#include "modules/pacing/paced_sender.h"
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "rtc_base/checks.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/logging.h"
#include "rtc_base/ptr_util.h"
#include "rtc_base/thread_annotations.h"
#include "system_wrappers/include/field_trial.h"
#include "system_wrappers/include/metrics.h"
#include "typedefs.h" // NOLINT(build/include)
namespace {
constexpr int kTimestampGroupLengthMs = 5;
constexpr int kAbsSendTimeFraction = 18;
constexpr int kAbsSendTimeInterArrivalUpshift = 8;
constexpr int kInterArrivalShift =
kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
constexpr double kTimestampToMs =
1000.0 / static_cast<double>(1 << kInterArrivalShift);
// This ssrc is used to fulfill the current API but will be removed
// after the API has been changed.
constexpr uint32_t kFixedSsrc = 0;
// Parameters for linear least squares fit of regression line to noisy data.
constexpr size_t kDefaultTrendlineWindowSize = 20;
constexpr double kDefaultTrendlineSmoothingCoeff = 0.9;
constexpr double kDefaultTrendlineThresholdGain = 4.0;
constexpr int kMaxConsecutiveFailedLookups = 5;
const char kBweWindowSizeInPacketsExperiment[] =
"WebRTC-BweWindowSizeInPackets";
size_t ReadTrendlineFilterWindowSize() {
std::string experiment_string =
webrtc::field_trial::FindFullName(kBweWindowSizeInPacketsExperiment);
size_t window_size;
int parsed_values =
sscanf(experiment_string.c_str(), "Enabled-%zu", &window_size);
if (parsed_values == 1) {
if (window_size > 1)
return window_size;
RTC_LOG(WARNING) << "Window size must be greater than 1.";
}
RTC_LOG(LS_WARNING) << "Failed to parse parameters for BweTrendlineFilter "
"experiment from field trial string. Using default.";
return kDefaultTrendlineWindowSize;
}
} // namespace
namespace webrtc {
DelayBasedBwe::Result::Result()
: updated(false),
probe(false),
target_bitrate_bps(0),
recovered_from_overuse(false) {}
DelayBasedBwe::Result::Result(bool probe, uint32_t target_bitrate_bps)
: updated(true),
probe(probe),
target_bitrate_bps(target_bitrate_bps),
recovered_from_overuse(false) {}
DelayBasedBwe::Result::~Result() {}
DelayBasedBwe::DelayBasedBwe(RtcEventLog* event_log, const Clock* clock)
: event_log_(event_log),
clock_(clock),
inter_arrival_(),
delay_detector_(),
last_seen_packet_ms_(-1),
uma_recorded_(false),
probe_bitrate_estimator_(event_log),
trendline_window_size_(
webrtc::field_trial::IsEnabled(kBweWindowSizeInPacketsExperiment)
? ReadTrendlineFilterWindowSize()
: kDefaultTrendlineWindowSize),
trendline_smoothing_coeff_(kDefaultTrendlineSmoothingCoeff),
trendline_threshold_gain_(kDefaultTrendlineThresholdGain),
consecutive_delayed_feedbacks_(0),
prev_bitrate_(0),
prev_state_(BandwidthUsage::kBwNormal) {
RTC_LOG(LS_INFO)
<< "Using Trendline filter for delay change estimation with window size "
<< trendline_window_size_;
delay_detector_.reset(new TrendlineEstimator(trendline_window_size_,
trendline_smoothing_coeff_,
trendline_threshold_gain_));
}
DelayBasedBwe::~DelayBasedBwe() {}
DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector,
absl::optional<uint32_t> acked_bitrate_bps) {
RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(),
packet_feedback_vector.end(),
PacketFeedbackComparator()));
RTC_DCHECK_RUNS_SERIALIZED(&network_race_);
// TOOD(holmer): An empty feedback vector here likely means that
// all acks were too late and that the send time history had
// timed out. We should reduce the rate when this occurs.
if (packet_feedback_vector.empty()) {
RTC_LOG(LS_WARNING) << "Very late feedback received.";
return DelayBasedBwe::Result();
}
if (!uma_recorded_) {
RTC_HISTOGRAM_ENUMERATION(kBweTypeHistogram,
BweNames::kSendSideTransportSeqNum,
BweNames::kBweNamesMax);
uma_recorded_ = true;
}
bool delayed_feedback = true;
bool recovered_from_overuse = false;
BandwidthUsage prev_detector_state = delay_detector_->State();
for (const auto& packet_feedback : packet_feedback_vector) {
if (packet_feedback.send_time_ms < 0)
continue;
delayed_feedback = false;
IncomingPacketFeedback(packet_feedback);
if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
delay_detector_->State() == BandwidthUsage::kBwNormal) {
recovered_from_overuse = true;
}
prev_detector_state = delay_detector_->State();
}
if (delayed_feedback) {
++consecutive_delayed_feedbacks_;
if (consecutive_delayed_feedbacks_ >= kMaxConsecutiveFailedLookups) {
consecutive_delayed_feedbacks_ = 0;
return OnLongFeedbackDelay(packet_feedback_vector.back().arrival_time_ms);
}
} else {
consecutive_delayed_feedbacks_ = 0;
return MaybeUpdateEstimate(acked_bitrate_bps, recovered_from_overuse);
}
return Result();
}
DelayBasedBwe::Result DelayBasedBwe::OnLongFeedbackDelay(
int64_t arrival_time_ms) {
// Estimate should always be valid since a start bitrate always is set in the
// Call constructor. An alternative would be to return an empty Result here,
// or to estimate the throughput based on the feedback we received.
RTC_DCHECK(rate_control_.ValidEstimate());
rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2,
arrival_time_ms);
Result result;
result.updated = true;
result.probe = false;
result.target_bitrate_bps = rate_control_.LatestEstimate();
RTC_LOG(LS_WARNING) << "Long feedback delay detected, reducing BWE to "
<< result.target_bitrate_bps;
return result;
}
void DelayBasedBwe::IncomingPacketFeedback(
const PacketFeedback& packet_feedback) {
int64_t now_ms = clock_->TimeInMilliseconds();
// Reset if the stream has timed out.
if (last_seen_packet_ms_ == -1 ||
now_ms - last_seen_packet_ms_ > kStreamTimeOutMs) {
inter_arrival_.reset(
new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
kTimestampToMs, true));
delay_detector_.reset(new TrendlineEstimator(trendline_window_size_,
trendline_smoothing_coeff_,
trendline_threshold_gain_));
}
last_seen_packet_ms_ = now_ms;
uint32_t send_time_24bits =
static_cast<uint32_t>(
((static_cast<uint64_t>(packet_feedback.send_time_ms)
<< kAbsSendTimeFraction) +
500) /
1000) &
0x00FFFFFF;
// 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;
uint32_t ts_delta = 0;
int64_t t_delta = 0;
int size_delta = 0;
if (inter_arrival_->ComputeDeltas(timestamp, packet_feedback.arrival_time_ms,
now_ms, packet_feedback.payload_size,
&ts_delta, &t_delta, &size_delta)) {
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
delay_detector_->Update(t_delta, ts_delta_ms,
packet_feedback.arrival_time_ms);
}
if (packet_feedback.pacing_info.probe_cluster_id !=
PacedPacketInfo::kNotAProbe) {
probe_bitrate_estimator_.HandleProbeAndEstimateBitrate(packet_feedback);
}
}
DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
absl::optional<uint32_t> acked_bitrate_bps,
bool recovered_from_overuse) {
Result result;
int64_t now_ms = clock_->TimeInMilliseconds();
absl::optional<int> probe_bitrate_bps =
probe_bitrate_estimator_.FetchAndResetLastEstimatedBitrateBps();
// Currently overusing the bandwidth.
if (delay_detector_->State() == BandwidthUsage::kBwOverusing) {
if (acked_bitrate_bps &&
rate_control_.TimeToReduceFurther(now_ms, *acked_bitrate_bps)) {
result.updated =
UpdateEstimate(now_ms, acked_bitrate_bps, &result.target_bitrate_bps);
} else if (!acked_bitrate_bps && rate_control_.ValidEstimate() &&
rate_control_.TimeToReduceFurther(
now_ms, rate_control_.LatestEstimate() / 2 - 1)) {
// Overusing before we have a measured acknowledged bitrate. We check
// TimeToReduceFurther (with a fake acknowledged bitrate) to avoid
// reducing too often.
// TODO(tschumim): Improve this and/or the acknowledged bitrate estimator
// so that we (almost) always have a bitrate estimate.
rate_control_.SetEstimate(rate_control_.LatestEstimate() / 2, now_ms);
result.updated = true;
result.probe = false;
result.target_bitrate_bps = rate_control_.LatestEstimate();
}
} else {
if (probe_bitrate_bps) {
result.probe = true;
result.updated = true;
result.target_bitrate_bps = *probe_bitrate_bps;
rate_control_.SetEstimate(*probe_bitrate_bps, now_ms);
} else {
result.updated =
UpdateEstimate(now_ms, acked_bitrate_bps, &result.target_bitrate_bps);
result.recovered_from_overuse = recovered_from_overuse;
}
}
BandwidthUsage detector_state = delay_detector_->State();
if ((result.updated && prev_bitrate_ != result.target_bitrate_bps) ||
detector_state != prev_state_) {
uint32_t bitrate_bps =
result.updated ? result.target_bitrate_bps : prev_bitrate_;
BWE_TEST_LOGGING_PLOT(1, "target_bitrate_bps", now_ms, bitrate_bps);
if (event_log_) {
event_log_->Log(rtc::MakeUnique<RtcEventBweUpdateDelayBased>(
bitrate_bps, detector_state));
}
prev_bitrate_ = bitrate_bps;
prev_state_ = detector_state;
}
return result;
}
bool DelayBasedBwe::UpdateEstimate(int64_t now_ms,
absl::optional<uint32_t> acked_bitrate_bps,
uint32_t* target_bitrate_bps) {
const RateControlInput input(delay_detector_->State(), acked_bitrate_bps);
*target_bitrate_bps = rate_control_.Update(&input, now_ms);
return rate_control_.ValidEstimate();
}
void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
rate_control_.SetRtt(avg_rtt_ms);
}
bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
uint32_t* bitrate_bps) const {
// Currently accessed from both the process thread (see
// ModuleRtpRtcpImpl::Process()) and the configuration thread (see
// Call::GetStats()). Should in the future only be accessed from a single
// thread.
RTC_DCHECK(ssrcs);
RTC_DCHECK(bitrate_bps);
if (!rate_control_.ValidEstimate())
return false;
*ssrcs = {kFixedSsrc};
*bitrate_bps = rate_control_.LatestEstimate();
return true;
}
void DelayBasedBwe::SetStartBitrate(int start_bitrate_bps) {
RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: " << start_bitrate_bps;
rate_control_.SetStartBitrate(start_bitrate_bps);
}
void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
// Called from both the configuration thread and the network thread. Shouldn't
// be called from the network thread in the future.
rate_control_.SetMinBitrate(min_bitrate_bps);
}
int64_t DelayBasedBwe::GetExpectedBwePeriodMs() const {
return rate_control_.GetExpectedBandwidthPeriodMs();
}
} // namespace webrtc

View File

@ -1,90 +0,0 @@
/*
* 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 MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_
#define MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_
#include <memory>
#include <utility>
#include <vector>
#include "modules/congestion_controller/goog_cc/delay_increase_detector_interface.h"
#include "modules/congestion_controller/goog_cc/probe_bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/aimd_rate_control.h"
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/inter_arrival.h"
#include "rtc_base/checks.h"
#include "rtc_base/constructormagic.h"
#include "rtc_base/race_checker.h"
namespace webrtc {
class RtcEventLog;
class DelayBasedBwe {
public:
static const int64_t kStreamTimeOutMs = 2000;
struct Result {
Result();
Result(bool probe, uint32_t target_bitrate_bps);
~Result();
bool updated;
bool probe;
uint32_t target_bitrate_bps;
bool recovered_from_overuse;
};
DelayBasedBwe(RtcEventLog* event_log, const Clock* clock);
virtual ~DelayBasedBwe();
Result IncomingPacketFeedbackVector(
const std::vector<PacketFeedback>& packet_feedback_vector,
absl::optional<uint32_t> acked_bitrate_bps);
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms);
bool LatestEstimate(std::vector<uint32_t>* ssrcs,
uint32_t* bitrate_bps) const;
void SetStartBitrate(int start_bitrate_bps);
void SetMinBitrate(int min_bitrate_bps);
int64_t GetExpectedBwePeriodMs() const;
private:
void IncomingPacketFeedback(const PacketFeedback& packet_feedback);
Result OnLongFeedbackDelay(int64_t arrival_time_ms);
Result MaybeUpdateEstimate(absl::optional<uint32_t> acked_bitrate_bps,
bool request_probe);
// Updates the current remote rate estimate and returns true if a valid
// estimate exists.
bool UpdateEstimate(int64_t now_ms,
absl::optional<uint32_t> acked_bitrate_bps,
uint32_t* target_bitrate_bps);
rtc::RaceChecker network_race_;
RtcEventLog* const event_log_;
const Clock* const clock_;
std::unique_ptr<InterArrival> inter_arrival_;
std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_;
int64_t last_seen_packet_ms_;
bool uma_recorded_;
AimdRateControl rate_control_;
ProbeBitrateEstimator probe_bitrate_estimator_;
size_t trendline_window_size_;
double trendline_smoothing_coeff_;
double trendline_threshold_gain_;
int consecutive_delayed_feedbacks_;
uint32_t prev_bitrate_;
BandwidthUsage prev_state_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe);
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_

View File

@ -1,236 +0,0 @@
/*
* 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 "modules/congestion_controller/delay_based_bwe.h"
#include "modules/congestion_controller/delay_based_bwe_unittest_helper.h"
#include "modules/pacing/paced_sender.h"
#include "rtc_base/constructormagic.h"
#include "system_wrappers/include/clock.h"
#include "test/field_trial.h"
#include "test/gtest.h"
namespace webrtc {
namespace {
constexpr int kNumProbesCluster0 = 5;
constexpr int kNumProbesCluster1 = 8;
const PacedPacketInfo kPacingInfo0(0, kNumProbesCluster0, 2000);
const PacedPacketInfo kPacingInfo1(1, kNumProbesCluster1, 4000);
constexpr float kTargetUtilizationFraction = 0.95f;
} // namespace
TEST_F(LegacyDelayBasedBweTest, NoCrashEmptyFeedback) {
std::vector<PacketFeedback> packet_feedback_vector;
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
absl::nullopt);
}
TEST_F(LegacyDelayBasedBweTest, NoCrashOnlyLostFeedback) {
std::vector<PacketFeedback> packet_feedback_vector;
packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
PacketFeedback::kNoSendTime,
0, 1500, PacedPacketInfo()));
packet_feedback_vector.push_back(PacketFeedback(PacketFeedback::kNotReceived,
PacketFeedback::kNoSendTime,
1, 1500, PacedPacketInfo()));
bitrate_estimator_->IncomingPacketFeedbackVector(packet_feedback_vector,
absl::nullopt);
}
TEST_F(LegacyDelayBasedBweTest, 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 < kNumProbesCluster0; ++i) {
clock_.AdvanceTimeMilliseconds(10);
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo0);
}
EXPECT_TRUE(bitrate_observer_.updated());
// Second burst sent at 8 * 1000 / 5 = 1600 kbps.
for (int i = 0; i < kNumProbesCluster1; ++i) {
clock_.AdvanceTimeMilliseconds(5);
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo1);
}
EXPECT_TRUE(bitrate_observer_.updated());
EXPECT_GT(bitrate_observer_.latest_bitrate(), 1500000u);
}
TEST_F(LegacyDelayBasedBweTest, 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 < kNumProbesCluster0; ++i) {
clock_.AdvanceTimeMilliseconds(5);
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, now_ms, seq_num++, 1000, kPacingInfo0);
// Non-paced packet, arriving 5 ms after.
clock_.AdvanceTimeMilliseconds(5);
IncomingFeedback(now_ms, now_ms, seq_num++, 100, PacedPacketInfo());
}
EXPECT_TRUE(bitrate_observer_.updated());
EXPECT_GT(bitrate_observer_.latest_bitrate(), 800000u);
}
TEST_F(LegacyDelayBasedBweTest, 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;
for (int i = 0; i < kNumProbesCluster0; ++i) {
clock_.AdvanceTimeMilliseconds(1);
send_time_ms += 10;
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo0);
}
EXPECT_FALSE(bitrate_observer_.updated());
}
TEST_F(LegacyDelayBasedBweTest, 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.
// Since the receive rate is significantly below the send rate, we expect to
// use 95% of the estimated capacity.
int64_t send_time_ms = 0;
for (int i = 0; i < kNumProbesCluster1; ++i) {
clock_.AdvanceTimeMilliseconds(7);
send_time_ms += 5;
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo1);
}
EXPECT_TRUE(bitrate_observer_.updated());
EXPECT_NEAR(bitrate_observer_.latest_bitrate(),
kTargetUtilizationFraction * 1140000u, 10000u);
}
TEST_F(LegacyDelayBasedBweTest, 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.
// Since the receive rate is significantly below the send rate, we expect to
// use 95% of the estimated capacity.
int64_t send_time_ms = 0;
for (int i = 0; i < kNumProbesCluster1; ++i) {
clock_.AdvanceTimeMilliseconds(2);
send_time_ms += 1;
now_ms = clock_.TimeInMilliseconds();
IncomingFeedback(now_ms, send_time_ms, seq_num++, 1000, kPacingInfo1);
}
EXPECT_TRUE(bitrate_observer_.updated());
EXPECT_NEAR(bitrate_observer_.latest_bitrate(),
kTargetUtilizationFraction * 4000000u, 10000u);
}
TEST_F(LegacyDelayBasedBweTest, GetExpectedBwePeriodMs) {
int64_t default_interval_ms = bitrate_estimator_->GetExpectedBwePeriodMs();
EXPECT_GT(default_interval_ms, 0);
CapacityDropTestHelper(1, true, 333, 0);
int64_t interval_ms = bitrate_estimator_->GetExpectedBwePeriodMs();
EXPECT_GT(interval_ms, 0);
EXPECT_NE(interval_ms, default_interval_ms);
}
TEST_F(LegacyDelayBasedBweTest, InitialBehavior) {
InitialBehaviorTestHelper(730000);
}
TEST_F(LegacyDelayBasedBweTest, RateIncreaseReordering) {
RateIncreaseReorderingTestHelper(730000);
}
TEST_F(LegacyDelayBasedBweTest, RateIncreaseRtpTimestamps) {
RateIncreaseRtpTimestampsTestHelper(627);
}
TEST_F(LegacyDelayBasedBweTest, CapacityDropOneStream) {
CapacityDropTestHelper(1, false, 300, 0);
}
TEST_F(LegacyDelayBasedBweTest, CapacityDropPosOffsetChange) {
CapacityDropTestHelper(1, false, 867, 30000);
}
TEST_F(LegacyDelayBasedBweTest, CapacityDropNegOffsetChange) {
CapacityDropTestHelper(1, false, 933, -30000);
}
TEST_F(LegacyDelayBasedBweTest, CapacityDropOneStreamWrap) {
CapacityDropTestHelper(1, true, 333, 0);
}
TEST_F(LegacyDelayBasedBweTest, TestTimestampGrouping) {
TestTimestampGroupingTestHelper();
}
TEST_F(LegacyDelayBasedBweTest, 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(LegacyDelayBasedBweTest, 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);
}
TEST_F(LegacyDelayBasedBweTest, TestInitialOveruse) {
const uint32_t kStartBitrate = 300e3;
const uint32_t kInitialCapacityBps = 200e3;
const uint32_t kDummySsrc = 0;
// High FPS to ensure that we send a lot of packets in a short time.
const int kFps = 90;
stream_generator_->AddStream(new test::RtpStream(kFps, kStartBitrate));
stream_generator_->set_capacity_bps(kInitialCapacityBps);
// Needed to initialize the AimdRateControl.
bitrate_estimator_->SetStartBitrate(kStartBitrate);
// Produce 30 frames (in 1/3 second) and give them to the estimator.
uint32_t bitrate_bps = kStartBitrate;
bool seen_overuse = false;
for (int i = 0; i < 30; ++i) {
bool overuse = GenerateAndProcessFrame(kDummySsrc, bitrate_bps);
// The purpose of this test is to ensure that we back down even if we don't
// have any acknowledged bitrate estimate yet. Hence, if the test works
// as expected, we should not have a measured bitrate yet.
EXPECT_FALSE(acknowledged_bitrate_estimator_->bitrate_bps().has_value());
if (overuse) {
EXPECT_TRUE(bitrate_observer_.updated());
EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000);
bitrate_bps = bitrate_observer_.latest_bitrate();
seen_overuse = true;
break;
} else if (bitrate_observer_.updated()) {
bitrate_bps = bitrate_observer_.latest_bitrate();
bitrate_observer_.Reset();
}
}
EXPECT_TRUE(seen_overuse);
EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000);
}
} // namespace webrtc

View File

@ -1,514 +0,0 @@
/*
* 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 "modules/congestion_controller/delay_based_bwe_unittest_helper.h"
#include <algorithm>
#include <limits>
#include <utility>
#include "modules/congestion_controller/delay_based_bwe.h"
#include "rtc_base/checks.h"
#include "rtc_base/ptr_util.h"
namespace webrtc {
constexpr size_t kMtu = 1200;
constexpr uint32_t kAcceptedBitrateErrorBps = 50000;
// Number of packets needed before we have a valid estimate.
constexpr int kNumInitialPackets = 2;
constexpr int kInitialProbingPackets = 5;
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<PacketFeedback>* 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) {
PacketFeedback packet(-1, sequence_number_++);
packet.send_time_ms = (time_now_us + kSendSideOffsetUs) / 1000;
packet.payload_size = payload_size;
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<PacketFeedback>* 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 (PacketFeedback& 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
LegacyDelayBasedBweTest::LegacyDelayBasedBweTest()
: clock_(100000000),
acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
bitrate_estimator_(new DelayBasedBwe(nullptr, &clock_)),
stream_generator_(new test::StreamGenerator(1e6, // Capacity.
clock_.TimeInMicroseconds())),
arrival_time_offset_ms_(0),
first_update_(true) {}
LegacyDelayBasedBweTest::~LegacyDelayBasedBweTest() {}
void LegacyDelayBasedBweTest::AddDefaultStream() {
stream_generator_->AddStream(new test::RtpStream(30, 3e5));
}
const uint32_t LegacyDelayBasedBweTest::kDefaultSsrc = 0;
void LegacyDelayBasedBweTest::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,
PacedPacketInfo());
}
void LegacyDelayBasedBweTest::IncomingFeedback(
int64_t arrival_time_ms,
int64_t send_time_ms,
uint16_t sequence_number,
size_t payload_size,
const PacedPacketInfo& pacing_info) {
RTC_CHECK_GE(arrival_time_ms + arrival_time_offset_ms_, 0);
PacketFeedback packet(arrival_time_ms + arrival_time_offset_ms_, send_time_ms,
sequence_number, payload_size, pacing_info);
std::vector<PacketFeedback> packets;
packets.push_back(packet);
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
DelayBasedBwe::Result result =
bitrate_estimator_->IncomingPacketFeedbackVector(
packets, acknowledged_bitrate_estimator_->bitrate_bps());
const uint32_t kDummySsrc = 0;
if (result.updated) {
bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
result.target_bitrate_bps);
}
}
// 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 LegacyDelayBasedBweTest::GenerateAndProcessFrame(uint32_t ssrc,
uint32_t bitrate_bps) {
stream_generator_->SetBitrateBps(bitrate_bps);
std::vector<PacketFeedback> 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_;
}
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(packets);
DelayBasedBwe::Result result =
bitrate_estimator_->IncomingPacketFeedbackVector(
packets, acknowledged_bitrate_estimator_->bitrate_bps());
const uint32_t kDummySsrc = 0;
if (result.updated) {
bitrate_observer_.OnReceiveBitrateChanged({kDummySsrc},
result.target_bitrate_bps);
if (!first_update_ && result.target_bitrate_bps < bitrate_bps)
overuse = true;
first_update_ = false;
}
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 LegacyDelayBasedBweTest::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 LegacyDelayBasedBweTest::InitialBehaviorTestHelper(
uint32_t expected_converge_bitrate) {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
const PacedPacketInfo kPacingInfo(0, 5, 5000);
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);
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) {
// NOTE!!! If the following line is moved under the if case then this test
// wont work on windows realease bots.
PacedPacketInfo pacing_info =
i < kInitialProbingPackets ? kPacingInfo : PacedPacketInfo();
if (i == kNumInitialPackets) {
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, pacing_info);
clock_.AdvanceTimeMilliseconds(1000 / kFramerate);
send_time_ms += kFrameIntervalMs;
}
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);
}
void LegacyDelayBasedBweTest::RateIncreaseReorderingTestHelper(
uint32_t expected_bitrate_bps) {
const int kFramerate = 50; // 50 fps to avoid rounding errors.
const int kFrameIntervalMs = 1000 / kFramerate;
const PacedPacketInfo kPacingInfo(0, 5, 5000);
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) {
// NOTE!!! If the following line is moved under the if case then this test
// wont work on windows realease bots.
PacedPacketInfo pacing_info =
i < kInitialProbingPackets ? kPacingInfo : PacedPacketInfo();
// 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.
EXPECT_FALSE(bitrate_observer_.updated()); // No valid estimate.
}
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
sequence_number++, kMtu, pacing_info);
clock_.AdvanceTimeMilliseconds(kFrameIntervalMs);
send_time_ms += kFrameIntervalMs;
}
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;
}
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 LegacyDelayBasedBweTest::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_EQ(expected_iterations, iterations);
}
void LegacyDelayBasedBweTest::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, 180000u);
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 LegacyDelayBasedBweTest::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);
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;
}
EXPECT_TRUE(bitrate_observer_.updated());
// Should have reduced the estimate.
EXPECT_LT(bitrate_observer_.latest_bitrate(), 400000u);
}
void LegacyDelayBasedBweTest::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;
}
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;
for (size_t i = 0; i < 24; ++i) {
IncomingFeedback(clock_.TimeInMilliseconds(), send_time_ms,
sequence_number++, 1000);
clock_.AdvanceTimeMilliseconds(2 * kFrameIntervalMs);
send_time_ms += kFrameIntervalMs;
}
uint32_t bitrate_after = 0;
bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after);
EXPECT_LT(bitrate_after, bitrate_before);
}
} // namespace webrtc

View File

@ -1,178 +0,0 @@
/*
* 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 MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_
#define MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_
#include <list>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#include "modules/congestion_controller/delay_based_bwe.h"
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
#include "modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "rtc_base/constructormagic.h"
#include "system_wrappers/include/clock.h"
#include "test/gtest.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<PacketFeedback>* 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<PacketFeedback>* 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 LegacyDelayBasedBweTest : public ::testing::Test {
public:
LegacyDelayBasedBweTest();
virtual ~LegacyDelayBasedBweTest();
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,
const PacedPacketInfo& pacing_info);
// 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.
test::TestBitrateObserver bitrate_observer_;
std::unique_ptr<AcknowledgedBitrateEstimator> acknowledged_bitrate_estimator_;
std::unique_ptr<DelayBasedBwe> bitrate_estimator_;
std::unique_ptr<test::StreamGenerator> stream_generator_;
int64_t arrival_time_offset_ms_;
bool first_update_;
RTC_DISALLOW_COPY_AND_ASSIGN(LegacyDelayBasedBweTest);
};
} // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_UNITTEST_HELPER_H_

View File

@ -70,7 +70,6 @@ size_t ReadTrendlineFilterWindowSize() {
} // namespace } // namespace
namespace webrtc { namespace webrtc {
namespace webrtc_cc {
DelayBasedBwe::Result::Result() DelayBasedBwe::Result::Result()
: updated(false), : updated(false),
@ -312,7 +311,7 @@ bool DelayBasedBwe::LatestEstimate(std::vector<uint32_t>* ssrcs,
} }
void DelayBasedBwe::SetStartBitrate(int start_bitrate_bps) { void DelayBasedBwe::SetStartBitrate(int start_bitrate_bps) {
RTC_LOG(LS_WARNING) << "BWE Setting start bitrate to: " << start_bitrate_bps; RTC_LOG(LS_INFO) << "BWE Setting start bitrate to: " << start_bitrate_bps;
rate_control_.SetStartBitrate(start_bitrate_bps); rate_control_.SetStartBitrate(start_bitrate_bps);
} }
@ -325,5 +324,4 @@ void DelayBasedBwe::SetMinBitrate(int min_bitrate_bps) {
int64_t DelayBasedBwe::GetExpectedBwePeriodMs() const { int64_t DelayBasedBwe::GetExpectedBwePeriodMs() const {
return rate_control_.GetExpectedBandwidthPeriodMs(); return rate_control_.GetExpectedBandwidthPeriodMs();
} }
} // namespace webrtc_cc
} // namespace webrtc } // namespace webrtc

View File

@ -27,8 +27,6 @@
namespace webrtc { namespace webrtc {
class RtcEventLog; class RtcEventLog;
namespace webrtc_cc {
class DelayBasedBwe { class DelayBasedBwe {
public: public:
static const int64_t kStreamTimeOutMs = 2000; static const int64_t kStreamTimeOutMs = 2000;
@ -88,7 +86,6 @@ class DelayBasedBwe {
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe); RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe);
}; };
} // namespace webrtc_cc
} // namespace webrtc } // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_ #endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_H_

View File

@ -17,7 +17,6 @@
#include "test/gtest.h" #include "test/gtest.h"
namespace webrtc { namespace webrtc {
namespace webrtc_cc {
namespace { namespace {
constexpr int kNumProbesCluster0 = 5; constexpr int kNumProbesCluster0 = 5;
@ -235,5 +234,4 @@ TEST_F(DelayBasedBweTest, TestInitialOveruse) {
EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000); EXPECT_NEAR(bitrate_observer_.latest_bitrate(), kStartBitrate / 2, 15000);
} }
} // namespace webrtc_cc
} // namespace webrtc } // namespace webrtc

View File

@ -18,8 +18,6 @@
#include "rtc_base/ptr_util.h" #include "rtc_base/ptr_util.h"
namespace webrtc { namespace webrtc {
namespace webrtc_cc {
constexpr size_t kMtu = 1200; constexpr size_t kMtu = 1200;
constexpr uint32_t kAcceptedBitrateErrorBps = 50000; constexpr uint32_t kAcceptedBitrateErrorBps = 50000;
@ -513,5 +511,4 @@ void DelayBasedBweTest::TestWrappingHelper(int silence_time_s) {
bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after); bitrate_estimator_->LatestEstimate(&ssrcs, &bitrate_after);
EXPECT_LT(bitrate_after, bitrate_before); EXPECT_LT(bitrate_after, bitrate_before);
} }
} // namespace webrtc_cc
} // namespace webrtc } // namespace webrtc

View File

@ -25,7 +25,6 @@
#include "test/gtest.h" #include "test/gtest.h"
namespace webrtc { namespace webrtc {
namespace webrtc_cc {
namespace test { namespace test {
class TestBitrateObserver : public RemoteBitrateObserver { class TestBitrateObserver : public RemoteBitrateObserver {
@ -174,7 +173,6 @@ class DelayBasedBweTest : public ::testing::Test {
RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest); RTC_DISALLOW_COPY_AND_ASSIGN(DelayBasedBweTest);
}; };
} // namespace webrtc_cc
} // namespace webrtc } // namespace webrtc
#endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_UNITTEST_HELPER_H_ #endif // MODULES_CONGESTION_CONTROLLER_GOOG_CC_DELAY_BASED_BWE_UNITTEST_HELPER_H_

View File

@ -15,7 +15,7 @@
#include <vector> #include <vector>
#include "common_types.h" // NOLINT(build/include) #include "common_types.h" // NOLINT(build/include)
#include "modules/congestion_controller/delay_based_bwe.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
#include "modules/congestion_controller/include/network_changed_observer.h" #include "modules/congestion_controller/include/network_changed_observer.h"
#include "modules/congestion_controller/include/send_side_congestion_controller_interface.h" #include "modules/congestion_controller/include/send_side_congestion_controller_interface.h"
#include "modules/congestion_controller/transport_feedback_adapter.h" #include "modules/congestion_controller/transport_feedback_adapter.h"

View File

@ -128,7 +128,7 @@ SendSideCongestionController::SendSideCongestionController(
pause_pacer_(false), pause_pacer_(false),
pacer_paused_(false), pacer_paused_(false),
min_bitrate_bps_(congestion_controller::GetMinBitrateBps()), min_bitrate_bps_(congestion_controller::GetMinBitrateBps()),
delay_based_bwe_(new DelayBasedBwe(event_log_, clock_)), delay_based_bwe_(new DelayBasedBwe(event_log_)),
in_cwnd_experiment_(CwndExperimentEnabled()), in_cwnd_experiment_(CwndExperimentEnabled()),
accepted_queue_ms_(kDefaultAcceptedQueueMs), accepted_queue_ms_(kDefaultAcceptedQueueMs),
was_in_alr_(false), was_in_alr_(false),
@ -217,7 +217,7 @@ void SendSideCongestionController::OnNetworkRouteChanged(
rtc::CritScope cs(&bwe_lock_); rtc::CritScope cs(&bwe_lock_);
transport_overhead_bytes_per_packet_ = network_route.packet_overhead; transport_overhead_bytes_per_packet_ = network_route.packet_overhead;
min_bitrate_bps_ = min_bitrate_bps; min_bitrate_bps_ = min_bitrate_bps;
delay_based_bwe_.reset(new DelayBasedBwe(event_log_, clock_)); delay_based_bwe_.reset(new DelayBasedBwe(event_log_));
acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator()); acknowledged_bitrate_estimator_.reset(new AcknowledgedBitrateEstimator());
delay_based_bwe_->SetStartBitrate(bitrate_bps); delay_based_bwe_->SetStartBitrate(bitrate_bps);
delay_based_bwe_->SetMinBitrate(min_bitrate_bps); delay_based_bwe_->SetMinBitrate(min_bitrate_bps);
@ -304,7 +304,7 @@ void SendSideCongestionController::OnSentPacket(
void SendSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms, void SendSideCongestionController::OnRttUpdate(int64_t avg_rtt_ms,
int64_t max_rtt_ms) { int64_t max_rtt_ms) {
rtc::CritScope cs(&bwe_lock_); rtc::CritScope cs(&bwe_lock_);
delay_based_bwe_->OnRttUpdate(avg_rtt_ms, max_rtt_ms); delay_based_bwe_->OnRttUpdate(avg_rtt_ms);
} }
int64_t SendSideCongestionController::TimeUntilNextProcess() { int64_t SendSideCongestionController::TimeUntilNextProcess() {
@ -367,7 +367,8 @@ void SendSideCongestionController::OnTransportFeedback(
{ {
rtc::CritScope cs(&bwe_lock_); rtc::CritScope cs(&bwe_lock_);
result = delay_based_bwe_->IncomingPacketFeedbackVector( result = delay_based_bwe_->IncomingPacketFeedbackVector(
feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps()); feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
clock_->TimeInMilliseconds());
} }
if (result.updated) { if (result.updated) {
bitrate_controller_->OnDelayBasedBweResult(result); bitrate_controller_->OnDelayBasedBweResult(result);

View File

@ -151,8 +151,8 @@ if (rtc_include_tests) {
"../../test:test_support", "../../test:test_support",
"../bitrate_controller", "../bitrate_controller",
"../congestion_controller", "../congestion_controller",
"../congestion_controller:delay_based_bwe",
"../congestion_controller:transport_feedback", "../congestion_controller:transport_feedback",
"../congestion_controller/goog_cc:delay_based_bwe",
"../congestion_controller/goog_cc:estimators", "../congestion_controller/goog_cc:estimators",
"../congestion_controller/rtp:transport_feedback", "../congestion_controller/rtp:transport_feedback",
"../pacing", "../pacing",

View File

@ -12,7 +12,7 @@
#include <algorithm> #include <algorithm>
#include "modules/congestion_controller/delay_based_bwe.h" #include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
#include "modules/remote_bitrate_estimator/test/bwe_test_logging.h" #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
#include "rtc_base/logging.h" #include "rtc_base/logging.h"
#include "rtc_base/ptr_util.h" #include "rtc_base/ptr_util.h"
@ -32,7 +32,7 @@ SendSideBweSender::SendSideBweSender(int kbps,
&event_log_)), &event_log_)),
acknowledged_bitrate_estimator_( acknowledged_bitrate_estimator_(
rtc::MakeUnique<AcknowledgedBitrateEstimator>()), rtc::MakeUnique<AcknowledgedBitrateEstimator>()),
bwe_(new DelayBasedBwe(nullptr, clock)), bwe_(new DelayBasedBwe(nullptr)),
feedback_observer_(bitrate_controller_.get()), feedback_observer_(bitrate_controller_.get()),
clock_(clock), clock_(clock),
send_time_history_(clock_, 10000), send_time_history_(clock_, 10000),
@ -72,7 +72,7 @@ void SendSideBweSender::GiveFeedback(const FeedbackPacket& feedback) {
int64_t rtt_ms = int64_t rtt_ms =
clock_->TimeInMilliseconds() - feedback.latest_send_time_ms(); clock_->TimeInMilliseconds() - feedback.latest_send_time_ms();
bwe_->OnRttUpdate(rtt_ms, rtt_ms); bwe_->OnRttUpdate(rtt_ms);
BWE_TEST_LOGGING_PLOT(1, "RTT", clock_->TimeInMilliseconds(), rtt_ms); BWE_TEST_LOGGING_PLOT(1, "RTT", clock_->TimeInMilliseconds(), rtt_ms);
std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(), std::sort(packet_feedback_vector.begin(), packet_feedback_vector.end(),
@ -80,7 +80,8 @@ void SendSideBweSender::GiveFeedback(const FeedbackPacket& feedback) {
acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector( acknowledged_bitrate_estimator_->IncomingPacketFeedbackVector(
packet_feedback_vector); packet_feedback_vector);
DelayBasedBwe::Result result = bwe_->IncomingPacketFeedbackVector( DelayBasedBwe::Result result = bwe_->IncomingPacketFeedbackVector(
packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps()); packet_feedback_vector, acknowledged_bitrate_estimator_->bitrate_bps(),
clock_->TimeInMilliseconds());
if (result.updated) if (result.updated)
bitrate_controller_->OnDelayBasedBweResult(result); bitrate_controller_->OnDelayBasedBweResult(result);

View File

@ -239,7 +239,7 @@ if (!build_with_chromium) {
# TODO(kwiberg): Remove this dependency. # TODO(kwiberg): Remove this dependency.
"../api/audio_codecs:audio_codecs_api", "../api/audio_codecs:audio_codecs_api",
"../modules/congestion_controller", "../modules/congestion_controller",
"../modules/congestion_controller:delay_based_bwe", "../modules/congestion_controller/goog_cc:delay_based_bwe",
"../modules/congestion_controller/goog_cc:estimators", "../modules/congestion_controller/goog_cc:estimators",
"../modules/pacing", "../modules/pacing",
"../modules/rtp_rtcp", "../modules/rtp_rtcp",

View File

@ -31,9 +31,9 @@
#include "modules/audio_coding/neteq/tools/neteq_replacement_input.h" #include "modules/audio_coding/neteq/tools/neteq_replacement_input.h"
#include "modules/audio_coding/neteq/tools/neteq_test.h" #include "modules/audio_coding/neteq/tools/neteq_test.h"
#include "modules/audio_coding/neteq/tools/resample_input_audio_file.h" #include "modules/audio_coding/neteq/tools/resample_input_audio_file.h"
#include "modules/congestion_controller/delay_based_bwe.h"
#include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/acknowledged_bitrate_estimator.h"
#include "modules/congestion_controller/goog_cc/bitrate_estimator.h" #include "modules/congestion_controller/goog_cc/bitrate_estimator.h"
#include "modules/congestion_controller/goog_cc/delay_based_bwe.h"
#include "modules/congestion_controller/include/receive_side_congestion_controller.h" #include "modules/congestion_controller/include/receive_side_congestion_controller.h"
#include "modules/congestion_controller/include/send_side_congestion_controller.h" #include "modules/congestion_controller/include/send_side_congestion_controller.h"
#include "modules/include/module_common_types.h" #include "modules/include/module_common_types.h"