]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add more rtp statistics with several new vars for cdr processing in_jitter_min_varian...
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 30 Jan 2014 00:08:27 +0000 (05:08 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Thu, 30 Jan 2014 00:08:34 +0000 (05:08 +0500)
src/include/switch_types.h
src/mod/applications/mod_commands/mod_commands.c
src/mod/applications/mod_conference/mod_conference.c
src/mod/applications/mod_dptools/mod_dptools.c
src/switch_core_media.c
src/switch_rtp.c

index bf91cd82966802e5d98f0d514faa99dd6c6f98bc..331bcb523fb842eb1c6a01a596010ca901fd6842 100644 (file)
@@ -227,6 +227,15 @@ SWITCH_BEGIN_EXTERN_C
 #define SWITCH_MAX_TRANS 2000
 #define SWITCH_CORE_SESSION_MAX_PRIVATES 2
 
+/* Jitter */
+#define JITTER_VARIANCE_THRESHOLD 400.0
+/* IPDV */
+#define IPDV_THRESHOLD 1.0
+/* Burst and Lost Rate */
+#define LOST_BURST_ANALYZE 500
+/* Burst */
+#define LOST_BURST_CAPTURE 1024
+
 typedef uint8_t switch_byte_t;
 
 typedef enum {
@@ -591,6 +600,29 @@ typedef struct {
        switch_size_t cng_packet_count;
        switch_size_t flush_packet_count;
        switch_size_t largest_jb_size;
+       /* Jitter */
+       int64_t last_proc_time;         
+       int64_t jitter_n;
+       int64_t jitter_add;
+       int64_t jitter_addsq;
+
+       double variance;
+       double min_variance;
+       double max_variance;
+       double std_deviation;
+
+       /* Burst and Packet Loss */
+       double lossrate;
+       double burstrate;
+       double mean_interval;
+       int loss[LOST_BURST_CAPTURE];
+       int last_loss;
+       int recved;     
+       int last_processed_seq;
+       switch_size_t flaws;
+       switch_size_t last_flaw;
+       double R;
+       double mos;
 } switch_rtp_numbers_t;
 
 
index 4c872e5c23f26915bb80d9f7c9e0c01cae7af35d..6869e51436c17216a861356aed8ccf987277a23b 100644 (file)
@@ -2928,6 +2928,130 @@ SWITCH_STANDARD_API(uuid_deflect)
        return SWITCH_STATUS_SUCCESS;
 }
 
+
+#define UUID_MEDIA_STATS_SYNTAX "<uuid>"
+SWITCH_STANDARD_API(uuid_set_media_stats)
+{
+       switch_core_session_t *tsession = NULL;
+       const char *uuid = cmd;
+
+       if (zstr(uuid)) {
+               stream->write_function(stream, "-USAGE: %s\n", UUID_MEDIA_STATS_SYNTAX);
+       } else {
+               if ((tsession = switch_core_session_locate(uuid))) {
+                       switch_core_media_set_stats(tsession);
+                       stream->write_function(stream, "+OK:\n");
+                       switch_core_session_rwunlock(tsession);
+               } else {
+                       stream->write_function(stream, "-ERR No such channel %s!\n", uuid);
+               }
+       }
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+#define add_stat(_i, _s) cJSON_AddItemToObject(jstats, _s, cJSON_CreateNumber(_i))
+
+static void jsonify_stats(cJSON *json, const char *name, switch_rtp_stats_t *stats)
+{
+       cJSON *jstats = cJSON_CreateObject();
+       cJSON_AddItemToObject(json, name, jstats);      
+
+       stats->inbound.std_deviation = sqrt(stats->inbound.variance);
+
+       add_stat(stats->inbound.raw_bytes, "in_raw_bytes");
+       add_stat(stats->inbound.media_bytes, "in_media_bytes");
+       add_stat(stats->inbound.packet_count, "in_packet_count");
+       add_stat(stats->inbound.media_packet_count, "in_media_packet_count");
+       add_stat(stats->inbound.skip_packet_count, "in_skip_packet_count");
+       add_stat(stats->inbound.jb_packet_count, "in_jitter_packet_count");
+       add_stat(stats->inbound.dtmf_packet_count, "in_dtmf_packet_count");
+       add_stat(stats->inbound.cng_packet_count, "in_cng_packet_count");
+       add_stat(stats->inbound.flush_packet_count, "in_flush_packet_count");
+       add_stat(stats->inbound.largest_jb_size, "in_largest_jb_size");
+
+       add_stat (stats->inbound.min_variance, "in_jitter_min_variance");
+       add_stat (stats->inbound.max_variance, "in_jitter_max_variance");
+       add_stat (stats->inbound.lossrate, "in_jitter_loss_rate");
+       add_stat (stats->inbound.burstrate, "in_jitter_burst_rate");
+       add_stat (stats->inbound.mean_interval, "in_mean_interval");
+
+       add_stat(stats->inbound.flaws, "in_flaw_total");
+
+       add_stat (stats->inbound.R, "in_quality_percentage");
+       add_stat (stats->inbound.mos, "in_mos");
+
+
+       add_stat(stats->outbound.raw_bytes, "out_raw_bytes");
+       add_stat(stats->outbound.media_bytes, "out_media_bytes");
+       add_stat(stats->outbound.packet_count, "out_packet_count");
+       add_stat(stats->outbound.media_packet_count, "out_media_packet_count");
+       add_stat(stats->outbound.skip_packet_count, "out_skip_packet_count");
+       add_stat(stats->outbound.dtmf_packet_count, "out_dtmf_packet_count");
+       add_stat(stats->outbound.cng_packet_count, "out_cng_packet_count");
+
+       add_stat(stats->rtcp.packet_count, "rtcp_packet_count");
+       add_stat(stats->rtcp.octet_count, "rtcp_octet_count");
+       
+}
+
+static switch_bool_t true_enough(cJSON *json)
+{
+       if (json && (json->type == cJSON_True || json->valueint || json->valuedouble || json->valuestring)) {
+               return SWITCH_TRUE;
+       }
+
+       return SWITCH_FALSE;
+}
+
+SWITCH_STANDARD_JSON_API(json_stats_function)
+{
+       cJSON *reply, *data = cJSON_GetObjectItem(json, "data");
+       switch_status_t status = SWITCH_STATUS_FALSE;
+       const char *uuid = cJSON_GetObjectCstr(data, "uuid");
+       cJSON *cdata = cJSON_GetObjectItem(data, "channelData");
+
+       switch_core_session_t *tsession;
+
+       reply = cJSON_CreateObject();
+       *json_reply = reply;    
+
+       if (zstr(uuid)) {
+               cJSON_AddItemToObject(reply, "response", cJSON_CreateString("INVALID INPUT"));
+               goto end;
+       }
+
+       
+       if ((tsession = switch_core_session_locate(uuid))) {
+               cJSON *jevent;
+               switch_rtp_stats_t *audio_stats = NULL, *video_stats = NULL;
+
+               switch_core_media_set_stats(tsession);
+               
+               audio_stats = switch_core_media_get_stats(tsession, SWITCH_MEDIA_TYPE_AUDIO, switch_core_session_get_pool(tsession));
+               video_stats = switch_core_media_get_stats(tsession, SWITCH_MEDIA_TYPE_VIDEO, switch_core_session_get_pool(tsession));
+               
+               jsonify_stats(reply, "audio", audio_stats);
+               jsonify_stats(reply, "video", video_stats);
+               
+               if (true_enough(cdata) && switch_ivr_generate_json_cdr(tsession, &jevent, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
+                       cJSON_AddItemToObject(reply, "channelData", jevent);
+               }
+
+               switch_core_session_rwunlock(tsession);
+               
+               status = SWITCH_STATUS_SUCCESS;
+       } else {
+               cJSON_AddItemToObject(reply, "response", cJSON_CreateString("Session does not exist"));
+               goto end;
+       }
+
+ end:
+
+       return status;
+}
+
+
 #define UUID_RECOVERY_REFRESH_SYNTAX "<uuid> <uri>"
 SWITCH_STANDARD_API(uuid_recovery_refresh)
 {
@@ -6494,6 +6618,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill channel", kill_function, KILL_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "uuid_send_message", "Send MESSAGE to the endpoint", uuid_send_message_function, SEND_MESSAGE_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "uuid_send_info", "Send info to the endpoint", uuid_send_info_function, INFO_SYNTAX);
+       SWITCH_ADD_API(commands_api_interface, "uuid_set_media_stats", "Set media stats", uuid_set_media_stats, UUID_MEDIA_STATS_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "uuid_video_refresh", "Send video refresh.", uuid_video_refresh_function, VIDEO_REFRESH_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "uuid_outgoing_answer", "Answer outgoing channel", outgoing_answer_function, OUTGOING_ANSWER_SYNTAX);
        SWITCH_ADD_API(commands_api_interface, "uuid_limit", "Increase limit resource", uuid_limit_function, LIMIT_SYNTAX);
@@ -6525,6 +6650,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
        SWITCH_ADD_API(commands_api_interface, "file_exists", "Check if a file exists on server", file_exists_function, "<file>");
        SWITCH_ADD_API(commands_api_interface, "json", "JSON API", json_function, "JSON");
 
+       SWITCH_ADD_JSON_API(json_api_interface, "mediaStats", "JSON Media Stats", json_stats_function, "");
 
        SWITCH_ADD_JSON_API(json_api_interface, "status", "JSON status API", json_status_function, "");
        SWITCH_ADD_JSON_API(json_api_interface, "fsapi", "JSON FSAPI Gateway", json_api_function, "");
index fc9fad6af72997d2b6c9be1e1762cea53531f703..e7fc3760f275d70a588890921a156e8bccdc85cf 100644 (file)
@@ -3655,6 +3655,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v
 
        switch_core_session_get_read_impl(session, &member->read_impl);
 
+       switch_channel_audio_sync(channel);
+
        /* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it 
           and mux it with any audio from other channels. */
 
@@ -8119,8 +8121,6 @@ SWITCH_STANDARD_APP(conference_function)
                goto end;
        }
 
-       
-
        if ((flags_str = strstr(mydata, flags_prefix))) {
                char *p;
                *((char *) flags_str) = '\0';
index 4167800a22646ee513391f72fcacddfd935e7b8b..b6ccbb26a1b1c09b78a17d770ca8fc3ffb4ed996 100755 (executable)
@@ -1175,6 +1175,13 @@ SWITCH_STANDARD_APP(eval_function)
        return;
 }
 
+SWITCH_STANDARD_APP(set_media_stats_function)
+{
+       switch_core_media_set_stats(session);
+
+       return;
+}
+
 SWITCH_STANDARD_APP(zombie_function)
 {
        switch_channel_t *channel = switch_core_session_get_channel(session);
@@ -5686,6 +5693,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
        SWITCH_ADD_APP(app_interface, "strftime", "strftime", "strftime", strftime_function, "[<epoch>|]<format string>", SAF_SUPPORT_NOMEDIA);
        SWITCH_ADD_APP(app_interface, "phrase", "Say a Phrase", "Say a Phrase", phrase_function, "<macro_name>,<data>", SAF_NONE);
        SWITCH_ADD_APP(app_interface, "eval", "Do Nothing", "Do Nothing", eval_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
+       SWITCH_ADD_APP(app_interface, "set_media_stats", "Set Media Stats", "Set Media Stats", set_media_stats_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC);
        SWITCH_ADD_APP(app_interface, "stop", "Do Nothing", "Do Nothing", eval_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
        SWITCH_ADD_APP(app_interface, "set_zombie_exec", "Enable Zombie Execution", "Enable Zombie Execution", 
                                   zombie_function, "", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
index d0ce10030e29e0d61d9fde3b2693a9373e1f8b43..f6121663f900ea2151f3d35bbd1cde93c8e493d9 100644 (file)
@@ -1116,6 +1116,11 @@ SWITCH_DECLARE(void) switch_core_session_check_outgoing_crypto(switch_core_sessi
        switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
        switch_channel_set_variable(channel, var_name, var_val)
 
+#define add_stat_double(_i, _s)                                                                                                \
+       switch_snprintf(var_name, sizeof(var_name), "rtp_%s_%s", switch_str_nil(prefix), _s) ; \
+       switch_snprintf(var_val, sizeof(var_val), "%0.2f", _i); \
+       switch_channel_set_variable(channel, var_name, var_val)
+
 static void set_stats(switch_core_session_t *session, switch_media_type_t type, const char *prefix)
 {
        switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
@@ -1124,17 +1129,27 @@ static void set_stats(switch_core_session_t *session, switch_media_type_t type,
        char var_name[256] = "", var_val[35] = "";
 
        if (stats) {
+               stats->inbound.std_deviation = sqrt(stats->inbound.variance);
 
                add_stat(stats->inbound.raw_bytes, "in_raw_bytes");
                add_stat(stats->inbound.media_bytes, "in_media_bytes");
                add_stat(stats->inbound.packet_count, "in_packet_count");
                add_stat(stats->inbound.media_packet_count, "in_media_packet_count");
                add_stat(stats->inbound.skip_packet_count, "in_skip_packet_count");
-               add_stat(stats->inbound.jb_packet_count, "in_jb_packet_count");
+               add_stat(stats->inbound.jb_packet_count, "in_jitter_packet_count");
                add_stat(stats->inbound.dtmf_packet_count, "in_dtmf_packet_count");
                add_stat(stats->inbound.cng_packet_count, "in_cng_packet_count");
                add_stat(stats->inbound.flush_packet_count, "in_flush_packet_count");
                add_stat(stats->inbound.largest_jb_size, "in_largest_jb_size");
+               add_stat_double(stats->inbound.min_variance, "in_jitter_min_variance");
+               add_stat_double(stats->inbound.max_variance, "in_jitter_max_variance");
+               add_stat_double(stats->inbound.lossrate, "in_jitter_loss_rate");
+               add_stat_double(stats->inbound.burstrate, "in_jitter_burst_rate");
+               add_stat_double(stats->inbound.mean_interval, "in_mean_interval");
+               add_stat(stats->inbound.flaws, "in_flaw_total");
+               add_stat_double(stats->inbound.R, "in_quality_percentage");
+               add_stat_double(stats->inbound.mos, "in_mos");
+
 
                add_stat(stats->outbound.raw_bytes, "out_raw_bytes");
                add_stat(stats->outbound.media_bytes, "out_media_bytes");
index 48b723a7b5ac161f598b2c1b0328315786539bf8..fb821ef6e99707639e498c71e5d3f59a5c5e5d8f 100644 (file)
@@ -69,6 +69,8 @@
 #define MAX_SRTP_ERRS 10
 #define RTP_TS_RESET 1
 
+#define DTMF_SANITY (rtp_session->one_second * 30)
+
 static switch_port_t START_PORT = RTP_START_PORT;
 static switch_port_t END_PORT = RTP_END_PORT;
 static switch_mutex_t *port_lock = NULL;
@@ -353,6 +355,11 @@ struct switch_rtp {
        uint32_t conf_samples_per_interval;
        uint32_t rsamples_per_interval;
        uint32_t ms_per_packet;
+       uint32_t one_second;
+       uint32_t consecutive_flaws;
+       uint32_t jitter_lead;
+       double old_mean;
+       switch_time_t next_stat_check_time;
        switch_port_t local_port;
        switch_port_t remote_port;
        switch_port_t eff_remote_port;
@@ -407,7 +414,6 @@ struct switch_rtp {
        int zinit;
 #endif
 
-
 };
 
 struct switch_rtcp_source {
@@ -480,8 +486,10 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
        if (rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON]) {
                rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON]++;
 
-               if (rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] > 1000) {
+               if (rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] > DTMF_SANITY) {
                        rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] = 0;
+               } else {
+                       rtp_session->stats.inbound.last_processed_seq = 0;
                }
        }
 
@@ -515,6 +523,8 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
                uint16_t in_digit_seq;
                uint32_t ts;
 
+               rtp_session->stats.inbound.last_processed_seq = 0;
+
                if (!(packet[0] || packet[1] || packet[2] || packet[3]) && len >= 8) {
 
                        
@@ -540,7 +550,7 @@ static handle_rfc2833_result_t handle_rfc2833(switch_rtp_t *rtp_session, switch_
                if (rtp_session->flags[SWITCH_RTP_FLAG_PASS_RFC2833]) {
 
                        if (end) {
-                               rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] = 998;
+                               rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] = DTMF_SANITY - 3;
                        } else if (!rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON]) {
                                rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] = 1;
                        }
@@ -1563,6 +1573,188 @@ static void send_pli(switch_rtp_t *rtp_session)
        return;
 }
 
+static void do_mos(switch_rtp_t *rtp_session, int force) {
+
+       if (rtp_session->stats.inbound.recved < rtp_session->stats.inbound.flaws) {
+               rtp_session->stats.inbound.flaws = 0;
+       }
+
+       if (rtp_session->stats.inbound.recved > 0 && 
+               rtp_session->stats.inbound.flaws && (force || rtp_session->stats.inbound.last_flaw != rtp_session->stats.inbound.flaws)) {
+               int R;
+
+               if (rtp_session->consecutive_flaws++) {
+                       int diff, penalty;
+
+                       diff = (rtp_session->stats.inbound.flaws - rtp_session->stats.inbound.last_flaw);
+
+                       if (diff < 1) diff = 1;
+
+                       penalty = diff * 2;
+                       
+                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s %s %d consecutive flaws, adding %d flaw penalty\n", 
+                                                         switch_core_session_get_name(rtp_session->session), rtp_type(rtp_session), 
+                                                         rtp_session->consecutive_flaws, penalty);
+
+                       rtp_session->stats.inbound.flaws += penalty;
+               }
+
+               R = ((double)((double)(rtp_session->stats.inbound.recved - rtp_session->stats.inbound.flaws) / (double)rtp_session->stats.inbound.recved) * 100.0);
+               
+               if (R < 0 || R > 100) R = 100;
+
+               rtp_session->stats.inbound.R = R;
+               rtp_session->stats.inbound.mos = 1 + (0.035) * R + (.000007) * R * (R-60) * (100-R);
+               rtp_session->stats.inbound.last_flaw = rtp_session->stats.inbound.flaws;
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s %s stat %0.2f %ld/%d flaws: %ld mos: %0.2f v: %0.2f %0.2f/%0.2f\n",
+                                                 switch_core_session_get_name(rtp_session->session),
+                                                 rtp_type(rtp_session),
+                                                 rtp_session->stats.inbound.R,
+                                                 rtp_session->stats.inbound.recved - rtp_session->stats.inbound.flaws, rtp_session->stats.inbound.recved,
+                                                 rtp_session->stats.inbound.flaws,
+                                                 rtp_session->stats.inbound.mos,
+                                                 rtp_session->stats.inbound.variance,
+                                                 rtp_session->stats.inbound.min_variance,
+                                                 rtp_session->stats.inbound.max_variance
+                                                 );
+       } else {
+               rtp_session->consecutive_flaws = 0;
+       }
+}
+
+void burstr_calculate ( int loss[], int received, double *burstr, double *lossr )
+{
+       int lost = 0;
+       int bursts = 0;
+       int i;
+
+       for ( i = 0; i < LOST_BURST_ANALYZE; i++ ) {
+               lost += i * loss[i];
+               bursts += loss[i];
+       }
+       if (received > 0 && bursts > 0) {
+               *burstr = (double)((double)lost / (double)bursts) / (double)(1.0 / ( 1.0 - (double)lost / (double)received ));
+               if (*burstr < 0) {
+                       *burstr = - *burstr;
+               }
+       } else {
+               *burstr = 0;
+       }
+       if (received > 0) {
+               *lossr = (double)((double)lost / (double)received);
+       } else {
+               *lossr = 0;
+       }
+}
+
+static void reset_jitter_seq(switch_rtp_t *rtp_session)
+{
+       rtp_session->stats.inbound.last_proc_time = 0;
+       rtp_session->stats.inbound.last_processed_seq = 0;
+       rtp_session->jitter_lead = 0;
+}
+
+static void check_jitter(switch_rtp_t *rtp_session)
+{
+       switch_time_t current_time;
+       int64_t diff_time = 0, cur_diff = 0;
+       int seq;
+
+       current_time = switch_micro_time_now() / 1000;
+
+       if (rtp_session->flags[SWITCH_RTP_FLAG_PAUSE] || rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] || rtp_session->dtmf_data.in_digit_ts) {
+               reset_jitter_seq(rtp_session);
+               return;
+       }
+
+       if (++rtp_session->jitter_lead < 10 || !rtp_session->stats.inbound.last_proc_time) {
+               rtp_session->stats.inbound.last_proc_time = current_time;
+               return;
+       }
+
+       diff_time = (current_time - rtp_session->stats.inbound.last_proc_time);
+       seq = (int)(uint16_t) ntohs((uint16_t) rtp_session->recv_msg.header.seq);
+       
+       /* Burst and Packet Loss */
+       rtp_session->stats.inbound.recved++;
+
+       if (rtp_session->stats.inbound.last_processed_seq > 0 && seq > (int)(rtp_session->stats.inbound.last_processed_seq + 1)) {
+               int lost = (seq - rtp_session->stats.inbound.last_processed_seq - 1);
+
+               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s Got: %s seq %d but expected: %d lost: %d\n", 
+                                                 switch_core_session_get_name(rtp_session->session),
+                                                 rtp_type(rtp_session),
+                                                 seq,
+                                                 (rtp_session->stats.inbound.last_processed_seq + 1), lost);
+               rtp_session->stats.inbound.last_loss++;
+
+               if (rtp_session->stats.inbound.last_loss > 0 && rtp_session->stats.inbound.last_loss < LOST_BURST_CAPTURE) {
+                       rtp_session->stats.inbound.loss[rtp_session->stats.inbound.last_loss] += lost;
+               }
+
+               rtp_session->stats.inbound.flaws += lost;
+               
+       } else {
+               rtp_session->stats.inbound.last_loss = 0;
+       }
+           
+       rtp_session->stats.inbound.last_processed_seq = seq;
+
+       /* Burst and Packet Loss */
+
+       if (current_time > rtp_session->next_stat_check_time) {
+               rtp_session->next_stat_check_time = current_time + 5000;
+               burstr_calculate(rtp_session->stats.inbound.loss, rtp_session->stats.inbound.recved,
+                                                &(rtp_session->stats.inbound.burstrate), &(rtp_session->stats.inbound.lossrate));
+               do_mos(rtp_session, SWITCH_TRUE);
+       } else {
+               do_mos(rtp_session, SWITCH_FALSE);
+       }
+               
+
+       if ( diff_time < 0 ) {
+               diff_time = -diff_time;
+       }
+       
+       rtp_session->stats.inbound.jitter_n++;
+       rtp_session->stats.inbound.jitter_add += diff_time;
+
+       cur_diff = diff_time - rtp_session->stats.inbound.mean_interval;
+       
+       rtp_session->stats.inbound.jitter_addsq += (cur_diff * cur_diff);
+       rtp_session->stats.inbound.last_proc_time = current_time;
+
+       if (rtp_session->stats.inbound.jitter_n > 0) {
+               double ipdv;
+
+               rtp_session->stats.inbound.mean_interval = (double)rtp_session->stats.inbound.jitter_add / (double)rtp_session->stats.inbound.jitter_n;
+
+               if (!rtp_session->old_mean) {
+                       rtp_session->old_mean = rtp_session->stats.inbound.mean_interval;
+               }
+
+               rtp_session->stats.inbound.variance = (double)rtp_session->stats.inbound.jitter_addsq / (double)rtp_session->stats.inbound.jitter_n;
+               
+               //printf("CHECK %d +%ld +%ld %f %f\n", rtp_session->timer.samplecount, diff_time, (diff_time * diff_time), rtp_session->stats.inbound.mean_interval, rtp_session->stats.inbound.variance);
+               
+               ipdv = rtp_session->old_mean - rtp_session->stats.inbound.mean_interval;
+
+               if ( ipdv > IPDV_THRESHOLD ) { /* It shows Increasing Delays */
+                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Calculated Instantaneous Packet Delay Variation: %s packet %lf\n",
+                                                         rtp_type(rtp_session), ipdv);
+               }
+
+               if ( rtp_session->stats.inbound.variance < rtp_session->stats.inbound.min_variance || rtp_session->stats.inbound.min_variance == 0 ) {
+                       rtp_session->stats.inbound.min_variance = rtp_session->stats.inbound.variance;
+               }
+
+               if ( rtp_session->stats.inbound.variance > rtp_session->stats.inbound.max_variance ) {
+                       rtp_session->stats.inbound.max_variance = rtp_session->stats.inbound.variance;
+               }
+
+               rtp_session->old_mean = rtp_session->stats.inbound.mean_interval;
+       }
+}
 
 static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
 {
@@ -1570,7 +1762,6 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session)
        int rtcp_ok = 1;
        switch_time_t now = switch_micro_time_now();
 
-
        if (rtp_session->fir_countdown) {
                //if (rtp_session->fir_countdown == FIR_COUNTDOWN) {
                //      do_flush(rtp_session, SWITCH_TRUE);
@@ -2923,6 +3114,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_interval(switch_rtp_t *rtp_sessio
        rtp_session->samples_per_second =
                (uint32_t) ((double) (1000.0f / (double) (rtp_session->ms_per_packet / 1000)) * (double) rtp_session->samples_per_interval);
 
+       rtp_session->one_second = (rtp_session->samples_per_second / rtp_session->samples_per_interval);
+
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -3026,6 +3219,8 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
        rtp_session->seq = (uint16_t) rand();
        rtp_session->ssrc = (uint32_t) ((intptr_t) rtp_session + (uint32_t) switch_epoch_time_now(NULL));
 
+       rtp_session->stats.inbound.R = 100.0;
+       rtp_session->stats.inbound.mos = 4.5;
        rtp_session->send_msg.header.ssrc = htonl(rtp_session->ssrc);
        rtp_session->send_msg.header.ts = 0;
        rtp_session->send_msg.header.m = 0;
@@ -3151,6 +3346,21 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_create(switch_rtp_t **new_rtp_session
 
 #endif
 
+       /* Jitter */
+       rtp_session->stats.inbound.last_proc_time = switch_time_now() / 1000;
+       rtp_session->stats.inbound.jitter_n = 0;
+       rtp_session->stats.inbound.jitter_add = 0;
+       rtp_session->stats.inbound.jitter_addsq = 0;
+       rtp_session->stats.inbound.min_variance = 0;
+       rtp_session->stats.inbound.max_variance = 0;
+       
+       /* Burst and Packet Loss */
+       rtp_session->stats.inbound.lossrate = 0;
+    rtp_session->stats.inbound.burstrate = 0;
+    memset(rtp_session->stats.inbound.loss, 0, sizeof(rtp_session->stats.inbound.loss));
+    rtp_session->stats.inbound.last_loss = 0;
+    rtp_session->stats.inbound.last_processed_seq = -1;
+
        rtp_session->ready = 1;
        *new_rtp_session = rtp_session;
 
@@ -3628,6 +3838,8 @@ SWITCH_DECLARE(void) switch_rtp_destroy(switch_rtp_t **rtp_session)
        READ_DEC((*rtp_session));
        WRITE_DEC((*rtp_session));
 
+       do_mos(*rtp_session, SWITCH_TRUE);
+
        switch_mutex_lock((*rtp_session)->flag_mutex);
 
        switch_rtp_kill_socket(*rtp_session);
@@ -3804,7 +4016,11 @@ SWITCH_DECLARE(void) switch_rtp_set_flag(switch_rtp_t *rtp_session, switch_rtp_f
        rtp_session->flags[flag] = 1;
        switch_mutex_unlock(rtp_session->flag_mutex);
 
-       if (flag == SWITCH_RTP_FLAG_AUTOADJ) {
+       if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
+               rtp_session->stats.inbound.last_processed_seq = 0;
+       } else if (flag == SWITCH_RTP_FLAG_FLUSH) {
+               reset_jitter_seq(rtp_session);
+       } else if (flag == SWITCH_RTP_FLAG_AUTOADJ) {
                rtp_session->autoadj_window = 20;
                rtp_session->autoadj_tally = 0;
                rtp_flush_read_buffer(rtp_session, SWITCH_RTP_FLUSH_ONCE);
@@ -3829,7 +4045,9 @@ SWITCH_DECLARE(void) switch_rtp_clear_flag(switch_rtp_t *rtp_session, switch_rtp
        rtp_session->flags[flag] = 0;
        switch_mutex_unlock(rtp_session->flag_mutex);
 
-       if (flag == SWITCH_RTP_FLAG_NOBLOCK && rtp_session->sock_input) {
+       if (flag == SWITCH_RTP_FLAG_DTMF_ON) {
+               rtp_session->stats.inbound.last_processed_seq = 0;
+       } else if (flag == SWITCH_RTP_FLAG_NOBLOCK && rtp_session->sock_input) {
                switch_socket_opt_set(rtp_session->sock_input, SWITCH_SO_NONBLOCK, FALSE);
        }
 }
@@ -4023,6 +4241,7 @@ SWITCH_DECLARE(void) rtp_flush_read_buffer(switch_rtp_t *rtp_session, switch_rtp
        if (switch_rtp_ready(rtp_session)) {
                rtp_session->last_write_ts = RTP_TS_RESET;
                rtp_session->flags[SWITCH_RTP_FLAG_FLUSH] = 1;
+               reset_jitter_seq(rtp_session);
 
                switch (flush) {
                case SWITCH_RTP_FLUSH_STICK:
@@ -4046,6 +4265,7 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
        if (!switch_rtp_ready(rtp_session)) {
                return;
        }
+       reset_jitter_seq(rtp_session);
 
        if (!force) {
                if (rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] || 
@@ -4057,7 +4277,6 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
                }
        }
        
-
        READ_INC(rtp_session);
 
        if (switch_rtp_ready(rtp_session)) {
@@ -4104,6 +4323,7 @@ static void do_flush(switch_rtp_t *rtp_session, int force)
 
                if (rtp_session->jb && flushed) {
                        stfu_n_sync(rtp_session->jb, flushed);
+                       reset_jitter_seq(rtp_session);
                }
 
                if (was_blocking && switch_rtp_ready(rtp_session)) {
@@ -4164,6 +4384,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
        unsigned char *b = NULL;
        int sync = 0;
        switch_time_t now;
+       switch_size_t xcheck_jitter = 0;
 
        switch_assert(bytes);
  more:
@@ -4177,6 +4398,13 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
                rtp_session->missed_count = 0;
        }
 
+
+       if (*bytes > rtp_header_len && (rtp_session->recv_msg.header.version == 2 && check_recv_payload(rtp_session))) {
+               xcheck_jitter = *bytes;
+               check_jitter(rtp_session);
+       }
+
+
        if (check_rtcp_and_ice(rtp_session) == -1) {
                return SWITCH_STATUS_GENERR;
        }
@@ -4279,6 +4507,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
        if (sync) {
                if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
                        switch_core_timer_sync(&rtp_session->timer);
+                       reset_jitter_seq(rtp_session);
                }
                rtp_session->hot_hits = 0;
                goto more;
@@ -4384,7 +4613,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
                if (!rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] && !rtp_session->flags[SWITCH_RTP_FLAG_UDPTL]) {
 #ifdef ENABLE_ZRTP
                        /* ZRTP Recv */
-                       if(zrtp_on) {
+                       if (zrtp_on) {
                                
                                unsigned int sbytes = (int) *bytes;
                                zrtp_status_t stat = 0;
@@ -4487,6 +4716,7 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
 
                if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
                        switch_core_timer_sync(&rtp_session->timer);
+                       reset_jitter_seq(rtp_session);
                }
 
                if (stfu_n_eat(rtp_session->jb, rtp_session->last_read_ts, 
@@ -4520,6 +4750,12 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t
                        rtp_session->recv_msg.header.pt = jb_frame->pt;
                        rtp_session->recv_msg.header.seq = htons(jb_frame->seq);
                        status = SWITCH_STATUS_SUCCESS;
+                       if (!xcheck_jitter) {
+                               printf("XXX %d\n", __LINE__);
+                               check_jitter(rtp_session);
+                               xcheck_jitter = *bytes;
+                       }
+
                }
        }
 
@@ -4711,6 +4947,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
        int rtcp_fdr = 0;
        int hot_socket = 0;
        int read_loops = 0;
+       int slept = 0;
 
        if (!switch_rtp_ready(rtp_session)) {
                return -1;
@@ -4743,6 +4980,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                //!rtp_session->flags[SWITCH_RTP_FLAG_RTCP_MUX] && 
                                //!rtp_session->dtls && 
                                rtp_session->read_pollfd) {
+
                                if (switch_poll(rtp_session->read_pollfd, 1, &fdr, 0) == SWITCH_STATUS_SUCCESS) {
                                        status = read_rtp_packet(rtp_session, &bytes, flags, SWITCH_FALSE);
                                        if (status == SWITCH_STATUS_GENERR) {
@@ -4788,6 +5026,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG10, "%s skip timer once\n", switch_core_session_get_name(rtp_session->session));
                                rtp_session->sync_packets++;
                                switch_core_timer_sync(&rtp_session->timer);
+                               reset_jitter_seq(rtp_session);
                        } else {
                                
                                if (rtp_session->sync_packets) {
@@ -4796,13 +5035,27 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                                                          "%s Auto-Flush catching up %d packets (%d)ms.\n",
                                                                          switch_core_session_get_name(rtp_session->session),
                                                                          rtp_session->sync_packets, (rtp_session->ms_per_packet * rtp_session->sync_packets) / 1000);
+                                       if (!rtp_session->flags[SWITCH_RTP_FLAG_PAUSE]) {
+                                               switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s syncing %d %s packet(s)\n", 
+                                                                                 switch_core_session_get_name(rtp_session->session),
+                                                                                 rtp_session->sync_packets, rtp_type(rtp_session));
+
+                                               rtp_session->stats.inbound.flaws += rtp_session->sync_packets;
+                                       }
+
                                        switch_core_timer_sync(&rtp_session->timer);
+                                       reset_jitter_seq(rtp_session);
                                        rtp_session->hot_hits = 0;
                                } else {
+                                       if (slept) {
+                                               switch_cond_next();
+                                       } else {
+                                               switch_core_timer_next(&rtp_session->timer);
+                                               slept++;
+                                       }
 
-                                       switch_core_timer_next(&rtp_session->timer);
                                }
-
+                               
                                rtp_session->sync_packets = 0;
                        }
                }
@@ -4854,6 +5107,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                        if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && rtp_session->flags[SWITCH_RTP_FLAG_BREAK]) {
                                switch_rtp_clear_flag(rtp_session, SWITCH_RTP_FLAG_BREAK);
                                bytes = 0;
+                               reset_jitter_seq(rtp_session);
                 return_cng_frame();
                        }
 
@@ -5048,6 +5302,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                        
                                                if (!rtp_session->flags[SWITCH_RTP_FLAG_USE_TIMER] && rtp_session->timer.interval) {
                                                        switch_core_timer_sync(&rtp_session->timer);
+                                                       reset_jitter_seq(rtp_session);
                                                }
 
 
@@ -5118,6 +5373,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                rtp_session->flags[SWITCH_RTP_FLAG_PROXY_MEDIA] || rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] || 
                                (bytes && bytes < 5) || (!bytes && poll_loop)) {
                                bytes = 0;
+                               reset_jitter_seq(rtp_session);
                                return_cng_frame();
                        }
                }
@@ -5306,11 +5562,26 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_
                                        switch_cond_next();
                                        continue;
                                }
+
                                
+                               
+                               if (!rtp_session->flags[SWITCH_RTP_FLAG_PAUSE] && !rtp_session->flags[SWITCH_RTP_FLAG_DTMF_ON] && !rtp_session->dtmf_data.in_digit_ts 
+                                       && rtp_session->cng_count > (rtp_session->one_second * 2)) {
+
+                                       switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "%s %s timeout\n", 
+                                                                         switch_core_session_get_name(rtp_session->session), rtp_type(rtp_session));
+
+                                       rtp_session->stats.inbound.flaws++;
+                                       do_mos(rtp_session, SWITCH_FALSE);
+                               }
+
+                               rtp_session->cng_count++;
                                return_cng_frame();
                        }
                }
 
+               rtp_session->cng_count = 0;
+
                if (status == SWITCH_STATUS_BREAK || bytes == 0) {
                        if (!(io_flags & SWITCH_IO_FLAG_SINGLE_READ) && rtp_session->flags[SWITCH_RTP_FLAG_DATAWAIT]) {
                                goto do_continue;
@@ -5549,7 +5820,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_zerocopy_read_frame(switch_rtp_t *rtp
        frame->seq = (uint16_t) ntohs((uint16_t) rtp_session->recv_msg.header.seq);
        frame->ssrc = ntohl(rtp_session->recv_msg.header.ssrc);
        frame->m = rtp_session->recv_msg.header.m ? SWITCH_TRUE : SWITCH_FALSE;
-
+       
 #ifdef ENABLE_ZRTP
        if (zrtp_on && rtp_session->flags[SWITCH_ZRTP_FLAG_SECURE_MITM_RECV]) {
                zrtp_session_info_t zrtp_session_info;
@@ -6342,6 +6613,9 @@ SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_sess
        if (rtp_session->jb) {
                s->inbound.largest_jb_size = stfu_n_get_most_qlen(rtp_session->jb);
        }
+
+       do_mos(rtp_session, SWITCH_FALSE);
+
        switch_mutex_unlock(rtp_session->flag_mutex);
 
        return s;