diff -urN asterisk-1.4.11/channels/chan_sip.c asterisk-1.4.11-rtp/channels/chan_sip.c --- asterisk-1.4.11/channels/chan_sip.c 2007-08-21 15:42:15.000000000 -0300 +++ asterisk-1.4.11-rtp/channels/chan_sip.c 2007-09-27 17:00:24.000000000 -0300 @@ -3529,9 +3529,17 @@ } else { /* Call is in UP state, send BYE */ if (!p->pendinginvite) { char *audioqos = ""; + char *audioqos_jitter = ""; + char *audioqos_loss = ""; + char *audioqos_rtt = ""; char *videoqos = ""; if (p->rtp) + { audioqos = ast_rtp_get_quality(p->rtp, NULL); + audioqos_jitter = ast_rtp_get_quality_jitter(p->rtp, NULL); + audioqos_loss = ast_rtp_get_quality_loss(p->rtp, NULL); + audioqos_rtt = ast_rtp_get_quality_rtt(p->rtp, NULL); + } if (p->vrtp) videoqos = ast_rtp_get_quality(p->vrtp, NULL); /* Send a hangup */ @@ -3540,12 +3548,22 @@ /* Get RTCP quality before end of call */ if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) { if (p->rtp) + { append_history(p, "RTCPaudio", "Quality:%s", audioqos); + append_history(p, "RTCPaudioJitter", "Quality:%s", audioqos_jitter); + append_history(p, "RTCPaudioLoss", "Quality:%s", audioqos_loss); + append_history(p, "RTCPaudioRTT", "Quality:%s", audioqos_rtt); + } if (p->vrtp) append_history(p, "RTCPvideo", "Quality:%s", videoqos); } if (p->rtp && oldowner) + { pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOS", audioqos); + pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOSJITTER", audioqos_jitter); + pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOSLOSS", audioqos_loss); + pbx_builtin_setvar_helper(oldowner, "RTPAUDIOQOSRTT", audioqos_rtt); + } if (p->vrtp && oldowner) pbx_builtin_setvar_helper(oldowner, "RTPVIDEOQOS", videoqos); } else { @@ -14439,13 +14457,24 @@ /* Get RTCP quality before end of call */ if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY) || p->owner) { - char *audioqos, *videoqos; + char *audioqos, *audioqos_jitter, *audioqos_loss, *audioqos_rtt, *videoqos; if (p->rtp) { audioqos = ast_rtp_get_quality(p->rtp, NULL); - if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) + audioqos_jitter = ast_rtp_get_quality_jitter(p->rtp, NULL); + audioqos_loss = ast_rtp_get_quality_loss(p->rtp, NULL); + audioqos_rtt = ast_rtp_get_quality_rtt(p->rtp, NULL); + if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY)) { append_history(p, "RTCPaudio", "Quality:%s", audioqos); - if (p->owner) + append_history(p, "RTCPaudioJitter", "Quality:%s", audioqos_jitter); + append_history(p, "RTCPaudioLoss", "Quality:%s", audioqos_loss); + append_history(p, "RTCPaudioRTT", "Quality:%s", audioqos_rtt); + } + if (p->owner) { pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOS", audioqos); + pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOSJITTER", audioqos_jitter); + pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOSLOSS", audioqos_loss); + pbx_builtin_setvar_helper(p->owner, "RTPAUDIOQOSRTT", audioqos_rtt); + } } if (p->vrtp) { videoqos = ast_rtp_get_quality(p->vrtp, NULL); diff -urN asterisk-1.4.11/include/asterisk/rtp.h asterisk-1.4.11-rtp/include/asterisk/rtp.h --- asterisk-1.4.11/include/asterisk/rtp.h 2007-03-26 14:45:55.000000000 -0300 +++ asterisk-1.4.11-rtp/include/asterisk/rtp.h 2007-09-27 16:57:09.000000000 -0300 @@ -219,7 +219,10 @@ /*! \brief Return RTCP quality string */ char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual); - +/*! \Verbose Return RTCP quality string */ +char *ast_rtp_get_quality_jitter(struct ast_rtp *rtp, struct ast_rtp_quality *qual); +char *ast_rtp_get_quality_loss(struct ast_rtp *rtp, struct ast_rtp_quality *qual); +char *ast_rtp_get_quality_rtt(struct ast_rtp *rtp, struct ast_rtp_quality *qual); /*! \brief Send an H.261 fast update request. Some devices need this rather than the XML message in SIP */ int ast_rtcp_send_h261fur(void *data); @@ -250,6 +253,9 @@ /* \brief Put RTP timeout timers on hold during another transaction, like T.38 */ void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp); + +double normdev_compute(double normdev,double sample,unsigned int sample_count); +double stddev_compute(double stddev,double sample,double normdev,double normdev_curent,unsigned int sample_count); #if defined(__cplusplus) || defined(c_plusplus) } #endif diff -urN asterisk-1.4.11/main/rtp.c asterisk-1.4.11-rtp/main/rtp.c --- asterisk-1.4.11/main/rtp.c 2007-08-15 11:40:23.000000000 -0300 +++ asterisk-1.4.11-rtp/main/rtp.c 2007-09-27 16:55:11.000000000 -0300 @@ -42,6 +42,7 @@ #include #include #include +#include #include "asterisk/rtp.h" #include "asterisk/frame.h" @@ -224,10 +225,38 @@ unsigned int reported_jitter; /*!< The contents of their last jitter entry in the RR */ unsigned int reported_lost; /*!< Reported lost packets in their RR */ char quality[AST_MAX_USER_FIELD]; + char quality_jitter[AST_MAX_USER_FIELD]; + char quality_loss[AST_MAX_USER_FIELD]; + char quality_rtt[AST_MAX_USER_FIELD]; + + double reported_maxjitter; + double reported_minjitter; + double reported_normdev_jitter; + double reported_stdev_jitter; + unsigned int reported_jitter_count; + + double reported_maxlost; + double reported_minlost; + double reported_normdev_lost; + double reported_stdev_lost; + + double rxlost; + double maxrxlost; + double minrxlost; + double normdev_rxlost; + double stdev_rxlost; + unsigned int rxlost_count; + double maxrxjitter; double minrxjitter; + double normdev_rxjitter; + double stdev_rxjitter; + unsigned int rxjitter_count; double maxrtt; double minrtt; + double normdevrtt; + double stdevrtt; + unsigned int rtt_count; int sendfur; }; @@ -839,7 +868,12 @@ unsigned int lsw; unsigned int comp; struct ast_frame *f = &ast_null_frame; - + double reported_jitter; + double reported_normdev_jitter_current; + double normdevrtt_current; + double reported_lost; + double reported_normdev_lost_current; + if (!rtp || !rtp->rtcp) return &ast_null_frame; @@ -934,14 +968,21 @@ } rtt = rtt / 1000.; rttsec = rtt / 1000.; + rtp->rtcp->rtt = rttsec; + if (comp - dlsr >= lsr) { rtp->rtcp->accumulated_transit += rttsec; - rtp->rtcp->rtt = rttsec; + if(rtp->rtcp->rtt_count==0) rtp->rtcp->minrtt=rttsec; if (rtp->rtcp->maxrttrtcp->maxrtt = rttsec; if (rtp->rtcp->minrtt>rttsec) rtp->rtcp->minrtt = rttsec; + normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count); + rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count); + rtp->rtcp->normdevrtt = normdevrtt_current; + rtp->rtcp->rtt_count++; + } else if (rtcp_debug_test_addr(&sin)) { ast_verbose("Internal RTCP NTP clock skew detected: " "lsr=%u, now=%u, dlsr=%u (%d:%03dms), " @@ -953,7 +994,29 @@ } rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]); + reported_jitter = (double) rtp->rtcp->reported_jitter; + if(rtp->rtcp->reported_jitter_count==0) rtp->rtcp->reported_minjitter=reported_jitter; + if(reported_jitter < rtp->rtcp->reported_minjitter) + rtp->rtcp->reported_minjitter=reported_jitter; + if(reported_jitter > rtp->rtcp->reported_maxjitter) + rtp->rtcp->reported_maxjitter=reported_jitter; + reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count); + rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count); + rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current; + rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff; + reported_lost = (double) rtp->rtcp->reported_lost; + //using same counter as for jitter + if(rtp->rtcp->reported_jitter_count==0) rtp->rtcp->reported_minlost=reported_lost; + if(reported_lost < rtp->rtcp->reported_minlost) + rtp->rtcp->reported_minlost=reported_lost; + if(reported_lost > rtp->rtcp->reported_maxlost) + rtp->rtcp->reported_maxlost=reported_lost; + reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count); + rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count); + rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current; + rtp->rtcp->reported_jitter_count++; + if (rtcp_debug_test_addr(&sin)) { ast_verbose(" Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24)); ast_verbose(" Packets lost so far: %d\n", rtp->rtcp->reported_lost); @@ -1004,7 +1067,7 @@ double d; double dtv; double prog; - + double normdev_rxjitter_current; if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) { gettimeofday(&rtp->rxcore, NULL); rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000; @@ -1040,8 +1103,30 @@ rtp->rxjitter += (1./16.) * (d - rtp->rxjitter); if (rtp->rtcp && rtp->rxjitter > rtp->rtcp->maxrxjitter) rtp->rtcp->maxrxjitter = rtp->rxjitter; + if(rtp->rtcp->rxjitter_count == 1)rtp->rtcp->minrxjitter = rtp->rxjitter; if (rtp->rtcp && rtp->rxjitter < rtp->rtcp->minrxjitter) rtp->rtcp->minrxjitter = rtp->rxjitter; + + normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count); + rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count); + + rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current; + rtp->rtcp->rxjitter_count++; +} + +/*! \brief Calculate normal deviation */ +double normdev_compute(double normdev,double sample,unsigned int sample_count) +{ + return (normdev*sample_count+sample)/(sample_count+1); +} + +double stddev_compute(double stddev,double sample,double normdev,double normdev_curent,unsigned int sample_count) +{ + //for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf +// return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1)); + //we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute + //optimized formula + return (sample_count*stddev + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1); } /*! \brief Perform a Packet2Packet RTP write */ @@ -2047,6 +2132,45 @@ rtp->rxseqno = 0; } + + +char *ast_rtp_get_quality_jitter(struct ast_rtp *rtp, struct ast_rtp_quality *qual) +{ + /* + *ssrc our ssrc + *themssrc their ssrc + *lp lost packets + *rxjitter our calculated jitter(rx) + *rxcount no. received packets + *txjitter reported jitter of the other end + *txcount transmitted packets + *rlp remote lost packets + *rtt round trip time + */ + snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), "minrxjitter=%f;maxrxjitter=%f;avgrxjitter=%f;stdevrxjitter=%f;reported_minjitter=%f;reported_maxjitter=%f;reported_avgjitter=%f;reported_stdevjitter=%f;", + rtp->rtcp->minrxjitter,rtp->rtcp->maxrxjitter,rtp->rtcp->normdev_rxjitter,sqrt(rtp->rtcp->stdev_rxjitter), + rtp->rtcp->reported_minjitter,rtp->rtcp->reported_maxjitter,rtp->rtcp->reported_normdev_jitter,sqrt(rtp->rtcp->reported_stdev_jitter) + ); + return rtp->rtcp->quality_jitter; +} + +char *ast_rtp_get_quality_loss(struct ast_rtp *rtp, struct ast_rtp_quality *qual) +{ + snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), "minrxlost=%f;maxrxlost=%f;avgrxlostr=%f;stdevrxlost=%f;reported_minlost=%f;reported_maxlost=%f;reported_avglost=%f;reported_stdevlost=%f;", + rtp->rtcp->minrxlost,rtp->rtcp->maxrxlost,rtp->rtcp->normdev_rxlost,sqrt(rtp->rtcp->stdev_rxlost), + rtp->rtcp->reported_minlost,rtp->rtcp->reported_maxlost,rtp->rtcp->reported_normdev_lost,sqrt(rtp->rtcp->reported_stdev_lost) + ); + return rtp->rtcp->quality_loss; +} + +char *ast_rtp_get_quality_rtt(struct ast_rtp *rtp, struct ast_rtp_quality *qual) +{ + snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;", + rtp->rtcp->minrtt,rtp->rtcp->maxrtt,rtp->rtcp->normdevrtt,sqrt(rtp->rtcp->stdevrtt) + ); + return rtp->rtcp->quality_rtt; +} + char *ast_rtp_get_quality(struct ast_rtp *rtp, struct ast_rtp_quality *qual) { /* @@ -2073,7 +2197,6 @@ qual->rtt = rtp->rtcp->rtt; } snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality), "ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f", rtp->ssrc, rtp->themssrc, rtp->rtcp->expected_prior - rtp->rtcp->received_prior, rtp->rxjitter, rtp->rxcount, (double)rtp->rtcp->reported_jitter/65536., rtp->txcount, rtp->rtcp->reported_lost, rtp->rtcp->rtt); - return rtp->rtcp->quality; } @@ -2325,6 +2448,7 @@ int fraction; struct timeval dlsr; char bdata[512]; + double rxlost_current; /* Commented condition is always not NULL if rtp->rtcp is not NULL */ if (!rtp || !rtp->rtcp/* || (&rtp->rtcp->them.sin_addr == 0)*/) @@ -2359,6 +2483,24 @@ received_interval = rtp->rxcount - rtp->rtcp->received_prior; rtp->rtcp->received_prior = rtp->rxcount; lost_interval = expected_interval - received_interval; + + + if(lost_interval<=0) + rtp->rtcp->rxlost = 0; + else + rtp->rtcp->rxlost = rtp->rtcp->rxlost; + if(rtp->rtcp->rxlost_count == 0) + rtp->rtcp->minrxlost = rtp->rtcp->rxlost; + if(lost_interval < rtp->rtcp->minrxlost) + rtp->rtcp->minrxlost = rtp->rtcp->rxlost; + if(lost_interval > rtp->rtcp->maxrxlost) + rtp->rtcp->maxrxlost = rtp->rtcp->rxlost; + + rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count); + rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count); + rtp->rtcp->normdev_rxlost = rxlost_current; + rtp->rtcp->rxlost_count++; + if (expected_interval == 0 || lost_interval <= 0) fraction = 0; else