Huge thanks to our Platinum Members Endace and LiveAction,
and our Silver Member Veeam, for supporting the Wireshark Foundation and project.

Ethereal-dev: [Ethereal-dev] [PATCH] New columns for RTP streams

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: "Lars Ruoff" <Lars.Ruoff@xxxxxxxxxx>
Date: Mon, 14 Feb 2005 08:52:00 +0100
Hi,

please consider applying the attached patches to RTP streams/analysis:
I've added columns for Lost packets, maximum delta, maximum jitter and mean
jitter to the RTP streams dialog box.
That means that these values are calculated for each RTP stream using the
rtp_packet_analyse function from rtp_analysis. That function has been
extended and made global for that reason.
PS: Added a column "PB?" that will show "X" for streams that have
encountered sequencing- or timestamp-problems.

The attached file is the relevant output of "svn diff ethereal".
Is that ok?

regards,
Lars Ruoff.
Index: ethereal/gtk/rtp_stream_dlg.c
===================================================================
--- ethereal/gtk/rtp_stream_dlg.c	(Revision 13391)
+++ ethereal/gtk/rtp_stream_dlg.c	(Arbeitskopie)
@@ -72,14 +72,19 @@
 
 static guint32 streams_nb = 0;     /* number of displayed streams */
 
+#define NUM_COLS 12
+
 /****************************************************************************/
 /* append a line to clist */
 static void add_to_clist(rtp_stream_info_t* strinfo)
 {
 	gchar label_text[256];
 	gint added_row;
-	gchar *data[8];
-	gchar field[8][30];
+	gchar *data[NUM_COLS];
+	gchar field[NUM_COLS][30];
+	guint32 expected;
+	gint32 lost;
+	double perc;
 
 	data[0]=&field[0][0];
 	data[1]=&field[1][0];
@@ -89,6 +94,10 @@
 	data[5]=&field[5][0];
 	data[6]=&field[6][0];
 	data[7]=&field[7][0];
+	data[8]=&field[8][0];
+	data[9]=&field[9][0];
+	data[10]=&field[10][0];
+	data[11]=&field[11][0];
 
 	g_snprintf(field[0], 20, "%s", address_to_str_w_none(&(strinfo->src_addr)));
 	g_snprintf(field[1], 20, "%u", strinfo->src_port);
@@ -98,9 +107,24 @@
 	g_snprintf(field[5], 30, "%s", val_to_str(strinfo->pt, rtp_payload_type_vals,
 		"Unknown (%u)"));
 	g_snprintf(field[6], 20, "%u", strinfo->npackets);
-	/* XXX: Comment field is not used for the moment */
-/*	g_snprintf(field[7], 20, "%s", "");*/
 
+	expected = (strinfo->rtp_stats.stop_seq_nr + strinfo->rtp_stats.cycles*65536)
+		- strinfo->rtp_stats.start_seq_nr + 1;
+	lost = expected - strinfo->rtp_stats.total_nr;
+	if (expected){
+		perc = (double)(lost*100)/(double)expected;
+	} else {
+		perc = 0;
+	}
+	g_snprintf(field[7], 20, "%d (%.1f%%)", lost, perc);
+	g_snprintf(field[8], 20, "%.2f", strinfo->rtp_stats.max_delta*1000);
+	g_snprintf(field[9], 20, "%.2f", strinfo->rtp_stats.max_jitter*1000);
+	g_snprintf(field[10], 20, "%.2f", strinfo->rtp_stats.mean_jitter*1000);
+	if (strinfo->problem)
+		g_snprintf(field[11], 20, "X");
+	else
+		g_snprintf(field[11], 20, "");
+
 	added_row = gtk_clist_append(GTK_CLIST(clist), data);
 
 	/* set data pointer of last row to point to user data for that row */
@@ -491,8 +515,6 @@
 
 
 /****************************************************************************/
-#define NUM_COLS 7
-
 typedef struct column_arrows {
 	GtkWidget *table;
 	GtkWidget *ascend_pm;
@@ -551,12 +573,16 @@
 	case 0:
 	case 2:
 	case 5:
-	case 7:
+	case 11:
 		return strcmp (text1, text2);
 	case 1:
 	case 3:
 	case 4:
 	case 6:
+	case 7:
+	case 8:
+	case 9:
+	case 10:
 		i1=atoi(text1);
 		i2=atoi(text2);
 		return i1-i2;
@@ -586,7 +612,7 @@
 	GtkWidget *bt_close;
     GtkTooltips *tooltips = gtk_tooltips_new();
 
-	gchar *titles[8] =  {"Src IP addr", "Src port",  "Dest IP addr", "Dest port", "SSRC", "Payload", "Packets", "Comment"};
+	gchar *titles[NUM_COLS] =  {"Src IP addr", "Src port",  "Dest IP addr", "Dest port", "SSRC", "Payload", "Packets", "Lost", "Max Delta (ms)", "Max Jitter (ms)", "Mean Jitter (ms)", "Pb?"};
 	column_arrows *col_arrows;
 	GtkWidget *column_lb;
 	int i;
@@ -607,14 +633,18 @@
 	clist = gtk_clist_new (NUM_COLS);
 	gtk_container_add (GTK_CONTAINER (scrolledwindow), clist);
 
-	gtk_clist_set_column_width (GTK_CLIST (clist), 0, 100);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 1, 50);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 2, 100);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 3, 50);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 4, 80);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 5, 118);
-	gtk_clist_set_column_width (GTK_CLIST (clist), 6, 40);
-/*	gtk_clist_set_column_width (GTK_CLIST (clist), 7, 51);*/
+	gtk_clist_set_column_width (GTK_CLIST (clist), 0, 88);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 1, 44);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 2, 88);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 3, 44);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 4, 64);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 5, 96);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 6, 50);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 7, 50);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 8, 80);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 9, 80);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 10, 80);
+	gtk_clist_set_column_width (GTK_CLIST (clist), 11, 40);
 
 	gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
 	gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
@@ -623,7 +653,11 @@
 	gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
 	gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_LEFT);
 	gtk_clist_set_column_justification(GTK_CLIST(clist), 6, GTK_JUSTIFY_RIGHT);
-/*	gtk_clist_set_column_justification(GTK_CLIST(clist), 7, GTK_JUSTIFY_CENTER);*/
+	gtk_clist_set_column_justification(GTK_CLIST(clist), 7, GTK_JUSTIFY_RIGHT);
+	gtk_clist_set_column_justification(GTK_CLIST(clist), 8, GTK_JUSTIFY_RIGHT);
+	gtk_clist_set_column_justification(GTK_CLIST(clist), 9, GTK_JUSTIFY_RIGHT);
+	gtk_clist_set_column_justification(GTK_CLIST(clist), 10, GTK_JUSTIFY_RIGHT);
+	gtk_clist_set_column_justification(GTK_CLIST(clist), 11, GTK_JUSTIFY_LEFT);
 
 	gtk_clist_column_titles_show (GTK_CLIST (clist));
 
Index: ethereal/gtk/rtp_stream.c
===================================================================
--- ethereal/gtk/rtp_stream.c	(Revision 13391)
+++ ethereal/gtk/rtp_stream.c	(Arbeitskopie)
@@ -245,9 +245,33 @@
 			tmp_strinfo.tag_vlan_error = 0;
 			tmp_strinfo.tag_diffserv_error = 0;
 			tmp_strinfo.vlan_id = 0;
-			
+			tmp_strinfo.problem = FALSE;
+
+			/* reset RTP stats */
+			tmp_strinfo.rtp_stats.first_packet = TRUE;
+			tmp_strinfo.rtp_stats.max_delta = 0;
+			tmp_strinfo.rtp_stats.max_jitter = 0;
+			tmp_strinfo.rtp_stats.mean_jitter = 0;
+			tmp_strinfo.rtp_stats.delta = 0;
+			tmp_strinfo.rtp_stats.diff = 0;
+			tmp_strinfo.rtp_stats.jitter = 0;
+			tmp_strinfo.rtp_stats.bandwidth = 0;
+			tmp_strinfo.rtp_stats.total_bytes = 0;
+			tmp_strinfo.rtp_stats.bw_start_index = 0;
+			tmp_strinfo.rtp_stats.bw_index = 0;
+			tmp_strinfo.rtp_stats.timestamp = 0;
+			tmp_strinfo.rtp_stats.max_nr = 0;
+			tmp_strinfo.rtp_stats.total_nr = 0;
+			tmp_strinfo.rtp_stats.sequence = 0;
+			tmp_strinfo.rtp_stats.start_seq_nr = 0;
+			tmp_strinfo.rtp_stats.stop_seq_nr = 0;
+			tmp_strinfo.rtp_stats.cycles = 0;
+			tmp_strinfo.rtp_stats.under = FALSE;
+			tmp_strinfo.rtp_stats.start_time = 0;
+			tmp_strinfo.rtp_stats.time = 0;
+			tmp_strinfo.rtp_stats.reg_pt = PT_UNDEFINED;
+
             /* Get the Setup frame number who set this RTP stream */
-
             p_conv_data = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name("rtp"));
             if (p_conv_data)
 				tmp_strinfo.setup_frame_number = p_conv_data->frame_number;
@@ -259,6 +283,13 @@
 			tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
 		}
 
+		/* get RTP stats for the packet */
+		rtp_packet_analyse(&(strinfo->rtp_stats), pinfo, rtpinfo);
+		if (strinfo->rtp_stats.flags & STAT_FLAG_WRONG_TIMESTAMP
+			|| strinfo->rtp_stats.flags & STAT_FLAG_WRONG_SEQ)
+			strinfo->problem = TRUE;
+
+
 		/* increment the packets counter for this stream */
 		++(strinfo->npackets);
 		strinfo->stop_rel_sec = pinfo->fd->rel_secs;
Index: ethereal/gtk/rtp_stream.h
===================================================================
--- ethereal/gtk/rtp_stream.h	(Revision 13391)
+++ ethereal/gtk/rtp_stream.h	(Arbeitskopie)
@@ -28,6 +28,7 @@
 #ifndef RTP_STREAM_H_INCLUDED
 #define RTP_STREAM_H_INCLUDED
 
+#include "rtp_analysis.h"
 #include <glib.h>
 #include <stdio.h>
 #include <epan/address.h>
@@ -77,6 +78,8 @@
 	gboolean tag_diffserv_error;
 	guint16 vlan_id;
 
+	tap_rtp_stat_t rtp_stats;  /* here goes the RTP statistics info */
+	gboolean problem; /* if the streams had wrong sequence numbers or wrong timerstamps */
 } rtp_stream_info_t;
 
 
Index: ethereal/gtk/rtp_analysis.c
===================================================================
--- ethereal/gtk/rtp_analysis.c	(Revision 13391)
+++ ethereal/gtk/rtp_analysis.c	(Arbeitskopie)
@@ -181,9 +181,7 @@
 } dialog_data_t;
 
 #define OK_TEXT "[ Ok ]"
-#define PT_UNDEFINED -1
 
-
 typedef struct _key_value {
   guint32  key;
   guint32  value;
@@ -253,54 +251,6 @@
 GdkColormap *colormap;
 #endif
 
-/****************************************************************************/
-/* structure that holds the information about the forward and reversed direction */
-typedef struct _bw_history_item {
-        double time;
-        guint32 bytes;
-} bw_history_item;
-#define BUFF_BW 300 
-typedef struct _tap_rtp_stat_t {
-	gboolean first_packet;     /* do not use in code that is called after rtp_packet_analyse */
-	                           /* use (flags & STAT_FLAG_FIRST) instead */
-	/* all of the following fields will be initialized after
-	 rtp_packet_analyse has been called */
-	guint32 flags;             /* see STAT_FLAG-defines below */
-	guint16 seq_num;
-	guint32 timestamp;
-	guint32 delta_timestamp;
-	double bandwidth;
-	bw_history_item bw_history[BUFF_BW];
-	guint16 bw_start_index;
-	guint16 bw_index;
-	guint32 total_bytes;
-	double delta;
-	double jitter;
-	double diff;
-	double time;
-	double start_time;
-	double max_delta;
-	guint32 max_nr;
-	guint16 start_seq_nr;
-	guint16 stop_seq_nr;
-	guint32 total_nr;
-	guint32 sequence;
-	gboolean under;
-	gint cycles;
-	guint16 pt;
-	int reg_pt;
-} tap_rtp_stat_t;
-
-/* status flags for the flags parameter in tap_rtp_stat_t */
-#define STAT_FLAG_FIRST       0x01
-#define STAT_FLAG_MARKER      0x02
-#define STAT_FLAG_WRONG_SEQ   0x04
-#define STAT_FLAG_PT_CHANGE   0x08
-#define STAT_FLAG_PT_CN       0x10
-#define STAT_FLAG_FOLLOW_PT_CN  0x20
-#define STAT_FLAG_REG_PT_CHANGE  0x40
-#define STAT_FLAG_WRONG_TIMESTAMP  0x80
-
 typedef struct _tap_rtp_save_info_t {
 	FILE *fp;
 	guint32 count;
@@ -388,6 +338,10 @@
 	user_data->reversed.statinfo.first_packet = TRUE;
 	user_data->forward.statinfo.max_delta = 0;
 	user_data->reversed.statinfo.max_delta = 0;
+	user_data->forward.statinfo.max_jitter = 0;
+	user_data->reversed.statinfo.max_jitter = 0;
+	user_data->forward.statinfo.mean_jitter = 0;
+	user_data->reversed.statinfo.mean_jitter = 0;
 	user_data->forward.statinfo.delta = 0;
 	user_data->reversed.statinfo.delta = 0;
         user_data->forward.statinfo.diff = 0;
@@ -530,12 +484,10 @@
                          double delta, double jitter, double bandwidth, gchar *status, gboolean marker,
                          gchar *timeStr, guint32 pkt_len, GdkColor *color);
 
-static int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
-                              packet_info *pinfo,
-                              const struct _rtp_info *rtpinfo);
 static int rtp_packet_add_info(GtkCList *clist,
 	tap_rtp_stat_t *statinfo, packet_info *pinfo,
 	const struct _rtp_info *rtpinfo);
+
 static int rtp_packet_save_payload(tap_rtp_save_info_t *saveinfo, 
                                    tap_rtp_stat_t *statinfo,
                                    packet_info *pinfo,
@@ -593,7 +545,7 @@
 
 
 /****************************************************************************/
-static int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
+int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
                               packet_info *pinfo,
                               const struct _rtp_info *rtpinfo)
 {
@@ -674,6 +626,11 @@
 			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;
+		}
+		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)
Index: ethereal/gtk/rtp_analysis.h
===================================================================
--- ethereal/gtk/rtp_analysis.h	(Revision 13391)
+++ ethereal/gtk/rtp_analysis.h	(Arbeitskopie)
@@ -34,6 +34,7 @@
 
 #include <glib.h>
 #include <epan/address.h>
+#include <epan/packet_info.h>
 
 /** @file
  *  ??? 
@@ -53,5 +54,67 @@
 		guint32 ssrc_rev
 		);
 
+/****************************************************************************/
+/* structure that holds the information about the forward and reversed direction */
+typedef struct _bw_history_item {
+        double time;
+        guint32 bytes;
+} bw_history_item;
 
+#define BUFF_BW 300 
+
+typedef struct _tap_rtp_stat_t {
+	gboolean first_packet;     /* do not use in code that is called after rtp_packet_analyse */
+	                           /* use (flags & STAT_FLAG_FIRST) instead */
+	/* all of the following fields will be initialized after
+	 rtp_packet_analyse has been called */
+	guint32 flags;             /* see STAT_FLAG-defines below */
+	guint16 seq_num;
+	guint32 timestamp;
+	guint32 delta_timestamp;
+	double bandwidth;
+	bw_history_item bw_history[BUFF_BW];
+	guint16 bw_start_index;
+	guint16 bw_index;
+	guint32 total_bytes;
+	double delta;
+	double jitter;
+	double diff;
+	double time;
+	double start_time;
+	double max_delta;
+	double max_jitter;
+	double mean_jitter;
+	guint32 max_nr;
+	guint16 start_seq_nr;
+	guint16 stop_seq_nr;
+	guint32 total_nr;
+	guint32 sequence;
+	gboolean under;
+	gint cycles;
+	guint16 pt;
+	int reg_pt;
+} tap_rtp_stat_t;
+
+#define PT_UNDEFINED -1
+
+/* status flags for the flags parameter in tap_rtp_stat_t */
+#define STAT_FLAG_FIRST       0x01
+#define STAT_FLAG_MARKER      0x02
+#define STAT_FLAG_WRONG_SEQ   0x04
+#define STAT_FLAG_PT_CHANGE   0x08
+#define STAT_FLAG_PT_CN       0x10
+#define STAT_FLAG_FOLLOW_PT_CN  0x20
+#define STAT_FLAG_REG_PT_CHANGE  0x40
+#define STAT_FLAG_WRONG_TIMESTAMP  0x80
+
+/* forward */
+struct _rtp_info;
+
+/* function for analysing an RTP packet. Called from rtp_analysis and rtp_streams */
+extern int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
+        packet_info *pinfo,
+        const struct _rtp_info *rtpinfo);
+
+
 #endif /*RTP_ANALYSIS_H_INCLUDED*/