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 <assert.h>
14 #include <stdlib.h>
15 #include <string.h> // memset
16 #include <limits>
17 #include <set>
18
19 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
20 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
21 #include "webrtc/system_wrappers/interface/logging.h"
22
23 namespace webrtc {
24
25 enum { kMinPacketRequestBytes = 50 };
26
RTPPacketHistory(Clock * clock)27 RTPPacketHistory::RTPPacketHistory(Clock* clock)
28 : clock_(clock),
29 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
30 store_(false),
31 prev_index_(0),
32 max_packet_length_(0) {
33 }
34
~RTPPacketHistory()35 RTPPacketHistory::~RTPPacketHistory() {
36 {
37 CriticalSectionScoped cs(critsect_);
38 Free();
39 }
40 delete critsect_;
41 }
42
SetStorePacketsStatus(bool enable,uint16_t number_to_store)43 void RTPPacketHistory::SetStorePacketsStatus(bool enable,
44 uint16_t number_to_store) {
45 CriticalSectionScoped cs(critsect_);
46 if (enable) {
47 if (store_) {
48 LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
49 Free();
50 }
51 Allocate(number_to_store);
52 } else {
53 Free();
54 }
55 }
56
Allocate(uint16_t number_to_store)57 void RTPPacketHistory::Allocate(uint16_t number_to_store) {
58 assert(number_to_store > 0);
59 assert(!store_);
60 store_ = true;
61 stored_packets_.resize(number_to_store);
62 stored_seq_nums_.resize(number_to_store);
63 stored_lengths_.resize(number_to_store);
64 stored_times_.resize(number_to_store);
65 stored_send_times_.resize(number_to_store);
66 stored_types_.resize(number_to_store);
67 }
68
Free()69 void RTPPacketHistory::Free() {
70 if (!store_) {
71 return;
72 }
73
74 std::vector<std::vector<uint8_t> >::iterator it;
75 for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
76 it->clear();
77 }
78
79 stored_packets_.clear();
80 stored_seq_nums_.clear();
81 stored_lengths_.clear();
82 stored_times_.clear();
83 stored_send_times_.clear();
84 stored_types_.clear();
85
86 store_ = false;
87 prev_index_ = 0;
88 max_packet_length_ = 0;
89 }
90
StorePackets() const91 bool RTPPacketHistory::StorePackets() const {
92 CriticalSectionScoped cs(critsect_);
93 return store_;
94 }
95
96 // private, lock should already be taken
VerifyAndAllocatePacketLength(uint16_t packet_length)97 void RTPPacketHistory::VerifyAndAllocatePacketLength(uint16_t packet_length) {
98 assert(packet_length > 0);
99 if (!store_) {
100 return;
101 }
102
103 if (packet_length <= max_packet_length_) {
104 return;
105 }
106
107 std::vector<std::vector<uint8_t> >::iterator it;
108 for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
109 it->resize(packet_length);
110 }
111 max_packet_length_ = packet_length;
112 }
113
PutRTPPacket(const uint8_t * packet,uint16_t packet_length,uint16_t max_packet_length,int64_t capture_time_ms,StorageType type)114 int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
115 uint16_t packet_length,
116 uint16_t max_packet_length,
117 int64_t capture_time_ms,
118 StorageType type) {
119 if (type == kDontStore) {
120 return 0;
121 }
122
123 CriticalSectionScoped cs(critsect_);
124 if (!store_) {
125 return 0;
126 }
127
128 assert(packet);
129 assert(packet_length > 3);
130
131 VerifyAndAllocatePacketLength(max_packet_length);
132
133 if (packet_length > max_packet_length_) {
134 LOG(LS_WARNING) << "Failed to store RTP packet with length: "
135 << packet_length;
136 return -1;
137 }
138
139 const uint16_t seq_num = (packet[2] << 8) + packet[3];
140
141 // Store packet
142 std::vector<std::vector<uint8_t> >::iterator it =
143 stored_packets_.begin() + prev_index_;
144 std::copy(packet, packet + packet_length, it->begin());
145
146 stored_seq_nums_[prev_index_] = seq_num;
147 stored_lengths_[prev_index_] = packet_length;
148 stored_times_[prev_index_] = (capture_time_ms > 0) ? capture_time_ms :
149 clock_->TimeInMilliseconds();
150 stored_send_times_[prev_index_] = 0; // Packet not sent.
151 stored_types_[prev_index_] = type;
152
153 ++prev_index_;
154 if (prev_index_ >= stored_seq_nums_.size()) {
155 prev_index_ = 0;
156 }
157 return 0;
158 }
159
HasRTPPacket(uint16_t sequence_number) const160 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
161 CriticalSectionScoped cs(critsect_);
162 if (!store_) {
163 return false;
164 }
165
166 int32_t index = 0;
167 bool found = FindSeqNum(sequence_number, &index);
168 if (!found) {
169 return false;
170 }
171
172 uint16_t length = stored_lengths_.at(index);
173 if (length == 0 || length > max_packet_length_) {
174 // Invalid length.
175 return false;
176 }
177 return true;
178 }
179
GetPacketAndSetSendTime(uint16_t sequence_number,uint32_t min_elapsed_time_ms,bool retransmit,uint8_t * packet,uint16_t * packet_length,int64_t * stored_time_ms)180 bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
181 uint32_t min_elapsed_time_ms,
182 bool retransmit,
183 uint8_t* packet,
184 uint16_t* packet_length,
185 int64_t* stored_time_ms) {
186 assert(*packet_length >= max_packet_length_);
187 CriticalSectionScoped cs(critsect_);
188 if (!store_) {
189 return false;
190 }
191
192 int32_t index = 0;
193 bool found = FindSeqNum(sequence_number, &index);
194 if (!found) {
195 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number;
196 return false;
197 }
198
199 uint16_t length = stored_lengths_.at(index);
200 assert(length <= max_packet_length_);
201 if (length == 0) {
202 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number
203 << ", len " << length;
204 return false;
205 }
206
207 // Verify elapsed time since last retrieve.
208 int64_t now = clock_->TimeInMilliseconds();
209 if (min_elapsed_time_ms > 0 &&
210 ((now - stored_send_times_.at(index)) < min_elapsed_time_ms)) {
211 return false;
212 }
213
214 if (retransmit && stored_types_.at(index) == kDontRetransmit) {
215 // No bytes copied since this packet shouldn't be retransmitted or is
216 // of zero size.
217 return false;
218 }
219 stored_send_times_[index] = clock_->TimeInMilliseconds();
220 GetPacket(index, packet, packet_length, stored_time_ms);
221 return true;
222 }
223
GetPacket(int index,uint8_t * packet,uint16_t * packet_length,int64_t * stored_time_ms) const224 void RTPPacketHistory::GetPacket(int index,
225 uint8_t* packet,
226 uint16_t* packet_length,
227 int64_t* stored_time_ms) const {
228 // Get packet.
229 uint16_t length = stored_lengths_.at(index);
230 std::vector<std::vector<uint8_t> >::const_iterator it_found_packet =
231 stored_packets_.begin() + index;
232 std::copy(it_found_packet->begin(), it_found_packet->begin() + length,
233 packet);
234 *packet_length = length;
235 *stored_time_ms = stored_times_.at(index);
236 }
237
GetBestFittingPacket(uint8_t * packet,uint16_t * packet_length,int64_t * stored_time_ms)238 bool RTPPacketHistory::GetBestFittingPacket(uint8_t* packet,
239 uint16_t* packet_length,
240 int64_t* stored_time_ms) {
241 CriticalSectionScoped cs(critsect_);
242 if (!store_)
243 return false;
244 int index = FindBestFittingPacket(*packet_length);
245 if (index < 0)
246 return false;
247 GetPacket(index, packet, packet_length, stored_time_ms);
248 return true;
249 }
250
251 // private, lock should already be taken
FindSeqNum(uint16_t sequence_number,int32_t * index) const252 bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
253 int32_t* index) const {
254 uint16_t temp_sequence_number = 0;
255 if (prev_index_ > 0) {
256 *index = prev_index_ - 1;
257 temp_sequence_number = stored_seq_nums_[*index];
258 } else {
259 *index = stored_seq_nums_.size() - 1;
260 temp_sequence_number = stored_seq_nums_[*index]; // wrap
261 }
262
263 int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
264 if (idx >= 0 && idx < static_cast<int>(stored_seq_nums_.size())) {
265 *index = idx;
266 temp_sequence_number = stored_seq_nums_[*index];
267 }
268
269 if (temp_sequence_number != sequence_number) {
270 // We did not found a match, search all.
271 for (uint16_t m = 0; m < stored_seq_nums_.size(); m++) {
272 if (stored_seq_nums_[m] == sequence_number) {
273 *index = m;
274 temp_sequence_number = stored_seq_nums_[*index];
275 break;
276 }
277 }
278 }
279 if (temp_sequence_number == sequence_number) {
280 // We found a match.
281 return true;
282 }
283 return false;
284 }
285
FindBestFittingPacket(uint16_t size) const286 int RTPPacketHistory::FindBestFittingPacket(uint16_t size) const {
287 if (size < kMinPacketRequestBytes || stored_lengths_.empty())
288 return -1;
289 int min_diff = -1;
290 size_t best_index = 0;
291 for (size_t i = 0; i < stored_lengths_.size(); ++i) {
292 if (stored_lengths_[i] == 0)
293 continue;
294 int diff = abs(stored_lengths_[i] - size);
295 if (min_diff < 0 || diff < min_diff) {
296 min_diff = diff;
297 best_index = i;
298 }
299 }
300 if (min_diff < 0)
301 return -1;
302 return best_index;
303 }
304 } // namespace webrtc
305