summaryrefslogtreecommitdiff
path: root/toxav/rtp.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-04-26 00:31:03 +0200
committermannol <eniz_vukovic@hotmail.com>2015-04-26 00:31:03 +0200
commit144fc94d6987c8c6f74d8024af5a5c1738fe4678 (patch)
treebc5ad70ea24dafb8e358911ba118fc599f3f9999 /toxav/rtp.c
parent1bfd93e64a2a6d3bf9c90a9aa89abd29f3d826a7 (diff)
Almost done
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r--toxav/rtp.c276
1 files changed, 144 insertions, 132 deletions
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 9657da67..a48eba20 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -29,6 +29,7 @@
29 29
30#include "rtp.h" 30#include "rtp.h"
31#include <stdlib.h> 31#include <stdlib.h>
32#include <assert.h>
32 33
33#define size_32 4 34#define size_32 4
34#define RTCP_REPORT_INTERVAL_MS 500 35#define RTCP_REPORT_INTERVAL_MS 500
@@ -37,8 +38,8 @@
37#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0) 38#define ADD_FLAG_PADDING(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xDF; ( _h->flags ) |= ( ( ( _v ) << 5 ) & 0x20 ); } while(0)
38#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0) 39#define ADD_FLAG_EXTENSION(_h, _v) do { if ( _v > 0 ) _v = 1; ( _h->flags ) &= 0xEF;( _h->flags ) |= ( ( ( _v ) << 4 ) & 0x10 ); } while(0)
39#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0) 40#define ADD_FLAG_CSRCC(_h, _v) do { ( _h->flags ) &= 0xF0; ( _h->flags ) |= ( ( _v ) & 0x0F ); } while(0)
40#define ADD_SETTING_MARKER(_h, _v) do { if ( _v > 1 ) _v = 1; ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0) 41#define ADD_SETTING_MARKER(_h, _v) do { ( _h->marker_payloadt ) &= 0x7F; ( _h->marker_payloadt ) |= ( ( ( _v ) << 7 ) /*& 0x80 */ ); } while(0)
41#define ADD_SETTING_PAYLOAD(_h, _v) do { if ( _v > 127 ) _v = 127; ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0) 42#define ADD_SETTING_PAYLOAD(_h, _v) do { ( _h->marker_payloadt ) &= 0x80; ( _h->marker_payloadt ) |= ( ( _v ) /* & 0x7F */ ); } while(0)
42 43
43#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6) 44#define GET_FLAG_VERSION(_h) (( _h->flags & 0xd0 ) >> 6)
44#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5) 45#define GET_FLAG_PADDING(_h) (( _h->flags & 0x20 ) >> 5)
@@ -70,17 +71,19 @@ typedef struct RTCPSession_s {
70 71
71RTPHeader *parse_header_in ( const uint8_t *payload, int length ); 72RTPHeader *parse_header_in ( const uint8_t *payload, int length );
72RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length ); 73RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length );
73RTPMessage *msg_parse ( const uint8_t *data, int length );
74uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload ); 74uint8_t *parse_header_out ( const RTPHeader* header, uint8_t* payload );
75uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload ); 75uint8_t *parse_ext_header_out ( const RTPExtHeader* header, uint8_t* payload );
76void build_header ( RTPSession* session, RTPHeader* header );
77void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
78int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); 76int handle_rtp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
79int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object ); 77int handle_rtcp_packet ( Messenger *m, uint32_t friendnumber, const uint8_t *data, uint16_t length, void *object );
78void send_rtcp_report ( RTCPSession* session, Messenger* m, uint32_t friendnumber );
80 79
81 80
82RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num ) 81RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num, void* cs, int (*mcb) (void*, RTPMessage*) )
83{ 82{
83 assert(mcb);
84 assert(cs);
85 assert(messenger);
86
84 RTPSession *retu = calloc(1, sizeof(RTPSession)); 87 RTPSession *retu = calloc(1, sizeof(RTPSession));
85 88
86 if ( !retu ) { 89 if ( !retu ) {
@@ -107,6 +110,8 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
107 /* Also set payload type as prefix */ 110 /* Also set payload type as prefix */
108 retu->prefix = payload_type; 111 retu->prefix = payload_type;
109 112
113 retu->cs = cs;
114 retu->mcb = mcb;
110 115
111 /* Initialize rtcp session */ 116 /* Initialize rtcp session */
112 if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) { 117 if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) {
@@ -120,6 +125,14 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
120 retu->rtcp_session->pl_stats = rb_new(4); 125 retu->rtcp_session->pl_stats = rb_new(4);
121 retu->rtcp_session->rtp_session = retu; 126 retu->rtcp_session->rtp_session = retu;
122 127
128 if (-1 == rtp_start_receiving(retu)) {
129 LOGGER_WARNING("Failed to start rtp receiving mode");
130 free(retu->rtcp_session);
131 free(retu->csrc);
132 free(retu);
133 return NULL;
134 }
135
123 return retu; 136 return retu;
124} 137}
125void rtp_kill ( RTPSession *session ) 138void rtp_kill ( RTPSession *session )
@@ -156,11 +169,12 @@ void rtp_do(RTPSession *session)
156 RTCPReport* reports[4]; 169 RTCPReport* reports[4];
157 170
158 int i = 0; 171 int i = 0;
159 for (; rb_read(session->rtcp_session->pl_stats, (void**) reports + i); i++); 172 for (; i < 4; i++)
173 rb_read(session->rtcp_session->pl_stats, (void**) reports + i);
160 174
161 /* Check for timed out reports (> 6 sec) */ 175 /* Check for timed out reports (> 6 sec) */
162 uint64_t now = current_time_monotonic(); 176 uint64_t now = current_time_monotonic();
163 for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++); 177 for (i = 0; i < 4 && (now - reports[i]->timestamp) < 6000; i ++);
164 for (; i < 4; i ++) { 178 for (; i < 4; i ++) {
165 rb_write(session->rtcp_session->pl_stats, reports[i]); 179 rb_write(session->rtcp_session->pl_stats, reports[i]);
166 reports[i] = NULL; 180 reports[i] = NULL;
@@ -168,18 +182,18 @@ void rtp_do(RTPSession *session)
168 if (!rb_empty(session->rtcp_session->pl_stats)) { 182 if (!rb_empty(session->rtcp_session->pl_stats)) {
169 for (i = 0; reports[i] != NULL; i ++) 183 for (i = 0; reports[i] != NULL; i ++)
170 free(reports[i]); 184 free(reports[i]);
171 return; /* As some reports are timed out, we need more... */ 185 return; /* As some reports are timed out, we need more */
172 } 186 }
173 187
174 /* We have 4 on-time reports so we can proceed */ 188 /* We have 4 on-time reports so we can proceed */
175 uint32_t quality = 100; 189 uint32_t quality = 100;
176 for (i = 0; i < 4; i++) { 190 for (i = 0; i < 4; i++) {
177 uint32_t idx = reports[i]->received_packets * 100 / reports[i]->expected_packets; 191 uint32_t current = reports[i]->received_packets * 100 / reports[i]->expected_packets;
178 quality = MIN(quality, idx); 192 quality = MIN(quality, current);
179 free(reports[i]); 193 free(reports[i]);
180 } 194 }
181 195
182 if (quality <= 70) { 196 if (quality <= 90) {
183 session->tstate = rtp_StateBad; 197 session->tstate = rtp_StateBad;
184 LOGGER_WARNING("Stream quality: BAD"); 198 LOGGER_WARNING("Stream quality: BAD");
185 } else if (quality >= 99) { 199 } else if (quality >= 99) {
@@ -220,7 +234,7 @@ int rtp_stop_receiving(RTPSession* session)
220 234
221 return 0; 235 return 0;
222} 236}
223int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length ) 237int rtp_send_data ( RTPSession *session, const uint8_t *data, uint16_t length, bool dummy )
224{ 238{
225 if ( !session ) { 239 if ( !session ) {
226 LOGGER_WARNING("No session!"); 240 LOGGER_WARNING("No session!");
@@ -231,12 +245,31 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
231 uint8_t *it; 245 uint8_t *it;
232 246
233 RTPHeader header[1]; 247 RTPHeader header[1];
234 build_header(session, header); 248 ADD_FLAG_VERSION ( header, session->version );
249 ADD_FLAG_PADDING ( header, session->padding );
250 ADD_FLAG_EXTENSION ( header, session->extension );
251 ADD_FLAG_CSRCC ( header, session->cc );
252 ADD_SETTING_MARKER ( header, session->marker );
253
254 if (dummy)
255 ADD_SETTING_PAYLOAD ( header, (session->payload_type + 2) % 128 );
256 else
257 ADD_SETTING_PAYLOAD ( header, session->payload_type );
235 258
259 header->sequnum = session->sequnum;
260 header->timestamp = current_time_monotonic();
261 header->ssrc = session->ssrc;
262
263 int i;
264 for ( i = 0; i < session->cc; i++ )
265 header->csrc[i] = session->csrc[i];
266
267 header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
268
236 uint32_t parsed_len = length + header->length + 1; 269 uint32_t parsed_len = length + header->length + 1;
270 assert(parsed_len + (session->ext_header ? session->ext_header->length * size_32 : 0) > MAX_RTP_SIZE );
237 271
238 parsed[0] = session->prefix; 272 parsed[0] = session->prefix;
239
240 it = parse_header_out ( header, parsed + 1 ); 273 it = parse_header_out ( header, parsed + 1 );
241 274
242 if ( session->ext_header ) { 275 if ( session->ext_header ) {
@@ -244,8 +277,7 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
244 it = parse_ext_header_out ( session->ext_header, it ); 277 it = parse_ext_header_out ( session->ext_header, it );
245 } 278 }
246 279
247 memcpy ( it, data, length ); 280 memcpy(it, data, length);
248
249 281
250 if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) { 282 if ( -1 == send_custom_lossy_packet(session->m, session->friend_id, parsed, parsed_len) ) {
251 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno)); 283 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", length, strerror(errno));
@@ -256,18 +288,11 @@ int rtp_send_msg ( RTPSession *session, const uint8_t *data, uint16_t length )
256 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1; 288 session->sequnum = session->sequnum >= MAX_SEQU_NUM ? 0 : session->sequnum + 1;
257 return 0; 289 return 0;
258} 290}
259void rtp_free_msg ( RTPSession *session, RTPMessage *msg ) 291void rtp_free_msg ( RTPMessage *msg )
260{ 292{
261 if ( !session ) { 293 if ( msg->ext_header ) {
262 if ( msg->ext_header ) { 294 free ( msg->ext_header->table );
263 free ( msg->ext_header->table ); 295 free ( msg->ext_header );
264 free ( msg->ext_header );
265 }
266 } else {
267 if ( msg->ext_header && session->ext_header != msg->ext_header ) {
268 free ( msg->ext_header->table );
269 free ( msg->ext_header );
270 }
271 } 296 }
272 297
273 free ( msg->header ); 298 free ( msg->header );
@@ -389,50 +414,6 @@ RTPExtHeader *parse_ext_header_in ( const uint8_t *payload, uint16_t length )
389 414
390 return retu; 415 return retu;
391} 416}
392RTPMessage *msg_parse ( const uint8_t *data, int length )
393{
394 /* TODO: data dynamic, [0]
395 * TODO: dummy payload type
396 * TODO: parse header before allocating message
397 */
398 RTPMessage *retu = calloc(1, sizeof (RTPMessage));
399
400 retu->header = parse_header_in ( data, length ); /* It allocates memory and all */
401
402 if ( !retu->header ) {
403 LOGGER_WARNING("Header failed to extract!");
404 free(retu);
405 return NULL;
406 }
407
408 uint16_t from_pos = retu->header->length;
409 retu->length = length - from_pos;
410
411 if ( GET_FLAG_EXTENSION ( retu->header ) ) {
412 retu->ext_header = parse_ext_header_in ( data + from_pos, length );
413
414 if ( retu->ext_header ) {
415 retu->length -= ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
416 from_pos += ( 4 /* Minimum ext header len */ + retu->ext_header->length * size_32 );
417 } else { /* Error */
418 LOGGER_WARNING("Ext Header failed to extract!");
419 rtp_free_msg(NULL, retu);
420 return NULL;
421 }
422 } else {
423 retu->ext_header = NULL;
424 }
425
426 if ( length - from_pos <= MAX_RTP_SIZE )
427 memcpy ( retu->data, data + from_pos, length - from_pos );
428 else {
429 LOGGER_WARNING("Invalid length!");
430 rtp_free_msg(NULL, retu);
431 return NULL;
432 }
433
434 return retu;
435}
436uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload ) 417uint8_t *parse_header_out ( const RTPHeader *header, uint8_t *payload )
437{ 418{
438 uint8_t cc = GET_FLAG_CSRCC ( header ); 419 uint8_t cc = GET_FLAG_CSRCC ( header );
@@ -495,88 +476,95 @@ uint8_t *parse_ext_header_out ( const RTPExtHeader *header, uint8_t *payload )
495 476
496 return it + 4; 477 return it + 4;
497} 478}
498void build_header ( RTPSession *session, RTPHeader *header )
499{
500 ADD_FLAG_VERSION ( header, session->version );
501 ADD_FLAG_PADDING ( header, session->padding );
502 ADD_FLAG_EXTENSION ( header, session->extension );
503 ADD_FLAG_CSRCC ( header, session->cc );
504 ADD_SETTING_MARKER ( header, session->marker );
505 ADD_SETTING_PAYLOAD ( header, session->payload_type );
506
507 header->sequnum = session->sequnum;
508 header->timestamp = current_time_monotonic(); /* milliseconds */
509 header->ssrc = session->ssrc;
510
511 int i;
512 for ( i = 0; i < session->cc; i++ )
513 header->csrc[i] = session->csrc[i];
514
515 header->length = 12 /* Minimum header len */ + ( session->cc * size_32 );
516}
517void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
518{
519 if (session->last_expected_packets == 0)
520 return;
521
522 uint8_t parsed[9];
523 parsed[0] = session->prefix;
524
525 uint32_t received_packets = htonl(session->last_received_packets);
526 uint32_t expected_packets = htonl(session->last_expected_packets);
527
528 memcpy(parsed + 1, &received_packets, 4);
529 memcpy(parsed + 5, &expected_packets, 4);
530
531 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
532 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
533 else {
534 LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
535
536 session->last_received_packets = 0;
537 session->last_expected_packets = 0;
538 session->last_sent_report_ts = current_time_monotonic();
539 }
540}
541int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) 479int handle_rtp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
542{ 480{
543 RTPSession *session = object; 481 RTPSession *session = object;
544 RTPMessage *msg;
545 482
546 if ( !session || length < 13 ) { /* 12 is the minimum length for rtp + desc. byte */ 483 if ( !session || length < 13 || length > MAX_RTP_SIZE ) {
547 LOGGER_WARNING("No session or invalid length of received buffer!"); 484 LOGGER_WARNING("No session or invalid length of received buffer!");
548 return -1; 485 return -1;
549 } 486 }
487
488 RTPHeader* header = parse_header_in ( data, length );
550 489
551 msg = msg_parse ( data + 1, length - 1 ); 490 if ( !header ) {
552 491 LOGGER_WARNING("Could not parse message: Header failed to extract!");
553 if ( !msg ) {
554 LOGGER_WARNING("Could not parse message!");
555 return -1; 492 return -1;
556 } 493 }
494
495 RTPExtHeader* ext_header = NULL;
496
497 uint16_t from_pos = header->length;
498 uint16_t msg_length = length - from_pos;
557 499
500 if ( GET_FLAG_EXTENSION ( header ) ) {
501 ext_header = parse_ext_header_in ( data + from_pos, length );
502
503 if ( ext_header ) {
504 msg_length -= ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
505 from_pos += ( 4 /* Minimum ext header len */ + ext_header->length * size_32 );
506 } else { /* Error */
507 LOGGER_WARNING("Could not parse message: Ext Header failed to extract!");
508 free(header);
509 return -1;
510 }
511 }
512
513 if (msg_length > MAX_RTP_SIZE) {
514 LOGGER_WARNING("Could not parse message: Invalid length!");
515 free(header);
516 free(ext_header);
517 return -1;
518 }
519
558 /* Check if message came in late */ 520 /* Check if message came in late */
559 if ( msg->header->sequnum > session->rsequnum || msg->header->timestamp > session->rtimestamp ) { 521 if ( header->sequnum > session->rsequnum || header->timestamp > session->rtimestamp ) {
560 /* Not late */ 522 /* Not late */
561 if (msg->header->sequnum > session->rsequnum) 523 if (header->sequnum > session->rsequnum)
562 session->rtcp_session->last_expected_packets += msg->header->sequnum - session->rsequnum; 524 session->rtcp_session->last_expected_packets += header->sequnum - session->rsequnum;
563 else if (msg->header->sequnum < session->rsequnum) 525 else if (header->sequnum < session->rsequnum)
564 session->rtcp_session->last_expected_packets += (msg->header->sequnum + 65535) - session->rsequnum; 526 session->rtcp_session->last_expected_packets += (header->sequnum + 65535) - session->rsequnum;
565 else /* Usual case when transmission starts */ 527 else /* Usual case when transmission starts */
566 session->rtcp_session->last_expected_packets ++; 528 session->rtcp_session->last_expected_packets ++;
567 529
568 session->rsequnum = msg->header->sequnum; 530 session->rsequnum = header->sequnum;
569 session->rtimestamp = msg->header->timestamp; 531 session->rtimestamp = header->timestamp;
570 } 532 }
571 533
572 session->rtcp_session->last_received_packets ++; 534 session->rtcp_session->last_received_packets ++;
573 535
574 if (session->mcb) 536 /* Check if the message is dummy. We don't keep dummy messages */
575 return session->mcb (session->cs, msg); 537 if (GET_SETTING_PAYLOAD(header) == (session->payload_type + 2) % 128) {
576 else { 538 LOGGER_DEBUG("Received dummy rtp message");
577 rtp_free_msg(session, msg); 539 free(header);
540 free(ext_header);
541 return 0;
542 }
543
544 /* Otherwise we will store the message if we have an appropriate handler */
545 if (!session->mcb) {
546 LOGGER_DEBUG("No handler for the message of %d payload", GET_SETTING_PAYLOAD(header));
547 free(header);
548 free(ext_header);
578 return 0; 549 return 0;
579 } 550 }
551
552 RTPMessage *msg = calloc(1, sizeof (RTPMessage) + msg_length);
553
554 if ( !msg ) {
555 LOGGER_WARNING("Could not parse message: Allocation failed!");
556 free(header);
557 free(ext_header);
558 return -1;
559 }
560
561 msg->header = header;
562 msg->ext_header = ext_header;
563 msg->length = msg_length;
564
565 memcpy ( msg->data, data + from_pos, msg_length );
566
567 return session->mcb (session->cs, msg);
580} 568}
581int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object ) 569int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* data, uint16_t length, void* object )
582{ 570{
@@ -605,4 +593,28 @@ int handle_rtcp_packet ( Messenger* m, uint32_t friendnumber, const uint8_t* dat
605 593
606 LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets); 594 LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets);
607 return 0; 595 return 0;
596}
597void send_rtcp_report(RTCPSession* session, Messenger* m, uint32_t friendnumber)
598{
599 if (session->last_expected_packets == 0)
600 return;
601
602 uint8_t parsed[9];
603 parsed[0] = session->prefix;
604
605 uint32_t received_packets = htonl(session->last_received_packets);
606 uint32_t expected_packets = htonl(session->last_expected_packets);
607
608 memcpy(parsed + 1, &received_packets, 4);
609 memcpy(parsed + 5, &expected_packets, 4);
610
611 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
612 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
613 else {
614 LOGGER_DEBUG("Sent rtcp report: ex: %d rc: %d", session->last_expected_packets, session->last_received_packets);
615
616 session->last_received_packets = 0;
617 session->last_expected_packets = 0;
618 session->last_sent_report_ts = current_time_monotonic();
619 }
608} \ No newline at end of file 620} \ No newline at end of file