From Miha Jemec :
authorsahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 6 Mar 2003 20:35:12 +0000 (20:35 +0000)
committersahlberg <sahlberg@f5534014-38df-0310-8fa8-9805f1628bb7>
Thu, 6 Mar 2003 20:35:12 +0000 (20:35 +0000)
Functionality to reassemble a RTP stream and save it as a file.
Support for G.711 coded

git-svn-id: http://anonsvn.wireshark.org/wireshark/trunk@7297 f5534014-38df-0310-8fa8-9805f1628bb7

12 files changed:
AUTHORS
Makefile.am
Makefile.nmake
g711.c [new file with mode: 0644]
g711.h [new file with mode: 0644]
gtk/Makefile.am
gtk/Makefile.nmake
gtk/menu.c
gtk/tap_rtp.c [new file with mode: 0644]
gtk/tap_rtp.h [new file with mode: 0644]
packet-rtp.c
packet-rtp.h

diff --git a/AUTHORS b/AUTHORS
index fd2e5979eb0c324d41f840bd044fe6dab2ea1489..a8f6bfeb28ee2fd4882a2e92938bb0c629111d40 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1635,6 +1635,11 @@ Lars Ronald <Lars.Roland [AT] gmx.net> {
        MGCP request/response matching and MGCPSTAT calculation
 }
 
+Miha Jemec <m.jemec [AT] iskratel.si> {
+       Support to follow a RTP stream and save it as a file.
+       Support for G.711 codec
+}
+
 And assorted fixes and enhancements by the people listed above and by:
 
        Pavel Roskin <proski [AT] gnu.org>
index 81afca8c94364b5e9f624a09cbe557b58f7891bb..6d8f36dad31219f8875890dfde0a683f0f4b616d 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for Ethereal
 #
-# $Id: Makefile.am,v 1.565 2003/03/06 09:01:40 sahlberg Exp $
+# $Id: Makefile.am,v 1.566 2003/03/06 20:35:09 sahlberg Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@ethereal.com>
@@ -678,6 +678,8 @@ ETHEREAL_COMMON_SRC = \
        follow.c       \
        follow.h       \
        format-oid.h   \
+       g711.c          \
+       g711.h          \
        greproto.h     \
        in_cksum.c     \
        in_cksum.h     \
index 7fabd50fb92d5d2fa2fd950e4581f728f3bf68dc..0bc96d81e0a3df2da3230bfc73526a4d4d030f26 100644 (file)
@@ -1,7 +1,7 @@
 ## Makefile for building ethereal.exe with Microsoft C and nmake
 ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
 #
-# $Id: Makefile.nmake,v 1.285 2003/03/06 09:01:40 sahlberg Exp $
+# $Id: Makefile.nmake,v 1.286 2003/03/06 20:35:09 sahlberg Exp $
 
 include config.nmake
 include <win32.mak>
@@ -379,6 +379,7 @@ ETHEREAL_COMMON_OBJECTS = \
        crypt-md5.obj    \
        crypt-rc4.obj    \
        follow.obj       \
+       g711.obj        \
        getopt.obj       \
        in_cksum.obj     \
        ipproto.obj      \
diff --git a/g711.c b/g711.c
new file mode 100644 (file)
index 0000000..a5f4679
--- /dev/null
+++ b/g711.c
@@ -0,0 +1,283 @@
+/*\r
+ * This source code is a product of Sun Microsystems, Inc. and is provided\r
+ * for unrestricted use.  Users may copy or modify this source code without\r
+ * charge.\r
+ *\r
+ * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING\r
+ * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.\r
+ *\r
+ * Sun source code is provided with no support and without any obligation on\r
+ * the part of Sun Microsystems, Inc. to assist in its use, correction,\r
+ * modification or enhancement.\r
+ *\r
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE\r
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE\r
+ * OR ANY PART THEREOF.\r
+ *\r
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue\r
+ * or profits or other special, indirect and consequential damages, even if\r
+ * Sun has been advised of the possibility of such damages.\r
+ *\r
+ * Sun Microsystems, Inc.\r
+ * 2550 Garcia Avenue\r
+ * Mountain View, California  94043\r
+ */\r
+\r
+/*\r
+ * g711.c\r
+ *\r
+ * u-law, A-law and linear PCM conversions.\r
+ */\r
+#define        SIGN_BIT        (0x80)          /* Sign bit for a A-law byte. */\r
+#define        QUANT_MASK      (0xf)           /* Quantization field mask. */\r
+#define        NSEGS           (8)             /* Number of A-law segments. */\r
+#define        SEG_SHIFT       (4)             /* Left shift for segment number. */\r
+#define        SEG_MASK        (0x70)          /* Segment field mask. */\r
+\r
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,\r
+                           0xFFF, 0x1FFF, 0x3FFF, 0x7FFF};\r
+\r
+/* copy from CCITT G.711 specifications */\r
+unsigned char _u2a[128] = {                    /* u- to A-law conversions */\r
+       1,      1,      2,      2,      3,      3,      4,      4,\r
+       5,      5,      6,      6,      7,      7,      8,      8,\r
+       9,      10,     11,     12,     13,     14,     15,     16,\r
+       17,     18,     19,     20,     21,     22,     23,     24,\r
+       25,     27,     29,     31,     33,     34,     35,     36,\r
+       37,     38,     39,     40,     41,     42,     43,     44,\r
+       46,     48,     49,     50,     51,     52,     53,     54,\r
+       55,     56,     57,     58,     59,     60,     61,     62,\r
+       64,     65,     66,     67,     68,     69,     70,     71,\r
+       72,     73,     74,     75,     76,     77,     78,     79,\r
+       81,     82,     83,     84,     85,     86,     87,     88,\r
+       89,     90,     91,     92,     93,     94,     95,     96,\r
+       97,     98,     99,     100,    101,    102,    103,    104,\r
+       105,    106,    107,    108,    109,    110,    111,    112,\r
+       113,    114,    115,    116,    117,    118,    119,    120,\r
+       121,    122,    123,    124,    125,    126,    127,    128};\r
+\r
+unsigned char _a2u[128] = {                    /* A- to u-law conversions */\r
+       1,      3,      5,      7,      9,      11,     13,     15,\r
+       16,     17,     18,     19,     20,     21,     22,     23,\r
+       24,     25,     26,     27,     28,     29,     30,     31,\r
+       32,     32,     33,     33,     34,     34,     35,     35,\r
+       36,     37,     38,     39,     40,     41,     42,     43,\r
+       44,     45,     46,     47,     48,     48,     49,     49,\r
+       50,     51,     52,     53,     54,     55,     56,     57,\r
+       58,     59,     60,     61,     62,     63,     64,     64,\r
+       65,     66,     67,     68,     69,     70,     71,     72,\r
+       73,     74,     75,     76,     77,     78,     79,     79,\r
+       80,     81,     82,     83,     84,     85,     86,     87,\r
+       88,     89,     90,     91,     92,     93,     94,     95,\r
+       96,     97,     98,     99,     100,    101,    102,    103,\r
+       104,    105,    106,    107,    108,    109,    110,    111,\r
+       112,    113,    114,    115,    116,    117,    118,    119,\r
+       120,    121,    122,    123,    124,    125,    126,    127};\r
+\r
+static int\r
+search(\r
+       int             val,\r
+       short           *table,\r
+       int             size)\r
+{\r
+       int             i;\r
+\r
+       for (i = 0; i < size; i++) {\r
+               if (val <= *table++)\r
+                       return (i);\r
+       }\r
+       return (size);\r
+}\r
+\r
+/*\r
+ * linear2alaw() - Convert a 16-bit linear PCM value to 8-bit A-law\r
+ *\r
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.\r
+ *\r
+ *             Linear Input Code       Compressed Code\r
+ *     ------------------------        ---------------\r
+ *     0000000wxyza                    000wxyz\r
+ *     0000001wxyza                    001wxyz\r
+ *     000001wxyzab                    010wxyz\r
+ *     00001wxyzabc                    011wxyz\r
+ *     0001wxyzabcd                    100wxyz\r
+ *     001wxyzabcde                    101wxyz\r
+ *     01wxyzabcdef                    110wxyz\r
+ *     1wxyzabcdefg                    111wxyz\r
+ *\r
+ * For further information see John C. Bellamy's Digital Telephony, 1982,\r
+ * John Wiley & Sons, pps 98-111 and 472-476.\r
+ */\r
+unsigned char\r
+linear2alaw(\r
+       int             pcm_val)        /* 2's complement (16-bit range) */\r
+{\r
+       int             mask;\r
+       int             seg;\r
+       unsigned char   aval;\r
+       if (pcm_val >= 0) {\r
+               mask = 0xD5;            /* sign (7th) bit = 1 */\r
+       } else {\r
+               mask = 0x55;            /* sign bit = 0 */\r
+               pcm_val = -pcm_val - 8;\r
+       }\r
+\r
+       /* Convert the scaled magnitude to segment number. */\r
+       seg = search(pcm_val, seg_end, 8);\r
+\r
+       /* Combine the sign, segment, and quantization bits. */\r
+\r
+       if (seg >= 8)           /* out of range, return maximum value. */\r
+               return (0x7F ^ mask);\r
+       else {\r
+               aval = seg << SEG_SHIFT;\r
+               if (seg < 2)\r
+                       aval |= (pcm_val >> 4) & QUANT_MASK;\r
+               else\r
+                       aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;\r
+               return (aval ^ mask);\r
+       }\r
+}\r
+\r
+/*\r
+ * alaw2linear() - Convert an A-law value to 16-bit linear PCM\r
+ *\r
+ */\r
+int\r
+alaw2linear(\r
+       unsigned char   a_val)\r
+{\r
+       int             t;\r
+       int             seg;\r
+       //printf(" vrednost a_val %X ", a_val);\r
+       a_val ^= 0x55;\r
+\r
+       t = (a_val & QUANT_MASK) << 4;\r
+       seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;\r
+       switch (seg) {\r
+       case 0:\r
+               t += 8;\r
+               break;\r
+       case 1:\r
+               t += 0x108;\r
+               break;\r
+       default:\r
+               t += 0x108;\r
+               t <<= seg - 1;\r
+       }\r
+       //printf("izracunan int %d in njegov hex %X \n", t,t);\r
+       return ((a_val & SIGN_BIT) ? t : -t);\r
+}\r
+\r
+#define        BIAS            (0x84)          /* Bias for linear code. */\r
+\r
+/*\r
+ * linear2ulaw() - Convert a linear PCM value to u-law\r
+ *\r
+ * In order to simplify the encoding process, the original linear magnitude\r
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to\r
+ * (33 - 8191). The result can be seen in the following encoding table:\r
+ *\r
+ *     Biased Linear Input Code        Compressed Code\r
+ *     ------------------------        ---------------\r
+ *     00000001wxyza                   000wxyz\r
+ *     0000001wxyzab                   001wxyz\r
+ *     000001wxyzabc                   010wxyz\r
+ *     00001wxyzabcd                   011wxyz\r
+ *     0001wxyzabcde                   100wxyz\r
+ *     001wxyzabcdef                   101wxyz\r
+ *     01wxyzabcdefg                   110wxyz\r
+ *     1wxyzabcdefgh                   111wxyz\r
+ *\r
+ * Each biased linear code has a leading 1 which identifies the segment\r
+ * number. The value of the segment number is equal to 7 minus the number\r
+ * of leading 0's. The quantization interval is directly available as the\r
+ * four bits wxyz.  * The trailing bits (a - h) are ignored.\r
+ *\r
+ * Ordinarily the complement of the resulting code word is used for\r
+ * transmission, and so the code word is complemented before it is returned.\r
+ *\r
+ * For further information see John C. Bellamy's Digital Telephony, 1982,\r
+ * John Wiley & Sons, pps 98-111 and 472-476.\r
+ */\r
+unsigned char\r
+linear2ulaw(\r
+       int             pcm_val)        /* 2's complement (16-bit range) */\r
+{\r
+       int             mask;\r
+       int             seg;\r
+       unsigned char   uval;\r
+\r
+       /* Get the sign and the magnitude of the value. */\r
+       if (pcm_val < 0) {\r
+               pcm_val = BIAS - pcm_val;\r
+               mask = 0x7F;\r
+       } else {\r
+               pcm_val += BIAS;\r
+               mask = 0xFF;\r
+       }\r
+\r
+       /* Convert the scaled magnitude to segment number. */\r
+       seg = search(pcm_val, seg_end, 8);\r
+\r
+       /*\r
+        * Combine the sign, segment, quantization bits;\r
+        * and complement the code word.\r
+        */\r
+       if (seg >= 8)           /* out of range, return maximum value. */\r
+               return (0x7F ^ mask);\r
+       else {\r
+               uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);\r
+               return (uval ^ mask);\r
+       }\r
+\r
+}\r
+\r
+/*\r
+ * ulaw2linear() - Convert a u-law value to 16-bit linear PCM\r
+ *\r
+ * First, a biased linear code is derived from the code word. An unbiased\r
+ * output can then be obtained by subtracting 33 from the biased code.\r
+ *\r
+ * Note that this function expects to be passed the complement of the\r
+ * original code word. This is in keeping with ISDN conventions.\r
+ */\r
+int\r
+ulaw2linear(\r
+       unsigned char   u_val)\r
+{\r
+       int             t;\r
+\r
+       /* Complement to obtain normal u-law value. */\r
+       u_val = ~u_val;\r
+\r
+       /*\r
+        * Extract and bias the quantization bits. Then\r
+        * shift up by the segment number and subtract out the bias.\r
+        */\r
+       t = ((u_val & QUANT_MASK) << 3) + BIAS;\r
+       t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;\r
+\r
+       return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));\r
+}\r
+\r
+/* A-law to u-law conversion */\r
+unsigned char\r
+alaw2ulaw(\r
+       unsigned char   aval)\r
+{\r
+       aval &= 0xff;\r
+       return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :\r
+           (0x7F ^ _a2u[aval ^ 0x55]));\r
+}\r
+\r
+/* u-law to A-law conversion */\r
+unsigned char\r
+ulaw2alaw(\r
+       unsigned char   uval)\r
+{\r
+       uval &= 0xff;\r
+       return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :\r
+           (0x55 ^ (_u2a[0x7F ^ uval] - 1)));\r
+}\r
diff --git a/g711.h b/g711.h
new file mode 100644 (file)
index 0000000..1c16824
--- /dev/null
+++ b/g711.h
@@ -0,0 +1,28 @@
+/* \r
+ * g711.h\r
+ *\r
+ * Definitions for routines for u-law, A-law and linear PCM conversions\r
+ *\r
+ * Ethereal - Network traffic analyzer\r
+ * By Gerald Combs <gerald@ethereal.com>\r
+ * Copyright 1998 Gerald Combs\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ */\r
+\r
+unsigned char linear2alaw( int );\r
+int alaw2linear( unsigned char );\r
+unsigned char linear2ulaw( int );\r
+int ulaw2linear( unsigned char ); \r
index 82f2116536c0820d6f37a79e2f26609ad381a134..99bd8d357c7690976f45f39824bf9d6d927ec26e 100644 (file)
@@ -1,7 +1,7 @@
 # Makefile.am
 # Automake file for the GTK interface routines for Ethereal
 #
-# $Id: Makefile.am,v 1.53 2003/01/22 00:40:36 sahlberg Exp $
+# $Id: Makefile.am,v 1.54 2003/03/06 20:35:12 sahlberg Exp $
 #
 # Ethereal - Network traffic analyzer
 # By Gerald Combs <gerald@ethereal.com>
@@ -37,7 +37,9 @@ ETHEREAL_TAP_SRC = \
        rpc_progs.c     \
        rpc_progs.h     \
        smb_stat.c      \
-       smb_stat.h
+       smb_stat.h      \
+       tap_rtp.c       \
+       tap_rtp.h
 
 ethereal-tap-register.c: $(ETHEREAL_TAP_SRC) $(top_srcdir)/make-tapreg-dotc
        @echo Making ethereal-tap-register.c
index 1cf9636c05497a8b669c8f4725f12c55ff8d71ef..1e43c56fe8240beafc922021b32b4d3ce8334b27 100644 (file)
@@ -1,7 +1,7 @@
 ## Makefile for building ethereal.exe with Microsoft C and nmake
 ## Use: $(MAKE) /$(MAKEFLAGS) -f makefile.nmake
 #
-# $Id: Makefile.nmake,v 1.40 2003/02/10 23:34:49 guy Exp $
+# $Id: Makefile.nmake,v 1.41 2003/03/06 20:35:12 sahlberg Exp $
 
 include ..\config.nmake
 
@@ -26,7 +26,8 @@ ETHEREAL_TAP_SRC = \
        io_stat.c       \
        rpc_stat.c      \
        rpc_progs.c     \
-       smb_stat.c
+       smb_stat.c      \
+       tap_rtp.c
 
 ETHEREAL_TAP_OBJECTS = $(ETHEREAL_TAP_SRC:.c=.obj)
 
index d7df085c2fcb32394a1bcb39424be65aa0a684d6..252ec5d8aaa43d71ab2aacbb0dac0a47ef569493 100644 (file)
@@ -1,7 +1,7 @@
 /* menu.c
  * Menu routines
  *
- * $Id: menu.c,v 1.83 2003/01/22 00:40:36 sahlberg Exp $
+ * $Id: menu.c,v 1.84 2003/03/06 20:35:12 sahlberg Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -64,6 +64,7 @@
 #include "smb_stat.h"
 #include "compat_macros.h"
 #include "gtkglobals.h"
+#include "tap_rtp.h"
 
 GtkWidget *popup_menu_object;
 
@@ -218,6 +219,8 @@ static GtkItemFactoryEntry menu_items[] =
                        0, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Tools/_Decode As...", NULL, decode_as_cb,
                        0, NULL, NULL),
+    ITEM_FACTORY_ENTRY("/Tools/_RTP analysis...", NULL, rtp_analyse_cb,
+                       0, NULL, NULL),
     ITEM_FACTORY_ENTRY("/Tools/_Go To Corresponding Frame", NULL, goto_framenum_cb,
                        0, NULL, NULL),
 /*  {"/Tools/Graph", NULL, NULL, 0, NULL}, future use */
diff --git a/gtk/tap_rtp.c b/gtk/tap_rtp.c
new file mode 100644 (file)
index 0000000..51a2942
--- /dev/null
@@ -0,0 +1,1997 @@
+/*\r
+ * tap_rtp.c\r
+ *\r
+ * RTP analysing addition  for ethereal\r
+ *\r
+ * Copyright 2003, Iskratel, Ltd, Kranj\r
+ * By Miha Jemec <m.jemec@iskratel.si>\r
+ *\r
+ * Ethereal - Network traffic analyzer\r
+ * By Gerald Combs <gerald@ethereal.com>\r
+ * Copyright 1998 Gerald Combs\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ *\r
+ * This tap works as follows:\r
+ * When the user clicks on the RTP analisys button, we first check if it is a RTP packet.\r
+ * If yes we store the SSRC, ip, and port values. Then the tap is registered and the \r
+ * redissect_packets() routine is called. So we go through all the RTP packets and search \r
+ * for SSRC of reversed connection (it has inversed socket parameters). If more than one \r
+ * is found a window is displayed where the user can select the appropriate from the list.\r
+ * Rigth now we have the information about the converstion we are looking for (both SSRC). \r
+ * The redissect_packets() routine is called again. This time whenever a RTP packet with\r
+ * matching SSRC values arrives, we store all the information we need (number, sequence\r
+ * number, arrival time, ...) and compute the delay, jitter and wrong sequence number.\r
+ * We add this values to CList. If the RTP packet carries voice in g711 alaw or ulaw, we\r
+ * also store this voice information in a temp file. Window is displayed.\r
+ * Then three buttons are available: Close, Refresh and Save voice.\r
+ * The Refresh button calls the redissect_packets() routine again. It goes through the packets\r
+ * again and does all the calculation again (if capturing in real time this means that some\r
+ * more packets could come and can be computed in statistic). It also writes the sound\r
+ * data again.\r
+ * The Save voice button opens the dialog where we can choose the file name, format (not yet)\r
+ * and direction we want to save. Currently it works only with g711 alaw and ulaw, and if the\r
+ * length of captured packets is equal the length of packets on wire and if there are no padding\r
+ * bits.    \r
+ *\r
+ * To do:\r
+ * - Support for saving voice in more different formats and with more different codecs:\r
+ *   Since this should be portable to all OS, there is only possibility to save the \r
+ *   voice in a file and not play it directly through the sound card. There are enough \r
+ *   players on all platforms, that are doing right this. What about the format? \r
+ *   Currently there is only support for saving as an .au file (ulaw, 8000 Hz, 8bit)\r
+ *   There are many players for this format on all platforms (for example Windows Media Player\r
+ *   under Windows, command play under Linux). Support will be added for wav format and \r
+ *   possibility to save with two channels (separate channel for each direction)\r
+ *\r
+ * - Support for more codecs. Now you can save voice only if the codec is g.711 alaw or ulaw.\r
+ *\r
+ * - right now, the reversed connection must have the same (only inversed) ip and port numbers.\r
+ *   I think that there is no reason that in special cases the reversed connection would not use \r
+ *   some different port or even the IP combination (please correct me if I am wrong). \r
+ *   So this will be added soon.\r
+ *\r
+ * - some more statistics (delay and jitter distribution)\r
+ *\r
+ * - GTK2 implementation\r
+ *\r
+ * - grammar correction\r
+ * \r
+ * - some more testing (other OS)\r
+ *\r
+ * XXX Problems: \r
+ *\r
+ * - how to use snprintf (or g_snprintf) with guint16, guint32 ? If I put %lu for guint32 \r
+ *   then compiler makes a warning but it works. If I put %d for guint32, \r
+ *   then compiler doesn't warns, but then it doesn't work\r
+ *\r
+ * - instead of tmpnam() use of mkstemp(). \r
+ *   I tried to do it with mkstemp() but didn't now how to solve following  problem: \r
+ *   I call mkstemp() and then write in this temp file and it works fine . But if the user \r
+ *   then hits the refresh button, this temp file should be deleted and opened again. I tried\r
+ *   to call close() and unlink(), but when I call mkstemp() for the second time I always get\r
+ *   an error ( -1) as return value. What is the correct order? Is it possible to call \r
+ *   mkstemp() twice with the same template?    \r
+ *\r
+ * - problem with statistics for lost (late, duplicated) packets. How to make the statistic \r
+ *   more resistant to special (bizarre) arrival of sequence numbers\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+# include "config.h"\r
+#endif\r
+\r
+#include <stdio.h>\r
+\r
+#ifdef HAVE_SYS_TYPES_H\r
+# include <sys/types.h>\r
+#endif\r
+\r
+#include <gtk/gtk.h>\r
+#include "tap_rtp.h"\r
+#include "globals.h"\r
+#include <string.h>\r
+#include "epan/packet_info.h"\r
+#include <epan/epan_dissect.h>\r
+#include <epan/filesystem.h>\r
+#include "../tap.h"\r
+#include "../register.h"\r
+#include "../packet-rtp.h"\r
+#include "file_dlg.h"\r
+#include "dlg_utils.h"\r
+#include "ui_util.h"\r
+#include "simple_dialog.h"\r
+#include "main.h"\r
+#include <math.h>\r
+#include "progress_dlg.h"\r
+#include "compat_macros.h"\r
+#include "../g711.h"\r
+#include <unistd.h>\r
+#include <fcntl.h>\r
+\r
+static GtkWidget *rtp_w = NULL;\r
+static GtkWidget *voice_w = NULL;\r
+static GtkWidget *save_w = NULL;\r
+static GtkWidget *main_vb;\r
+static GtkWidget *clist;\r
+static GtkWidget *clist_r;\r
+static GtkWidget *max;\r
+static GtkWidget *max_r;\r
+\r
+static gboolean copy_file(gchar *, /*gint,*/ gint, void *);\r
+\r
+char f_tempname[100], r_tempname[100];\r
+\r
+/* type of error when saving voice in a file didn't succeed */\r
+typedef enum {\r
+       WRONG_CODEC,\r
+       WRONG_LENGTH,\r
+       PADDING_SET,\r
+       FILE_OPEN_ERROR,\r
+       NO_DATA\r
+} error_type_t; \r
+\r
+/* structure that holds the information about the forwarding and reversed connection */\r
+/* f_* always aplies to the forward direction and r_* to the reversed */\r
+typedef struct _info_stat {\r
+       gchar source[16];\r
+       gchar destination[16];\r
+       guint16 srcport;\r
+       guint16 dstport;\r
+       guint32 ssrc_forward;\r
+       guint32 ssrc_reversed;\r
+       guint32 *ssrc_tmp;\r
+       gboolean search_ssrc;\r
+       guint reversed_ip;\r
+       guint reversed_ip_and_port;\r
+       gboolean f_first_packet;\r
+       gboolean r_first_packet;\r
+       guint16 f_seq_num;\r
+       guint16 r_seq_num;\r
+       guint32 f_timestamp;\r
+       guint32 r_timestamp;\r
+       guint32 f_delta_timestamp;\r
+       guint32 r_delta_timestamp;\r
+       double f_delay;\r
+       double r_delay;\r
+       double f_jitter;\r
+       double r_jitter;\r
+       double f_time;\r
+       double r_time;\r
+       double f_start_time;\r
+       double r_start_time;\r
+       double f_max_delay;\r
+       double r_max_delay;\r
+       guint32 f_max_nr;\r
+       guint32 r_max_nr;\r
+       guint16 f_start_seq_nr;\r
+       guint16 r_start_seq_nr;\r
+       guint16 f_stop_seq_nr;\r
+       guint16 r_stop_seq_nr;\r
+       guint32 f_total_nr;\r
+       guint32 r_total_nr;\r
+       guint32 f_sequence;\r
+       guint32 r_sequence;\r
+       gint f_cycles;\r
+       gint r_cycles;\r
+       gboolean f_under;\r
+       gboolean r_under;\r
+       FILE *f_fp;\r
+       FILE *r_fp;\r
+       gboolean f_saved;\r
+       gboolean r_saved;\r
+       error_type_t f_error_type;\r
+       error_type_t r_error_type;\r
+       guint32 f_count;\r
+       guint32 r_count;\r
+} info_stat;\r
+\r
+\r
+/* when there is a [re]reading of packet's */\r
+static void\r
+rtp_reset(void *prs)\r
+{\r
+  info_stat *rs=prs;\r
+\r
+  rs->f_first_packet = TRUE;\r
+  rs->r_first_packet = TRUE;\r
+  rs->f_max_delay = 0;\r
+  rs->r_max_delay = 0;\r
+  rs->f_max_nr = 0;\r
+  rs->r_max_nr = 0;\r
+  rs->f_total_nr = 0;\r
+  rs->r_total_nr = 0;\r
+  rs->f_sequence = 0;\r
+  rs->r_sequence = 0;\r
+  rs->f_start_seq_nr = 0;\r
+  rs->r_start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */\r
+  rs->f_stop_seq_nr = 0;\r
+  rs->r_stop_seq_nr = 0;\r
+  rs->f_cycles = 0;\r
+  rs->r_cycles = 0;\r
+  rs->f_under = FALSE;\r
+  rs->r_under = FALSE;\r
+  rs->f_saved = FALSE;\r
+  rs->r_saved = FALSE;\r
+  rs->f_start_time = 0;\r
+  rs->r_start_time = 0;\r
+  rs->f_count = 0;\r
+  rs->r_count = 0;\r
+  /* XXX check for error at fclose? */\r
+  if (rs->f_fp != NULL)\r
+       fclose(rs->f_fp); \r
+  if (rs->r_fp != NULL)\r
+       fclose(rs->r_fp); \r
+  rs->f_fp = fopen(f_tempname, "w"); \r
+  if (rs->f_fp == NULL)\r
+       rs->f_error_type = FILE_OPEN_ERROR;\r
+  rs->r_fp = fopen(r_tempname, "w");\r
+  if (rs->r_fp == NULL)\r
+       rs->r_error_type = FILE_OPEN_ERROR;\r
+  return;\r
+}\r
+\r
+/* here we can redraw the output */\r
+/* not used yet */\r
+static void rtp_draw(void *prs _U_)\r
+{\r
+       return;\r
+}\r
+\r
+/* when we are finished with redisection, we add the label for the statistic */\r
+static void draw_stat(void *prs)\r
+{\r
+       info_stat *rs=prs;\r
+       gchar label_max[200];\r
+       guint32 f_expected = (rs->f_stop_seq_nr + rs->f_cycles*65536) - rs->f_start_seq_nr + 1;\r
+       guint32 r_expected = (rs->r_stop_seq_nr + rs->r_cycles*65536) - rs->r_start_seq_nr + 1;\r
+       gint32 f_lost = f_expected - rs->f_total_nr;\r
+       gint32 r_lost = r_expected - rs->r_total_nr;\r
+\r
+       g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"\r
+               "Total RTP packets = %u   (expected %u)   Lost RTP packets = %d"  \r
+               "   Sequence error = %u",\r
+                       rs->f_max_delay, rs->f_max_nr, rs->f_total_nr, f_expected, \r
+                                                       f_lost, rs->f_sequence);\r
+\r
+       gtk_label_set_text(GTK_LABEL(max), label_max);\r
+\r
+       g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"\r
+               "Total RTP packets = %u   (expected %u)   Lost RTP packets = %d"\r
+               "   Sequence error = %u",\r
+                        rs->r_max_delay, rs->r_max_nr, rs->r_total_nr, r_expected,\r
+                                                       r_lost, rs->r_sequence);\r
+\r
+       gtk_label_set_text(GTK_LABEL(max_r), label_max);\r
+\r
+       /* could be done somewhere else, but can be here as well */\r
+       /* if this is true, then we don't have any reversed connection, so the error type\r
+        * will be no data. This applies only the reversed connection */\r
+       if (rs->reversed_ip_and_port == 0)\r
+               rs->r_error_type = NO_DATA;\r
+\r
+       return ;\r
+}\r
+\r
+/* append a line to clist */\r
+/* XXX is there a nicer way to make these assignements? */\r
+static void add_to_clist(gboolean forward, guint32 number, guint16 seq_num, \r
+                               double delay, double jitter, gboolean status, gboolean marker)\r
+{\r
+       gchar *data[6];\r
+       gchar field[6][30];\r
+\r
+       data[0]=&field[0][0];\r
+       data[1]=&field[1][0];\r
+       data[2]=&field[2][0];\r
+       data[3]=&field[3][0];\r
+       data[4]=&field[4][0];\r
+       data[5]=&field[5][0];\r
+\r
+       g_snprintf(field[0], 20, "%u", number);\r
+       g_snprintf(field[1], 20, "%u", seq_num);\r
+       g_snprintf(field[2], 20, "%f", delay);\r
+       g_snprintf(field[3], 20, "%f", jitter);\r
+       g_snprintf(field[4], 20, "%s", marker? "SET" : "");\r
+       g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");\r
+\r
+       gtk_clist_append(GTK_CLIST(forward? clist : clist_r), data);\r
+\r
+}\r
+\r
+/* whenever a RTP packet is seen by the tap listener */\r
+/* this function works as follows:\r
+ * 1) packets that are not displayed are ignored\r
+ *     return\r
+ * 2) are we searching what could be the reversed connection (looking for reversed SSRC)\r
+ *     if yes, do the parameters match (inversed IP and port combination from the forward one)?\r
+ *             if yes, do we already have this SSRC stored\r
+ *                     if not store it\r
+ * 3) if not, is current packet matching the forward direction\r
+ *     is it the first time we see a packet in this direction\r
+ *             if yes, store some values, add a line to list and save the voice info\r
+ *             in a temporary file if the codec is supported and the RTP data is ok\r
+ *     if not, is it a packet with mark bit set (there was silence surpression)\r
+ *             same as above, only we have to add some silence in front of the voice data\r
+ *     if not, then this must be a normal packet\r
+ *             store the values and voice data\r
+ * 4) if not, is current packet matching the reversed connection\r
+ *     (same as for number 3)\r
+ */\r
+static int rtp_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *vpri)\r
+{\r
+       info_stat *rs=prs;\r
+       struct _rtp_info *pri=vpri;\r
+       guint i;\r
+       double n_time;\r
+       double n_jitter;\r
+       guint8 *data;\r
+       gint16 tmp;\r
+\r
+       /* we ignore packets that are not displayed */\r
+       if (pinfo->fd->flags.passed_dfilter == 0)\r
+               return 0;\r
+\r
+       /* are we looking for the SSRC of the reversed connection? */\r
+       if (rs->search_ssrc != FALSE) {\r
+               /* XXX what should be the rules for reversed connection? \r
+                * 1. It should should have same inversed IP and port numbers\r
+                * 2. If none are found, only inversed IP's - is this possible?\r
+                * 3. If none are found, there isn't any reversed connection \r
+                * XXX is it possible that the conversation is not P2P? \r
+                * Curretly it works only if it matches the number 1. */\r
+\r
+               /* have we found inverse parameters? */\r
+               if ( strcmp(ip_to_str(pinfo->src.data), rs->destination) == 0  && \r
+                               strcmp( ip_to_str(pinfo->dst.data), rs->source) == 0 ) {\r
+\r
+                       /* do the ports also match? */\r
+                       if ((rs->srcport == pinfo->destport) && (rs->dstport == pinfo->srcport)) {\r
+                               /* ok, the ip and port combination does match \r
+                                * do we already have this ssrc stored */\r
+                               for(i=0; i< rs->reversed_ip_and_port; i++) {\r
+                                       if (pri->info_sync_src == *(rs->ssrc_tmp+i) ) \r
+                                               return 0;\r
+                               }\r
+                               \r
+                               /* no, we found new ssrc, let's store it */\r
+                               rs->ssrc_tmp = (guint32*)g_realloc(rs->ssrc_tmp, \r
+                                                               (i+1)*sizeof(guint32));\r
+                               *(rs->ssrc_tmp+i) = pri->info_sync_src;\r
+                               rs->reversed_ip_and_port++;\r
+                               return 0;\r
+                       }\r
+                       /* no, only ip addresses match */\r
+                       /* XXX not implemented yet */\r
+                       else {\r
+                               rs->reversed_ip++;\r
+                               return 0;\r
+                       }\r
+\r
+               }\r
+       }\r
+       \r
+       /* ok, we are not looking for SSRC of the reversed connection */\r
+       /* is it the forward direction? \r
+        * if yes, there 3 possibilities:\r
+        * a) is this the first packet we got in this direction?\r
+        * b) or is it a packet with the mark bit set?\r
+        * c) if neither then it is a "normal" packet */\r
+       else if (rs->ssrc_forward == pri->info_sync_src) {\r
+               /* first packet? */\r
+               if (rs->f_first_packet != FALSE) {\r
+                       /* we store all the values */\r
+                       rs->f_seq_num = pri->info_seq_num;\r
+                       rs->f_delay = 0;\r
+                       rs->f_jitter = 0;\r
+                       rs->f_first_packet = FALSE;\r
+                       rs->f_timestamp = pri->info_timestamp;\r
+                       rs->f_start_seq_nr = pri->info_seq_num;\r
+                       rs->f_stop_seq_nr = pri->info_seq_num;\r
+                       rs->f_total_nr++;\r
+                       rs->f_time = (double)pinfo->fd->rel_secs + \r
+                                               (double) pinfo->fd->rel_usecs/1000000;\r
+                       rs->f_start_time = rs->f_time;\r
+                       /* and add a row to clist; delay and jitter are 0 for the first packet */\r
+                       add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);\r
+\r
+                       /* and now save the voice info */\r
+\r
+                       /* if we couldn't open the tmp file for writing, then we set the flag */\r
+                       if (rs->f_fp == NULL) {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = FILE_OPEN_ERROR;\r
+                               return 0;\r
+                       }\r
+                       /* if the captured length and packet length aren't equal, we quit \r
+                        * because there is some information missing */\r
+                       if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = WRONG_LENGTH;\r
+                               return 0;\r
+                       }\r
+                       /* if padding bit is set, we don't do it yet */\r
+                       if (pri->info_padding_set != FALSE) {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = PADDING_SET;\r
+                               return 0;\r
+                       }\r
+                       /* is it the ulaw? */\r
+                       if (pri->info_payload_type == 0) {\r
+                               /* we put the pointer at the beggining of the RTP data, that is\r
+                                * at the end of the current frame minus the length of the \r
+                                * RTP field plus 12 for the RTP header */\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               rs->f_saved = TRUE;\r
+                               return 0;\r
+                       }\r
+                       /* alaw? */\r
+                       else if (pri->info_payload_type == 8) {\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len -12 ); i++, data++) {\r
+                                       tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               rs->f_saved = TRUE;\r
+                               return 0;\r
+                       }\r
+                       /* unsupported codec or other error */\r
+                       else {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = WRONG_CODEC;\r
+                               return 0;\r
+                       }\r
+               }\r
+               \r
+               /* packet with mark bit set? */\r
+               if (pri->info_marker_set != FALSE) {\r
+                       n_time = (double)pinfo->fd->rel_secs +\r
+                                       (double) pinfo->fd->rel_usecs/1000000;\r
+                       /* jitter is calculated as for RCTP - RFC 1889 \r
+                        * J = J + ( | D(i-1, i) | - J) / 16\r
+                        * XXX the output there should be in timestamp (probably miliseconds)\r
+                        * units expressed as an unsigned integer, so should we do it the same? \r
+                        * (currently we use seconds) \r
+                        *\r
+                        * XXX Packet loss in RTCP is calculated as the difference between the\r
+                        * number of packets expected and actually received, where for actually \r
+                        * received the number is simply the count of packets as they arrive, \r
+                        * including any late or duplicate packets (this means that the number\r
+                        * can be negative). For example, if the seq numbers of the arrived\r
+                        * packets are: 1,2,3,4,5,5,7,7,9,10 the expected number is 10 and the\r
+                        * the number of actually captured frames is also 10. So in upper \r
+                        * calculation there would be no losses. But there are 2 losses and \r
+                        * 2 duplicate packets. Because this kind of statistic is rather \r
+                        * useless (or confusing) we add the information, that there was \r
+                        * an error with sequence number each time the sequence number was \r
+                        * not one bigger than the previous one\r
+                       */\r
+                       \r
+                       /* jitter calculation */\r
+                       n_jitter = rs->f_jitter + ( fabs(n_time-(rs->f_time) - \r
+                                       ((double)(pri->info_timestamp)-\r
+                                       (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;\r
+\r
+                       /* we add the information into the clist */\r
+                       add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),\r
+                                n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);\r
+\r
+                       /* when calculating expected rtp packets the seq number can wrap around\r
+                        * so we have to count the number of cycles \r
+                        * f_cycles counts the wraps around in forwarding connection and\r
+                        * f_under is flag that indicates where we are \r
+                        *\r
+                        * XXX how to determine number of cycles with all possible lost, late\r
+                        * and duplicated packets without any doubt? It seems to me, that \r
+                        * because of all possible combination of late, duplicated or lost\r
+                        * packets, this can only be more or less good approximation\r
+                        *\r
+                        * There are some combinations (rare but theoretically possible), \r
+                        * where below code won't work correctly - statistic may be wrong then.\r
+                        */\r
+\r
+                       /* so if the current sequence number is less than the start one\r
+                        * we assume, that there is another cycle running */\r
+                       if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){\r
+                               rs->f_cycles++;\r
+                               rs->f_under = TRUE;\r
+                       }\r
+                       /* what if the start seq nr was 0. Then the above condition will never \r
+                        * be true, so we add another condition. XXX The problem would arise if\r
+                        * if one of the packets with seq nr 0 or 65535 would be lost or late */\r
+                       else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) && \r
+                                                                       (rs->f_under == FALSE)){\r
+                               rs->f_cycles++;\r
+                               rs->f_under = TRUE;\r
+                       }\r
+                       /* the whole round is over, so reset the flag */\r
+                       else if ((pri->info_seq_num>rs->f_start_seq_nr)&&(rs->f_under!=FALSE)){\r
+                               rs->f_under = FALSE;\r
+                       }\r
+\r
+                       /* number of times where sequence number was not ok */\r
+                       if ( rs->f_seq_num+1 == pri->info_seq_num)\r
+                               rs->f_seq_num = pri->info_seq_num;\r
+                       /* XXX same problem as above */\r
+                       else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )\r
+                               rs->f_seq_num = pri->info_seq_num;\r
+                       /* lost packets */\r
+                       else if (rs->f_seq_num+1 < pri->info_seq_num) {\r
+                               rs->f_seq_num = pri->info_seq_num;\r
+                               rs->f_sequence++;\r
+                       }\r
+                       /* late or duplicated */\r
+                       else if (rs->f_seq_num+1 > pri->info_seq_num)\r
+                               rs->f_sequence++;\r
+\r
+                       rs->f_stop_seq_nr = pri->info_seq_num;\r
+                       rs->f_time = n_time;\r
+                       rs->f_jitter = n_jitter;\r
+                       rs->f_delta_timestamp = pri->info_timestamp - rs->f_timestamp;\r
+                       rs->f_timestamp = pri->info_timestamp;\r
+                       rs->f_total_nr++;\r
+\r
+                       /* save the voice information */\r
+                       /* if there was already an error, we quit */\r
+                       if (rs->f_saved == FALSE)\r
+                               return 0;\r
+                       /* if the captured length and packet length aren't equal, we quit */\r
+                       if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = WRONG_LENGTH;\r
+                               return 0;\r
+                       }\r
+                       /* if padding bit is set, we don't do it yet */\r
+                       if (pri->info_padding_set != FALSE) {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = PADDING_SET;\r
+                               return 0;\r
+                       }\r
+                       /* because the mark bit is set, we have to add some silence in front */\r
+                       /* is it the ulaw? */\r
+                       if (pri->info_payload_type == 0) {\r
+                               /* we insert some silence */\r
+                               /* XXX the amount of silence should be the difference between\r
+                                * the last timestamp and the current one minus x in the\r
+                                * I am not sure if x is equal the amount of information \r
+                                * current packet? */\r
+                               for(i=0; i<(rs->f_delta_timestamp-pri->info_data_len+12); i++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)(0x55));\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               return 0;\r
+                       }\r
+                       /* alaw? */\r
+                       else if (pri->info_payload_type == 8) {\r
+                               for(i=0; i < (rs->f_delta_timestamp-pri->info_data_len+12); i++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)(0x55));\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len -12 ); i++, data++) {\r
+                                       tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->f_fp);\r
+                                       rs->f_count++;\r
+                               }\r
+                               return 0;\r
+                       }\r
+                       /* unsupported codec or other error */\r
+                       else {\r
+                               rs->f_saved = FALSE;\r
+                               rs->f_error_type = WRONG_CODEC;\r
+                               return 0;\r
+                       }\r
+                       return 0;\r
+               }\r
+               \r
+               /* normal packet in forward connection */\r
+               n_time = (double)pinfo->fd->rel_secs +\r
+                                       (double) pinfo->fd->rel_usecs/1000000;\r
+               n_jitter = rs->f_jitter + ( fabs (n_time-(rs->f_time) - \r
+                               ((double)(pri->info_timestamp)-\r
+                               (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;\r
+               rs->f_delay =  n_time-(rs->f_time);\r
+               /* the delay is bigger than previous max delay, so store the delay and nr */\r
+               if (rs->f_delay > rs->f_max_delay) {\r
+                       rs->f_max_delay = rs->f_delay;\r
+                       rs->f_max_nr = pinfo->fd->num;\r
+               }\r
+               add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),\r
+                                n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);\r
+\r
+               /* count the cycles */\r
+               if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){\r
+                       rs->f_cycles++;\r
+                       rs->f_under = TRUE;\r
+               }\r
+               else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) && \r
+                                                               (rs->f_under == FALSE)){\r
+                       rs->f_cycles++;\r
+                       rs->f_under = TRUE;\r
+               }\r
+               /* the whole round is over, so reset the flag */\r
+               else if ((pri->info_seq_num>rs->f_start_seq_nr+1)&&(rs->f_under!=FALSE)){\r
+                       rs->f_under = FALSE;\r
+               }\r
+\r
+               /* number of times where sequence number was not ok */\r
+               if ( rs->f_seq_num+1 == pri->info_seq_num)\r
+                       rs->f_seq_num = pri->info_seq_num;\r
+               else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )\r
+                       rs->f_seq_num = pri->info_seq_num;\r
+               /* lost packets */\r
+               else if (rs->f_seq_num+1 < pri->info_seq_num) {\r
+                       rs->f_seq_num = pri->info_seq_num;\r
+                       rs->f_sequence++;\r
+               }\r
+               /* late or duplicated */\r
+               else if (rs->f_seq_num+1 > pri->info_seq_num)\r
+                       rs->f_sequence++;\r
+\r
+               rs->f_stop_seq_nr = pri->info_seq_num;\r
+               rs->f_time = n_time;\r
+               rs->f_jitter = n_jitter;\r
+               rs->f_timestamp = pri->info_timestamp;\r
+               rs->f_total_nr++;\r
+\r
+               /* save the voice information */\r
+               /* we do it only in following cases:\r
+                * - the codecs we support are g.711 alaw in ulaw\r
+                * - the captured length must equal the packet length\r
+                * - XXX we don't support it if there are padding bits \r
+                */\r
+               /* if there was already an error, we quit */\r
+               if (rs->f_saved == FALSE)\r
+                       return 0;\r
+               /* if the captured length and packet length aren't equal, we quit */\r
+               if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                       rs->f_saved = FALSE;\r
+                       rs->f_error_type = WRONG_LENGTH;\r
+                       return 0;\r
+               }\r
+               /* if padding bit is set, we don't do it yet */\r
+               if (pri->info_padding_set != FALSE) {\r
+                       rs->f_saved = FALSE;\r
+                       rs->f_error_type = PADDING_SET;\r
+                       return 0;\r
+               }\r
+               /* is it the ulaw? */\r
+               if (pri->info_payload_type == 0) {\r
+                       /* cfile.pd points at the beggining of the actual packet. We have\r
+                        * to move this pointer at the RTP data. This is the packet length,\r
+                        * minus whole RTP data length (including the RTP header, that is\r
+                        * why we add 12) */\r
+                       data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                       for(i=0; i < (pri->info_data_len - 12); i++, data++) {\r
+                               tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                               fwrite(&tmp, 2, 1, rs->f_fp);\r
+                               rs->f_count++;\r
+                       }\r
+                       return 0;                               \r
+               }\r
+               /* alaw? */\r
+               else if (pri->info_payload_type == 8) {\r
+                       data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                       for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                               tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                               fwrite(&tmp, 2, 1, rs->f_fp);\r
+                               rs->f_count++;\r
+                       }\r
+                       return 0;\r
+               }\r
+               /* unsupported codec or other error */\r
+               else {\r
+                       rs->f_saved = FALSE;\r
+                       rs->f_error_type = WRONG_CODEC;\r
+                       return 0;\r
+               }\r
+       }                               \r
+\r
+       /* is it the reversed direction? */\r
+       else if (rs->ssrc_reversed == pri->info_sync_src) {\r
+               /* first packet? */\r
+               if (rs->r_first_packet !=FALSE) {\r
+                       rs->r_seq_num = pri->info_seq_num;\r
+                       rs->r_delay = 0;\r
+                       rs->r_jitter = 0;\r
+                       rs->r_first_packet = FALSE;\r
+                       rs->r_timestamp = pri->info_timestamp;\r
+                       rs->r_start_seq_nr = pri->info_seq_num;\r
+                       rs->r_stop_seq_nr = pri->info_seq_num;\r
+                       rs->r_total_nr++;\r
+                       rs->r_time = (double)pinfo->fd->rel_secs + \r
+                                               (double) pinfo->fd->rel_usecs/1000000;\r
+                       rs->r_start_time = rs->r_time;\r
+                       add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);\r
+\r
+                       /* save it */\r
+                       /* if we couldn't open the tmp file for writing, then we set the flag */\r
+                       if (rs->r_fp == NULL) {\r
+                               rs->r_saved = FALSE;\r
+                               return 0;\r
+                       }\r
+                       /* if the captured length and packet length aren't equal, we quit */\r
+                       if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = WRONG_LENGTH;\r
+                               return 0;\r
+                       }\r
+                       /* if padding bit is set, we don't do it yet */\r
+                       if (pri->info_padding_set != FALSE) {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = PADDING_SET;\r
+                               return 0;\r
+                       }\r
+                       /* is it the ulaw? */\r
+                       if (pri->info_payload_type == 0) {\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               rs->r_saved = TRUE;\r
+                               return 0;\r
+                       }\r
+                       /* alaw? */\r
+                       else if (pri->info_payload_type == 8) {\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len -12 ); i++, data++) {\r
+                                       tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               rs->r_saved = TRUE;\r
+                               return 0;\r
+                       }\r
+                       /* unsupported codec or other error */\r
+                       else {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = WRONG_CODEC;\r
+                               return 0;\r
+                       }\r
+               }\r
+               \r
+               /* packet with mark bit set? */\r
+               if (pri->info_marker_set != FALSE) {\r
+                       n_time = (double)pinfo->fd->rel_secs +\r
+                                       (double) pinfo->fd->rel_usecs/1000000;\r
+                       n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) - \r
+                                       ((double)(pri->info_timestamp)-\r
+                                       (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;\r
+                       add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),\r
+                                n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);\r
+\r
+                       /* count the cycles */\r
+                       if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){\r
+                               rs->r_cycles++;\r
+                               rs->r_under = TRUE;\r
+                       }\r
+                       else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) && \r
+                                                                       (rs->r_under == FALSE)){\r
+                               rs->r_cycles++;\r
+                               rs->r_under = TRUE;\r
+                       }\r
+                       /* the whole round is over, so reset the flag */\r
+                       else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){\r
+                               rs->r_under = FALSE;\r
+                       }\r
+\r
+                       /* number of times where sequence number was not ok */\r
+                       if ( rs->r_seq_num+1 == pri->info_seq_num)\r
+                               rs->r_seq_num = pri->info_seq_num;\r
+                       else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )\r
+                               rs->r_seq_num = pri->info_seq_num;\r
+                       /* lost packets */\r
+                       else if (rs->r_seq_num+1 < pri->info_seq_num) {\r
+                               rs->r_seq_num = pri->info_seq_num;\r
+                               rs->r_sequence++;\r
+                       }\r
+                       /* late or duplicated */\r
+                       else if (rs->r_seq_num+1 > pri->info_seq_num)\r
+                               rs->r_sequence++;\r
+\r
+                       rs->r_stop_seq_nr = pri->info_seq_num;\r
+                       rs->r_time = n_time;\r
+                       rs->r_jitter = n_jitter;\r
+                       rs->r_delta_timestamp = pri->info_timestamp - rs->r_timestamp;\r
+                       rs->r_timestamp = pri->info_timestamp;\r
+                       rs->r_total_nr++;\r
+\r
+                       /* save the voice information */\r
+                       /* if there was already an error, we quit */\r
+                       if (rs->r_saved == FALSE)\r
+                               return 0;\r
+                       /* if the captured length and packet length aren't equal, we quit */\r
+                       if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = WRONG_LENGTH;\r
+                               return 0;\r
+                       }\r
+                       /* if padding bit is set, we don't do it yet */\r
+                       if (pri->info_padding_set != FALSE) {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = PADDING_SET;\r
+                               return 0;\r
+                       }\r
+                       /* because the mark bit is set, we have to add some silence in front */\r
+                       /* is it the ulaw? */\r
+                       if (pri->info_payload_type == 0) {\r
+                               /* we insert some silence */\r
+                               for(i=0; i<(rs->r_delta_timestamp-pri->info_data_len+12); i++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)(0x55));\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               return 0;\r
+                       }\r
+                       /* alaw? */\r
+                       else if (pri->info_payload_type == 8) {\r
+                               for(i=0; i < (rs->r_delta_timestamp-pri->info_data_len+12); i++) {\r
+                                       tmp = (gint16 )ulaw2linear((unsigned char)(0x55));\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                               for(i=0; i < (pri->info_data_len -12 ); i++, data++) {\r
+                                       tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                                       fwrite(&tmp, 2, 1, rs->r_fp);\r
+                                       rs->r_count++;\r
+                               }\r
+                               return 0;\r
+                       }\r
+                       /* unsupported codec or other error */\r
+                       else {\r
+                               rs->r_saved = FALSE;\r
+                               rs->r_error_type = WRONG_CODEC;\r
+                               return 0;\r
+                       }\r
+                       return 0;\r
+               }\r
+               \r
+               /* normal packet in reversed connection */\r
+               n_time = (double)pinfo->fd->rel_secs +\r
+                               (double) pinfo->fd->rel_usecs/1000000;\r
+               n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) - \r
+                               ((double)(pri->info_timestamp)-\r
+                               (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;\r
+               rs->r_delay =  n_time-(rs->r_time);\r
+               if (rs->r_delay > rs->r_max_delay) {\r
+                       rs->r_max_delay = rs->r_delay;\r
+                       rs->r_max_nr = pinfo->fd->num;\r
+               }\r
+               add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),\r
+                                n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);\r
+               /* count the cycles */\r
+               if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){\r
+                       rs->r_cycles++;\r
+                       rs->r_under = TRUE;\r
+               }\r
+               else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) && \r
+                                                               (rs->r_under == FALSE)){\r
+                       rs->r_cycles++;\r
+                       rs->r_under = TRUE;\r
+               }\r
+               /* the whole round is over, so reset the flag */\r
+               else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){\r
+                       rs->r_under = FALSE;\r
+               }\r
+\r
+               /* number of times where sequence number was not ok */\r
+               if ( rs->r_seq_num+1 == pri->info_seq_num)\r
+                       rs->r_seq_num = pri->info_seq_num;\r
+               else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )\r
+                       rs->r_seq_num = pri->info_seq_num;\r
+               /* lost packets */\r
+               else if (rs->r_seq_num+1 < pri->info_seq_num) {\r
+                       rs->r_seq_num = pri->info_seq_num;\r
+                       rs->r_sequence++;\r
+               }\r
+               /* late or duplicated */\r
+               else if (rs->r_seq_num+1 > pri->info_seq_num)\r
+                       rs->r_sequence++;\r
+\r
+               rs->r_stop_seq_nr = pri->info_seq_num;\r
+               rs->r_time = n_time;\r
+               rs->r_jitter = n_jitter;\r
+               rs->r_timestamp = pri->info_timestamp;\r
+               rs->r_total_nr++;\r
+\r
+               /* save the voice information */\r
+               /* if there was already an error, we quit */\r
+               if (rs->r_saved == FALSE)\r
+                       return 0;\r
+               /* if the captured length and packet length aren't equal, we quit */\r
+               if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {\r
+                       rs->r_saved = FALSE;\r
+                       rs->r_error_type = WRONG_LENGTH;\r
+                       return 0;\r
+               }\r
+               /* if padding bit is set, we don't do it yet */\r
+               if (pri->info_padding_set != FALSE) {\r
+                       rs->r_saved = FALSE;\r
+                       rs->r_error_type = PADDING_SET;\r
+                       return 0;\r
+               }\r
+               /* is it the ulaw? */\r
+               if (pri->info_payload_type == 0) {\r
+                       data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                       for(i=0; i < (pri->info_data_len-12 ); i++, data++) {\r
+                               tmp = (gint16 )ulaw2linear((unsigned char)*data);\r
+                               fwrite(&tmp, 2, 1, rs->r_fp);\r
+                               rs->r_count++;\r
+                       }\r
+                       return 0;\r
+               }\r
+               /* alaw? */\r
+               else if (pri->info_payload_type == 8) {\r
+                       data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);\r
+                       for(i=0; i < (pri->info_data_len -12 ); i++, data++) {\r
+                               tmp = (gint16 )alaw2linear((unsigned char)*data);\r
+                               fwrite(&tmp, 2, 1, rs->r_fp);\r
+                               rs->r_count++;\r
+                       }\r
+                       return 0;\r
+               }\r
+               /* unsupported codec or other error */\r
+               else {\r
+                       rs->r_saved = FALSE;\r
+                       rs->r_error_type = WRONG_CODEC;\r
+                       return 0;\r
+               }\r
+       }                               \r
+\r
+       return 0;\r
+}\r
+\r
+/* XXX just copied from gtk/rpc_stat.c */\r
+void protect_thread_critical_region(void);\r
+void unprotect_thread_critical_region(void);\r
+\r
+\r
+/* here we close the rtp analysis dialog window and remove the tap listener */\r
+static void rtp_destroy_cb(GtkWidget *win _U_, gpointer data _U_)\r
+{\r
+  info_stat *rs=(info_stat *)data;\r
+\r
+  protect_thread_critical_region();\r
+  remove_tap_listener(rs);\r
+  unprotect_thread_critical_region();\r
+\r
+  /* xxx is this enough? */\r
+  g_free(rs->ssrc_tmp);\r
+  g_free(rs);\r
\r
+  if (rs->f_fp != NULL)\r
+       fclose(rs->f_fp);\r
+  if (rs->r_fp != NULL)\r
+       fclose(rs->r_fp);\r
+  remove(f_tempname);\r
+  remove(r_tempname);\r
+\r
+  /* is there a save window open */\r
+  if (save_w != NULL)\r
+       gtk_widget_destroy(save_w);\r
+\r
+  /* Is there a save voice window open? */\r
+  if (voice_w != NULL)\r
+       gtk_widget_destroy(voice_w);\r
+\r
+  /* Note that we no longer have a "RTP Analyse" dialog box. */\r
+  rtp_w = NULL;\r
+}\r
+\r
+/* when the close button in rtp window was clicked */\r
+/* it seems to me that rtp_destroy_cb is automatically called, so we don't\r
+ * need to do the g_free... and rtp_w = NULL ... */\r
+static void rtp_destroy (GtkWidget *close_bt _U_, gpointer parent_w)\r
+{\r
+    gtk_grab_remove(GTK_WIDGET(parent_w));\r
+    gtk_widget_destroy(GTK_WIDGET(parent_w));\r
+}\r
+\r
+/* we search the rtp.ssrc node here (thanks to Guy Harris - code here is magic for me */\r
+static guint32 process_node(proto_item *ptree_node, header_field_info *hfinformation) \r
+{\r
+  field_info            *finfo;\r
+  proto_item            *proto_sibling_node;\r
+  header_field_info     *hfssrc;\r
+  guint32 ssrc;\r
+\r
+  finfo = PITEM_FINFO(ptree_node);\r
+\r
+  if (hfinformation==(finfo->hfinfo)) {\r
+       hfssrc = proto_registrar_get_byname("rtp.ssrc");\r
+       if (hfssrc == NULL)\r
+               return 0;\r
+       for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL; \r
+                               ptree_node=g_node_next_sibling(ptree_node)) {\r
+               finfo=PITEM_FINFO(ptree_node);\r
+               if (hfssrc==finfo->hfinfo) {\r
+                       ssrc = fvalue_get_integer(finfo->value);\r
+                       return ssrc;\r
+               }\r
+               }\r
+  }\r
+\r
+  proto_sibling_node = g_node_next_sibling(ptree_node);\r
+\r
+  if (proto_sibling_node) {\r
+       ssrc = process_node(proto_sibling_node, hfinformation);\r
+       return ssrc;\r
+  }\r
+  else\r
+       return 0;\r
+}\r
+\r
+/* here we search the rtp protocol */\r
+static guint32 process_tree(proto_tree *protocol_tree)\r
+{\r
+  proto_item      *ptree_node;\r
+  header_field_info     *hfinformation;\r
+\r
+  hfinformation = proto_registrar_get_byname("rtp");\r
+  if (hfinformation == NULL)\r
+       return 0;\r
+\r
+  ptree_node = g_node_first_child(protocol_tree);\r
+  if (!ptree_node)\r
+       return 0;\r
+\r
+  return process_node(ptree_node, hfinformation);\r
+}\r
+\r
+/* when we want to update the information */\r
+static void refresh_cb(GtkWidget *w _U_, void *pri)\r
+{\r
+  info_stat *rs=pri;\r
+\r
+  gtk_clist_clear(GTK_CLIST(clist));\r
+  gtk_clist_clear(GTK_CLIST(clist_r));\r
+  redissect_packets(&cfile);\r
+  draw_stat(rs);\r
+}\r
+\r
+/* when the user clicks the close button */\r
+static void voice_close_cb(GtkWidget *close_bt _U_, gpointer parent_w _U_)\r
+{\r
+  gtk_widget_destroy(GTK_WIDGET(parent_w));\r
+}\r
+\r
+static void voice_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)\r
+{\r
+  if (save_w != NULL)\r
+       gtk_widget_destroy(GTK_WIDGET(save_w));\r
+\r
+  /* Note that we no longer have a Save voice info dialog box. */\r
+  voice_w = NULL;\r
+}\r
+\r
+\r
+/* the user wants to save in a file */\r
+/* XXX support for different formats is currently commented out */\r
+static void ok_button_cb(GtkWidget *ok_bt, gpointer data)\r
+{\r
+  info_stat *rs=(info_stat *)data;\r
+  GtkWidget *entry, *rev, *forw, *both;\r
+  /*GtkWidget *wav, *au, *sw;*/\r
+  gchar *g_dest;\r
+  gint channels /*, format*/;\r
+\r
+  entry = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "file_entry");\r
+  /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");\r
+  au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");\r
+  sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/\r
+  rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");\r
+  forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");\r
+  both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");\r
+  g_dest = gtk_entry_get_text(GTK_ENTRY(entry));\r
+\r
+  /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.\r
+   * we don't support that codec. So we pop up a warning. Maybe it would be better to\r
+   * disable the ok button or disable the buttons for direction if only one is not ok. The\r
+   * problem is if we open the save voice dialog and then click the refresh button and maybe \r
+   * the state changes, so we can't save anymore. In this case we should be able to update\r
+   * the buttons. For now it is easier if we put the warning when the ok button is pressed.\r
+   */\r
+\r
+  /* we can not save in both dirctions */\r
+  if ((rs->f_saved == FALSE) && (rs->r_saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {\r
+       /* there are many combinations here, we just exit when first matches */\r
+       if ((rs->f_error_type == WRONG_CODEC) || (rs->r_error_type == WRONG_CODEC))\r
+               simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save in a file: Unsupported codec!");\r
+       else if ((rs->f_error_type == WRONG_LENGTH) || (rs->r_error_type == WRONG_LENGTH))\r
+               simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save in a file: Wrong length of captured packets!");\r
+       else if ((rs->f_error_type == PADDING_SET) || (rs->r_error_type == PADDING_SET))\r
+               simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save in a file: RTP data with padding!");\r
+       else  \r
+               simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save in a file: File I/O problem!");\r
+       return;\r
+  }\r
+  /* we can not save forward direction */\r
+  else if ((rs->f_saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||\r
+                                               (GTK_TOGGLE_BUTTON (both)->active))) {  \r
+       if (rs->f_error_type == WRONG_CODEC)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save forward direction in a file: Unsupported codec!");\r
+        else if (rs->f_error_type == WRONG_LENGTH)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save forward direction in a file: Wrong length of captured packets!");\r
+        else if (rs->f_error_type == PADDING_SET)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save forward direction in a file: RTP data with padding!");\r
+        else\r
+                simple_dialog(ESD_TYPE_CRIT, NULL, \r
+               "Can't save forward direction in a file: File I/O problem!");\r
+       return;\r
+  }\r
+  /* we can not save reversed direction */\r
+  else if ((rs->r_saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||\r
+                                               (GTK_TOGGLE_BUTTON (both)->active))) {  \r
+       if (rs->r_error_type == WRONG_CODEC)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save reversed direction in a file: Unsupported codec!");\r
+        else if (rs->r_error_type == WRONG_LENGTH)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save reversed direction in a file: Wrong length of captured packets!");\r
+        else if (rs->r_error_type == PADDING_SET)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save reversed direction in a file: RTP data with padding!");\r
+        else if (rs->r_error_type == NO_DATA)\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save reversed direction in a file: No RTP data!");\r
+       else\r
+                simple_dialog(ESD_TYPE_CRIT, NULL,\r
+                "Can't save reversed direction in a file: File I/O problem!");\r
+        return;\r
+  }\r
+\r
+  /* if the file text entry is empty */\r
+  if (!g_dest[0]) {\r
+       simple_dialog(ESD_TYPE_CRIT, NULL, "Saving to file, but no file specified.");\r
+       return;\r
+  }\r
+\r
+  /*if (GTK_TOGGLE_BUTTON (wav)->active)\r
+       format = 1;\r
+  else if (GTK_TOGGLE_BUTTON (au)->active)\r
+       format = 2;\r
+  else if (GTK_TOGGLE_BUTTON (sw)->active)\r
+       format = 3;*/\r
+\r
+  if (GTK_TOGGLE_BUTTON (rev)->active)\r
+       channels = 2;\r
+  else if (GTK_TOGGLE_BUTTON (both)->active)\r
+       channels = 3;\r
+  else \r
+       channels = 1;\r
+\r
+  if(!copy_file(g_dest, channels/*, format*/, rs)) {\r
+       simple_dialog(ESD_TYPE_CRIT, NULL, "An error occured while saving voice in a file!");\r
+       return;\r
+  }\r
+\r
+  if (save_w != NULL)\r
+       gtk_widget_destroy(GTK_WIDGET(save_w));\r
+\r
+  /* XXX I get GTK warning (sometimes?)!!! */\r
+  gtk_widget_destroy(GTK_WIDGET(voice_w));\r
+}\r
+\r
+static void save_ok_button_cb(GtkWidget *w _U_, gpointer data)\r
+{\r
+  gchar     *f_name;\r
+\r
+  f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));\r
+\r
+  /* Perhaps the user specified a directory instead of a file.\r
+     Check whether they did. */\r
+  if (test_for_directory(f_name) == EISDIR) {\r
+       /* It's a directory - set the file selection box to display it. */\r
+       set_last_open_dir(f_name);\r
+       g_free(f_name);\r
+       gtk_file_selection_set_filename(GTK_FILE_SELECTION(data), last_open_dir);\r
+       return;\r
+  }\r
+\r
+  gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, "file_entry")), f_name);\r
+  gtk_widget_destroy(GTK_WIDGET(data));\r
+\r
+  g_free(f_name);\r
+}\r
+\r
+static void save_cancel_button_cb(GtkWidget *w _U_, gpointer data)\r
+{\r
+  gtk_widget_destroy(GTK_WIDGET(data));\r
+}\r
+\r
+static void save_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)\r
+{\r
+  /* Note that we no longer have a Save voice info dialog box. */\r
+  save_w = NULL;\r
+}\r
+\r
+/* file selection window */\r
+static void file_selection_cb(GtkWidget *w _U_, gpointer file_entry)\r
+{\r
+ if (save_w != NULL) {\r
+       /* Yes.  Just re-activate that dialog box. */\r
+       reactivate_window(save_w);\r
+       return;\r
+  }\r
+\r
+  save_w = gtk_file_selection_new ("Ethereal: Save to File");\r
+  gtk_signal_connect(GTK_OBJECT(save_w), "destroy", GTK_SIGNAL_FUNC(save_destroy_cb), NULL);\r
+\r
+  OBJECT_SET_DATA(save_w, "file_entry", file_entry);\r
+\r
+  gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->cancel_button), "clicked", \r
+               GTK_SIGNAL_FUNC(save_cancel_button_cb), GTK_OBJECT(save_w));\r
+  \r
+  gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->ok_button), "clicked",\r
+               GTK_SIGNAL_FUNC(save_ok_button_cb), GTK_OBJECT(save_w));\r
+  \r
+  gtk_widget_show(save_w);\r
+}\r
+\r
+/* when the user wants to save the voice information in a file */\r
+/* XXX support for different formats is currently commented out */\r
+static void voice_cb(GtkWidget *w _U_, gpointer data)\r
+{\r
+  info_stat *rs=(info_stat *)data;\r
+\r
+  GtkWidget *vertb;\r
+  GtkWidget *table1;\r
+  GtkWidget *label_format;\r
+  GtkWidget *channels_label;\r
+  /*GSList *format_group = NULL;*/\r
+  GSList *channels_group = NULL;\r
+  GtkWidget *forward_rb;\r
+  GtkWidget *reversed_rb;\r
+  GtkWidget *both_rb;\r
+  /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/\r
+  GtkWidget *hbox3;\r
+  GtkWidget *file_button;\r
+  GtkWidget *file_entry;\r
+  GtkWidget *hbox4;\r
+  GtkWidget *ok_bt;\r
+  GtkWidget *cancel_bt;\r
+\r
+  /* if we can't save in a file: wrong codec, cut packets or other errors */\r
+  /* shold the error arise here or later when you click ok button ? \r
+   * if we do it here, then we must disable the refresh button, so we don't do it here */\r
+\r
+  if (voice_w != NULL) {\r
+       /* There's already a Save voice info dialog box; reactivate it. */\r
+       reactivate_window(voice_w);\r
+       return;\r
+  }\r
+  \r
+  voice_w = dlg_window_new("Ethereal: Save voice data");\r
+  gtk_signal_connect(GTK_OBJECT(voice_w), "destroy",\r
+       GTK_SIGNAL_FUNC(voice_destroy_cb), NULL);\r
+\r
+  /* Container for each row of widgets */\r
+  vertb = gtk_vbox_new(FALSE, 0);\r
+  gtk_container_border_width(GTK_CONTAINER(vertb), 5);\r
+  gtk_container_add(GTK_CONTAINER(voice_w), vertb);\r
+  gtk_widget_show (vertb);\r
+\r
+  table1 = gtk_table_new (2, 4, FALSE);\r
+  gtk_widget_show (table1);\r
+  gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);\r
+  gtk_container_set_border_width (GTK_CONTAINER (table1), 10);\r
+  gtk_table_set_row_spacings (GTK_TABLE (table1), 20);\r
+\r
+  label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");\r
+  gtk_widget_show (label_format);\r
+  gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,\r
+                    (GtkAttachOptions) (GTK_FILL),\r
+                    (GtkAttachOptions) (0), 0, 0);\r
+\r
+  /* we support .au - ulaw*/ \r
+/*  wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");\r
+  format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));\r
+  gtk_widget_show (wav_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,\r
+                    (GtkAttachOptions) (GTK_FILL),\r
+                    (GtkAttachOptions) (0), 0, 0);\r
+\r
+  sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit  ");\r
+  format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));\r
+  gtk_widget_show (sw_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,\r
+                    (GtkAttachOptions) (GTK_FILL),\r
+                    (GtkAttachOptions) (0), 0, 0);\r
+  au_rb = gtk_radio_button_new_with_label (format_group, ".au");\r
+  format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));\r
+  gtk_widget_show (au_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,\r
+                    (GtkAttachOptions) (GTK_FILL),\r
+                    (GtkAttachOptions) (0), 0, 0);\r
+ */ \r
+\r
+  channels_label = gtk_label_new ("Channels:");\r
+  gtk_widget_show (channels_label);\r
+  gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,\r
+                               (GtkAttachOptions) (GTK_FILL),\r
+                               (GtkAttachOptions) (0), 0, 0);\r
+  gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);\r
+\r
+  forward_rb = gtk_radio_button_new_with_label (channels_group, "forward  ");\r
+  channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));\r
+  gtk_widget_show (forward_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,\r
+                       (GtkAttachOptions) (GTK_FILL),\r
+                       (GtkAttachOptions) (0), 0, 0);\r
+\r
+  reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");\r
+  channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));\r
+  gtk_widget_show (reversed_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,\r
+                       (GtkAttachOptions) (GTK_FILL),\r
+                       (GtkAttachOptions) (0), 0, 0);\r
+\r
+  both_rb = gtk_radio_button_new_with_label (channels_group, "both");\r
+  channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));\r
+  gtk_widget_show (both_rb);\r
+  gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,\r
+                       (GtkAttachOptions) (GTK_FILL),\r
+                       (GtkAttachOptions) (0), 0, 0);\r
+\r
+  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);\r
+\r
+  /* if one direction is nok we don't allow saving \r
+  XXX this is not ok since the user can click the refresh button and cause changes\r
+  but we can not update this window. So we move all the decision on the time the ok\r
+  button is clicked\r
+  if (rs->f_saved == FALSE) {\r
+       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);\r
+       gtk_widget_set_sensitive(forward_rb, FALSE);\r
+       gtk_widget_set_sensitive(both_rb, FALSE);\r
+  }\r
+  else if (rs->r_saved == FALSE) {\r
+       gtk_widget_set_sensitive(reversed_rb, FALSE);\r
+       gtk_widget_set_sensitive(both_rb, FALSE);\r
+  }\r
+  */\r
+  hbox3 = gtk_hbox_new (FALSE, 0);\r
+  gtk_widget_show (hbox3);\r
+  gtk_box_pack_start (GTK_BOX (vertb), hbox3, FALSE, FALSE, 0);\r
+  gtk_container_set_border_width (GTK_CONTAINER (hbox3), 10);\r
+\r
+  file_button = gtk_button_new_with_label ("File:");\r
+  gtk_widget_show (file_button);\r
+  gtk_box_pack_start (GTK_BOX (hbox3), file_button, FALSE, FALSE, 0);\r
+\r
+  file_entry = gtk_entry_new ();\r
+  gtk_widget_show (file_entry);\r
+  gtk_box_pack_start (GTK_BOX (hbox3), file_entry, TRUE, TRUE, 10);\r
+\r
+  hbox4 = gtk_hbox_new (FALSE, 0);\r
+  gtk_widget_show (hbox4);\r
+  gtk_box_pack_start (GTK_BOX (vertb), hbox4, FALSE, FALSE, 0);\r
+  gtk_container_set_border_width (GTK_CONTAINER (hbox4), 10);\r
+\r
+  ok_bt = gtk_button_new_with_label ("OK");\r
+  gtk_widget_show (ok_bt);\r
+  gtk_box_pack_start (GTK_BOX (hbox4), ok_bt, TRUE, FALSE, 0);\r
+  gtk_widget_set_usize (ok_bt, 60, -2);\r
+  OBJECT_SET_DATA(ok_bt, "file_entry", file_entry);\r
+  /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);\r
+  OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);\r
+  OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/\r
+  OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);\r
+  OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);\r
+  OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);\r
+\r
+  cancel_bt = gtk_button_new_with_label (" Cancel ");\r
+  gtk_widget_show (cancel_bt);\r
+  gtk_box_pack_start (GTK_BOX (hbox4), cancel_bt, TRUE, FALSE, 0);\r
+  gtk_widget_set_usize (cancel_bt, 60, -2);\r
+  \r
+  gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",\r
+               GTK_SIGNAL_FUNC(voice_close_cb), GTK_OBJECT(voice_w));\r
+  \r
+  gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",\r
+               GTK_SIGNAL_FUNC(ok_button_cb), rs);\r
+  \r
+  gtk_signal_connect(GTK_OBJECT(file_button), "clicked",\r
+               GTK_SIGNAL_FUNC(file_selection_cb), file_entry);\r
+  \r
+  gtk_widget_show(voice_w);\r
+}\r
+\r
+/* all the graphics on the window is done here */\r
+static void add_rtp_notebook(void *pri) \r
+{\r
+  info_stat *rs=pri;\r
+\r
+  GtkWidget *notebook, *page, *page_r, *label, *label1, *label2, *label3;\r
+  GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;\r
+  GtkWidget *box4, *voice_bt, *refresh_bt, *close_bn;\r
+  \r
+  gchar *titles[6] =  {"Packet nr.", "Sequence",  "Delay (s)", "Jitter (s)", "Marker", "Status"};\r
+  gchar label_forward[150];\r
+  gchar label_reverse[150];\r
+\r
+  /* XXX is it ok to use %lu for guint32? The compiler is not satisfied, but it works\r
+   * with %d the compiler is satisfied, but it doesn't work */\r
+  g_snprintf(label_forward, 149, \r
+               "Analysing connection from  %s port %u  to  %s port %u   SSRC = %u\n", \r
+               rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward);\r
+  g_snprintf(label_reverse, 149,\r
+               "Analysing connection from  %s port %u  to  %s port %u   SSRC = %u\n", \r
+               rs->destination, rs->dstport, rs->source, rs->srcport, rs->ssrc_reversed);\r
+\r
+  gtk_widget_destroy(main_vb);\r
+  main_vb = gtk_vbox_new(FALSE, 3);\r
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);\r
+  gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);\r
+  gtk_widget_show(main_vb);\r
+\r
+  /* Start a nootbook for flipping between sets of changes */\r
+  notebook = gtk_notebook_new();\r
+  gtk_container_add(GTK_CONTAINER(main_vb), notebook);\r
+  gtk_object_set_data(GTK_OBJECT(rtp_w), "notebook", notebook);\r
+\r
+  /* page for forward connection */\r
+  page = gtk_vbox_new(FALSE, 5);\r
+  gtk_container_set_border_width(GTK_CONTAINER(page), 20);\r
+\r
+  /* scrolled window */\r
+  scrolled_window = gtk_scrolled_window_new(NULL, NULL);\r
+  gtk_widget_set_usize(scrolled_window, 600, 200);\r
+  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), \r
+                                       GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);\r
+\r
+  /* direction label */\r
+  label1 = gtk_label_new(label_forward);\r
+  gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);\r
+\r
+  /* place for some statistics */\r
+  max = gtk_label_new("\n\n");\r
+  gtk_box_pack_end(GTK_BOX(page), max, FALSE, FALSE, 5);\r
+\r
+  /* clist for the information */\r
+  clist = gtk_clist_new_with_titles(6, titles);\r
+  gtk_widget_show(clist);\r
+  gtk_container_add(GTK_CONTAINER(scrolled_window), clist);\r
+  gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);\r
+\r
+  /* and the label */\r
+  label = gtk_label_new("     Forward Direction     ");\r
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);\r
+\r
+  /* column width and justification */\r
+  gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist), 4, 40);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_CENTER);\r
+\r
+  /* same page for reversed connection */\r
+  page_r = gtk_vbox_new(FALSE, 5);\r
+  gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);\r
+  scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);\r
+  gtk_widget_set_usize(scrolled_window_r, 600, 200);\r
+  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r), \r
+                               GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);\r
+  label3 = gtk_label_new(label_reverse);\r
+  gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);\r
+  max_r = gtk_label_new("\n\n");\r
+  gtk_box_pack_end(GTK_BOX(page_r), max_r, FALSE, FALSE, 5);\r
+  clist_r = gtk_clist_new_with_titles(6, titles);\r
+  gtk_widget_show(clist_r);\r
+  gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_r);\r
+  gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);\r
+  label2 = gtk_label_new("     Reversed Direction     ");\r
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);\r
+\r
+  gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist_r), 1, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist_r), 2, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist_r), 3, 80);\r
+  gtk_clist_set_column_width(GTK_CLIST(clist_r), 4, 40);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 0, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 1, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 2, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 3, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 4, GTK_JUSTIFY_CENTER);\r
+  gtk_clist_set_column_justification(GTK_CLIST(clist_r), 5, GTK_JUSTIFY_CENTER);\r
+\r
+  /* page for help&about or future \r
+  page_help = gtk_hbox_new(FALSE, 5);\r
+  label4 = gtk_label_new("     Future    ");\r
+  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);\r
+  frame = gtk_frame_new("");\r
+  text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");\r
+  gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);\r
+  gtk_container_add(GTK_CONTAINER(frame), text);\r
+  gtk_container_set_border_width(GTK_CONTAINER(frame), 20);\r
+  gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);\r
+*/\r
+  /* show all notebooks */\r
+  gtk_widget_show_all(notebook);\r
+\r
+  /* and the buttons */\r
+  box4 = gtk_hbutton_box_new();\r
+  gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, TRUE, 0);\r
+  gtk_container_set_border_width(GTK_CONTAINER(box4), 10);\r
+  gtk_button_box_set_layout(GTK_BUTTON_BOX(box4), GTK_BUTTONBOX_SPREAD);\r
+  gtk_widget_show(box4);\r
+\r
+  voice_bt = gtk_button_new_with_label("Save voice data");\r
+  gtk_container_add(GTK_CONTAINER(box4), voice_bt);\r
+  gtk_widget_show(voice_bt);\r
+  gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",\r
+               GTK_SIGNAL_FUNC(voice_cb), rs);\r
+\r
+  refresh_bt = gtk_button_new_with_label("Refresh");\r
+  gtk_container_add(GTK_CONTAINER(box4), refresh_bt);\r
+  gtk_widget_show(refresh_bt);\r
+  gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",\r
+               GTK_SIGNAL_FUNC(refresh_cb), rs);\r
+\r
+  close_bn = gtk_button_new_with_label("Close");\r
+  gtk_container_add(GTK_CONTAINER(box4), close_bn);\r
+  gtk_widget_show(close_bn);\r
+  gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",\r
+               GTK_SIGNAL_FUNC(rtp_destroy), GTK_OBJECT(rtp_w));\r
+\r
+  redissect_packets(&cfile);\r
+\r
+  draw_stat(rs);\r
+}\r
+\r
+\r
+/* when we click on the selected row it copies that ssrc value into ssrc_reversed */\r
+static void get_selected_ssrc(GtkWidget *clist_r, gint row, gint column, \r
+                                               GdkEventButton *event _U_, gpointer data)\r
+{\r
+  info_stat *rs=(info_stat *)data;\r
+  gchar *text;\r
+\r
+  gtk_clist_get_text(GTK_CLIST(clist_r), row, column, &text);\r
+  /* XXX is this strtoul portable for guint32? */\r
+  rs->ssrc_reversed = strtoul(text, (char **)NULL, 10);\r
+  return;\r
+}\r
+\r
+/* when we click apply button in ssrc reversed dialog */\r
+static void apply_selected_ssrc(GtkWidget *w _U_, gpointer data)\r
+{\r
+  info_stat *rs=(info_stat *)data;\r
+  add_rtp_notebook(rs);\r
+}\r
+\r
+/* this function goes through all the packets that have the same ip and port combination \r
+ * (only inversed) as the forward direction (XXX what if the reversed direction doesn't use \r
+ * the same ports???) and looks for different SSRC values. This can happen if you capture\r
+ * two RTP conversations one after another from the same pair of phones (PC's). \r
+ * Both have same IP's and can also have same port numbers, so they (should) differ only \r
+ * in SSRC values. In such case we get a list of ssrc values and we have to choose the right \r
+ * one from the list. If there is only one or none, we do it automatically */ \r
+static void get_reversed_ssrc(void *prs)\r
+{\r
+       info_stat *ri = prs;\r
+       GtkWidget *scroll_r, *clist_r, *ok_bt, *label, *label2, *label1, *main_hbnbox;\r
+       gchar temp[150];\r
+       guint i;\r
+\r
+       switch(ri->reversed_ip_and_port)\r
+       {\r
+               /* in case we haven't found any reversed ssrc */\r
+               /* XXX in this case we could look for the inversed IP only */\r
+               case 0: {\r
+                       ri->ssrc_reversed = 0;\r
+                       ri->search_ssrc = FALSE;\r
+                       add_rtp_notebook(ri);\r
+                       return;\r
+               }\r
+               /* in case we found exactly one matching ssrc for reversed connection */ \r
+               case 1: { \r
+                       ri->ssrc_reversed = ri->ssrc_tmp[0];\r
+                       ri->search_ssrc = FALSE;\r
+                       add_rtp_notebook(ri);\r
+                       return;\r
+               }\r
+               /* there is more then one matching ssrc, so we have to choose between them */\r
+               default: {\r
+                       ri->search_ssrc = FALSE;\r
+                       /* let's draw the window */\r
+                       label = gtk_label_new("Found more SSRC values for the reversed\n"\r
+                                                "connection with following parameters:\n");\r
+                       g_snprintf(temp, 149, "Source %s port %u Destination %s port %u", \r
+                                       ri->destination, ri->dstport, ri->source, ri->srcport);\r
+                       label2 = gtk_label_new(temp);\r
+                       gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE, FALSE, 0);\r
+                       gtk_box_pack_start(GTK_BOX(main_vb), label2, FALSE, FALSE, 0);\r
+                       scroll_r = gtk_scrolled_window_new(NULL, NULL);\r
+                       gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_r), \r
+                                               GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);\r
+                       clist_r = gtk_clist_new(1);\r
+                       gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);\r
+                       gtk_container_add(GTK_CONTAINER(scroll_r), clist_r);\r
+                       gtk_box_pack_start(GTK_BOX(main_vb), scroll_r, TRUE, TRUE, 0);\r
+                       label1 = gtk_label_new("Select one value and click apply");\r
+                       gtk_box_pack_start(GTK_BOX(main_vb), label1, FALSE, FALSE, 0);\r
+\r
+                       main_hbnbox = gtk_hbutton_box_new();\r
+                       gtk_box_pack_start(GTK_BOX(main_vb), main_hbnbox, FALSE, TRUE, 0);\r
+                       gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);\r
+                       gtk_button_box_set_layout(GTK_BUTTON_BOX(main_hbnbox), \r
+                                                               GTK_BUTTONBOX_SPREAD);\r
+                       gtk_widget_show(main_hbnbox);\r
+\r
+                       ok_bt = gtk_button_new_with_label("Apply");\r
+                       gtk_container_add(GTK_CONTAINER(main_hbnbox), ok_bt);\r
+                       gtk_signal_connect(GTK_OBJECT(clist_r), "select_row", \r
+                                       GTK_SIGNAL_FUNC(get_selected_ssrc), ri);\r
+                       gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked", \r
+                                       GTK_SIGNAL_FUNC(apply_selected_ssrc), ri);\r
+\r
+                       /* add all the ssrc values in the clist */\r
+                       /* XXX I'm sure the tmp variable could be avoided here\r
+                        * i tried to assign guint32 from ri->ssrc_tmp somehow to gchar **text\r
+                        * but gave up. So if you can do this, just go ahead */\r
+                       for (i=0; i < ri->reversed_ip_and_port; i++) {\r
+                               gchar *text[0];\r
+                               gchar tmp[20];\r
+                               g_snprintf(tmp, 20, "%u", ri->ssrc_tmp[i]);\r
+                               text[0] = (gchar *)&tmp;\r
+                               gtk_clist_append(GTK_CLIST(clist_r), text);\r
+                       }\r
+                       \r
+                       gtk_clist_select_row(GTK_CLIST(clist_r), 0, 0);\r
+\r
+                       gtk_widget_show(label);\r
+                       gtk_widget_show(label1);\r
+                       gtk_widget_show(label2);\r
+                       gtk_widget_show(ok_bt);\r
+                       gtk_widget_show(clist_r);\r
+                       gtk_widget_show(scroll_r);\r
+               }\r
+       }\r
+}\r
+\r
+/* when the user clicks the RTP dialog button */\r
+void rtp_analyse_cb(GtkWidget *w _U_, gpointer data _U_) \r
+{ \r
+  info_stat *rs;\r
+  gchar filter_text[]="rtp";\r
+  dfilter_t *sfcode;\r
+  capture_file *cf;\r
+  epan_dissect_t *edt;\r
+  gint err;\r
+  gboolean frame_matched;\r
+  frame_data *fdata;\r
+\r
+  /* There's already a "Display Options" dialog box; reactivate it. */\r
+  if (rtp_w != NULL) {\r
+       reactivate_window(rtp_w);\r
+       return;\r
+  }\r
+\r
+  /* Try to compile the filter. */\r
+  if (!dfilter_compile(filter_text, &sfcode)) {\r
+       simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);\r
+       return;\r
+  }\r
+  /* we load the current file into cf variable */\r
+  cf = &cfile;\r
+  fdata = cf->current_frame;\r
+\r
+  /* we are on the selected frame now */\r
+  if (fdata == NULL)\r
+       return; /* if we exit here it's an error */\r
+\r
+  /* XXX instead of looking for RTP protocol like this, we could do the process_node() staff */\r
+  /* dissect the current frame */\r
+  wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err);\r
+  edt = epan_dissect_new(TRUE, FALSE);\r
+  epan_dissect_prime_dfilter(edt, sfcode);\r
+  epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);\r
+  frame_matched = dfilter_apply_edt(sfcode, edt);\r
+\r
+  /* if it is not an rtp frame, exit */\r
+  frame_matched = dfilter_apply_edt(sfcode, edt);\r
+  if (frame_matched != 1) {\r
+       epan_dissect_free(edt);\r
+       simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a RTP packet!");\r
+       return;\r
+       }\r
+\r
+  /* in rs we put all the info */\r
+  rs=g_malloc(sizeof(info_stat));      \r
+\r
+  /* ok, it is a RTP frame, so let's get the ip and port values */\r
+  rs->srcport = edt->pi.srcport;\r
+  rs->dstport = edt->pi.destport;\r
+  strncpy(rs->source, ip_to_str(edt->pi.src.data), 16);  \r
+  strncpy(rs->destination, ip_to_str(edt->pi.dst.data), 16);  \r
+\r
+  /* now we need the SSRC value of the current frame */\r
+  rs->ssrc_forward = process_tree(edt->tree);\r
+  if (rs->ssrc_forward == 0) {\r
+       simple_dialog(ESD_TYPE_CRIT, NULL, "SSRC value couldn't be found!");\r
+       return;\r
+  }\r
+\r
+  /* now we have all the information about the forwarding connection\r
+   * we need to go through all the packets and search for reversed connection\r
+   */\r
+  rs->search_ssrc = TRUE;\r
+  rs->ssrc_reversed = 0;       \r
+  rs->reversed_ip = 0;\r
+  rs->reversed_ip_and_port = 0;\r
+  rs->ssrc_tmp = NULL;\r
+\r
+/* XXX compiler warning:passing arg 5 of `register_tap_listener' from incompatible pointer type */\r
+  if(register_tap_listener("rtp", rs, NULL, rtp_reset, rtp_packet, rtp_draw)){\r
+       printf("ethereal: rtp_init() failed to attach the tap.\n");\r
+       /* XXX is this enough or do I have to free anything else? */\r
+       g_free(rs);\r
+       exit(1);\r
+  }\r
+\r
+  /* let's draw the window */\r
+  rtp_w = dlg_window_new("Ethereal: RTP Analyse");\r
+  gtk_window_set_position (GTK_WINDOW (rtp_w), GTK_WIN_POS_CENTER);\r
+  gtk_signal_connect(GTK_OBJECT(rtp_w), "destroy",\r
+       GTK_SIGNAL_FUNC(rtp_destroy_cb), rs);\r
+\r
+  /* Container for each row of widgets */\r
+  main_vb = gtk_vbox_new(FALSE, 3);\r
+  gtk_container_border_width(GTK_CONTAINER(main_vb), 5);\r
+  gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);\r
+  gtk_widget_show(main_vb);\r
+\r
+  /* file names for storing sound data */\r
+  tmpnam(f_tempname);\r
+  tmpnam(r_tempname);\r
+  rs->f_fp = NULL;\r
+  rs->r_fp = NULL;\r
+\r
+  redissect_packets(cf);\r
+\r
+  /* so how many reversed connection we have ? */\r
+  get_reversed_ssrc(rs);\r
+\r
+  /* and finally display this window */\r
+  gtk_widget_show(rtp_w);\r
+}\r
+\r
+static void\r
+rtp_analyse_init(char *dummy _U_)\r
+{\r
+       rtp_analyse_cb(NULL, NULL);\r
+}\r
+\r
+/* XXX compiler warning:passing arg 2 of `register_ethereal_tap' from incompatible pointer type */\r
+void\r
+register_tap_listener_gtkrtp(void)\r
+{\r
+       register_ethereal_tap("rtp", rtp_analyse_init, NULL, NULL);\r
+}\r
+\r
+\r
+/* here we save it into a file that user specified */\r
+/* XXX what about endians here? could go something wrong? */\r
+static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ void *data)\r
+{\r
+       info_stat *rs=(info_stat *)data;\r
+       int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;\r
+       gint16 f_pd;\r
+       gint16 r_pd;\r
+       gchar pd[1];\r
+       guint32 f_write_silence = 0;\r
+       guint32 r_write_silence = 0;\r
+       progdlg_t *progbar;\r
+       guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;\r
+       gboolean stop_flag = FALSE;\r
+\r
+       forw_fd = open(f_tempname, O_RDONLY | 0);\r
+       if (forw_fd < 0) \r
+               return FALSE;\r
+       rev_fd = open(r_tempname, O_RDONLY | 0);\r
+       if (rev_fd < 0) {\r
+               close(forw_fd); \r
+               return FALSE;\r
+       }\r
+\r
+       /* open file for saving */\r
+       to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | 0, 0644);\r
+       if (to_fd < 0) {\r
+               close(forw_fd);\r
+               close(rev_fd);\r
+               return FALSE;\r
+       }\r
+\r
+       progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);\r
+\r
+       /* First we write the .au header. XXX Hope this is endian independant */\r
+       /* the magic word 0x2e736e64 == .snd */\r
+       *pd = (unsigned char)0x2e; write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x73; write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x6e; write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x64; write(to_fd, pd, 1);\r
+       /* header offset == 24 bytes */\r
+       *pd = (unsigned char)0x00; write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x18; write(to_fd, pd, 1);\r
+       /* total length, it is permited to set this to 0xffffffff */\r
+       *pd = (unsigned char)0xff; write(to_fd, pd, 1); \r
+       write(to_fd, pd, 1); \r
+       write(to_fd, pd, 1); \r
+       write(to_fd, pd, 1);\r
+       /* encoding format == 8 bit ulaw */\r
+       *pd = (unsigned char)0x00; write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x01; write(to_fd, pd, 1);\r
+       /* sample rate == 8000 Hz */\r
+       *pd = (unsigned char)0x00; write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x1f; write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x40; write(to_fd, pd, 1);\r
+       /* channels == 1 */\r
+       *pd = (unsigned char)0x00; write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       write(to_fd, pd, 1);\r
+       *pd = (unsigned char)0x01; write(to_fd, pd, 1);\r
+       \r
+       switch (channels) {\r
+               /* only forward direction */\r
+               case 1: {\r
+                       progbar_count = rs->f_count;\r
+                       progbar_quantum = rs->f_count/100;\r
+                       while ((fread = read(forw_fd, &f_pd, 2)) > 0) {\r
+                               if(stop_flag) \r
+                                       break;\r
+                               if((count > progbar_nextstep) && (count <= progbar_count)) {\r
+                                       update_progress_dlg(progbar, \r
+                                               (gfloat) count/progbar_count, "Saving");\r
+                                       progbar_nextstep = progbar_nextstep + progbar_quantum;\r
+                               }\r
+                               count++;\r
+                               *pd = (unsigned char)linear2ulaw(f_pd);\r
+                               fwritten = write(to_fd, pd, 1);\r
+                               if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {\r
+                                       close(forw_fd);\r
+                                       close(rev_fd);\r
+                                       close(to_fd);\r
+                                       destroy_progress_dlg(progbar);\r
+                                       return FALSE;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+               /* only reversed direction */\r
+               case 2: {\r
+                       progbar_count = rs->r_count;\r
+                       progbar_quantum = rs->r_count/100;\r
+                       while ((rread = read(rev_fd, &r_pd, 2)) > 0) {\r
+                               if(stop_flag) \r
+                                       break;\r
+                               if((count > progbar_nextstep) && (count <= progbar_count)) {\r
+                                       update_progress_dlg(progbar, \r
+                                               (gfloat) count/progbar_count, "Saving");\r
+                                       progbar_nextstep = progbar_nextstep + progbar_quantum;\r
+                               }\r
+                               count++;\r
+                               *pd = (unsigned char)linear2ulaw(r_pd);\r
+                               rwritten = write(to_fd, pd, 1);\r
+                               if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {\r
+                                       close(forw_fd);\r
+                                       close(rev_fd);\r
+                                       close(to_fd);\r
+                                       destroy_progress_dlg(progbar);\r
+                                       return FALSE;\r
+                               }\r
+                       }\r
+                       break;\r
+               }\r
+               /* both directions */\r
+               default: {\r
+                       (rs->f_count > rs->r_count) ? (progbar_count = rs->f_count) : \r
+                                                               (progbar_count = rs->r_count);\r
+                       progbar_quantum = progbar_count/100;\r
+                       /* since conversation in one way can start later than in the other one, \r
+                        * we have to write some silence information for one channel */\r
+                       if (rs->f_start_time > rs->r_start_time) {\r
+                               f_write_silence = (rs->f_start_time-rs->r_start_time)*8000;\r
+                       }\r
+                       else if (rs->f_start_time < rs->r_start_time) {\r
+                               r_write_silence = (rs->r_start_time-rs->f_start_time)*8000;\r
+                       }\r
+                       for(;;) {\r
+                               if(stop_flag) \r
+                                       break;\r
+                               if((count > progbar_nextstep) && (count <= progbar_count)) {\r
+                                       update_progress_dlg(progbar, \r
+                                               (gfloat) count/progbar_count, "Saving");\r
+                                       progbar_nextstep = progbar_nextstep + progbar_quantum;\r
+                               }\r
+                               count++;\r
+                               if(f_write_silence > 0) {\r
+                                       rread = read(rev_fd, &r_pd, 2);\r
+                                       f_pd = 0;\r
+                                       fread = 1;\r
+                                       f_write_silence--;\r
+                               }\r
+                               else if(r_write_silence > 0) {\r
+                                       fread = read(forw_fd, &f_pd, 2);\r
+                                       r_pd = 0;\r
+                                       rread = 1;\r
+                                       r_write_silence--;\r
+                               }\r
+                               else {\r
+                                       fread = read(forw_fd, &f_pd, 2); \r
+                                       rread = read(rev_fd, &r_pd, 2);\r
+                               }\r
+                               if ((rread == 0) && (fread == 0)) \r
+                                       break;\r
+                               *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );\r
+                               rwritten = write(to_fd, pd, 1);\r
+                               if ((rwritten < 0) || (rread < 0) || (fread < 0)) {\r
+                                       close(forw_fd);\r
+                                       close(rev_fd);\r
+                                       close(to_fd);\r
+                                       destroy_progress_dlg(progbar);\r
+                                       return FALSE;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       destroy_progress_dlg(progbar);\r
+       close(forw_fd);\r
+       close(rev_fd);\r
+       close(to_fd);\r
+       return TRUE;\r
+\r
+}\r
+\r
diff --git a/gtk/tap_rtp.h b/gtk/tap_rtp.h
new file mode 100644 (file)
index 0000000..cb4d668
--- /dev/null
@@ -0,0 +1,27 @@
+/*\r
+ * tap_rtp.h\r
+ *\r
+ * Declaration for rtp analysing tool\r
+ *\r
+ * Copyright 2003, Iskratel, Ltd, Kranj\r
+ * By Miha Jemec <m.jemec@iskratel.si>\r
+ *\r
+ * Ethereal - Network traffic analyzer\r
+ * By Gerald Combs <gerald@ethereal.com>\r
+ * Copyright 1998 Gerald Combs\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation,  Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+*/\r
+void rtp_analyse_cb(GtkWidget *, gpointer);\r
index b95fd6258d100a7daece798252d8553cb5c682c4..8439e0854cd124f0ac085447c1c98bb9fb6aa737 100644 (file)
@@ -6,7 +6,7 @@
  * Copyright 2000, Philips Electronics N.V.
  * Written by Andreas Sikkema <andreas.sikkema@philips.com>
  *
- * $Id: packet-rtp.c,v 1.37 2003/02/28 22:03:08 guy Exp $
+ * $Id: packet-rtp.c,v 1.38 2003/03/06 20:35:09 sahlberg Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -63,6 +63,9 @@
 
 #include "packet-rtp.h"
 #include <epan/conversation.h>
+#include "tap.h"
+
+static int rtp_tap = -1;
 
 /* RTP header fields             */
 static int proto_rtp           = -1;
@@ -349,6 +352,8 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
        guint32     sync_src;
        guint32     csrc_item;
 
+       static struct _rtp_info rtp_info;
+
        /* Get the fields in the first octet */
        octet = tvb_get_guint8( tvb, offset );
        version = RTP_VERSION( octet );
@@ -390,6 +395,16 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
        timestamp = tvb_get_ntohl( tvb, offset + 4 );
        sync_src = tvb_get_ntohl( tvb, offset + 8 );
 
+       /* fill in the rtp_info structure */ 
+       rtp_info.info_padding_set = padding_set;
+       rtp_info.info_padding_count = 0;
+       rtp_info.info_marker_set = marker_set;
+       rtp_info.info_payload_type = payload_type;
+       rtp_info.info_seq_num = seq_num;
+       rtp_info.info_timestamp = timestamp;
+       rtp_info.info_sync_src = sync_src;
+       rtp_info.info_data_len = tvb_reported_length_remaining( tvb, offset );
+
        if ( check_col( pinfo->cinfo, COL_PROTOCOL ) )   {
                col_set_str( pinfo->cinfo, COL_PROTOCOL, "RTP" );
        }
@@ -404,7 +419,6 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
                    timestamp,
                    marker_set ? ", Mark" : "");
        }
-
        if ( tree ) {
                ti = proto_tree_add_item( tree, proto_rtp, tvb, offset, -1, FALSE );
                rtp_tree = proto_item_add_subtree( ti, ett_rtp );
@@ -555,6 +569,7 @@ dissect_rtp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree )
                            payload_type );
                }
        }
+       tap_queue_packet(rtp_tap, pinfo, &rtp_info);
 }
 
 void
@@ -770,6 +785,7 @@ proto_register_rtp(void)
        proto_register_subtree_array(ett, array_length(ett));
 
        register_dissector("rtp", dissect_rtp, proto_rtp);
+       rtp_tap = register_tap("rtp");
 
 #if 0
        register_init_routine( &rtp_init );
index 4eecb3d26ff32e3b5fb19f31fc1ee3788cb292eb..bd9dd967725537aede1258e5213b428056de950c 100644 (file)
@@ -3,7 +3,7 @@
  * Routines for RTP dissection
  * RTP = Real time Transport Protocol
  *
- * $Id: packet-rtp.h,v 1.7 2002/08/28 21:00:30 jmayer Exp $
+ * $Id: packet-rtp.h,v 1.8 2003/03/06 20:35:09 sahlberg Exp $
  *
  * Copyright 2000, Philips Electronics N.V.
  * Written by Andreas Sikkema <andreas.sikkema@philips.com>
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
+struct _rtp_info {
+       gboolean        info_padding_set;
+       gboolean        info_marker_set;
+       unsigned int    info_payload_type;
+       unsigned int    info_padding_count;
+       guint16         info_seq_num;
+       guint32         info_timestamp;
+       guint32         info_sync_src;
+       guint           info_data_len;
+};
+
 void     rtp_add_address   ( packet_info *pinfo, const unsigned char* ip_addr, int prt );
 void     proto_register_rtp( void );