Enabling Packet-Loss plots for BweReceiver.
Packet-loss computation and plot were added to BweReceiver class. Objective function and plot were added to PacketReceiver class. BUG=4550 R=stefan@webrtc.org Review URL: https://webrtc-codereview.appspot.com/56459004 Cr-Commit-Position: refs/heads/master@{#9391}
This commit is contained in:
parent
c1b9d4e686
commit
77cabab51a
@ -22,6 +22,16 @@ namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
// With the assumption that packet loss is lower than 97%, the max gap
|
||||
// between elements in the set is lower than 0x8000, hence we have a
|
||||
// total order in the set. For (x,y,z) subset of the LinkedSet,
|
||||
// (x<=y and y<=z) ==> x<=z so the set can be sorted.
|
||||
const int kSetCapacity = 1000;
|
||||
|
||||
BweReceiver::BweReceiver(int flow_id)
|
||||
: flow_id_(flow_id), received_packets_(kSetCapacity) {
|
||||
}
|
||||
|
||||
class NullBweSender : public BweSender {
|
||||
public:
|
||||
NullBweSender() {}
|
||||
@ -86,6 +96,98 @@ BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float BweReceiver::GlobalPacketLossRatio() {
|
||||
if (received_packets_.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
// Possibly there are packets missing.
|
||||
const uint16_t kMaxGap = 1.5 * kSetCapacity;
|
||||
uint16_t min = received_packets_.find_min();
|
||||
uint16_t max = received_packets_.find_max();
|
||||
|
||||
int gap;
|
||||
if (max - min < kMaxGap) {
|
||||
gap = max - min + 1;
|
||||
} else { // There was an overflow.
|
||||
max = received_packets_.upper_bound(kMaxGap);
|
||||
min = received_packets_.lower_bound(0xFFFF - kMaxGap);
|
||||
gap = max + (0xFFFF - min) + 2;
|
||||
}
|
||||
return static_cast<float>(received_packets_.size()) / gap;
|
||||
}
|
||||
|
||||
// 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.
|
||||
int64_t time_limit_ms = (*node_it)->arrival_time_ms - kPacketLossTimeWindowMs;
|
||||
// Oldest and newest values found within the given time window.
|
||||
uint16_t oldest_seq_nb = (*node_it)->sequence_number;
|
||||
uint16_t newest_seq_nb = oldest_seq_nb;
|
||||
|
||||
while (node_it != received_packets_.end()) {
|
||||
if ((*node_it)->arrival_time_ms < time_limit_ms) {
|
||||
break;
|
||||
}
|
||||
uint16_t seq_nb = (*node_it)->sequence_number;
|
||||
if (IsNewerSequenceNumber(seq_nb, newest_seq_nb)) {
|
||||
newest_seq_nb = seq_nb;
|
||||
}
|
||||
if (IsNewerSequenceNumber(oldest_seq_nb, seq_nb)) {
|
||||
oldest_seq_nb = seq_nb;
|
||||
}
|
||||
++node_it;
|
||||
++number_packets_received;
|
||||
}
|
||||
// Interval width between oldest and newest sequence number.
|
||||
// There was an overflow if newest_seq_nb < oldest_seq_nb.
|
||||
int gap = static_cast<uint16_t>(newest_seq_nb - oldest_seq_nb + 1);
|
||||
|
||||
return static_cast<float>(gap - number_packets_received) / gap;
|
||||
}
|
||||
|
||||
void LinkedSet::Insert(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size) {
|
||||
std::map<uint16_t, PacketNodeIt>::iterator it = map_.find(sequence_number);
|
||||
if (it != map_.end()) {
|
||||
PacketNodeIt node_it = it->second;
|
||||
PacketIdentifierNode* node = *node_it;
|
||||
node->arrival_time_ms = arrival_time_ms;
|
||||
if (node_it != list_.begin()) {
|
||||
list_.erase(node_it);
|
||||
list_.push_front(node);
|
||||
map_[sequence_number] = list_.begin();
|
||||
}
|
||||
} else {
|
||||
if (size() == capacity_) {
|
||||
RemoveTail();
|
||||
}
|
||||
UpdateHead(new PacketIdentifierNode(sequence_number, send_time_ms,
|
||||
arrival_time_ms, payload_size));
|
||||
}
|
||||
}
|
||||
void LinkedSet::RemoveTail() {
|
||||
map_.erase(list_.back()->sequence_number);
|
||||
list_.pop_back();
|
||||
}
|
||||
void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) {
|
||||
list_.push_front(new_head);
|
||||
map_[new_head->sequence_number] = list_.begin();
|
||||
}
|
||||
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
@ -20,6 +20,66 @@ namespace webrtc {
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
// Holds only essential information about packets to be saved for
|
||||
// further use, e.g. for calculating packet loss and receiving rate.
|
||||
struct PacketIdentifierNode {
|
||||
PacketIdentifierNode(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size)
|
||||
: sequence_number(sequence_number),
|
||||
send_time_ms(send_time_ms),
|
||||
arrival_time_ms(arrival_time_ms),
|
||||
payload_size(payload_size) {}
|
||||
|
||||
uint16_t sequence_number;
|
||||
int64_t send_time_ms;
|
||||
int64_t arrival_time_ms;
|
||||
size_t payload_size;
|
||||
};
|
||||
|
||||
typedef std::list<PacketIdentifierNode*>::iterator PacketNodeIt;
|
||||
|
||||
// FIFO implementation for a limited capacity set.
|
||||
// Used for keeping the latest arrived packets while avoiding duplicates.
|
||||
// Allows efficient insertion, deletion and search.
|
||||
class LinkedSet {
|
||||
public:
|
||||
explicit LinkedSet(int capacity) : capacity_(capacity) {}
|
||||
|
||||
// If the arriving packet (identified by its sequence number) is already
|
||||
// in the LinkedSet, move its Node to the head of the list. Else, create
|
||||
// a PacketIdentifierNode n_ and then UpdateHead(n_), calling RemoveTail()
|
||||
// if the LinkedSet reached its maximum capacity.
|
||||
void Insert(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size);
|
||||
|
||||
PacketNodeIt begin() { return list_.begin(); }
|
||||
PacketNodeIt end() { return list_.end(); }
|
||||
bool empty() { return list_.empty(); }
|
||||
size_t size() { return list_.size(); }
|
||||
// Gets the latest arrived sequence number.
|
||||
uint16_t find_max() { return map_.rbegin()->first; }
|
||||
// Gets the first arrived sequence number still saved in the LinkedSet.
|
||||
uint16_t find_min() { return map_.begin()->first; }
|
||||
// Gets the lowest saved sequence number that is >= than the input key.
|
||||
uint16_t lower_bound(uint16_t key) { return map_.lower_bound(key)->first; }
|
||||
// Gets the highest saved sequence number that is <= than the input key.
|
||||
uint16_t upper_bound(uint16_t key) { return map_.upper_bound(key)->first; }
|
||||
size_t capacity() { return capacity_; }
|
||||
|
||||
private:
|
||||
// Pop oldest element from the back of the list and remove it from the map.
|
||||
void RemoveTail();
|
||||
// Add new element to the front of the list and insert it in the map.
|
||||
void UpdateHead(PacketIdentifierNode* new_head);
|
||||
size_t capacity_;
|
||||
std::map<uint16_t, PacketNodeIt> map_;
|
||||
std::list<PacketIdentifierNode*> list_;
|
||||
};
|
||||
|
||||
const int kMinBitrateKbps = 150;
|
||||
const int kMaxBitrateKbps = 3000;
|
||||
|
||||
@ -38,15 +98,23 @@ class BweSender : public Module {
|
||||
|
||||
class BweReceiver {
|
||||
public:
|
||||
explicit BweReceiver(int flow_id) : flow_id_(flow_id) {}
|
||||
explicit BweReceiver(int flow_id);
|
||||
virtual ~BweReceiver() {}
|
||||
|
||||
virtual void ReceivePacket(int64_t arrival_time_ms,
|
||||
const MediaPacket& media_packet) {}
|
||||
virtual FeedbackPacket* GetFeedback(int64_t now_ms) { return NULL; }
|
||||
|
||||
float GlobalPacketLossRatio();
|
||||
float RecentPacketLossRatio();
|
||||
size_t GetSetCapacity() { return received_packets_.capacity(); }
|
||||
|
||||
static const int64_t kPacketLossTimeWindowMs = 500;
|
||||
|
||||
protected:
|
||||
int flow_id_;
|
||||
// Deals with packets sent more than once.
|
||||
LinkedSet received_packets_;
|
||||
};
|
||||
|
||||
enum BandwidthEstimatorType {
|
||||
|
@ -28,10 +28,9 @@ namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
const int NadaBweReceiver::kMedian;
|
||||
const int64_t NadaBweReceiver::kPacketLossTimeWindowMs;
|
||||
const int64_t NadaBweReceiver::kReceivingRateTimeWindowMs;
|
||||
const int NadaBweSender::kMinRefRateKbps;
|
||||
const int NadaBweSender::kMaxRefRateKbps;
|
||||
const int64_t NadaBweReceiver::kReceivingRateTimeWindowMs;
|
||||
|
||||
NadaBweReceiver::NadaBweReceiver(int flow_id)
|
||||
: BweReceiver(flow_id),
|
||||
@ -84,9 +83,9 @@ void NadaBweReceiver::ReceivePacket(int64_t arrival_time_ms,
|
||||
est_queuing_delay_signal_ms_ = 0;
|
||||
}
|
||||
|
||||
received_packets_->Insert(media_packet.sequence_number(),
|
||||
media_packet.send_time_ms(), arrival_time_ms,
|
||||
media_packet.payload_size());
|
||||
received_packets_.Insert(media_packet.sequence_number(),
|
||||
media_packet.send_time_ms(), arrival_time_ms,
|
||||
media_packet.payload_size());
|
||||
}
|
||||
|
||||
FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
|
||||
@ -110,7 +109,7 @@ FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
|
||||
last_feedback_ms_ = now_ms;
|
||||
last_congestion_signal_ms_ = congestion_signal_ms;
|
||||
|
||||
PacketIdentifierNode* latest = *(received_packets_->begin());
|
||||
PacketIdentifierNode* latest = *(received_packets_.begin());
|
||||
int64_t corrected_send_time_ms =
|
||||
latest->send_time_ms + now_ms - latest->arrival_time_ms;
|
||||
|
||||
@ -122,83 +121,22 @@ FeedbackPacket* NadaBweReceiver::GetFeedback(int64_t now_ms) {
|
||||
corrected_send_time_ms);
|
||||
}
|
||||
|
||||
float NadaBweReceiver::GlobalPacketLossRatio() {
|
||||
if (received_packets_->empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
// Possibly there are packets missing.
|
||||
const uint16_t kMaxGap = 1.5 * kSetCapacity;
|
||||
uint16_t min = received_packets_->find_min();
|
||||
uint16_t max = received_packets_->find_max();
|
||||
|
||||
int gap;
|
||||
if (max - min < kMaxGap) {
|
||||
gap = max - min + 1;
|
||||
} else { // There was an overflow.
|
||||
max = received_packets_->upper_bound(kMaxGap);
|
||||
min = received_packets_->lower_bound(0xFFFF - kMaxGap);
|
||||
gap = max + (0xFFFF - min) + 2;
|
||||
}
|
||||
return static_cast<float>(received_packets_->size()) / gap;
|
||||
}
|
||||
|
||||
// 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 NadaBweReceiver::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.
|
||||
int64_t time_limit_ms = (*node_it)->arrival_time_ms - kPacketLossTimeWindowMs;
|
||||
// Oldest and newest values found within the given time window.
|
||||
uint16_t oldest_seq_nb = (*node_it)->sequence_number;
|
||||
uint16_t newest_seq_nb = oldest_seq_nb;
|
||||
|
||||
while (node_it != received_packets_->end()) {
|
||||
if ((*node_it)->arrival_time_ms < time_limit_ms) {
|
||||
break;
|
||||
}
|
||||
uint16_t seq_nb = (*node_it)->sequence_number;
|
||||
if (IsNewerSequenceNumber(seq_nb, newest_seq_nb)) {
|
||||
newest_seq_nb = seq_nb;
|
||||
}
|
||||
if (IsNewerSequenceNumber(oldest_seq_nb, seq_nb)) {
|
||||
oldest_seq_nb = seq_nb;
|
||||
}
|
||||
++node_it;
|
||||
++number_packets_received;
|
||||
}
|
||||
// Interval width between oldest and newest sequence number.
|
||||
// There was an overflow if newest_seq_nb < oldest_seq_nb.
|
||||
int gap = static_cast<uint16_t>(newest_seq_nb - oldest_seq_nb + 1);
|
||||
|
||||
return static_cast<float>(gap - number_packets_received) / gap;
|
||||
}
|
||||
|
||||
// For a given time window, compute the receiving speed rate in kbps.
|
||||
// As described below, three cases are considered depending on the number of
|
||||
// packets received.
|
||||
size_t NadaBweReceiver::RecentReceivingRate() {
|
||||
// If the receiver didn't receive any packet, return 0.
|
||||
if (received_packets_->empty()) {
|
||||
if (received_packets_.empty()) {
|
||||
return 0.0f;
|
||||
}
|
||||
size_t total_size = 0;
|
||||
int number_packets = 0;
|
||||
|
||||
PacketNodeIt node_it = received_packets_->begin();
|
||||
PacketNodeIt node_it = received_packets_.begin();
|
||||
|
||||
int64_t last_time_ms = (*node_it)->arrival_time_ms;
|
||||
int64_t start_time_ms = last_time_ms;
|
||||
PacketNodeIt end = received_packets_->end();
|
||||
PacketNodeIt end = received_packets_.end();
|
||||
|
||||
// Stops after including the first packet out of the timeWindow.
|
||||
// Ameliorates results when there are wide gaps between packets.
|
||||
@ -218,13 +156,14 @@ size_t NadaBweReceiver::RecentReceivingRate() {
|
||||
// If the receiver received a single packet, return its size*8/timeWindow.
|
||||
if (number_packets == 1) {
|
||||
corrected_time_ms = kReceivingRateTimeWindowMs;
|
||||
} else {
|
||||
// If the receiver received multiple packets, use as time interval the gap
|
||||
// between first and last packet falling in the timeWindow corrected by the
|
||||
// factor number_packets/(number_packets-1).
|
||||
// E.g: Let timeWindow = 500ms, payload_size = 500bytes, number_packets=2,
|
||||
// packets received at t1(0ms) and t2(499 or 501ms). This prevent the
|
||||
// function from returning ~2*8, sending instead a more likely ~1*8 kbps.
|
||||
}
|
||||
// If the receiver received multiple packets, use as time interval the gap
|
||||
// between first and last packet falling in the timeWindow corrected by the
|
||||
// factor number_packets/(number_packets-1).
|
||||
// E.g: Let timeWindow = 500ms, payload_size = 500 bytes, number_packets = 2,
|
||||
// packets received at t1(0ms) and t2(499 or 501ms). This prevent the function
|
||||
// from returning ~2*8, sending instead a more likely ~1*8 kbps.
|
||||
else {
|
||||
corrected_time_ms = (number_packets * (start_time_ms - last_time_ms)) /
|
||||
(number_packets - 1);
|
||||
}
|
||||
@ -383,37 +322,6 @@ void NadaBweSender::GradualRateUpdate(const NadaFeedback& fb,
|
||||
bitrate_kbps_ = bitrate_kbps_ + smoothing_factor * original_increase;
|
||||
}
|
||||
|
||||
void LinkedSet::Insert(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size) {
|
||||
std::map<uint16_t, PacketNodeIt>::iterator it = map_.find(sequence_number);
|
||||
if (it != map_.end()) {
|
||||
PacketNodeIt node_it = it->second;
|
||||
PacketIdentifierNode* node = *node_it;
|
||||
node->arrival_time_ms = arrival_time_ms;
|
||||
if (node_it != list_.begin()) {
|
||||
list_.erase(node_it);
|
||||
list_.push_front(node);
|
||||
map_[sequence_number] = list_.begin();
|
||||
}
|
||||
} else {
|
||||
if (size() == capacity_) {
|
||||
RemoveTail();
|
||||
}
|
||||
UpdateHead(new PacketIdentifierNode(sequence_number, send_time_ms,
|
||||
arrival_time_ms, payload_size));
|
||||
}
|
||||
}
|
||||
void LinkedSet::RemoveTail() {
|
||||
map_.erase(list_.back()->sequence_number);
|
||||
list_.pop_back();
|
||||
}
|
||||
void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) {
|
||||
list_.push_front(new_head);
|
||||
map_[new_head->sequence_number] = list_.begin();
|
||||
}
|
||||
|
||||
} // namespace bwe
|
||||
} // namespace testing
|
||||
} // namespace webrtc
|
||||
|
@ -31,65 +31,6 @@ class ReceiveStatistics;
|
||||
namespace testing {
|
||||
namespace bwe {
|
||||
|
||||
// Holds only essential information about packets to be saved for
|
||||
// further use, e.g. for calculating packet loss and receiving rate.
|
||||
struct PacketIdentifierNode {
|
||||
PacketIdentifierNode(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size)
|
||||
: sequence_number(sequence_number),
|
||||
send_time_ms(send_time_ms),
|
||||
arrival_time_ms(arrival_time_ms),
|
||||
payload_size(payload_size) {}
|
||||
|
||||
uint16_t sequence_number;
|
||||
int64_t send_time_ms;
|
||||
int64_t arrival_time_ms;
|
||||
size_t payload_size;
|
||||
};
|
||||
|
||||
typedef std::list<PacketIdentifierNode*>::iterator PacketNodeIt;
|
||||
|
||||
// FIFO implementation for a limited capacity set.
|
||||
// Used for keeping the latest arrived packets while avoiding duplicates.
|
||||
// Allows efficient insertion, deletion and search.
|
||||
class LinkedSet {
|
||||
public:
|
||||
explicit LinkedSet(size_t capacity) : capacity_(capacity) {}
|
||||
|
||||
// If the arriving packet (identified by its sequence number) is already
|
||||
// in the LinkedSet, move its Node to the head of the list. Else, create
|
||||
// a PacketIdentifierNode n_ and then UpdateHead(n_), calling RemoveTail()
|
||||
// if the LinkedSet reached its maximum capacity.
|
||||
void Insert(uint16_t sequence_number,
|
||||
int64_t send_time_ms,
|
||||
int64_t arrival_time_ms,
|
||||
size_t payload_size);
|
||||
|
||||
PacketNodeIt begin() { return list_.begin(); }
|
||||
PacketNodeIt end() { return list_.end(); }
|
||||
bool empty() { return list_.empty(); }
|
||||
size_t size() { return list_.size(); }
|
||||
// Gets the latest arrived sequence number.
|
||||
uint16_t find_max() { return map_.rbegin()->first; }
|
||||
// Gets the first arrived sequence number still saved in the LinkedSet.
|
||||
uint16_t find_min() { return map_.begin()->first; }
|
||||
// Gets the lowest saved sequence number that is >= than the input key.
|
||||
uint16_t lower_bound(uint16_t key) { return map_.lower_bound(key)->first; }
|
||||
// Gets the highest saved sequence number that is <= than the input key.
|
||||
uint16_t upper_bound(uint16_t key) { return map_.upper_bound(key)->first; }
|
||||
|
||||
private:
|
||||
// Pop oldest element from the back of the list and remove it from the map.
|
||||
void RemoveTail();
|
||||
// Add new element to the front of the list and insert it in the map.
|
||||
void UpdateHead(PacketIdentifierNode* new_head);
|
||||
size_t capacity_;
|
||||
std::map<uint16_t, PacketNodeIt> map_;
|
||||
std::list<PacketIdentifierNode*> list_;
|
||||
};
|
||||
|
||||
class NadaBweReceiver : public BweReceiver {
|
||||
public:
|
||||
explicit NadaBweReceiver(int flow_id);
|
||||
@ -98,20 +39,13 @@ class NadaBweReceiver : public BweReceiver {
|
||||
void ReceivePacket(int64_t arrival_time_ms,
|
||||
const MediaPacket& media_packet) override;
|
||||
FeedbackPacket* GetFeedback(int64_t now_ms) override;
|
||||
float GlobalPacketLossRatio();
|
||||
float RecentPacketLossRatio();
|
||||
|
||||
size_t RecentReceivingRate();
|
||||
static int64_t MedianFilter(int64_t* v, int size);
|
||||
static int64_t ExponentialSmoothingFilter(int64_t new_value,
|
||||
int64_t last_smoothed_value,
|
||||
float alpha);
|
||||
|
||||
// With the assumption that packet loss is lower than 97%, the max gap
|
||||
// between elements in the set is lower than 0x8000, hence we have a
|
||||
// total order in the set. For (x,y,z) subset of the LinkedSet,
|
||||
// (x<=y and y<=z) ==> x<=z so the set can be sorted.
|
||||
static const int kSetCapacity = 1000;
|
||||
static const int64_t kPacketLossTimeWindowMs = 500;
|
||||
static const int64_t kReceivingRateTimeWindowMs = 500;
|
||||
|
||||
private:
|
||||
@ -125,8 +59,6 @@ class NadaBweReceiver : public BweReceiver {
|
||||
int64_t exp_smoothed_delay_ms_; // Referred as d_hat_n.
|
||||
int64_t est_queuing_delay_signal_ms_; // Referred as d_tilde_n.
|
||||
|
||||
// Deals with packets sent more than once.
|
||||
LinkedSet* received_packets_ = new LinkedSet(kSetCapacity);
|
||||
static const int kMedian = 5; // Used for k-points Median Filter.
|
||||
int64_t last_delays_ms_[kMedian]; // Used for Median Filter.
|
||||
};
|
||||
|
@ -435,7 +435,7 @@ TEST_F(NadaReceiverSideTest, PacketLossSinglePacket) {
|
||||
|
||||
TEST_F(NadaReceiverSideTest, PacketLossContiguousPackets) {
|
||||
const int64_t kTimeWindowMs = NadaBweReceiver::kPacketLossTimeWindowMs;
|
||||
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
|
||||
size_t set_capacity = nada_receiver_.GetSetCapacity();
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
uint16_t sequence_number = static_cast<uint16_t>(i);
|
||||
@ -465,7 +465,7 @@ TEST_F(NadaReceiverSideTest, PacketLossContiguousPackets) {
|
||||
EXPECT_EQ(nada_receiver_.RecentPacketLossRatio(), 0.0f);
|
||||
|
||||
// Should handle set overflow.
|
||||
for (int i = 0; i < kSetCapacity * 1.5; ++i) {
|
||||
for (int i = 0; i < set_capacity * 1.5; ++i) {
|
||||
uint16_t sequence_number = static_cast<uint16_t>(i);
|
||||
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
|
||||
// Only the packets sent in this for loop will be considered.
|
||||
@ -503,11 +503,11 @@ TEST_F(NadaReceiverSideTest, PacketLossDuplicatedPackets) {
|
||||
}
|
||||
|
||||
TEST_F(NadaReceiverSideTest, PacketLossLakingPackets) {
|
||||
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
|
||||
EXPECT_LT(kSetCapacity, 0xFFFF);
|
||||
size_t set_capacity = nada_receiver_.GetSetCapacity();
|
||||
EXPECT_LT(set_capacity, static_cast<size_t>(0xFFFF));
|
||||
|
||||
// Missing every other packet.
|
||||
for (int i = 0; i < kSetCapacity; ++i) {
|
||||
for (size_t i = 0; i < set_capacity; ++i) {
|
||||
if ((i & 1) == 0) { // Only even sequence numbers.
|
||||
uint16_t sequence_number = static_cast<uint16_t>(i);
|
||||
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
|
||||
@ -519,12 +519,12 @@ TEST_F(NadaReceiverSideTest, PacketLossLakingPackets) {
|
||||
}
|
||||
|
||||
TEST_F(NadaReceiverSideTest, PacketLossLakingFewPackets) {
|
||||
const int kSetCapacity = NadaBweReceiver::kSetCapacity;
|
||||
EXPECT_LT(kSetCapacity, 0xFFFF);
|
||||
size_t set_capacity = nada_receiver_.GetSetCapacity();
|
||||
EXPECT_LT(set_capacity, static_cast<size_t>(0xFFFF));
|
||||
|
||||
const int kPeriod = 100;
|
||||
// Missing one for each kPeriod packets.
|
||||
for (int i = 0; i < kSetCapacity; ++i) {
|
||||
for (size_t i = 0; i < set_capacity; ++i) {
|
||||
if ((i % kPeriod) != 0) {
|
||||
uint16_t sequence_number = static_cast<uint16_t>(i);
|
||||
const MediaPacket media_packet(kFlowId, 0, 0, sequence_number);
|
||||
@ -557,16 +557,16 @@ TEST_F(NadaReceiverSideTest, PacketLossWideGap) {
|
||||
|
||||
// Packets arriving unordered should not be counted as losted.
|
||||
TEST_F(NadaReceiverSideTest, PacketLossUnorderedPackets) {
|
||||
const int kNumPackets = NadaBweReceiver::kSetCapacity / 2;
|
||||
int num_packets = nada_receiver_.GetSetCapacity() / 2;
|
||||
std::vector<uint16_t> sequence_numbers;
|
||||
|
||||
for (int i = 0; i < kNumPackets; ++i) {
|
||||
for (int i = 0; i < num_packets; ++i) {
|
||||
sequence_numbers.push_back(static_cast<uint16_t>(i + 1));
|
||||
}
|
||||
|
||||
random_shuffle(sequence_numbers.begin(), sequence_numbers.end());
|
||||
|
||||
for (int i = 0; i < kNumPackets; ++i) {
|
||||
for (int i = 0; i < num_packets; ++i) {
|
||||
const MediaPacket media_packet(kFlowId, 0, 0, sequence_numbers[i]);
|
||||
// Arrival time = 0, all packets will be considered.
|
||||
nada_receiver_.ReceivePacket(0, media_packet);
|
||||
|
@ -99,6 +99,10 @@ void RembReceiver::ReceivePacket(int64_t arrival_time_ms,
|
||||
media_packet.header());
|
||||
clock_.AdvanceTimeMilliseconds(arrival_time_ms - clock_.TimeInMilliseconds());
|
||||
ASSERT_TRUE(arrival_time_ms == clock_.TimeInMilliseconds());
|
||||
|
||||
received_packets_.Insert(media_packet.sequence_number(),
|
||||
media_packet.send_time_ms(), arrival_time_ms,
|
||||
media_packet.payload_size());
|
||||
}
|
||||
|
||||
FeedbackPacket* RembReceiver::GetFeedback(int64_t now_ms) {
|
||||
|
@ -127,6 +127,10 @@ void SendSideBweReceiver::ReceivePacket(int64_t arrival_time_ms,
|
||||
packet_feedback_vector_.push_back(PacketInfo(
|
||||
arrival_time_ms, media_packet.sender_timestamp_us() / 1000,
|
||||
media_packet.header().sequenceNumber, media_packet.payload_size()));
|
||||
|
||||
received_packets_.Insert(media_packet.sequence_number(),
|
||||
media_packet.send_time_ms(), arrival_time_ms,
|
||||
media_packet.payload_size());
|
||||
}
|
||||
|
||||
FeedbackPacket* SendSideBweReceiver::GetFeedback(int64_t now_ms) {
|
||||
|
@ -35,6 +35,10 @@ void TcpBweReceiver::ReceivePacket(int64_t arrival_time_ms,
|
||||
const MediaPacket& media_packet) {
|
||||
latest_owd_ms_ = arrival_time_ms - media_packet.sender_timestamp_us() / 1000;
|
||||
acks_.push_back(media_packet.header().sequenceNumber);
|
||||
|
||||
received_packets_.Insert(media_packet.sequence_number(),
|
||||
media_packet.send_time_ms(), arrival_time_ms,
|
||||
media_packet.payload_size());
|
||||
}
|
||||
|
||||
FeedbackPacket* TcpBweReceiver::GetFeedback(int64_t now_ms) {
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "webrtc/modules/remote_bitrate_estimator/test/packet_receiver.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <vector>
|
||||
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
@ -31,13 +32,32 @@ PacketReceiver::PacketReceiver(PacketProcessorListener* listener,
|
||||
bool plot_bwe)
|
||||
: PacketProcessor(listener, flow_id, kReceiver),
|
||||
delay_log_prefix_(),
|
||||
metric_log_prefix_(),
|
||||
packet_loss_log_prefix_(),
|
||||
last_delay_plot_ms_(0),
|
||||
last_metric_plot_ms_(0),
|
||||
last_packet_loss_plot_ms_(0),
|
||||
plot_delay_(plot_delay),
|
||||
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)) {
|
||||
// TODO(magalhaesc) Add separated plot_objective_function and
|
||||
// plot_packet_loss parameters to the constructor.
|
||||
plot_objective_function_(plot_delay),
|
||||
plot_packet_loss_(plot_delay),
|
||||
bwe_receiver_(CreateBweReceiver(bwe_type, flow_id, plot_bwe)),
|
||||
total_delay_ms_(0),
|
||||
total_throughput_(0),
|
||||
number_packets_(0) {
|
||||
// Setup the prefix ststd::rings used when logging.
|
||||
std::stringstream ss;
|
||||
ss << "Delay_" << flow_id << "#2";
|
||||
delay_log_prefix_ = ss.str();
|
||||
std::stringstream ss1;
|
||||
ss1 << "Delay_" << flow_id << "#2";
|
||||
delay_log_prefix_ = ss1.str();
|
||||
|
||||
std::stringstream ss2;
|
||||
ss2 << "Objective_function_" << flow_id << "#2";
|
||||
metric_log_prefix_ = ss2.str();
|
||||
|
||||
std::stringstream ss3;
|
||||
ss3 << "Packet_Loss_" << flow_id << "#2";
|
||||
packet_loss_log_prefix_ = ss3.str();
|
||||
}
|
||||
|
||||
PacketReceiver::~PacketReceiver() {
|
||||
@ -61,6 +81,12 @@ void PacketReceiver::RunFor(int64_t time_ms, Packets* in_out) {
|
||||
int64_t send_time_ms = (media_packet->creation_time_us() + 500) / 1000;
|
||||
delay_stats_.Push(arrival_time_ms - send_time_ms);
|
||||
PlotDelay(arrival_time_ms, send_time_ms);
|
||||
PlotObjectiveFunction(arrival_time_ms);
|
||||
PlotPacketLoss(arrival_time_ms);
|
||||
|
||||
total_delay_ms_ += arrival_time_ms - send_time_ms;
|
||||
total_throughput_ += media_packet->payload_size();
|
||||
++number_packets_;
|
||||
|
||||
bwe_receiver_->ReceivePacket(arrival_time_ms, *media_packet);
|
||||
FeedbackPacket* fb = bwe_receiver_->GetFeedback(arrival_time_ms);
|
||||
@ -87,6 +113,37 @@ void PacketReceiver::PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms) {
|
||||
}
|
||||
}
|
||||
|
||||
double PacketReceiver::ObjectiveFunction() {
|
||||
const double kDelta = 1.0; // Delay penalty factor.
|
||||
double throughput_metric = log(static_cast<double>(total_throughput_));
|
||||
double delay_penalty = kDelta * log(static_cast<double>(total_delay_ms_));
|
||||
return throughput_metric - delay_penalty;
|
||||
}
|
||||
|
||||
void PacketReceiver::PlotObjectiveFunction(int64_t arrival_time_ms) {
|
||||
static const int kMetricPlotIntervalMs = 1000;
|
||||
if (!plot_objective_function_) {
|
||||
return;
|
||||
}
|
||||
if (arrival_time_ms - last_metric_plot_ms_ > kMetricPlotIntervalMs) {
|
||||
BWE_TEST_LOGGING_PLOT(1, metric_log_prefix_, arrival_time_ms,
|
||||
ObjectiveFunction());
|
||||
last_metric_plot_ms_ = arrival_time_ms;
|
||||
}
|
||||
}
|
||||
|
||||
void PacketReceiver::PlotPacketLoss(int64_t arrival_time_ms) {
|
||||
static const int kPacketLossPlotIntervalMs = 500;
|
||||
if (!plot_packet_loss_) {
|
||||
return;
|
||||
}
|
||||
if (arrival_time_ms - last_packet_loss_plot_ms_ > kPacketLossPlotIntervalMs) {
|
||||
BWE_TEST_LOGGING_PLOT(2, packet_loss_log_prefix_, arrival_time_ms,
|
||||
bwe_receiver_->RecentPacketLossRatio());
|
||||
last_packet_loss_plot_ms_ = arrival_time_ms;
|
||||
}
|
||||
}
|
||||
|
||||
Stats<double> PacketReceiver::GetDelayStats() const {
|
||||
return delay_stats_;
|
||||
}
|
||||
|
@ -40,14 +40,27 @@ class PacketReceiver : public PacketProcessor {
|
||||
|
||||
protected:
|
||||
void PlotDelay(int64_t arrival_time_ms, int64_t send_time_ms);
|
||||
void PlotObjectiveFunction(int64_t arrival_time_ms);
|
||||
void PlotPacketLoss(int64_t arrival_time_ms);
|
||||
double ObjectiveFunction();
|
||||
|
||||
int64_t now_ms_;
|
||||
std::string delay_log_prefix_;
|
||||
std::string metric_log_prefix_;
|
||||
std::string packet_loss_log_prefix_;
|
||||
int64_t last_delay_plot_ms_;
|
||||
int64_t last_metric_plot_ms_;
|
||||
int64_t last_packet_loss_plot_ms_;
|
||||
bool plot_delay_;
|
||||
bool plot_objective_function_;
|
||||
bool plot_packet_loss_;
|
||||
Stats<double> delay_stats_;
|
||||
rtc::scoped_ptr<BweReceiver> bwe_receiver_;
|
||||
|
||||
int64_t total_delay_ms_;
|
||||
size_t total_throughput_;
|
||||
int number_packets_;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(PacketReceiver);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user