Line data Source code
1 : /*
2 : * Copyright (c) 2012 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 :
11 : #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
12 :
13 : #include <algorithm>
14 : #include <limits>
15 :
16 : #include "webrtc/base/checks.h"
17 : #include "webrtc/base/logging.h"
18 : #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
19 : #include "webrtc/system_wrappers/include/clock.h"
20 :
21 : namespace webrtc {
22 : namespace {
23 : constexpr size_t kMinPacketRequestBytes = 50;
24 : } // namespace
25 : constexpr size_t RtpPacketHistory::kMaxCapacity;
26 :
27 0 : RtpPacketHistory::RtpPacketHistory(Clock* clock)
28 0 : : clock_(clock), store_(false), prev_index_(0) {}
29 :
30 0 : RtpPacketHistory::~RtpPacketHistory() {}
31 :
32 0 : void RtpPacketHistory::SetStorePacketsStatus(bool enable,
33 : uint16_t number_to_store) {
34 0 : rtc::CritScope cs(&critsect_);
35 0 : if (enable) {
36 0 : if (store_) {
37 0 : LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
38 0 : Free();
39 : }
40 0 : RTC_DCHECK(!store_);
41 0 : Allocate(number_to_store);
42 : } else {
43 0 : Free();
44 : }
45 0 : }
46 :
47 0 : void RtpPacketHistory::Allocate(size_t number_to_store) {
48 0 : RTC_DCHECK_GT(number_to_store, 0);
49 0 : RTC_DCHECK_LE(number_to_store, kMaxCapacity);
50 0 : store_ = true;
51 0 : stored_packets_.resize(number_to_store);
52 0 : }
53 :
54 0 : void RtpPacketHistory::Free() {
55 0 : if (!store_) {
56 0 : return;
57 : }
58 :
59 0 : stored_packets_.clear();
60 :
61 0 : store_ = false;
62 0 : prev_index_ = 0;
63 : }
64 :
65 0 : bool RtpPacketHistory::StorePackets() const {
66 0 : rtc::CritScope cs(&critsect_);
67 0 : return store_;
68 : }
69 :
70 0 : void RtpPacketHistory::PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet,
71 : StorageType type,
72 : bool sent) {
73 0 : RTC_DCHECK(packet);
74 0 : rtc::CritScope cs(&critsect_);
75 0 : if (!store_) {
76 0 : return;
77 : }
78 :
79 : // If index we're about to overwrite contains a packet that has not
80 : // yet been sent (probably pending in paced sender), we need to expand
81 : // the buffer.
82 0 : if (stored_packets_[prev_index_].packet &&
83 0 : stored_packets_[prev_index_].send_time == 0) {
84 0 : size_t current_size = static_cast<uint16_t>(stored_packets_.size());
85 0 : if (current_size < kMaxCapacity) {
86 0 : size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1);
87 0 : expanded_size = std::min(expanded_size, kMaxCapacity);
88 0 : Allocate(expanded_size);
89 : // Causes discontinuity, but that's OK-ish. FindSeqNum() will still work,
90 : // but may be slower - at least until buffer has wrapped around once.
91 0 : prev_index_ = current_size;
92 : }
93 : }
94 :
95 : // Store packet.
96 0 : if (packet->capture_time_ms() <= 0)
97 0 : packet->set_capture_time_ms(clock_->TimeInMilliseconds());
98 0 : stored_packets_[prev_index_].sequence_number = packet->SequenceNumber();
99 0 : stored_packets_[prev_index_].send_time =
100 0 : (sent ? clock_->TimeInMilliseconds() : 0);
101 0 : stored_packets_[prev_index_].storage_type = type;
102 0 : stored_packets_[prev_index_].has_been_retransmitted = false;
103 0 : stored_packets_[prev_index_].packet = std::move(packet);
104 :
105 0 : ++prev_index_;
106 0 : if (prev_index_ >= stored_packets_.size()) {
107 0 : prev_index_ = 0;
108 : }
109 : }
110 :
111 0 : bool RtpPacketHistory::HasRtpPacket(uint16_t sequence_number) const {
112 0 : rtc::CritScope cs(&critsect_);
113 0 : if (!store_) {
114 0 : return false;
115 : }
116 :
117 0 : int unused_index = 0;
118 0 : return FindSeqNum(sequence_number, &unused_index);
119 : }
120 :
121 0 : std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndSetSendTime(
122 : uint16_t sequence_number,
123 : int64_t min_elapsed_time_ms,
124 : bool retransmit) {
125 0 : rtc::CritScope cs(&critsect_);
126 0 : if (!store_) {
127 0 : return nullptr;
128 : }
129 :
130 0 : int index = 0;
131 0 : if (!FindSeqNum(sequence_number, &index)) {
132 0 : LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number;
133 0 : return nullptr;
134 : }
135 0 : RTC_DCHECK_EQ(sequence_number,
136 0 : stored_packets_[index].packet->SequenceNumber());
137 :
138 : // Verify elapsed time since last retrieve, but only for retransmissions and
139 : // always send packet upon first retransmission request.
140 0 : int64_t now = clock_->TimeInMilliseconds();
141 0 : if (min_elapsed_time_ms > 0 && retransmit &&
142 0 : stored_packets_[index].has_been_retransmitted &&
143 0 : ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) {
144 0 : return nullptr;
145 : }
146 :
147 0 : if (retransmit) {
148 0 : if (stored_packets_[index].storage_type == kDontRetransmit) {
149 : // No bytes copied since this packet shouldn't be retransmitted.
150 0 : return nullptr;
151 : }
152 0 : stored_packets_[index].has_been_retransmitted = true;
153 : }
154 0 : stored_packets_[index].send_time = clock_->TimeInMilliseconds();
155 0 : return GetPacket(index);
156 : }
157 :
158 0 : std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacket(int index) const {
159 0 : const RtpPacketToSend& stored = *stored_packets_[index].packet;
160 0 : return std::unique_ptr<RtpPacketToSend>(new RtpPacketToSend(stored));
161 : }
162 :
163 0 : std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetBestFittingPacket(
164 : size_t packet_length) const {
165 0 : rtc::CritScope cs(&critsect_);
166 0 : if (!store_)
167 0 : return nullptr;
168 0 : int index = FindBestFittingPacket(packet_length);
169 0 : if (index < 0)
170 0 : return nullptr;
171 0 : return GetPacket(index);
172 : }
173 :
174 0 : bool RtpPacketHistory::FindSeqNum(uint16_t sequence_number, int* index) const {
175 0 : if (prev_index_ > 0) {
176 0 : *index = prev_index_ - 1;
177 : } else {
178 0 : *index = stored_packets_.size() - 1; // Wrap.
179 : }
180 0 : uint16_t temp_sequence_number = stored_packets_[*index].sequence_number;
181 :
182 0 : int idx = *index - (temp_sequence_number - sequence_number);
183 0 : if (idx >= 0 && idx < static_cast<int>(stored_packets_.size())) {
184 0 : *index = idx;
185 0 : temp_sequence_number = stored_packets_[*index].sequence_number;
186 : }
187 :
188 0 : if (temp_sequence_number != sequence_number) {
189 : // We did not found a match, search all.
190 0 : for (uint16_t m = 0; m < stored_packets_.size(); m++) {
191 0 : if (stored_packets_[m].sequence_number == sequence_number) {
192 0 : *index = m;
193 0 : temp_sequence_number = stored_packets_[*index].sequence_number;
194 0 : break;
195 : }
196 : }
197 : }
198 0 : return temp_sequence_number == sequence_number &&
199 0 : stored_packets_[*index].packet;
200 : }
201 :
202 0 : int RtpPacketHistory::FindBestFittingPacket(size_t size) const {
203 0 : if (size < kMinPacketRequestBytes || stored_packets_.empty())
204 0 : return -1;
205 0 : size_t min_diff = std::numeric_limits<size_t>::max();
206 0 : int best_index = -1; // Returned unchanged if we don't find anything.
207 0 : for (size_t i = 0; i < stored_packets_.size(); ++i) {
208 0 : if (!stored_packets_[i].packet)
209 0 : continue;
210 0 : size_t stored_size = stored_packets_[i].packet->size();
211 : size_t diff =
212 0 : (stored_size > size) ? (stored_size - size) : (size - stored_size);
213 0 : if (diff < min_diff) {
214 0 : min_diff = diff;
215 0 : best_index = static_cast<int>(i);
216 : }
217 : }
218 0 : return best_index;
219 : }
220 :
221 : } // namespace webrtc
|