/* * Copyright (c) 2019 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 "modules/congestion_controller/goog_cc/robust_throughput_estimator.h" #include #include #include #include "rtc_base/checks.h" namespace webrtc { RobustThroughputEstimator::RobustThroughputEstimator( const RobustThroughputEstimatorSettings& settings) : settings_(settings) { RTC_DCHECK(settings.enabled); } RobustThroughputEstimator::~RobustThroughputEstimator() {} void RobustThroughputEstimator::IncomingPacketFeedbackVector( const std::vector& packet_feedback_vector) { RTC_DCHECK(std::is_sorted(packet_feedback_vector.begin(), packet_feedback_vector.end(), PacketResult::ReceiveTimeOrder())); for (const auto& packet : packet_feedback_vector) { // Insert the new packet. window_.push_back(packet); // In most cases, receive timestamps should already be in order, but in the // rare case where feedback packets have been reordered, we do some swaps to // ensure that the window is sorted. for (size_t i = window_.size() - 1; i > 0 && window_[i].receive_time < window_[i - 1].receive_time; i--) { std::swap(window_[i], window_[i - 1]); } // Remove old packets. while (window_.size() > settings_.kMaxPackets || (window_.size() > settings_.min_packets && packet.receive_time - window_.front().receive_time > settings_.window_duration)) { window_.pop_front(); } } } absl::optional RobustThroughputEstimator::bitrate() const { if (window_.size() < settings_.initial_packets) return absl::nullopt; TimeDelta largest_recv_gap(TimeDelta::Millis(0)); TimeDelta second_largest_recv_gap(TimeDelta::Millis(0)); for (size_t i = 1; i < window_.size(); i++) { // Find receive time gaps TimeDelta gap = window_[i].receive_time - window_[i - 1].receive_time; if (gap > largest_recv_gap) { second_largest_recv_gap = largest_recv_gap; largest_recv_gap = gap; } else if (gap > second_largest_recv_gap) { second_largest_recv_gap = gap; } } Timestamp min_send_time = window_[0].sent_packet.send_time; Timestamp max_send_time = window_[0].sent_packet.send_time; Timestamp min_recv_time = window_[0].receive_time; Timestamp max_recv_time = window_[0].receive_time; DataSize data_size = DataSize::Bytes(0); for (const auto& packet : window_) { min_send_time = std::min(min_send_time, packet.sent_packet.send_time); max_send_time = std::max(max_send_time, packet.sent_packet.send_time); min_recv_time = std::min(min_recv_time, packet.receive_time); max_recv_time = std::max(max_recv_time, packet.receive_time); data_size += packet.sent_packet.size; data_size += packet.sent_packet.prior_unacked_data * settings_.unacked_weight; } // Suppose a packet of size S is sent every T milliseconds. // A window of N packets would contain N*S bytes, but the time difference // between the first and the last packet would only be (N-1)*T. Thus, we // need to remove one packet. DataSize recv_size = data_size; DataSize send_size = data_size; if (settings_.assume_shared_link) { // Depending on how the bottleneck queue is implemented, a large packet // may delay sending of sebsequent packets, so the delay between packets // i and i+1 depends on the size of both packets. In this case we minimize // the maximum error by removing half of both the first and last packet // size. DataSize first_last_average_size = (window_.front().sent_packet.size + window_.front().sent_packet.prior_unacked_data + window_.back().sent_packet.size + window_.back().sent_packet.prior_unacked_data) / 2; recv_size -= first_last_average_size; send_size -= first_last_average_size; } else { // In the simpler case where the delay between packets i and i+1 only // depends on the size of packet i+1, the first packet doesn't give us // any information. Analogously, we assume that the start send time // for the last packet doesn't depend on the size of the packet. recv_size -= (window_.front().sent_packet.size + window_.front().sent_packet.prior_unacked_data); send_size -= (window_.back().sent_packet.size + window_.back().sent_packet.prior_unacked_data); } // Remove the largest gap by replacing it by the second largest gap // or the average gap. TimeDelta send_duration = max_send_time - min_send_time; TimeDelta recv_duration = (max_recv_time - min_recv_time) - largest_recv_gap; if (settings_.reduce_bias) { recv_duration += second_largest_recv_gap; } else { recv_duration += recv_duration / (window_.size() - 2); } send_duration = std::max(send_duration, TimeDelta::Millis(1)); recv_duration = std::max(recv_duration, TimeDelta::Millis(1)); return std::min(send_size / send_duration, recv_size / recv_duration); } } // namespace webrtc