- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / rtp_rtcp / source / rtp_packet_history.cc
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 <string.h>   // memset
15
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"
19
20 namespace webrtc {
21
22 RTPPacketHistory::RTPPacketHistory(Clock* clock)
23   : clock_(clock),
24     critsect_(CriticalSectionWrapper::CreateCriticalSection()),
25     store_(false),
26     prev_index_(0),
27     max_packet_length_(0) {
28 }
29
30 RTPPacketHistory::~RTPPacketHistory() {
31   Free();
32   delete critsect_;
33 }
34
35 void RTPPacketHistory::SetStorePacketsStatus(bool enable, 
36                                              uint16_t number_to_store) {
37   if (enable) {
38     Allocate(number_to_store);
39   } else {
40     Free();
41   }
42 }
43
44 void RTPPacketHistory::Allocate(uint16_t number_to_store) {
45   assert(number_to_store > 0);
46   CriticalSectionScoped cs(critsect_);
47   if (store_) {
48     WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
49         "SetStorePacketsStatus already set, number: %d", number_to_store);
50     return;
51   }
52
53   store_ = true;
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);
60 }
61
62 void RTPPacketHistory::Free() {
63   CriticalSectionScoped cs(critsect_);
64   if (!store_) {
65     return;
66   }
67
68   std::vector<std::vector<uint8_t> >::iterator it;
69   for (it = stored_packets_.begin(); it != stored_packets_.end(); ++it) {   
70     it->clear();
71   }
72
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();
79
80   store_ = false;
81   prev_index_ = 0;
82   max_packet_length_ = 0;
83 }
84
85 bool RTPPacketHistory::StorePackets() const {
86   CriticalSectionScoped cs(critsect_);
87   return store_;
88 }
89
90 // private, lock should already be taken
91 void RTPPacketHistory::VerifyAndAllocatePacketLength(uint16_t packet_length) {
92   assert(packet_length > 0);
93   if (!store_) {
94     return;
95   }
96
97   if (packet_length <= max_packet_length_) {
98     return;
99   }
100
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);
104   }
105   max_packet_length_ = packet_length;
106 }
107
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,
112                                        StorageType type) {
113   if (type == kDontStore) {
114     return 0;
115   }
116
117   CriticalSectionScoped cs(critsect_);
118   if (!store_) {
119     return 0;
120   }
121
122   assert(packet);
123   assert(packet_length > 3);
124
125   VerifyAndAllocatePacketLength(max_packet_length);
126
127   if (packet_length > max_packet_length_) {
128     WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, -1,
129         "Failed to store RTP packet, length: %d", packet_length);
130     return -1;
131   }
132
133   const uint16_t seq_num = (packet[2] << 8) + packet[3];
134
135   // Store packet
136   std::vector<std::vector<uint8_t> >::iterator it =
137       stored_packets_.begin() + prev_index_;
138   std::copy(packet, packet + packet_length, it->begin());
139
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;
146
147   ++prev_index_;
148   if (prev_index_ >= stored_seq_nums_.size()) {
149     prev_index_ = 0;
150   }
151   return 0;
152 }
153
154 int32_t RTPPacketHistory::ReplaceRTPHeader(const uint8_t* packet,
155                                            uint16_t sequence_number,
156                                            uint16_t rtp_header_length) {
157   CriticalSectionScoped cs(critsect_);
158   if (!store_) {
159     return 0;
160   }
161
162   assert(packet);
163   assert(rtp_header_length > 3);
164
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);
168     return -1;
169   }
170
171   int32_t index = 0;
172   bool found = FindSeqNum(sequence_number, &index);
173   if (!found) {
174     WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
175         "No match for getting seqNum %u", sequence_number);
176     return -1;
177   }
178
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);
183     return -1;
184   }
185   assert(stored_seq_nums_[index] == sequence_number);
186
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());
191   return 0;
192 }
193
194 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const {
195   CriticalSectionScoped cs(critsect_);
196   if (!store_) {
197     return false;
198   }
199
200   int32_t index = 0;
201   bool found = FindSeqNum(sequence_number, &index);
202   if (!found) {
203     return false;
204   }
205  
206   uint16_t length = stored_lengths_.at(index);
207   if (length == 0 || length > max_packet_length_) {
208     // Invalid length.
209     return false;
210   }
211   return true;
212 }
213
214 bool RTPPacketHistory::GetRTPPacket(uint16_t sequence_number,
215                                     uint32_t min_elapsed_time_ms,
216                                     uint8_t* packet,
217                                     uint16_t* packet_length,
218                                     int64_t* stored_time_ms,
219                                     StorageType* type) const {
220   CriticalSectionScoped cs(critsect_);
221   if (!store_) {
222     return false;
223   }
224
225   int32_t index = 0;
226   bool found = FindSeqNum(sequence_number, &index);
227   if (!found) {
228     WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
229         "No match for getting seqNum %u", sequence_number);
230     return false;
231   }
232
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);
237     return false;
238   }
239
240  if (length > *packet_length) {
241     WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1, 
242         "Input buffer too short for packet %u", sequence_number);
243     return false;
244  }
245
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);
252     *packet_length = 0;
253     return true;
254   }
255
256   // Get packet.
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);
263   return true;
264 }
265
266 void RTPPacketHistory::UpdateResendTime(uint16_t sequence_number) {
267   CriticalSectionScoped cs(critsect_);
268   if (!store_) {
269     return;
270   }
271
272   int32_t index = 0;
273   bool found = FindSeqNum(sequence_number, &index);
274   if (!found) {
275     WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, -1,
276         "Failed to update resend time, seq num: %u.", sequence_number);
277     return;
278   }
279   stored_resend_times_[index] = clock_->TimeInMilliseconds();
280 }
281
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];
289   } else {
290     *index = stored_seq_nums_.size() - 1;
291     temp_sequence_number = stored_seq_nums_[*index];  // wrap
292   }
293
294   int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number);
295   if (idx >= 0 && idx < static_cast<int>(stored_seq_nums_.size())) {
296     *index = idx;
297     temp_sequence_number = stored_seq_nums_[*index];
298   }
299
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) {
304         *index = m;
305         temp_sequence_number = stored_seq_nums_[*index];
306         break;
307       }
308     }
309   }
310   if (temp_sequence_number == sequence_number) {
311     // We found a match.
312     return true;
313   }
314   return false;
315 }
316 }  // namespace webrtc