Statistics
| Branch: | Revision:

janus-gateway / rtcp.c @ 5e9e29e0

History | View | Annotate | Download (14.6 KB)

1 be35facb meetecho
/*! \file    rtcp.c
2
 * \author   Lorenzo Miniero <lorenzo@meetecho.com>
3
 * \copyright GNU Affero 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 gateway 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 gateway). 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 "debug.h"
17
#include "rtcp.h"
18
19
int janus_rtcp_parse(char *packet, int len) {
20
        return janus_rtcp_fix_ssrc(packet, len, 0, 0, 0);
21
}
22
23
int janus_rtcp_fix_ssrc(char *packet, int len, int fixssrc, uint32_t newssrcl, uint32_t newssrcr) {
24
        if(packet == NULL || len == 0)
25
                return -1;
26
        rtcp_header *rtcp = (rtcp_header *)packet;
27
        if(rtcp->version != 2)
28
                return -2;
29
        int pno = 0, total = len;
30
        JANUS_PRINT("   Parsing compound packet (total of %d bytes)\n", total);
31
        while(rtcp) {
32
                pno++;
33
                /* TODO Should we handle any of these packets ourselves, or just relay them? */
34
                switch(rtcp->type) {
35
                        case RTCP_SR: {
36
                                /* SR, sender report */
37
                                JANUS_PRINT("     #%d SR (200)\n", pno);
38
                                rtcp_sr *sr = (rtcp_sr*)rtcp;
39
                                //~ JANUS_PRINT("       -- SSRC: %u (%u in RB)\n", ntohl(sr->ssrc), report_block_get_ssrc(&sr->rb[0]));
40
                                //~ JANUS_PRINT("       -- Lost: %u/%u\n", report_block_get_fraction_lost(&sr->rb[0]), report_block_get_cum_packet_loss(&sr->rb[0]));
41
                                if(fixssrc && newssrcl) {
42
                                        sr->ssrc = htonl(newssrcl);
43
                                }
44
                                if(fixssrc && newssrcr && sr->header.rc > 0) {
45
                                        sr->rb[0].ssrc = htonl(newssrcr);
46
                                }
47
                                break;
48
                        }
49
                        case RTCP_RR: {
50
                                /* RR, receiver report */
51
                                JANUS_PRINT("     #%d RR (201)\n", pno);
52
                                rtcp_rr *rr = (rtcp_rr*)rtcp;
53
                                //~ JANUS_PRINT("       -- SSRC: %u (%u in RB)\n", ntohl(rr->ssrc), report_block_get_ssrc(&rr->rb[0]));
54
                                //~ JANUS_PRINT("       -- Lost: %u/%u\n", report_block_get_fraction_lost(&rr->rb[0]), report_block_get_cum_packet_loss(&rr->rb[0]));
55
                                if(fixssrc && newssrcl) {
56
                                        rr->ssrc = htonl(newssrcl);
57
                                }
58
                                if(fixssrc && newssrcr && rr->header.rc > 0) {
59
                                        rr->rb[0].ssrc = htonl(newssrcr);
60
                                }
61
                                break;
62
                        }
63
                        case RTCP_SDES: {
64
                                /* SDES, source description */
65
                                JANUS_PRINT("     #%d SDES (202)\n", pno);
66
                                rtcp_sdes *sdes = (rtcp_sdes*)rtcp;
67
                                //~ JANUS_PRINT("       -- SSRC: %u\n", ntohl(sr->ssrc));
68
                                if(fixssrc && newssrcl) {
69
                                        sdes->ssrc = htonl(newssrcl);
70
                                }
71
                                break;
72
                        }
73
                        case RTCP_BYE: {
74
                                /* BYE, goodbye */
75
                                JANUS_PRINT("     #%d BYE (203)\n", pno);
76
                                rtcp_bye_t *bye = (rtcp_bye_t*)rtcp;
77
                                //~ JANUS_PRINT("       -- SSRC: %u\n", ntohl(bye->ssrc[0]));
78
                                if(fixssrc && newssrcl) {
79
                                        bye->ssrc[0] = htonl(newssrcl);
80
                                }
81
                                break;
82
                        }
83
                        case RTCP_APP: {
84
                                /* APP, application-defined */
85
                                JANUS_PRINT("     #%d APP (204)\n", pno);
86
                                rtcp_app_t *app = (rtcp_app_t*)rtcp;
87
                                //~ JANUS_PRINT("       -- SSRC: %u\n", ntohl(app->ssrc));
88
                                if(fixssrc && newssrcl) {
89
                                        app->ssrc = htonl(newssrcl);
90
                                }
91
                                break;
92
                        }
93 5e9e29e0 meetecho
                        case RTCP_FIR: {
94
                                /* FIR, rfc2032 */
95
                                JANUS_PRINT("     #%d FIR (192)\n", pno);
96
                                rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
97
                                if(fixssrc && newssrcr && (ntohs(rtcp->length) >= 20)) {
98
                                        rtcpfb->media = htonl(newssrcr);
99
                                }
100
                                if(fixssrc && newssrcr) {
101
                                        uint32_t *ssrc = (uint32_t *)rtcpfb->fci;
102
                                        *ssrc = htonl(newssrcr);
103
                                }
104
                                break;
105
                        }
106 be35facb meetecho
                        case RTCP_RTPFB: {
107
                                /* RTPFB, Transport layer FB message (rfc4585) */
108
                                //~ JANUS_PRINT("     #%d RTPFB (205)\n", pno);
109
                                gint fmt = rtcp->rc;
110
                                //~ JANUS_PRINT("       -- FMT: %u\n", fmt);
111
                                rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
112
                                //~ JANUS_PRINT("       -- SSRC: %u\n", ntohl(rtcpfb->ssrc));
113
                                if(fmt == 1) {
114
                                        JANUS_PRINT("     #%d NACK -- RTPFB (205)\n", pno);
115
                                        if(fixssrc && newssrcr) {
116
                                                rtcpfb->media = htonl(newssrcr);
117
                                        }
118
                                        //~ int nacks = ntohs(rtcp->length)-2;        /* Skip SSRCs */
119
                                        //~ if(nacks > 0) {
120
                                                //~ JANUS_PRINT("        Got %d nacks\n", nacks);
121
                                                //~ rtcp_nack *nack = NULL;
122
                                                //~ uint16_t pid = 0;
123
                                                //~ uint16_t blp = 0;
124
                                                //~ int i=0, j=0;
125
                                                //~ char bitmask[20];
126
                                                //~ for(i=0; i< nacks; i++) {
127
                                                        //~ nack = (rtcp_nack *)rtcpfb->fci + i;
128
                                                        //~ pid = ntohs(nack->pid);
129
                                                        //~ blp = ntohs(nack->blp);
130
                                                        //~ memset(bitmask, 0, 20);
131
                                                        //~ for(j=0; j<16; j++) {
132
                                                                //~ bitmask[j] = (blp & ( 1 << j )) >> j ? '1' : '0';
133
                                                        //~ }
134
                                                        //~ bitmask[16] = '\n';
135
                                                        //~ JANUS_PRINT("[%d] %"SCNu16" / %s\n", i, pid, bitmask);
136
                                                //~ }
137
                                        //~ }
138
                                } else if(fmt == 3) {        /* rfc5104 */
139
                                        /* TMMBR: http://tools.ietf.org/html/rfc5104#section-4.2.1.1 */
140
                                        JANUS_PRINT("     #%d TMMBR -- RTPFB (205)\n", pno);
141
                                        if(fixssrc && newssrcr) {
142
                                                uint32_t *ssrc = (uint32_t *)rtcpfb->fci;
143
                                                *ssrc = htonl(newssrcr);
144
                                        }
145
                                } else {
146
                                        JANUS_PRINT("     #%d ??? -- RTPFB (205, fmt=%d)\n", pno, fmt);
147
                                }
148
                                if(fixssrc && newssrcl) {
149
                                        rtcpfb->ssrc = htonl(newssrcl);
150
                                }
151
                                break;
152
                        }
153
                        case RTCP_PSFB: {
154
                                /* PSFB, Payload-specific FB message (rfc4585) */
155
                                //~ JANUS_PRINT("     #%d PSFB (206)\n", pno);
156
                                gint fmt = rtcp->rc;
157
                                //~ JANUS_PRINT("       -- FMT: %u\n", fmt);
158
                                rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
159
                                //~ JANUS_PRINT("       -- SSRC: %u\n", ntohl(rtcpfb->ssrc));
160
                                if(fmt == 1) {
161
                                        JANUS_PRINT("     #%d PLI -- PSFB (206)\n", pno);
162
                                        if(fixssrc && newssrcr) {
163
                                                rtcpfb->media = htonl(newssrcr);
164
                                        }
165
                                } else if(fmt == 2) {
166
                                        JANUS_PRINT("     #%d SLI -- PSFB (206)\n", pno);
167
                                } else if(fmt == 3) {
168
                                        JANUS_PRINT("     #%d RPSI -- PSFB (206)\n", pno);
169
                                } else if(fmt == 4) {        /* rfc5104 */
170
                                        /* FIR: http://tools.ietf.org/html/rfc5104#section-4.3.1.1 */
171
                                        JANUS_PRINT("     #%d FIR -- PSFB (206)\n", pno);
172
                                        if(fixssrc && newssrcr) {
173
                                                rtcpfb->media = htonl(newssrcr);
174
                                        }
175
                                        if(fixssrc && newssrcr) {
176
                                                uint32_t *ssrc = (uint32_t *)rtcpfb->fci;
177
                                                *ssrc = htonl(newssrcr);
178
                                        }
179
                                } else if(fmt == 5) {        /* rfc5104 */
180
                                        /* FIR: http://tools.ietf.org/html/rfc5104#section-4.3.2.1 */
181
                                        JANUS_PRINT("     #%d PLI -- TSTR (206)\n", pno);
182
                                        if(fixssrc && newssrcr) {
183
                                                uint32_t *ssrc = (uint32_t *)rtcpfb->fci;
184
                                                *ssrc = htonl(newssrcr);
185
                                        }
186
                                } else if(fmt == 15) {
187
                                        //~ JANUS_PRINT("       -- This is a AFB!\n");
188
                                        rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
189
                                        rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
190
                                        if(remb->id[0] == 'R' && remb->id[1] == 'E' && remb->id[2] == 'M' && remb->id[3] == 'B') {
191
                                                JANUS_PRINT("     #%d REMB -- PSFB (206)\n", pno);
192
                                                /* FIXME From rtcp_utility.cc */
193
                                                unsigned char *_ptrRTCPData = (unsigned char *)remb;
194
                                                _ptrRTCPData += 4;        // Skip unique identifier and num ssrc
195
                                                //~ JANUS_PRINT(" %02X %02X %02X %02X\n", _ptrRTCPData[0], _ptrRTCPData[1], _ptrRTCPData[2], _ptrRTCPData[3]);
196
                                                uint8_t numssrc = (_ptrRTCPData[0]);
197
                                                uint8_t brExp = (_ptrRTCPData[1] >> 2) & 0x3F;
198
                                                uint32_t brMantissa = (_ptrRTCPData[1] & 0x03) << 16;
199
                                                brMantissa += (_ptrRTCPData[2] << 8);
200
                                                brMantissa += (_ptrRTCPData[3]);
201
                                                uint64_t bitRate = brMantissa << brExp;
202
                                                JANUS_PRINT("       -- -- -- REMB: %u * 2^%u = %"SCNu64" (%d SSRCs, %u)\n",
203
                                                        brMantissa, brExp, bitRate, numssrc, ntohl(remb->ssrc[0]));
204
205
                                                if(fixssrc && newssrcr) {
206
                                                        remb->ssrc[0] = htonl(newssrcr);
207
                                                }
208
                                        } else {
209
                                                JANUS_PRINT("     #%d AFB ?? -- PSFB (206)\n", pno);
210
                                        }
211
                                } else {
212
                                        JANUS_PRINT("     #%d ?? -- PSFB (206, fmt=%d)\n", pno, fmt);
213
                                }
214
                                if(fixssrc && newssrcl) {
215
                                        rtcpfb->ssrc = htonl(newssrcl);
216
                                }
217
                                break;
218
                        }
219
                        default:
220
                                JANUS_DEBUG("     Unknown RTCP PT %d\n", rtcp->type);
221
                                break;
222
                }
223
                /* Is this a compound packet? */
224
                int length = ntohs(rtcp->length);
225
                if(length == 0) {
226
                        //~ JANUS_PRINT("  0-length, end of compound packet\n");
227
                        break;
228
                }
229
                total -= length*4+4;
230
                //~ JANUS_PRINT("     Packet has length %d (%d bytes, %d remaining), moving to next one...\n", length, length*4+4, total);
231
                if(total <= 0) {
232
                        JANUS_PRINT("  End of compound packet\n");
233
                        break;
234
                }
235
                rtcp = (rtcp_header *)((uint32_t*)rtcp + length + 1);
236
        }
237
        return 0;
238
}
239
240
GSList *janus_rtcp_get_nacks(char *packet, int len) {
241
        if(packet == NULL || len == 0)
242
                return NULL;
243
        rtcp_header *rtcp = (rtcp_header *)packet;
244
        if(rtcp->version != 2)
245
                return NULL;
246
        /* FIXME Get list of sequence numbers we should send again */
247
        GSList *list = NULL;
248
        int total = len;
249
        while(rtcp) {
250
                if(rtcp->type == RTCP_RTPFB) {
251
                        gint fmt = rtcp->rc;
252
                        if(fmt == 1) {
253
                                rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
254
                                int nacks = ntohs(rtcp->length)-2;        /* Skip SSRCs */
255
                                if(nacks > 0) {
256
                                        JANUS_PRINT("        Got %d nacks\n", nacks);
257
                                        rtcp_nack *nack = NULL;
258
                                        uint16_t pid = 0;
259
                                        uint16_t blp = 0;
260
                                        int i=0, j=0;
261
                                        char bitmask[20];
262
                                        for(i=0; i< nacks; i++) {
263
                                                nack = (rtcp_nack *)rtcpfb->fci + i;
264
                                                pid = ntohs(nack->pid);
265
                                                list = g_slist_append(list, GUINT_TO_POINTER(pid));
266
                                                blp = ntohs(nack->blp);
267
                                                memset(bitmask, 0, 20);
268
                                                for(j=0; j<16; j++) {
269
                                                        bitmask[j] = (blp & ( 1 << j )) >> j ? '1' : '0';
270
                                                        if((blp & ( 1 << j )) >> j)
271
                                                                list = g_slist_append(list, GUINT_TO_POINTER(pid+j+1));
272
                                                }
273
                                                bitmask[16] = '\n';
274
                                                JANUS_PRINT("[%d] %"SCNu16" / %s\n", i, pid, bitmask);
275
                                        }
276
                                }
277
                        }
278
                }
279
                /* Is this a compound packet? */
280
                int length = ntohs(rtcp->length);
281
                if(length == 0)
282
                        break;
283
                total -= length*4+4;
284
                if(total <= 0)
285
                        break;
286
                rtcp = (rtcp_header *)((uint32_t*)rtcp + length + 1);
287
        }
288
        return list;
289
}
290
291
/* Change an existing REMB message */
292
int janus_rtcp_cap_remb(char *packet, int len, uint64_t bitrate) {
293
        if(packet == NULL || len == 0)
294
                return -1;
295
        rtcp_header *rtcp = (rtcp_header *)packet;
296
        if(rtcp->version != 2)
297
                return -2;
298
        if(bitrate == 0)
299
                return 0;        /* No need to cap */
300
        /* Cap REMB bitrate */
301
        int total = len;
302
        while(rtcp) {
303
                if(rtcp->type == RTCP_PSFB) {
304
                        gint fmt = rtcp->rc;
305
                        if(fmt == 15) {
306
                                rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
307
                                rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
308
                                if(remb->id[0] == 'R' && remb->id[1] == 'E' && remb->id[2] == 'M' && remb->id[3] == 'B') {
309
                                        /* FIXME From rtcp_utility.cc */
310
                                        unsigned char *_ptrRTCPData = (unsigned char *)remb;
311
                                        _ptrRTCPData += 4;        /* Skip unique identifier and num ssrc */
312
                                        //~ JANUS_PRINT(" %02X %02X %02X %02X\n", _ptrRTCPData[0], _ptrRTCPData[1], _ptrRTCPData[2], _ptrRTCPData[3]);
313
                                        uint8_t brExp = (_ptrRTCPData[1] >> 2) & 0x3F;
314
                                        uint32_t brMantissa = (_ptrRTCPData[1] & 0x03) << 16;
315
                                        brMantissa += (_ptrRTCPData[2] << 8);
316
                                        brMantissa += (_ptrRTCPData[3]);
317
                                        uint64_t origbitrate = brMantissa << brExp;
318
                                        if(origbitrate > bitrate) {
319
                                                JANUS_PRINT("Got REMB bitrate %"SCNu64", need to cap it to %"SCNu64"\n", origbitrate, bitrate);
320
                                                JANUS_PRINT("  >> %u * 2^%u = %"SCNu64"\n", brMantissa, brExp, origbitrate);
321
                                                /* bitrate --> brexp/brmantissa */
322
                                                uint8_t b = 0;
323
                                                uint8_t newbrexp = 0;
324
                                                uint32_t newbrmantissa = 0;
325
                                                for(b=0; b<64; b++) {
326
                                                        if(bitrate <= (0x3FFFF << b)) {
327
                                                                newbrexp = b;
328
                                                                break;
329
                                                        }
330
                                                }
331
                                                newbrmantissa = bitrate >> b;
332
                                                JANUS_PRINT("new brexp:      %"SCNu8"\n", newbrexp);
333
                                                JANUS_PRINT("new brmantissa: %"SCNu32"\n", newbrmantissa);
334
                                                /* FIXME From rtcp_sender.cc */
335
                                                _ptrRTCPData[1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03));
336
                                                _ptrRTCPData[2] = (uint8_t)(newbrmantissa >> 8);
337
                                                _ptrRTCPData[3] = (uint8_t)(newbrmantissa);
338
                                        }
339
                                }
340
                        }
341
                }
342
                /* Is this a compound packet? */
343
                int length = ntohs(rtcp->length);
344
                if(length == 0)
345
                        break;
346
                total -= length*4+4;
347
                if(total <= 0)
348
                        break;
349
                rtcp = (rtcp_header *)((uint32_t*)rtcp + length + 1);
350
        }
351
        return 0;
352
}
353
354
/* Generate a new REMB message */
355
int janus_rtcp_remb(char *packet, int len, uint64_t bitrate) {
356
        if(packet == NULL || len != 24)
357
                return -1;
358
        rtcp_header *rtcp = (rtcp_header *)packet;
359
        /* Set header */
360
        rtcp->version = 2;
361
        rtcp->type = RTCP_PSFB;
362
        rtcp->rc = 15;
363
        rtcp->length = htons((len/4)-1);
364
        /* Now set REMB stuff */
365
        rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
366
        rtcp_remb *remb = (rtcp_remb *)rtcpfb->fci;
367
        remb->id[0] = 'R';
368
        remb->id[1] = 'E';
369
        remb->id[2] = 'M';
370
        remb->id[3] = 'B';
371
        /* bitrate --> brexp/brmantissa */
372
        uint8_t b = 0;
373
        uint8_t newbrexp = 0;
374
        uint32_t newbrmantissa = 0;
375
        for(b=0; b<64; b++) {
376
                if(bitrate <= (0x3FFFF << b)) {
377
                        newbrexp = b;
378
                        break;
379
                }
380
        }
381
        newbrmantissa = bitrate >> b;
382
        /* FIXME From rtcp_sender.cc */
383
        unsigned char *_ptrRTCPData = (unsigned char *)remb;
384
        _ptrRTCPData += 4;        /* Skip unique identifier */
385
        _ptrRTCPData[0] = (uint8_t)(1);        /* Just one SSRC */
386
        _ptrRTCPData[1] = (uint8_t)((newbrexp << 2) + ((newbrmantissa >> 16) & 0x03));
387
        _ptrRTCPData[2] = (uint8_t)(newbrmantissa >> 8);
388
        _ptrRTCPData[3] = (uint8_t)(newbrmantissa);
389
        JANUS_PRINT("[REMB] bitrate=%"SCNu64" (%d bytes)\n", bitrate, 4*(ntohs(rtcp->length)+1));
390
        return 0;
391
}
392
393
/* Generate a new FIR message */
394
int janus_rtcp_fir(char *packet, int len, int *seqnr) {
395
        if(packet == NULL || len != 20 || seqnr == NULL)
396
                return -1;
397
        rtcp_header *rtcp = (rtcp_header *)packet;
398
        *seqnr = *seqnr + 1;
399
        if(*seqnr < 0 || *seqnr >= 256)
400
                *seqnr = 0;        /* Reset sequence number */
401
        /* Set header */
402
        rtcp->version = 2;
403
        rtcp->type = RTCP_PSFB;
404
        rtcp->rc = 4;        /* FMT=4 */
405
        rtcp->length = htons((len/4)-1);
406
        /* Now set FIR stuff */
407
        rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
408
        rtcp_fir *fir = (rtcp_fir *)rtcpfb->fci;
409
        fir->seqnr = htonl(*seqnr << 24);        /* FCI: Sequence number */
410
        JANUS_PRINT("[FIR] seqnr=%d (%d bytes)\n", *seqnr, 4*(ntohs(rtcp->length)+1));
411
        return 0;
412
}
413
414 5e9e29e0 meetecho
/* Generate a new legacy FIR message */
415
int janus_rtcp_fir_legacy(char *packet, int len, int *seqnr) {
416
        /* FIXME Right now, this is identical to the new FIR, with the difference that we use 192 as PT */
417
        if(packet == NULL || len != 20 || seqnr == NULL)
418
                return -1;
419
        rtcp_header *rtcp = (rtcp_header *)packet;
420
        *seqnr = *seqnr + 1;
421
        if(*seqnr < 0 || *seqnr >= 256)
422
                *seqnr = 0;        /* Reset sequence number */
423
        /* Set header */
424
        rtcp->version = 2;
425
        rtcp->type = RTCP_FIR;
426
        rtcp->rc = 4;        /* FMT=4 */
427
        rtcp->length = htons((len/4)-1);
428
        /* Now set FIR stuff */
429
        rtcp_fb *rtcpfb = (rtcp_fb *)rtcp;
430
        rtcp_fir *fir = (rtcp_fir *)rtcpfb->fci;
431
        fir->seqnr = htonl(*seqnr << 24);        /* FCI: Sequence number */
432
        JANUS_PRINT("[FIR] seqnr=%d (%d bytes)\n", *seqnr, 4*(ntohs(rtcp->length)+1));
433
        return 0;
434
}
435
436 be35facb meetecho
/* Generate a new PLI message */
437
int janus_rtcp_pli(char *packet, int len) {
438
        if(packet == NULL || len != 12)
439
                return -1;
440
        rtcp_header *rtcp = (rtcp_header *)packet;
441
        /* Set header */
442
        rtcp->version = 2;
443
        rtcp->type = RTCP_PSFB;
444
        rtcp->rc = 1;        /* FMT=1 */
445
        rtcp->length = htons((len/4)-1);
446
        return 0;
447
}