aboutsummaryrefslogtreecommitdiff
path: root/webrtc/modules/remote_bitrate_estimator/test/bwe.cc
blob: c667b6864e4638a40e3d227849f6230dab8d8930 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
/*
 *  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.
 */

#include "webrtc/modules/remote_bitrate_estimator/test/bwe.h"

#include <limits>

#include "webrtc/base/common.h"
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/nada.h"
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/remb.h"
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/send_side.h"
#include "webrtc/modules/remote_bitrate_estimator/test/estimators/tcp.h"

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),
      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()));
}

class NullBweSender : public BweSender {
 public:
  NullBweSender() {}
  virtual ~NullBweSender() {}

  int GetFeedbackIntervalMs() const override { return 1000; }
  void GiveFeedback(const FeedbackPacket& feedback) override {}
  void OnPacketsSent(const Packets& packets) override {}
  int64_t TimeUntilNextProcess() override {
    return std::numeric_limits<int64_t>::max();
  }
  int Process() override { return 0; }

 private:
  RTC_DISALLOW_COPY_AND_ASSIGN(NullBweSender);
};

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;
}

BweSender* CreateBweSender(BandwidthEstimatorType estimator,
                           int kbps,
                           BitrateObserver* observer,
                           Clock* clock) {
  switch (estimator) {
    case kRembEstimator:
      return new RembBweSender(kbps, observer, clock);
    case kFullSendSideEstimator:
      return new FullBweSender(kbps, observer, clock);
    case kNadaEstimator:
      return new NadaBweSender(kbps, observer, clock);
    case kTcpEstimator:
      FALLTHROUGH();
    case kNullEstimator:
      return new NullBweSender();
  }
  assert(false);
  return NULL;
}

BweReceiver* CreateBweReceiver(BandwidthEstimatorType type,
                               int flow_id,
                               bool plot) {
  switch (type) {
    case kRembEstimator:
      return new RembReceiver(flow_id, plot);
    case kFullSendSideEstimator:
      return new SendSideBweReceiver(flow_id);
    case kNadaEstimator:
      return new NadaBweReceiver(flow_id);
    case kTcpEstimator:
      return new TcpBweReceiver(flow_id);
    case kNullEstimator:
      return new BweReceiver(flow_id);
  }
  assert(false);
  return NULL;
}

// 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++);
  }

  // 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();
  }

  uint16_t oldest_seq_num = received_packets_.OldestSeqNumber();
  uint16_t newest_seq_num = received_packets_.NewestSeqNumber();

  size_t set_total_packets =
      static_cast<uint16_t>(newest_seq_num - oldest_seq_num + 1);

  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;
}

// 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_num = (*node_it)->sequence_number;
  uint16_t newest_seq_num = oldest_seq_num;

  while (node_it != received_packets_.end()) {
    if ((*node_it)->arrival_time_ms < time_limit_ms) {
      break;
    }
    uint16_t seq_num = (*node_it)->sequence_number;
    if (IsNewerSequenceNumber(seq_num, newest_seq_num)) {
      newest_seq_num = seq_num;
    }
    if (IsNewerSequenceNumber(oldest_seq_num, seq_num)) {
      oldest_seq_num = seq_num;
    }
    ++node_it;
    ++number_packets_received;
  }
  // Interval width between oldest and newest sequence number.
  // There was an overflow if newest_seq_num < oldest_seq_num.
  int gap = static_cast<uint16_t>(newest_seq_num - oldest_seq_num + 1);

  return static_cast<float>(gap - number_packets_received) / gap;
}

LinkedSet::~LinkedSet() {
  while (!empty())
    RemoveTail();
}

void LinkedSet::Insert(uint16_t sequence_number,
                       int64_t send_time_ms,
                       int64_t arrival_time_ms,
                       size_t payload_size) {
  auto 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::Insert(PacketIdentifierNode packet_identifier) {
  Insert(packet_identifier.sequence_number, packet_identifier.send_time_ms,
         packet_identifier.arrival_time_ms, packet_identifier.payload_size);
}

void LinkedSet::RemoveTail() {
  map_.erase(list_.back()->sequence_number);
  delete list_.back();
  list_.pop_back();
}
void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) {
  list_.push_front(new_head);
  map_[new_head->sequence_number] = list_.begin();
}

void LinkedSet::Erase(PacketNodeIt node_it) {
  map_.erase((*node_it)->sequence_number);
  delete (*node_it);
  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;
}

}  // namespace bwe
}  // namespace testing
}  // namespace webrtc