chenqiyang
2021-08-20 7b95fb4d4549d3452ee17165236186afc1f2b393
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
/*
 * Copyright (c) 2010-2019 Belledonne Communications SARL.
 *
 * This file is part of oRTP.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
 
 
#ifndef RTCP_H
#define RTCP_H
 
#include <ortp/port.h>
 
#define RTCP_MAX_RECV_BUFSIZE 1500
 
#define RTCP_SENDER_INFO_SIZE 20
#define RTCP_REPORT_BLOCK_SIZE 24
#define RTCP_COMMON_HEADER_SIZE 4
#define RTCP_SSRC_FIELD_SIZE 4
 
#ifdef __cplusplus
extern "C"{
#endif
 
/* RTCP common header */
 
typedef enum {
    RTCP_SR = 200,
    RTCP_RR = 201,
    RTCP_SDES = 202,
    RTCP_BYE = 203,
    RTCP_APP = 204,
    RTCP_RTPFB = 205,
    RTCP_PSFB = 206,
    RTCP_XR = 207
} rtcp_type_t;
 
 
typedef struct rtcp_common_header
{
#ifdef ORTP_BIGENDIAN
    uint16_t version:2;
    uint16_t padbit:1;
    uint16_t rc:5;
    uint16_t packet_type:8;
#else
    uint16_t rc:5;
    uint16_t padbit:1;
    uint16_t version:2;
    uint16_t packet_type:8;
#endif
    uint16_t length:16;
} rtcp_common_header_t;
 
#define rtcp_common_header_set_version(ch,v) (ch)->version=v
#define rtcp_common_header_set_padbit(ch,p) (ch)->padbit=p
#define rtcp_common_header_set_rc(ch,rc) (ch)->rc=rc
#define rtcp_common_header_set_packet_type(ch,pt) (ch)->packet_type=pt
#define rtcp_common_header_set_length(ch,l)    (ch)->length=htons(l)
 
#define rtcp_common_header_get_version(ch) ((ch)->version)
#define rtcp_common_header_get_padbit(ch) ((ch)->padbit)
#define rtcp_common_header_get_rc(ch) ((ch)->rc)
#define rtcp_common_header_get_packet_type(ch) ((ch)->packet_type)
#define rtcp_common_header_get_length(ch)    ntohs((ch)->length)
 
 
/* RTCP SR or RR  packets */
 
typedef struct sender_info
{
    uint32_t ntp_timestamp_msw;
    uint32_t ntp_timestamp_lsw;
    uint32_t rtp_timestamp;
    uint32_t senders_packet_count;
    uint32_t senders_octet_count;
} sender_info_t;
 
static ORTP_INLINE uint64_t sender_info_get_ntp_timestamp(const sender_info_t *si) {
  return ((((uint64_t)ntohl(si->ntp_timestamp_msw)) << 32) +
          ((uint64_t) ntohl(si->ntp_timestamp_lsw)));
}
#define sender_info_get_rtp_timestamp(si)    ntohl((si)->rtp_timestamp)
#define sender_info_get_packet_count(si) \
    ntohl((si)->senders_packet_count)
#define sender_info_get_octet_count(si) \
    ntohl((si)->senders_octet_count)
 
 
typedef struct report_block
{
    uint32_t ssrc;
    uint32_t fl_cnpl;/*fraction lost + cumulative number of packet lost*/
    uint32_t ext_high_seq_num_rec; /*extended highest sequence number received */
    uint32_t interarrival_jitter;
    uint32_t lsr; /*last SR */
    uint32_t delay_snc_last_sr; /*delay since last sr*/
} report_block_t;
 
static ORTP_INLINE uint32_t report_block_get_ssrc(const report_block_t * rb) {
    return ntohl(rb->ssrc);
}
static ORTP_INLINE uint32_t report_block_get_high_ext_seq(const report_block_t * rb) {
    return ntohl(rb->ext_high_seq_num_rec);
}
static ORTP_INLINE uint32_t report_block_get_interarrival_jitter(const report_block_t * rb) {
    return ntohl(rb->interarrival_jitter);
}
 
static ORTP_INLINE uint32_t report_block_get_last_SR_time(const report_block_t * rb) {
    return ntohl(rb->lsr);
}
static ORTP_INLINE uint32_t report_block_get_last_SR_delay(const report_block_t * rb) {
    return ntohl(rb->delay_snc_last_sr);
}
static ORTP_INLINE uint32_t report_block_get_fraction_lost(const report_block_t * rb) {
    return (ntohl(rb->fl_cnpl)>>24);
}
static ORTP_INLINE int32_t report_block_get_cum_packet_lost(const report_block_t * rb){
    uint32_t cum_loss = (uint32_t)ntohl(rb->fl_cnpl);
    if (((cum_loss>>23)&1)==0)
        return (int32_t) (0x00FFFFFF & cum_loss);
    else
        return (int32_t)(0xFF000000 | (cum_loss-0xFFFFFF-1));
}
 
static ORTP_INLINE void report_block_set_fraction_lost(report_block_t * rb, int fl){
    rb->fl_cnpl = (uint32_t)htonl( ((uint32_t)ntohl(rb->fl_cnpl) & 0xFFFFFF) | ((uint32_t)fl&0xFF)<<24);
}
 
static ORTP_INLINE void report_block_set_cum_packet_lost(report_block_t * rb, int64_t cpl) {
    uint32_t clamp = (uint32_t)((1<<24) + ((cpl>=0) ? (cpl>0x7FFFFF?0x7FFFFF:cpl) : (-cpl>0x800000?-0x800000:cpl)));
 
    rb->fl_cnpl=htonl(
            (ntohl(rb->fl_cnpl) & 0xFF000000) |
            (cpl >= 0 ? clamp&0x7FFFFF : clamp|0x800000)
        );
}
 
/* SDES packets */
 
typedef enum {
    RTCP_SDES_END = 0,
    RTCP_SDES_CNAME = 1,
    RTCP_SDES_NAME = 2,
    RTCP_SDES_EMAIL = 3,
    RTCP_SDES_PHONE = 4,
    RTCP_SDES_LOC = 5,
    RTCP_SDES_TOOL = 6,
    RTCP_SDES_NOTE = 7,
    RTCP_SDES_PRIV = 8,
    RTCP_SDES_MID = 10, /* TODO: change this value when his identifier will be assigned */
    RTCP_SDES_MAX = 11
} rtcp_sdes_type_t;
 
typedef struct sdes_chunk
{
    uint32_t csrc;
} sdes_chunk_t;
 
 
#define sdes_chunk_get_csrc(c)    ntohl((c)->csrc)
 
typedef struct sdes_item
{
    uint8_t item_type;
    uint8_t len;
    char content[1];
} sdes_item_t;
 
#define RTCP_SDES_MAX_STRING_SIZE 255
#define RTCP_SDES_ITEM_HEADER_SIZE 2
#define RTCP_SDES_CHUNK_DEFAULT_SIZE 1024
#define RTCP_SDES_CHUNK_HEADER_SIZE (sizeof(sdes_chunk_t))
 
/* RTCP bye packet */
 
typedef struct rtcp_bye_reason
{
    uint8_t len;
    char content[1];
} rtcp_bye_reason_t;
 
typedef struct rtcp_bye
{
    rtcp_common_header_t ch;
    uint32_t ssrc[1];  /* the bye may contain several ssrc/csrc */
} rtcp_bye_t;
#define RTCP_BYE_HEADER_SIZE sizeof(rtcp_bye_t)
#define RTCP_BYE_REASON_MAX_STRING_SIZE 255
 
 
/* RTCP XR packet */
 
#define RTCP_XR_VOIP_METRICS_CONFIG_PLC_STD ((1 << 7) | (1 << 6))
#define RTCP_XR_VOIP_METRICS_CONFIG_PLC_ENH (1 << 7)
#define RTCP_XR_VOIP_METRICS_CONFIG_PLC_DIS (1 << 6)
#define RTCP_XR_VOIP_METRICS_CONFIG_PLC_UNS 0
#define RTCP_XR_VOIP_METRICS_CONFIG_JBA_ADA ((1 << 5) | (1 << 4))
#define RTCP_XR_VOIP_METRICS_CONFIG_JBA_NON (1 << 5)
#define RTCP_XR_VOIP_METRICS_CONFIG_JBA_UNK 0
 
typedef enum {
    RTCP_XR_LOSS_RLE = 1,
    RTCP_XR_DUPLICATE_RLE = 2,
    RTCP_XR_PACKET_RECEIPT_TIMES = 3,
    RTCP_XR_RCVR_RTT = 4,
    RTCP_XR_DLRR = 5,
    RTCP_XR_STAT_SUMMARY = 6,
    RTCP_XR_VOIP_METRICS = 7
} rtcp_xr_block_type_t;
 
typedef struct rtcp_xr_header {
    rtcp_common_header_t ch;
    uint32_t ssrc;
} rtcp_xr_header_t;
 
typedef struct rtcp_xr_generic_block_header {
    uint8_t bt;
    uint8_t flags;
    uint16_t length;
} rtcp_xr_generic_block_header_t;
 
typedef struct rtcp_xr_rcvr_rtt_report_block {
    rtcp_xr_generic_block_header_t bh;
    uint32_t ntp_timestamp_msw;
    uint32_t ntp_timestamp_lsw;
} rtcp_xr_rcvr_rtt_report_block_t;
 
typedef struct rtcp_xr_dlrr_report_subblock {
    uint32_t ssrc;
    uint32_t lrr;
    uint32_t dlrr;
} rtcp_xr_dlrr_report_subblock_t;
 
typedef struct rtcp_xr_dlrr_report_block {
    rtcp_xr_generic_block_header_t bh;
    rtcp_xr_dlrr_report_subblock_t content[1];
} rtcp_xr_dlrr_report_block_t;
 
typedef struct rtcp_xr_stat_summary_report_block {
    rtcp_xr_generic_block_header_t bh;
    uint32_t ssrc;
    uint16_t begin_seq;
    uint16_t end_seq;
    uint32_t lost_packets;
    uint32_t dup_packets;
    uint32_t min_jitter;
    uint32_t max_jitter;
    uint32_t mean_jitter;
    uint32_t dev_jitter;
    uint8_t min_ttl_or_hl;
    uint8_t max_ttl_or_hl;
    uint8_t mean_ttl_or_hl;
    uint8_t dev_ttl_or_hl;
} rtcp_xr_stat_summary_report_block_t;
 
typedef struct rtcp_xr_voip_metrics_report_block {
    rtcp_xr_generic_block_header_t bh;
    uint32_t ssrc;
    uint8_t loss_rate;
    uint8_t discard_rate;
    uint8_t burst_density;
    uint8_t gap_density;
    uint16_t burst_duration;
    uint16_t gap_duration;
    uint16_t round_trip_delay;
    uint16_t end_system_delay;
    uint8_t signal_level;
    uint8_t noise_level;
    uint8_t rerl;
    uint8_t gmin;
    uint8_t r_factor;
    uint8_t ext_r_factor;
    uint8_t mos_lq;
    uint8_t mos_cq;
    uint8_t rx_config;
    uint8_t reserved2;
    uint16_t jb_nominal;
    uint16_t jb_maximum;
    uint16_t jb_abs_max;
} rtcp_xr_voip_metrics_report_block_t;
 
#define MIN_RTCP_XR_PACKET_SIZE (sizeof(rtcp_xr_header_t) + 4)
 
/* RTCP FB packet */
typedef enum {
    RTCP_RTPFB_NACK = 1,
    RTCP_RTPFB_TMMBR = 3,
    RTCP_RTPFB_TMMBN = 4
} rtcp_rtpfb_type_t;
 
typedef enum {
    RTCP_PSFB_PLI = 1,
    RTCP_PSFB_SLI = 2,
    RTCP_PSFB_RPSI = 3,
    RTCP_PSFB_FIR = 4,
    RTCP_PSFB_AFB = 15
} rtcp_psfb_type_t;
 
typedef struct rtcp_fb_header {
    uint32_t packet_sender_ssrc;
    uint32_t media_source_ssrc;
} rtcp_fb_header_t;
 
typedef struct rtcp_fb_generic_nack_fci {
    uint16_t pid;
    uint16_t blp;
} rtcp_fb_generic_nack_fci_t;
 
#define rtcp_fb_generic_nack_fci_get_pid(nack) ntohs((nack)->pid)
#define rtcp_fb_generic_nack_fci_set_pid(nack, value) ((nack)->pid) = htons(value)
#define rtcp_fb_generic_nack_fci_get_blp(nack) ntohs((nack)->blp)
#define rtcp_fb_generic_nack_fci_set_blp(nack, value) ((nack)->blp) = htons(value)
 
typedef struct rtcp_fb_tmmbr_fci {
    uint32_t ssrc;
    uint32_t value;
} rtcp_fb_tmmbr_fci_t;
 
#define rtcp_fb_tmmbr_fci_get_ssrc(tmmbr) ntohl((tmmbr)->ssrc)
#define rtcp_fb_tmmbr_fci_get_mxtbr_exp(tmmbr) \
    ((uint8_t)((ntohl((tmmbr)->value) >> 26) & 0x0000003F))
#define rtcp_fb_tmmbr_fci_set_mxtbr_exp(tmmbr, mxtbr_exp) \
    ((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0x03FFFFFF) | (((mxtbr_exp) & 0x0000003F) << 26))
#define rtcp_fb_tmmbr_fci_get_mxtbr_mantissa(tmmbr) \
    ((uint32_t)((ntohl((tmmbr)->value) >> 9) & 0x0001FFFF))
#define rtcp_fb_tmmbr_fci_set_mxtbr_mantissa(tmmbr, mxtbr_mantissa) \
    ((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0xFC0001FF) | (((mxtbr_mantissa) & 0x0001FFFF) << 9))
#define rtcp_fb_tmmbr_fci_get_measured_overhead(tmmbr) \
    ((uint16_t)(ntohl((tmmbr)->value) & 0x000001FF))
#define rtcp_fb_tmmbr_fci_set_measured_overhead(tmmbr, measured_overhead) \
    ((tmmbr)->value) = htonl((ntohl((tmmbr)->value) & 0xFFFFFE00) | ((measured_overhead) & 0x000001FF))
 
typedef struct rtcp_fb_fir_fci {
    uint32_t ssrc;
    uint8_t seq_nr;
    uint8_t pad1;
    uint16_t pad2;
} rtcp_fb_fir_fci_t;
 
#define rtcp_fb_fir_fci_get_ssrc(fci) ntohl((fci)->ssrc)
#define rtcp_fb_fir_fci_get_seq_nr(fci) (fci)->seq_nr
 
typedef struct rtcp_fb_sli_fci {
    uint32_t value;
} rtcp_fb_sli_fci_t;
 
#define rtcp_fb_sli_fci_get_first(fci) \
    ((uint16_t)((ntohl((fci)->value) >> 19) & 0x00001FFF))
#define rtcp_fb_sli_fci_set_first(fci, first) \
    ((fci)->value) = htonl((ntohl((fci)->value) & 0x0007FFFF) | (((first) & 0x00001FFF) << 19))
#define rtcp_fb_sli_fci_get_number(fci) \
    ((uint16_t)((ntohl((fci)->value) >> 6) & 0x00001FFF))
#define rtcp_fb_sli_fci_set_number(fci, number) \
    ((fci)->value) = htonl((ntohl((fci)->value) & 0xFFF8003F) | (((number) & 0x00001FFF) << 6))
#define rtcp_fb_sli_fci_get_picture_id(fci) \
    ((uint8_t)(ntohl((fci)->value) & 0x0000003F))
#define rtcp_fb_sli_fci_set_picture_id(fci, picture_id) \
    ((fci)->value) = htonl((ntohl((fci)->value) & 0xFFFFFFC0) | ((picture_id) & 0x0000003F))
 
typedef struct rtcp_fb_rpsi_fci {
    uint8_t pb;
    uint8_t payload_type;
    uint16_t bit_string[1];
} rtcp_fb_rpsi_fci_t;
 
#define rtcp_fb_rpsi_fci_get_payload_type(fci) (fci)->payload_type
#define rtcp_fb_rpsi_fci_get_bit_string(fci) ((uint8_t *)(fci)->bit_string)
 
#define MIN_RTCP_PSFB_PACKET_SIZE (sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t))
#define MIN_RTCP_RTPFB_PACKET_SIZE (sizeof(rtcp_common_header_t) + sizeof(rtcp_fb_header_t))
 
/* RTCP structs */
 
typedef struct rtcp_sr{
    rtcp_common_header_t ch;
    uint32_t ssrc;
    sender_info_t si;
    report_block_t rb[1];
} rtcp_sr_t;
 
typedef struct rtcp_rr{
    rtcp_common_header_t ch;
    uint32_t ssrc;
    report_block_t rb[1];
} rtcp_rr_t;
 
typedef struct rtcp_app{
    rtcp_common_header_t ch;
    uint32_t ssrc;
    char name[4];
} rtcp_app_t;
 
struct _RtpSession;
struct _RtpStream;
ORTP_PUBLIC void rtp_session_rtcp_process_send(struct _RtpSession *s);
ORTP_PUBLIC void rtp_session_rtcp_process_recv(struct _RtpSession *s);
 
 
#define RTCP_DEFAULT_REPORT_INTERVAL 5000 /* in milliseconds */
 
 
/* packet parsing api */
 
/*return the size of the rtcp packet*/
ORTP_PUBLIC size_t rtcp_get_size(const mblk_t *m);
/*in case of coumpound packet, set read pointer of m to the beginning of the next RTCP
packet */
ORTP_PUBLIC bool_t rtcp_next_packet(mblk_t *m);
/* put the read pointer at the first RTCP packet of the compound packet (as before any previous calls ot rtcp_next_packet() */
ORTP_PUBLIC void rtcp_rewind(mblk_t *m);
/* get common header*/
ORTP_PUBLIC const rtcp_common_header_t * rtcp_get_common_header(const mblk_t *m);
 
/*Sender Report accessors */
/* check if this packet is a SR and if it is correct */
ORTP_PUBLIC bool_t rtcp_is_SR(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_SR_get_ssrc(const mblk_t *m);
ORTP_PUBLIC const sender_info_t * rtcp_SR_get_sender_info(const mblk_t *m);
ORTP_PUBLIC const report_block_t * rtcp_SR_get_report_block(const mblk_t *m, int idx);
 
/*Receiver report accessors*/
ORTP_PUBLIC bool_t rtcp_is_RR(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_RR_get_ssrc(const mblk_t *m);
ORTP_PUBLIC const report_block_t * rtcp_RR_get_report_block(const mblk_t *m,int idx);
 
/*SDES accessors */
ORTP_PUBLIC bool_t rtcp_is_SDES(const mblk_t *m);
typedef void (*SdesItemFoundCallback)(void *user_data, uint32_t csrc, rtcp_sdes_type_t t, const char *content, uint8_t content_len);
ORTP_PUBLIC void rtcp_sdes_parse(const mblk_t *m, SdesItemFoundCallback cb, void *user_data);
 
/*BYE accessors */
ORTP_PUBLIC bool_t rtcp_is_BYE(const mblk_t *m);
ORTP_PUBLIC bool_t rtcp_BYE_get_ssrc(const mblk_t *m, int idx, uint32_t *ssrc);
ORTP_PUBLIC bool_t rtcp_BYE_get_reason(const mblk_t *m, const char **reason, int *reason_len);
 
/*APP accessors */
ORTP_PUBLIC bool_t rtcp_is_APP(const mblk_t *m);
ORTP_PUBLIC int rtcp_APP_get_subtype(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_APP_get_ssrc(const mblk_t *m);
/* name argument is supposed to be at least 4 characters (note: no '\0' written)*/
ORTP_PUBLIC void rtcp_APP_get_name(const mblk_t *m, char *name);
/* retrieve the data. when returning, data points directly into the mblk_t */
ORTP_PUBLIC void rtcp_APP_get_data(const mblk_t *m, uint8_t **data, int *len);
 
/* RTCP XR accessors */
ORTP_PUBLIC bool_t rtcp_is_XR(const mblk_t *m);
ORTP_PUBLIC rtcp_xr_block_type_t rtcp_XR_get_block_type(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_get_ssrc(const mblk_t *m);
ORTP_PUBLIC uint64_t rtcp_XR_rcvr_rtt_get_ntp_timestamp(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_dlrr_get_ssrc(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_dlrr_get_lrr(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_dlrr_get_dlrr(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_stat_summary_get_flags(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_ssrc(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_stat_summary_get_begin_seq(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_stat_summary_get_end_seq(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_lost_packets(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_dup_packets(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_min_jitter(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_max_jitter(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_mean_jitter(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_stat_summary_get_dev_jitter(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_stat_summary_get_min_ttl_or_hl(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_stat_summary_get_max_ttl_or_hl(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_stat_summary_get_mean_ttl_or_hl(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_stat_summary_get_dev_ttl_or_hl(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_XR_voip_metrics_get_ssrc(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_loss_rate(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_discard_rate(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_burst_density(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_gap_density(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_burst_duration(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_gap_duration(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_round_trip_delay(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_end_system_delay(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_signal_level(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_noise_level(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_rerl(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_gmin(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_r_factor(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_ext_r_factor(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_mos_lq(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_mos_cq(const mblk_t *m);
ORTP_PUBLIC uint8_t rtcp_XR_voip_metrics_get_rx_config(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_jb_nominal(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_jb_maximum(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_XR_voip_metrics_get_jb_abs_max(const mblk_t *m);
 
/* RTCP RTPFB accessors */
ORTP_PUBLIC bool_t rtcp_is_RTPFB(const mblk_t *m);
ORTP_PUBLIC rtcp_rtpfb_type_t rtcp_RTPFB_get_type(const mblk_t *m);
ORTP_PUBLIC rtcp_fb_generic_nack_fci_t * rtcp_RTPFB_generic_nack_get_fci(const mblk_t *m);
ORTP_PUBLIC rtcp_fb_tmmbr_fci_t * rtcp_RTPFB_tmmbr_get_fci(const mblk_t *m);
/**
 * Return the maximum bitrate in bits / sec contained in the packet.
 *
 * @param m RTCP TMMBR packet to read
 * @return maximum bitrate in bits / sec.
 */
ORTP_PUBLIC uint64_t rtcp_RTPFB_tmmbr_get_max_bitrate(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_RTPFB_get_packet_sender_ssrc(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_RTPFB_get_media_source_ssrc(const mblk_t *m);
 
/* RTCP PSFB accessors */
ORTP_PUBLIC bool_t rtcp_is_PSFB(const mblk_t *m);
ORTP_PUBLIC rtcp_psfb_type_t rtcp_PSFB_get_type(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_PSFB_get_packet_sender_ssrc(const mblk_t *m);
ORTP_PUBLIC uint32_t rtcp_PSFB_get_media_source_ssrc(const mblk_t *m);
ORTP_PUBLIC rtcp_fb_fir_fci_t * rtcp_PSFB_fir_get_fci(const mblk_t *m, unsigned int idx);
ORTP_PUBLIC rtcp_fb_sli_fci_t * rtcp_PSFB_sli_get_fci(const mblk_t *m, unsigned int idx);
ORTP_PUBLIC rtcp_fb_rpsi_fci_t * rtcp_PSFB_rpsi_get_fci(const mblk_t *m);
ORTP_PUBLIC uint16_t rtcp_PSFB_rpsi_get_fci_bit_string_len(const mblk_t *m);
 
 
typedef struct OrtpLossRateEstimator{
    int min_packet_count_interval;
    uint64_t min_time_ms_interval;
    uint64_t last_estimate_time_ms;
    int32_t last_cum_loss;
    int32_t last_ext_seq;
    float loss_rate;
    /**
    * Total number of outgoing duplicate packets on last
    * ortp_loss_rate_estimator_process_report_block iteration.
    **/
    int64_t last_dup_packet_sent_count;
    /**
    * Total number of outgoing unique packets on last
    * ortp_loss_rate_estimator_process_report_block iteration.
    **/
    int64_t last_packet_sent_count;
}OrtpLossRateEstimator;
 
 
ORTP_PUBLIC OrtpLossRateEstimator * ortp_loss_rate_estimator_new(int min_packet_count_interval, uint64_t min_time_ms_interval, struct _RtpSession *session);
 
ORTP_PUBLIC void ortp_loss_rate_estimator_init(OrtpLossRateEstimator *obj, int min_packet_count_interval, uint64_t min_time_ms_interval, struct _RtpSession *session);
 
 
/**
 * Process an incoming report block to compute loss rate percentage. It tries to compute
 * loss rate, depending on the previous report block. It may fails if the two
 * reports are too close or if a discontinuity occurred. You should NOT use
 * loss rate field of the report block directly (see below).
 * This estimator is useful for two reasons: first, on AVPF session, multiple
 * reports can be received in a short period and loss_rate contained in these
 * reports is unreliable. Secondly, it computes the loss rate using the
 * cumulative loss factor which allows us to take into consideration duplicates
 * packets as well.
 * @param[in] obj #OrtpLossRateEstimator object.
 * @param[in] session #_RtpSession stream in which the report block to consider belongs.
 * @param[in] rb Report block to analyze.
 * @return TRUE if a new loss rate estimation is ready, FALSE otherwise.
 */
ORTP_PUBLIC bool_t ortp_loss_rate_estimator_process_report_block(OrtpLossRateEstimator *obj,
                                                                 const struct _RtpSession *session,
                                                                 const report_block_t *rb);
/**
 * Get the latest loss rate in percentage estimation computed.
 *
 * @param obj #OrtpLossRateEstimator object.
 * @return The latest loss rate in percentage computed.
 */
ORTP_PUBLIC float ortp_loss_rate_estimator_get_value(OrtpLossRateEstimator *obj);
 
ORTP_PUBLIC void ortp_loss_rate_estimator_destroy(OrtpLossRateEstimator *obj);
 
#ifdef __cplusplus
}
#endif
 
#endif