/* * Copyright (c) 2021 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/remote_bitrate_estimator/packet_arrival_map.h" #include #include "rtc_base/numerics/safe_minmax.h" namespace webrtc { constexpr size_t PacketArrivalTimeMap::kMaxNumberOfPackets; void PacketArrivalTimeMap::AddPacket(int64_t sequence_number, Timestamp arrival_time) { if (!has_seen_packet_) { // First packet. has_seen_packet_ = true; begin_sequence_number_ = sequence_number; arrival_times_.push_back(arrival_time); return; } int64_t pos = sequence_number - begin_sequence_number_; if (pos >= 0 && pos < static_cast(arrival_times_.size())) { // The packet is within the buffer - no need to expand it. arrival_times_[pos] = arrival_time; return; } if (pos < 0) { // The packet goes before the current buffer. Expand to add packet, but only // if it fits within kMaxNumberOfPackets. size_t missing_packets = -pos; if (missing_packets + arrival_times_.size() > kMaxNumberOfPackets) { // Don't expand the buffer further, as that would remove newly received // packets. return; } arrival_times_.insert(arrival_times_.begin(), missing_packets, Timestamp::Zero()); arrival_times_[0] = arrival_time; begin_sequence_number_ = sequence_number; return; } // The packet goes after the buffer. if (static_cast(pos) >= kMaxNumberOfPackets) { // The buffer grows too large - old packets have to be removed. size_t packets_to_remove = pos - kMaxNumberOfPackets + 1; if (packets_to_remove >= arrival_times_.size()) { arrival_times_.clear(); begin_sequence_number_ = sequence_number; pos = 0; } else { // Also trim the buffer to remove leading non-received packets, to // ensure that the buffer only spans received packets. while (packets_to_remove < arrival_times_.size() && arrival_times_[packets_to_remove] == Timestamp::Zero()) { ++packets_to_remove; } arrival_times_.erase(arrival_times_.begin(), arrival_times_.begin() + packets_to_remove); begin_sequence_number_ += packets_to_remove; pos -= packets_to_remove; RTC_DCHECK_GE(pos, 0); } } // Packets can be received out-of-order. If this isn't the next expected // packet, add enough placeholders to fill the gap. size_t missing_gap_packets = pos - arrival_times_.size(); if (missing_gap_packets > 0) { arrival_times_.insert(arrival_times_.end(), missing_gap_packets, Timestamp::Zero()); } RTC_DCHECK_EQ(arrival_times_.size(), pos); arrival_times_.push_back(arrival_time); RTC_DCHECK_LE(arrival_times_.size(), kMaxNumberOfPackets); } void PacketArrivalTimeMap::RemoveOldPackets(int64_t sequence_number, Timestamp arrival_time_limit) { while (!arrival_times_.empty() && begin_sequence_number_ < sequence_number && arrival_times_.front() <= arrival_time_limit) { arrival_times_.pop_front(); ++begin_sequence_number_; } } bool PacketArrivalTimeMap::has_received(int64_t sequence_number) const { int64_t pos = sequence_number - begin_sequence_number_; if (pos >= 0 && pos < static_cast(arrival_times_.size()) && arrival_times_[pos] != Timestamp::Zero()) { return true; } return false; } void PacketArrivalTimeMap::EraseTo(int64_t sequence_number) { if (sequence_number > begin_sequence_number_) { size_t count = std::min(static_cast(sequence_number - begin_sequence_number_), arrival_times_.size()); arrival_times_.erase(arrival_times_.begin(), arrival_times_.begin() + count); begin_sequence_number_ += count; } } int64_t PacketArrivalTimeMap::clamp(int64_t sequence_number) const { return rtc::SafeClamp(sequence_number, begin_sequence_number(), end_sequence_number()); } } // namespace webrtc