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"
14 #include <string.h> // memset
16 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h"
17 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
18 #include "webrtc/system_wrappers/interface/trace.h"
22 RTPPacketHistory::RTPPacketHistory(Clock* clock)
24 critsect_(CriticalSectionWrapper::CreateCriticalSection()),
27 max_packet_length_(0) {
30 RTPPacketHistory::~RTPPacketHistory() {
35 void RTPPacketHistory::SetStorePacketsStatus(bool enable,
36 uint16_t number_to_store) {
38 Allocate(number_to_store);
44 void RTPPacketHistory::Allocate(uint16_t number_to_store) {
45 assert(number_to_store > 0);
46 CriticalSectionScoped cs(critsect_);
48 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
49 "SetStorePacketsStatus already set, number: %d", number_to_store);
54 stored_packets_.resize(number_to_store);
55 stored_seq_nums_.resize(number_to_store);
56 stored_lengths_.resize(number_to_store);
57 stored_times_.resize(number_to_store);
58 stored_resend_times_.resize(number_to_store);
59 stored_types_.resize(number_to_store);
62 void RTPPacketHistory::Free() {
63 CriticalSectionScoped cs(critsect_);
68 std::vector<std::vector<uint8_t> >::iterator it;
69 for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
73 stored_packets_.clear();
74 stored_seq_nums_.clear();
75 stored_lengths_.clear();
76 stored_times_.clear();
77 stored_resend_times_.clear();
78 stored_types_.clear();
82 max_packet_length_ = 0;
85 bool RTPPacketHistory::StorePackets() const {
86 CriticalSectionScoped cs(critsect_);
90 // private, lock should already be taken
91 void RTPPacketHistory::VerifyAndAllocatePacketLength(uint16_t packet_length) {
92 assert(packet_length > 0);
97 if (packet_length <= max_packet_length_) {
101 std::vector<std::vector<uint8_t> >::iterator it;
102 for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {
103 it->resize(packet_length);
105 max_packet_length_ = packet_length;
108 int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet,
109 uint16_t packet_length,
110 uint16_t max_packet_length,
111 int64_t capture_time_ms,
113 if (type == kDontStore) {
117 CriticalSectionScoped cs(critsect_);
123 assert(packet_length > 3);
125 VerifyAndAllocatePacketLength(max_packet_length);
127 if (packet_length > max_packet_length_) {
128 WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, -1,
129 "Failed to store RTP packet, length: %d", packet_length);
133 const uint16_t seq_num = (packet[2] << 8) + packet[3];
136 std::vector<std::vector<uint8_t> >::iterator it =
137 stored_packets_.begin() + prev_index_;
138 std::copy(packet, packet + packet_length, it->begin());
140 stored_seq_nums_[prev_index_] = seq_num;
141 stored_lengths_[prev_index_] = packet_length;
142 stored_times_[prev_index_] =
143 (capture_time_ms > 0) ? capture_time_ms : clock_->TimeInMilliseconds();
144 stored_resend_times_[prev_index_] = 0; // packet not resent
145 stored_types_[prev_index_] = type;
148 if (prev_index_ >= stored_seq_nums_.size()) {
154 int32_t RTPPacketHistory::ReplaceRTPHeader(const uint8_t* packet,
155 uint16_t sequence_number,
156 uint16_t rtp_header_length) {
157 CriticalSectionScoped cs(critsect_);
163 assert(rtp_header_length > 3);
165 if (rtp_header_length > max_packet_length_) {
166 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
167 "Failed to replace RTP packet, length: %d", rtp_header_length);
172 bool found = FindSeqNum(sequence_number, &index);
174 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
175 "No match for getting seqNum %u", sequence_number);
179 uint16_t length = stored_lengths_.at(index);
180 if (length == 0 || length > max_packet_length_) {
181 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
182 "No match for getting seqNum %u, len %d", sequence_number, length);
185 assert(stored_seq_nums_[index] == sequence_number);
187 // Update RTP header.
188 std::vector<std::vector<uint8_t> >::iterator it =
189 stored_packets_.begin() + index;
190 std::copy(packet, packet + rtp_header_length, it->begin());
194 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
195 CriticalSectionScoped cs(critsect_);
201 bool found = FindSeqNum(sequence_number, &index);
206 uint16_t length = stored_lengths_.at(index);
207 if (length == 0 || length > max_packet_length_) {
214 bool RTPPacketHistory::GetRTPPacket(uint16_t sequence_number,
215 uint32_t min_elapsed_time_ms,
217 uint16_t* packet_length,
218 int64_t* stored_time_ms,
219 StorageType* type) const {
220 CriticalSectionScoped cs(critsect_);
226 bool found = FindSeqNum(sequence_number, &index);
228 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
229 "No match for getting seqNum %u", sequence_number);
233 uint16_t length = stored_lengths_.at(index);
234 if (length == 0 || length > max_packet_length_) {
235 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
236 "No match for getting seqNum %u, len %d", sequence_number, length);
240 if (length > *packet_length) {
241 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
242 "Input buffer too short for packet %u", sequence_number);
246 // Verify elapsed time since last retrieve.
247 int64_t now = clock_->TimeInMilliseconds();
248 if (min_elapsed_time_ms > 0 &&
249 ((now - stored_resend_times_.at(index)) < min_elapsed_time_ms)) {
250 WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
251 "Skip getting packet %u, packet recently resent.", sequence_number);
257 std::vector<std::vector<uint8_t> >::const_iterator it_found_packet =
258 stored_packets_.begin() + index;
259 std::copy(it_found_packet->begin(), it_found_packet->begin() + length, packet);
260 *packet_length = stored_lengths_.at(index);
261 *stored_time_ms = stored_times_.at(index);
262 *type = stored_types_.at(index);
266 void RTPPacketHistory::UpdateResendTime(uint16_t sequence_number) {
267 CriticalSectionScoped cs(critsect_);
273 bool found = FindSeqNum(sequence_number, &index);
275 WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
276 "Failed to update resend time, seq num: %u.", sequence_number);
279 stored_resend_times_[index] = clock_->TimeInMilliseconds();
282 // private, lock should already be taken
283 bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number,
284 int32_t* index) const {
285 uint16_t temp_sequence_number = 0;
286 if (prev_index_ > 0) {
287 *index = prev_index_ - 1;
288 temp_sequence_number = stored_seq_nums_[*index];
290 *index = stored_seq_nums_.size() - 1;
291 temp_sequence_number = stored_seq_nums_[*index]; // wrap
294 int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
295 if (idx >= 0 && idx < static_cast<int>(stored_seq_nums_.size())) {
297 temp_sequence_number = stored_seq_nums_[*index];
300 if (temp_sequence_number != sequence_number) {
301 // We did not found a match, search all.
302 for (uint16_t m = 0; m < stored_seq_nums_.size(); m++) {
303 if (stored_seq_nums_[m] == sequence_number) {
305 temp_sequence_number = stored_seq_nums_[*index];
310 if (temp_sequence_number == sequence_number) {
316 } // namespace webrtc