2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h"
15 #include <string.h> // memset
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"
25 enum { kMinPacketRequestBytes = 50 };
27 RTPPacketHistory::RTPPacketHistory(Clock* clock)
29 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
32 max_packet_length_(0) {
35 RTPPacketHistory::~RTPPacketHistory() {
37 CriticalSectionScoped cs(critsect_);
43 void RTPPacketHistory::SetStorePacketsStatus(bool enable,
44 uint16_t number_to_store) {
45 CriticalSectionScoped cs(critsect_);
48 LOG(LS_WARNING) << "Purging packet history in order to re-set status.";
51 Allocate(number_to_store);
57 void RTPPacketHistory::Allocate(uint16_t number_to_store) {
58 assert(number_to_store > 0);
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);
69 void RTPPacketHistory::Free() {
74 std::vector<std::vector<uint8_t> >::iterator it;
75 for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
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();
88 max_packet_length_ = 0;
91 bool RTPPacketHistory::StorePackets() const {
92 CriticalSectionScoped cs(critsect_);
96 // private, lock should already be taken
97 void RTPPacketHistory::VerifyAndAllocatePacketLength(uint16_t packet_length) {
98 assert(packet_length > 0);
103 if (packet_length <= max_packet_length_) {
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);
111 max_packet_length_ = packet_length;
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,
119 if (type == kDontStore) {
123 CriticalSectionScoped cs(critsect_);
129 assert(packet_length > 3);
131 VerifyAndAllocatePacketLength(max_packet_length);
133 if (packet_length > max_packet_length_) {
134 LOG(LS_WARNING) << "Failed to store RTP packet with length: "
139 const uint16_t seq_num = (packet[2] << 8) + packet[3];
142 std::vector<std::vector<uint8_t> >::iterator it =
143 stored_packets_.begin() + prev_index_;
144 std::copy(packet, packet + packet_length, it->begin());
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;
154 if (prev_index_ >= stored_seq_nums_.size()) {
160 int32_t RTPPacketHistory::ReplaceRTPHeader(const uint8_t* packet,
161 uint16_t sequence_number,
162 uint16_t rtp_header_length) {
163 CriticalSectionScoped cs(critsect_);
169 assert(rtp_header_length > 3);
170 assert(rtp_header_length <= max_packet_length_);
173 bool found = FindSeqNum(sequence_number, &index);
176 << "Failed to replace RTP packet due to missing sequence number.";
180 uint16_t length = stored_lengths_.at(index);
181 if (length == 0 || length > max_packet_length_) {
182 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number
183 << ", len " << length;
186 assert(stored_seq_nums_[index] == sequence_number);
188 // Update RTP header.
189 std::vector<std::vector<uint8_t> >::iterator it =
190 stored_packets_.begin() + index;
191 std::copy(packet, packet + rtp_header_length, it->begin());
195 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
196 CriticalSectionScoped cs(critsect_);
202 bool found = FindSeqNum(sequence_number, &index);
207 uint16_t length = stored_lengths_.at(index);
208 if (length == 0 || length > max_packet_length_) {
215 bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number,
216 uint32_t min_elapsed_time_ms,
219 uint16_t* packet_length,
220 int64_t* stored_time_ms) {
221 assert(*packet_length >= max_packet_length_);
222 CriticalSectionScoped cs(critsect_);
228 bool found = FindSeqNum(sequence_number, &index);
230 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number;
234 uint16_t length = stored_lengths_.at(index);
235 assert(length <= max_packet_length_);
237 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number
238 << ", len " << length;
242 // Verify elapsed time since last retrieve.
243 int64_t now = clock_->TimeInMilliseconds();
244 if (min_elapsed_time_ms > 0 &&
245 ((now - stored_send_times_.at(index)) < min_elapsed_time_ms)) {
249 if (retransmit && stored_types_.at(index) == kDontRetransmit) {
250 // No bytes copied since this packet shouldn't be retransmitted or is
254 stored_send_times_[index] = clock_->TimeInMilliseconds();
255 GetPacket(index, packet, packet_length, stored_time_ms);
259 void RTPPacketHistory::GetPacket(int index,
261 uint16_t* packet_length,
262 int64_t* stored_time_ms) const {
264 uint16_t length = stored_lengths_.at(index);
265 std::vector<std::vector<uint8_t> >::const_iterator it_found_packet =
266 stored_packets_.begin() + index;
267 std::copy(it_found_packet->begin(), it_found_packet->begin() + length,
269 *packet_length = length;
270 *stored_time_ms = stored_times_.at(index);
273 bool RTPPacketHistory::GetBestFittingPacket(uint8_t* packet,
274 uint16_t* packet_length,
275 int64_t* stored_time_ms) {
276 CriticalSectionScoped cs(critsect_);
279 int index = FindBestFittingPacket(*packet_length);
282 GetPacket(index, packet, packet_length, stored_time_ms);
286 // private, lock should already be taken
287 bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
288 int32_t* index) const {
289 uint16_t temp_sequence_number = 0;
290 if (prev_index_ > 0) {
291 *index = prev_index_ - 1;
292 temp_sequence_number = stored_seq_nums_[*index];
294 *index = stored_seq_nums_.size() - 1;
295 temp_sequence_number = stored_seq_nums_[*index]; // wrap
298 int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
299 if (idx >= 0 && idx < static_cast<int>(stored_seq_nums_.size())) {
301 temp_sequence_number = stored_seq_nums_[*index];
304 if (temp_sequence_number != sequence_number) {
305 // We did not found a match, search all.
306 for (uint16_t m = 0; m < stored_seq_nums_.size(); m++) {
307 if (stored_seq_nums_[m] == sequence_number) {
309 temp_sequence_number = stored_seq_nums_[*index];
314 if (temp_sequence_number == sequence_number) {
321 int RTPPacketHistory::FindBestFittingPacket(uint16_t size) const {
322 if (size < kMinPacketRequestBytes || stored_lengths_.empty())
325 size_t best_index = 0;
326 for (size_t i = 0; i < stored_lengths_.size(); ++i) {
327 if (stored_lengths_[i] == 0)
329 int diff = abs(stored_lengths_[i] - size);
330 if (min_diff < 0 || diff < min_diff) {
339 } // namespace webrtc