/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
}