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 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 35 RTPPacketHistory::~RTPPacketHistory() { 36 { 37 CriticalSectionScoped cs(critsect_); 38 Free(); 39 } 40 delete critsect_; 41 } 42 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 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 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 91 bool RTPPacketHistory::StorePackets() const { 92 CriticalSectionScoped cs(critsect_); 93 return store_; 94 } 95 96 // private, lock should already be taken 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 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 160 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 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 224 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 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 252 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 286 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