2015-02-16 12:02:20 +00:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2015 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.
|
|
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/remote_bitrate_estimator/test/bwe.h"
|
2015-02-16 12:02:20 +00:00
|
|
|
|
2018-08-03 19:24:25 +02:00
|
|
|
#include <algorithm>
|
2015-02-16 12:02:20 +00:00
|
|
|
#include <limits>
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "modules/remote_bitrate_estimator/test/estimators/bbr.h"
|
|
|
|
|
#include "modules/remote_bitrate_estimator/test/estimators/nada.h"
|
|
|
|
|
#include "modules/remote_bitrate_estimator/test/estimators/remb.h"
|
|
|
|
|
#include "modules/remote_bitrate_estimator/test/estimators/send_side.h"
|
|
|
|
|
#include "modules/remote_bitrate_estimator/test/estimators/tcp.h"
|
2019-01-11 09:11:00 -08:00
|
|
|
#include "rtc_base/constructor_magic.h"
|
2018-08-03 19:24:25 +02:00
|
|
|
#include "rtc_base/numerics/safe_conversions.h"
|
2018-02-05 10:33:35 +01:00
|
|
|
#include "rtc_base/system/fallthrough.h"
|
2015-02-16 12:02:20 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
namespace testing {
|
|
|
|
|
namespace bwe {
|
|
|
|
|
|
2015-06-08 11:29:08 +02:00
|
|
|
const int kSetCapacity = 1000;
|
|
|
|
|
|
|
|
|
|
BweReceiver::BweReceiver(int flow_id)
|
2015-07-15 16:31:18 +02:00
|
|
|
: flow_id_(flow_id),
|
|
|
|
|
received_packets_(kSetCapacity),
|
|
|
|
|
rate_counter_(),
|
|
|
|
|
loss_account_() {}
|
|
|
|
|
|
|
|
|
|
BweReceiver::BweReceiver(int flow_id, int64_t window_size_ms)
|
|
|
|
|
: flow_id_(flow_id),
|
|
|
|
|
received_packets_(kSetCapacity),
|
|
|
|
|
rate_counter_(window_size_ms),
|
|
|
|
|
loss_account_() {}
|
|
|
|
|
|
|
|
|
|
void BweReceiver::ReceivePacket(int64_t arrival_time_ms,
|
|
|
|
|
const MediaPacket& media_packet) {
|
|
|
|
|
if (received_packets_.size() == kSetCapacity) {
|
|
|
|
|
RelieveSetAndUpdateLoss();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
received_packets_.Insert(media_packet.sequence_number(),
|
|
|
|
|
media_packet.send_time_ms(), arrival_time_ms,
|
|
|
|
|
media_packet.payload_size());
|
|
|
|
|
|
|
|
|
|
rate_counter_.UpdateRates(media_packet.send_time_ms() * 1000,
|
|
|
|
|
static_cast<uint32_t>(media_packet.payload_size()));
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
2018-07-18 15:37:01 +02:00
|
|
|
FeedbackPacket* BweReceiver::GetFeedback(int64_t now_ms) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 16:03:45 +00:00
|
|
|
class NullBweSender : public BweSender {
|
2015-02-16 12:02:20 +00:00
|
|
|
public:
|
2015-02-17 16:03:45 +00:00
|
|
|
NullBweSender() {}
|
2018-07-18 15:37:01 +02:00
|
|
|
~NullBweSender() override {}
|
2015-02-16 12:02:20 +00:00
|
|
|
|
2015-03-04 12:58:35 +00:00
|
|
|
int GetFeedbackIntervalMs() const override { return 1000; }
|
|
|
|
|
void GiveFeedback(const FeedbackPacket& feedback) override {}
|
2015-03-18 13:40:54 +00:00
|
|
|
void OnPacketsSent(const Packets& packets) override {}
|
2015-03-04 12:58:35 +00:00
|
|
|
int64_t TimeUntilNextProcess() override {
|
2015-02-16 12:02:20 +00:00
|
|
|
return std::numeric_limits<int64_t>::max();
|
|
|
|
|
}
|
2016-02-25 04:50:01 -08:00
|
|
|
void Process() override {}
|
2015-02-16 12:02:20 +00:00
|
|
|
|
|
|
|
|
private:
|
2015-09-16 05:37:44 -07:00
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(NullBweSender);
|
2015-02-16 12:02:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) {
|
|
|
|
|
const int kInterArrivalShift = 26;
|
|
|
|
|
const int kAbsSendTimeInterArrivalUpshift = 8;
|
|
|
|
|
const double kTimestampToMs =
|
|
|
|
|
1000.0 / static_cast<double>(1 << kInterArrivalShift);
|
|
|
|
|
uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift;
|
|
|
|
|
return static_cast<int64_t>(timestamp) * kTimestampToMs;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 16:03:45 +00:00
|
|
|
BweSender* CreateBweSender(BandwidthEstimatorType estimator,
|
|
|
|
|
int kbps,
|
|
|
|
|
BitrateObserver* observer,
|
|
|
|
|
Clock* clock) {
|
2015-02-16 12:02:20 +00:00
|
|
|
switch (estimator) {
|
|
|
|
|
case kRembEstimator:
|
2015-02-17 16:03:45 +00:00
|
|
|
return new RembBweSender(kbps, observer, clock);
|
2016-10-25 07:04:37 -07:00
|
|
|
case kSendSideEstimator:
|
|
|
|
|
return new SendSideBweSender(kbps, observer, clock);
|
2015-02-17 16:03:45 +00:00
|
|
|
case kNadaEstimator:
|
|
|
|
|
return new NadaBweSender(kbps, observer, clock);
|
This is an initial cl, which contains small amount of implemented functions, and large amount of unimplemented ones.
Code should implement BBR which is the congestion controlling algorithm. BBR tries to estimate two values bottle-neck bandwidth(bw) and round trip time(rtt),then use these two values to set two control parameters pacing rate(pacing_rate),the rate at which data should be sent and congestion window size (cwnd), cwnd is the upper bound for data in flight,data_in_flight <= cwnd at all time.
BBR has four modes:
1)Startup-ramping up throughput discovering estimated bw.
2)Drain-after Startup decrease throughput to drain queues.
3)Probe Bandwidth-most of the time BBR should be in this mode,
sending data at the rate of estimated bw, while sometimes trying to discover new bandwidth.
4)Probe Rtt-in this mode BBR tries to discover new rtt for the connection.
The key moment in BBR is when we receive feedback from the receiver,as this is the only moment which should effect our two estimators. At this moment all the switches between modes should happen, except switch to ProbeRtt mode (switching to ProbeRtt mode should happen when current min_rtt value expires).
This cl serves to emphasize the structure of Bbr, when switches happen and what key classes/functions should be implemented for proper functionality.
BUG=webrtc:7713
NOTRY=True
Review-Url: https://codereview.webrtc.org/2904183002
Cr-Commit-Position: refs/heads/master@{#18444}
2017-06-05 06:01:26 -07:00
|
|
|
case kBbrEstimator:
|
2017-08-20 09:19:58 -07:00
|
|
|
return new BbrBweSender(observer, clock);
|
2015-04-16 19:55:45 +02:00
|
|
|
case kTcpEstimator:
|
2018-02-05 10:33:35 +01:00
|
|
|
RTC_FALLTHROUGH();
|
2015-02-16 12:02:20 +00:00
|
|
|
case kNullEstimator:
|
2015-02-17 16:03:45 +00:00
|
|
|
return new NullBweSender();
|
2015-02-16 12:02:20 +00:00
|
|
|
}
|
|
|
|
|
assert(false);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
|
|
|
|
|
int flow_id,
|
|
|
|
|
bool plot) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case kRembEstimator:
|
|
|
|
|
return new RembReceiver(flow_id, plot);
|
2016-10-25 07:04:37 -07:00
|
|
|
case kSendSideEstimator:
|
2015-02-16 12:02:20 +00:00
|
|
|
return new SendSideBweReceiver(flow_id);
|
2015-02-17 16:03:45 +00:00
|
|
|
case kNadaEstimator:
|
|
|
|
|
return new NadaBweReceiver(flow_id);
|
This is an initial cl, which contains small amount of implemented functions, and large amount of unimplemented ones.
Code should implement BBR which is the congestion controlling algorithm. BBR tries to estimate two values bottle-neck bandwidth(bw) and round trip time(rtt),then use these two values to set two control parameters pacing rate(pacing_rate),the rate at which data should be sent and congestion window size (cwnd), cwnd is the upper bound for data in flight,data_in_flight <= cwnd at all time.
BBR has four modes:
1)Startup-ramping up throughput discovering estimated bw.
2)Drain-after Startup decrease throughput to drain queues.
3)Probe Bandwidth-most of the time BBR should be in this mode,
sending data at the rate of estimated bw, while sometimes trying to discover new bandwidth.
4)Probe Rtt-in this mode BBR tries to discover new rtt for the connection.
The key moment in BBR is when we receive feedback from the receiver,as this is the only moment which should effect our two estimators. At this moment all the switches between modes should happen, except switch to ProbeRtt mode (switching to ProbeRtt mode should happen when current min_rtt value expires).
This cl serves to emphasize the structure of Bbr, when switches happen and what key classes/functions should be implemented for proper functionality.
BUG=webrtc:7713
NOTRY=True
Review-Url: https://codereview.webrtc.org/2904183002
Cr-Commit-Position: refs/heads/master@{#18444}
2017-06-05 06:01:26 -07:00
|
|
|
case kBbrEstimator:
|
|
|
|
|
return new BbrBweReceiver(flow_id);
|
2015-04-16 19:55:45 +02:00
|
|
|
case kTcpEstimator:
|
|
|
|
|
return new TcpBweReceiver(flow_id);
|
2015-02-16 12:02:20 +00:00
|
|
|
case kNullEstimator:
|
|
|
|
|
return new BweReceiver(flow_id);
|
|
|
|
|
}
|
|
|
|
|
assert(false);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2015-06-08 11:29:08 +02:00
|
|
|
|
2015-07-15 16:31:18 +02:00
|
|
|
// Take into account all LinkedSet content.
|
|
|
|
|
void BweReceiver::UpdateLoss() {
|
|
|
|
|
loss_account_.Add(LinkedSetPacketLossRatio());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Preserve 10% latest packets and update packet loss based on the oldest
|
|
|
|
|
// 90%, that will be removed.
|
|
|
|
|
void BweReceiver::RelieveSetAndUpdateLoss() {
|
|
|
|
|
// Compute Loss for the whole LinkedSet and updates loss_account_.
|
|
|
|
|
UpdateLoss();
|
|
|
|
|
|
|
|
|
|
size_t num_preserved_elements = received_packets_.size() / 10;
|
|
|
|
|
PacketNodeIt it = received_packets_.begin();
|
|
|
|
|
std::advance(it, num_preserved_elements);
|
|
|
|
|
|
|
|
|
|
while (it != received_packets_.end()) {
|
|
|
|
|
received_packets_.Erase(it++);
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
2015-07-15 16:31:18 +02:00
|
|
|
|
|
|
|
|
// Compute Loss for the preserved elements
|
|
|
|
|
loss_account_.Subtract(LinkedSetPacketLossRatio());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float BweReceiver::GlobalReceiverPacketLossRatio() {
|
|
|
|
|
UpdateLoss();
|
|
|
|
|
return loss_account_.LossRatio();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This function considers at most kSetCapacity = 1000 packets.
|
|
|
|
|
LossAccount BweReceiver::LinkedSetPacketLossRatio() {
|
|
|
|
|
if (received_packets_.empty()) {
|
|
|
|
|
return LossAccount();
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
2015-07-15 16:31:18 +02:00
|
|
|
|
2018-08-03 19:24:25 +02:00
|
|
|
size_t set_total_packets = received_packets_.Range();
|
2015-07-15 16:31:18 +02:00
|
|
|
size_t set_received_packets = received_packets_.size();
|
|
|
|
|
size_t set_lost_packets = set_total_packets - set_received_packets;
|
|
|
|
|
|
|
|
|
|
return LossAccount(set_total_packets, set_lost_packets);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t BweReceiver::RecentKbps() const {
|
|
|
|
|
return (rate_counter_.bits_per_second() + 500) / 1000;
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Go through a fixed time window of most recent packets received and
|
|
|
|
|
// counts packets missing to obtain the packet loss ratio. If an unordered
|
|
|
|
|
// packet falls out of the timewindow it will be counted as missing.
|
|
|
|
|
// E.g.: for a timewindow covering 5 packets of the following arrival sequence
|
|
|
|
|
// {10 7 9 5 6} 8 3 2 4 1, the output will be 1/6 (#8 is considered as missing).
|
|
|
|
|
float BweReceiver::RecentPacketLossRatio() {
|
|
|
|
|
if (received_packets_.empty()) {
|
|
|
|
|
return 0.0f;
|
|
|
|
|
}
|
|
|
|
|
int number_packets_received = 0;
|
|
|
|
|
|
|
|
|
|
PacketNodeIt node_it = received_packets_.begin(); // Latest.
|
|
|
|
|
|
|
|
|
|
// Lowest timestamp limit, oldest one that should be checked.
|
2018-08-07 19:12:47 +02:00
|
|
|
int64_t time_limit_ms = node_it->arrival_time_ms - kPacketLossTimeWindowMs;
|
2015-06-08 11:29:08 +02:00
|
|
|
// Oldest and newest values found within the given time window.
|
2018-08-07 19:12:47 +02:00
|
|
|
int64_t oldest_seq_num = node_it->unwrapped_sequence_number;
|
2018-08-03 19:24:25 +02:00
|
|
|
int64_t newest_seq_num = oldest_seq_num;
|
2015-06-08 11:29:08 +02:00
|
|
|
|
|
|
|
|
while (node_it != received_packets_.end()) {
|
2018-08-07 19:12:47 +02:00
|
|
|
if (node_it->arrival_time_ms < time_limit_ms) {
|
2015-06-08 11:29:08 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2018-08-07 19:12:47 +02:00
|
|
|
int64_t seq_num = node_it->unwrapped_sequence_number;
|
2018-08-03 19:24:25 +02:00
|
|
|
newest_seq_num = std::max(newest_seq_num, seq_num);
|
|
|
|
|
oldest_seq_num = std::min(oldest_seq_num, seq_num);
|
2015-06-08 11:29:08 +02:00
|
|
|
++node_it;
|
|
|
|
|
++number_packets_received;
|
|
|
|
|
}
|
|
|
|
|
// Interval width between oldest and newest sequence number.
|
2018-08-03 19:24:25 +02:00
|
|
|
int gap = rtc::dchecked_cast<int>(newest_seq_num - oldest_seq_num + 1);
|
2015-06-08 11:29:08 +02:00
|
|
|
|
|
|
|
|
return static_cast<float>(gap - number_packets_received) / gap;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-18 15:37:01 +02:00
|
|
|
LinkedSet::LinkedSet(int capacity) : capacity_(capacity) {}
|
|
|
|
|
|
2015-07-14 03:53:57 -07:00
|
|
|
LinkedSet::~LinkedSet() {
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-08 11:29:08 +02:00
|
|
|
void LinkedSet::Insert(uint16_t sequence_number,
|
|
|
|
|
int64_t send_time_ms,
|
|
|
|
|
int64_t arrival_time_ms,
|
|
|
|
|
size_t payload_size) {
|
2018-08-03 19:24:25 +02:00
|
|
|
auto unwrapped_sequence_number = unwrapper_.Unwrap(sequence_number);
|
|
|
|
|
auto it = map_.find(unwrapped_sequence_number);
|
|
|
|
|
// Handle duplicate unwrapped sequence number.
|
2015-06-08 11:29:08 +02:00
|
|
|
if (it != map_.end()) {
|
|
|
|
|
PacketNodeIt node_it = it->second;
|
2018-08-07 19:12:47 +02:00
|
|
|
PacketIdentifierNode& node = *node_it;
|
|
|
|
|
node.arrival_time_ms = arrival_time_ms;
|
|
|
|
|
// Move to front, without invalidating iterators.
|
|
|
|
|
list_.splice(list_.begin(), list_, node_it);
|
2015-06-08 11:29:08 +02:00
|
|
|
} else {
|
|
|
|
|
if (size() == capacity_) {
|
|
|
|
|
RemoveTail();
|
|
|
|
|
}
|
2018-08-07 19:12:47 +02:00
|
|
|
// Push new element to the front of the list and insert it in the map.
|
|
|
|
|
PacketIdentifierNode new_head(unwrapped_sequence_number, send_time_ms,
|
|
|
|
|
arrival_time_ms, payload_size);
|
|
|
|
|
list_.push_front(new_head);
|
|
|
|
|
map_[unwrapped_sequence_number] = list_.begin();
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
|
|
|
|
}
|
2015-07-15 16:31:18 +02:00
|
|
|
|
2015-06-08 11:29:08 +02:00
|
|
|
void LinkedSet::RemoveTail() {
|
2018-08-07 19:12:47 +02:00
|
|
|
Erase(--list_.end());
|
2015-06-08 11:29:08 +02:00
|
|
|
}
|
|
|
|
|
|
2015-07-15 16:31:18 +02:00
|
|
|
void LinkedSet::Erase(PacketNodeIt node_it) {
|
2018-08-07 19:12:47 +02:00
|
|
|
map_.erase(node_it->unwrapped_sequence_number);
|
2015-07-15 16:31:18 +02:00
|
|
|
list_.erase(node_it);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LossAccount::Add(LossAccount rhs) {
|
|
|
|
|
num_total += rhs.num_total;
|
|
|
|
|
num_lost += rhs.num_lost;
|
|
|
|
|
}
|
|
|
|
|
void LossAccount::Subtract(LossAccount rhs) {
|
|
|
|
|
num_total -= rhs.num_total;
|
|
|
|
|
num_lost -= rhs.num_lost;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float LossAccount::LossRatio() {
|
|
|
|
|
if (num_total == 0)
|
|
|
|
|
return 0.0f;
|
|
|
|
|
return static_cast<float>(num_lost) / num_total;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-16 12:02:20 +00:00
|
|
|
} // namespace bwe
|
|
|
|
|
} // namespace testing
|
|
|
|
|
} // namespace webrtc
|