diff options
author | mannol <eniz_vukovic@hotmail.com> | 2015-04-16 02:00:34 +0200 |
---|---|---|
committer | mannol <eniz_vukovic@hotmail.com> | 2015-04-16 02:00:34 +0200 |
commit | da6c17222f54c933c826e9c557e66629ee57790f (patch) | |
tree | 2cf5e0ff002bef5d69f0048475ea7becc11bd389 /toxav/rtp.c | |
parent | 2465f486acd90ed8395c8a83a13af09ecd024c98 (diff) |
The pretty basic adaptive bitrate is *working*
Diffstat (limited to 'toxav/rtp.c')
-rw-r--r-- | toxav/rtp.c | 101 |
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 @@ | |||
50 | typedef struct { | 50 | typedef 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 | ||
58 | typedef struct RTCPSession_s { | 58 | typedef 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 */ |
70 | void queue_message(RTPSession *session, RTPMessage *msg); | 73 | void queue_message(RTPSession *session, RTPMessage *msg); |
71 | RTPHeader *parse_header_in ( const uint8_t *payload, int length ); | 74 | RTPHeader *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 | } |
153 | void rtp_do(RTPSession *session) | 151 | void 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 | } |
530 | int handle_rtp_packet ( Messenger *m, int32_t friendnumber, const uint8_t *data, uint32_t length, void *object ) | 541 | int 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 |