blob: 72696f6c80a0b429cb6045c950fc5ccf8f21852f [file] [log] [blame]
Victor Boivieae1f8f52021-05-04 13:52:321/*
2 * Copyright (c) 2021 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#include "modules/remote_bitrate_estimator/packet_arrival_map.h"
11
12#include <algorithm>
13
14#include "rtc_base/numerics/safe_minmax.h"
15
16namespace webrtc {
17
18constexpr size_t PacketArrivalTimeMap::kMaxNumberOfPackets;
19
20void PacketArrivalTimeMap::AddPacket(int64_t sequence_number,
21 int64_t arrival_time_ms) {
22 if (!has_seen_packet_) {
23 // First packet.
24 has_seen_packet_ = true;
25 begin_sequence_number_ = sequence_number;
26 arrival_times.push_back(arrival_time_ms);
27 return;
28 }
29
30 int64_t pos = sequence_number - begin_sequence_number_;
31 if (pos >= 0 && pos < static_cast<int64_t>(arrival_times.size())) {
32 // The packet is within the buffer - no need to expand it.
33 arrival_times[pos] = arrival_time_ms;
34 return;
35 }
36
37 if (pos < 0) {
38 // The packet goes before the current buffer. Expand to add packet, but only
39 // if it fits within kMaxNumberOfPackets.
40 size_t missing_packets = -pos;
41 if (missing_packets + arrival_times.size() > kMaxNumberOfPackets) {
42 // Don't expand the buffer further, as that would remove newly received
43 // packets.
44 return;
45 }
46
47 arrival_times.insert(arrival_times.begin(), missing_packets, 0);
48 arrival_times[0] = arrival_time_ms;
49 begin_sequence_number_ = sequence_number;
50 return;
51 }
52
53 // The packet goes after the buffer.
54
55 if (static_cast<size_t>(pos) >= kMaxNumberOfPackets) {
56 // The buffer grows too large - old packets have to be removed.
57 size_t packets_to_remove = pos - kMaxNumberOfPackets + 1;
58 if (packets_to_remove >= arrival_times.size()) {
59 arrival_times.clear();
60 begin_sequence_number_ = sequence_number;
61 pos = 0;
62 } else {
63 // Also trim the buffer to remove leading non-received packets, to
64 // ensure that the buffer only spans received packets.
65 while (packets_to_remove < arrival_times.size() &&
66 arrival_times[packets_to_remove] == 0) {
67 ++packets_to_remove;
68 }
69
70 arrival_times.erase(arrival_times.begin(),
71 arrival_times.begin() + packets_to_remove);
72 begin_sequence_number_ += packets_to_remove;
73 pos -= packets_to_remove;
74 RTC_DCHECK_GE(pos, 0);
75 }
76 }
77
78 // Packets can be received out-of-order. If this isn't the next expected
79 // packet, add enough placeholders to fill the gap.
80 size_t missing_gap_packets = pos - arrival_times.size();
81 if (missing_gap_packets > 0) {
82 arrival_times.insert(arrival_times.end(), missing_gap_packets, 0);
83 }
84 RTC_DCHECK_EQ(arrival_times.size(), pos);
85 arrival_times.push_back(arrival_time_ms);
86 RTC_DCHECK_LE(arrival_times.size(), kMaxNumberOfPackets);
87}
88
89void PacketArrivalTimeMap::RemoveOldPackets(int64_t sequence_number,
90 int64_t arrival_time_limit) {
91 while (!arrival_times.empty() && begin_sequence_number_ < sequence_number &&
92 arrival_times.front() <= arrival_time_limit) {
93 arrival_times.pop_front();
94 ++begin_sequence_number_;
95 }
96}
97
98bool PacketArrivalTimeMap::has_received(int64_t sequence_number) const {
99 int64_t pos = sequence_number - begin_sequence_number_;
100 if (pos >= 0 && pos < static_cast<int64_t>(arrival_times.size()) &&
101 arrival_times[pos] != 0) {
102 return true;
103 }
104 return false;
105}
106
107void PacketArrivalTimeMap::EraseTo(int64_t sequence_number) {
108 if (sequence_number > begin_sequence_number_) {
109 size_t count =
110 std::min(static_cast<size_t>(sequence_number - begin_sequence_number_),
111 arrival_times.size());
112
113 arrival_times.erase(arrival_times.begin(), arrival_times.begin() + count);
114 begin_sequence_number_ += count;
115 }
116}
117
118int64_t PacketArrivalTimeMap::clamp(int64_t sequence_number) const {
119 return rtc::SafeClamp(sequence_number, begin_sequence_number(),
120 end_sequence_number());
121}
122
123} // namespace webrtc