forked from osmocom/wireshark
Calculate skew and clock drift, make it possible to copy the label.
svn path=/trunk/; revision=28606
This commit is contained in:
parent
28dee99cdc
commit
75af067043
|
@ -87,6 +87,7 @@ enum
|
|||
SEQUENCE_COLUMN,
|
||||
DELTA_COLUMN,
|
||||
JITTER_COLUMN,
|
||||
SKEW_COLUMN,
|
||||
IPBW_COLUMN,
|
||||
MARKER_COLUMN,
|
||||
STATUS_COLUMN,
|
||||
|
@ -238,11 +239,12 @@ typedef struct _user_data_t {
|
|||
|
||||
|
||||
/* Column titles. */
|
||||
static const gchar *titles[9] = {
|
||||
static const gchar *titles[10] = {
|
||||
"Packet",
|
||||
"Sequence",
|
||||
"Delta (ms)",
|
||||
"Jitter (ms)",
|
||||
"Skew(ms)",
|
||||
"IP BW (kbps)",
|
||||
"Marker",
|
||||
"Status",
|
||||
|
@ -430,7 +432,7 @@ static void rtp_draw(void *prs _U_)
|
|||
|
||||
/* forward declarations */
|
||||
static void add_to_list(GtkWidget *list, user_data_t * user_data, guint32 number, guint16 seq_num,
|
||||
double delta, double jitter, double bandwidth, gchar *status, gboolean marker,
|
||||
double delta, double jitter, double skew ,double bandwidth, gchar *status, gboolean marker,
|
||||
gchar *timeStr, guint32 pkt_len,gchar *color_str, guint32 flags);
|
||||
|
||||
static int rtp_packet_add_info(GtkWidget *list, user_data_t * user_data,
|
||||
|
@ -582,6 +584,7 @@ static int rtp_packet_add_info(GtkWidget *list, user_data_t * user_data,
|
|||
pinfo->fd->num, rtpinfo->info_seq_num,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
statinfo->bandwidth,
|
||||
status,
|
||||
rtpinfo->info_marker_set,
|
||||
|
@ -594,6 +597,7 @@ static int rtp_packet_add_info(GtkWidget *list, user_data_t * user_data,
|
|||
pinfo->fd->num, rtpinfo->info_seq_num,
|
||||
statinfo->delta,
|
||||
statinfo->jitter,
|
||||
statinfo->skew,
|
||||
statinfo->bandwidth,
|
||||
status,
|
||||
rtpinfo->info_marker_set,
|
||||
|
@ -2885,46 +2889,86 @@ static void on_save_bt_clicked(GtkWidget *bt _U_, user_data_t *user_data)
|
|||
/* when we are finished with redisection, we add the label for the statistic */
|
||||
static void draw_stat(user_data_t *user_data)
|
||||
{
|
||||
gchar label_max[200];
|
||||
gchar label_max[300];
|
||||
guint32 f_expected = (user_data->forward.statinfo.stop_seq_nr + user_data->forward.statinfo.cycles*65536)
|
||||
- user_data->forward.statinfo.start_seq_nr + 1;
|
||||
guint32 r_expected = (user_data->reversed.statinfo.stop_seq_nr + user_data->reversed.statinfo.cycles*65536)
|
||||
- user_data->reversed.statinfo.start_seq_nr + 1;
|
||||
gint32 f_lost = f_expected - user_data->forward.statinfo.total_nr;
|
||||
gint32 r_lost = r_expected - user_data->reversed.statinfo.total_nr;
|
||||
guint32 f_total_nr = user_data->forward.statinfo.total_nr;
|
||||
guint32 r_total_nr = user_data->reversed.statinfo.total_nr;
|
||||
gint32 f_lost = f_expected - f_total_nr;
|
||||
gint32 r_lost = r_expected - r_total_nr;
|
||||
double f_sumt = user_data->forward.statinfo.sumt;
|
||||
double f_sumTS = user_data->forward.statinfo.sumTS;
|
||||
double f_sumt2 = user_data->forward.statinfo.sumt2;
|
||||
double f_sumtTS = user_data->forward.statinfo.sumtTS;
|
||||
|
||||
double r_sumt = user_data->reversed.statinfo.sumt;
|
||||
double r_sumTS = user_data->reversed.statinfo.sumTS;
|
||||
double r_sumt2 = user_data->reversed.statinfo.sumt2;
|
||||
double r_sumtTS = user_data->reversed.statinfo.sumtTS;
|
||||
double f_perc, r_perc;
|
||||
double f_clock_drift = 1.0;
|
||||
double r_clock_drift = 1.0;
|
||||
double f_duration = user_data->forward.statinfo.time - user_data->forward.statinfo.start_time;
|
||||
double r_duration = user_data->reversed.statinfo.time - user_data->reversed.statinfo.start_time;
|
||||
guint32 f_clock_rate = user_data->forward.statinfo.clock_rate;
|
||||
guint32 r_clock_rate = user_data->reversed.statinfo.clock_rate;
|
||||
|
||||
if (f_clock_rate == 0){
|
||||
f_clock_rate = 1;
|
||||
}
|
||||
|
||||
if (r_clock_rate == 0){
|
||||
r_clock_rate = 1;
|
||||
}
|
||||
|
||||
if (f_expected){
|
||||
f_perc = (double)(f_lost*100)/(double)f_expected;
|
||||
} else {
|
||||
f_perc = 0;
|
||||
}
|
||||
if (r_expected){
|
||||
r_perc = (double)(r_lost*100)/(double)r_expected;
|
||||
} else {
|
||||
r_perc = 0;
|
||||
}
|
||||
if (r_expected){
|
||||
r_perc = (double)(r_lost*100)/(double)r_expected;
|
||||
} else {
|
||||
r_perc = 0;
|
||||
}
|
||||
|
||||
if ((f_total_nr >0)&&(f_sumt2 > 0)){
|
||||
f_clock_drift = (f_total_nr * f_sumtTS - f_sumt * f_sumTS) / (f_total_nr * f_sumt2 - f_sumt * f_sumt);
|
||||
}
|
||||
if ((r_total_nr >0)&&(r_sumt2 > 0)){
|
||||
r_clock_drift = (r_total_nr * r_sumtTS - r_sumt * r_sumTS) / (r_total_nr * r_sumt2 - r_sumt * r_sumt);
|
||||
}
|
||||
g_snprintf(label_max, sizeof(label_max), "Max delta = %.2f ms at packet no. %u \n"
|
||||
"Max jitter = %.2f ms. Mean jitter = %.2f ms.\n"
|
||||
"Max skew = %.2f ms.\n"
|
||||
"Total RTP packets = %u (expected %u) Lost RTP packets = %d (%.2f%%)"
|
||||
" Sequence errors = %u \n"
|
||||
"Duration %.2f s (%.0f ms clock drift, corresponding to %.0f Hz (%+.2f%%)",
|
||||
user_data->forward.statinfo.max_delta, user_data->forward.statinfo.max_nr,
|
||||
user_data->forward.statinfo.max_jitter,user_data->forward.statinfo.mean_jitter,
|
||||
user_data->forward.statinfo.max_skew,
|
||||
f_expected, f_expected, f_lost, f_perc,
|
||||
user_data->forward.statinfo.sequence,
|
||||
f_duration/1000,f_duration*(f_clock_drift-1.0),f_clock_drift*f_clock_rate,100.0*(f_clock_drift-1.0));
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_fwd), label_max);
|
||||
gtk_label_set_selectable (GTK_LABEL(user_data->dlg.label_stats_fwd),TRUE);
|
||||
|
||||
g_snprintf(label_max, sizeof(label_max), "Max delta = %.2f ms at packet no. %u \n"
|
||||
"Max jitter = %.2f ms. Mean jitter = %.2f ms.\n"
|
||||
"Total RTP packets = %u (expected %u) Lost RTP packets = %d (%.2f%%)"
|
||||
" Sequence errors = %u",
|
||||
user_data->forward.statinfo.max_delta, user_data->forward.statinfo.max_nr,
|
||||
user_data->forward.statinfo.max_jitter,user_data->forward.statinfo.mean_jitter,
|
||||
user_data->forward.statinfo.total_nr, f_expected, f_lost, f_perc,
|
||||
user_data->forward.statinfo.sequence);
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_fwd), label_max);
|
||||
|
||||
g_snprintf(label_max, sizeof(label_max), "Max delta = %f ms at packet no. %u \n"
|
||||
"Max jitter = %.2f ms. Mean jitter = %.2f ms.\n"
|
||||
"Total RTP packets = %u (expected %u) Lost RTP packets = %d (%.2f%%)"
|
||||
" Sequence errors = %u",
|
||||
" Sequence errors = %u \n"
|
||||
"Duration %.0f s (%.0f ms clock drift, corresponding to %.0f Hz (%+.2f%%)",
|
||||
user_data->reversed.statinfo.max_delta, user_data->reversed.statinfo.max_nr,
|
||||
user_data->reversed.statinfo.max_jitter,user_data->reversed.statinfo.mean_jitter,
|
||||
user_data->reversed.statinfo.total_nr, r_expected, r_lost, r_perc,
|
||||
user_data->reversed.statinfo.sequence);
|
||||
r_expected, r_expected, r_lost, r_perc,
|
||||
user_data->reversed.statinfo.sequence,
|
||||
r_duration/1000,r_duration*(r_clock_drift-1.0),r_clock_drift*r_clock_rate,100.0*(r_clock_drift-1.0));
|
||||
|
||||
gtk_label_set_text(GTK_LABEL(user_data->dlg.label_stats_rev), label_max);
|
||||
gtk_label_set_selectable (GTK_LABEL(user_data->dlg.label_stats_rev),TRUE);
|
||||
|
||||
return ;
|
||||
}
|
||||
|
@ -2934,7 +2978,7 @@ static void draw_stat(user_data_t *user_data)
|
|||
/****************************************************************************/
|
||||
/* append a line to list */
|
||||
static void add_to_list(GtkWidget *list, user_data_t * user_data, guint32 number, guint16 seq_num,
|
||||
double delta, double jitter, double bandwidth, gchar *status, gboolean marker,
|
||||
double delta, double jitter,double skew, double bandwidth, gchar *status, gboolean marker,
|
||||
gchar *timeStr, guint32 pkt_len, gchar *color_str, guint32 flags)
|
||||
{
|
||||
GtkListStore *list_store;
|
||||
|
@ -2961,6 +3005,7 @@ static void add_to_list(GtkWidget *list, user_data_t * user_data, guint32 number
|
|||
SEQUENCE_COLUMN, seq_num,
|
||||
DELTA_COLUMN, delta,
|
||||
JITTER_COLUMN, jitter,
|
||||
SKEW_COLUMN, skew,
|
||||
IPBW_COLUMN, bandwidth,
|
||||
MARKER_COLUMN, marker,
|
||||
STATUS_COLUMN, (char *)status,
|
||||
|
@ -3026,6 +3071,7 @@ GtkWidget* create_list(user_data_t* user_data)
|
|||
G_TYPE_UINT, /* Sequence */
|
||||
G_TYPE_FLOAT, /* Delta(ms) */
|
||||
G_TYPE_FLOAT, /* Filtered Jitter(ms) */
|
||||
G_TYPE_FLOAT, /* Skew(ms) */
|
||||
G_TYPE_FLOAT, /* IP BW(kbps) */
|
||||
G_TYPE_BOOLEAN, /* Marker */
|
||||
G_TYPE_STRING, /* Status */
|
||||
|
@ -3117,6 +3163,23 @@ GtkWidget* create_list(user_data_t* user_data)
|
|||
gtk_tree_view_column_set_min_width(column, 110);
|
||||
gtk_tree_view_append_column (list_view, column);
|
||||
|
||||
/* Skew(ms). */
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes ("Skew(ms)", renderer,
|
||||
"text", SKEW_COLUMN,
|
||||
"foreground", FOREGROUND_COLOR_COL,
|
||||
"background", BACKGROUND_COLOR_COL,
|
||||
NULL);
|
||||
|
||||
gtk_tree_view_column_set_cell_data_func(column, renderer, float_data_func,
|
||||
GINT_TO_POINTER(SKEW_COLUMN), NULL);
|
||||
|
||||
gtk_tree_view_column_set_sort_column_id(column, SKEW_COLUMN);
|
||||
gtk_tree_view_column_set_resizable(column, TRUE);
|
||||
gtk_tree_view_column_set_sizing(column, GTK_TREE_VIEW_COLUMN_FIXED);
|
||||
gtk_tree_view_column_set_min_width(column, 110);
|
||||
gtk_tree_view_append_column (list_view, column);
|
||||
|
||||
/* IP BW(kbps). */
|
||||
renderer = gtk_cell_renderer_text_new ();
|
||||
column = gtk_tree_view_column_new_with_attributes ("IP BW(kbps)", renderer,
|
||||
|
|
|
@ -71,19 +71,28 @@ typedef struct _tap_rtp_stat_t {
|
|||
guint32 flags; /* see STAT_FLAG-defines below */
|
||||
guint16 seq_num;
|
||||
guint32 timestamp;
|
||||
guint32 first_timestamp;
|
||||
guint32 delta_timestamp;
|
||||
double bandwidth;
|
||||
bw_history_item bw_history[BUFF_BW];
|
||||
guint16 bw_start_index;
|
||||
guint16 bw_index;
|
||||
guint32 total_bytes;
|
||||
guint32 clock_rate;
|
||||
double delta;
|
||||
double jitter;
|
||||
double diff;
|
||||
double time;
|
||||
double skew;
|
||||
double sumt;
|
||||
double sumTS;
|
||||
double sumt2;
|
||||
double sumtTS;
|
||||
double time; /* Unit is ms */
|
||||
double start_time;
|
||||
double lastnominaltime;
|
||||
double max_delta;
|
||||
double max_jitter;
|
||||
double max_skew;
|
||||
double mean_jitter;
|
||||
guint32 max_nr;
|
||||
guint16 start_seq_nr;
|
||||
|
|
123
tap-rtp-common.c
123
tap-rtp-common.c
|
@ -357,7 +357,7 @@ get_clock_rate(guint32 key)
|
|||
if (clock_map[i].key == key)
|
||||
return clock_map[i].value;
|
||||
}
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct _mimetype_and_clock {
|
||||
|
@ -399,7 +399,7 @@ static const mimetype_and_clock mimetype_and_clock_map[] = {
|
|||
{"GSM-EFR", 8000}, /* [RFC3551] */
|
||||
{"H263-1998", 90000}, /* [RFC2429],[RFC3555] */
|
||||
{"H263-2000", 90000}, /* [RFC2429],[RFC3555] */
|
||||
{"H264", 90000}, /* [RFC3984] */
|
||||
{"H264", 90000}, /* [RFC3984] */
|
||||
{"MP1S", 90000}, /* [RFC2250],[RFC3555] */
|
||||
{"MP2P", 90000}, /* [RFC2250],[RFC3555] */
|
||||
{"MP4V-ES", 90000}, /* [RFC3016] */
|
||||
|
@ -427,7 +427,7 @@ get_dyn_pt_clock_rate(gchar *payload_type_str)
|
|||
return mimetype_and_clock_map[i].value;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
@ -438,9 +438,46 @@ int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
|
|||
double current_time;
|
||||
double current_jitter;
|
||||
double current_diff;
|
||||
double nominaltime;
|
||||
double arrivaltime; /* Time relative to start_time */
|
||||
double expected_time;
|
||||
double absskew;
|
||||
guint32 clock_rate;
|
||||
|
||||
/* Store the current time */
|
||||
current_time = nstime_to_msec(&pinfo->fd->rel_ts);
|
||||
|
||||
/* Is this the first packet we got in this direction? */
|
||||
if (statinfo->first_packet) {
|
||||
statinfo->start_seq_nr = rtpinfo->info_seq_num;
|
||||
statinfo->stop_seq_nr = rtpinfo->info_seq_num;
|
||||
statinfo->seq_num = rtpinfo->info_seq_num;
|
||||
statinfo->start_time = current_time;
|
||||
statinfo->timestamp = rtpinfo->info_timestamp;
|
||||
statinfo->first_timestamp = rtpinfo->info_timestamp;
|
||||
statinfo->time = current_time;
|
||||
statinfo->pt = rtpinfo->info_payload_type;
|
||||
statinfo->reg_pt = rtpinfo->info_payload_type;
|
||||
statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
|
||||
statinfo->bw_history[statinfo->bw_index].time = current_time;
|
||||
statinfo->bw_index++;
|
||||
statinfo->total_bytes += rtpinfo->info_data_len + 28;
|
||||
statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000;
|
||||
/* Not needed ? initialised to zero? */
|
||||
statinfo->delta = 0;
|
||||
statinfo->jitter = 0;
|
||||
statinfo->diff = 0;
|
||||
|
||||
statinfo->total_nr++;
|
||||
statinfo->flags |= STAT_FLAG_FIRST;
|
||||
if (rtpinfo->info_marker_set) {
|
||||
statinfo->flags |= STAT_FLAG_MARKER;
|
||||
}
|
||||
statinfo->first_packet = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Reset flags */
|
||||
statinfo->flags = 0;
|
||||
|
||||
/* check payload type */
|
||||
|
@ -453,10 +490,10 @@ int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
|
|||
if (rtpinfo->info_payload_type != statinfo->pt)
|
||||
statinfo->flags |= STAT_FLAG_PT_CHANGE;
|
||||
statinfo->pt = rtpinfo->info_payload_type;
|
||||
|
||||
/*
|
||||
* XXX - should "get_clock_rate()" return 0 for unknown
|
||||
* payload types, presumably meaning that we should
|
||||
* just ignore this packet?
|
||||
* Return 0 for unknown payload types
|
||||
* Ignore jitter calculation for clockrate = 0
|
||||
*/
|
||||
if (statinfo->pt < 96 ){
|
||||
clock_rate = get_clock_rate(statinfo->pt);
|
||||
|
@ -464,23 +501,67 @@ int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
|
|||
if ( rtpinfo->info_payload_type_str != NULL )
|
||||
clock_rate = get_dyn_pt_clock_rate(rtpinfo-> info_payload_type_str);
|
||||
else
|
||||
clock_rate = 1;
|
||||
clock_rate = 0;
|
||||
}
|
||||
|
||||
/* Store the current time and calculate the current jitter(in ms) */
|
||||
current_time = nstime_to_msec(&pinfo->fd->rel_ts);
|
||||
/* Expected time is last arrival time + the timestamp difference divided by the sampling clock( /1000 to get ms) */
|
||||
expected_time = statinfo->time + ((double)(rtpinfo->info_timestamp)-(double)(statinfo->timestamp))/(clock_rate/1000);
|
||||
current_diff = fabs(current_time - expected_time);
|
||||
current_jitter = (15 * statinfo->jitter + current_diff) / 16;
|
||||
/* Handle wraparound ? */
|
||||
arrivaltime = current_time - statinfo->start_time;
|
||||
|
||||
statinfo->delta = current_time-(statinfo->time);
|
||||
statinfo->jitter = current_jitter;
|
||||
statinfo->diff = current_diff;
|
||||
if (statinfo->first_timestamp > rtpinfo->info_timestamp){
|
||||
/* Handle wraparound */
|
||||
nominaltime = (double)(rtpinfo->info_timestamp + 0xffffffff - statinfo->first_timestamp + 1);
|
||||
}else{
|
||||
nominaltime = (double)(rtpinfo->info_timestamp - statinfo->first_timestamp);
|
||||
}
|
||||
|
||||
/* Can only analyze defined sampling rates */
|
||||
if (clock_rate != 0) {
|
||||
statinfo->clock_rate = clock_rate;
|
||||
/* Convert from sampling clock to ms */
|
||||
nominaltime = nominaltime /(clock_rate/1000);
|
||||
|
||||
/* Calculate the current jitter(in ms) */
|
||||
if (!statinfo->first_packet) {
|
||||
expected_time = statinfo->time + (nominaltime - statinfo->lastnominaltime);
|
||||
current_diff = fabs(current_time - expected_time);
|
||||
current_jitter = (15 * statinfo->jitter + current_diff) / 16;
|
||||
|
||||
statinfo->delta = current_time-(statinfo->time);
|
||||
statinfo->jitter = current_jitter;
|
||||
statinfo->diff = current_diff;
|
||||
}
|
||||
statinfo->lastnominaltime = nominaltime;
|
||||
/* Calculate skew, i.e. absolute jitter that also catches clock drift
|
||||
* Skew is positive if TS (nominal) is too fast
|
||||
*/
|
||||
statinfo->skew = nominaltime - arrivaltime;
|
||||
absskew = fabs(statinfo->skew);
|
||||
if(absskew > fabs(statinfo->max_skew)){
|
||||
statinfo->max_skew = statinfo->skew;
|
||||
}
|
||||
/* Gather data for calculation of average, minimum and maximum framerate based on timestamp */
|
||||
#if 0
|
||||
if (numPackets > 0 && (!hardPayloadType || !alternatePayloadType)) {
|
||||
/* Skip first packet and possibly alternate payload type packets */
|
||||
double dt;
|
||||
dt = nominaltime - statinfo->lastnominaltime;
|
||||
sumdt += 1.0 * dt;
|
||||
numdt += (dt != 0 ? 1 : 0);
|
||||
mindt = (dt < mindt ? dt : mindt);
|
||||
maxdt = (dt > maxdt ? dt : maxdt);
|
||||
}
|
||||
#endif
|
||||
/* Gather data for calculation of skew least square */
|
||||
statinfo->sumt += 1.0 * current_time;
|
||||
statinfo->sumTS += 1.0 * nominaltime;
|
||||
statinfo->sumt2 += 1.0 * current_time * current_time;
|
||||
statinfo->sumtTS += 1.0 * current_time * nominaltime;
|
||||
}
|
||||
|
||||
/* calculate the BW in Kbps adding the IP+UDP header to the RTP -> 20bytes(IP)+8bytes(UDP) = 28bytes */
|
||||
statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
|
||||
statinfo->bw_history[statinfo->bw_index].time = current_time;
|
||||
|
||||
/* check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */
|
||||
while ((statinfo->bw_history[statinfo->bw_start_index].time+1000/* ms */)<current_time){
|
||||
statinfo->total_bytes -= statinfo->bw_history[statinfo->bw_start_index].bytes;
|
||||
|
@ -524,11 +605,13 @@ int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
|
|||
statinfo->max_delta = statinfo->delta;
|
||||
statinfo->max_nr = pinfo->fd->num;
|
||||
}
|
||||
/* maximum and mean jitter calculation */
|
||||
if (statinfo->jitter > statinfo->max_jitter) {
|
||||
statinfo->max_jitter = statinfo->jitter;
|
||||
if (clock_rate != 0) {
|
||||
/* maximum and mean jitter calculation */
|
||||
if (statinfo->jitter > statinfo->max_jitter) {
|
||||
statinfo->max_jitter = statinfo->jitter;
|
||||
}
|
||||
statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
|
||||
}
|
||||
statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
|
||||
}
|
||||
/* regular payload change? (CN ignored) */
|
||||
if (!(statinfo->flags & STAT_FLAG_FIRST)
|
||||
|
|
Loading…
Reference in New Issue