Use |probe_cluster_id| to cluster packets.

Introduced new class DelayBasedProbingEstimator which is a copy of
RemoteBitrateEstimatorAbsSendTime with only minor changes. This makes probing
more reliable but is still not usable for mid-call probing.

BUG=

Review-Url: https://codereview.webrtc.org/2038023002
Cr-Commit-Position: refs/heads/master@{#13195}
This commit is contained in:
philipel 2016-06-17 09:21:34 -07:00 committed by Commit bot
parent 217fb66e16
commit 863a8264cc
7 changed files with 802 additions and 1 deletions

View File

@ -11,6 +11,8 @@ import("../../build/webrtc.gni")
source_set("congestion_controller") {
sources = [
"congestion_controller.cc",
"delay_based_bwe.cc",
"delay_based_bwe.h",
"include/congestion_controller.h",
]

View File

@ -20,6 +20,7 @@
#include "webrtc/base/socket.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
#include "webrtc/modules/remote_bitrate_estimator/include/send_time_history.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_abs_send_time.h"
#include "webrtc/modules/remote_bitrate_estimator/remote_bitrate_estimator_single_stream.h"
@ -207,7 +208,7 @@ CongestionController::~CongestionController() {}
void CongestionController::Init() {
transport_feedback_adapter_.SetBitrateEstimator(
new RemoteBitrateEstimatorAbsSendTime(&transport_feedback_adapter_));
new DelayBasedBwe(&transport_feedback_adapter_));
transport_feedback_adapter_.GetBitrateEstimator()->SetMinBitrate(
min_bitrate_bps_);
}

View File

@ -19,6 +19,8 @@
'sources': [
'congestion_controller.cc',
'include/congestion_controller.h',
'delay_based_bwe.cc',
'delay_based_bwe.h',
],
# TODO(jschuh): Bug 1348: fix size_t to int truncations.
'msvs_disabled_warnings': [ 4267, ],

View File

@ -0,0 +1,406 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
#include <math.h>
#include <algorithm>
#include "webrtc/base/checks.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/thread_annotations.h"
#include "webrtc/modules/pacing/paced_sender.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
#include "webrtc/typedefs.h"
namespace {
enum {
kTimestampGroupLengthMs = 5,
kAbsSendTimeFraction = 18,
kAbsSendTimeInterArrivalUpshift = 8,
kInterArrivalShift = kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift,
kInitialProbingIntervalMs = 2000,
kMinClusterSize = 4,
kMaxProbePackets = 15,
kExpectedNumberOfProbes = 3
};
static const double kTimestampToMs =
1000.0 / static_cast<double>(1 << kInterArrivalShift);
template <typename K, typename V>
std::vector<K> Keys(const std::map<K, V>& map) {
std::vector<K> keys;
keys.reserve(map.size());
for (typename std::map<K, V>::const_iterator it = map.begin();
it != map.end(); ++it) {
keys.push_back(it->first);
}
return keys;
}
uint32_t ConvertMsTo24Bits(int64_t time_ms) {
uint32_t time_24_bits =
static_cast<uint32_t>(
((static_cast<uint64_t>(time_ms) << kAbsSendTimeFraction) + 500) /
1000) &
0x00FFFFFF;
return time_24_bits;
}
} // namespace
namespace webrtc {
void DelayBasedBwe::AddCluster(std::list<Cluster>* clusters, Cluster* cluster) {
cluster->send_mean_ms /= static_cast<float>(cluster->count);
cluster->recv_mean_ms /= static_cast<float>(cluster->count);
cluster->mean_size /= cluster->count;
clusters->push_back(*cluster);
}
DelayBasedBwe::DelayBasedBwe(RemoteBitrateObserver* observer)
: observer_(observer),
inter_arrival_(),
estimator_(),
detector_(OverUseDetectorOptions()),
incoming_bitrate_(kBitrateWindowMs, 8000),
total_probes_received_(0),
first_packet_time_ms_(-1),
last_update_ms_(-1),
ssrcs_() {
RTC_DCHECK(observer_);
// NOTE! The BitrateEstimatorTest relies on this EXACT log line.
LOG(LS_INFO) << "RemoteBitrateEstimatorAbsSendTime: Instantiating.";
network_thread_.DetachFromThread();
}
void DelayBasedBwe::ComputeClusters(std::list<Cluster>* clusters) const {
Cluster current;
int64_t prev_send_time = -1;
int64_t prev_recv_time = -1;
int last_probe_cluster_id = -1;
for (std::list<Probe>::const_iterator it = probes_.begin();
it != probes_.end(); ++it) {
if (last_probe_cluster_id == -1)
last_probe_cluster_id = it->cluster_id;
if (prev_send_time >= 0) {
int send_delta_ms = it->send_time_ms - prev_send_time;
int recv_delta_ms = it->recv_time_ms - prev_recv_time;
if (send_delta_ms >= 1 && recv_delta_ms >= 1) {
++current.num_above_min_delta;
}
if (it->cluster_id != last_probe_cluster_id) {
if (current.count >= kMinClusterSize)
AddCluster(clusters, &current);
current = Cluster();
}
current.send_mean_ms += send_delta_ms;
current.recv_mean_ms += recv_delta_ms;
current.mean_size += it->payload_size;
++current.count;
last_probe_cluster_id = it->cluster_id;
}
prev_send_time = it->send_time_ms;
prev_recv_time = it->recv_time_ms;
}
if (current.count >= kMinClusterSize)
AddCluster(clusters, &current);
}
std::list<DelayBasedBwe::Cluster>::const_iterator DelayBasedBwe::FindBestProbe(
const std::list<Cluster>& clusters) const {
int highest_probe_bitrate_bps = 0;
std::list<Cluster>::const_iterator best_it = clusters.end();
for (std::list<Cluster>::const_iterator it = clusters.begin();
it != clusters.end(); ++it) {
if (it->send_mean_ms == 0 || it->recv_mean_ms == 0)
continue;
int send_bitrate_bps = it->mean_size * 8 * 1000 / it->send_mean_ms;
int recv_bitrate_bps = it->mean_size * 8 * 1000 / it->recv_mean_ms;
if (it->num_above_min_delta > it->count / 2 &&
(it->recv_mean_ms - it->send_mean_ms <= 2.0f &&
it->send_mean_ms - it->recv_mean_ms <= 5.0f)) {
int probe_bitrate_bps =
std::min(it->GetSendBitrateBps(), it->GetRecvBitrateBps());
if (probe_bitrate_bps > highest_probe_bitrate_bps) {
highest_probe_bitrate_bps = probe_bitrate_bps;
best_it = it;
}
} else {
LOG(LS_INFO) << "Probe failed, sent at " << send_bitrate_bps
<< " bps, received at " << recv_bitrate_bps
<< " bps. Mean send delta: " << it->send_mean_ms
<< " ms, mean recv delta: " << it->recv_mean_ms
<< " ms, num probes: " << it->count;
break;
}
}
return best_it;
}
DelayBasedBwe::ProbeResult DelayBasedBwe::ProcessClusters(int64_t now_ms) {
std::list<Cluster> clusters;
ComputeClusters(&clusters);
if (clusters.empty()) {
// If we reach the max number of probe packets and still have no clusters,
// we will remove the oldest one.
if (probes_.size() >= kMaxProbePackets)
probes_.pop_front();
return ProbeResult::kNoUpdate;
}
std::list<Cluster>::const_iterator best_it = FindBestProbe(clusters);
if (best_it != clusters.end()) {
int probe_bitrate_bps =
std::min(best_it->GetSendBitrateBps(), best_it->GetRecvBitrateBps());
// Make sure that a probe sent on a lower bitrate than our estimate can't
// reduce the estimate.
if (IsBitrateImproving(probe_bitrate_bps)) {
LOG(LS_INFO) << "Probe successful, sent at "
<< best_it->GetSendBitrateBps() << " bps, received at "
<< best_it->GetRecvBitrateBps()
<< " bps. Mean send delta: " << best_it->send_mean_ms
<< " ms, mean recv delta: " << best_it->recv_mean_ms
<< " ms, num probes: " << best_it->count;
remote_rate_.SetEstimate(probe_bitrate_bps, now_ms);
return ProbeResult::kBitrateUpdated;
}
}
// Not probing and received non-probe packet, or finished with current set
// of probes.
if (clusters.size() >= kExpectedNumberOfProbes)
probes_.clear();
return ProbeResult::kNoUpdate;
}
bool DelayBasedBwe::IsBitrateImproving(int new_bitrate_bps) const {
bool initial_probe = !remote_rate_.ValidEstimate() && new_bitrate_bps > 0;
bool bitrate_above_estimate =
remote_rate_.ValidEstimate() &&
new_bitrate_bps > static_cast<int>(remote_rate_.LatestEstimate());
return initial_probe || bitrate_above_estimate;
}
void DelayBasedBwe::IncomingPacketFeedbackVector(
const std::vector<PacketInfo>& packet_feedback_vector) {
RTC_DCHECK(network_thread_.CalledOnValidThread());
for (const auto& packet_info : packet_feedback_vector) {
IncomingPacketInfo(packet_info.arrival_time_ms,
ConvertMsTo24Bits(packet_info.send_time_ms),
packet_info.payload_size, 0, packet_info.was_paced,
packet_info.probe_cluster_id);
}
}
void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header,
bool was_paced) {
RTC_DCHECK(network_thread_.CalledOnValidThread());
if (!header.extension.hasAbsoluteSendTime) {
// NOTE! The BitrateEstimatorTest relies on this EXACT log line.
LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet "
"is missing absolute send time extension!";
return;
}
IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime,
payload_size, header.ssrc, was_paced,
PacketInfo::kNotAProbe);
}
void DelayBasedBwe::IncomingPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header,
bool was_paced,
int probe_cluster_id) {
RTC_DCHECK(network_thread_.CalledOnValidThread());
if (!header.extension.hasAbsoluteSendTime) {
// NOTE! The BitrateEstimatorTest relies on this EXACT log line.
LOG(LS_WARNING) << "RemoteBitrateEstimatorAbsSendTime: Incoming packet "
"is missing absolute send time extension!";
return;
}
IncomingPacketInfo(arrival_time_ms, header.extension.absoluteSendTime,
payload_size, header.ssrc, was_paced, probe_cluster_id);
}
void DelayBasedBwe::IncomingPacketInfo(int64_t arrival_time_ms,
uint32_t send_time_24bits,
size_t payload_size,
uint32_t ssrc,
bool was_paced,
int probe_cluster_id) {
assert(send_time_24bits < (1ul << 24));
// Shift up send time to use the full 32 bits that inter_arrival works with,
// so wrapping works properly.
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
int64_t send_time_ms = static_cast<int64_t>(timestamp) * kTimestampToMs;
int64_t now_ms = arrival_time_ms;
// TODO(holmer): SSRCs are only needed for REMB, should be broken out from
// here.
incoming_bitrate_.Update(payload_size, now_ms);
if (first_packet_time_ms_ == -1)
first_packet_time_ms_ = arrival_time_ms;
uint32_t ts_delta = 0;
int64_t t_delta = 0;
int size_delta = 0;
bool update_estimate = false;
uint32_t target_bitrate_bps = 0;
std::vector<uint32_t> ssrcs;
{
rtc::CritScope lock(&crit_);
TimeoutStreams(now_ms);
RTC_DCHECK(inter_arrival_.get());
RTC_DCHECK(estimator_.get());
ssrcs_[ssrc] = now_ms;
// For now only try to detect probes while we don't have a valid estimate,
// and make sure the packet was paced. We currently assume that only packets
// larger than 200 bytes are paced by the sender.
if (probe_cluster_id != PacketInfo::kNotAProbe &&
payload_size > PacedSender::kMinProbePacketSize &&
(!remote_rate_.ValidEstimate() ||
now_ms - first_packet_time_ms_ < kInitialProbingIntervalMs)) {
// TODO(holmer): Use a map instead to get correct order?
if (total_probes_received_ < kMaxProbePackets) {
int send_delta_ms = -1;
int recv_delta_ms = -1;
if (!probes_.empty()) {
send_delta_ms = send_time_ms - probes_.back().send_time_ms;
recv_delta_ms = arrival_time_ms - probes_.back().recv_time_ms;
}
LOG(LS_INFO) << "Probe packet received: send time=" << send_time_ms
<< " ms, recv time=" << arrival_time_ms
<< " ms, send delta=" << send_delta_ms
<< " ms, recv delta=" << recv_delta_ms << " ms.";
}
probes_.push_back(
Probe(send_time_ms, arrival_time_ms, payload_size, probe_cluster_id));
++total_probes_received_;
// Make sure that a probe which updated the bitrate immediately has an
// effect by calling the OnReceiveBitrateChanged callback.
if (ProcessClusters(now_ms) == ProbeResult::kBitrateUpdated)
update_estimate = true;
}
if (inter_arrival_->ComputeDeltas(timestamp, arrival_time_ms, payload_size,
&ts_delta, &t_delta, &size_delta)) {
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
estimator_->Update(t_delta, ts_delta_ms, size_delta, detector_.State());
detector_.Detect(estimator_->offset(), ts_delta_ms,
estimator_->num_of_deltas(), arrival_time_ms);
}
if (!update_estimate) {
// Check if it's time for a periodic update or if we should update because
// of an over-use.
if (last_update_ms_ == -1 ||
now_ms - last_update_ms_ > remote_rate_.GetFeedbackInterval()) {
update_estimate = true;
} else if (detector_.State() == kBwOverusing) {
rtc::Optional<uint32_t> incoming_rate = incoming_bitrate_.Rate(now_ms);
if (incoming_rate &&
remote_rate_.TimeToReduceFurther(now_ms, *incoming_rate)) {
update_estimate = true;
}
}
}
if (update_estimate) {
// The first overuse should immediately trigger a new estimate.
// We also have to update the estimate immediately if we are overusing
// and the target bitrate is too high compared to what we are receiving.
const RateControlInput input(detector_.State(),
incoming_bitrate_.Rate(now_ms),
estimator_->var_noise());
remote_rate_.Update(&input, now_ms);
target_bitrate_bps = remote_rate_.UpdateBandwidthEstimate(now_ms);
update_estimate = remote_rate_.ValidEstimate();
ssrcs = Keys(ssrcs_);
}
}
if (update_estimate) {
last_update_ms_ = now_ms;
observer_->OnReceiveBitrateChanged(ssrcs, target_bitrate_bps);
}
}
void DelayBasedBwe::Process() {}
int64_t DelayBasedBwe::TimeUntilNextProcess() {
const int64_t kDisabledModuleTime = 1000;
return kDisabledModuleTime;
}
void DelayBasedBwe::TimeoutStreams(int64_t now_ms) {
for (Ssrcs::iterator it = ssrcs_.begin(); it != ssrcs_.end();) {
if ((now_ms - it->second) > kStreamTimeOutMs) {
ssrcs_.erase(it++);
} else {
++it;
}
}
if (ssrcs_.empty()) {
// We can't update the estimate if we don't have any active streams.
inter_arrival_.reset(
new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
kTimestampToMs, true));
estimator_.reset(new OveruseEstimator(OverUseDetectorOptions()));
// We deliberately don't reset the first_packet_time_ms_ here for now since
// we only probe for bandwidth in the beginning of a call right now.
}
}
void DelayBasedBwe::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
rtc::CritScope lock(&crit_);
remote_rate_.SetRtt(avg_rtt_ms);
}
void DelayBasedBwe::RemoveStream(uint32_t ssrc) {
rtc::CritScope lock(&crit_);
ssrcs_.erase(ssrc);
}
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);
rtc::CritScope lock(&crit_);
if (!remote_rate_.ValidEstimate()) {
return false;
}
*ssrcs = Keys(ssrcs_);
if (ssrcs_.empty()) {
*bitrate_bps = 0;
} else {
*bitrate_bps = remote_rate_.LatestEstimate();
}
return true;
}
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.
rtc::CritScope lock(&crit_);
remote_rate_.SetMinBitrate(min_bitrate_bps);
}
} // namespace webrtc

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_
#define WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_
#include <list>
#include <map>
#include <memory>
#include <vector>
#include "webrtc/base/checks.h"
#include "webrtc/base/constructormagic.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/rate_statistics.h"
#include "webrtc/base/thread_checker.h"
#include "webrtc/modules/remote_bitrate_estimator/aimd_rate_control.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/modules/remote_bitrate_estimator/inter_arrival.h"
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
#include "webrtc/modules/remote_bitrate_estimator/overuse_estimator.h"
#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
namespace webrtc {
class DelayBasedBwe : public RemoteBitrateEstimator {
public:
explicit DelayBasedBwe(RemoteBitrateObserver* observer);
virtual ~DelayBasedBwe() {}
void IncomingPacketFeedbackVector(
const std::vector<PacketInfo>& packet_feedback_vector) override;
void IncomingPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header,
bool was_paced) override;
void IncomingPacket(int64_t arrival_time_ms,
size_t payload_size,
const RTPHeader& header,
bool was_paced,
int probe_cluster_id);
// This class relies on Process() being called periodically (at least once
// every other second) for streams to be timed out properly. Therefore it
// shouldn't be detached from the ProcessThread except if it's about to be
// deleted.
void Process() override;
int64_t TimeUntilNextProcess() override;
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
void RemoveStream(uint32_t ssrc) override;
bool LatestEstimate(std::vector<uint32_t>* ssrcs,
uint32_t* bitrate_bps) const override;
void SetMinBitrate(int min_bitrate_bps) override;
private:
struct Probe {
Probe(int64_t send_time_ms,
int64_t recv_time_ms,
size_t payload_size,
int cluster_id)
: send_time_ms(send_time_ms),
recv_time_ms(recv_time_ms),
payload_size(payload_size),
cluster_id(cluster_id) {}
int64_t send_time_ms;
int64_t recv_time_ms;
size_t payload_size;
int cluster_id;
};
struct Cluster {
Cluster()
: send_mean_ms(0.0f),
recv_mean_ms(0.0f),
mean_size(0),
count(0),
num_above_min_delta(0) {}
int GetSendBitrateBps() const {
RTC_CHECK_GT(send_mean_ms, 0.0f);
return mean_size * 8 * 1000 / send_mean_ms;
}
int GetRecvBitrateBps() const {
RTC_CHECK_GT(recv_mean_ms, 0.0f);
return mean_size * 8 * 1000 / recv_mean_ms;
}
float send_mean_ms;
float recv_mean_ms;
// TODO(holmer): Add some variance metric as well?
size_t mean_size;
int count;
int num_above_min_delta;
};
typedef std::map<uint32_t, int64_t> Ssrcs;
enum class ProbeResult { kBitrateUpdated, kNoUpdate };
static void AddCluster(std::list<Cluster>* clusters, Cluster* cluster);
void IncomingPacketInfo(int64_t arrival_time_ms,
uint32_t send_time_24bits,
size_t payload_size,
uint32_t ssrc,
bool was_paced,
int probe_cluster_id);
void ComputeClusters(std::list<Cluster>* clusters) const;
std::list<Cluster>::const_iterator FindBestProbe(
const std::list<Cluster>& clusters) const;
// Returns true if a probe which changed the estimate was detected.
ProbeResult ProcessClusters(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_);
bool IsBitrateImproving(int probe_bitrate_bps) const
EXCLUSIVE_LOCKS_REQUIRED(&crit_);
void TimeoutStreams(int64_t now_ms) EXCLUSIVE_LOCKS_REQUIRED(&crit_);
rtc::ThreadChecker network_thread_;
RemoteBitrateObserver* const observer_;
std::unique_ptr<InterArrival> inter_arrival_;
std::unique_ptr<OveruseEstimator> estimator_;
OveruseDetector detector_;
RateStatistics incoming_bitrate_;
std::vector<int> recent_propagation_delta_ms_;
std::vector<int64_t> recent_update_time_ms_;
std::list<Probe> probes_;
size_t total_probes_received_;
int64_t first_packet_time_ms_;
int64_t last_update_ms_;
rtc::CriticalSection crit_;
Ssrcs ssrcs_ GUARDED_BY(&crit_);
AimdRateControl remote_rate_ GUARDED_BY(&crit_);
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(DelayBasedBwe);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_CONGESTION_CONTROLLER_DELAY_BASED_BWE_H_

View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#include "webrtc/modules/congestion_controller/delay_based_bwe.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/pacing/paced_sender.h"
#include "webrtc/system_wrappers/include/clock.h"
namespace webrtc {
class TestDelayBasedBwe : public ::testing::Test, public RemoteBitrateObserver {
public:
static constexpr int kArrivalTimeClockOffsetMs = 60000;
static constexpr int kNumProbes = 5;
TestDelayBasedBwe()
: bwe_(this), clock_(0), bitrate_updated_(false), latest_bitrate_(0) {}
uint32_t AbsSendTime(int64_t t, int64_t denom) {
return (((t << 18) + (denom >> 1)) / denom) & 0x00fffffful;
}
void IncomingPacket(uint32_t ssrc,
size_t payload_size,
int64_t arrival_time,
uint32_t rtp_timestamp,
uint32_t absolute_send_time,
bool was_paced,
int probe_cluster_id) {
RTPHeader header;
memset(&header, 0, sizeof(header));
header.ssrc = ssrc;
header.timestamp = rtp_timestamp;
header.extension.hasAbsoluteSendTime = true;
header.extension.absoluteSendTime = absolute_send_time;
bwe_.IncomingPacket(arrival_time + kArrivalTimeClockOffsetMs, payload_size,
header, was_paced, probe_cluster_id);
}
void OnReceiveBitrateChanged(const std::vector<uint32_t>& ssrcs,
uint32_t bitrate) {
bitrate_updated_ = true;
latest_bitrate_ = bitrate;
}
bool bitrate_updated() {
bool res = bitrate_updated_;
bitrate_updated_ = false;
return res;
}
int latest_bitrate() { return latest_bitrate_; }
DelayBasedBwe bwe_;
SimulatedClock clock_;
private:
bool bitrate_updated_;
int latest_bitrate_;
};
TEST_F(TestDelayBasedBwe, ProbeDetection) {
int64_t now_ms = clock_.TimeInMilliseconds();
// First burst sent at 8 * 1000 / 10 = 800 kbps.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(10);
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000),
true, 0);
}
EXPECT_TRUE(bitrate_updated());
// Second burst sent at 8 * 1000 / 5 = 1600 kbps.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(5);
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000),
true, 1);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_GT(latest_bitrate(), 1500000);
}
TEST_F(TestDelayBasedBwe, ProbeDetectionNonPacedPackets) {
int64_t now_ms = clock_.TimeInMilliseconds();
// First burst sent at 8 * 1000 / 10 = 800 kbps, but with every other packet
// not being paced which could mess things up.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(5);
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000),
true, 0);
// Non-paced packet, arriving 5 ms after.
clock_.AdvanceTimeMilliseconds(5);
IncomingPacket(0, PacedSender::kMinProbePacketSize + 1, now_ms, 90 * now_ms,
AbsSendTime(now_ms, 1000), false, PacketInfo::kNotAProbe);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_GT(latest_bitrate(), 800000);
}
// Packets will require 5 ms to be transmitted to the receiver, causing packets
// of the second probe to be dispersed.
TEST_F(TestDelayBasedBwe, ProbeDetectionTooHighBitrate) {
int64_t now_ms = clock_.TimeInMilliseconds();
int64_t send_time_ms = 0;
// First burst sent at 8 * 1000 / 10 = 800 kbps.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(10);
now_ms = clock_.TimeInMilliseconds();
send_time_ms += 10;
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 0);
}
// Second burst sent at 8 * 1000 / 5 = 1600 kbps, arriving at 8 * 1000 / 8 =
// 1000 kbps.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(8);
now_ms = clock_.TimeInMilliseconds();
send_time_ms += 5;
IncomingPacket(0, 1000, now_ms, send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 1);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_NEAR(latest_bitrate(), 800000, 10000);
}
TEST_F(TestDelayBasedBwe, ProbeDetectionSlightlyFasterArrival) {
int64_t now_ms = clock_.TimeInMilliseconds();
// 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 < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(5);
send_time_ms += 10;
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 23);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_GT(latest_bitrate(), 800000);
}
TEST_F(TestDelayBasedBwe, ProbeDetectionFasterArrival) {
int64_t now_ms = clock_.TimeInMilliseconds();
// 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 < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(1);
send_time_ms += 10;
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 0);
}
EXPECT_FALSE(bitrate_updated());
}
TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrival) {
int64_t now_ms = clock_.TimeInMilliseconds();
// First burst sent at 8 * 1000 / 5 = 1600 kbps.
// Arriving at 8 * 1000 / 7 = 1142 kbps.
int64_t send_time_ms = 0;
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(7);
send_time_ms += 5;
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 1);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_NEAR(latest_bitrate(), 1140000, 10000);
}
TEST_F(TestDelayBasedBwe, ProbeDetectionSlowerArrivalHighBitrate) {
int64_t now_ms = clock_.TimeInMilliseconds();
// Burst sent at 8 * 1000 / 1 = 8000 kbps.
// Arriving at 8 * 1000 / 2 = 4000 kbps.
int64_t send_time_ms = 0;
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(2);
send_time_ms += 1;
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * send_time_ms,
AbsSendTime(send_time_ms, 1000), true, 1);
}
EXPECT_TRUE(bitrate_updated());
EXPECT_NEAR(latest_bitrate(), 4000000u, 10000);
}
TEST_F(TestDelayBasedBwe, ProbingIgnoresSmallPackets) {
int64_t now_ms = clock_.TimeInMilliseconds();
// Probing with 200 bytes every 10 ms, should be ignored by the probe
// detection.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(10);
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, PacedSender::kMinProbePacketSize, now_ms, 90 * now_ms,
AbsSendTime(now_ms, 1000), true, 1);
}
EXPECT_FALSE(bitrate_updated());
// Followed by a probe with 1000 bytes packets, should be detected as a
// probe.
for (int i = 0; i < kNumProbes; ++i) {
clock_.AdvanceTimeMilliseconds(10);
now_ms = clock_.TimeInMilliseconds();
IncomingPacket(0, 1000, now_ms, 90 * now_ms, AbsSendTime(now_ms, 1000),
true, 1);
}
// Wait long enough so that we can call Process again.
clock_.AdvanceTimeMilliseconds(1000);
EXPECT_TRUE(bitrate_updated());
EXPECT_NEAR(latest_bitrate(), 800000u, 10000);
}
} // namespace webrtc

View File

@ -270,6 +270,7 @@
'bitrate_controller/bitrate_controller_unittest.cc',
'bitrate_controller/send_side_bandwidth_estimation_unittest.cc',
'congestion_controller/congestion_controller_unittest.cc',
'congestion_controller/delay_based_bwe_unittest.cc',
'media_file/media_file_unittest.cc',
'module_common_types_unittest.cc',
'pacing/bitrate_prober_unittest.cc',