summaryrefslogtreecommitdiff
path: root/toxav/rtp.c
diff options
context:
space:
mode:
authormannol <eniz_vukovic@hotmail.com>2015-04-16 02:00:34 +0200
committermannol <eniz_vukovic@hotmail.com>2015-04-16 02:00:34 +0200
commitda6c17222f54c933c826e9c557e66629ee57790f (patch)
tree2cf5e0ff002bef5d69f0048475ea7becc11bd389 /toxav/rtp.c
parent2465f486acd90ed8395c8a83a13af09ecd024c98 (diff)
The pretty basic adaptive bitrate is *working*
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r--toxav/rtp.c101
1 files changed, 62 insertions, 39 deletions
diff --git a/toxav/rtp.c b/toxav/rtp.c
index 77fce056..665ebf86 100644
--- a/toxav/rtp.c
+++ b/toxav/rtp.c
@@ -50,15 +50,17 @@
50typedef struct { 50typedef struct {
51 uint64_t timestamp; /* in ms */ 51 uint64_t timestamp; /* in ms */
52 52
53 uint32_t packets_missing; 53 uint32_t received_packets;
54 uint32_t expected_packets; 54 uint32_t expected_packets;
55 /* ... other stuff in the future */ 55 /* ... other stuff in the future */
56} RTCPReport; 56} RTCPReport;
57 57
58typedef struct RTCPSession_s { 58typedef struct RTCPSession_s {
59 RTPSession *rtp_session;
60
59 uint8_t prefix; 61 uint8_t prefix;
60 uint64_t last_sent_report_ts; 62 uint64_t last_sent_report_ts;
61 uint32_t last_missing_packets; 63 uint32_t last_received_packets;
62 uint32_t last_expected_packets; 64 uint32_t last_expected_packets;
63 65
64 RingBuffer* pl_stats; /* Packet loss stats over time */ 66 RingBuffer* pl_stats; /* Packet loss stats over time */
@@ -66,6 +68,7 @@ typedef struct RTCPSession_s {
66 68
67 69
68 70
71
69/* queue_message() is defined in codec.c */ 72/* queue_message() is defined in codec.c */
70void queue_message(RTPSession *session, RTPMessage *msg); 73void queue_message(RTPSession *session, RTPMessage *msg);
71RTPHeader *parse_header_in ( const uint8_t *payload, int length ); 74RTPHeader *parse_header_in ( const uint8_t *payload, int length );
@@ -91,18 +94,12 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
91 } 94 }
92 95
93 retu->version = RTP_VERSION; /* It's always 2 */ 96 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(); 97 retu->ssrc = random_int();
99 retu->marker = 0;
100 retu->payload_type = payload_type % 128; 98 retu->payload_type = payload_type % 128;
101 99
100 retu->tstate = rtp_StateNormal;
102 retu->m = messenger; 101 retu->m = messenger;
103 retu->dest = friend_num; 102 retu->dest = friend_num;
104 retu->rsequnum = retu->sequnum = 0;
105 retu->ext_header = NULL; /* When needed allocate */
106 103
107 if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) { 104 if ( !(retu->csrc = calloc(1, sizeof(uint32_t))) ) {
108 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 105 LOGGER_WARNING("Alloc failed! Program might misbehave!");
@@ -117,15 +114,16 @@ RTPSession *rtp_new ( int payload_type, Messenger *messenger, int friend_num )
117 114
118 115
119 /* Initialize rtcp session */ 116 /* Initialize rtcp session */
120 if (!(retu->rtcp = calloc(1, sizeof(RTCPSession)))) { 117 if (!(retu->rtcp_session = calloc(1, sizeof(RTCPSession)))) {
121 LOGGER_WARNING("Alloc failed! Program might misbehave!"); 118 LOGGER_WARNING("Alloc failed! Program might misbehave!");
122 free(retu->csrc); 119 free(retu->csrc);
123 free(retu); 120 free(retu);
124 return NULL; 121 return NULL;
125 } 122 }
126 123
127 retu->rtcp->prefix = 222 + payload_type % 192; 124 retu->rtcp_session->prefix = 222 + payload_type % 192;
128 retu->rtcp->pl_stats = rb_new(4); 125 retu->rtcp_session->pl_stats = rb_new(4);
126 retu->rtcp_session->rtp_session = retu;
129 127
130 return retu; 128 return retu;
131} 129}
@@ -139,11 +137,11 @@ void rtp_kill ( RTPSession *session )
139 free ( session->csrc ); 137 free ( session->csrc );
140 138
141 void* t; 139 void* t;
142 while (!rb_empty(session->rtcp->pl_stats)) { 140 while (!rb_empty(session->rtcp_session->pl_stats)) {
143 rb_read(session->rtcp->pl_stats, (void**) &t); 141 rb_read(session->rtcp_session->pl_stats, (void**) &t);
144 free(t); 142 free(t);
145 } 143 }
146 rb_free(session->rtcp->pl_stats); 144 rb_free(session->rtcp_session->pl_stats);
147 145
148 LOGGER_DEBUG("Terminated RTP session: %p", session); 146 LOGGER_DEBUG("Terminated RTP session: %p", session);
149 147
@@ -152,41 +150,49 @@ void rtp_kill ( RTPSession *session )
152} 150}
153void rtp_do(RTPSession *session) 151void rtp_do(RTPSession *session)
154{ 152{
155 if (!session || !session->rtcp) 153 if (!session || !session->rtcp_session)
156 return; 154 return;
157 155
158 if (current_time_monotonic() - session->rtcp->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) { 156 if (current_time_monotonic() - session->rtcp_session->last_sent_report_ts >= RTCP_REPORT_INTERVAL_MS) {
159 send_rtcp_report(session->rtcp, session->m, session->dest); 157 send_rtcp_report(session->rtcp_session, session->m, session->dest);
160 } 158 }
161 159
162 if (rb_full(session->rtcp->pl_stats)) { 160 if (rb_full(session->rtcp_session->pl_stats)) {
163 RTCPReport* reports[4]; 161 RTCPReport* reports[4];
164 162
165 int i = 0; 163 int i = 0;
166 for (; rb_read(session->rtcp->pl_stats, (void**) reports + i); i++); 164 for (; rb_read(session->rtcp_session->pl_stats, (void**) reports + i); i++);
167 165
168 /* Check for timed out reports (> 6 sec) */ 166 /* Check for timed out reports (> 6 sec) */
169 uint64_t now = current_time_monotonic(); 167 uint64_t now = current_time_monotonic();
170 for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++); 168 for (i = 0; i < 4 && now - reports[i]->timestamp < 6000; i ++);
171 for (; i < 4; i ++) { 169 for (; i < 4; i ++) {
172 rb_write(session->rtcp->pl_stats, reports[i]); 170 rb_write(session->rtcp_session->pl_stats, reports[i]);
173 reports[i] = NULL; 171 reports[i] = NULL;
174 } 172 }
175 if (!rb_empty(session->rtcp->pl_stats)) { 173 if (!rb_empty(session->rtcp_session->pl_stats)) {
176 for (i = 0; reports[i] != NULL; i ++) 174 for (i = 0; reports[i] != NULL; i ++)
177 free(reports[i]); 175 free(reports[i]);
178 return; /* As some reports are timed out, we need more... */ 176 return; /* As some reports are timed out, we need more... */
179 } 177 }
180 178
181 /* We have 4 on-time reports so we can proceed */ 179 /* We have 4 on-time reports so we can proceed */
182 uint32_t quality_loss = 0; 180 uint32_t quality = 100;
183 for (i = 0; i < 4; i++) { 181 for (i = 0; i < 4; i++) {
184 uint32_t idx = reports[i]->packets_missing * 100 / reports[i]->expected_packets; 182 uint32_t idx = reports[i]->received_packets * 100 / reports[i]->expected_packets;
185 quality_loss += idx; 183 quality = MIN(quality, idx);
184 free(reports[i]);
186 } 185 }
187 186
188 if (quality_loss > 40) { 187 if (quality <= 70) {
189 LOGGER_DEBUG("Packet loss detected"); 188 session->tstate = rtp_StateBad;
189 LOGGER_WARNING("Stream quality: BAD");
190 } else if (quality >= 99) {
191 session->tstate = rtp_StateGood;
192 LOGGER_DEBUG("Stream quality: GOOD");
193 } else {
194 session->tstate = rtp_StateNormal;
195 LOGGER_DEBUG("Stream quality: NORMAL");
190 } 196 }
191 } 197 }
192} 198}
@@ -200,8 +206,8 @@ int rtp_start_receiving(RTPSession* session)
200 LOGGER_WARNING("Failed to register rtp receive handler"); 206 LOGGER_WARNING("Failed to register rtp receive handler");
201 return -1; 207 return -1;
202 } 208 }
203 if (custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp->prefix, 209 if (custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp_session->prefix,
204 handle_rtcp_packet, session->rtcp) == -1) { 210 handle_rtcp_packet, session->rtcp_session) == -1) {
205 LOGGER_WARNING("Failed to register rtcp receive handler"); 211 LOGGER_WARNING("Failed to register rtcp receive handler");
206 custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL); 212 custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL);
207 return -1; 213 return -1;
@@ -215,7 +221,7 @@ int rtp_stop_receiving(RTPSession* session)
215 return -1; 221 return -1;
216 222
217 custom_lossy_packet_registerhandler(session->m, session->dest, session->prefix, NULL, NULL); 223 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 */ 224 custom_lossy_packet_registerhandler(session->m, session->dest, session->rtcp_session->prefix, NULL, NULL); /* RTCP */
219 225
220 return 0; 226 return 0;
221} 227}
@@ -516,16 +522,21 @@ void send_rtcp_report(RTCPSession* session, Messenger* m, int32_t friendnumber)
516 uint8_t parsed[9]; 522 uint8_t parsed[9];
517 parsed[0] = session->prefix; 523 parsed[0] = session->prefix;
518 524
519 uint32_t packets_missing = htonl(session->last_missing_packets); 525 uint32_t received_packets = htonl(session->last_received_packets);
520 uint32_t expected_packets = htonl(session->last_expected_packets); 526 uint32_t expected_packets = htonl(session->last_expected_packets);
521 527
522 memcpy(parsed + 1, &packets_missing, 4); 528 memcpy(parsed + 1, &received_packets, 4);
523 memcpy(parsed + 5, &expected_packets, 4); 529 memcpy(parsed + 5, &expected_packets, 4);
524 530
525 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed))) 531 if (-1 == send_custom_lossy_packet(m, friendnumber, parsed, sizeof(parsed)))
526 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno)); 532 LOGGER_WARNING("Failed to send full packet (len: %d)! std error: %s", sizeof(parsed), strerror(errno));
527 else 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;
528 session->last_sent_report_ts = current_time_monotonic(); 538 session->last_sent_report_ts = current_time_monotonic();
539 }
529} 540}
530int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) 541int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object )
531{ 542{
@@ -545,12 +556,21 @@ int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data,
545 } 556 }
546 557
547 /* Check if message came in late */ 558 /* Check if message came in late */
548 if ( msg->header->sequnum > session->rsequnum && msg->header->timestamp > session->rtimestamp ) { 559 if ( msg->header->sequnum > session->rsequnum || msg->header->timestamp > session->rtimestamp ) {
549 /* Not late */ 560 /* Not late */
561 if (msg->header->sequnum > session->rsequnum)
562 session->rtcp_session->last_expected_packets += msg->header->sequnum - session->rsequnum;
563 else if (msg->header->sequnum < session->rsequnum)
564 session->rtcp_session->last_expected_packets += (msg->header->sequnum + 65535) - session->rsequnum;
565 else /* Usual case when transmission starts */
566 session->rtcp_session->last_expected_packets ++;
567
550 session->rsequnum = msg->header->sequnum; 568 session->rsequnum = msg->header->sequnum;
551 session->rtimestamp = msg->header->timestamp; 569 session->rtimestamp = msg->header->timestamp;
552 } 570 }
553 571
572 session->rtcp_session->last_received_packets ++;
573
554 queue_message(session, msg); 574 queue_message(session, msg);
555 return 0; 575 return 0;
556} 576}
@@ -562,14 +582,15 @@ int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data
562 RTCPSession* session = object; 582 RTCPSession* session = object;
563 RTCPReport* report = malloc(sizeof(RTCPReport)); 583 RTCPReport* report = malloc(sizeof(RTCPReport));
564 584
565 memcpy(&report->packets_missing, data + 1, 4); 585 memcpy(&report->received_packets, data + 1, 4);
566 memcpy(&report->expected_packets, data + 5, 4); 586 memcpy(&report->expected_packets, data + 5, 4);
567 587
568 report->packets_missing = ntohl(report->packets_missing); 588 report->received_packets = ntohl(report->received_packets);
569 report->expected_packets = ntohl(report->expected_packets); 589 report->expected_packets = ntohl(report->expected_packets);
570 590
571 /* This would cause undefined behaviour */ 591 /* Invalid values */
572 if (report->expected_packets == 0) { 592 if (report->expected_packets == 0 || report->received_packets > report->expected_packets) {
593 LOGGER_WARNING("Malformed rtcp report! %d %d", report->expected_packets, report->received_packets);
573 free(report); 594 free(report);
574 return 0; 595 return 0;
575 } 596 }
@@ -577,5 +598,7 @@ int handle_rtcp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data
577 report->timestamp = current_time_monotonic(); 598 report->timestamp = current_time_monotonic();
578 599
579 free(rb_write(session->pl_stats, report)); 600 free(rb_write(session->pl_stats, report));
601
602 LOGGER_DEBUG("Got rtcp report: ex: %d rc: %d", report->expected_packets, report->received_packets);
580 return 0; 603 return 0;
581} \ No newline at end of file 604} \ No newline at end of file