OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h" | 11 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_history.h" |
12 | 12 |
13 #include <assert.h> | |
14 #include <stdlib.h> | |
15 #include <string.h> // memset | |
16 | |
17 #include <algorithm> | 13 #include <algorithm> |
18 #include <limits> | 14 #include <limits> |
19 #include <set> | |
20 | 15 |
21 #include "webrtc/base/checks.h" | 16 #include "webrtc/base/checks.h" |
22 #include "webrtc/base/logging.h" | 17 #include "webrtc/base/logging.h" |
23 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | 18 #include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h" |
19 #include "webrtc/system_wrappers/include/clock.h" | |
24 | 20 |
25 namespace webrtc { | 21 namespace webrtc { |
22 namespace { | |
23 constexpr size_t kMinPacketRequestBytes = 50; | |
24 } // namespace | |
25 constexpr size_t RtpPacketHistory::kMaxCapacity; | |
26 | 26 |
27 static const int kMinPacketRequestBytes = 50; | 27 RtpPacketHistory::RtpPacketHistory(Clock* clock) |
28 : clock_(clock), store_(false), prev_index_(0) {} | |
28 | 29 |
29 RTPPacketHistory::RTPPacketHistory(Clock* clock) | 30 RtpPacketHistory::~RtpPacketHistory() {} |
30 : clock_(clock), | |
31 store_(false), | |
32 prev_index_(0) {} | |
33 | 31 |
34 RTPPacketHistory::~RTPPacketHistory() { | 32 void RtpPacketHistory::SetStorePacketsStatus(bool enable, |
35 } | |
36 | |
37 void RTPPacketHistory::SetStorePacketsStatus(bool enable, | |
38 uint16_t number_to_store) { | 33 uint16_t number_to_store) { |
39 rtc::CritScope cs(&critsect_); | 34 rtc::CritScope cs(&critsect_); |
40 if (enable) { | 35 if (enable) { |
41 if (store_) { | 36 if (store_) { |
42 LOG(LS_WARNING) << "Purging packet history in order to re-set status."; | 37 LOG(LS_WARNING) << "Purging packet history in order to re-set status."; |
43 Free(); | 38 Free(); |
44 } | 39 } |
45 assert(!store_); | 40 RTC_DCHECK(!store_); |
46 Allocate(number_to_store); | 41 Allocate(number_to_store); |
47 } else { | 42 } else { |
48 Free(); | 43 Free(); |
49 } | 44 } |
50 } | 45 } |
51 | 46 |
52 void RTPPacketHistory::Allocate(size_t number_to_store) { | 47 void RtpPacketHistory::Allocate(size_t number_to_store) { |
53 assert(number_to_store > 0); | 48 RTC_DCHECK_GT(number_to_store, 0u); |
54 assert(number_to_store <= kMaxHistoryCapacity); | 49 RTC_DCHECK_LE(number_to_store, kMaxCapacity); |
55 store_ = true; | 50 store_ = true; |
56 stored_packets_.resize(number_to_store); | 51 stored_packets_.resize(number_to_store); |
57 } | 52 } |
58 | 53 |
59 void RTPPacketHistory::Free() { | 54 void RtpPacketHistory::Free() { |
60 if (!store_) { | 55 if (!store_) { |
61 return; | 56 return; |
62 } | 57 } |
63 | 58 |
64 stored_packets_.clear(); | 59 stored_packets_.clear(); |
65 | 60 |
66 store_ = false; | 61 store_ = false; |
67 prev_index_ = 0; | 62 prev_index_ = 0; |
68 } | 63 } |
69 | 64 |
70 bool RTPPacketHistory::StorePackets() const { | 65 bool RtpPacketHistory::StorePackets() const { |
71 rtc::CritScope cs(&critsect_); | 66 rtc::CritScope cs(&critsect_); |
72 return store_; | 67 return store_; |
73 } | 68 } |
74 | 69 |
75 int32_t RTPPacketHistory::PutRTPPacket(const uint8_t* packet, | 70 void RtpPacketHistory::PutRtpPacket(std::unique_ptr<RtpPacketToSend> packet, |
76 size_t packet_length, | 71 StorageType type, |
77 int64_t capture_time_ms, | 72 bool sent) { |
78 StorageType type) { | 73 RTC_DCHECK(packet); |
79 rtc::CritScope cs(&critsect_); | 74 rtc::CritScope cs(&critsect_); |
80 if (!store_) { | 75 if (!store_) { |
81 return 0; | 76 return; |
82 } | 77 } |
83 | 78 |
84 assert(packet); | |
85 assert(packet_length > 3); | |
86 | |
87 if (packet_length > IP_PACKET_SIZE) { | |
88 LOG(LS_WARNING) << "Failed to store RTP packet with length: " | |
89 << packet_length; | |
90 return -1; | |
91 } | |
92 | |
93 const uint16_t seq_num = (packet[2] << 8) + packet[3]; | |
94 | |
95 // If index we're about to overwrite contains a packet that has not | 79 // If index we're about to overwrite contains a packet that has not |
96 // yet been sent (probably pending in paced sender), we need to expand | 80 // yet been sent (probably pending in paced sender), we need to expand |
97 // the buffer. | 81 // the buffer. |
98 if (stored_packets_[prev_index_].length > 0 && | 82 if (stored_packets_[prev_index_].packet && |
stefan-webrtc
2016/05/09 11:49:23
Should we check for non-zero length as well, or is
danilchap
2016/05/09 13:45:22
This is implicit: history used length = 0 to indic
| |
99 stored_packets_[prev_index_].send_time == 0) { | 83 stored_packets_[prev_index_].send_time == 0) { |
100 size_t current_size = static_cast<uint16_t>(stored_packets_.size()); | 84 size_t current_size = static_cast<uint16_t>(stored_packets_.size()); |
101 if (current_size < kMaxHistoryCapacity) { | 85 if (current_size < kMaxCapacity) { |
102 size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1); | 86 size_t expanded_size = std::max(current_size * 3 / 2, current_size + 1); |
103 expanded_size = std::min(expanded_size, kMaxHistoryCapacity); | 87 expanded_size = std::min(expanded_size, kMaxCapacity); |
104 Allocate(expanded_size); | 88 Allocate(expanded_size); |
105 // Causes discontinuity, but that's OK-ish. FindSeqNum() will still work, | 89 // Causes discontinuity, but that's OK-ish. FindSeqNum() will still work, |
106 // but may be slower - at least until buffer has wrapped around once. | 90 // but may be slower - at least until buffer has wrapped around once. |
107 prev_index_ = current_size; | 91 prev_index_ = current_size; |
108 } | 92 } |
109 } | 93 } |
110 | 94 |
111 // Store packet | 95 // Store packet. |
112 // TODO(sprang): Overhaul this class and get rid of this copy step. | 96 if (packet->capture_time_ms() <= 0) { |
113 // (Finally introduce the RtpPacket class?) | 97 packet->set_capture_time_ms(clock_->TimeInMilliseconds()); |
114 memcpy(stored_packets_[prev_index_].data, packet, packet_length); | 98 } |
115 stored_packets_[prev_index_].length = packet_length; | 99 stored_packets_[prev_index_].sequence_number = packet->SequenceNumber(); |
116 | 100 stored_packets_[prev_index_].send_time = |
117 stored_packets_[prev_index_].sequence_number = seq_num; | 101 (sent ? clock_->TimeInMilliseconds() : 0); |
118 stored_packets_[prev_index_].time_ms = | |
119 (capture_time_ms > 0) ? capture_time_ms : clock_->TimeInMilliseconds(); | |
120 stored_packets_[prev_index_].send_time = 0; // Packet not sent. | |
121 stored_packets_[prev_index_].storage_type = type; | 102 stored_packets_[prev_index_].storage_type = type; |
122 stored_packets_[prev_index_].has_been_retransmitted = false; | 103 stored_packets_[prev_index_].has_been_retransmitted = false; |
104 stored_packets_[prev_index_].packet = std::move(packet); | |
123 | 105 |
124 ++prev_index_; | 106 ++prev_index_; |
125 if (prev_index_ >= stored_packets_.size()) { | 107 if (prev_index_ >= stored_packets_.size()) { |
126 prev_index_ = 0; | 108 prev_index_ = 0; |
127 } | 109 } |
128 return 0; | |
129 } | 110 } |
130 | 111 |
131 bool RTPPacketHistory::HasRTPPacket(uint16_t sequence_number) const { | 112 bool RtpPacketHistory::HasRtpPacket(uint16_t sequence_number) const { |
132 rtc::CritScope cs(&critsect_); | 113 rtc::CritScope cs(&critsect_); |
133 if (!store_) { | 114 if (!store_) { |
134 return false; | 115 return false; |
135 } | 116 } |
136 | 117 |
137 int32_t index = 0; | 118 int unused_index = 0; |
138 bool found = FindSeqNum(sequence_number, &index); | 119 return FindSeqNum(sequence_number, &unused_index); |
139 if (!found) { | 120 } |
140 return false; | 121 |
122 std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacketAndSetSendTime( | |
123 uint16_t sequence_number, | |
124 int64_t min_elapsed_time_ms, | |
125 bool retransmit) { | |
126 rtc::CritScope cs(&critsect_); | |
127 if (!store_) { | |
128 return nullptr; | |
141 } | 129 } |
142 | 130 |
143 if (stored_packets_[index].length == 0) { | 131 int index = 0; |
144 // Invalid length. | 132 if (!FindSeqNum(sequence_number, &index)) { |
145 return false; | 133 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number; |
134 return nullptr; | |
146 } | 135 } |
147 return true; | 136 RTC_DCHECK_EQ(sequence_number, |
148 } | 137 stored_packets_[index].packet->SequenceNumber()); |
149 | |
150 bool RTPPacketHistory::SetSent(uint16_t sequence_number) { | |
151 rtc::CritScope cs(&critsect_); | |
152 if (!store_) { | |
153 return false; | |
154 } | |
155 | |
156 int32_t index = 0; | |
157 bool found = FindSeqNum(sequence_number, &index); | |
158 if (!found) { | |
159 return false; | |
160 } | |
161 | |
162 // Send time already set. | |
163 if (stored_packets_[index].send_time != 0) { | |
164 return false; | |
165 } | |
166 | |
167 stored_packets_[index].send_time = clock_->TimeInMilliseconds(); | |
168 return true; | |
169 } | |
170 | |
171 bool RTPPacketHistory::GetPacketAndSetSendTime(uint16_t sequence_number, | |
172 int64_t min_elapsed_time_ms, | |
173 bool retransmit, | |
174 uint8_t* packet, | |
175 size_t* packet_length, | |
176 int64_t* stored_time_ms) { | |
177 rtc::CritScope cs(&critsect_); | |
178 RTC_CHECK_GE(*packet_length, static_cast<size_t>(IP_PACKET_SIZE)); | |
179 if (!store_) | |
180 return false; | |
181 | |
182 int32_t index = 0; | |
183 bool found = FindSeqNum(sequence_number, &index); | |
184 if (!found) { | |
185 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number; | |
186 return false; | |
187 } | |
188 | |
189 size_t length = stored_packets_[index].length; | |
190 assert(length <= IP_PACKET_SIZE); | |
191 if (length == 0) { | |
192 LOG(LS_WARNING) << "No match for getting seqNum " << sequence_number | |
193 << ", len " << length; | |
194 return false; | |
195 } | |
196 | 138 |
197 // Verify elapsed time since last retrieve, but only for retransmissions and | 139 // Verify elapsed time since last retrieve, but only for retransmissions and |
198 // always send packet upon first retransmission request. | 140 // always send packet upon first retransmission request. |
199 int64_t now = clock_->TimeInMilliseconds(); | 141 int64_t now = clock_->TimeInMilliseconds(); |
200 if (min_elapsed_time_ms > 0 && retransmit && | 142 if (min_elapsed_time_ms > 0 && retransmit && |
201 stored_packets_[index].has_been_retransmitted && | 143 stored_packets_[index].has_been_retransmitted && |
202 ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) { | 144 ((now - stored_packets_[index].send_time) < min_elapsed_time_ms)) { |
203 return false; | 145 return nullptr; |
204 } | 146 } |
205 | 147 |
206 if (retransmit) { | 148 if (retransmit) { |
207 if (stored_packets_[index].storage_type == kDontRetransmit) { | 149 if (stored_packets_[index].storage_type == kDontRetransmit) { |
208 // No bytes copied since this packet shouldn't be retransmitted or is | 150 // No bytes copied since this packet shouldn't be retransmitted. |
209 // of zero size. | 151 return nullptr; |
210 return false; | |
211 } | 152 } |
212 stored_packets_[index].has_been_retransmitted = true; | 153 stored_packets_[index].has_been_retransmitted = true; |
213 } | 154 } |
214 stored_packets_[index].send_time = clock_->TimeInMilliseconds(); | 155 stored_packets_[index].send_time = clock_->TimeInMilliseconds(); |
215 GetPacket(index, packet, packet_length, stored_time_ms); | 156 return GetPacket(index); |
216 return true; | |
217 } | 157 } |
218 | 158 |
219 void RTPPacketHistory::GetPacket(int index, | 159 std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetPacket(int index) { |
stefan-webrtc
2016/05/09 11:49:23
Should this be called something like GetPacketCopy
danilchap
2016/05/09 13:45:22
While this function creates new RtpPacketToSend an
stefan-webrtc
2016/05/12 12:22:34
Ah, I see. Looks good then.
| |
220 uint8_t* packet, | 160 const RtpPacketToSend& stored = *stored_packets_[index].packet; |
221 size_t* packet_length, | 161 return std::unique_ptr<RtpPacketToSend>(new RtpPacketToSend(stored)); |
222 int64_t* stored_time_ms) const { | |
223 // Get packet. | |
224 size_t length = stored_packets_[index].length; | |
225 memcpy(packet, stored_packets_[index].data, length); | |
226 *packet_length = length; | |
227 *stored_time_ms = stored_packets_[index].time_ms; | |
228 } | 162 } |
229 | 163 |
230 bool RTPPacketHistory::GetBestFittingPacket(uint8_t* packet, | 164 std::unique_ptr<RtpPacketToSend> RtpPacketHistory::GetBestFittingPacket( |
231 size_t* packet_length, | 165 size_t packet_length) { |
232 int64_t* stored_time_ms) { | |
233 rtc::CritScope cs(&critsect_); | 166 rtc::CritScope cs(&critsect_); |
234 if (!store_) | 167 if (!store_) { |
235 return false; | 168 return nullptr; |
236 int index = FindBestFittingPacket(*packet_length); | 169 } |
237 if (index < 0) | 170 int index = FindBestFittingPacket(packet_length); |
238 return false; | 171 if (index < 0) { |
239 GetPacket(index, packet, packet_length, stored_time_ms); | 172 return nullptr; |
240 return true; | 173 } |
174 return GetPacket(index); | |
241 } | 175 } |
242 | 176 |
243 // private, lock should already be taken | 177 bool RtpPacketHistory::FindSeqNum(uint16_t sequence_number, int* index) const { |
244 bool RTPPacketHistory::FindSeqNum(uint16_t sequence_number, | |
245 int32_t* index) const { | |
246 uint16_t temp_sequence_number = 0; | |
247 if (prev_index_ > 0) { | 178 if (prev_index_ > 0) { |
248 *index = prev_index_ - 1; | 179 *index = prev_index_ - 1; |
249 temp_sequence_number = stored_packets_[*index].sequence_number; | |
250 } else { | 180 } else { |
251 *index = stored_packets_.size() - 1; | 181 *index = stored_packets_.size() - 1; // Wrap. |
252 temp_sequence_number = stored_packets_[*index].sequence_number; // wrap | |
253 } | 182 } |
183 uint16_t temp_sequence_number = stored_packets_[*index].sequence_number; | |
254 | 184 |
255 int32_t idx = (prev_index_ - 1) - (temp_sequence_number - sequence_number); | 185 int idx = *index - (temp_sequence_number - sequence_number); |
256 if (idx >= 0 && idx < static_cast<int>(stored_packets_.size())) { | 186 if (idx >= 0 && idx < static_cast<int>(stored_packets_.size())) { |
257 *index = idx; | 187 *index = idx; |
258 temp_sequence_number = stored_packets_[*index].sequence_number; | 188 temp_sequence_number = stored_packets_[*index].sequence_number; |
259 } | 189 } |
260 | 190 |
261 if (temp_sequence_number != sequence_number) { | 191 if (temp_sequence_number != sequence_number) { |
262 // We did not found a match, search all. | 192 // We did not found a match, search all. |
263 for (uint16_t m = 0; m < stored_packets_.size(); m++) { | 193 for (uint16_t m = 0; m < stored_packets_.size(); m++) { |
264 if (stored_packets_[m].sequence_number == sequence_number) { | 194 if (stored_packets_[m].sequence_number == sequence_number) { |
265 *index = m; | 195 *index = m; |
266 temp_sequence_number = stored_packets_[*index].sequence_number; | 196 temp_sequence_number = stored_packets_[*index].sequence_number; |
267 break; | 197 break; |
268 } | 198 } |
269 } | 199 } |
270 } | 200 } |
271 if (temp_sequence_number == sequence_number) { | 201 return (temp_sequence_number == sequence_number && |
272 // We found a match. | 202 stored_packets_[*index].packet); |
273 return true; | |
274 } | |
275 return false; | |
276 } | 203 } |
277 | 204 |
278 int RTPPacketHistory::FindBestFittingPacket(size_t size) const { | 205 int RtpPacketHistory::FindBestFittingPacket(size_t size) const { |
279 if (size < kMinPacketRequestBytes || stored_packets_.empty()) | 206 if (size < kMinPacketRequestBytes || stored_packets_.empty()) { |
280 return -1; | 207 return -1; |
208 } | |
281 size_t min_diff = std::numeric_limits<size_t>::max(); | 209 size_t min_diff = std::numeric_limits<size_t>::max(); |
282 int best_index = -1; // Returned unchanged if we don't find anything. | 210 int best_index = -1; // Returned unchanged if we don't find anything. |
283 for (size_t i = 0; i < stored_packets_.size(); ++i) { | 211 for (size_t i = 0; i < stored_packets_.size(); ++i) { |
284 if (stored_packets_[i].length == 0) | 212 if (!stored_packets_[i].packet) { |
285 continue; | 213 continue; |
286 size_t diff = (stored_packets_[i].length > size) | 214 } |
287 ? (stored_packets_[i].length - size) | 215 size_t stored_size = stored_packets_[i].packet->size(); |
288 : (size - stored_packets_[i].length); | 216 size_t diff = |
217 (stored_size > size) ? (stored_size - size) : (size - stored_size); | |
289 if (diff < min_diff) { | 218 if (diff < min_diff) { |
290 min_diff = diff; | 219 min_diff = diff; |
291 best_index = static_cast<int>(i); | 220 best_index = static_cast<int>(i); |
292 } | 221 } |
293 } | 222 } |
294 return best_index; | 223 return best_index; |
295 } | 224 } |
296 | 225 |
297 RTPPacketHistory::StoredPacket::StoredPacket() {} | |
298 | |
299 } // namespace webrtc | 226 } // namespace webrtc |
OLD | NEW |