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 
21 #include <pjmedia/rtcp_xr.h>
22 #include <pjmedia/errno.h>
23 #include <pjmedia/rtcp.h>
24 #include <pj/assert.h>
25 #include <pj/log.h>
26 #include <pj/os.h>
27 #include <pj/sock.h>
28 #include <pj/string.h>
29 
30 #if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
31 
32 #define THIS_FILE "rtcp_xr.c"
33 
34 
35 #if PJ_HAS_HIGH_RES_TIMER==0
36 #   error "High resolution timer needs to be enabled"
37 #endif
38 
39 
40 /* RTCP XR payload type */
41 #define RTCP_XR		    207
42 
43 /* RTCP XR block types */
44 #define BT_LOSS_RLE	    1
45 #define BT_DUP_RLE	    2
46 #define BT_RCPT_TIMES	    3
47 #define BT_RR_TIME	    4
48 #define BT_DLRR		    5
49 #define BT_STATS	    6
50 #define BT_VOIP_METRICS	    7
51 
52 
53 #define DEFAULT_GMIN	    16
54 
55 
56 #if 0
57 #   define TRACE_(x)	PJ_LOG(3,x)
58 #else
59 #   define TRACE_(x)	;
60 #endif
61 
pjmedia_rtcp_xr_init(pjmedia_rtcp_xr_session * session,struct pjmedia_rtcp_session * parent_session,pj_uint8_t gmin,unsigned frames_per_packet)62 void pjmedia_rtcp_xr_init( pjmedia_rtcp_xr_session *session,
63 			   struct pjmedia_rtcp_session *parent_session,
64 			   pj_uint8_t gmin,
65 			   unsigned frames_per_packet)
66 {
67     pj_bzero(session, sizeof(pjmedia_rtcp_xr_session));
68 
69     session->name = parent_session->name;
70     session->rtcp_session = parent_session;
71     pj_memcpy(&session->pkt.common, &session->rtcp_session->rtcp_sr_pkt.common,
72 	      sizeof(pjmedia_rtcp_common));
73     session->pkt.common.pt = RTCP_XR;
74 
75     /* Init config */
76     session->stat.rx.voip_mtc.gmin = (pj_uint8_t)(gmin? gmin : DEFAULT_GMIN);
77     session->ptime = session->rtcp_session->pkt_size * 1000 /
78 		     session->rtcp_session->clock_rate;
79     session->frames_per_packet = frames_per_packet;
80 
81     /* Init Statistics Summary fields which have non-zero default */
82     session->stat.rx.stat_sum.jitter.min = (unsigned) -1;
83     session->stat.rx.stat_sum.toh.min = (unsigned) -1;
84 
85     /* Init VoIP Metrics fields which have non-zero default */
86     session->stat.rx.voip_mtc.signal_lvl = 127;
87     session->stat.rx.voip_mtc.noise_lvl = 127;
88     session->stat.rx.voip_mtc.rerl = 127;
89     session->stat.rx.voip_mtc.r_factor = 127;
90     session->stat.rx.voip_mtc.ext_r_factor = 127;
91     session->stat.rx.voip_mtc.mos_lq = 127;
92     session->stat.rx.voip_mtc.mos_cq = 127;
93 
94     session->stat.tx.voip_mtc.signal_lvl = 127;
95     session->stat.tx.voip_mtc.noise_lvl = 127;
96     session->stat.tx.voip_mtc.rerl = 127;
97     session->stat.tx.voip_mtc.r_factor = 127;
98     session->stat.tx.voip_mtc.ext_r_factor = 127;
99     session->stat.tx.voip_mtc.mos_lq = 127;
100     session->stat.tx.voip_mtc.mos_cq = 127;
101 }
102 
pjmedia_rtcp_xr_fini(pjmedia_rtcp_xr_session * session)103 void pjmedia_rtcp_xr_fini(pjmedia_rtcp_xr_session *session)
104 {
105     PJ_UNUSED_ARG(session);
106 }
107 
pjmedia_rtcp_build_rtcp_xr(pjmedia_rtcp_xr_session * sess,unsigned rpt_types,void ** rtcp_pkt,int * len)108 PJ_DEF(void) pjmedia_rtcp_build_rtcp_xr( pjmedia_rtcp_xr_session *sess,
109 					 unsigned rpt_types,
110 					 void **rtcp_pkt, int *len)
111 {
112     pj_uint16_t size = 0;
113 
114     /* Receiver Reference Time Report Block */
115     /* Build this block if we have received packets since last build */
116     if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_RR_TIME)) &&
117 	sess->rx_last_rr != sess->rtcp_session->stat.rx.pkt)
118     {
119 	pjmedia_rtcp_xr_rb_rr_time *r;
120 	pjmedia_rtcp_ntp_rec ntp;
121 
122 	r = (pjmedia_rtcp_xr_rb_rr_time*) &sess->pkt.buf[size];
123 	pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_rr_time));
124 
125 	/* Init block header */
126 	r->header.bt = BT_RR_TIME;
127 	r->header.specific = 0;
128 	r->header.length = pj_htons(2);
129 
130 	/* Generate block contents */
131 	pjmedia_rtcp_get_ntp_time(sess->rtcp_session, &ntp);
132 	r->ntp_sec = pj_htonl(ntp.hi);
133 	r->ntp_frac = pj_htonl(ntp.lo);
134 
135 	/* Finally */
136 	size += sizeof(pjmedia_rtcp_xr_rb_rr_time);
137 	sess->rx_last_rr = sess->rtcp_session->stat.rx.pkt;
138     }
139 
140     /* DLRR Report Block */
141     /* Build this block if we have received RR NTP (rx_lrr) before */
142     if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_DLRR)) &&
143 	sess->rx_lrr)
144     {
145 	pjmedia_rtcp_xr_rb_dlrr *r;
146 	pjmedia_rtcp_xr_rb_dlrr_item *dlrr_item;
147 	pj_timestamp ts;
148 
149 	r = (pjmedia_rtcp_xr_rb_dlrr*) &sess->pkt.buf[size];
150 	pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_dlrr));
151 
152 	/* Init block header */
153 	r->header.bt = BT_DLRR;
154 	r->header.specific = 0;
155 	r->header.length = pj_htons(sizeof(pjmedia_rtcp_xr_rb_dlrr)/4 - 1);
156 
157 	/* Generate block contents */
158 	dlrr_item = &r->item;
159 	dlrr_item->ssrc = pj_htonl(sess->rtcp_session->peer_ssrc);
160 	dlrr_item->lrr = pj_htonl(sess->rx_lrr);
161 
162 	/* Calculate DLRR */
163 	if (sess->rx_lrr != 0) {
164 	    pj_get_timestamp(&ts);
165 	    ts.u64 -= sess->rx_lrr_time.u64;
166 
167 	    /* Convert DLRR time to 1/65536 seconds resolution */
168 	    ts.u64 = (ts.u64 << 16) / sess->rtcp_session->ts_freq.u64;
169 	    dlrr_item->dlrr = pj_htonl(ts.u32.lo);
170 	} else {
171 	    dlrr_item->dlrr = 0;
172 	}
173 
174 	/* Finally */
175 	size += sizeof(pjmedia_rtcp_xr_rb_dlrr);
176     }
177 
178     /* Statistics Summary Block */
179     /* Build this block if we have received packets since last build */
180     if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_STATS)) &&
181 	sess->stat.rx.stat_sum.count > 0)
182     {
183 	pjmedia_rtcp_xr_rb_stats *r;
184 	pj_uint8_t specific = 0;
185 
186 	r = (pjmedia_rtcp_xr_rb_stats*) &sess->pkt.buf[size];
187 	pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_stats));
188 
189 	/* Init block header */
190 	specific |= sess->stat.rx.stat_sum.l ? (1 << 7) : 0;
191 	specific |= sess->stat.rx.stat_sum.d ? (1 << 6) : 0;
192 	specific |= sess->stat.rx.stat_sum.j ? (1 << 5) : 0;
193 	specific |= (sess->stat.rx.stat_sum.t & 3) << 3;
194 	r->header.bt = BT_STATS;
195 	r->header.specific = specific;
196 	r->header.length = pj_htons(9);
197 
198 	/* Generate block contents */
199 	r->ssrc = pj_htonl(sess->rtcp_session->peer_ssrc);
200 	r->begin_seq = pj_htons((pj_uint16_t)
201 				(sess->stat.rx.stat_sum.begin_seq & 0xFFFF));
202 	r->end_seq = pj_htons((pj_uint16_t)
203 			      (sess->stat.rx.stat_sum.end_seq & 0xFFFF));
204 	if (sess->stat.rx.stat_sum.l) {
205 	    r->lost = pj_htonl(sess->stat.rx.stat_sum.lost);
206 	}
207 	if (sess->stat.rx.stat_sum.d) {
208 	    r->dup = pj_htonl(sess->stat.rx.stat_sum.dup);
209 	}
210 	if (sess->stat.rx.stat_sum.j) {
211 	    r->jitter_min = pj_htonl(sess->stat.rx.stat_sum.jitter.min);
212 	    r->jitter_max = pj_htonl(sess->stat.rx.stat_sum.jitter.max);
213 	    r->jitter_mean =
214 		pj_htonl((unsigned)sess->stat.rx.stat_sum.jitter.mean);
215 	    r->jitter_dev =
216 		pj_htonl(pj_math_stat_get_stddev(&sess->stat.rx.stat_sum.jitter));
217 	}
218 	if (sess->stat.rx.stat_sum.t) {
219 	    r->toh_min = sess->stat.rx.stat_sum.toh.min;
220 	    r->toh_max = sess->stat.rx.stat_sum.toh.max;
221 	    r->toh_mean = (unsigned) sess->stat.rx.stat_sum.toh.mean;
222 	    r->toh_dev = pj_math_stat_get_stddev(&sess->stat.rx.stat_sum.toh);
223 	}
224 
225 	/* Reset TX statistics summary each time built */
226 	pj_bzero(&sess->stat.rx.stat_sum, sizeof(sess->stat.rx.stat_sum));
227 	sess->stat.rx.stat_sum.jitter.min = (unsigned) -1;
228 	sess->stat.rx.stat_sum.toh.min = (unsigned) -1;
229 
230 	/* Finally */
231 	size += sizeof(pjmedia_rtcp_xr_rb_stats);
232 	pj_gettimeofday(&sess->stat.rx.stat_sum.update);
233     }
234 
235     /* Voip Metrics Block */
236     /* Build this block if we have received packets */
237     if ((rpt_types == 0 || (rpt_types & PJMEDIA_RTCP_XR_VOIP_METRICS)) &&
238 	sess->rtcp_session->stat.rx.pkt)
239     {
240 	pjmedia_rtcp_xr_rb_voip_mtc *r;
241 	pj_uint32_t c11;
242 	pj_uint32_t c13;
243 	pj_uint32_t c14;
244 	pj_uint32_t c22;
245 	pj_uint32_t c23;
246 	pj_uint32_t c31;
247 	pj_uint32_t c32;
248 	pj_uint32_t c33;
249 	pj_uint32_t ctotal, m;
250 	unsigned est_extra_delay;
251 
252 	r = (pjmedia_rtcp_xr_rb_voip_mtc*) &sess->pkt.buf[size];
253 	pj_bzero(r, sizeof(pjmedia_rtcp_xr_rb_voip_mtc));
254 
255 	/* Init block header */
256 	r->header.bt = BT_VOIP_METRICS;
257 	r->header.specific = 0;
258 	r->header.length = pj_htons(8);
259 
260 	/* Use temp vars for easiness. */
261 	c11 = sess->voip_mtc_stat.c11;
262 	c13 = sess->voip_mtc_stat.c13;
263 	c14 = sess->voip_mtc_stat.c14;
264 	c22 = sess->voip_mtc_stat.c22;
265 	c23 = sess->voip_mtc_stat.c23;
266 	c33 = sess->voip_mtc_stat.c33;
267 	m = sess->ptime * sess->frames_per_packet;
268 
269 	/* Calculate additional transition counts. */
270 	c31 = c13;
271 	c32 = c23;
272 	ctotal = c11 + c14 + c13 + c22 + c23 + c31 + c32 + c33;
273 
274 	if (ctotal) {
275 	    pj_uint32_t p32, p23;
276 
277 	    //original version:
278 	    //p32 = c32 / (c31 + c32 + c33);
279 	    if (c31 + c32 + c33 == 0)
280 		p32 = 0;
281 	    else
282 		p32 = (c32 << 16) / (c31 + c32 + c33);
283 
284 	    //original version:
285 	    //if ((c22 + c23) < 1) {
286 	    //    p23 = 1;
287 	    //} else {
288 	    //    p23 = 1 - c22 / (c22 + c23);
289 	    //}
290 	    if (c23 == 0) {
291 	        p23 = 0;
292 	    } else {
293 	        p23 = (c23 << 16) / (c22 + c23);
294 	    }
295 
296 	    /* Calculate loss/discard densities, scaled of 0-256 */
297 	    if (c11 == 0)
298 		sess->stat.rx.voip_mtc.gap_den = 0;
299 	    else
300 		sess->stat.rx.voip_mtc.gap_den = (pj_uint8_t)
301 						 ((c14 << 8) / (c11 + c14));
302 	    if (p23 == 0)
303 		sess->stat.rx.voip_mtc.burst_den = 0;
304 	    else
305 		sess->stat.rx.voip_mtc.burst_den = (pj_uint8_t)
306 						   ((p23 << 8) / (p23 + p32));
307 
308 	    /* Calculate (average) durations, in ms */
309 	    if (c13 == 0) {
310 		c13 = 1;
311 		ctotal += 1;
312 	    }
313 	    sess->stat.rx.voip_mtc.gap_dur = (pj_uint16_t)
314 					    ((c11+c14+c13) * m / c13);
315 	    sess->stat.rx.voip_mtc.burst_dur = (pj_uint16_t)
316 					    ((ctotal - (c11+c14+c13)) * m / c13);
317 
318 	    /* Callculate loss/discard rates, scaled 0-256 */
319 	    sess->stat.rx.voip_mtc.loss_rate = (pj_uint8_t)
320 			((sess->voip_mtc_stat.loss_count << 8) / ctotal);
321 	    sess->stat.rx.voip_mtc.discard_rate = (pj_uint8_t)
322 			((sess->voip_mtc_stat.discard_count << 8) / ctotal);
323 	} else {
324 	    /* No lost/discarded packet yet. */
325 	    sess->stat.rx.voip_mtc.gap_den = 0;
326 	    sess->stat.rx.voip_mtc.burst_den = 0;
327 	    sess->stat.rx.voip_mtc.gap_dur = 0;
328 	    sess->stat.rx.voip_mtc.burst_dur = 0;
329 	    sess->stat.rx.voip_mtc.loss_rate = 0;
330 	    sess->stat.rx.voip_mtc.discard_rate = 0;
331 	}
332 
333 	/* Set round trip delay (in ms) to RTT calculated after receiving
334 	 * DLRR or DLSR.
335 	 */
336 	if (sess->stat.rtt.last)
337 	    sess->stat.rx.voip_mtc.rnd_trip_delay = (pj_uint16_t)
338 				    (sess->stat.rtt.last / 1000);
339 	else if (sess->rtcp_session->stat.rtt.last)
340 	    sess->stat.rx.voip_mtc.rnd_trip_delay = (pj_uint16_t)
341 				    (sess->rtcp_session->stat.rtt.last / 1000);
342 
343 	/* End system delay = RTT/2 + current jitter buffer size +
344 	 *                    EXTRA (estimated extra delay)
345 	 * EXTRA will cover additional delay introduced by other components of
346 	 * audio engine, e.g: sound device, codec, AEC, PLC, WSOLA.
347 	 * Since it is difficult to get the exact value of EXTRA, estimation
348 	 * is taken to be totally around 30ms + sound device latency.
349 	 */
350 	est_extra_delay = 30;
351 
352 #if !PJMEDIA_AUDIO_DEV_HAS_NULL_AUDIO
353 	est_extra_delay += PJMEDIA_SND_DEFAULT_REC_LATENCY +
354 			   PJMEDIA_SND_DEFAULT_PLAY_LATENCY;
355 #endif
356 
357 	sess->stat.rx.voip_mtc.end_sys_delay = (pj_uint16_t)
358 				 (sess->stat.rx.voip_mtc.rnd_trip_delay / 2 +
359 				 sess->stat.rx.voip_mtc.jb_nom +
360 				 est_extra_delay);
361 
362 	/* Generate block contents */
363 	r->ssrc		    = pj_htonl(sess->rtcp_session->peer_ssrc);
364 	r->loss_rate	    = sess->stat.rx.voip_mtc.loss_rate;
365 	r->discard_rate	    = sess->stat.rx.voip_mtc.discard_rate;
366 	r->burst_den	    = sess->stat.rx.voip_mtc.burst_den;
367 	r->gap_den	    = sess->stat.rx.voip_mtc.gap_den;
368 	r->burst_dur	    = pj_htons(sess->stat.rx.voip_mtc.burst_dur);
369 	r->gap_dur	    = pj_htons(sess->stat.rx.voip_mtc.gap_dur);
370 	r->rnd_trip_delay   = pj_htons(sess->stat.rx.voip_mtc.rnd_trip_delay);
371 	r->end_sys_delay    = pj_htons(sess->stat.rx.voip_mtc.end_sys_delay);
372 	/* signal & noise level encoded in two's complement form */
373 	r->signal_lvl	    = (pj_uint8_t)
374 			      ((sess->stat.rx.voip_mtc.signal_lvl >= 0)?
375 			       sess->stat.rx.voip_mtc.signal_lvl :
376 			       (sess->stat.rx.voip_mtc.signal_lvl + 256));
377 	r->noise_lvl	    = (pj_uint8_t)
378 			      ((sess->stat.rx.voip_mtc.noise_lvl >= 0)?
379 			       sess->stat.rx.voip_mtc.noise_lvl :
380 			       (sess->stat.rx.voip_mtc.noise_lvl + 256));
381 	r->rerl		    = sess->stat.rx.voip_mtc.rerl;
382 	r->gmin		    = sess->stat.rx.voip_mtc.gmin;
383 	r->r_factor	    = sess->stat.rx.voip_mtc.r_factor;
384 	r->ext_r_factor	    = sess->stat.rx.voip_mtc.ext_r_factor;
385 	r->mos_lq	    = sess->stat.rx.voip_mtc.mos_lq;
386 	r->mos_cq	    = sess->stat.rx.voip_mtc.mos_cq;
387 	r->rx_config	    = sess->stat.rx.voip_mtc.rx_config;
388 	r->jb_nom	    = pj_htons(sess->stat.rx.voip_mtc.jb_nom);
389 	r->jb_max	    = pj_htons(sess->stat.rx.voip_mtc.jb_max);
390 	r->jb_abs_max	    = pj_htons(sess->stat.rx.voip_mtc.jb_abs_max);
391 
392 	/* Finally */
393 	size += sizeof(pjmedia_rtcp_xr_rb_voip_mtc);
394 	pj_gettimeofday(&sess->stat.rx.voip_mtc.update);
395     }
396 
397     /* Add RTCP XR header size */
398     size += sizeof(sess->pkt.common);
399 
400     /* Set RTCP XR header 'length' to packet size in 32-bit unit minus one */
401     sess->pkt.common.length = pj_htons((pj_uint16_t)(size/4 - 1));
402 
403     /* Set the return values */
404     *rtcp_pkt = (void*) &sess->pkt;
405     *len = size;
406 }
407 
408 
pjmedia_rtcp_xr_rx_rtcp_xr(pjmedia_rtcp_xr_session * sess,const void * pkt,pj_size_t size)409 void pjmedia_rtcp_xr_rx_rtcp_xr( pjmedia_rtcp_xr_session *sess,
410 				 const void *pkt,
411 				 pj_size_t size)
412 {
413     const pjmedia_rtcp_xr_pkt	      *rtcp_xr = (pjmedia_rtcp_xr_pkt*) pkt;
414     const pjmedia_rtcp_xr_rb_rr_time  *rb_rr_time = NULL;
415     const pjmedia_rtcp_xr_rb_dlrr     *rb_dlrr = NULL;
416     const pjmedia_rtcp_xr_rb_stats    *rb_stats = NULL;
417     const pjmedia_rtcp_xr_rb_voip_mtc *rb_voip_mtc = NULL;
418     const pjmedia_rtcp_xr_rb_header   *rb_hdr = (pjmedia_rtcp_xr_rb_header*)
419 						rtcp_xr->buf;
420     unsigned pkt_len, rb_len;
421 
422     if (rtcp_xr->common.pt != RTCP_XR)
423 	return;
424 
425     pkt_len = pj_ntohs((pj_uint16_t)rtcp_xr->common.length);
426 
427     if ((pkt_len + 1) > (size / 4))
428 	return;
429 
430     /* Parse report rpt_types */
431     while ((pj_int32_t*)rb_hdr < (pj_int32_t*)pkt + pkt_len)
432     {
433 	rb_len = pj_ntohs((pj_uint16_t)rb_hdr->length);
434 
435 	/* Just skip any block with length == 0 (no report content) */
436 	if (rb_len) {
437 	    switch (rb_hdr->bt) {
438 		case BT_RR_TIME:
439 		    rb_rr_time = (pjmedia_rtcp_xr_rb_rr_time*) rb_hdr;
440 		    break;
441 		case BT_DLRR:
442 		    rb_dlrr = (pjmedia_rtcp_xr_rb_dlrr*) rb_hdr;
443 		    break;
444 		case BT_STATS:
445 		    rb_stats = (pjmedia_rtcp_xr_rb_stats*) rb_hdr;
446 		    break;
447 		case BT_VOIP_METRICS:
448 		    rb_voip_mtc = (pjmedia_rtcp_xr_rb_voip_mtc*) rb_hdr;
449 		    break;
450 		default:
451 		    break;
452 	    }
453 	}
454 	rb_hdr = (pjmedia_rtcp_xr_rb_header*)
455 		 ((pj_int32_t*)rb_hdr + rb_len + 1);
456     }
457 
458     /* Receiving RR Time */
459     if (rb_rr_time) {
460 	/* Save LRR from NTP timestamp of the RR time block report */
461 	sess->rx_lrr = ((pj_ntohl(rb_rr_time->ntp_sec) & 0x0000FFFF) << 16) |
462 		       ((pj_ntohl(rb_rr_time->ntp_frac) >> 16) & 0xFFFF);
463 
464 	/* Calculate RR arrival time for DLRR */
465 	pj_get_timestamp(&sess->rx_lrr_time);
466 
467 	TRACE_((sess->name, "Rx RTCP SR: ntp_ts=%p", sess->rx_lrr,
468 	       (pj_uint32_t)(sess->rx_lrr_time.u64*65536/
469 			     sess->rtcp_session->ts_freq.u64)));
470     }
471 
472     /* Receiving DLRR */
473     if (rb_dlrr) {
474 	pj_uint32_t lrr, now, dlrr;
475 	pj_uint64_t eedelay;
476 	pjmedia_rtcp_ntp_rec ntp;
477 
478 	/* LRR is the middle 32bit of NTP. It has 1/65536 second
479 	 * resolution
480 	 */
481 	lrr = pj_ntohl(rb_dlrr->item.lrr);
482 
483 	/* DLRR is delay since LRR, also in 1/65536 resolution */
484 	dlrr = pj_ntohl(rb_dlrr->item.dlrr);
485 
486 	/* Get current time, and convert to 1/65536 resolution */
487 	pjmedia_rtcp_get_ntp_time(sess->rtcp_session, &ntp);
488 	now = ((ntp.hi & 0xFFFF) << 16) + (ntp.lo >> 16);
489 
490 	/* End-to-end delay is (now-lrr-dlrr) */
491 	eedelay = now - lrr - dlrr;
492 
493 	/* Convert end to end delay to usec (keeping the calculation in
494          * 64bit space)::
495 	 *   sess->ee_delay = (eedelay * 1000) / 65536;
496 	 */
497 	if (eedelay < 4294) {
498 	    eedelay = (eedelay * 1000000) >> 16;
499 	} else {
500 	    eedelay = (eedelay * 1000) >> 16;
501 	    eedelay *= 1000;
502 	}
503 
504 	TRACE_((sess->name, "Rx RTCP XR DLRR: lrr=%p, dlrr=%p (%d:%03dms), "
505 			   "now=%p, rtt=%p",
506 		lrr, dlrr, dlrr/65536, (dlrr%65536)*1000/65536,
507 		now, (pj_uint32_t)eedelay));
508 
509 	/* Only save calculation if "now" is greater than lrr, or
510 	 * otherwise rtt will be invalid
511 	 */
512 	if (now-dlrr >= lrr) {
513 	    unsigned rtt = (pj_uint32_t)eedelay;
514 
515 	    /* Check that eedelay value really makes sense.
516 	     * We allow up to 30 seconds RTT!
517 	     */
518 	    if (eedelay <= 30 * 1000 * 1000UL) {
519 		/* "Normalize" rtt value that is exceptionally high.
520 		 * For such values, "normalize" the rtt to be three times
521 		 * the average value.
522 		 */
523 		if (rtt>((unsigned)sess->stat.rtt.mean*3) && sess->stat.rtt.n!=0)
524 		{
525 		    unsigned orig_rtt = rtt;
526 		    rtt = (unsigned)sess->stat.rtt.mean*3;
527 		    PJ_LOG(5,(sess->name,
528 			      "RTT value %d usec is normalized to %d usec",
529 			      orig_rtt, rtt));
530 		}
531 
532 		TRACE_((sess->name, "RTCP RTT is set to %d usec", rtt));
533 		pj_math_stat_update(&sess->stat.rtt, rtt);
534 	    }
535 	} else {
536 	    PJ_LOG(5, (sess->name, "Internal RTCP NTP clock skew detected: "
537 				   "lrr=%p, now=%p, dlrr=%p (%d:%03dms), "
538 				   "diff=%d",
539 				   lrr, now, dlrr, dlrr/65536,
540 				   (dlrr%65536)*1000/65536,
541 				   dlrr-(now-lrr)));
542 	}
543     }
544 
545     /* Receiving Statistics Summary */
546     if (rb_stats) {
547 	pj_uint8_t flags = rb_stats->header.specific;
548 
549 	pj_bzero(&sess->stat.tx.stat_sum, sizeof(sess->stat.tx.stat_sum));
550 
551 	/* Range of packets sequence reported in this blocks */
552 	sess->stat.tx.stat_sum.begin_seq = pj_ntohs(rb_stats->begin_seq);
553 	sess->stat.tx.stat_sum.end_seq   = pj_ntohs(rb_stats->end_seq);
554 
555 	/* Get flags of valid fields */
556 	sess->stat.tx.stat_sum.l = (flags & (1 << 7)) != 0;
557 	sess->stat.tx.stat_sum.d = (flags & (1 << 6)) != 0;
558 	sess->stat.tx.stat_sum.j = (flags & (1 << 5)) != 0;
559 	sess->stat.tx.stat_sum.t = (flags & (3 << 3)) != 0;
560 
561 	/* Fetch the reports info */
562 	if (sess->stat.tx.stat_sum.l) {
563 	    sess->stat.tx.stat_sum.lost = pj_ntohl(rb_stats->lost);
564 	}
565 
566 	if (sess->stat.tx.stat_sum.d) {
567 	    sess->stat.tx.stat_sum.dup = pj_ntohl(rb_stats->dup);
568 	}
569 
570 	if (sess->stat.tx.stat_sum.j) {
571 	    sess->stat.tx.stat_sum.jitter.min = pj_ntohl(rb_stats->jitter_min);
572 	    sess->stat.tx.stat_sum.jitter.max = pj_ntohl(rb_stats->jitter_max);
573 	    sess->stat.tx.stat_sum.jitter.mean= pj_ntohl(rb_stats->jitter_mean);
574 	    pj_math_stat_set_stddev(&sess->stat.tx.stat_sum.jitter,
575 				    pj_ntohl(rb_stats->jitter_dev));
576 	}
577 
578 	if (sess->stat.tx.stat_sum.t) {
579 	    sess->stat.tx.stat_sum.toh.min = rb_stats->toh_min;
580 	    sess->stat.tx.stat_sum.toh.max = rb_stats->toh_max;
581 	    sess->stat.tx.stat_sum.toh.mean= rb_stats->toh_mean;
582 	    pj_math_stat_set_stddev(&sess->stat.tx.stat_sum.toh,
583 				    pj_ntohl(rb_stats->toh_dev));
584 	}
585 
586 	pj_gettimeofday(&sess->stat.tx.stat_sum.update);
587     }
588 
589     /* Receiving VoIP Metrics */
590     if (rb_voip_mtc) {
591 	sess->stat.tx.voip_mtc.loss_rate = rb_voip_mtc->loss_rate;
592 	sess->stat.tx.voip_mtc.discard_rate = rb_voip_mtc->discard_rate;
593 	sess->stat.tx.voip_mtc.burst_den = rb_voip_mtc->burst_den;
594 	sess->stat.tx.voip_mtc.gap_den = rb_voip_mtc->gap_den;
595 	sess->stat.tx.voip_mtc.burst_dur = pj_ntohs(rb_voip_mtc->burst_dur);
596 	sess->stat.tx.voip_mtc.gap_dur = pj_ntohs(rb_voip_mtc->gap_dur);
597 	sess->stat.tx.voip_mtc.rnd_trip_delay =
598 					pj_ntohs(rb_voip_mtc->rnd_trip_delay);
599 	sess->stat.tx.voip_mtc.end_sys_delay =
600 					pj_ntohs(rb_voip_mtc->end_sys_delay);
601 	/* signal & noise level encoded in two's complement form */
602 	sess->stat.tx.voip_mtc.signal_lvl = (pj_int8_t)
603 				    ((rb_voip_mtc->signal_lvl > 127)?
604 				     ((int)rb_voip_mtc->signal_lvl - 256) :
605 				     rb_voip_mtc->signal_lvl);
606 	sess->stat.tx.voip_mtc.noise_lvl  = (pj_int8_t)
607 				    ((rb_voip_mtc->noise_lvl > 127)?
608 				     ((int)rb_voip_mtc->noise_lvl - 256) :
609 				     rb_voip_mtc->noise_lvl);
610 	sess->stat.tx.voip_mtc.rerl = rb_voip_mtc->rerl;
611 	sess->stat.tx.voip_mtc.gmin = rb_voip_mtc->gmin;
612 	sess->stat.tx.voip_mtc.r_factor = rb_voip_mtc->r_factor;
613 	sess->stat.tx.voip_mtc.ext_r_factor = rb_voip_mtc->ext_r_factor;
614 	sess->stat.tx.voip_mtc.mos_lq = rb_voip_mtc->mos_lq;
615 	sess->stat.tx.voip_mtc.mos_cq = rb_voip_mtc->mos_cq;
616 	sess->stat.tx.voip_mtc.rx_config = rb_voip_mtc->rx_config;
617 	sess->stat.tx.voip_mtc.jb_nom = pj_ntohs(rb_voip_mtc->jb_nom);
618 	sess->stat.tx.voip_mtc.jb_max = pj_ntohs(rb_voip_mtc->jb_max);
619 	sess->stat.tx.voip_mtc.jb_abs_max = pj_ntohs(rb_voip_mtc->jb_abs_max);
620 
621 	pj_gettimeofday(&sess->stat.tx.voip_mtc.update);
622     }
623 }
624 
625 /* Place seq into a 32-bit sequence number space based upon a
626  * heuristic for its most likely location.
627  */
extend_seq(pjmedia_rtcp_xr_session * sess,const pj_uint16_t seq)628 static pj_uint32_t extend_seq(pjmedia_rtcp_xr_session *sess,
629 			      const pj_uint16_t seq)
630 {
631 
632     pj_uint32_t extended_seq, seq_a, seq_b, diff_a, diff_b;
633     if(sess->uninitialized_src_ref_seq) {
634 	/* This is the first sequence number received.  Place
635 	 * it in the middle of the extended sequence number
636 	 * space.
637 	 */
638 	sess->src_ref_seq = seq | 0x80000000u;
639 	sess->uninitialized_src_ref_seq = PJ_FALSE;
640 	extended_seq = sess->src_ref_seq;
641     } else {
642 	/* Prior sequence numbers have been received.
643 	 * Propose two candidates for the extended sequence
644 	 * number: seq_a is without wraparound, seq_b with
645 	 * wraparound.
646 	 */
647 	seq_a = seq | (sess->src_ref_seq & 0xFFFF0000u);
648 	if(sess->src_ref_seq < seq_a) {
649 	    seq_b  = seq_a - 0x00010000u;
650 	    diff_a = seq_a - sess->src_ref_seq;
651 	    diff_b = sess->src_ref_seq - seq_b;
652 	} else {
653 	    seq_b  = seq_a + 0x00010000u;
654 	    diff_a = sess->src_ref_seq - seq_a;
655 	    diff_b = seq_b - sess->src_ref_seq;
656 	}
657 
658 	/* Choose the closer candidate.  If they are equally
659 	 * close, the choice is somewhat arbitrary: we choose
660 	 * the candidate for which no rollover is necessary.
661 	 */
662 	if(diff_a < diff_b) {
663 	    extended_seq = seq_a;
664 	} else {
665 	    extended_seq = seq_b;
666 	}
667 
668 	/* Set the reference sequence number to be this most
669 	 * recently-received sequence number.
670 	 */
671 	sess->src_ref_seq = extended_seq;
672     }
673 
674     /* Return our best guess for a 32-bit sequence number that
675      * corresponds to the 16-bit number we were given.
676      */
677     return extended_seq;
678 }
679 
pjmedia_rtcp_xr_rx_rtp(pjmedia_rtcp_xr_session * sess,unsigned seq,int lost,int dup,int discarded,int jitter,int toh,pj_bool_t toh_ipv4)680 void pjmedia_rtcp_xr_rx_rtp( pjmedia_rtcp_xr_session *sess,
681 			     unsigned seq,
682 			     int lost,
683 			     int dup,
684 			     int discarded,
685 			     int jitter,
686 			     int toh, pj_bool_t toh_ipv4)
687 {
688     pj_uint32_t ext_seq;
689 
690     /* Get 32 bit version of sequence */
691     ext_seq = extend_seq(sess, (pj_uint16_t)seq);
692 
693     /* Update statistics summary */
694     sess->stat.rx.stat_sum.count++;
695 
696     if (sess->stat.rx.stat_sum.begin_seq == 0 ||
697 	sess->stat.rx.stat_sum.begin_seq > ext_seq)
698     {
699 	sess->stat.rx.stat_sum.begin_seq = ext_seq;
700     }
701 
702     if (sess->stat.rx.stat_sum.end_seq == 0 ||
703 	sess->stat.rx.stat_sum.end_seq < ext_seq)
704     {
705 	sess->stat.rx.stat_sum.end_seq = ext_seq;
706     }
707 
708     if (lost >= 0) {
709 	sess->stat.rx.stat_sum.l = PJ_TRUE;
710 	if (lost > 0)
711 	    sess->stat.rx.stat_sum.lost++;
712     }
713 
714     if (dup >= 0) {
715 	sess->stat.rx.stat_sum.d = PJ_TRUE;
716 	if (dup > 0)
717 	    sess->stat.rx.stat_sum.dup++;
718     }
719 
720     if (jitter >= 0) {
721 	sess->stat.rx.stat_sum.j = PJ_TRUE;
722 	pj_math_stat_update(&sess->stat.rx.stat_sum.jitter, jitter);
723     }
724 
725     if (toh >= 0) {
726 	sess->stat.rx.stat_sum.t = toh_ipv4? 1 : 2;
727 	pj_math_stat_update(&sess->stat.rx.stat_sum.toh, toh);
728     }
729 
730     /* Update burst metrics.
731      * There are two terms introduced in the RFC 3611: gap & burst.
732      * Gap represents good stream condition, lost+discard rate <= 1/Gmin.
733      * Burst represents the opposite, lost+discard rate > 1/Gmin.
734      */
735     if (lost >= 0 && discarded >= 0) {
736 	if(lost > 0) {
737 	    sess->voip_mtc_stat.loss_count++;
738 	}
739 	if(discarded > 0) {
740 	    sess->voip_mtc_stat.discard_count++;
741 	}
742 	if(!lost && !discarded) {
743 	    /* Number of good packets since last lost/discarded */
744 	    sess->voip_mtc_stat.pkt++;
745 	}
746 	else {
747 	    if(sess->voip_mtc_stat.pkt >= sess->stat.rx.voip_mtc.gmin) {
748 		/* Gap condition */
749 		if(sess->voip_mtc_stat.lost == 1) {
750 		    /* Gap -> Gap */
751 		    sess->voip_mtc_stat.c14++;
752 		}
753 		else {
754 		    /* Burst -> Gap */
755 		    sess->voip_mtc_stat.c13++;
756 		}
757 		sess->voip_mtc_stat.lost = 1;
758 		sess->voip_mtc_stat.c11 += sess->voip_mtc_stat.pkt;
759 	    }
760 	    else {
761 		/* Burst condition */
762 		sess->voip_mtc_stat.lost++;
763 		if(sess->voip_mtc_stat.pkt == 0) {
764 		    /* Consecutive losts */
765 		    sess->voip_mtc_stat.c33++;
766 		}
767 		else {
768 		    /* Any good packets, but still bursting */
769 		    sess->voip_mtc_stat.c23++;
770 		    sess->voip_mtc_stat.c22 += (sess->voip_mtc_stat.pkt - 1);
771 		}
772 	    }
773 
774 	    sess->voip_mtc_stat.pkt = 0;
775 	}
776     }
777 }
778 
pjmedia_rtcp_xr_tx_rtp(pjmedia_rtcp_xr_session * session,unsigned ptsize)779 void pjmedia_rtcp_xr_tx_rtp( pjmedia_rtcp_xr_session *session,
780 			     unsigned ptsize )
781 {
782     PJ_UNUSED_ARG(session);
783     PJ_UNUSED_ARG(ptsize);
784 }
785 
pjmedia_rtcp_xr_update_info(pjmedia_rtcp_xr_session * sess,unsigned info,pj_int32_t val)786 PJ_DEF(pj_status_t) pjmedia_rtcp_xr_update_info(
787 					 pjmedia_rtcp_xr_session *sess,
788 					 unsigned info,
789 					 pj_int32_t val)
790 {
791     int v = val;
792 
793     switch(info) {
794 	case PJMEDIA_RTCP_XR_INFO_SIGNAL_LVL:
795 	    sess->stat.rx.voip_mtc.signal_lvl = (pj_int8_t) v;
796 	    break;
797 
798 	case PJMEDIA_RTCP_XR_INFO_NOISE_LVL:
799 	    sess->stat.rx.voip_mtc.noise_lvl = (pj_int8_t) v;
800 	    break;
801 
802 	case PJMEDIA_RTCP_XR_INFO_RERL:
803 	    sess->stat.rx.voip_mtc.rerl = (pj_uint8_t) v;
804 	    break;
805 
806 	case PJMEDIA_RTCP_XR_INFO_R_FACTOR:
807 	    sess->stat.rx.voip_mtc.ext_r_factor = (pj_uint8_t) v;
808 	    break;
809 
810 	case PJMEDIA_RTCP_XR_INFO_MOS_LQ:
811 	    sess->stat.rx.voip_mtc.mos_lq = (pj_uint8_t) v;
812 	    break;
813 
814 	case PJMEDIA_RTCP_XR_INFO_MOS_CQ:
815 	    sess->stat.rx.voip_mtc.mos_cq = (pj_uint8_t) v;
816 	    break;
817 
818 	case PJMEDIA_RTCP_XR_INFO_CONF_PLC:
819 	    if (v >= 0 && v <= 3) {
820 		sess->stat.rx.voip_mtc.rx_config &= 0x3F;
821 		sess->stat.rx.voip_mtc.rx_config |= (pj_uint8_t) (v << 6);
822 	    }
823 	    break;
824 
825 	case PJMEDIA_RTCP_XR_INFO_CONF_JBA:
826 	    if (v >= 0 && v <= 3) {
827 		sess->stat.rx.voip_mtc.rx_config &= 0xCF;
828 		sess->stat.rx.voip_mtc.rx_config |= (pj_uint8_t) (v << 4);
829 	    }
830 	    break;
831 
832 	case PJMEDIA_RTCP_XR_INFO_CONF_JBR:
833 	    if (v >= 0 && v <= 15) {
834 		sess->stat.rx.voip_mtc.rx_config &= 0xF0;
835 		sess->stat.rx.voip_mtc.rx_config |= (pj_uint8_t) v;
836 	    }
837 	    break;
838 
839 	case PJMEDIA_RTCP_XR_INFO_JB_NOM:
840 	    sess->stat.rx.voip_mtc.jb_nom = (pj_uint16_t) v;
841 	    break;
842 
843 	case PJMEDIA_RTCP_XR_INFO_JB_MAX:
844 	    sess->stat.rx.voip_mtc.jb_max = (pj_uint16_t) v;
845 	    break;
846 
847 	case PJMEDIA_RTCP_XR_INFO_JB_ABS_MAX:
848 	    sess->stat.rx.voip_mtc.jb_abs_max = (pj_uint16_t) v;
849 	    break;
850 
851 	default:
852 	    return PJ_EINVAL;
853     }
854 
855     return PJ_SUCCESS;
856 }
857 
858 #endif
859