/home/atoppi/src/janus-gateway/rtcp.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*! \file rtcp.c |
2 | | * \author Lorenzo Miniero <[email protected]> |
3 | | * \copyright GNU General Public License v3 |
4 | | * \brief RTCP processing |
5 | | * \details Implementation (based on the oRTP structures) of the RTCP |
6 | | * messages. RTCP messages coming through the server are parsed and, |
7 | | * if needed (according to http://tools.ietf.org/html/draft-ietf-straw-b2bua-rtcp-00), |
8 | | * fixed before they are sent to the peers (e.g., to fix SSRCs that may |
9 | | * have been changed by the server). Methods to generate FIR messages |
10 | | * and generate/cap REMB messages are provided as well. |
11 | | * |
12 | | * \ingroup protocols |
13 | | * \ref protocols |
14 | | */ |
15 | | |
16 | | #include <math.h> |
17 | | #include <stdlib.h> |
18 | | #include <sys/time.h> |
19 | | |
20 | | #include "debug.h" |
21 | | #include "rtp.h" |
22 | | #include "rtcp.h" |
23 | | #include "utils.h" |
24 | | |
25 | 83 | gboolean janus_is_rtcp(char *buf, guint len) { |
26 | 83 | if (len < 8) |
27 | 7 | return FALSE; |
28 | 76 | janus_rtp_header *header = (janus_rtp_header *)buf; |
29 | 76 | return ((header->type >= 64) && (header->type < 96)); |
30 | 76 | } |
31 | | |
32 | 73 | int janus_rtcp_parse(janus_rtcp_context *ctx, char *packet, int len) { |
33 | 73 | return janus_rtcp_fix_ssrc(ctx, packet, len, 0, 0, 0); |
34 | 73 | } |
35 | | |
36 | 73 | guint32 janus_rtcp_get_sender_ssrc(char *packet, int len) { |
37 | 73 | if(packet == NULL || len == 0) |
38 | 0 | return 0; |
39 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
40 | 73 | int pno = 0, total = len; |
41 | 74 | while(rtcp) { |
42 | 74 | if (!janus_rtcp_check_len(rtcp, total)) |
43 | 7 | break; |
44 | 67 | if(rtcp->version != 2) |
45 | 0 | break; |
46 | 67 | pno++; |
47 | 67 | switch(rtcp->type) { |
48 | 67 | case RTCP_SR: { |
49 | 3 | /* SR, sender report */ |
50 | 3 | janus_rtcp_sr *sr = (janus_rtcp_sr *)rtcp; |
51 | 3 | return ntohl(sr->ssrc); |
52 | 67 | } |
53 | 67 | case RTCP_RR: { |
54 | 6 | /* RR, receiver report */ |
55 | 6 | janus_rtcp_rr *rr = (janus_rtcp_rr *)rtcp; |
56 | 6 | return ntohl(rr->ssrc); |
57 | 67 | } |
58 | 67 | case RTCP_RTPFB: { |
59 | 12 | /* RTPFB, Transport layer FB message (rfc4585) */ |
60 | 12 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
61 | 12 | return ntohl(rtcpfb->ssrc); |
62 | 67 | } |
63 | 67 | case RTCP_PSFB: { |
64 | 22 | /* PSFB, Payload-specific FB message (rfc4585) */ |
65 | 22 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
66 | 22 | return ntohl(rtcpfb->ssrc); |
67 | 67 | } |
68 | 67 | case RTCP_XR: { |
69 | 8 | /* XR, extended reports (rfc3611) */ |
70 | 8 | janus_rtcp_xr *xr = (janus_rtcp_xr *)rtcp; |
71 | 8 | return ntohl(xr->ssrc); |
72 | 67 | } |
73 | 67 | default: |
74 | 16 | break; |
75 | 16 | } |
76 | 16 | /* Is this a compound packet? */ |
77 | 16 | int length = ntohs(rtcp->length); |
78 | 16 | if(length == 0) { |
79 | 0 | break; |
80 | 0 | } |
81 | 16 | total -= length*4+4; |
82 | 16 | if(total <= 0) |
83 | 15 | break; |
84 | 1 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
85 | 1 | } |
86 | 73 | return 0; |
87 | 73 | } |
88 | | |
89 | 73 | guint32 janus_rtcp_get_receiver_ssrc(char *packet, int len) { |
90 | 73 | if(packet == NULL || len == 0) |
91 | 0 | return 0; |
92 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
93 | 73 | int pno = 0, total = len; |
94 | 77 | while(rtcp) { |
95 | 77 | if (!janus_rtcp_check_len(rtcp, total)) |
96 | 7 | break; |
97 | 70 | if(rtcp->version != 2) |
98 | 0 | break; |
99 | 70 | pno++; |
100 | 70 | switch(rtcp->type) { |
101 | 70 | case RTCP_SR: { |
102 | 3 | /* SR, sender report */ |
103 | 3 | if (!janus_rtcp_check_sr(rtcp, total)) |
104 | 0 | break; |
105 | 3 | janus_rtcp_sr *sr = (janus_rtcp_sr *)rtcp; |
106 | 3 | if(sr->header.rc > 0) { |
107 | 1 | return ntohl(sr->rb[0].ssrc); |
108 | 1 | } |
109 | 2 | break; |
110 | 2 | } |
111 | 6 | case RTCP_RR: { |
112 | 6 | /* RR, receiver report */ |
113 | 6 | if (!janus_rtcp_check_rr(rtcp, total)) |
114 | 0 | break; |
115 | 6 | janus_rtcp_rr *rr = (janus_rtcp_rr *)rtcp; |
116 | 6 | if(rr->header.rc > 0) { |
117 | 4 | return ntohl(rr->rb[0].ssrc); |
118 | 4 | } |
119 | 2 | break; |
120 | 2 | } |
121 | 61 | default: |
122 | 61 | break; |
123 | 65 | } |
124 | 65 | /* Is this a compound packet? */ |
125 | 65 | int length = ntohs(rtcp->length); |
126 | 65 | if(length == 0) { |
127 | 0 | break; |
128 | 0 | } |
129 | 65 | total -= length*4+4; |
130 | 65 | if(total <= 0) |
131 | 61 | break; |
132 | 4 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
133 | 4 | } |
134 | 73 | return 0; |
135 | 73 | } |
136 | | |
137 | | /* Helper to handle an incoming SR: triggered by a call to janus_rtcp_fix_ssrc with fixssrc=0 */ |
138 | 6 | static void janus_rtcp_incoming_sr(janus_rtcp_context *ctx, janus_rtcp_sr *sr) { |
139 | 6 | if(ctx == NULL) |
140 | 6 | return; |
141 | 6 | /* Update the context with info on the monotonic time of last SR received */ |
142 | 6 | ctx->lsr_ts = janus_get_monotonic_time(); |
143 | 6 | /* Compute the last SR received as well */ |
144 | 6 | uint64_t ntp = ntohl(sr->si.ntp_ts_msw); |
145 | 6 | ntp = (ntp << 32) | ntohl(sr->si.ntp_ts_lsw); |
146 | 6 | ctx->lsr = (ntp >> 16); |
147 | 6 | } |
148 | | |
149 | | /* Link quality estimate filter coefficient */ |
150 | 0 | #define LINK_QUALITY_FILTER_K 3.0 |
151 | | |
152 | 0 | static double janus_rtcp_link_quality_filter(double last, double in) { |
153 | 0 | /* Note: the last!=last is there to check for NaN */ |
154 | 0 | if(last == 0 || last == in || last != last) { |
155 | 0 | return in; |
156 | 0 | } else { |
157 | 0 | return (1.0 - 1.0/LINK_QUALITY_FILTER_K) * last + (1.0/LINK_QUALITY_FILTER_K) * in; |
158 | 0 | } |
159 | 0 | } |
160 | | |
161 | | /* Update link quality stats based on RR */ |
162 | 8 | static void janus_rtcp_rr_update_stats(rtcp_context *ctx, janus_report_block rb) { |
163 | 8 | int64_t ts = janus_get_monotonic_time(); |
164 | 8 | int64_t delta_t = ts - ctx->rr_last_ts; |
165 | 8 | if(delta_t < 2*G_USEC_PER_SEC) { |
166 | 0 | return; |
167 | 0 | } |
168 | 8 | ctx->rr_last_ts = ts; |
169 | 8 | uint32_t total_lost = ntohl(rb.flcnpl) & 0x00FFFFFF; |
170 | 8 | if (ctx->rr_last_ehsnr != 0) { |
171 | 0 | uint32_t sent = g_atomic_int_get(&ctx->sent_packets_since_last_rr); |
172 | 0 | uint32_t expect = ntohl(rb.ehsnr) - ctx->rr_last_ehsnr; |
173 | 0 | int32_t nacks = g_atomic_int_get(&ctx->nack_count) - ctx->rr_last_nack_count; |
174 | 0 | double link_q = !sent ? 0 : 100.0 - (100.0 * nacks / (double)sent); |
175 | 0 | ctx->out_link_quality = janus_rtcp_link_quality_filter(ctx->out_link_quality, link_q); |
176 | 0 | int32_t lost = total_lost - ctx->rr_last_lost; |
177 | 0 | if(lost < 0) { |
178 | 0 | lost = 0; |
179 | 0 | } |
180 | 0 | double media_link_q = !expect ? 0 : 100.0 - (100.0 * lost / (double)expect); |
181 | 0 | ctx->out_media_link_quality = janus_rtcp_link_quality_filter(ctx->out_media_link_quality, media_link_q); |
182 | 0 | JANUS_LOG(LOG_HUGE, "Out link quality=%"SCNu32", media link quality=%"SCNu32"\n", janus_rtcp_context_get_out_link_quality(ctx), janus_rtcp_context_get_out_media_link_quality(ctx)); |
183 | 0 | } |
184 | 8 | ctx->rr_last_ehsnr = ntohl(rb.ehsnr); |
185 | 8 | ctx->rr_last_lost = total_lost; |
186 | 8 | ctx->rr_last_nack_count = g_atomic_int_get(&ctx->nack_count); |
187 | 8 | g_atomic_int_set(&ctx->sent_packets_since_last_rr, 0); |
188 | 8 | } |
189 | | |
190 | | /* Helper to handle an incoming RR: triggered by a call to janus_rtcp_fix_ssrc with fixssrc=0 */ |
191 | 12 | static void janus_rtcp_incoming_rr(janus_rtcp_context *ctx, janus_rtcp_rr *rr) { |
192 | 12 | if(ctx == NULL) |
193 | 12 | return; |
194 | 12 | /* FIXME Check the Record Blocks */ |
195 | 12 | if(rr->header.rc > 0) { |
196 | 8 | double jitter = (double)ntohl(rr->rb[0].jitter); |
197 | 8 | uint32_t fraction = ntohl(rr->rb[0].flcnpl) >> 24; |
198 | 8 | uint32_t total = ntohl(rr->rb[0].flcnpl) & 0x00FFFFFF; |
199 | 8 | JANUS_LOG(LOG_HUGE, "jitter=%f, fraction=%"SCNu32", loss=%"SCNu32"\n", jitter, fraction, total); |
200 | 8 | ctx->lost_remote = total; |
201 | 8 | ctx->jitter_remote = jitter; |
202 | 8 | janus_rtcp_rr_update_stats(ctx, rr->rb[0]); |
203 | 8 | /* FIXME Compute round trip time */ |
204 | 8 | uint32_t lsr = ntohl(rr->rb[0].lsr); |
205 | 8 | uint32_t dlsr = ntohl(rr->rb[0].delay); |
206 | 8 | if(lsr == 0) /* Not enough info yet */ |
207 | 2 | return; |
208 | 6 | struct timeval tv; |
209 | 6 | gettimeofday(&tv, NULL); |
210 | 6 | uint32_t s = tv.tv_sec + 2208988800u; |
211 | 6 | uint32_t u = tv.tv_usec; |
212 | 6 | uint32_t f = (u << 12) + (u << 8) - ((u * 3650) >> 6); |
213 | 6 | uint32_t ntp_ts_msw = s; |
214 | 6 | uint32_t ntp_ts_lsw = f; |
215 | 6 | uint64_t temp = ((uint64_t)ntp_ts_msw << 32 ) | ntp_ts_lsw; |
216 | 6 | uint32_t a = (uint32_t)(temp >> 16); |
217 | 6 | uint32_t rtt = a - lsr - dlsr; |
218 | 6 | uint32_t rtt_msw = (rtt & 0xFFFF0000) >> 16; |
219 | 6 | uint32_t rtt_lsw = rtt & 0x0000FFFF; |
220 | 6 | tv.tv_sec = rtt_msw; |
221 | 6 | tv.tv_usec = (rtt_lsw * 15625) >> 10; |
222 | 6 | ctx->rtt = tv.tv_sec*1000 + tv.tv_usec/1000; /* We need milliseconds */ |
223 | 6 | JANUS_LOG(LOG_HUGE, "rtt=%"SCNu32"\n", ctx->rtt); |
224 | 6 | } |
225 | 12 | } |
226 | | |
227 | 1.00k | gboolean janus_rtcp_check_len(janus_rtcp_header *rtcp, int len) { |
228 | 1.00k | if (len < (int)sizeof(janus_rtcp_header) + (int)sizeof(uint32_t)) { |
229 | 13 | JANUS_LOG(LOG_VERB, "Packet size is too small (%d bytes) to contain RTCP\n", len); |
230 | 13 | return FALSE; |
231 | 13 | } |
232 | 995 | int header_def_len = 4*(int)ntohs(rtcp->length) + 4; |
233 | 995 | if (len < header_def_len) { |
234 | 78 | JANUS_LOG(LOG_VERB, "Invalid RTCP packet defined length, expected %d bytes > actual %d bytes\n", header_def_len, len); |
235 | 78 | return FALSE; |
236 | 78 | } |
237 | 917 | return TRUE; |
238 | 917 | } |
239 | | |
240 | 12 | gboolean janus_rtcp_check_sr(janus_rtcp_header *rtcp, int len) { |
241 | 12 | if (len < (int)sizeof(janus_rtcp_header) + (int)sizeof(uint32_t) + (int)sizeof(sender_info)) { |
242 | 0 | JANUS_LOG(LOG_VERB, "RTCP Packet is too small (%d bytes) to contain SR\n", len); |
243 | 0 | return FALSE; |
244 | 0 | } |
245 | 12 | int header_rb_len = (int)(rtcp->rc)*(int)sizeof(report_block); |
246 | 12 | int actual_rb_len = len - (int)sizeof(janus_rtcp_header) - (int)sizeof(uint32_t) - (int)sizeof(sender_info); |
247 | 12 | if (actual_rb_len < header_rb_len) { |
248 | 0 | JANUS_LOG(LOG_VERB, "SR got %d RB count, expected %d bytes > actual %d bytes\n", rtcp->rc, header_rb_len, actual_rb_len); |
249 | 0 | return FALSE; |
250 | 0 | } |
251 | 12 | return TRUE; |
252 | 12 | } |
253 | | |
254 | 24 | gboolean janus_rtcp_check_rr(janus_rtcp_header *rtcp, int len) { |
255 | 24 | int header_rb_len = (int)(rtcp->rc)*(int)sizeof(report_block); |
256 | 24 | int actual_rb_len = len - (int)sizeof(janus_rtcp_header) - (int)sizeof(uint32_t); |
257 | 24 | if (actual_rb_len < header_rb_len) { |
258 | 0 | JANUS_LOG(LOG_VERB, "RR got %d RB count, expected %d bytes > actual %d bytes\n", rtcp->rc, header_rb_len, actual_rb_len); |
259 | 0 | return FALSE; |
260 | 0 | } |
261 | 24 | return TRUE; |
262 | 24 | } |
263 | | |
264 | 23 | gboolean janus_rtcp_check_fci(janus_rtcp_header *rtcp, int len, int sizeof_fci) { |
265 | 23 | /* At least one sizeof_fci bytes FCI */ |
266 | 23 | if (len < (int)sizeof(janus_rtcp_header) + 2*(int)sizeof(uint32_t) + sizeof_fci) { |
267 | 4 | JANUS_LOG(LOG_VERB, "RTCP Packet is too small (%d bytes) to contain at least one %d bytes FCI\n", len, sizeof_fci); |
268 | 4 | return FALSE; |
269 | 4 | } |
270 | 19 | /* Evaluate fci total size */ |
271 | 19 | int fci_size = len - (int)sizeof(janus_rtcp_header) - 2*(int)sizeof(uint32_t); |
272 | 19 | /* The length of the feedback message is set to 2+(sizeof_fci/4)*N where |
273 | 19 | N is the number of FCI entries */ |
274 | 19 | int fcis; |
275 | 19 | switch(sizeof_fci) { |
276 | 19 | case 0: |
277 | 10 | fcis = 0; |
278 | 10 | break; |
279 | 19 | case 4: |
280 | 4 | fcis = (int)ntohs(rtcp->length) - 2; |
281 | 4 | break; |
282 | 19 | case 8: |
283 | 5 | fcis = ((int)ntohs(rtcp->length) - 2) >> 1; |
284 | 5 | break; |
285 | 19 | default: |
286 | 0 | fcis = ((int)ntohs(rtcp->length)- 2) / (sizeof_fci >> 2); |
287 | 0 | break; |
288 | 19 | } |
289 | 19 | /* Every FCI is sizeof_fci bytes */ |
290 | 19 | if (fci_size < sizeof_fci*fcis) { |
291 | 0 | JANUS_LOG(LOG_VERB, "Got %d FCI count, expected %d bytes > actual %d bytes\n", fcis, sizeof_fci*fcis, fci_size); |
292 | 0 | return FALSE; |
293 | 0 | } |
294 | 19 | return TRUE; |
295 | 19 | } |
296 | | |
297 | 32 | gboolean janus_rtcp_check_remb(janus_rtcp_header *rtcp, int len) { |
298 | 32 | /* At least 1 SSRC feedback */ |
299 | 32 | if (len < (int)sizeof(janus_rtcp_header) + 2*(int)sizeof(uint32_t) + 3*(int)sizeof(uint32_t)) { |
300 | 12 | JANUS_LOG(LOG_VERB, "Packet is too small (%d bytes) to contain REMB\n", len); |
301 | 12 | return FALSE; |
302 | 12 | } |
303 | 20 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
304 | 20 | uint8_t numssrc = *(rtcpfb->fci+4); |
305 | 20 | /* Evaluate ssrcs total size */ |
306 | 20 | int ssrc_size = len - (int)sizeof(janus_rtcp_header) - 2*(int)sizeof(uint32_t); |
307 | 20 | /* Every SSRC is 4 bytes */ |
308 | 20 | if (ssrc_size < 4*numssrc) { |
309 | 0 | JANUS_LOG(LOG_VERB, "REMB got %d SSRC count, expected %d bytes > actual %d bytes\n", numssrc, 4*numssrc, ssrc_size); |
310 | 0 | return FALSE; |
311 | 0 | } |
312 | 20 | return TRUE; |
313 | 20 | } |
314 | | |
315 | 146 | int janus_rtcp_fix_ssrc(janus_rtcp_context *ctx, char *packet, int len, int fixssrc, uint32_t newssrcl, uint32_t newssrcr) { |
316 | 146 | if(packet == NULL || len <= 0) |
317 | 0 | return -1; |
318 | 146 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
319 | 146 | int pno = 0, total = len; |
320 | 146 | JANUS_LOG(LOG_HUGE, " Parsing compound packet (total of %d bytes)\n", total); |
321 | 156 | while(rtcp) { |
322 | 156 | if (!janus_rtcp_check_len(rtcp, total)) |
323 | 14 | return -2; |
324 | 142 | if(rtcp->version != 2) |
325 | 0 | return -2; |
326 | 142 | pno++; |
327 | 142 | /* TODO Should we handle any of these packets ourselves, or just relay them? */ |
328 | 142 | switch(rtcp->type) { |
329 | 142 | case RTCP_SR: { |
330 | 6 | /* SR, sender report */ |
331 | 6 | JANUS_LOG(LOG_HUGE, " #%d SR (200)\n", pno); |
332 | 6 | if (!janus_rtcp_check_sr(rtcp, total)) |
333 | 0 | return -2; |
334 | 6 | janus_rtcp_sr *sr = (janus_rtcp_sr *)rtcp; |
335 | 6 | /* If an RTCP context was provided, update it with info on this SR */ |
336 | 6 | janus_rtcp_incoming_sr(ctx, sr); |
337 | 6 | if(fixssrc && newssrcl) { |
338 | 3 | sr->ssrc = htonl(newssrcl); |
339 | 3 | if (sr->header.rc > 0) { |
340 | 1 | sr->rb[0].ssrc = htonl(newssrcr); |
341 | 1 | } |
342 | 3 | } |
343 | 6 | break; |
344 | 6 | } |
345 | 12 | case RTCP_RR: { |
346 | 12 | /* RR, receiver report */ |
347 | 12 | JANUS_LOG(LOG_HUGE, " #%d RR (201)\n", pno); |
348 | 12 | if (!janus_rtcp_check_rr(rtcp, total)) |
349 | 0 | return -2; |
350 | 12 | janus_rtcp_rr *rr = (janus_rtcp_rr *)rtcp; |
351 | 12 | /* If an RTCP context was provided, update it with info on this RR */ |
352 | 12 | janus_rtcp_incoming_rr(ctx, rr); |
353 | 12 | if(fixssrc && newssrcl) { |
354 | 6 | rr->ssrc = htonl(newssrcl); |
355 | 6 | if (rr->header.rc > 0) { |
356 | 4 | rr->rb[0].ssrc = htonl(newssrcr); |
357 | 4 | } |
358 | 6 | } |
359 | 12 | break; |
360 | 12 | } |
361 | 24 | case RTCP_SDES: { |
362 | 24 | /* SDES, source description */ |
363 | 24 | JANUS_LOG(LOG_HUGE, " #%d SDES (202)\n", pno); |
364 | 24 | janus_rtcp_sdes *sdes = (janus_rtcp_sdes *)rtcp; |
365 | 24 | //~ JANUS_LOG(LOG_HUGE, " -- SSRC: %u\n", ntohl(sdes->chunk.ssrc)); |
366 | 24 | if(fixssrc && newssrcl) { |
367 | 12 | sdes->chunk.ssrc = htonl(newssrcl); |
368 | 12 | } |
369 | 24 | break; |
370 | 12 | } |
371 | 12 | case RTCP_BYE: { |
372 | 8 | /* BYE, goodbye */ |
373 | 8 | JANUS_LOG(LOG_HUGE, " #%d BYE (203)\n", pno); |
374 | 8 | janus_rtcp_bye *bye = (janus_rtcp_bye *)rtcp; |
375 | 8 | //~ JANUS_LOG(LOG_HUGE, " -- SSRC: %u\n", ntohl(bye->ssrc[0])); |
376 | 8 | if(fixssrc && newssrcl) { |
377 | 4 | bye->ssrc[0] = htonl(newssrcl); |
378 | 4 | } |
379 | 8 | break; |
380 | 12 | } |
381 | 12 | case RTCP_APP: { |
382 | 0 | /* APP, application-defined */ |
383 | 0 | JANUS_LOG(LOG_HUGE, " #%d APP (204)\n", pno); |
384 | 0 | janus_rtcp_app *app = (janus_rtcp_app *)rtcp; |
385 | 0 | //~ JANUS_LOG(LOG_HUGE, " -- SSRC: %u\n", ntohl(app->ssrc)); |
386 | 0 | if(fixssrc && newssrcl) { |
387 | 0 | app->ssrc = htonl(newssrcl); |
388 | 0 | } |
389 | 0 | break; |
390 | 12 | } |
391 | 12 | case RTCP_FIR: { |
392 | 0 | /* FIR, rfc2032 */ |
393 | 0 | JANUS_LOG(LOG_HUGE, " #%d FIR (192)\n", pno); |
394 | 0 | break; |
395 | 12 | } |
396 | 24 | case RTCP_RTPFB: { |
397 | 24 | /* RTPFB, Transport layer FB message (rfc4585) */ |
398 | 24 | //~ JANUS_LOG(LOG_HUGE, " #%d RTPFB (205)\n", pno); |
399 | 24 | gint fmt = rtcp->rc; |
400 | 24 | //~ JANUS_LOG(LOG_HUGE, " -- FMT: %u\n", fmt); |
401 | 24 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
402 | 24 | //~ JANUS_LOG(LOG_HUGE, " -- SSRC: %u\n", ntohl(rtcpfb->ssrc)); |
403 | 24 | if(fmt == 1) { |
404 | 2 | JANUS_LOG(LOG_HUGE, " #%d NACK -- RTPFB (205)\n", pno); |
405 | 2 | /* NACK FCI size is 4 bytes */ |
406 | 2 | if (!janus_rtcp_check_fci(rtcp, total, 4)) |
407 | 0 | return -2; |
408 | 2 | if(fixssrc && newssrcr) { |
409 | 1 | rtcpfb->media = htonl(newssrcr); |
410 | 1 | } |
411 | 2 | int nacks = ntohs(rtcp->length)-2; /* Skip SSRCs */ |
412 | 2 | if(nacks > 0) { |
413 | 2 | JANUS_LOG(LOG_DBG, " Got %d nacks\n", nacks); |
414 | 2 | janus_rtcp_nack *nack = NULL; |
415 | 2 | uint16_t pid = 0; |
416 | 2 | uint16_t blp = 0; |
417 | 2 | int i=0, j=0; |
418 | 2 | char bitmask[20]; |
419 | 4 | for(i=0; i< nacks; i++) { |
420 | 2 | nack = (janus_rtcp_nack *)rtcpfb->fci + i; |
421 | 2 | pid = ntohs(nack->pid); |
422 | 2 | blp = ntohs(nack->blp); |
423 | 2 | memset(bitmask, 0, 20); |
424 | 34 | for(j=0; j<16; j++) { |
425 | 32 | bitmask[j] = (blp & ( 1 << j )) >> j ? '1' : '0'; |
426 | 32 | } |
427 | 2 | bitmask[16] = '\n'; |
428 | 2 | JANUS_LOG(LOG_DBG, "[%d] %"SCNu16" / %s\n", i, pid, bitmask); |
429 | 2 | } |
430 | 2 | } |
431 | 22 | } else if(fmt == 3) { /* rfc5104 */ |
432 | 8 | /* TMMBR: http://tools.ietf.org/html/rfc5104#section-4.2.1.1 */ |
433 | 8 | JANUS_LOG(LOG_HUGE, " #%d TMMBR -- RTPFB (205)\n", pno); |
434 | 8 | if(fixssrc && newssrcr) { |
435 | 4 | /* TMMBR FCI size is 8 bytes */ |
436 | 4 | if (!janus_rtcp_check_fci(rtcp, total, 8)) |
437 | 2 | return -2; |
438 | 2 | uint32_t *ssrc = (uint32_t *)rtcpfb->fci; |
439 | 2 | *ssrc = htonl(newssrcr); |
440 | 2 | } |
441 | 14 | } else { |
442 | 14 | JANUS_LOG(LOG_HUGE, " #%d ??? -- RTPFB (205, fmt=%d)\n", pno, fmt); |
443 | 14 | } |
444 | 24 | if(fixssrc && newssrcl) { |
445 | 10 | rtcpfb->ssrc = htonl(newssrcl); |
446 | 10 | } |
447 | 22 | break; |
448 | 24 | } |
449 | 46 | case RTCP_PSFB: { |
450 | 46 | /* PSFB, Payload-specific FB message (rfc4585) */ |
451 | 46 | //~ JANUS_LOG(LOG_HUGE, " #%d PSFB (206)\n", pno); |
452 | 46 | gint fmt = rtcp->rc; |
453 | 46 | //~ JANUS_LOG(LOG_HUGE, " -- FMT: %u\n", fmt); |
454 | 46 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
455 | 46 | //~ JANUS_LOG(LOG_HUGE, " -- SSRC: %u\n", ntohl(rtcpfb->ssrc)); |
456 | 46 | if(fmt == 1) { |
457 | 6 | JANUS_LOG(LOG_HUGE, " #%d PLI -- PSFB (206)\n", pno); |
458 | 6 | /* PLI does not require parameters. Therefore, the length field MUST be |
459 | 6 | 2, and there MUST NOT be any Feedback Control Information. */ |
460 | 6 | if(fixssrc && newssrcr) { |
461 | 3 | if (!janus_rtcp_check_fci(rtcp, total, 0)) |
462 | 1 | return -2; |
463 | 2 | rtcpfb->media = htonl(newssrcr); |
464 | 2 | } |
465 | 40 | } else if(fmt == 2) { |
466 | 4 | JANUS_LOG(LOG_HUGE, " #%d SLI -- PSFB (206)\n", pno); |
467 | 36 | } else if(fmt == 3) { |
468 | 12 | JANUS_LOG(LOG_HUGE, " #%d RPSI -- PSFB (206)\n", pno); |
469 | 24 | } else if(fmt == 4) { /* rfc5104 */ |
470 | 8 | /* FIR: http://tools.ietf.org/html/rfc5104#section-4.3.1.1 */ |
471 | 8 | JANUS_LOG(LOG_HUGE, " #%d FIR -- PSFB (206)\n", pno); |
472 | 8 | if(fixssrc && newssrcr) { |
473 | 4 | /* FIR FCI size is 8 bytes */ |
474 | 4 | if (!janus_rtcp_check_fci(rtcp, total, 8)) |
475 | 1 | return -2; |
476 | 3 | rtcpfb->media = htonl(newssrcr); |
477 | 3 | uint32_t *ssrc = (uint32_t *)rtcpfb->fci; |
478 | 3 | *ssrc = htonl(newssrcr); |
479 | 3 | } |
480 | 16 | } else if(fmt == 5) { /* rfc5104 */ |
481 | 0 | /* TSTR: http://tools.ietf.org/html/rfc5104#section-4.3.2.1 */ |
482 | 0 | JANUS_LOG(LOG_HUGE, " #%d PLI -- TSTR (206)\n", pno); |
483 | 16 | } else if(fmt == 15) { |
484 | 16 | //~ JANUS_LOG(LOG_HUGE, " -- This is a AFB!\n"); |
485 | 16 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
486 | 16 | if(fixssrc && newssrcr) { |
487 | 8 | /* AFB FCI size is variable, check just media SSRC */ |
488 | 8 | if (!janus_rtcp_check_fci(rtcp, total, 0)) |
489 | 0 | return -2; |
490 | 8 | rtcpfb->ssrc = htonl(newssrcr); |
491 | 8 | rtcpfb->media = 0; |
492 | 8 | } |
493 | 16 | janus_rtcp_fb_remb *remb = (janus_rtcp_fb_remb *)rtcpfb->fci; |
494 | 16 | if(janus_rtcp_check_remb(rtcp, total) && remb->id[0] == 'R' && remb->id[1] == 'E' && remb->id[2] == 'M' && remb->id[3] == 'B') { |
495 | 8 | JANUS_LOG(LOG_HUGE, " #%d REMB -- PSFB (206)\n", pno); |
496 | 8 | if(fixssrc && newssrcr) { |
497 | 4 | remb->ssrc[0] = htonl(newssrcr); |
498 | 4 | } |
499 | 8 | /* FIXME From rtcp_utility.cc */ |
500 | 8 | unsigned char *_ptrRTCPData = (unsigned char *)remb; |
501 | 8 | _ptrRTCPData += 4; // Skip unique identifier and num ssrc |
502 | 8 | //~ JANUS_LOG(LOG_HUGE, " %02X %02X %02X %02X\n", _ptrRTCPData[0], _ptrRTCPData[1], _ptrRTCPData[2], _ptrRTCPData[3]); |
503 | 8 | uint8_t numssrc = (_ptrRTCPData[0]); |
504 | 8 | uint8_t brExp = (_ptrRTCPData[1] >> 2) & 0x3F; |
505 | 8 | uint32_t brMantissa = (_ptrRTCPData[1] & 0x03) << 16; |
506 | 8 | brMantissa += (_ptrRTCPData[2] << 8); |
507 | 8 | brMantissa += (_ptrRTCPData[3]); |
508 | 8 | uint32_t bitRate = (uint64_t)brMantissa << brExp; |
509 | 8 | JANUS_LOG(LOG_HUGE, " -- -- -- REMB: %u * 2^%u = %"SCNu32" (%d SSRCs, %u)\n", |
510 | 8 | brMantissa, brExp, bitRate, numssrc, ntohl(remb->ssrc[0])); |
511 | 8 | } else { |
512 | 8 | JANUS_LOG(LOG_HUGE, " #%d AFB ?? -- PSFB (206)\n", pno); |
513 | 8 | } |
514 | 16 | } else { |
515 | 0 | JANUS_LOG(LOG_HUGE, " #%d ?? -- PSFB (206, fmt=%d)\n", pno, fmt); |
516 | 0 | } |
517 | 46 | if(fixssrc && newssrcl) { |
518 | 21 | rtcpfb->ssrc = htonl(newssrcl); |
519 | 21 | } |
520 | 44 | break; |
521 | 46 | } |
522 | 46 | case RTCP_XR: { |
523 | 16 | /* XR, extended reports (rfc3611) */ |
524 | 16 | janus_rtcp_xr *xr = (janus_rtcp_xr *)rtcp; |
525 | 16 | if(fixssrc && newssrcl) { |
526 | 8 | xr->ssrc = htonl(newssrcl); |
527 | 8 | } |
528 | 16 | /* TODO Fix report blocks too, once we support them */ |
529 | 16 | break; |
530 | 46 | } |
531 | 46 | default: |
532 | 6 | JANUS_LOG(LOG_ERR, " Unknown RTCP PT %d\n", rtcp->type); |
533 | 6 | break; |
534 | 138 | } |
535 | 138 | /* Is this a compound packet? */ |
536 | 138 | int length = ntohs(rtcp->length); |
537 | 138 | JANUS_LOG(LOG_HUGE, " RTCP PT %d, length: %d bytes\n", rtcp->type, length*4+4); |
538 | 138 | if(length == 0) { |
539 | 0 | //~ JANUS_LOG(LOG_HUGE, " 0-length, end of compound packet\n"); |
540 | 0 | break; |
541 | 0 | } |
542 | 138 | total -= length*4+4; |
543 | 138 | //~ JANUS_LOG(LOG_HUGE, " Packet has length %d (%d bytes, %d remaining), moving to next one...\n", length, length*4+4, total); |
544 | 138 | if(total <= 0) |
545 | 128 | break; |
546 | 10 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
547 | 10 | } |
548 | 146 | return 0; |
549 | 146 | } |
550 | | |
551 | 73 | char *janus_rtcp_filter(char *packet, int len, int *newlen) { |
552 | 73 | if(packet == NULL || len <= 0 || newlen == NULL) |
553 | 73 | return NULL; |
554 | 73 | *newlen = 0; |
555 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
556 | 73 | char *filtered = NULL; |
557 | 73 | int total = len, length = 0, bytes = 0; |
558 | 73 | /* Iterate on the compound packets */ |
559 | 73 | gboolean keep = TRUE; |
560 | 73 | gboolean error = FALSE; |
561 | 78 | while(rtcp) { |
562 | 78 | if (!janus_rtcp_check_len(rtcp, total)) { |
563 | 7 | error = TRUE; |
564 | 7 | break; |
565 | 7 | } |
566 | 71 | if(rtcp->version != 2) { |
567 | 0 | error = TRUE; |
568 | 0 | break; |
569 | 0 | } |
570 | 71 | keep = TRUE; |
571 | 71 | length = ntohs(rtcp->length); |
572 | 71 | if(length == 0) |
573 | 0 | break; |
574 | 71 | bytes = length*4+4; |
575 | 71 | switch(rtcp->type) { |
576 | 71 | case RTCP_SR: |
577 | 21 | case RTCP_RR: |
578 | 21 | case RTCP_SDES: |
579 | 21 | /* These are packets we generate ourselves, so remove them */ |
580 | 21 | keep = FALSE; |
581 | 21 | break; |
582 | 27 | case RTCP_BYE: |
583 | 27 | case RTCP_APP: |
584 | 27 | case RTCP_FIR: |
585 | 27 | case RTCP_PSFB: |
586 | 27 | break; |
587 | 27 | case RTCP_RTPFB: |
588 | 12 | if(rtcp->rc == 1) { |
589 | 1 | /* We handle NACKs ourselves as well, remove this too */ |
590 | 1 | keep = FALSE; |
591 | 1 | break; |
592 | 1 | } |
593 | 11 | break; |
594 | 11 | case RTCP_XR: |
595 | 8 | /* FIXME We generate RR/SR ourselves, so remove XR */ |
596 | 8 | keep = FALSE; |
597 | 8 | break; |
598 | 11 | default: |
599 | 3 | JANUS_LOG(LOG_ERR, "Unknown RTCP PT %d\n", rtcp->type); |
600 | 3 | /* FIXME Should we allow this to go through instead? */ |
601 | 3 | keep = FALSE; |
602 | 3 | break; |
603 | 71 | } |
604 | 71 | if(keep) { |
605 | 38 | /* Keep this packet */ |
606 | 38 | if(filtered == NULL) |
607 | 38 | filtered = g_malloc0(total); |
608 | 38 | memcpy(filtered+*newlen, (char *)rtcp, bytes); |
609 | 38 | *newlen += bytes; |
610 | 38 | } |
611 | 71 | total -= bytes; |
612 | 71 | if(total <= 0) |
613 | 66 | break; |
614 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
615 | 5 | } |
616 | 73 | if (error) { |
617 | 7 | g_free(filtered); |
618 | 7 | filtered = NULL; |
619 | 7 | *newlen = 0; |
620 | 7 | } |
621 | 73 | return filtered; |
622 | 73 | } |
623 | | |
624 | | |
625 | 0 | int janus_rtcp_process_incoming_rtp(janus_rtcp_context *ctx, char *packet, int len, gboolean count_lost) { |
626 | 0 | if(ctx == NULL || packet == NULL || len < 1) |
627 | 0 | return -1; |
628 | 0 | |
629 | 0 | /* First of all, let's check if this is G.711: in case we may need to change the timestamp base */ |
630 | 0 | janus_rtp_header *rtp = (janus_rtp_header *)packet; |
631 | 0 | int pt = rtp->type; |
632 | 0 | if((pt == 0 || pt == 8) && (ctx->tb == 48000)) |
633 | 0 | ctx->tb = 8000; |
634 | 0 | /* Now parse this RTP packet header and update the rtcp_context instance */ |
635 | 0 | uint16_t seq_number = ntohs(rtp->seq_number); |
636 | 0 | if(ctx->base_seq == 0 && ctx->seq_cycle == 0) |
637 | 0 | ctx->base_seq = seq_number; |
638 | 0 |
|
639 | 0 | if((int16_t)(seq_number - ctx->max_seq_nr) < 0) { |
640 | 0 | /* Late packet or retransmission */ |
641 | 0 | ctx->retransmitted++; |
642 | 0 | } else { |
643 | 0 | if(seq_number < ctx->max_seq_nr) |
644 | 0 | ctx->seq_cycle++; |
645 | 0 | ctx->max_seq_nr = seq_number; |
646 | 0 | ctx->received++; |
647 | 0 | } |
648 | 0 | uint32_t rtp_expected = 0x0; |
649 | 0 | if(ctx->seq_cycle > 0) { |
650 | 0 | rtp_expected = ctx->seq_cycle; |
651 | 0 | rtp_expected = rtp_expected << 16; |
652 | 0 | } |
653 | 0 | rtp_expected = rtp_expected + 1 + ctx->max_seq_nr - ctx->base_seq; |
654 | 0 | if(count_lost && rtp_expected >= ctx->received) |
655 | 0 | ctx->lost = rtp_expected - ctx->received; |
656 | 0 | ctx->expected = rtp_expected; |
657 | 0 |
|
658 | 0 | int64_t arrival = (janus_get_monotonic_time() * ctx->tb) / 1000000; |
659 | 0 | int64_t transit = arrival - ntohl(rtp->timestamp); |
660 | 0 | int64_t d = transit - ctx->transit; |
661 | 0 | if (d < 0) d = -d; |
662 | 0 | ctx->transit = transit; |
663 | 0 | ctx->jitter += (1./16.) * ((double)d - ctx->jitter); |
664 | 0 |
|
665 | 0 | /* RTP packet received: it means we can start sending RR */ |
666 | 0 | ctx->rtp_recvd = 1; |
667 | 0 |
|
668 | 0 | return 0; |
669 | 0 | } |
670 | | |
671 | | |
672 | 0 | uint32_t janus_rtcp_context_get_rtt(janus_rtcp_context *ctx) { |
673 | 0 | return ctx ? ctx->rtt : 0; |
674 | 0 | } |
675 | | |
676 | 0 | uint32_t janus_rtcp_context_get_in_link_quality(janus_rtcp_context *ctx) { |
677 | 0 | return ctx ? (uint32_t)(ctx->in_link_quality + 0.5) : 0; |
678 | 0 | } |
679 | | |
680 | 0 | uint32_t janus_rtcp_context_get_in_media_link_quality(janus_rtcp_context *ctx) { |
681 | 0 | return ctx ? (uint32_t)(ctx->in_media_link_quality + 0.5) : 0; |
682 | 0 | } |
683 | | |
684 | 0 | uint32_t janus_rtcp_context_get_out_link_quality(janus_rtcp_context *ctx) { |
685 | 0 | return ctx ? (uint32_t)(ctx->out_link_quality + 0.5) : 0; |
686 | 0 | } |
687 | | |
688 | 0 | uint32_t janus_rtcp_context_get_out_media_link_quality(janus_rtcp_context *ctx) { |
689 | 0 | return ctx ? (uint32_t)(ctx->out_media_link_quality + 0.5) : 0; |
690 | 0 | } |
691 | | |
692 | 0 | uint32_t janus_rtcp_context_get_lost_all(janus_rtcp_context *ctx, gboolean remote) { |
693 | 0 | if(ctx == NULL) |
694 | 0 | return 0; |
695 | 0 | return remote ? ctx->lost_remote : ctx->lost; |
696 | 0 | } |
697 | | |
698 | 0 | static uint32_t janus_rtcp_context_get_lost(janus_rtcp_context *ctx) { |
699 | 0 | if(ctx == NULL) |
700 | 0 | return 0; |
701 | 0 | uint32_t lost; |
702 | 0 | if(ctx->lost > 0x7FFFFF) { |
703 | 0 | lost = 0x7FFFFF; |
704 | 0 | } else { |
705 | 0 | lost = ctx->lost; |
706 | 0 | } |
707 | 0 | return lost; |
708 | 0 | } |
709 | | |
710 | 0 | static uint32_t janus_rtcp_context_get_lost_fraction(janus_rtcp_context *ctx) { |
711 | 0 | if(ctx == NULL) |
712 | 0 | return 0; |
713 | 0 | uint32_t expected_interval = ctx->expected - ctx->expected_prior; |
714 | 0 | uint32_t received_interval = ctx->received - ctx->received_prior; |
715 | 0 | int32_t lost_interval = expected_interval - received_interval; |
716 | 0 | uint32_t fraction; |
717 | 0 | if(expected_interval == 0 || lost_interval <=0) |
718 | 0 | fraction = 0; |
719 | 0 | else |
720 | 0 | fraction = (lost_interval << 8) / expected_interval; |
721 | 0 | return fraction << 24; |
722 | 0 | } |
723 | | |
724 | 0 | uint32_t janus_rtcp_context_get_jitter(janus_rtcp_context *ctx, gboolean remote) { |
725 | 0 | if(ctx == NULL || ctx->tb == 0) |
726 | 0 | return 0; |
727 | 0 | return (uint32_t) floor((remote ? ctx->jitter_remote : ctx->jitter) * 1000.0 / ctx->tb); |
728 | 0 | } |
729 | | |
730 | 0 | static void janus_rtcp_estimate_in_link_quality(janus_rtcp_context *ctx) { |
731 | 0 | int64_t ts = janus_get_monotonic_time(); |
732 | 0 | int64_t delta_t = ts - ctx->out_rr_last_ts; |
733 | 0 | if(delta_t < 3*G_USEC_PER_SEC) { |
734 | 0 | return; |
735 | 0 | } |
736 | 0 | ctx->out_rr_last_ts = ts; |
737 | 0 |
|
738 | 0 | uint32_t expected_interval = ctx->expected - ctx->expected_prior; |
739 | 0 | uint32_t received_interval = ctx->received - ctx->received_prior; |
740 | 0 | uint32_t retransmitted_interval = ctx->retransmitted - ctx->retransmitted_prior; |
741 | 0 |
|
742 | 0 | int32_t link_lost = expected_interval - (received_interval - retransmitted_interval); |
743 | 0 | double link_q = !expected_interval ? 0 : 100.0 - (100.0 * (double)link_lost / (double)expected_interval); |
744 | 0 | ctx->in_link_quality = janus_rtcp_link_quality_filter(ctx->in_link_quality, link_q); |
745 | 0 |
|
746 | 0 | int32_t lost = expected_interval - received_interval; |
747 | 0 | if (lost < 0) { |
748 | 0 | lost = 0; |
749 | 0 | } |
750 | 0 | double media_link_q = !expected_interval ? 0 : 100.0 - (100.0 * (double)lost / (double)expected_interval); |
751 | 0 | ctx->in_media_link_quality = janus_rtcp_link_quality_filter(ctx->in_media_link_quality, media_link_q); |
752 | 0 |
|
753 | 0 | JANUS_LOG(LOG_HUGE, "In link quality=%"SCNu32", media link quality=%"SCNu32"\n", janus_rtcp_context_get_in_link_quality(ctx), janus_rtcp_context_get_in_media_link_quality(ctx)); |
754 | 0 | } |
755 | | |
756 | 0 | int janus_rtcp_report_block(janus_rtcp_context *ctx, janus_report_block *rb) { |
757 | 0 | if(ctx == NULL || rb == NULL) |
758 | 0 | return -1; |
759 | 0 | gint64 now = janus_get_monotonic_time(); |
760 | 0 | rb->jitter = htonl((uint32_t) ctx->jitter); |
761 | 0 | rb->ehsnr = htonl((((uint32_t) 0x0 + ctx->seq_cycle) << 16) + ctx->max_seq_nr); |
762 | 0 | uint32_t lost = janus_rtcp_context_get_lost(ctx); |
763 | 0 | uint32_t fraction = janus_rtcp_context_get_lost_fraction(ctx); |
764 | 0 | janus_rtcp_estimate_in_link_quality(ctx); |
765 | 0 | ctx->expected_prior = ctx->expected; |
766 | 0 | ctx->received_prior = ctx->received; |
767 | 0 | ctx->retransmitted_prior = ctx->retransmitted; |
768 | 0 | rb->flcnpl = htonl(lost | fraction); |
769 | 0 | if(ctx->lsr > 0) { |
770 | 0 | rb->lsr = htonl(ctx->lsr); |
771 | 0 | rb->delay = htonl(((now - ctx->lsr_ts) << 16) / 1000000); |
772 | 0 | } else { |
773 | 0 | rb->lsr = 0; |
774 | 0 | rb->delay = 0; |
775 | 0 | } |
776 | 0 | ctx->last_sent = now; |
777 | 0 | return 0; |
778 | 0 | } |
779 | | |
780 | 73 | int janus_rtcp_fix_report_data(char *packet, int len, uint32_t base_ts, uint32_t base_ts_prev, uint32_t ssrc_peer, uint32_t ssrc_local, uint32_t ssrc_expected, gboolean video) { |
781 | 73 | if(packet == NULL || len <= 0) |
782 | 0 | return -1; |
783 | 73 | /* Parse RTCP compound packet */ |
784 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
785 | 73 | int pno = 0, total = len, status = 0; |
786 | 77 | while(rtcp) { |
787 | 77 | if (!janus_rtcp_check_len(rtcp, total)) |
788 | 7 | return -2; |
789 | 70 | if(rtcp->version != 2) |
790 | 0 | return -2; |
791 | 70 | pno++; |
792 | 70 | switch(rtcp->type) { |
793 | 70 | case RTCP_RR: { |
794 | 6 | if (!janus_rtcp_check_rr(rtcp, total)) |
795 | 0 | return -2; |
796 | 6 | janus_rtcp_rr *rr = (janus_rtcp_rr *)rtcp; |
797 | 6 | rr->ssrc = htonl(ssrc_peer); |
798 | 6 | status++; |
799 | 6 | if (rr->header.rc > 0) { |
800 | 4 | rr->rb[0].ssrc = htonl(ssrc_local); |
801 | 4 | status++; |
802 | 4 | /* FIXME we need to fix the extended highest sequence number received */ |
803 | 4 | /* FIXME we need to fix the cumulative number of packets lost */ |
804 | 4 | break; |
805 | 4 | } |
806 | 2 | break; |
807 | 2 | } |
808 | 3 | case RTCP_SR: { |
809 | 3 | if (!janus_rtcp_check_sr(rtcp, total)) |
810 | 0 | return -2; |
811 | 3 | janus_rtcp_sr *sr = (janus_rtcp_sr *)rtcp; |
812 | 3 | uint32_t recv_ssrc = ntohl(sr->ssrc); |
813 | 3 | if (recv_ssrc != ssrc_expected) { |
814 | 3 | JANUS_LOG(LOG_WARN,"Incoming RTCP SR SSRC (%"SCNu32") does not match the expected one (%"SCNu32") video=%d\n", recv_ssrc, ssrc_expected, video); |
815 | 3 | return -3; |
816 | 3 | } |
817 | 0 | sr->ssrc = htonl(ssrc_peer); |
818 | 0 | /* FIXME we need to fix the sender's packet count */ |
819 | 0 | /* FIXME we need to fix the sender's octet count */ |
820 | 0 | uint32_t sr_ts = ntohl(sr->si.rtp_ts); |
821 | 0 | uint32_t fix_ts = (sr_ts - base_ts) + base_ts_prev; |
822 | 0 | sr->si.rtp_ts = htonl(fix_ts); |
823 | 0 | status++; |
824 | 0 | if (sr->header.rc > 0) { |
825 | 0 | sr->rb[0].ssrc = htonl(ssrc_local); |
826 | 0 | status++; |
827 | 0 | /* FIXME we need to fix the extended highest sequence number received */ |
828 | 0 | /* FIXME we need to fix the cumulative number of packets lost */ |
829 | 0 | break; |
830 | 0 | } |
831 | 0 | break; |
832 | 0 | } |
833 | 61 | default: |
834 | 61 | break; |
835 | 67 | } |
836 | 67 | /* Is this a compound packet? */ |
837 | 67 | int length = ntohs(rtcp->length); |
838 | 67 | if(length == 0) |
839 | 0 | break; |
840 | 67 | total -= length*4+4; |
841 | 67 | if(total <= 0) |
842 | 63 | break; |
843 | 4 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
844 | 4 | } |
845 | 73 | return status; |
846 | 73 | } |
847 | | |
848 | 73 | gboolean janus_rtcp_has_bye(char *packet, int len) { |
849 | 73 | /* Parse RTCP compound packet */ |
850 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
851 | 73 | int pno = 0, total = len; |
852 | 78 | while(rtcp) { |
853 | 78 | if (!janus_rtcp_check_len(rtcp, total)) |
854 | 7 | break; |
855 | 71 | if(rtcp->version != 2) |
856 | 0 | break; |
857 | 71 | pno++; |
858 | 71 | switch(rtcp->type) { |
859 | 71 | case RTCP_BYE: |
860 | 4 | return TRUE; |
861 | 71 | default: |
862 | 67 | break; |
863 | 67 | } |
864 | 67 | /* Is this a compound packet? */ |
865 | 67 | int length = ntohs(rtcp->length); |
866 | 67 | if(length == 0) |
867 | 0 | break; |
868 | 67 | total -= length*4+4; |
869 | 67 | if(total <= 0) |
870 | 62 | break; |
871 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
872 | 5 | } |
873 | 73 | return FALSE; |
874 | 73 | } |
875 | | |
876 | 73 | gboolean janus_rtcp_has_fir(char *packet, int len) { |
877 | 73 | /* Parse RTCP compound packet */ |
878 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
879 | 73 | int pno = 0, total = len; |
880 | 78 | while(rtcp) { |
881 | 78 | if (!janus_rtcp_check_len(rtcp, total)) |
882 | 7 | break; |
883 | 71 | if(rtcp->version != 2) |
884 | 0 | break; |
885 | 71 | pno++; |
886 | 71 | switch(rtcp->type) { |
887 | 71 | case RTCP_FIR: |
888 | 0 | return TRUE; |
889 | 71 | default: |
890 | 71 | break; |
891 | 71 | } |
892 | 71 | /* Is this a compound packet? */ |
893 | 71 | int length = ntohs(rtcp->length); |
894 | 71 | if(length == 0) |
895 | 0 | break; |
896 | 71 | total -= length*4+4; |
897 | 71 | if(total <= 0) |
898 | 66 | break; |
899 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
900 | 5 | } |
901 | 73 | return FALSE; |
902 | 73 | } |
903 | | |
904 | 73 | gboolean janus_rtcp_has_pli(char *packet, int len) { |
905 | 73 | /* Parse RTCP compound packet */ |
906 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
907 | 73 | int pno = 0, total = len; |
908 | 78 | while(rtcp) { |
909 | 78 | if (!janus_rtcp_check_len(rtcp, total)) |
910 | 7 | break; |
911 | 71 | if(rtcp->version != 2) |
912 | 0 | break; |
913 | 71 | pno++; |
914 | 71 | switch(rtcp->type) { |
915 | 71 | case RTCP_PSFB: { |
916 | 23 | gint fmt = rtcp->rc; |
917 | 23 | if(fmt == 1) |
918 | 3 | return TRUE; |
919 | 20 | break; |
920 | 20 | } |
921 | 48 | default: |
922 | 48 | break; |
923 | 68 | } |
924 | 68 | /* Is this a compound packet? */ |
925 | 68 | int length = ntohs(rtcp->length); |
926 | 68 | if(length == 0) |
927 | 0 | break; |
928 | 68 | total -= length*4+4; |
929 | 68 | if(total <= 0) |
930 | 63 | break; |
931 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
932 | 5 | } |
933 | 73 | return FALSE; |
934 | 73 | } |
935 | | |
936 | 73 | GSList *janus_rtcp_get_nacks(char *packet, int len) { |
937 | 73 | if(packet == NULL || len == 0) |
938 | 0 | return NULL; |
939 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
940 | 73 | /* FIXME Get list of sequence numbers we should send again */ |
941 | 73 | GSList *list = NULL; |
942 | 73 | int total = len; |
943 | 73 | gboolean error = FALSE; |
944 | 78 | while(rtcp) { |
945 | 78 | if (!janus_rtcp_check_len(rtcp, total)) { |
946 | 7 | error = TRUE; |
947 | 7 | break; |
948 | 7 | } |
949 | 71 | if (rtcp->version != 2) { |
950 | 0 | error = TRUE; |
951 | 0 | break; |
952 | 0 | } |
953 | 71 | if(rtcp->type == RTCP_RTPFB) { |
954 | 12 | gint fmt = rtcp->rc; |
955 | 12 | if(fmt == 1) { |
956 | 1 | /* NACK FCI size is 4 bytes */ |
957 | 1 | if (!janus_rtcp_check_fci(rtcp, total, 4)) { |
958 | 0 | error = TRUE; |
959 | 0 | break; |
960 | 0 | } |
961 | 1 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
962 | 1 | int nacks = ntohs(rtcp->length)-2; /* Skip SSRCs */ |
963 | 1 | if(nacks > 0) { |
964 | 1 | JANUS_LOG(LOG_DBG, " Got %d nacks\n", nacks); |
965 | 1 | janus_rtcp_nack *nack = NULL; |
966 | 1 | uint16_t pid = 0; |
967 | 1 | uint16_t blp = 0; |
968 | 1 | int i=0, j=0; |
969 | 1 | char bitmask[20]; |
970 | 2 | for(i=0; i< nacks; i++) { |
971 | 1 | nack = (janus_rtcp_nack *)rtcpfb->fci + i; |
972 | 1 | pid = ntohs(nack->pid); |
973 | 1 | list = g_slist_append(list, GUINT_TO_POINTER(pid)); |
974 | 1 | blp = ntohs(nack->blp); |
975 | 1 | memset(bitmask, 0, 20); |
976 | 17 | for(j=0; j<16; j++) { |
977 | 16 | bitmask[j] = (blp & ( 1 << j )) >> j ? '1' : '0'; |
978 | 16 | if((blp & ( 1 << j )) >> j) |
979 | 1 | list = g_slist_append(list, GUINT_TO_POINTER(pid+j+1)); |
980 | 16 | } |
981 | 1 | bitmask[16] = '\n'; |
982 | 1 | JANUS_LOG(LOG_DBG, "[%d] %"SCNu16" / %s\n", i, pid, bitmask); |
983 | 1 | } |
984 | 1 | } |
985 | 1 | break; |
986 | 1 | } |
987 | 12 | } |
988 | 70 | /* Is this a compound packet? */ |
989 | 70 | int length = ntohs(rtcp->length); |
990 | 70 | if(length == 0) |
991 | 0 | break; |
992 | 70 | total -= length*4+4; |
993 | 70 | if(total <= 0) |
994 | 65 | break; |
995 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
996 | 5 | } |
997 | 73 | if (error && list) { |
998 | 0 | g_slist_free(list); |
999 | 0 | list = NULL; |
1000 | 0 | } |
1001 | 73 | return list; |
1002 | 73 | } |
1003 | | |
1004 | 73 | int janus_rtcp_remove_nacks(char *packet, int len) { |
1005 | 73 | if(packet == NULL || len == 0) |
1006 | 0 | return len; |
1007 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1008 | 73 | /* Find the NACK message */ |
1009 | 73 | char *nacks = NULL; |
1010 | 73 | int total = len, nacks_len = 0; |
1011 | 78 | while(rtcp) { |
1012 | 78 | if (!janus_rtcp_check_len(rtcp, total)) { |
1013 | 7 | break; |
1014 | 7 | } |
1015 | 71 | if(rtcp->version != 2) |
1016 | 0 | break; |
1017 | 71 | if(rtcp->type == RTCP_RTPFB) { |
1018 | 12 | gint fmt = rtcp->rc; |
1019 | 12 | if(fmt == 1) { |
1020 | 1 | nacks = (char *)rtcp; |
1021 | 1 | if (!janus_rtcp_check_fci(rtcp, total, 4)) { |
1022 | 0 | break; |
1023 | 0 | } |
1024 | 71 | } |
1025 | 12 | } |
1026 | 71 | /* Is this a compound packet? */ |
1027 | 71 | int length = ntohs(rtcp->length); |
1028 | 71 | if(length == 0) |
1029 | 0 | break; |
1030 | 71 | if(nacks != NULL) { |
1031 | 1 | nacks_len = length*4+4; |
1032 | 1 | break; |
1033 | 1 | } |
1034 | 70 | total -= length*4+4; |
1035 | 70 | if(total <= 0) |
1036 | 65 | break; |
1037 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
1038 | 5 | } |
1039 | 73 | if(nacks != NULL) { |
1040 | 1 | total = len - ((nacks-packet)+nacks_len); |
1041 | 1 | if(total < 0) { |
1042 | 0 | /* FIXME Should never happen, but you never know: do nothing */ |
1043 | 0 | return len; |
1044 | 1 | } else if(total == 0) { |
1045 | 1 | /* NACK was the last compound packet, easy enough */ |
1046 | 1 | return len-nacks_len; |
1047 | 1 | } else { |
1048 | 0 | /* NACK is between two compound packets, move them around */ |
1049 | 0 | int i=0; |
1050 | 0 | for(i=0; i<total; i++) |
1051 | 0 | *(nacks+i) = *(nacks+nacks_len+i); |
1052 | 0 | return len-nacks_len; |
1053 | 0 | } |
1054 | 72 | } |
1055 | 72 | return len; |
1056 | 72 | } |
1057 | | |
1058 | | /* Query an existing REMB message */ |
1059 | 73 | uint32_t janus_rtcp_get_remb(char *packet, int len) { |
1060 | 73 | if(packet == NULL || len == 0) |
1061 | 0 | return 0; |
1062 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1063 | 73 | /* Get REMB bitrate, if any */ |
1064 | 73 | int total = len; |
1065 | 78 | while(rtcp) { |
1066 | 78 | if (!janus_rtcp_check_len(rtcp, total)) |
1067 | 7 | break; |
1068 | 71 | if(rtcp->version != 2) |
1069 | 0 | break; |
1070 | 71 | if(rtcp->type == RTCP_PSFB) { |
1071 | 23 | gint fmt = rtcp->rc; |
1072 | 23 | if(fmt == 15) { |
1073 | 8 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1074 | 8 | janus_rtcp_fb_remb *remb = (janus_rtcp_fb_remb *)rtcpfb->fci; |
1075 | 8 | if(janus_rtcp_check_remb(rtcp, total) && remb->id[0] == 'R' && remb->id[1] == 'E' && remb->id[2] == 'M' && remb->id[3] == 'B') { |
1076 | 4 | /* FIXME From rtcp_utility.cc */ |
1077 | 4 | unsigned char *_ptrRTCPData = (unsigned char *)remb; |
1078 | 4 | _ptrRTCPData += 4; /* Skip unique identifier and num ssrc */ |
1079 | 4 | //~ JANUS_LOG(LOG_VERB, " %02X %02X %02X %02X\n", _ptrRTCPData[0], _ptrRTCPData[1], _ptrRTCPData[2], _ptrRTCPData[3]); |
1080 | 4 | uint8_t brExp = (_ptrRTCPData[1] >> 2) & 0x3F; |
1081 | 4 | uint32_t brMantissa = (_ptrRTCPData[1] & 0x03) << 16; |
1082 | 4 | brMantissa += (_ptrRTCPData[2] << 8); |
1083 | 4 | brMantissa += (_ptrRTCPData[3]); |
1084 | 4 | uint32_t bitrate = (uint64_t)brMantissa << brExp; |
1085 | 4 | JANUS_LOG(LOG_HUGE, "Got REMB bitrate %"SCNu32"\n", bitrate); |
1086 | 4 | return bitrate; |
1087 | 4 | } |
1088 | 67 | } |
1089 | 23 | } |
1090 | 67 | /* Is this a compound packet? */ |
1091 | 67 | int length = ntohs(rtcp->length); |
1092 | 67 | if(length == 0) |
1093 | 0 | break; |
1094 | 67 | total -= length*4+4; |
1095 | 67 | if(total <= 0) |
1096 | 62 | break; |
1097 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
1098 | 5 | } |
1099 | 73 | return 0; |
1100 | 73 | } |
1101 | | |
1102 | | /* Change an existing REMB message */ |
1103 | 73 | int janus_rtcp_cap_remb(char *packet, int len, uint32_t bitrate) { |
1104 | 73 | if(packet == NULL || len == 0) |
1105 | 0 | return -1; |
1106 | 73 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1107 | 73 | if(bitrate == 0) |
1108 | 0 | return 0; /* No need to cap */ |
1109 | 73 | /* Cap REMB bitrate */ |
1110 | 73 | int total = len; |
1111 | 78 | while(rtcp) { |
1112 | 78 | if (!janus_rtcp_check_len(rtcp, total)) |
1113 | 7 | return -2; |
1114 | 71 | if(rtcp->version != 2) |
1115 | 0 | return -2; |
1116 | 71 | if(rtcp->type == RTCP_PSFB) { |
1117 | 23 | gint fmt = rtcp->rc; |
1118 | 23 | if(fmt == 15) { |
1119 | 8 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1120 | 8 | janus_rtcp_fb_remb *remb = (janus_rtcp_fb_remb *)rtcpfb->fci; |
1121 | 8 | if(janus_rtcp_check_remb(rtcp, total) && remb->id[0] == 'R' && remb->id[1] == 'E' && remb->id[2] == 'M' && remb->id[3] == 'B') { |
1122 | 4 | /* FIXME From rtcp_utility.cc */ |
1123 | 4 | unsigned char *_ptrRTCPData = (unsigned char *)remb; |
1124 | 4 | _ptrRTCPData += 4; /* Skip unique identifier and num ssrc */ |
1125 | 4 | //~ JANUS_LOG(LOG_VERB, " %02X %02X %02X %02X\n", _ptrRTCPData[0], _ptrRTCPData[1], _ptrRTCPData[2], _ptrRTCPData[3]); |
1126 | 4 | uint8_t brExp = (_ptrRTCPData[1] >> 2) & 0x3F; |
1127 | 4 | uint32_t brMantissa = (_ptrRTCPData[1] & 0x03) << 16; |
1128 | 4 | brMantissa += (_ptrRTCPData[2] << 8); |
1129 | 4 | brMantissa += (_ptrRTCPData[3]); |
1130 | 4 | uint32_t origbitrate = (uint64_t)brMantissa << brExp; |
1131 | 4 | if(origbitrate > bitrate) { |
1132 | 3 | JANUS_LOG(LOG_HUGE, "Got REMB bitrate %"SCNu32", need to cap it to %"SCNu32"\n", origbitrate, bitrate); |
1133 | 3 | JANUS_LOG(LOG_HUGE, " >> %u * 2^%u = %"SCNu32"\n", brMantissa, brExp, origbitrate); |
1134 | 3 | /* bitrate --> brexp/brmantissa */ |
1135 | 3 | uint8_t b = 0; |
1136 | 3 | uint8_t newbrexp = 0; |
1137 | 3 | uint32_t newbrmantissa = 0; |
1138 | 3 | for(b=0; b<32; b++) { |
1139 | 3 | if(bitrate <= ((uint32_t) 0x3FFFF << b)) { |
1140 | 3 | newbrexp = b; |
1141 | 3 | break; |
1142 | 3 | } |
1143 | 3 | } |
1144 | 3 | if(b > 31) |
1145 | 0 | b = 31; |
1146 | 3 | newbrmantissa = bitrate >> b; |
1147 | 3 | JANUS_LOG(LOG_HUGE, "new brexp: %"SCNu8"\n", newbrexp); |
1148 | 3 | JANUS_LOG(LOG_HUGE, "new brmantissa: %"SCNu32"\n", newbrmantissa); |
1149 | 3 | /* FIXME From rtcp_sender.cc */ |
1150 | 3 | _ptrRTCPData[1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03)); |
1151 | 3 | _ptrRTCPData[2] = (uint8_t)(newbrmantissa >> 8); |
1152 | 3 | _ptrRTCPData[3] = (uint8_t)(newbrmantissa); |
1153 | 3 | } |
1154 | 4 | } |
1155 | 8 | } |
1156 | 23 | } |
1157 | 71 | /* Is this a compound packet? */ |
1158 | 71 | int length = ntohs(rtcp->length); |
1159 | 71 | if(length == 0) |
1160 | 0 | break; |
1161 | 71 | total -= length*4+4; |
1162 | 71 | if(total <= 0) |
1163 | 66 | break; |
1164 | 5 | rtcp = (janus_rtcp_header *)((uint32_t*)rtcp + length + 1); |
1165 | 5 | } |
1166 | 73 | return 0; |
1167 | 73 | } |
1168 | | |
1169 | | /* Generate a new SDES message */ |
1170 | 0 | int janus_rtcp_sdes_cname(char *packet, int len, const char *cname, int cnamelen) { |
1171 | 0 | if(packet == NULL || len <= 0 || cname == NULL || cnamelen <= 0) |
1172 | 0 | return -1; |
1173 | 0 | memset(packet, 0, len); |
1174 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1175 | 0 | /* Set header */ |
1176 | 0 | rtcp->version = 2; |
1177 | 0 | rtcp->type = RTCP_SDES; |
1178 | 0 | rtcp->rc = 1; |
1179 | 0 | int plen = 8; /* Header + chunk + item header */ |
1180 | 0 | plen += cnamelen+3; /* cname item header(2) + cnamelen + terminator(1) */ |
1181 | 0 | /* calculate padding length. assume that plen is shorter than 65535 */ |
1182 | 0 | plen = (plen + 3) & 0xFFFC; |
1183 | 0 | if(len < plen) { |
1184 | 0 | JANUS_LOG(LOG_ERR, "Buffer too small for SDES message: %d < %d\n", len, plen); |
1185 | 0 | return -1; |
1186 | 0 | } |
1187 | 0 | rtcp->length = htons((plen/4)-1); |
1188 | 0 | /* Now set SDES stuff */ |
1189 | 0 | janus_rtcp_sdes *rtcpsdes = (janus_rtcp_sdes *)rtcp; |
1190 | 0 | rtcpsdes->item.type = 1; |
1191 | 0 | rtcpsdes->item.len = cnamelen; |
1192 | 0 | memcpy(rtcpsdes->item.content, cname, cnamelen); |
1193 | 0 | return plen; |
1194 | 0 | } |
1195 | | |
1196 | | /* Generate a new REMB message */ |
1197 | 0 | int janus_rtcp_remb(char *packet, int len, uint32_t bitrate) { |
1198 | 0 | /* By default we assume a single SSRC will be set */ |
1199 | 0 | return janus_rtcp_remb_ssrcs(packet, len, bitrate, 1); |
1200 | 0 | } |
1201 | | |
1202 | 0 | int janus_rtcp_remb_ssrcs(char *packet, int len, uint32_t bitrate, uint8_t numssrc) { |
1203 | 0 | if(packet == NULL || numssrc == 0) |
1204 | 0 | return -1; |
1205 | 0 | int min_len = 20 + numssrc*4; |
1206 | 0 | if(len < min_len) |
1207 | 0 | return -1; |
1208 | 0 | memset(packet, 0, len); |
1209 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1210 | 0 | /* Set header */ |
1211 | 0 | rtcp->version = 2; |
1212 | 0 | rtcp->type = RTCP_PSFB; |
1213 | 0 | rtcp->rc = 15; |
1214 | 0 | rtcp->length = htons((min_len/4)-1); |
1215 | 0 | /* Now set REMB stuff */ |
1216 | 0 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1217 | 0 | janus_rtcp_fb_remb *remb = (janus_rtcp_fb_remb *)rtcpfb->fci; |
1218 | 0 | remb->id[0] = 'R'; |
1219 | 0 | remb->id[1] = 'E'; |
1220 | 0 | remb->id[2] = 'M'; |
1221 | 0 | remb->id[3] = 'B'; |
1222 | 0 | /* bitrate --> brexp/brmantissa */ |
1223 | 0 | uint8_t b = 0; |
1224 | 0 | uint8_t newbrexp = 0; |
1225 | 0 | uint32_t newbrmantissa = 0; |
1226 | 0 | for(b=0; b<32; b++) { |
1227 | 0 | if(bitrate <= ((uint32_t) 0x3FFFF << b)) { |
1228 | 0 | newbrexp = b; |
1229 | 0 | break; |
1230 | 0 | } |
1231 | 0 | } |
1232 | 0 | if(b > 31) |
1233 | 0 | b = 31; |
1234 | 0 | newbrmantissa = bitrate >> b; |
1235 | 0 | /* FIXME From rtcp_sender.cc */ |
1236 | 0 | unsigned char *_ptrRTCPData = (unsigned char *)remb; |
1237 | 0 | _ptrRTCPData += 4; /* Skip unique identifier */ |
1238 | 0 | _ptrRTCPData[0] = numssrc; |
1239 | 0 | _ptrRTCPData[1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03)); |
1240 | 0 | _ptrRTCPData[2] = (uint8_t)(newbrmantissa >> 8); |
1241 | 0 | _ptrRTCPData[3] = (uint8_t)(newbrmantissa); |
1242 | 0 | JANUS_LOG(LOG_HUGE, "[REMB] bitrate=%"SCNu32" (%d bytes)\n", bitrate, 4*(ntohs(rtcp->length)+1)); |
1243 | 0 | return min_len; |
1244 | 0 | } |
1245 | | |
1246 | | /* Generate a new FIR message */ |
1247 | 0 | int janus_rtcp_fir(char *packet, int len, int *seqnr) { |
1248 | 0 | if(packet == NULL || len != 20 || seqnr == NULL) |
1249 | 0 | return -1; |
1250 | 0 | memset(packet, 0, len); |
1251 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1252 | 0 | *seqnr = *seqnr + 1; |
1253 | 0 | if(*seqnr < 0 || *seqnr >= 256) |
1254 | 0 | *seqnr = 0; /* Reset sequence number */ |
1255 | 0 | /* Set header */ |
1256 | 0 | rtcp->version = 2; |
1257 | 0 | rtcp->type = RTCP_PSFB; |
1258 | 0 | rtcp->rc = 4; /* FMT=4 */ |
1259 | 0 | rtcp->length = htons((len/4)-1); |
1260 | 0 | /* Now set FIR stuff */ |
1261 | 0 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1262 | 0 | janus_rtcp_fb_fir *fir = (janus_rtcp_fb_fir *)rtcpfb->fci; |
1263 | 0 | fir->seqnr = htonl(*seqnr << 24); /* FCI: Sequence number */ |
1264 | 0 | JANUS_LOG(LOG_HUGE, "[FIR] seqnr=%d (%d bytes)\n", *seqnr, 4*(ntohs(rtcp->length)+1)); |
1265 | 0 | return 20; |
1266 | 0 | } |
1267 | | |
1268 | | /* Generate a new PLI message */ |
1269 | 0 | int janus_rtcp_pli(char *packet, int len) { |
1270 | 0 | if(packet == NULL || len != 12) |
1271 | 0 | return -1; |
1272 | 0 | memset(packet, 0, len); |
1273 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1274 | 0 | /* Set header */ |
1275 | 0 | rtcp->version = 2; |
1276 | 0 | rtcp->type = RTCP_PSFB; |
1277 | 0 | rtcp->rc = 1; /* FMT=1 */ |
1278 | 0 | rtcp->length = htons((len/4)-1); |
1279 | 0 | return 12; |
1280 | 0 | } |
1281 | | |
1282 | | /* Generate a new NACK message */ |
1283 | 0 | int janus_rtcp_nacks(char *packet, int len, GSList *nacks) { |
1284 | 0 | if(packet == NULL || len < 16 || nacks == NULL) |
1285 | 0 | return -1; |
1286 | 0 | memset(packet, 0, len); |
1287 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1288 | 0 | /* Set header */ |
1289 | 0 | rtcp->version = 2; |
1290 | 0 | rtcp->type = RTCP_RTPFB; |
1291 | 0 | rtcp->rc = 1; /* FMT=1 */ |
1292 | 0 | /* Now set NACK stuff */ |
1293 | 0 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1294 | 0 | janus_rtcp_nack *nack = (janus_rtcp_nack *)rtcpfb->fci; |
1295 | 0 | /* FIXME We assume the GSList list is already ordered... */ |
1296 | 0 | guint16 pid = GPOINTER_TO_UINT(nacks->data); |
1297 | 0 | nack->pid = htons(pid); |
1298 | 0 | nacks = nacks->next; |
1299 | 0 | int words = 3; |
1300 | 0 | while(nacks) { |
1301 | 0 | guint16 npid = GPOINTER_TO_UINT(nacks->data); |
1302 | 0 | if(npid-pid < 1) { |
1303 | 0 | JANUS_LOG(LOG_HUGE, "Skipping PID to NACK (%"SCNu16" already added)...\n", npid); |
1304 | 0 | } else if(npid-pid > 16) { |
1305 | 0 | /* We need a new block: this sequence number will be its root PID */ |
1306 | 0 | JANUS_LOG(LOG_HUGE, "Adding another block of NACKs (%"SCNu16"-%"SCNu16" > 16)...\n", npid, pid); |
1307 | 0 | words++; |
1308 | 0 | if(len < (words*4+4)) { |
1309 | 0 | JANUS_LOG(LOG_ERR, "Buffer too small: %d < %d (at least %d NACK blocks needed)\n", len, words*4+4, words); |
1310 | 0 | return -1; |
1311 | 0 | } |
1312 | 0 | char *new_block = packet + words*4; |
1313 | 0 | nack = (janus_rtcp_nack *)new_block; |
1314 | 0 | pid = GPOINTER_TO_UINT(nacks->data); |
1315 | 0 | nack->pid = htons(pid); |
1316 | 0 | } else { |
1317 | 0 | uint16_t blp = ntohs(nack->blp); |
1318 | 0 | blp |= 1 << (npid-pid-1); |
1319 | 0 | nack->blp = htons(blp); |
1320 | 0 | } |
1321 | 0 | nacks = nacks->next; |
1322 | 0 | } |
1323 | 0 | rtcp->length = htons(words); |
1324 | 0 | return words*4+4; |
1325 | 0 | } |
1326 | | |
1327 | | typedef enum janus_rtp_packet_status { |
1328 | | janus_rtp_packet_status_notreceived = 0, |
1329 | | janus_rtp_packet_status_smalldelta = 1, |
1330 | | janus_rtp_packet_status_largeornegativedelta = 2, |
1331 | | janus_rtp_packet_status_reserved = 3 |
1332 | | } janus_rtp_packet_status; |
1333 | | |
1334 | 0 | int janus_rtcp_transport_wide_cc_feedback(char *packet, size_t size, guint32 ssrc, guint32 media, guint8 feedback_packet_count, GQueue *transport_wide_cc_stats) { |
1335 | 0 | if(packet == NULL || size < sizeof(janus_rtcp_header) || transport_wide_cc_stats == NULL || g_queue_is_empty(transport_wide_cc_stats)) |
1336 | 0 | return -1; |
1337 | 0 | |
1338 | 0 | memset(packet, 0, size); |
1339 | 0 | janus_rtcp_header *rtcp = (janus_rtcp_header *)packet; |
1340 | 0 | /* Set header */ |
1341 | 0 | rtcp->version = 2; |
1342 | 0 | rtcp->type = RTCP_RTPFB; |
1343 | 0 | rtcp->rc = 15; |
1344 | 0 | /* Now set FB stuff */ |
1345 | 0 | janus_rtcp_fb *rtcpfb = (janus_rtcp_fb *)rtcp; |
1346 | 0 | rtcpfb->ssrc = htonl(ssrc); |
1347 | 0 | rtcpfb->media = htonl(media); |
1348 | 0 |
|
1349 | 0 | /* Get first packet */ |
1350 | 0 | janus_rtcp_transport_wide_cc_stats *stat = (janus_rtcp_transport_wide_cc_stats *) g_queue_pop_head (transport_wide_cc_stats); |
1351 | 0 | /* Calculate temporal info */ |
1352 | 0 | guint16 base_seq_num = stat->transport_seq_num; |
1353 | 0 | gboolean first_received = FALSE; |
1354 | 0 | guint64 reference_time = 0; |
1355 | 0 | guint packet_status_count = g_queue_get_length(transport_wide_cc_stats) + 1; |
1356 | 0 |
|
1357 | 0 | /* |
1358 | 0 | 0 1 2 3 |
1359 | 0 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
1360 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1361 | 0 | | base sequence number | packet status count | |
1362 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1363 | 0 | | reference time | fb pkt. count | |
1364 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1365 | 0 | */ |
1366 | 0 |
|
1367 | 0 | /* The packet as unsigned */ |
1368 | 0 | guint8 *data = (guint8 *)packet; |
1369 | 0 | /* The start of the feedback data */ |
1370 | 0 | size_t len = sizeof(janus_rtcp_header) + 8; |
1371 | 0 |
|
1372 | 0 | /* Set header data */ |
1373 | 0 | janus_set2(data, len, base_seq_num); |
1374 | 0 | janus_set2(data, len+2, packet_status_count); |
1375 | 0 | /* Set3 referenceTime when first received */ |
1376 | 0 | size_t reference_time_pos = len + 4; |
1377 | 0 | janus_set1(data, len+7, feedback_packet_count); |
1378 | 0 |
|
1379 | 0 | /* Next byte */ |
1380 | 0 | len += 8; |
1381 | 0 |
|
1382 | 0 | /* Initial time in us */ |
1383 | 0 | guint64 timestamp = 0; |
1384 | 0 |
|
1385 | 0 | /* Store delta array */ |
1386 | 0 | GQueue *deltas = g_queue_new(); |
1387 | 0 | GQueue *statuses = g_queue_new(); |
1388 | 0 | janus_rtp_packet_status last_status = janus_rtp_packet_status_reserved; |
1389 | 0 | janus_rtp_packet_status max_status = janus_rtp_packet_status_notreceived; |
1390 | 0 | gboolean all_same = TRUE; |
1391 | 0 |
|
1392 | 0 | /* For each packet */ |
1393 | 0 | while (stat != NULL) { |
1394 | 0 | janus_rtp_packet_status status = janus_rtp_packet_status_notreceived; |
1395 | 0 |
|
1396 | 0 | /* If got packet */ |
1397 | 0 | if (stat->timestamp) { |
1398 | 0 | int delta = 0; |
1399 | 0 | /* If first received */ |
1400 | 0 | if (!first_received) { |
1401 | 0 | /* Got it */ |
1402 | 0 | first_received = TRUE; |
1403 | 0 | /* Set it */ |
1404 | 0 | reference_time = (stat->timestamp/64000); |
1405 | 0 | /* Get initial time */ |
1406 | 0 | timestamp = reference_time * 64000; |
1407 | 0 | /* also in bufffer */ |
1408 | 0 | janus_set3(data, reference_time_pos, reference_time); |
1409 | 0 | } |
1410 | 0 |
|
1411 | 0 | /* Get delta */ |
1412 | 0 | if (stat->timestamp>timestamp) |
1413 | 0 | delta = (stat->timestamp-timestamp)/250; |
1414 | 0 | else |
1415 | 0 | delta = -(int)((timestamp-stat->timestamp)/250); |
1416 | 0 | /* If it is negative or too big */ |
1417 | 0 | if (delta<0 || delta> 127) { |
1418 | 0 | /* Big one */ |
1419 | 0 | status = janus_rtp_packet_status_largeornegativedelta; |
1420 | 0 | } else { |
1421 | 0 | /* Small */ |
1422 | 0 | status = janus_rtp_packet_status_smalldelta; |
1423 | 0 | } |
1424 | 0 | /* Store delta */ |
1425 | 0 | g_queue_push_tail(deltas, GINT_TO_POINTER(delta)); |
1426 | 0 | /* Set last time */ |
1427 | 0 | timestamp = stat->timestamp; |
1428 | 0 | } |
1429 | 0 |
|
1430 | 0 | /* Check if all previoues ones were equal and this one the firt different */ |
1431 | 0 | if (all_same && last_status!=janus_rtp_packet_status_reserved && status!=last_status) { |
1432 | 0 | /* How big was the same run */ |
1433 | 0 | if (g_queue_get_length(statuses)>7) { |
1434 | 0 | guint32 word = 0; |
1435 | 0 | /* Write run! */ |
1436 | 0 | /* |
1437 | 0 | 0 1 |
1438 | 0 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
1439 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1440 | 0 | |T| S | Run Length | |
1441 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1442 | 0 | T = 0 |
1443 | 0 | */ |
1444 | 0 | word = janus_push_bits(word, 1, 0); |
1445 | 0 | word = janus_push_bits(word, 2, last_status); |
1446 | 0 | word = janus_push_bits(word, 13, g_queue_get_length(statuses)); |
1447 | 0 | /* Write word */ |
1448 | 0 | janus_set2(data, len, word); |
1449 | 0 | len += 2; |
1450 | 0 | /* Remove all statuses */ |
1451 | 0 | g_queue_clear(statuses); |
1452 | 0 | /* Reset status */ |
1453 | 0 | last_status = janus_rtp_packet_status_reserved; |
1454 | 0 | max_status = janus_rtp_packet_status_notreceived; |
1455 | 0 | all_same = TRUE; |
1456 | 0 | } else { |
1457 | 0 | /* Not same */ |
1458 | 0 | all_same = FALSE; |
1459 | 0 | } |
1460 | 0 | } |
1461 | 0 |
|
1462 | 0 | /* Push back statuses, it will be handled later */ |
1463 | 0 | g_queue_push_tail(statuses, GUINT_TO_POINTER(status)); |
1464 | 0 |
|
1465 | 0 | /* If it is bigger */ |
1466 | 0 | if (status>max_status) { |
1467 | 0 | /* Store it */ |
1468 | 0 | max_status = status; |
1469 | 0 | } |
1470 | 0 | /* Store las status */ |
1471 | 0 | last_status = status; |
1472 | 0 |
|
1473 | 0 | /* Check if we can still be enquing for a run */ |
1474 | 0 | if (!all_same) { |
1475 | 0 | /* Check */ |
1476 | 0 | if (!all_same && max_status==janus_rtp_packet_status_largeornegativedelta && g_queue_get_length(statuses)>6) { |
1477 | 0 | guint32 word = 0; |
1478 | 0 | /* |
1479 | 0 | 0 1 |
1480 | 0 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
1481 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1482 | 0 | |T|S| Symbols | |
1483 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1484 | 0 | T = 1 |
1485 | 0 | S = 1 |
1486 | 0 | */ |
1487 | 0 | word = janus_push_bits(word, 1, 1); |
1488 | 0 | word = janus_push_bits(word, 1, 1); |
1489 | 0 | /* Set next 7 */ |
1490 | 0 | size_t i = 0; |
1491 | 0 | for (i=0;i<7;++i) { |
1492 | 0 | /* Get status */ |
1493 | 0 | janus_rtp_packet_status status = (janus_rtp_packet_status) GPOINTER_TO_UINT(g_queue_pop_head (statuses)); |
1494 | 0 | /* Write */ |
1495 | 0 | word = janus_push_bits(word, 2, (guint8)status); |
1496 | 0 | } |
1497 | 0 | /* Write word */ |
1498 | 0 | janus_set2(data, len, word); |
1499 | 0 | len += 2; |
1500 | 0 | /* Reset */ |
1501 | 0 | last_status = janus_rtp_packet_status_reserved; |
1502 | 0 | max_status = janus_rtp_packet_status_notreceived; |
1503 | 0 | all_same = TRUE; |
1504 | 0 |
|
1505 | 0 | /* We need to restore the values, as there may be more elements on the buffer */ |
1506 | 0 | for (i=0; i<g_queue_get_length(statuses); ++i) { |
1507 | 0 | /* Get status */ |
1508 | 0 | status = (janus_rtp_packet_status) GPOINTER_TO_UINT(g_queue_peek_nth(statuses, i)); |
1509 | 0 | /* If it is bigger */ |
1510 | 0 | if (status>max_status) { |
1511 | 0 | /* Store it */ |
1512 | 0 | max_status = status; |
1513 | 0 | } |
1514 | 0 | //Check if it is the same */ |
1515 | 0 | if (all_same && last_status!=janus_rtp_packet_status_reserved && status!=last_status) { |
1516 | 0 | /* Not the same */ |
1517 | 0 | all_same = FALSE; |
1518 | 0 | } |
1519 | 0 | /* Store las status */ |
1520 | 0 | last_status = status; |
1521 | 0 | } |
1522 | 0 | } else if (!all_same && g_queue_get_length(statuses)>13) { |
1523 | 0 | guint32 word = 0; |
1524 | 0 | /* |
1525 | 0 | 0 1 |
1526 | 0 | 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
1527 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1528 | 0 | |T|S| symbol list | |
1529 | 0 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1530 | 0 | T = 1 |
1531 | 0 | S = 0 |
1532 | 0 | */ |
1533 | 0 | word = janus_push_bits(word, 1, 1); |
1534 | 0 | word = janus_push_bits(word, 1, 0); |
1535 | 0 | /* Set next 7 */ |
1536 | 0 | guint32 i = 0; |
1537 | 0 | for (i=0;i<14;++i) { |
1538 | 0 | /* Get status */ |
1539 | 0 | janus_rtp_packet_status status = (janus_rtp_packet_status) GPOINTER_TO_UINT(g_queue_pop_head (statuses)); |
1540 | 0 | /* Write */ |
1541 | 0 | word = janus_push_bits(word, 1, (guint8)status); |
1542 | 0 | } |
1543 | 0 | /* Write word */ |
1544 | 0 | janus_set2(data, len, word); |
1545 | 0 | len += 2; |
1546 | 0 | /* Reset */ |
1547 | 0 | last_status = janus_rtp_packet_status_reserved; |
1548 | 0 | max_status = janus_rtp_packet_status_notreceived; |
1549 | 0 | all_same = TRUE; |
1550 | 0 | } |
1551 | 0 | } |
1552 | 0 | /* Free mem */ |
1553 | 0 | g_free(stat); |
1554 | 0 |
|
1555 | 0 | /* Get next packet stat */ |
1556 | 0 | stat = (janus_rtcp_transport_wide_cc_stats *) g_queue_pop_head (transport_wide_cc_stats); |
1557 | 0 | } |
1558 | 0 |
|
1559 | 0 | /* Get status len */ |
1560 | 0 | size_t statuses_len = g_queue_get_length(statuses); |
1561 | 0 |
|
1562 | 0 | /* If not finished yet */ |
1563 | 0 | if (statuses_len>0) { |
1564 | 0 | /* How big was the same run */ |
1565 | 0 | if (all_same) { |
1566 | 0 | guint32 word = 0; |
1567 | 0 | /* Write run! */ |
1568 | 0 | word = janus_push_bits(word, 1, 0); |
1569 | 0 | word = janus_push_bits(word, 2, last_status); |
1570 | 0 | word = janus_push_bits(word, 13, statuses_len); |
1571 | 0 | /* Write word */ |
1572 | 0 | janus_set2(data, len, word); |
1573 | 0 | len += 2; |
1574 | 0 | } else if (max_status == janus_rtp_packet_status_largeornegativedelta) { |
1575 | 0 | guint32 word = 0; |
1576 | 0 | /* Write chunk */ |
1577 | 0 | word = janus_push_bits(word, 1, 1); |
1578 | 0 | word = janus_push_bits(word, 1, 1); |
1579 | 0 | /* Write all the statuses */ |
1580 | 0 | unsigned int i = 0; |
1581 | 0 | for (i=0;i<statuses_len;i++) { |
1582 | 0 | /* Get each status */ |
1583 | 0 | janus_rtp_packet_status status = (janus_rtp_packet_status) GPOINTER_TO_UINT(g_queue_pop_head (statuses)); |
1584 | 0 | /* Write */ |
1585 | 0 | word = janus_push_bits(word, 2, (guint8)status); |
1586 | 0 | } |
1587 | 0 | /* Write pending */ |
1588 | 0 | word = janus_push_bits(word, 14-statuses_len*2, 0); |
1589 | 0 | /* Write word */ |
1590 | 0 | janus_set2(data , len, word); |
1591 | 0 | len += 2; |
1592 | 0 | } else { |
1593 | 0 | guint32 word = 0; |
1594 | 0 | /* Write chunck */ |
1595 | 0 | word = janus_push_bits(word, 1, 1); |
1596 | 0 | word = janus_push_bits(word, 1, 0); |
1597 | 0 | /* Write all the statuses */ |
1598 | 0 | unsigned int i = 0; |
1599 | 0 | for (i=0;i<statuses_len;i++) { |
1600 | 0 | /* Get each status */ |
1601 | 0 | janus_rtp_packet_status status = (janus_rtp_packet_status) GPOINTER_TO_UINT(g_queue_pop_head (statuses)); |
1602 | 0 | /* Write */ |
1603 | 0 | word = janus_push_bits(word, 1, (guint8)status); |
1604 | 0 | } |
1605 | 0 | /* Write pending */ |
1606 | 0 | word = janus_push_bits(word, 14-statuses_len, 0); |
1607 | 0 | /* Write word */ |
1608 | 0 | janus_set2(data, len, word); |
1609 | 0 | len += 2; |
1610 | 0 | } |
1611 | 0 | } |
1612 | 0 |
|
1613 | 0 | /* Write now the deltas */ |
1614 | 0 | while (!g_queue_is_empty(deltas)) { |
1615 | 0 | /* Get next delta */ |
1616 | 0 | gint delta = GPOINTER_TO_INT(g_queue_pop_head (deltas)); |
1617 | 0 | /* Check size */ |
1618 | 0 | if (delta<0 || delta>127) { |
1619 | 0 | /* 2 bytes */ |
1620 | 0 | janus_set2(data, len, (short)delta); |
1621 | 0 | /* Inc */ |
1622 | 0 | len += 2; |
1623 | 0 | } else { |
1624 | 0 | /* 1 byte */ |
1625 | 0 | janus_set1(data, len, (guint8)delta); |
1626 | 0 | /* Inc */ |
1627 | 0 | len ++; |
1628 | 0 | } |
1629 | 0 | } |
1630 | 0 |
|
1631 | 0 | /* Clean mem */ |
1632 | 0 | g_queue_free(statuses); |
1633 | 0 | g_queue_free(deltas); |
1634 | 0 |
|
1635 | 0 | /* Add zero padding */ |
1636 | 0 | while (len%4) { |
1637 | 0 | /* Add padding */ |
1638 | 0 | janus_set1(data, len++, 0); |
1639 | 0 | } |
1640 | 0 |
|
1641 | 0 | /* Set RTCP Len */ |
1642 | 0 | rtcp->length = htons((len/4)-1); |
1643 | 0 |
|
1644 | 0 | /* Done */ |
1645 | 0 | return len; |
1646 | 0 | } |