diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-04-13 01:45:53 +0200 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-04-13 01:45:53 +0200 |
commit | 2465f486acd90ed8395c8a83a13af09ecd024c98 (patch) | |
tree | 4abe53d39eb07a45e5ed4d8894b7ae038e2bb705 /toxav/rtp.c | |
parent | b2d88a4544a81a217db18b60d91a44d85821db3d (diff) |
Started custom RTCP
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r-- | toxav/rtp.c | 589 |
1 files changed, 318 insertions, 271 deletions
diff --git a/toxav/rtp.c b/toxav/rtp.c index e5f45310..77fce056 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -28,9 +28,9 @@ | |||
28 | 28 | ||
29 | #include "rtp.h" | 29 | #include "rtp.h" |
30 | #include <stdlib.h> | 30 | #include <stdlib.h> |
31 | void queue_message(RTPSession *_session, RTPMessage *_msg); | ||
32 | 31 | ||
33 | #define size_32 4 | 32 | #define size_32 4 |
33 | #define RTCP_REPORT_INTERVAL_MS 500 | ||
34 | 34 | ||
35 | #define ADD_FLAG_VERSION(_h, _v) do { ( _h->flags ) &= 0x3F; ( _h->flags ) |= ( ( ( _v ) << 6 ) & 0xC0 ); } while(0) | 35 | #define ADD_FLAG_VERSION(_h, _v) do { ( _h->flags ) &= 0x3F; ( _h->flags ) |= ( ( ( _v ) << 6 ) & 0xC0 ); } while(0) |
36 | #define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) | 36 | #define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) |
@@ -46,24 +46,236 @@ void queue_message(RTPSession *_session, RTPMessage *_msg); | |||
46 | #define GET_SETTING_MARKER(_h) (( _h->marker_payloadt ) >> 7) | 46 | #define GET_SETTING_MARKER(_h) (( _h->marker_payloadt ) >> 7) |
47 | #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) | 47 | #define GET_SETTING_PAYLOAD(_h) ((_h->marker_payloadt) & 0x7f) |
48 | 48 | ||
49 | /** | 49 | |
50 | * Checks if message came in late. | 50 | typedef struct { |
51 | */ | 51 | uint64_t timestamp; /* in ms */ |
52 | static int check_late_message (RTPSession *session, RTPMessage *msg) | 52 | |
53 | uint32_t packets_missing; | ||
54 | uint32_t expected_packets; | ||
55 | /* ... other stuff in the future */ | ||
56 | } RTCPReport; | ||
57 | |||
58 | typedef struct RTCPSession_s { | ||
59 | uint8_t prefix; | ||
60 | uint64_t last_sent_report_ts; | ||
61 | uint32_t last_missing_packets; | ||
62 | uint32_t last_expected_packets; | ||
63 | |||
64 | RingBuffer* pl_stats; /* Packet loss stats over time */ | ||
65 | } RTCPSession; | ||
66 | |||
67 | |||
68 | |||
69 | /* queue_message() is defined in codec.c */ | ||
70 | void queue_message(RTPSession *session, RTPMessage *msg); | ||
71 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ); | ||
72 | RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ); | ||
73 | RTPMessage *msg_parse ( const uint8_t *data, int length ); | ||
74 | uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload ); | ||
75 | uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload ); | ||
76 | void build_header ( RTPSession* session, RTPHeader* header ); | ||
77 | void send_rtcp_report ( RTCPSession* session, Messenger* m, int32_t friendnumber ); | ||
78 | int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ); | ||
79 | int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ); | ||
80 | |||
81 | |||
82 | |||
83 | |||
84 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) | ||
53 | { | 85 | { |
54 | /* | 86 | RTPSession *retu = calloc(1, sizeof(RTPSession)); |
55 | * Check Sequence number. If this new msg has lesser number then the session->rsequnum | 87 | |
56 | * it shows that the message came in late. Also check timestamp to be 100% certain. | 88 | if ( !retu ) { |
57 | * | 89 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); |
58 | */ | 90 | return NULL; |
59 | return ( msg->header->sequnum < session->rsequnum && msg->header->timestamp < session->timestamp ) ? 0 : -1; | 91 | } |
92 | |||
93 | retu->version = RTP_VERSION; /* It's always 2 */ | ||
94 | retu->padding = 0; /* If some additional data is needed about the packet */ | ||
95 | retu->extension = 0; /* If extension to header is needed */ | ||
96 | retu->cc = 1; /* Amount of contributors */ | ||
97 | retu->csrc = NULL; /* Container */ | ||
98 | retu->ssrc = random_int(); | ||
99 | retu->marker = 0; | ||
100 | retu->payload_type = payload_type % 128; | ||
101 | |||
102 | retu->m = messenger; | ||
103 | retu->dest = friend_num; | ||
104 | retu->rsequnum = retu->sequnum = 0; | ||
105 | retu->ext_header = NULL; /* When needed allocate */ | ||
106 | |||
107 | if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) { | ||
108 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | ||
109 | free(retu); | ||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */ | ||
114 | |||
115 | /* Also set payload type as prefix */ | ||
116 | retu->prefix = payload_type; | ||
117 | |||
118 | |||
119 | /* Initialize rtcp session */ | ||
120 | if (!(retu->rtcp = calloc(1, sizeof(RTCPSession)))) { | ||
121 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | ||
122 | free(retu->csrc); | ||
123 | free(retu); | ||
124 | return NULL; | ||
125 | } | ||
126 | |||
127 | retu->rtcp->prefix = 222 + payload_type % 192; | ||
128 | retu->rtcp->pl_stats = rb_new(4); | ||
129 | |||
130 | return retu; | ||
60 | } | 131 | } |
132 | void rtp_kill ( RTPSession *session ) | ||
133 | { | ||
134 | if ( !session ) return; | ||
61 | 135 | ||
136 | rtp_stop_receiving (session); | ||
62 | 137 | ||
63 | /** | 138 | free ( session->ext_header ); |
64 | * Extracts header from payload. | 139 | free ( session->csrc ); |
65 | */ | 140 | |
66 | RTPHeader *extract_header ( const uint8_t *payload, int length ) | 141 | void* t; |
142 | while (!rb_empty(session->rtcp->pl_stats)) { | ||
143 | rb_read(session->rtcp->pl_stats, (void**) &t); | ||
144 | free(t); | ||
145 | } | ||
146 | rb_free(session->rtcp->pl_stats); | ||
147 | |||
148 | LOGGER_DEBUG("Terminated RTP session: %p", session); | ||
149 | |||
150 | /* And finally free session */ | ||
151 | free ( session ); | ||
152 | } | ||
153 | void rtp_do(RTPSession *session) | ||
154 | { | ||
155 | if (!session || !session->rtcp) | ||
156 | return; | ||
157 | |||
158 | if (current_time_monotonic() - session->rtcp->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) { | ||
159 | send_rtcp_report(session->rtcp, session->m, session->dest); | ||
160 | } | ||
161 | |||
162 | if (rb_full(session->rtcp->pl_stats)) { | ||
163 | RTCPReport* reports[4]; | ||
164 | |||
165 | int i = 0; | ||
166 | for (; rb_read(session->rtcp->pl_stats, (void**) reports + i); i++); | ||
167 | |||
168 | /* Check for timed out reports (> 6 sec) */ | ||
169 | uint64_t now = current_time_monotonic(); | ||
170 | for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++); | ||
171 | for (; i < 4; i ++) { | ||
172 | rb_write(session->rtcp->pl_stats, reports[i]); | ||
173 | reports[i] = NULL; | ||
174 | } | ||
175 | if (!rb_empty(session->rtcp->pl_stats)) { | ||
176 | for (i = 0; reports[i] != NULL; i ++) | ||
177 | free(reports[i]); | ||
178 | return; /* As some reports are timed out, we need more... */ | ||
179 | } | ||
180 | |||
181 | /* We have 4 on-time reports so we can proceed */ | ||
182 | uint32_t quality_loss = 0; | ||
183 | for (i = 0; i < 4; i++) { | ||
184 | uint32_t idx = reports[i]->packets_missing * 100 / reports[i]->expected_packets; | ||
185 | quality_loss += idx; | ||
186 | } | ||
187 | |||
188 | if (quality_loss > 40) { | ||
189 | LOGGER_DEBUG("Packet loss detected"); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | int rtp_start_receiving(RTPSession* session) | ||
194 | { | ||
195 | if (session == NULL) | ||
196 | return -1; | ||
197 | |||
198 | if (custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, | ||
199 | handle_rtp_packet, session) == -1) { | ||
200 | LOGGER_WARNING("Failed to register rtp receive handler"); | ||
201 | return -1; | ||
202 | } | ||
203 | if (custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp->prefix, | ||
204 | handle_rtcp_packet, session->rtcp) == -1) { | ||
205 | LOGGER_WARNING("Failed to register rtcp receive handler"); | ||
206 | custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL); | ||
207 | return -1; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | int rtp_stop_receiving(RTPSession* session) | ||
213 | { | ||
214 | if (session == NULL) | ||
215 | return -1; | ||
216 | |||
217 | custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL); | ||
218 | custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp->prefix, NULL, NULL); /* RTCP */ | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) | ||
223 | { | ||
224 | if ( !session ) { | ||
225 | LOGGER_WARNING("No session!"); | ||
226 | return -1; | ||
227 | } | ||
228 | |||
229 | uint8_t parsed[MAX_RTP_SIZE]; | ||
230 | uint8_t *it; | ||
231 | |||
232 | RTPHeader header[1]; | ||
233 | build_header(session, header); | ||
234 | |||
235 | uint32_t parsed_len = length + header->length + 1; | ||
236 | |||
237 | parsed[0] = session->prefix; | ||
238 | |||
239 | it = parse_header_out ( header, parsed + 1 ); | ||
240 | |||
241 | if ( session->ext_header ) { | ||
242 | parsed_len += ( 4 /* Minimum ext header len */ + session->ext_header->length * size_32 ); | ||
243 | it = parse_ext_header_out ( session->ext_header, it ); | ||
244 | } | ||
245 | |||
246 | memcpy ( it, data, length ); | ||
247 | |||
248 | if ( -1 == send_custom_lossy_packet(session->m, session->dest, parsed, parsed_len) ) { | ||
249 | LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); | ||
250 | return -1; | ||
251 | } | ||
252 | |||
253 | /* Set sequ number */ | ||
254 | session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1; | ||
255 | return 0; | ||
256 | } | ||
257 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) | ||
258 | { | ||
259 | if ( !session ) { | ||
260 | if ( msg->ext_header ) { | ||
261 | free ( msg->ext_header->table ); | ||
262 | free ( msg->ext_header ); | ||
263 | } | ||
264 | } else { | ||
265 | if ( msg->ext_header && session->ext_header != msg->ext_header ) { | ||
266 | free ( msg->ext_header->table ); | ||
267 | free ( msg->ext_header ); | ||
268 | } | ||
269 | } | ||
270 | |||
271 | free ( msg->header ); | ||
272 | free ( msg ); | ||
273 | } | ||
274 | |||
275 | |||
276 | |||
277 | |||
278 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ) | ||
67 | { | 279 | { |
68 | if ( !payload || !length ) { | 280 | if ( !payload || !length ) { |
69 | LOGGER_WARNING("No payload to extract!"); | 281 | LOGGER_WARNING("No payload to extract!"); |
@@ -111,8 +323,6 @@ RTPHeader *extract_header ( const uint8_t *payload, int length ) | |||
111 | return NULL; | 323 | return NULL; |
112 | } | 324 | } |
113 | 325 | ||
114 | memset(retu->csrc, 0, 16 * sizeof (uint32_t)); | ||
115 | |||
116 | retu->marker_payloadt = *it; | 326 | retu->marker_payloadt = *it; |
117 | ++it; | 327 | ++it; |
118 | retu->length = total; | 328 | retu->length = total; |
@@ -125,7 +335,6 @@ RTPHeader *extract_header ( const uint8_t *payload, int length ) | |||
125 | retu->ssrc = ntohl(retu->ssrc); | 335 | retu->ssrc = ntohl(retu->ssrc); |
126 | 336 | ||
127 | uint8_t x; | 337 | uint8_t x; |
128 | |||
129 | for ( x = 0; x < cc; x++ ) { | 338 | for ( x = 0; x < cc; x++ ) { |
130 | it += 4; | 339 | it += 4; |
131 | memcpy(&retu->csrc[x], it, sizeof(retu->csrc[x])); | 340 | memcpy(&retu->csrc[x], it, sizeof(retu->csrc[x])); |
@@ -134,11 +343,7 @@ RTPHeader *extract_header ( const uint8_t *payload, int length ) | |||
134 | 343 | ||
135 | return retu; | 344 | return retu; |
136 | } | 345 | } |
137 | 346 | RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ) | |
138 | /** | ||
139 | * Extracts external header from payload. Must be called AFTER extract_header()! | ||
140 | */ | ||
141 | RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) | ||
142 | { | 347 | { |
143 | const uint8_t *it = payload; | 348 | const uint8_t *it = payload; |
144 | 349 | ||
@@ -182,11 +387,47 @@ RTPExtHeader *extract_ext_header ( const uint8_t *payload, uint16_t length ) | |||
182 | 387 | ||
183 | return retu; | 388 | return retu; |
184 | } | 389 | } |
390 | RTPMessage *msg_parse ( const uint8_t *data, int length ) | ||
391 | { | ||
392 | RTPMessage *retu = calloc(1, sizeof (RTPMessage)); | ||
185 | 393 | ||
186 | /** | 394 | retu->header = parse_header_in ( data, length ); /* It allocates memory and all */ |
187 | * Adds header to payload. Make sure _payload_ has enough space. | 395 | |
188 | */ | 396 | if ( !retu->header ) { |
189 | uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) | 397 | LOGGER_WARNING("Header failed to extract!"); |
398 | free(retu); | ||
399 | return NULL; | ||
400 | } | ||
401 | |||
402 | uint16_t from_pos = retu->header->length; | ||
403 | retu->length = length - from_pos; | ||
404 | |||
405 | if ( GET_FLAG_EXTENSION ( retu->header ) ) { | ||
406 | retu->ext_header = parse_ext_header_in ( data + from_pos, length ); | ||
407 | |||
408 | if ( retu->ext_header ) { | ||
409 | retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); | ||
410 | from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); | ||
411 | } else { /* Error */ | ||
412 | LOGGER_WARNING("Ext Header failed to extract!"); | ||
413 | rtp_free_msg(NULL, retu); | ||
414 | return NULL; | ||
415 | } | ||
416 | } else { | ||
417 | retu->ext_header = NULL; | ||
418 | } | ||
419 | |||
420 | if ( length - from_pos <= MAX_RTP_SIZE ) | ||
421 | memcpy ( retu->data, data + from_pos, length - from_pos ); | ||
422 | else { | ||
423 | LOGGER_WARNING("Invalid length!"); | ||
424 | rtp_free_msg(NULL, retu); | ||
425 | return NULL; | ||
426 | } | ||
427 | |||
428 | return retu; | ||
429 | } | ||
430 | uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload ) | ||
190 | { | 431 | { |
191 | uint8_t cc = GET_FLAG_CSRCC ( header ); | 432 | uint8_t cc = GET_FLAG_CSRCC ( header ); |
192 | uint8_t *it = payload; | 433 | uint8_t *it = payload; |
@@ -223,11 +464,7 @@ uint8_t *add_header ( RTPHeader *header, uint8_t *payload ) | |||
223 | 464 | ||
224 | return it + 4; | 465 | return it + 4; |
225 | } | 466 | } |
226 | 467 | uint8_t *parse_ext_header_out ( const RTPExtHeader *header, uint8_t *payload ) | |
227 | /** | ||
228 | * Adds extension header to payload. Make sure _payload_ has enough space. | ||
229 | */ | ||
230 | uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) | ||
231 | { | 468 | { |
232 | uint8_t *it = payload; | 469 | uint8_t *it = payload; |
233 | uint16_t length; | 470 | uint16_t length; |
@@ -242,9 +479,7 @@ uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) | |||
242 | it -= 2; /* Return to 0 position */ | 479 | it -= 2; /* Return to 0 position */ |
243 | 480 | ||
244 | if ( header->table ) { | 481 | if ( header->table ) { |
245 | |||
246 | uint16_t x; | 482 | uint16_t x; |
247 | |||
248 | for ( x = 0; x < header->length; x++ ) { | 483 | for ( x = 0; x < header->length; x++ ) { |
249 | it += 4; | 484 | it += 4; |
250 | entry = htonl(header->table[x]); | 485 | entry = htonl(header->table[x]); |
@@ -254,92 +489,45 @@ uint8_t *add_ext_header ( RTPExtHeader *header, uint8_t *payload ) | |||
254 | 489 | ||
255 | return it + 4; | 490 | return it + 4; |
256 | } | 491 | } |
257 | 492 | void build_header ( RTPSession *session, RTPHeader *header ) | |
258 | /** | ||
259 | * Builds header from control session values. | ||
260 | */ | ||
261 | RTPHeader *build_header ( RTPSession *session ) | ||
262 | { | 493 | { |
263 | RTPHeader *retu = calloc ( 1, sizeof (RTPHeader) ); | 494 | ADD_FLAG_VERSION ( header, session->version ); |
264 | 495 | ADD_FLAG_PADDING ( header, session->padding ); | |
265 | if ( !retu ) { | 496 | ADD_FLAG_EXTENSION ( header, session->extension ); |
266 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | 497 | ADD_FLAG_CSRCC ( header, session->cc ); |
267 | return NULL; | 498 | ADD_SETTING_MARKER ( header, session->marker ); |
268 | } | 499 | ADD_SETTING_PAYLOAD ( header, session->payload_type ); |
269 | |||
270 | ADD_FLAG_VERSION ( retu, session->version ); | ||
271 | ADD_FLAG_PADDING ( retu, session->padding ); | ||
272 | ADD_FLAG_EXTENSION ( retu, session->extension ); | ||
273 | ADD_FLAG_CSRCC ( retu, session->cc ); | ||
274 | ADD_SETTING_MARKER ( retu, session->marker ); | ||
275 | ADD_SETTING_PAYLOAD ( retu, session->payload_type ); | ||
276 | 500 | ||
277 | retu->sequnum = session->sequnum; | 501 | header->sequnum = session->sequnum; |
278 | retu->timestamp = current_time_monotonic(); /* milliseconds */ | 502 | header->timestamp = current_time_monotonic(); /* milliseconds */ |
279 | retu->ssrc = session->ssrc; | 503 | header->ssrc = session->ssrc; |
280 | 504 | ||
281 | int i; | 505 | int i; |
282 | |||
283 | for ( i = 0; i < session->cc; i++ ) | 506 | for ( i = 0; i < session->cc; i++ ) |
284 | retu->csrc[i] = session->csrc[i]; | 507 | header->csrc[i] = session->csrc[i]; |
285 | |||
286 | retu->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); | ||
287 | 508 | ||
288 | return retu; | 509 | header->length = 12 /* Minimum header len */ + ( session->cc * size_32 ); |
289 | } | 510 | } |
290 | 511 | void send_rtcp_report(RTCPSession* session, Messenger* m, int32_t friendnumber) | |
291 | |||
292 | /** | ||
293 | * Parses data into RTPMessage struct. Stores headers separately from the payload data | ||
294 | * and so the length variable is set accordingly. | ||
295 | */ | ||
296 | RTPMessage *msg_parse ( const uint8_t *data, int length ) | ||
297 | { | 512 | { |
298 | RTPMessage *retu = calloc(1, sizeof (RTPMessage)); | 513 | if (session->last_expected_packets == 0) |
299 | 514 | return; | |
300 | retu->header = extract_header ( data, length ); /* It allocates memory and all */ | 515 | |
301 | 516 | uint8_t parsed[9]; | |
302 | if ( !retu->header ) { | 517 | parsed[0] = session->prefix; |
303 | LOGGER_WARNING("Header failed to extract!"); | 518 | |
304 | free(retu); | 519 | uint32_t packets_missing = htonl(session->last_missing_packets); |
305 | return NULL; | 520 | uint32_t expected_packets = htonl(session->last_expected_packets); |
306 | } | 521 | |
307 | 522 | memcpy(parsed + 1, &packets_missing, 4); | |
308 | uint16_t from_pos = retu->header->length; | 523 | memcpy(parsed + 5, &expected_packets, 4); |
309 | retu->length = length - from_pos; | 524 | |
310 | 525 | if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed))) | |
311 | 526 | LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno)); | |
312 | 527 | else | |
313 | if ( GET_FLAG_EXTENSION ( retu->header ) ) { | 528 | session->last_sent_report_ts = current_time_monotonic(); |
314 | retu->ext_header = extract_ext_header ( data + from_pos, length ); | ||
315 | |||
316 | if ( retu->ext_header ) { | ||
317 | retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); | ||
318 | from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); | ||
319 | } else { /* Error */ | ||
320 | LOGGER_WARNING("Ext Header failed to extract!"); | ||
321 | rtp_free_msg(NULL, retu); | ||
322 | return NULL; | ||
323 | } | ||
324 | } else { | ||
325 | retu->ext_header = NULL; | ||
326 | } | ||
327 | |||
328 | if ( length - from_pos <= MAX_RTP_SIZE ) | ||
329 | memcpy ( retu->data, data + from_pos, length - from_pos ); | ||
330 | else { | ||
331 | LOGGER_WARNING("Invalid length!"); | ||
332 | rtp_free_msg(NULL, retu); | ||
333 | return NULL; | ||
334 | } | ||
335 | |||
336 | return retu; | ||
337 | } | 529 | } |
338 | 530 | int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) | |
339 | /** | ||
340 | * Callback for networking core. | ||
341 | */ | ||
342 | int rtp_handle_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) | ||
343 | { | 531 | { |
344 | RTPSession *session = object; | 532 | RTPSession *session = object; |
345 | RTPMessage *msg; | 533 | RTPMessage *msg; |
@@ -357,178 +545,37 @@ int rtp_handle_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, | |||
357 | } | 545 | } |
358 | 546 | ||
359 | /* Check if message came in late */ | 547 | /* Check if message came in late */ |
360 | if ( check_late_message(session, msg) < 0 ) { /* Not late */ | 548 | if ( msg->header->sequnum > session->rsequnum && msg->header->timestamp > session->rtimestamp ) { |
549 | /* Not late */ | ||
361 | session->rsequnum = msg->header->sequnum; | 550 | session->rsequnum = msg->header->sequnum; |
362 | session->timestamp = msg->header->timestamp; | 551 | session->rtimestamp = msg->header->timestamp; |
363 | } | 552 | } |
364 | 553 | ||
365 | queue_message(session, msg); | 554 | queue_message(session, msg); |
366 | return 0; | 555 | return 0; |
367 | } | 556 | } |
368 | 557 | int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) | |
369 | /** | ||
370 | * Allocate message and store data there | ||
371 | */ | ||
372 | RTPMessage *rtp_new_message ( RTPSession *session, const uint8_t *data, uint32_t length ) | ||
373 | { | 558 | { |
374 | if ( !session ) { | 559 | if (length < 9) |
375 | LOGGER_WARNING("No session!"); | 560 | return -1; |
376 | return NULL; | ||
377 | } | ||
378 | |||
379 | uint8_t *from_pos; | ||
380 | RTPMessage *retu = calloc(1, sizeof (RTPMessage)); | ||
381 | |||
382 | if ( !retu ) { | ||
383 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | ||
384 | return NULL; | ||
385 | } | ||
386 | |||
387 | /* Sets header values and copies the extension header in retu */ | ||
388 | retu->header = build_header ( session ); /* It allocates memory and all */ | ||
389 | retu->ext_header = session->ext_header; | ||
390 | |||
391 | |||
392 | uint32_t total_length = length + retu->header->length + 1; | ||
393 | |||
394 | retu->data[0] = session->prefix; | ||
395 | |||
396 | if ( retu->ext_header ) { | ||
397 | total_length += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 ); | ||
398 | |||
399 | from_pos = add_header ( retu->header, retu->data + 1 ); | ||
400 | from_pos = add_ext_header ( retu->ext_header, from_pos + 1 ); | ||
401 | } else { | ||
402 | from_pos = add_header ( retu->header, retu->data + 1 ); | ||
403 | } | ||
404 | |||
405 | /* | ||
406 | * Parses the extension header into the message | ||
407 | * Of course if any | ||
408 | */ | ||
409 | |||
410 | /* Appends data on to retu->data */ | ||
411 | memcpy ( from_pos, data, length ); | ||
412 | |||
413 | retu->length = total_length; | ||
414 | |||
415 | return retu; | ||
416 | } | ||
417 | |||
418 | |||
419 | |||
420 | RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) | ||
421 | { | ||
422 | RTPSession *retu = calloc(1, sizeof(RTPSession)); | ||
423 | |||
424 | if ( !retu ) { | ||
425 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | ||
426 | return NULL; | ||
427 | } | ||
428 | |||
429 | retu->version = RTP_VERSION; /* It's always 2 */ | ||
430 | retu->padding = 0; /* If some additional data is needed about the packet */ | ||
431 | retu->extension = 0; /* If extension to header is needed */ | ||
432 | retu->cc = 1; /* Amount of contributors */ | ||
433 | retu->csrc = NULL; /* Container */ | ||
434 | retu->ssrc = random_int(); | ||
435 | retu->marker = 0; | ||
436 | retu->payload_type = payload_type % 128; | ||
437 | |||
438 | retu->dest = friend_num; | ||
439 | |||
440 | retu->rsequnum = retu->sequnum = 0; | ||
441 | |||
442 | retu->ext_header = NULL; /* When needed allocate */ | ||
443 | |||
444 | |||
445 | if ( !(retu->csrc = calloc(1, sizeof (uint32_t))) ) { | ||
446 | LOGGER_WARNING("Alloc failed! Program might misbehave!"); | ||
447 | free(retu); | ||
448 | return NULL; | ||
449 | } | ||
450 | |||
451 | retu->csrc[0] = retu->ssrc; /* Set my ssrc to the list receive */ | ||
452 | |||
453 | /* Also set payload type as prefix */ | ||
454 | retu->prefix = payload_type; | ||
455 | |||
456 | retu->m = messenger; | ||
457 | /* | ||
458 | * | ||
459 | */ | ||
460 | return retu; | ||
461 | } | ||
462 | |||
463 | void rtp_kill ( RTPSession *session ) | ||
464 | { | ||
465 | if ( !session ) return; | ||
466 | |||
467 | rtp_stop_receiving (session); | ||
468 | |||
469 | free ( session->ext_header ); | ||
470 | free ( session->csrc ); | ||
471 | |||
472 | LOGGER_DEBUG("Terminated RTP session: %p", session); | ||
473 | |||
474 | /* And finally free session */ | ||
475 | free ( session ); | ||
476 | } | ||
477 | |||
478 | int rtp_start_receiving(RTPSession* session) | ||
479 | { | ||
480 | if (session == NULL) | ||
481 | return 0; | ||
482 | 561 | ||
483 | LOGGER_DEBUG("Registering packet handler: pt: %d; friend: %d", session->prefix, session->dest); | 562 | RTCPSession* session = object; |
484 | return custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, | 563 | RTCPReport* report = malloc(sizeof(RTCPReport)); |
485 | rtp_handle_packet, session); | ||
486 | } | ||
487 | |||
488 | int rtp_stop_receiving(RTPSession* session) | ||
489 | { | ||
490 | if (session == NULL) | ||
491 | return 0; | ||
492 | 564 | ||
493 | LOGGER_DEBUG("Unregistering packet handler: pt: %d; friend: %d", session->prefix, session->dest); | 565 | memcpy(&report->packets_missing, data + 1, 4); |
494 | return custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, | 566 | memcpy(&report->expected_packets, data + 5, 4); |
495 | NULL, NULL); | ||
496 | } | ||
497 | |||
498 | int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) | ||
499 | { | ||
500 | RTPMessage *msg = rtp_new_message (session, data, length); | ||
501 | 567 | ||
502 | if ( !msg ) return -1; | 568 | report->packets_missing = ntohl(report->packets_missing); |
569 | report->expected_packets = ntohl(report->expected_packets); | ||
503 | 570 | ||
504 | if ( -1 == send_custom_lossy_packet(session->m, session->dest, msg->data, msg->length) ) { | 571 | /* This would cause undefined behaviour */ |
505 | LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); | 572 | if (report->expected_packets == 0) { |
506 | rtp_free_msg ( session, msg ); | 573 | free(report); |
507 | return -1; | 574 | return 0; |
508 | } | 575 | } |
509 | 576 | ||
577 | report->timestamp = current_time_monotonic(); | ||
510 | 578 | ||
511 | /* Set sequ number */ | 579 | free(rb_write(session->pl_stats, report)); |
512 | session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1; | ||
513 | rtp_free_msg ( session, msg ); | ||
514 | |||
515 | return 0; | 580 | return 0; |
516 | } | 581 | } \ No newline at end of file |
517 | |||
518 | void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) | ||
519 | { | ||
520 | if ( !session ) { | ||
521 | if ( msg->ext_header ) { | ||
522 | free ( msg->ext_header->table ); | ||
523 | free ( msg->ext_header ); | ||
524 | } | ||
525 | } else { | ||
526 | if ( msg->ext_header && session->ext_header != msg->ext_header ) { | ||
527 | free ( msg->ext_header->table ); | ||
528 | free ( msg->ext_header ); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | free ( msg->header ); | ||
533 | free ( msg ); | ||
534 | } | ||