Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjmedia / src / pjmedia / rtcp.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20 #include <pjmedia/rtcp.h>
21 #include <pjmedia/errno.h>
22 #include <pj/assert.h>
23 #include <pj/log.h>
24 #include <pj/os.h>
25 #include <pj/sock.h>
26 #include <pj/string.h>
27
28 #define THIS_FILE "rtcp.c"
29
30 #define RTCP_SR   200
31 #define RTCP_RR   201
32 #define RTCP_SDES 202
33 #define RTCP_BYE  203
34 #define RTCP_XR   207
35
36 enum {
37     RTCP_SDES_NULL  = 0,
38     RTCP_SDES_CNAME = 1,
39     RTCP_SDES_NAME  = 2,
40     RTCP_SDES_EMAIL = 3,
41     RTCP_SDES_PHONE = 4,
42     RTCP_SDES_LOC   = 5,
43     RTCP_SDES_TOOL  = 6,
44     RTCP_SDES_NOTE  = 7
45 };
46
47 #if PJ_HAS_HIGH_RES_TIMER==0
48 #   error "High resolution timer needs to be enabled"
49 #endif
50
51
52
53 #if 0
54 #   define TRACE_(x)    PJ_LOG(3,x)
55 #else
56 #   define TRACE_(x)    ;
57 #endif
58
59
60 /*
61  * Get NTP time.
62  */
63 PJ_DEF(pj_status_t) pjmedia_rtcp_get_ntp_time(const pjmedia_rtcp_session *sess,
64                                               pjmedia_rtcp_ntp_rec *ntp)
65 {
66 /* Seconds between 1900-01-01 to 1970-01-01 */
67 #define JAN_1970  (2208988800UL)
68     pj_timestamp ts;
69     pj_status_t status;
70
71     status = pj_get_timestamp(&ts);
72
73     /* Fill up the high 32bit part */
74     ntp->hi = (pj_uint32_t)((ts.u64 - sess->ts_base.u64) / sess->ts_freq.u64)
75               + sess->tv_base.sec + JAN_1970;
76
77     /* Calculate seconds fractions */
78     ts.u64 = (ts.u64 - sess->ts_base.u64) % sess->ts_freq.u64;
79     pj_assert(ts.u64 < sess->ts_freq.u64);
80     ts.u64 = (ts.u64 << 32) / sess->ts_freq.u64;
81
82     /* Fill up the low 32bit part */
83     ntp->lo = ts.u32.lo;
84
85
86 #if (defined(PJ_WIN32) && PJ_WIN32!=0) || \
87     (defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0)
88
89     /* On Win32, since we use QueryPerformanceCounter() as the backend
90      * timestamp API, we need to protect against this bug:
91      *   Performance counter value may unexpectedly leap forward
92      *   http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q274323
93      */
94     {
95         /*
96          * Compare elapsed time reported by timestamp with actual elapsed 
97          * time. If the difference is too excessive, then we use system
98          * time instead.
99          */
100
101         /* MIN_DIFF needs to be large enough so that "normal" diff caused
102          * by system activity or context switch doesn't trigger the time
103          * correction.
104          */
105         enum { MIN_DIFF = 400 };
106
107         pj_time_val ts_time, elapsed, diff;
108
109         pj_gettimeofday(&elapsed);
110
111         ts_time.sec = ntp->hi - sess->tv_base.sec - JAN_1970;
112         ts_time.msec = (long)(ntp->lo * 1000.0 / 0xFFFFFFFF);
113
114         PJ_TIME_VAL_SUB(elapsed, sess->tv_base);
115
116         if (PJ_TIME_VAL_LT(ts_time, elapsed)) {
117             diff = elapsed;
118             PJ_TIME_VAL_SUB(diff, ts_time);
119         } else {
120             diff = ts_time;
121             PJ_TIME_VAL_SUB(diff, elapsed);
122         }
123
124         if (PJ_TIME_VAL_MSEC(diff) >= MIN_DIFF) {
125
126             TRACE_((sess->name, "RTCP NTP timestamp corrected by %d ms",
127                     PJ_TIME_VAL_MSEC(diff)));
128
129
130             ntp->hi = elapsed.sec + sess->tv_base.sec + JAN_1970;
131             ntp->lo = (elapsed.msec * 65536 / 1000) << 16;
132         }
133
134     }
135 #endif
136
137     return status;
138 }
139
140
141 /*
142  * Initialize RTCP session setting.
143  */
144 PJ_DEF(void) pjmedia_rtcp_session_setting_default(
145                                     pjmedia_rtcp_session_setting *settings)
146 {
147     pj_bzero(settings, sizeof(*settings));
148 }
149
150
151 /*
152  * Initialize bidirectional RTCP statistics.
153  *
154  */
155 PJ_DEF(void) pjmedia_rtcp_init_stat(pjmedia_rtcp_stat *stat)
156 {
157     pj_time_val now;
158
159     pj_assert(stat);
160
161     pj_bzero(stat, sizeof(pjmedia_rtcp_stat));
162
163     pj_math_stat_init(&stat->rtt);
164     pj_math_stat_init(&stat->rx.loss_period);
165     pj_math_stat_init(&stat->rx.jitter);
166     pj_math_stat_init(&stat->tx.loss_period);
167     pj_math_stat_init(&stat->tx.jitter);
168
169 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
170     pj_math_stat_init(&stat->rx_ipdv);
171 #endif
172
173 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
174     pj_math_stat_init(&stat->rx_raw_jitter);
175 #endif
176
177     pj_gettimeofday(&now);
178     stat->start = now;
179 }
180
181
182 /*
183  * Initialize RTCP session.
184  */
185 PJ_DEF(void) pjmedia_rtcp_init(pjmedia_rtcp_session *sess, 
186                                char *name,
187                                unsigned clock_rate,
188                                unsigned samples_per_frame,
189                                pj_uint32_t ssrc)
190 {
191     pjmedia_rtcp_session_setting settings;
192
193     pjmedia_rtcp_session_setting_default(&settings);
194     settings.name = name;
195     settings.clock_rate = clock_rate;
196     settings.samples_per_frame = samples_per_frame;
197     settings.ssrc = ssrc;
198
199     pjmedia_rtcp_init2(sess, &settings);
200 }
201
202
203 /*
204  * Initialize RTCP session.
205  */
206 PJ_DEF(void) pjmedia_rtcp_init2( pjmedia_rtcp_session *sess,
207                                  const pjmedia_rtcp_session_setting *settings)
208 {
209     pjmedia_rtcp_sr_pkt *sr_pkt = &sess->rtcp_sr_pkt;
210     pj_time_val now;
211     
212     /* Memset everything */
213     pj_bzero(sess, sizeof(pjmedia_rtcp_session));
214
215     /* Last RX timestamp in RTP packet */
216     sess->rtp_last_ts = (unsigned)-1;
217
218     /* Name */
219     sess->name = settings->name ? settings->name : (char*)THIS_FILE;
220
221     /* Set clock rate */
222     sess->clock_rate = settings->clock_rate;
223     sess->pkt_size = settings->samples_per_frame;
224
225     /* Init common RTCP SR header */
226     sr_pkt->common.version = 2;
227     sr_pkt->common.count = 1;
228     sr_pkt->common.pt = RTCP_SR;
229     sr_pkt->common.length = pj_htons(12);
230     sr_pkt->common.ssrc = pj_htonl(settings->ssrc);
231     
232     /* Copy to RTCP RR header */
233     pj_memcpy(&sess->rtcp_rr_pkt.common, &sr_pkt->common, 
234               sizeof(pjmedia_rtcp_common));
235     sess->rtcp_rr_pkt.common.pt = RTCP_RR;
236     sess->rtcp_rr_pkt.common.length = pj_htons(7);
237
238     /* Get time and timestamp base and frequency */
239     pj_gettimeofday(&now);
240     sess->tv_base = now;
241     pj_get_timestamp(&sess->ts_base);
242     pj_get_timestamp_freq(&sess->ts_freq);
243     sess->rtp_ts_base = settings->rtp_ts_base;
244
245     /* Initialize statistics states */
246     pjmedia_rtcp_init_stat(&sess->stat);
247
248     /* RR will be initialized on receipt of the first RTP packet. */
249 }
250
251
252 PJ_DEF(void) pjmedia_rtcp_fini(pjmedia_rtcp_session *sess)
253 {
254 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
255     pjmedia_rtcp_xr_fini(&sess->xr_session);
256 #else
257     /* Nothing to do. */
258     PJ_UNUSED_ARG(sess);
259 #endif
260 }
261
262 static void rtcp_init_seq(pjmedia_rtcp_session *sess)
263 {
264     sess->received = 0;
265     sess->exp_prior = 0;
266     sess->rx_prior = 0;
267     sess->transit = 0;
268     sess->jitter = 0;
269 }
270
271 PJ_DEF(void) pjmedia_rtcp_rx_rtp( pjmedia_rtcp_session *sess, 
272                                   unsigned seq, 
273                                   unsigned rtp_ts,
274                                   unsigned payload)
275 {
276     pjmedia_rtcp_rx_rtp2(sess, seq, rtp_ts, payload, PJ_FALSE);
277 }
278
279 PJ_DEF(void) pjmedia_rtcp_rx_rtp2(pjmedia_rtcp_session *sess, 
280                                   unsigned seq, 
281                                   unsigned rtp_ts,
282                                   unsigned payload,
283                                   pj_bool_t discarded)
284 {   
285     pj_timestamp ts;
286     pj_uint32_t arrival;
287     pj_int32_t transit;
288     pjmedia_rtp_status seq_st;
289     unsigned last_seq;
290
291 #if !defined(PJMEDIA_HAS_RTCP_XR) || (PJMEDIA_HAS_RTCP_XR == 0)
292     PJ_UNUSED_ARG(discarded);
293 #endif
294
295     if (sess->stat.rx.pkt == 0) {
296         /* Init sequence for the first time. */
297         pjmedia_rtp_seq_init(&sess->seq_ctrl, (pj_uint16_t)seq);
298     } 
299
300     sess->stat.rx.pkt++;
301     sess->stat.rx.bytes += payload;
302
303     /* Process the RTP packet. */
304     last_seq = sess->seq_ctrl.max_seq;
305     pjmedia_rtp_seq_update(&sess->seq_ctrl, (pj_uint16_t)seq, &seq_st);
306
307     if (seq_st.status.flag.restart) {
308         rtcp_init_seq(sess);
309     }
310     
311     if (seq_st.status.flag.dup) {
312         sess->stat.rx.dup++;
313         TRACE_((sess->name, "Duplicate packet detected"));
314     }
315
316     if (seq_st.status.flag.outorder && !seq_st.status.flag.probation) {
317         sess->stat.rx.reorder++;
318         TRACE_((sess->name, "Out-of-order packet detected"));
319     }
320
321     if (seq_st.status.flag.bad) {
322         sess->stat.rx.discard++;
323
324 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
325         pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
326                                -1,                               /* lost    */
327                                (seq_st.status.flag.dup? 1:0),    /* dup     */
328                                (!seq_st.status.flag.dup? 1:-1),  /* discard */
329                                -1,                               /* jitter  */
330                                -1, 0);                           /* toh     */
331 #endif
332
333         TRACE_((sess->name, "Bad packet discarded"));
334         return;
335     }
336
337     /* Only mark "good" packets */
338     ++sess->received;
339
340     /* Calculate loss periods. */
341     if (seq_st.diff > 1) {
342         unsigned count = seq_st.diff - 1;
343         unsigned period;
344
345         period = count * sess->pkt_size * 1000 / sess->clock_rate;
346         period *= 1000;
347
348         /* Update packet lost. 
349          * The packet lost number will also be updated when we're sending
350          * outbound RTCP RR.
351          */
352         sess->stat.rx.loss += (seq_st.diff - 1);
353         TRACE_((sess->name, "%d packet(s) lost", seq_st.diff - 1));
354
355         /* Update loss period stat */
356         pj_math_stat_update(&sess->stat.rx.loss_period, period);
357     }
358
359
360     /*
361      * Calculate jitter only when sequence is good (see RFC 3550 section A.8),
362      * AND only when the timestamp is different than the last packet
363      * (see RTP FAQ).
364      */
365     if (seq_st.diff == 1 && rtp_ts != sess->rtp_last_ts) {
366         /* Get arrival time and convert timestamp to samples */
367         pj_get_timestamp(&ts);
368         ts.u64 = ts.u64 * sess->clock_rate / sess->ts_freq.u64;
369         arrival = ts.u32.lo;
370
371         transit = arrival - rtp_ts;
372     
373         /* Ignore the first N packets as they normally have bad jitter
374          * due to other threads working to establish the call
375          */
376         if (sess->transit == 0 || 
377             sess->received < PJMEDIA_RTCP_IGNORE_FIRST_PACKETS) 
378         {
379             sess->transit = transit;
380             sess->stat.rx.jitter.min = (unsigned)-1;
381         } else {
382             pj_int32_t d;
383             pj_uint32_t jitter;
384
385             d = transit - sess->transit;
386             if (d < 0) 
387                 d = -d;
388             
389             sess->jitter += d - ((sess->jitter + 8) >> 4);
390
391             /* Update jitter stat */
392             jitter = sess->jitter >> 4;
393             
394             /* Convert jitter unit from samples to usec */
395             if (jitter < 4294)
396                 jitter = jitter * 1000000 / sess->clock_rate;
397             else {
398                 jitter = jitter * 1000 / sess->clock_rate;
399                 jitter *= 1000;
400             }
401             pj_math_stat_update(&sess->stat.rx.jitter, jitter);
402
403
404 #if defined(PJMEDIA_RTCP_STAT_HAS_RAW_JITTER) && PJMEDIA_RTCP_STAT_HAS_RAW_JITTER!=0
405             {
406                 pj_uint32_t raw_jitter;
407
408                 /* Convert raw jitter unit from samples to usec */
409                 if (d < 4294)
410                     raw_jitter = d * 1000000 / sess->clock_rate;
411                 else {
412                     raw_jitter = d * 1000 / sess->clock_rate;
413                     raw_jitter *= 1000;
414                 }
415                 
416                 /* Update jitter stat */
417                 pj_math_stat_update(&sess->stat.rx_raw_jitter, raw_jitter);
418             }
419 #endif
420
421
422 #if defined(PJMEDIA_RTCP_STAT_HAS_IPDV) && PJMEDIA_RTCP_STAT_HAS_IPDV!=0
423             {
424                 pj_int32_t ipdv;
425
426                 ipdv = transit - sess->transit;
427                 /* Convert IPDV unit from samples to usec */
428                 if (ipdv > -2147 && ipdv < 2147)
429                     ipdv = ipdv * 1000000 / (int)sess->clock_rate;
430                 else {
431                     ipdv = ipdv * 1000 / (int)sess->clock_rate;
432                     ipdv *= 1000;
433                 }
434                 
435                 /* Update jitter stat */
436                 pj_math_stat_update(&sess->stat.rx_ipdv, ipdv);
437             }
438 #endif
439
440 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
441             pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
442                                    0,                       /* lost    */
443                                    0,                       /* dup     */
444                                    discarded,               /* discard */
445                                    (sess->jitter >> 4),     /* jitter  */
446                                    -1, 0);                  /* toh     */
447 #endif
448
449             /* Update session transit */
450             sess->transit = transit;
451         }
452 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
453     } else if (seq_st.diff > 1) {
454         int i;
455
456         /* Report RTCP XR about packet losses */
457         for (i=seq_st.diff-1; i>0; --i) {
458             pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq - i, 
459                                    1,                       /* lost    */
460                                    0,                       /* dup     */
461                                    0,                       /* discard */
462                                    -1,                      /* jitter  */
463                                    -1, 0);                  /* toh     */
464         }
465
466         /* Report RTCP XR this packet */
467         pjmedia_rtcp_xr_rx_rtp(&sess->xr_session, seq, 
468                                0,                           /* lost    */
469                                0,                           /* dup     */
470                                discarded,                   /* discard */
471                                -1,                          /* jitter  */
472                                -1, 0);                      /* toh     */
473 #endif
474     }
475
476     /* Update timestamp of last RX RTP packet */
477     sess->rtp_last_ts = rtp_ts;
478 }
479
480 PJ_DEF(void) pjmedia_rtcp_tx_rtp(pjmedia_rtcp_session *sess, 
481                                  unsigned bytes_payload_size)
482 {
483     /* Update statistics */
484     sess->stat.tx.pkt++;
485     sess->stat.tx.bytes += bytes_payload_size;
486 }
487
488
489 static void parse_rtcp_report( pjmedia_rtcp_session *sess,
490                                const void *pkt,
491                                pj_size_t size)
492 {
493     pjmedia_rtcp_common *common = (pjmedia_rtcp_common*) pkt;
494     const pjmedia_rtcp_rr *rr = NULL;
495     const pjmedia_rtcp_sr *sr = NULL;
496     pj_uint32_t last_loss, jitter_samp, jitter;
497
498     /* Parse RTCP */
499     if (common->pt == RTCP_SR) {
500         sr = (pjmedia_rtcp_sr*) (((char*)pkt) + sizeof(pjmedia_rtcp_common));
501         if (common->count > 0 && size >= (sizeof(pjmedia_rtcp_sr_pkt))) {
502             rr = (pjmedia_rtcp_rr*)(((char*)pkt) + (sizeof(pjmedia_rtcp_common)
503                                     + sizeof(pjmedia_rtcp_sr)));
504         }
505     } else if (common->pt == RTCP_RR && common->count > 0) {
506         rr = (pjmedia_rtcp_rr*)(((char*)pkt) + sizeof(pjmedia_rtcp_common));
507 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
508     } else if (common->pt == RTCP_XR) {
509         if (sess->xr_enabled)
510             pjmedia_rtcp_xr_rx_rtcp_xr(&sess->xr_session, pkt, size);
511
512         return;
513 #endif
514     }
515
516
517     if (sr) {
518         /* Save LSR from NTP timestamp of RTCP packet */
519         sess->rx_lsr = ((pj_ntohl(sr->ntp_sec) & 0x0000FFFF) << 16) | 
520                        ((pj_ntohl(sr->ntp_frac) >> 16) & 0xFFFF);
521
522         /* Calculate SR arrival time for DLSR */
523         pj_get_timestamp(&sess->rx_lsr_time);
524
525         TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p", 
526                 sess->rx_lsr,
527                 (pj_uint32_t)(sess->rx_lsr_time.u64*65536/sess->ts_freq.u64)));
528     }
529
530
531     /* Nothing more to do if there's no RR packet */
532     if (rr == NULL)
533         return;
534
535
536     last_loss = sess->stat.tx.loss;
537
538     /* Get packet loss */
539     sess->stat.tx.loss = (rr->total_lost_2 << 16) +
540                          (rr->total_lost_1 << 8) +
541                           rr->total_lost_0;
542
543     TRACE_((sess->name, "Rx RTCP RR: total_lost_2=%x, 1=%x, 0=%x, lost=%d", 
544             (int)rr->total_lost_2,
545             (int)rr->total_lost_1,
546             (int)rr->total_lost_0,
547             sess->stat.tx.loss));
548     
549     /* We can't calculate the exact loss period for TX, so just give the
550      * best estimation.
551      */
552     if (sess->stat.tx.loss > last_loss) {
553         unsigned period;
554
555         /* Loss period in msec */
556         period = (sess->stat.tx.loss - last_loss) * sess->pkt_size *
557                  1000 / sess->clock_rate;
558
559         /* Loss period in usec */
560         period *= 1000;
561
562         /* Update loss period stat */
563         pj_math_stat_update(&sess->stat.tx.loss_period, period);
564     }
565
566     /* Get jitter value in usec */
567     jitter_samp = pj_ntohl(rr->jitter);
568     /* Calculate jitter in usec, avoiding overflows */
569     if (jitter_samp <= 4294)
570         jitter = jitter_samp * 1000000 / sess->clock_rate;
571     else {
572         jitter = jitter_samp * 1000 / sess->clock_rate;
573         jitter *= 1000;
574     }
575
576     /* Update jitter statistics */
577     pj_math_stat_update(&sess->stat.tx.jitter, jitter);
578
579     /* Can only calculate if LSR and DLSR is present in RR */
580     if (rr->lsr && rr->dlsr) {
581         pj_uint32_t lsr, now, dlsr;
582         pj_uint64_t eedelay;
583         pjmedia_rtcp_ntp_rec ntp;
584
585         /* LSR is the middle 32bit of NTP. It has 1/65536 second 
586          * resolution 
587          */
588         lsr = pj_ntohl(rr->lsr);
589
590         /* DLSR is delay since LSR, also in 1/65536 resolution */
591         dlsr = pj_ntohl(rr->dlsr);
592
593         /* Get current time, and convert to 1/65536 resolution */
594         pjmedia_rtcp_get_ntp_time(sess, &ntp);
595         now = ((ntp.hi & 0xFFFF) << 16) + (ntp.lo >> 16);
596
597         /* End-to-end delay is (now-lsr-dlsr) */
598         eedelay = now - lsr - dlsr;
599
600         /* Convert end to end delay to usec (keeping the calculation in
601          * 64bit space)::
602          *   sess->ee_delay = (eedelay * 1000) / 65536;
603          */
604         if (eedelay < 4294) {
605             eedelay = (eedelay * 1000000) >> 16;
606         } else {
607             eedelay = (eedelay * 1000) >> 16;
608             eedelay *= 1000;
609         }
610
611         TRACE_((sess->name, "Rx RTCP RR: lsr=%p, dlsr=%p (%d:%03dms), "
612                            "now=%p, rtt=%p",
613                 lsr, dlsr, dlsr/65536, (dlsr%65536)*1000/65536,
614                 now, (pj_uint32_t)eedelay));
615         
616         /* Only save calculation if "now" is greater than lsr, or
617          * otherwise rtt will be invalid 
618          */
619         if (now-dlsr >= lsr) {
620             unsigned rtt = (pj_uint32_t)eedelay;
621             
622             /* Check that eedelay value really makes sense. 
623              * We allow up to 30 seconds RTT!
624              */
625             if (eedelay > 30 * 1000 * 1000UL) {
626
627                 TRACE_((sess->name, "RTT not making any sense, ignored.."));
628                 goto end_rtt_calc;
629             }
630
631 #if defined(PJMEDIA_RTCP_NORMALIZE_FACTOR) && PJMEDIA_RTCP_NORMALIZE_FACTOR!=0
632             /* "Normalize" rtt value that is exceptionally high. For such
633              * values, "normalize" the rtt to be PJMEDIA_RTCP_NORMALIZE_FACTOR
634              * times the average value.
635              */
636             if (rtt > ((unsigned)sess->stat.rtt.mean *
637                        PJMEDIA_RTCP_NORMALIZE_FACTOR) && sess->stat.rtt.n!=0)
638             {
639                 unsigned orig_rtt = rtt;
640                 rtt = sess->stat.rtt.mean * PJMEDIA_RTCP_NORMALIZE_FACTOR;
641                 PJ_LOG(5,(sess->name,
642                           "RTT value %d usec is normalized to %d usec",
643                           orig_rtt, rtt));
644             }
645 #endif
646             TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
647
648             /* Update RTT stat */
649             pj_math_stat_update(&sess->stat.rtt, rtt);
650
651         } else {
652             PJ_LOG(5, (sess->name, "Internal RTCP NTP clock skew detected: "
653                                    "lsr=%p, now=%p, dlsr=%p (%d:%03dms), "
654                                    "diff=%d",
655                                    lsr, now, dlsr, dlsr/65536,
656                                    (dlsr%65536)*1000/65536,
657                                    dlsr-(now-lsr)));
658         }
659     }
660
661 end_rtt_calc:
662
663     pj_gettimeofday(&sess->stat.tx.update);
664     sess->stat.tx.update_cnt++;
665 }
666
667
668 static void parse_rtcp_sdes(pjmedia_rtcp_session *sess,
669                             const void *pkt,
670                             pj_size_t size)
671 {
672     pjmedia_rtcp_sdes *sdes = &sess->stat.peer_sdes;
673     char *p, *p_end;
674     char *b, *b_end;
675
676     p = (char*)pkt + 8;
677     p_end = (char*)pkt + size;
678
679     pj_bzero(sdes, sizeof(*sdes));
680     b = sess->stat.peer_sdes_buf_;
681     b_end = b + sizeof(sess->stat.peer_sdes_buf_);
682
683     while (p < p_end) {
684         pj_uint8_t sdes_type, sdes_len;
685         pj_str_t sdes_value = {NULL, 0};
686
687         sdes_type = *p++;
688
689         /* Check for end of SDES item list */
690         if (sdes_type == RTCP_SDES_NULL || p == p_end)
691             break;
692
693         sdes_len = *p++;
694
695         /* Check for corrupted SDES packet */
696         if (p + sdes_len > p_end)
697             break;
698
699         /* Get SDES item */
700         if (b + sdes_len < b_end) {
701             pj_memcpy(b, p, sdes_len);
702             sdes_value.ptr = b;
703             sdes_value.slen = sdes_len;
704             b += sdes_len;
705         } else {
706             /* Insufficient SDES buffer */
707             PJ_LOG(5, (sess->name,
708                     "Unsufficient buffer to save RTCP SDES type %d:%.*s",
709                     sdes_type, sdes_len, p));
710             p += sdes_len;
711             continue;
712         }
713
714         switch (sdes_type) {
715         case RTCP_SDES_CNAME:
716             sdes->cname = sdes_value;
717             break;
718         case RTCP_SDES_NAME:
719             sdes->name = sdes_value;
720             break;
721         case RTCP_SDES_EMAIL:
722             sdes->email = sdes_value;
723             break;
724         case RTCP_SDES_PHONE:
725             sdes->phone = sdes_value;
726             break;
727         case RTCP_SDES_LOC:
728             sdes->loc = sdes_value;
729             break;
730         case RTCP_SDES_TOOL:
731             sdes->tool = sdes_value;
732             break;
733         case RTCP_SDES_NOTE:
734             sdes->note = sdes_value;
735             break;
736         default:
737             TRACE_((sess->name, "Received unknown RTCP SDES type %d:%.*s",
738                     sdes_type, sdes_value.slen, sdes_value.ptr));
739             break;
740         }
741
742         p += sdes_len;
743     }
744 }
745
746
747 static void parse_rtcp_bye(pjmedia_rtcp_session *sess,
748                            const void *pkt,
749                            pj_size_t size)
750 {
751     pj_str_t reason = {"-", 1};
752
753     /* Check and get BYE reason */
754     if (size > 8) {
755         reason.slen = *((pj_uint8_t*)pkt+8);
756         pj_memcpy(sess->stat.peer_sdes_buf_, ((pj_uint8_t*)pkt+9),
757                   reason.slen);
758         reason.ptr = sess->stat.peer_sdes_buf_;
759     }
760
761     /* Just print RTCP BYE log */
762     PJ_LOG(5, (sess->name, "Received RTCP BYE, reason: %.*s",
763                reason.slen, reason.ptr));
764 }
765
766
767 PJ_DEF(void) pjmedia_rtcp_rx_rtcp( pjmedia_rtcp_session *sess,
768                                    const void *pkt,
769                                    pj_size_t size)
770 {
771     pj_uint8_t *p, *p_end;
772
773     p = (pj_uint8_t*)pkt;
774     p_end = p + size;
775     while (p < p_end) {
776         pjmedia_rtcp_common *common = (pjmedia_rtcp_common*)p;
777         unsigned len;
778
779         len = (pj_ntohs((pj_uint16_t)common->length)+1) * 4;
780         switch(common->pt) {
781         case RTCP_SR:
782         case RTCP_RR:
783         case RTCP_XR:
784             parse_rtcp_report(sess, p, len);
785             break;
786         case RTCP_SDES:
787             parse_rtcp_sdes(sess, p, len);
788             break;
789         case RTCP_BYE:
790             parse_rtcp_bye(sess, p, len);
791             break;
792         default:
793             /* Ignore unknown RTCP */
794             TRACE_((sess->name, "Received unknown RTCP packet type=%d",
795                     common->pt));
796             break;
797         }
798
799         p += len;
800     }
801 }
802
803
804 PJ_DEF(void) pjmedia_rtcp_build_rtcp(pjmedia_rtcp_session *sess, 
805                                      void **ret_p_pkt, int *len)
806 {
807     pj_uint32_t expected, expected_interval, received_interval, lost_interval;
808     pjmedia_rtcp_common *common;
809     pjmedia_rtcp_sr *sr;
810     pjmedia_rtcp_rr *rr;
811     pj_timestamp ts_now;
812     pjmedia_rtcp_ntp_rec ntp;
813
814     /* Get current NTP time. */
815     pj_get_timestamp(&ts_now);
816     pjmedia_rtcp_get_ntp_time(sess, &ntp);
817
818
819     /* See if we have transmitted RTP packets since last time we
820      * sent RTCP SR.
821      */
822     if (sess->stat.tx.pkt != pj_ntohl(sess->rtcp_sr_pkt.sr.sender_pcount)) {
823         pj_time_val ts_time;
824         pj_uint32_t rtp_ts;
825
826         /* So we should send RTCP SR */
827         *ret_p_pkt = (void*) &sess->rtcp_sr_pkt;
828         *len = sizeof(pjmedia_rtcp_sr_pkt);
829         common = &sess->rtcp_sr_pkt.common;
830         rr = &sess->rtcp_sr_pkt.rr;
831         sr = &sess->rtcp_sr_pkt.sr;
832
833         /* Update packet count */
834         sr->sender_pcount = pj_htonl(sess->stat.tx.pkt);
835
836         /* Update octets count */
837         sr->sender_bcount = pj_htonl(sess->stat.tx.bytes);
838
839         /* Fill in NTP timestamp in SR. */
840         sr->ntp_sec = pj_htonl(ntp.hi);
841         sr->ntp_frac = pj_htonl(ntp.lo);
842
843         /* Fill in RTP timestamp (corresponds to NTP timestamp) in SR. */
844         ts_time.sec = ntp.hi - sess->tv_base.sec - JAN_1970;
845         ts_time.msec = (long)(ntp.lo * 1000.0 / 0xFFFFFFFF);
846         rtp_ts = sess->rtp_ts_base +
847                  (pj_uint32_t)(sess->clock_rate*ts_time.sec) +
848                  (pj_uint32_t)(sess->clock_rate*ts_time.msec/1000);
849         sr->rtp_ts = pj_htonl(rtp_ts);
850
851         TRACE_((sess->name, "TX RTCP SR: ntp_ts=%p", 
852                            ((ntp.hi & 0xFFFF) << 16) + ((ntp.lo & 0xFFFF0000) 
853                                 >> 16)));
854
855
856     } else {
857         /* We should send RTCP RR then */
858         *ret_p_pkt = (void*) &sess->rtcp_rr_pkt;
859         *len = sizeof(pjmedia_rtcp_rr_pkt);
860         common = &sess->rtcp_rr_pkt.common;
861         rr = &sess->rtcp_rr_pkt.rr;
862         sr = NULL;
863     }
864     
865     /* SSRC and last_seq */
866     rr->ssrc = pj_htonl(sess->peer_ssrc);
867     rr->last_seq = (sess->seq_ctrl.cycles & 0xFFFF0000L);
868     /* Since this is an "+=" operation, make sure we update last_seq on
869      * both RR and SR.
870      */
871     sess->rtcp_sr_pkt.rr.last_seq += sess->seq_ctrl.max_seq;
872     sess->rtcp_rr_pkt.rr.last_seq += sess->seq_ctrl.max_seq;
873     rr->last_seq = pj_htonl(rr->last_seq);
874
875
876     /* Jitter */
877     rr->jitter = pj_htonl(sess->jitter >> 4);
878     
879     
880     /* Total lost. */
881     expected = pj_ntohl(rr->last_seq) - sess->seq_ctrl.base_seq;
882
883     /* This is bug: total lost already calculated on each incoming RTP!
884     if (expected >= sess->received)
885         sess->stat.rx.loss = expected - sess->received;
886     else
887         sess->stat.rx.loss = 0;
888     */
889
890     rr->total_lost_2 = (sess->stat.rx.loss >> 16) & 0xFF;
891     rr->total_lost_1 = (sess->stat.rx.loss >> 8) & 0xFF;
892     rr->total_lost_0 = (sess->stat.rx.loss & 0xFF);
893
894     /* Fraction lost calculation */
895     expected_interval = expected - sess->exp_prior;
896     sess->exp_prior = expected;
897     
898     received_interval = sess->received - sess->rx_prior;
899     sess->rx_prior = sess->received;
900     
901     if (expected_interval >= received_interval)
902         lost_interval = expected_interval - received_interval;
903     else
904         lost_interval = 0;
905     
906     if (expected_interval==0 || lost_interval == 0) {
907         rr->fract_lost = 0;
908     } else {
909         rr->fract_lost = (lost_interval << 8) / expected_interval;
910     }
911     
912     if (sess->rx_lsr_time.u64 == 0 || sess->rx_lsr == 0) {
913         rr->lsr = 0;
914         rr->dlsr = 0;
915     } else {
916         pj_timestamp ts;
917         pj_uint32_t lsr = sess->rx_lsr;
918         pj_uint64_t lsr_time = sess->rx_lsr_time.u64;
919         pj_uint32_t dlsr;
920         
921         /* Convert LSR time to 1/65536 seconds resolution */
922         lsr_time = (lsr_time << 16) / sess->ts_freq.u64;
923
924         /* Fill in LSR.
925            LSR is the middle 32bit of the last SR NTP time received.
926          */
927         rr->lsr = pj_htonl(lsr);
928         
929         /* Fill in DLSR.
930            DLSR is Delay since Last SR, in 1/65536 seconds.
931          */
932         ts.u64 = ts_now.u64;
933
934         /* Convert interval to 1/65536 seconds value */
935         ts.u64 = (ts.u64 << 16) / sess->ts_freq.u64;
936
937         /* Get DLSR */
938         dlsr = (pj_uint32_t)(ts.u64 - lsr_time);
939         rr->dlsr = pj_htonl(dlsr);
940
941         TRACE_((sess->name,"Tx RTCP RR: lsr=%p, lsr_time=%p, now=%p, dlsr=%p"
942                            "(%ds:%03dms)",
943                            lsr, 
944                            (pj_uint32_t)lsr_time,
945                            (pj_uint32_t)ts.u64, 
946                            dlsr,
947                            dlsr/65536,
948                            (dlsr%65536)*1000/65536 ));
949     }
950     
951     /* Update counter */
952     pj_gettimeofday(&sess->stat.rx.update);
953     sess->stat.rx.update_cnt++;
954 }
955
956
957 PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_sdes(
958                                             pjmedia_rtcp_session *session, 
959                                             void *buf,
960                                             pj_size_t *length,
961                                             const pjmedia_rtcp_sdes *sdes)
962 {
963     pjmedia_rtcp_common *hdr;
964     pj_uint8_t *p;
965     unsigned len;
966
967     PJ_ASSERT_RETURN(session && buf && length && sdes, PJ_EINVAL);
968
969     /* Verify SDES item length */
970     if (sdes->cname.slen > 255 || sdes->name.slen  > 255 ||
971         sdes->email.slen > 255 || sdes->phone.slen > 255 ||
972         sdes->loc.slen   > 255 || sdes->tool.slen  > 255 ||
973         sdes->note.slen  > 255)
974     {
975         return PJ_EINVAL;
976     }
977
978     /* Verify buffer length */
979     len = sizeof(*hdr);
980     if (sdes->cname.slen) len += sdes->cname.slen + 2;
981     if (sdes->name.slen)  len += sdes->name.slen  + 2;
982     if (sdes->email.slen) len += sdes->email.slen + 2;
983     if (sdes->phone.slen) len += sdes->phone.slen + 2;
984     if (sdes->loc.slen)   len += sdes->loc.slen   + 2;
985     if (sdes->tool.slen)  len += sdes->tool.slen  + 2;
986     if (sdes->note.slen)  len += sdes->note.slen  + 2;
987     len++; /* null termination */
988     len = ((len+3)/4) * 4;
989     if (len > *length)
990         return PJ_ETOOSMALL;
991
992     /* Build RTCP SDES header */
993     hdr = (pjmedia_rtcp_common*)buf;
994     pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr));
995     hdr->pt = RTCP_SDES;
996     hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
997
998     /* Build RTCP SDES items */
999     p = (pj_uint8_t*)hdr + sizeof(*hdr);
1000 #define BUILD_SDES_ITEM(SDES_NAME, SDES_TYPE) \
1001     if (sdes->SDES_NAME.slen) { \
1002         *p++ = SDES_TYPE; \
1003         *p++ = (pj_uint8_t)sdes->SDES_NAME.slen; \
1004         pj_memcpy(p, sdes->SDES_NAME.ptr, sdes->SDES_NAME.slen); \
1005         p += sdes->SDES_NAME.slen; \
1006     }
1007     BUILD_SDES_ITEM(cname, RTCP_SDES_CNAME);
1008     BUILD_SDES_ITEM(name,  RTCP_SDES_NAME);
1009     BUILD_SDES_ITEM(email, RTCP_SDES_EMAIL);
1010     BUILD_SDES_ITEM(phone, RTCP_SDES_PHONE);
1011     BUILD_SDES_ITEM(loc,   RTCP_SDES_LOC);
1012     BUILD_SDES_ITEM(tool,  RTCP_SDES_TOOL);
1013     BUILD_SDES_ITEM(note,  RTCP_SDES_NOTE);
1014 #undef BUILD_SDES_ITEM
1015
1016     /* Null termination */
1017     *p++ = 0;
1018
1019     /* Pad to 32bit */
1020     while ((p-(pj_uint8_t*)buf) % 4)
1021         *p++ = 0;
1022
1023     /* Finally */
1024     pj_assert((int)len == p-(pj_uint8_t*)buf);
1025     *length = len;
1026
1027     return PJ_SUCCESS;
1028 }
1029
1030
1031 PJ_DEF(pj_status_t) pjmedia_rtcp_build_rtcp_bye(pjmedia_rtcp_session *session,
1032                                                 void *buf,
1033                                                 pj_size_t *length,
1034                                                 const pj_str_t *reason)
1035 {
1036     pjmedia_rtcp_common *hdr;
1037     pj_uint8_t *p;
1038     unsigned len;
1039
1040     PJ_ASSERT_RETURN(session && buf && length, PJ_EINVAL);
1041
1042     /* Verify BYE reason length */
1043     if (reason && reason->slen > 255)
1044         return PJ_EINVAL;
1045
1046     /* Verify buffer length */
1047     len = sizeof(*hdr);
1048     if (reason && reason->slen) len += reason->slen + 1;
1049     len = ((len+3)/4) * 4;
1050     if (len > *length)
1051         return PJ_ETOOSMALL;
1052
1053     /* Build RTCP BYE header */
1054     hdr = (pjmedia_rtcp_common*)buf;
1055     pj_memcpy(hdr, &session->rtcp_sr_pkt.common,  sizeof(*hdr));
1056     hdr->pt = RTCP_BYE;
1057     hdr->length = pj_htons((pj_uint16_t)(len/4 - 1));
1058
1059     /* Write RTCP BYE reason */
1060     p = (pj_uint8_t*)hdr + sizeof(*hdr);
1061     if (reason && reason->slen) {
1062         *p++ = (pj_uint8_t)reason->slen;
1063         pj_memcpy(p, reason->ptr, reason->slen);
1064         p += reason->slen;
1065     }
1066
1067     /* Pad to 32bit */
1068     while ((p-(pj_uint8_t*)buf) % 4)
1069         *p++ = 0;
1070
1071     pj_assert((int)len == p-(pj_uint8_t*)buf);
1072     *length = len;
1073
1074     return PJ_SUCCESS;
1075 }
1076
1077
1078 PJ_DEF(pj_status_t) pjmedia_rtcp_enable_xr( pjmedia_rtcp_session *sess, 
1079                                             pj_bool_t enable)
1080 {
1081 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
1082
1083     /* Check if request won't change anything */
1084     if (!(enable ^ sess->xr_enabled))
1085         return PJ_SUCCESS;
1086
1087     if (!enable) {
1088         sess->xr_enabled = PJ_FALSE;
1089         return PJ_SUCCESS;
1090     }
1091
1092     pjmedia_rtcp_xr_init(&sess->xr_session, sess, 0, 1);
1093     sess->xr_enabled = PJ_TRUE;
1094
1095     return PJ_SUCCESS;
1096
1097 #else
1098
1099     PJ_UNUSED_ARG(sess);
1100     PJ_UNUSED_ARG(enable);
1101     return PJ_ENOTSUP;
1102
1103 #endif
1104 }