stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 11 | #include "modules/remote_bitrate_estimator/test/bwe.h" |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 12 | |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 13 | #include <limits> |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 14 | |
Mirko Bonadei | 92ea95e | 2017-09-15 06:47:31 +0200 | [diff] [blame] | 15 | #include "modules/remote_bitrate_estimator/test/estimators/bbr.h" |
| 16 | #include "modules/remote_bitrate_estimator/test/estimators/nada.h" |
| 17 | #include "modules/remote_bitrate_estimator/test/estimators/remb.h" |
| 18 | #include "modules/remote_bitrate_estimator/test/estimators/send_side.h" |
| 19 | #include "modules/remote_bitrate_estimator/test/estimators/tcp.h" |
| 20 | #include "rtc_base/constructormagic.h" |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 21 | |
| 22 | namespace webrtc { |
| 23 | namespace testing { |
| 24 | namespace bwe { |
| 25 | |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 26 | // With the assumption that packet loss is lower than 97%, the max gap |
| 27 | // between elements in the set is lower than 0x8000, hence we have a |
| 28 | // total order in the set. For (x,y,z) subset of the LinkedSet, |
| 29 | // (x<=y and y<=z) ==> x<=z so the set can be sorted. |
| 30 | const int kSetCapacity = 1000; |
| 31 | |
| 32 | BweReceiver::BweReceiver(int flow_id) |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 33 | : flow_id_(flow_id), |
| 34 | received_packets_(kSetCapacity), |
| 35 | rate_counter_(), |
| 36 | loss_account_() { |
| 37 | } |
| 38 | |
| 39 | BweReceiver::BweReceiver(int flow_id, int64_t window_size_ms) |
| 40 | : flow_id_(flow_id), |
| 41 | received_packets_(kSetCapacity), |
| 42 | rate_counter_(window_size_ms), |
| 43 | loss_account_() { |
| 44 | } |
| 45 | |
| 46 | void BweReceiver::ReceivePacket(int64_t arrival_time_ms, |
| 47 | const MediaPacket& media_packet) { |
| 48 | if (received_packets_.size() == kSetCapacity) { |
| 49 | RelieveSetAndUpdateLoss(); |
| 50 | } |
| 51 | |
| 52 | received_packets_.Insert(media_packet.sequence_number(), |
| 53 | media_packet.send_time_ms(), arrival_time_ms, |
| 54 | media_packet.payload_size()); |
| 55 | |
| 56 | rate_counter_.UpdateRates(media_packet.send_time_ms() * 1000, |
| 57 | static_cast<uint32_t>(media_packet.payload_size())); |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 58 | } |
| 59 | |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 60 | class NullBweSender : public BweSender { |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 61 | public: |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 62 | NullBweSender() {} |
| 63 | virtual ~NullBweSender() {} |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 64 | |
kjellander@webrtc.org | 14665ff | 2015-03-04 12:58:35 +0000 | [diff] [blame] | 65 | int GetFeedbackIntervalMs() const override { return 1000; } |
| 66 | void GiveFeedback(const FeedbackPacket& feedback) override {} |
stefan@webrtc.org | 4346d92 | 2015-03-18 13:40:54 +0000 | [diff] [blame] | 67 | void OnPacketsSent(const Packets& packets) override {} |
kjellander@webrtc.org | 14665ff | 2015-03-04 12:58:35 +0000 | [diff] [blame] | 68 | int64_t TimeUntilNextProcess() override { |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 69 | return std::numeric_limits<int64_t>::max(); |
| 70 | } |
pbos | a26ac92 | 2016-02-25 04:50:01 -0800 | [diff] [blame] | 71 | void Process() override {} |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 72 | |
| 73 | private: |
henrikg | 3c089d7 | 2015-09-16 05:37:44 -0700 | [diff] [blame] | 74 | RTC_DISALLOW_COPY_AND_ASSIGN(NullBweSender); |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 75 | }; |
| 76 | |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 77 | int64_t GetAbsSendTimeInMs(uint32_t abs_send_time) { |
| 78 | const int kInterArrivalShift = 26; |
| 79 | const int kAbsSendTimeInterArrivalUpshift = 8; |
| 80 | const double kTimestampToMs = |
| 81 | 1000.0 / static_cast<double>(1 << kInterArrivalShift); |
| 82 | uint32_t timestamp = abs_send_time << kAbsSendTimeInterArrivalUpshift; |
| 83 | return static_cast<int64_t>(timestamp) * kTimestampToMs; |
| 84 | } |
| 85 | |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 86 | BweSender* CreateBweSender(BandwidthEstimatorType estimator, |
| 87 | int kbps, |
| 88 | BitrateObserver* observer, |
| 89 | Clock* clock) { |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 90 | switch (estimator) { |
| 91 | case kRembEstimator: |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 92 | return new RembBweSender(kbps, observer, clock); |
terelius | 2d81eb3 | 2016-10-25 07:04:37 -0700 | [diff] [blame] | 93 | case kSendSideEstimator: |
| 94 | return new SendSideBweSender(kbps, observer, clock); |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 95 | case kNadaEstimator: |
| 96 | return new NadaBweSender(kbps, observer, clock); |
gnish | 6dcdf10 | 2017-06-05 06:01:26 -0700 | [diff] [blame] | 97 | case kBbrEstimator: |
gnish | a36165c | 2017-08-20 09:19:58 -0700 | [diff] [blame] | 98 | return new BbrBweSender(observer, clock); |
Stefan Holmer | 3795937 | 2015-04-16 19:55:45 +0200 | [diff] [blame] | 99 | case kTcpEstimator: |
kjellander | bdf3072 | 2017-09-08 11:00:21 -0700 | [diff] [blame] | 100 | FALLTHROUGH(); |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 101 | case kNullEstimator: |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 102 | return new NullBweSender(); |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 103 | } |
| 104 | assert(false); |
| 105 | return NULL; |
| 106 | } |
| 107 | |
| 108 | BweReceiver* CreateBweReceiver(BandwidthEstimatorType type, |
| 109 | int flow_id, |
| 110 | bool plot) { |
| 111 | switch (type) { |
| 112 | case kRembEstimator: |
| 113 | return new RembReceiver(flow_id, plot); |
terelius | 2d81eb3 | 2016-10-25 07:04:37 -0700 | [diff] [blame] | 114 | case kSendSideEstimator: |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 115 | return new SendSideBweReceiver(flow_id); |
stefan@webrtc.org | 7663684 | 2015-02-17 16:03:45 +0000 | [diff] [blame] | 116 | case kNadaEstimator: |
| 117 | return new NadaBweReceiver(flow_id); |
gnish | 6dcdf10 | 2017-06-05 06:01:26 -0700 | [diff] [blame] | 118 | case kBbrEstimator: |
| 119 | return new BbrBweReceiver(flow_id); |
Stefan Holmer | 3795937 | 2015-04-16 19:55:45 +0200 | [diff] [blame] | 120 | case kTcpEstimator: |
| 121 | return new TcpBweReceiver(flow_id); |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 122 | case kNullEstimator: |
| 123 | return new BweReceiver(flow_id); |
| 124 | } |
| 125 | assert(false); |
| 126 | return NULL; |
| 127 | } |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 128 | |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 129 | // Take into account all LinkedSet content. |
| 130 | void BweReceiver::UpdateLoss() { |
| 131 | loss_account_.Add(LinkedSetPacketLossRatio()); |
| 132 | } |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 133 | |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 134 | // Preserve 10% latest packets and update packet loss based on the oldest |
| 135 | // 90%, that will be removed. |
| 136 | void BweReceiver::RelieveSetAndUpdateLoss() { |
| 137 | // Compute Loss for the whole LinkedSet and updates loss_account_. |
| 138 | UpdateLoss(); |
| 139 | |
| 140 | size_t num_preserved_elements = received_packets_.size() / 10; |
| 141 | PacketNodeIt it = received_packets_.begin(); |
| 142 | std::advance(it, num_preserved_elements); |
| 143 | |
| 144 | while (it != received_packets_.end()) { |
| 145 | received_packets_.Erase(it++); |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 146 | } |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 147 | |
| 148 | // Compute Loss for the preserved elements |
| 149 | loss_account_.Subtract(LinkedSetPacketLossRatio()); |
| 150 | } |
| 151 | |
| 152 | float BweReceiver::GlobalReceiverPacketLossRatio() { |
| 153 | UpdateLoss(); |
| 154 | return loss_account_.LossRatio(); |
| 155 | } |
| 156 | |
| 157 | // This function considers at most kSetCapacity = 1000 packets. |
| 158 | LossAccount BweReceiver::LinkedSetPacketLossRatio() { |
| 159 | if (received_packets_.empty()) { |
| 160 | return LossAccount(); |
| 161 | } |
| 162 | |
| 163 | uint16_t oldest_seq_num = received_packets_.OldestSeqNumber(); |
| 164 | uint16_t newest_seq_num = received_packets_.NewestSeqNumber(); |
| 165 | |
| 166 | size_t set_total_packets = |
| 167 | static_cast<uint16_t>(newest_seq_num - oldest_seq_num + 1); |
| 168 | |
| 169 | size_t set_received_packets = received_packets_.size(); |
| 170 | size_t set_lost_packets = set_total_packets - set_received_packets; |
| 171 | |
| 172 | return LossAccount(set_total_packets, set_lost_packets); |
| 173 | } |
| 174 | |
| 175 | uint32_t BweReceiver::RecentKbps() const { |
| 176 | return (rate_counter_.bits_per_second() + 500) / 1000; |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 177 | } |
| 178 | |
| 179 | // Go through a fixed time window of most recent packets received and |
| 180 | // counts packets missing to obtain the packet loss ratio. If an unordered |
| 181 | // packet falls out of the timewindow it will be counted as missing. |
| 182 | // E.g.: for a timewindow covering 5 packets of the following arrival sequence |
| 183 | // {10 7 9 5 6} 8 3 2 4 1, the output will be 1/6 (#8 is considered as missing). |
| 184 | float BweReceiver::RecentPacketLossRatio() { |
| 185 | if (received_packets_.empty()) { |
| 186 | return 0.0f; |
| 187 | } |
| 188 | int number_packets_received = 0; |
| 189 | |
| 190 | PacketNodeIt node_it = received_packets_.begin(); // Latest. |
| 191 | |
| 192 | // Lowest timestamp limit, oldest one that should be checked. |
| 193 | int64_t time_limit_ms = (*node_it)->arrival_time_ms - kPacketLossTimeWindowMs; |
| 194 | // Oldest and newest values found within the given time window. |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 195 | uint16_t oldest_seq_num = (*node_it)->sequence_number; |
| 196 | uint16_t newest_seq_num = oldest_seq_num; |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 197 | |
| 198 | while (node_it != received_packets_.end()) { |
| 199 | if ((*node_it)->arrival_time_ms < time_limit_ms) { |
| 200 | break; |
| 201 | } |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 202 | uint16_t seq_num = (*node_it)->sequence_number; |
| 203 | if (IsNewerSequenceNumber(seq_num, newest_seq_num)) { |
| 204 | newest_seq_num = seq_num; |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 205 | } |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 206 | if (IsNewerSequenceNumber(oldest_seq_num, seq_num)) { |
| 207 | oldest_seq_num = seq_num; |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 208 | } |
| 209 | ++node_it; |
| 210 | ++number_packets_received; |
| 211 | } |
| 212 | // Interval width between oldest and newest sequence number. |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 213 | // There was an overflow if newest_seq_num < oldest_seq_num. |
| 214 | int gap = static_cast<uint16_t>(newest_seq_num - oldest_seq_num + 1); |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 215 | |
| 216 | return static_cast<float>(gap - number_packets_received) / gap; |
| 217 | } |
| 218 | |
stefan | 870eee4 | 2015-07-14 03:53:57 -0700 | [diff] [blame] | 219 | LinkedSet::~LinkedSet() { |
| 220 | while (!empty()) |
| 221 | RemoveTail(); |
| 222 | } |
| 223 | |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 224 | void LinkedSet::Insert(uint16_t sequence_number, |
| 225 | int64_t send_time_ms, |
| 226 | int64_t arrival_time_ms, |
| 227 | size_t payload_size) { |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 228 | auto it = map_.find(sequence_number); |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 229 | if (it != map_.end()) { |
| 230 | PacketNodeIt node_it = it->second; |
| 231 | PacketIdentifierNode* node = *node_it; |
| 232 | node->arrival_time_ms = arrival_time_ms; |
| 233 | if (node_it != list_.begin()) { |
| 234 | list_.erase(node_it); |
| 235 | list_.push_front(node); |
| 236 | map_[sequence_number] = list_.begin(); |
| 237 | } |
| 238 | } else { |
| 239 | if (size() == capacity_) { |
| 240 | RemoveTail(); |
| 241 | } |
| 242 | UpdateHead(new PacketIdentifierNode(sequence_number, send_time_ms, |
| 243 | arrival_time_ms, payload_size)); |
| 244 | } |
| 245 | } |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 246 | |
| 247 | void LinkedSet::Insert(PacketIdentifierNode packet_identifier) { |
| 248 | Insert(packet_identifier.sequence_number, packet_identifier.send_time_ms, |
| 249 | packet_identifier.arrival_time_ms, packet_identifier.payload_size); |
| 250 | } |
| 251 | |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 252 | void LinkedSet::RemoveTail() { |
| 253 | map_.erase(list_.back()->sequence_number); |
stefan | 870eee4 | 2015-07-14 03:53:57 -0700 | [diff] [blame] | 254 | delete list_.back(); |
Cesar Magalhaes | 77cabab | 2015-06-08 11:29:08 +0200 | [diff] [blame] | 255 | list_.pop_back(); |
| 256 | } |
| 257 | void LinkedSet::UpdateHead(PacketIdentifierNode* new_head) { |
| 258 | list_.push_front(new_head); |
| 259 | map_[new_head->sequence_number] = list_.begin(); |
| 260 | } |
| 261 | |
Cesar Magalhaes | 9c261f2 | 2015-07-15 16:31:18 +0200 | [diff] [blame] | 262 | void LinkedSet::Erase(PacketNodeIt node_it) { |
| 263 | map_.erase((*node_it)->sequence_number); |
| 264 | delete (*node_it); |
| 265 | list_.erase(node_it); |
| 266 | } |
| 267 | |
| 268 | void LossAccount::Add(LossAccount rhs) { |
| 269 | num_total += rhs.num_total; |
| 270 | num_lost += rhs.num_lost; |
| 271 | } |
| 272 | void LossAccount::Subtract(LossAccount rhs) { |
| 273 | num_total -= rhs.num_total; |
| 274 | num_lost -= rhs.num_lost; |
| 275 | } |
| 276 | |
| 277 | float LossAccount::LossRatio() { |
| 278 | if (num_total == 0) |
| 279 | return 0.0f; |
| 280 | return static_cast<float>(num_lost) / num_total; |
| 281 | } |
| 282 | |
stefan@webrtc.org | 14b0279 | 2015-02-16 12:02:20 +0000 | [diff] [blame] | 283 | } // namespace bwe |
| 284 | } // namespace testing |
| 285 | } // namespace webrtc |