aboutsummaryrefslogtreecommitdiffstats
path: root/gtk/tap_rtp.c
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2003-03-06 23:09:09 +0000
committerGuy Harris <guy@alum.mit.edu>2003-03-06 23:09:09 +0000
commit60ab93fa9712b7a266a8e2f4247c1c3dcf7659c6 (patch)
tree8fa0fc8fdb3e50b63ffd05b0a0885904647f396e /gtk/tap_rtp.c
parente431a83cde4c2dd91a62c6c0b27d9b51ea4525ae (diff)
Get rid of CRs.
Get rid of comments about the format string to use with guint16 and guint32 - we're using the right string, which is neither "%lu" (as that requires a 64-bit argument on platforms with 64-bit longs) nor "%d" (as that expects a *signed* quantity, not an *unsigned* quantity), but "%u". Protect the include of <unistd.h> with "#ifdef HAVE_UNISTD_H", as it's not present on Windows if you're not building with a UNIXalike wrapper library. Use "wb", not "w", when creating binary files with "fopen()"; the "b" is required on Windows. Use O_BINARY when opening binary files, and #define it as 0 if it's not defined; O_BINARY is required on Windows. svn path=/trunk/; revision=7303
Diffstat (limited to 'gtk/tap_rtp.c')
-rw-r--r--gtk/tap_rtp.c3998
1 files changed, 1999 insertions, 1999 deletions
diff --git a/gtk/tap_rtp.c b/gtk/tap_rtp.c
index 280582409f..1b29da51ea 100644
--- a/gtk/tap_rtp.c
+++ b/gtk/tap_rtp.c
@@ -1,1999 +1,1999 @@
-/*
- * tap_rtp.c
- *
- * $Id: tap_rtp.c,v 1.2 2003/03/06 21:15:59 deniel Exp $
- *
- * RTP analysing addition for ethereal
- *
- * Copyright 2003, Iskratel, Ltd, Kranj
- * By Miha Jemec <m.jemec@iskratel.si>
- *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
- * Copyright 1998 Gerald Combs
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * This tap works as follows:
- * When the user clicks on the RTP analisys button, we first check if it is a RTP packet.
- * If yes we store the SSRC, ip, and port values. Then the tap is registered and the
- * redissect_packets() routine is called. So we go through all the RTP packets and search
- * for SSRC of reversed connection (it has inversed socket parameters). If more than one
- * is found a window is displayed where the user can select the appropriate from the list.
- * Rigth now we have the information about the converstion we are looking for (both SSRC).
- * The redissect_packets() routine is called again. This time whenever a RTP packet with
- * matching SSRC values arrives, we store all the information we need (number, sequence
- * number, arrival time, ...) and compute the delay, jitter and wrong sequence number.
- * We add this values to CList. If the RTP packet carries voice in g711 alaw or ulaw, we
- * also store this voice information in a temp file. Window is displayed.
- * Then three buttons are available: Close, Refresh and Save voice.
- * The Refresh button calls the redissect_packets() routine again. It goes through the packets
- * again and does all the calculation again (if capturing in real time this means that some
- * more packets could come and can be computed in statistic). It also writes the sound
- * data again.
- * The Save voice button opens the dialog where we can choose the file name, format (not yet)
- * and direction we want to save. Currently it works only with g711 alaw and ulaw, and if the
- * length of captured packets is equal the length of packets on wire and if there are no padding
- * bits.
- *
- * To do:
- * - Support for saving voice in more different formats and with more different codecs:
- * Since this should be portable to all OS, there is only possibility to save the
- * voice in a file and not play it directly through the sound card. There are enough
- * players on all platforms, that are doing right this. What about the format?
- * Currently there is only support for saving as an .au file (ulaw, 8000 Hz, 8bit)
- * There are many players for this format on all platforms (for example Windows Media Player
- * under Windows, command play under Linux). Support will be added for wav format and
- * possibility to save with two channels (separate channel for each direction)
- *
- * - Support for more codecs. Now you can save voice only if the codec is g.711 alaw or ulaw.
- *
- * - right now, the reversed connection must have the same (only inversed) ip and port numbers.
- * I think that there is no reason that in special cases the reversed connection would not use
- * some different port or even the IP combination (please correct me if I am wrong).
- * So this will be added soon.
- *
- * - some more statistics (delay and jitter distribution)
- *
- * - GTK2 implementation
- *
- * - grammar correction
- *
- * - some more testing (other OS)
- *
- * XXX Problems:
- *
- * - how to use snprintf (or g_snprintf) with guint16, guint32 ? If I put %lu for guint32
- * then compiler makes a warning but it works. If I put %d for guint32,
- * then compiler doesn't warns, but then it doesn't work
- *
- * - instead of tmpnam() use of mkstemp().
- * I tried to do it with mkstemp() but didn't now how to solve following problem:
- * I call mkstemp() and then write in this temp file and it works fine . But if the user
- * then hits the refresh button, this temp file should be deleted and opened again. I tried
- * to call close() and unlink(), but when I call mkstemp() for the second time I always get
- * an error ( -1) as return value. What is the correct order? Is it possible to call
- * mkstemp() twice with the same template?
- *
- * - problem with statistics for lost (late, duplicated) packets. How to make the statistic
- * more resistant to special (bizarre) arrival of sequence numbers
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdio.h>
-
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-
-#include <gtk/gtk.h>
-#include "tap_rtp.h"
-#include "globals.h"
-#include <string.h>
-#include "epan/packet_info.h"
-#include <epan/epan_dissect.h>
-#include <epan/filesystem.h>
-#include "../tap.h"
-#include "../register.h"
-#include "../packet-rtp.h"
-#include "file_dlg.h"
-#include "dlg_utils.h"
-#include "ui_util.h"
-#include "simple_dialog.h"
-#include "main.h"
-#include <math.h>
-#include "progress_dlg.h"
-#include "compat_macros.h"
-#include "../g711.h"
-#include <unistd.h>
-#include <fcntl.h>
-
-static GtkWidget *rtp_w = NULL;
-static GtkWidget *voice_w = NULL;
-static GtkWidget *save_w = NULL;
-static GtkWidget *main_vb;
-static GtkWidget *clist;
-static GtkWidget *clist_r;
-static GtkWidget *max;
-static GtkWidget *max_r;
-
-static gboolean copy_file(gchar *, /*gint,*/ gint, void *);
-
-char f_tempname[100], r_tempname[100];
-
-/* type of error when saving voice in a file didn't succeed */
-typedef enum {
- WRONG_CODEC,
- WRONG_LENGTH,
- PADDING_SET,
- FILE_OPEN_ERROR,
- NO_DATA
-} error_type_t;
-
-/* structure that holds the information about the forwarding and reversed connection */
-/* f_* always aplies to the forward direction and r_* to the reversed */
-typedef struct _info_stat {
- gchar source[16];
- gchar destination[16];
- guint16 srcport;
- guint16 dstport;
- guint32 ssrc_forward;
- guint32 ssrc_reversed;
- guint32 *ssrc_tmp;
- gboolean search_ssrc;
- guint reversed_ip;
- guint reversed_ip_and_port;
- gboolean f_first_packet;
- gboolean r_first_packet;
- guint16 f_seq_num;
- guint16 r_seq_num;
- guint32 f_timestamp;
- guint32 r_timestamp;
- guint32 f_delta_timestamp;
- guint32 r_delta_timestamp;
- double f_delay;
- double r_delay;
- double f_jitter;
- double r_jitter;
- double f_time;
- double r_time;
- double f_start_time;
- double r_start_time;
- double f_max_delay;
- double r_max_delay;
- guint32 f_max_nr;
- guint32 r_max_nr;
- guint16 f_start_seq_nr;
- guint16 r_start_seq_nr;
- guint16 f_stop_seq_nr;
- guint16 r_stop_seq_nr;
- guint32 f_total_nr;
- guint32 r_total_nr;
- guint32 f_sequence;
- guint32 r_sequence;
- gint f_cycles;
- gint r_cycles;
- gboolean f_under;
- gboolean r_under;
- FILE *f_fp;
- FILE *r_fp;
- gboolean f_saved;
- gboolean r_saved;
- error_type_t f_error_type;
- error_type_t r_error_type;
- guint32 f_count;
- guint32 r_count;
-} info_stat;
-
-
-/* when there is a [re]reading of packet's */
-static void
-rtp_reset(void *prs)
-{
- info_stat *rs=prs;
-
- rs->f_first_packet = TRUE;
- rs->r_first_packet = TRUE;
- rs->f_max_delay = 0;
- rs->r_max_delay = 0;
- rs->f_max_nr = 0;
- rs->r_max_nr = 0;
- rs->f_total_nr = 0;
- rs->r_total_nr = 0;
- rs->f_sequence = 0;
- rs->r_sequence = 0;
- rs->f_start_seq_nr = 0;
- rs->r_start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
- rs->f_stop_seq_nr = 0;
- rs->r_stop_seq_nr = 0;
- rs->f_cycles = 0;
- rs->r_cycles = 0;
- rs->f_under = FALSE;
- rs->r_under = FALSE;
- rs->f_saved = FALSE;
- rs->r_saved = FALSE;
- rs->f_start_time = 0;
- rs->r_start_time = 0;
- rs->f_count = 0;
- rs->r_count = 0;
- /* XXX check for error at fclose? */
- if (rs->f_fp != NULL)
- fclose(rs->f_fp);
- if (rs->r_fp != NULL)
- fclose(rs->r_fp);
- rs->f_fp = fopen(f_tempname, "w");
- if (rs->f_fp == NULL)
- rs->f_error_type = FILE_OPEN_ERROR;
- rs->r_fp = fopen(r_tempname, "w");
- if (rs->r_fp == NULL)
- rs->r_error_type = FILE_OPEN_ERROR;
- return;
-}
-
-/* here we can redraw the output */
-/* not used yet */
-static void rtp_draw(void *prs _U_)
-{
- return;
-}
-
-/* when we are finished with redisection, we add the label for the statistic */
-static void draw_stat(void *prs)
-{
- info_stat *rs=prs;
- gchar label_max[200];
- guint32 f_expected = (rs->f_stop_seq_nr + rs->f_cycles*65536) - rs->f_start_seq_nr + 1;
- guint32 r_expected = (rs->r_stop_seq_nr + rs->r_cycles*65536) - rs->r_start_seq_nr + 1;
- gint32 f_lost = f_expected - rs->f_total_nr;
- gint32 r_lost = r_expected - rs->r_total_nr;
-
- g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
- "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
- " Sequence error = %u",
- rs->f_max_delay, rs->f_max_nr, rs->f_total_nr, f_expected,
- f_lost, rs->f_sequence);
-
- gtk_label_set_text(GTK_LABEL(max), label_max);
-
- g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
- "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
- " Sequence error = %u",
- rs->r_max_delay, rs->r_max_nr, rs->r_total_nr, r_expected,
- r_lost, rs->r_sequence);
-
- gtk_label_set_text(GTK_LABEL(max_r), label_max);
-
- /* could be done somewhere else, but can be here as well */
- /* if this is true, then we don't have any reversed connection, so the error type
- * will be no data. This applies only the reversed connection */
- if (rs->reversed_ip_and_port == 0)
- rs->r_error_type = NO_DATA;
-
- return ;
-}
-
-/* append a line to clist */
-/* XXX is there a nicer way to make these assignements? */
-static void add_to_clist(gboolean forward, guint32 number, guint16 seq_num,
- double delay, double jitter, gboolean status, gboolean marker)
-{
- gchar *data[6];
- gchar field[6][30];
-
- data[0]=&field[0][0];
- data[1]=&field[1][0];
- data[2]=&field[2][0];
- data[3]=&field[3][0];
- data[4]=&field[4][0];
- data[5]=&field[5][0];
-
- g_snprintf(field[0], 20, "%u", number);
- g_snprintf(field[1], 20, "%u", seq_num);
- g_snprintf(field[2], 20, "%f", delay);
- g_snprintf(field[3], 20, "%f", jitter);
- g_snprintf(field[4], 20, "%s", marker? "SET" : "");
- g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");
-
- gtk_clist_append(GTK_CLIST(forward? clist : clist_r), data);
-
-}
-
-/* whenever a RTP packet is seen by the tap listener */
-/* this function works as follows:
- * 1) packets that are not displayed are ignored
- * return
- * 2) are we searching what could be the reversed connection (looking for reversed SSRC)
- * if yes, do the parameters match (inversed IP and port combination from the forward one)?
- * if yes, do we already have this SSRC stored
- * if not store it
- * 3) if not, is current packet matching the forward direction
- * is it the first time we see a packet in this direction
- * if yes, store some values, add a line to list and save the voice info
- * in a temporary file if the codec is supported and the RTP data is ok
- * if not, is it a packet with mark bit set (there was silence surpression)
- * same as above, only we have to add some silence in front of the voice data
- * if not, then this must be a normal packet
- * store the values and voice data
- * 4) if not, is current packet matching the reversed connection
- * (same as for number 3)
- */
-static int rtp_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *vpri)
-{
- info_stat *rs=prs;
- struct _rtp_info *pri=vpri;
- guint i;
- double n_time;
- double n_jitter;
- guint8 *data;
- gint16 tmp;
-
- /* we ignore packets that are not displayed */
- if (pinfo->fd->flags.passed_dfilter == 0)
- return 0;
-
- /* are we looking for the SSRC of the reversed connection? */
- if (rs->search_ssrc != FALSE) {
- /* XXX what should be the rules for reversed connection?
- * 1. It should should have same inversed IP and port numbers
- * 2. If none are found, only inversed IP's - is this possible?
- * 3. If none are found, there isn't any reversed connection
- * XXX is it possible that the conversation is not P2P?
- * Curretly it works only if it matches the number 1. */
-
- /* have we found inverse parameters? */
- if ( strcmp(ip_to_str(pinfo->src.data), rs->destination) == 0 &&
- strcmp( ip_to_str(pinfo->dst.data), rs->source) == 0 ) {
-
- /* do the ports also match? */
- if ((rs->srcport == pinfo->destport) && (rs->dstport == pinfo->srcport)) {
- /* ok, the ip and port combination does match
- * do we already have this ssrc stored */
- for(i=0; i< rs->reversed_ip_and_port; i++) {
- if (pri->info_sync_src == *(rs->ssrc_tmp+i) )
- return 0;
- }
-
- /* no, we found new ssrc, let's store it */
- rs->ssrc_tmp = (guint32*)g_realloc(rs->ssrc_tmp,
- (i+1)*sizeof(guint32));
- *(rs->ssrc_tmp+i) = pri->info_sync_src;
- rs->reversed_ip_and_port++;
- return 0;
- }
- /* no, only ip addresses match */
- /* XXX not implemented yet */
- else {
- rs->reversed_ip++;
- return 0;
- }
-
- }
- }
-
- /* ok, we are not looking for SSRC of the reversed connection */
- /* is it the forward direction?
- * if yes, there 3 possibilities:
- * a) is this the first packet we got in this direction?
- * b) or is it a packet with the mark bit set?
- * c) if neither then it is a "normal" packet */
- else if (rs->ssrc_forward == pri->info_sync_src) {
- /* first packet? */
- if (rs->f_first_packet != FALSE) {
- /* we store all the values */
- rs->f_seq_num = pri->info_seq_num;
- rs->f_delay = 0;
- rs->f_jitter = 0;
- rs->f_first_packet = FALSE;
- rs->f_timestamp = pri->info_timestamp;
- rs->f_start_seq_nr = pri->info_seq_num;
- rs->f_stop_seq_nr = pri->info_seq_num;
- rs->f_total_nr++;
- rs->f_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- rs->f_start_time = rs->f_time;
- /* and add a row to clist; delay and jitter are 0 for the first packet */
- add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
-
- /* and now save the voice info */
-
- /* if we couldn't open the tmp file for writing, then we set the flag */
- if (rs->f_fp == NULL) {
- rs->f_saved = FALSE;
- rs->f_error_type = FILE_OPEN_ERROR;
- return 0;
- }
- /* if the captured length and packet length aren't equal, we quit
- * because there is some information missing */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->f_saved = FALSE;
- rs->f_error_type = PADDING_SET;
- return 0;
- }
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- /* we put the pointer at the beggining of the RTP data, that is
- * at the end of the current frame minus the length of the
- * RTP field plus 12 for the RTP header */
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- rs->f_saved = TRUE;
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- rs->f_saved = TRUE;
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_CODEC;
- return 0;
- }
- }
-
- /* packet with mark bit set? */
- if (pri->info_marker_set != FALSE) {
- n_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- /* jitter is calculated as for RCTP - RFC 1889
- * J = J + ( | D(i-1, i) | - J) / 16
- * XXX the output there should be in timestamp (probably miliseconds)
- * units expressed as an unsigned integer, so should we do it the same?
- * (currently we use seconds)
- *
- * XXX Packet loss in RTCP is calculated as the difference between the
- * number of packets expected and actually received, where for actually
- * received the number is simply the count of packets as they arrive,
- * including any late or duplicate packets (this means that the number
- * can be negative). For example, if the seq numbers of the arrived
- * packets are: 1,2,3,4,5,5,7,7,9,10 the expected number is 10 and the
- * the number of actually captured frames is also 10. So in upper
- * calculation there would be no losses. But there are 2 losses and
- * 2 duplicate packets. Because this kind of statistic is rather
- * useless (or confusing) we add the information, that there was
- * an error with sequence number each time the sequence number was
- * not one bigger than the previous one
- */
-
- /* jitter calculation */
- n_jitter = rs->f_jitter + ( fabs(n_time-(rs->f_time) -
- ((double)(pri->info_timestamp)-
- (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
-
- /* we add the information into the clist */
- add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
- n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
-
- /* when calculating expected rtp packets the seq number can wrap around
- * so we have to count the number of cycles
- * f_cycles counts the wraps around in forwarding connection and
- * f_under is flag that indicates where we are
- *
- * XXX how to determine number of cycles with all possible lost, late
- * and duplicated packets without any doubt? It seems to me, that
- * because of all possible combination of late, duplicated or lost
- * packets, this can only be more or less good approximation
- *
- * There are some combinations (rare but theoretically possible),
- * where below code won't work correctly - statistic may be wrong then.
- */
-
- /* so if the current sequence number is less than the start one
- * we assume, that there is another cycle running */
- if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
- rs->f_cycles++;
- rs->f_under = TRUE;
- }
- /* what if the start seq nr was 0. Then the above condition will never
- * be true, so we add another condition. XXX The problem would arise if
- * if one of the packets with seq nr 0 or 65535 would be lost or late */
- else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
- (rs->f_under == FALSE)){
- rs->f_cycles++;
- rs->f_under = TRUE;
- }
- /* the whole round is over, so reset the flag */
- else if ((pri->info_seq_num>rs->f_start_seq_nr)&&(rs->f_under!=FALSE)){
- rs->f_under = FALSE;
- }
-
- /* number of times where sequence number was not ok */
- if ( rs->f_seq_num+1 == pri->info_seq_num)
- rs->f_seq_num = pri->info_seq_num;
- /* XXX same problem as above */
- else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
- rs->f_seq_num = pri->info_seq_num;
- /* lost packets */
- else if (rs->f_seq_num+1 < pri->info_seq_num) {
- rs->f_seq_num = pri->info_seq_num;
- rs->f_sequence++;
- }
- /* late or duplicated */
- else if (rs->f_seq_num+1 > pri->info_seq_num)
- rs->f_sequence++;
-
- rs->f_stop_seq_nr = pri->info_seq_num;
- rs->f_time = n_time;
- rs->f_jitter = n_jitter;
- rs->f_delta_timestamp = pri->info_timestamp - rs->f_timestamp;
- rs->f_timestamp = pri->info_timestamp;
- rs->f_total_nr++;
-
- /* save the voice information */
- /* if there was already an error, we quit */
- if (rs->f_saved == FALSE)
- return 0;
- /* if the captured length and packet length aren't equal, we quit */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->f_saved = FALSE;
- rs->f_error_type = PADDING_SET;
- return 0;
- }
- /* because the mark bit is set, we have to add some silence in front */
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- /* we insert some silence */
- /* XXX the amount of silence should be the difference between
- * the last timestamp and the current one minus x in the
- * I am not sure if x is equal the amount of information
- * current packet? */
- for(i=0; i<(rs->f_delta_timestamp-pri->info_data_len+12); i++) {
- tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- for(i=0; i < (rs->f_delta_timestamp-pri->info_data_len+12); i++) {
- tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_CODEC;
- return 0;
- }
- return 0;
- }
-
- /* normal packet in forward connection */
- n_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- n_jitter = rs->f_jitter + ( fabs (n_time-(rs->f_time) -
- ((double)(pri->info_timestamp)-
- (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
- rs->f_delay = n_time-(rs->f_time);
- /* the delay is bigger than previous max delay, so store the delay and nr */
- if (rs->f_delay > rs->f_max_delay) {
- rs->f_max_delay = rs->f_delay;
- rs->f_max_nr = pinfo->fd->num;
- }
- add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
- n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
-
- /* count the cycles */
- if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
- rs->f_cycles++;
- rs->f_under = TRUE;
- }
- else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
- (rs->f_under == FALSE)){
- rs->f_cycles++;
- rs->f_under = TRUE;
- }
- /* the whole round is over, so reset the flag */
- else if ((pri->info_seq_num>rs->f_start_seq_nr+1)&&(rs->f_under!=FALSE)){
- rs->f_under = FALSE;
- }
-
- /* number of times where sequence number was not ok */
- if ( rs->f_seq_num+1 == pri->info_seq_num)
- rs->f_seq_num = pri->info_seq_num;
- else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
- rs->f_seq_num = pri->info_seq_num;
- /* lost packets */
- else if (rs->f_seq_num+1 < pri->info_seq_num) {
- rs->f_seq_num = pri->info_seq_num;
- rs->f_sequence++;
- }
- /* late or duplicated */
- else if (rs->f_seq_num+1 > pri->info_seq_num)
- rs->f_sequence++;
-
- rs->f_stop_seq_nr = pri->info_seq_num;
- rs->f_time = n_time;
- rs->f_jitter = n_jitter;
- rs->f_timestamp = pri->info_timestamp;
- rs->f_total_nr++;
-
- /* save the voice information */
- /* we do it only in following cases:
- * - the codecs we support are g.711 alaw in ulaw
- * - the captured length must equal the packet length
- * - XXX we don't support it if there are padding bits
- */
- /* if there was already an error, we quit */
- if (rs->f_saved == FALSE)
- return 0;
- /* if the captured length and packet length aren't equal, we quit */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->f_saved = FALSE;
- rs->f_error_type = PADDING_SET;
- return 0;
- }
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- /* cfile.pd points at the beggining of the actual packet. We have
- * to move this pointer at the RTP data. This is the packet length,
- * minus whole RTP data length (including the RTP header, that is
- * why we add 12) */
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len - 12); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->f_fp);
- rs->f_count++;
- }
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->f_saved = FALSE;
- rs->f_error_type = WRONG_CODEC;
- return 0;
- }
- }
-
- /* is it the reversed direction? */
- else if (rs->ssrc_reversed == pri->info_sync_src) {
- /* first packet? */
- if (rs->r_first_packet !=FALSE) {
- rs->r_seq_num = pri->info_seq_num;
- rs->r_delay = 0;
- rs->r_jitter = 0;
- rs->r_first_packet = FALSE;
- rs->r_timestamp = pri->info_timestamp;
- rs->r_start_seq_nr = pri->info_seq_num;
- rs->r_stop_seq_nr = pri->info_seq_num;
- rs->r_total_nr++;
- rs->r_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- rs->r_start_time = rs->r_time;
- add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
-
- /* save it */
- /* if we couldn't open the tmp file for writing, then we set the flag */
- if (rs->r_fp == NULL) {
- rs->r_saved = FALSE;
- return 0;
- }
- /* if the captured length and packet length aren't equal, we quit */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->r_saved = FALSE;
- rs->r_error_type = PADDING_SET;
- return 0;
- }
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- rs->r_saved = TRUE;
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- rs->r_saved = TRUE;
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_CODEC;
- return 0;
- }
- }
-
- /* packet with mark bit set? */
- if (pri->info_marker_set != FALSE) {
- n_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
- ((double)(pri->info_timestamp)-
- (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
- add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
- n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
-
- /* count the cycles */
- if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
- rs->r_cycles++;
- rs->r_under = TRUE;
- }
- else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
- (rs->r_under == FALSE)){
- rs->r_cycles++;
- rs->r_under = TRUE;
- }
- /* the whole round is over, so reset the flag */
- else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
- rs->r_under = FALSE;
- }
-
- /* number of times where sequence number was not ok */
- if ( rs->r_seq_num+1 == pri->info_seq_num)
- rs->r_seq_num = pri->info_seq_num;
- else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
- rs->r_seq_num = pri->info_seq_num;
- /* lost packets */
- else if (rs->r_seq_num+1 < pri->info_seq_num) {
- rs->r_seq_num = pri->info_seq_num;
- rs->r_sequence++;
- }
- /* late or duplicated */
- else if (rs->r_seq_num+1 > pri->info_seq_num)
- rs->r_sequence++;
-
- rs->r_stop_seq_nr = pri->info_seq_num;
- rs->r_time = n_time;
- rs->r_jitter = n_jitter;
- rs->r_delta_timestamp = pri->info_timestamp - rs->r_timestamp;
- rs->r_timestamp = pri->info_timestamp;
- rs->r_total_nr++;
-
- /* save the voice information */
- /* if there was already an error, we quit */
- if (rs->r_saved == FALSE)
- return 0;
- /* if the captured length and packet length aren't equal, we quit */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->r_saved = FALSE;
- rs->r_error_type = PADDING_SET;
- return 0;
- }
- /* because the mark bit is set, we have to add some silence in front */
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- /* we insert some silence */
- for(i=0; i<(rs->r_delta_timestamp-pri->info_data_len+12); i++) {
- tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- for(i=0; i < (rs->r_delta_timestamp-pri->info_data_len+12); i++) {
- tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_CODEC;
- return 0;
- }
- return 0;
- }
-
- /* normal packet in reversed connection */
- n_time = (double)pinfo->fd->rel_secs +
- (double) pinfo->fd->rel_usecs/1000000;
- n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
- ((double)(pri->info_timestamp)-
- (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
- rs->r_delay = n_time-(rs->r_time);
- if (rs->r_delay > rs->r_max_delay) {
- rs->r_max_delay = rs->r_delay;
- rs->r_max_nr = pinfo->fd->num;
- }
- add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
- n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
- /* count the cycles */
- if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
- rs->r_cycles++;
- rs->r_under = TRUE;
- }
- else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
- (rs->r_under == FALSE)){
- rs->r_cycles++;
- rs->r_under = TRUE;
- }
- /* the whole round is over, so reset the flag */
- else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
- rs->r_under = FALSE;
- }
-
- /* number of times where sequence number was not ok */
- if ( rs->r_seq_num+1 == pri->info_seq_num)
- rs->r_seq_num = pri->info_seq_num;
- else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
- rs->r_seq_num = pri->info_seq_num;
- /* lost packets */
- else if (rs->r_seq_num+1 < pri->info_seq_num) {
- rs->r_seq_num = pri->info_seq_num;
- rs->r_sequence++;
- }
- /* late or duplicated */
- else if (rs->r_seq_num+1 > pri->info_seq_num)
- rs->r_sequence++;
-
- rs->r_stop_seq_nr = pri->info_seq_num;
- rs->r_time = n_time;
- rs->r_jitter = n_jitter;
- rs->r_timestamp = pri->info_timestamp;
- rs->r_total_nr++;
-
- /* save the voice information */
- /* if there was already an error, we quit */
- if (rs->r_saved == FALSE)
- return 0;
- /* if the captured length and packet length aren't equal, we quit */
- if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_LENGTH;
- return 0;
- }
- /* if padding bit is set, we don't do it yet */
- if (pri->info_padding_set != FALSE) {
- rs->r_saved = FALSE;
- rs->r_error_type = PADDING_SET;
- return 0;
- }
- /* is it the ulaw? */
- if (pri->info_payload_type == 0) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
- tmp = (gint16 )ulaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- return 0;
- }
- /* alaw? */
- else if (pri->info_payload_type == 8) {
- data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
- for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
- tmp = (gint16 )alaw2linear((unsigned char)*data);
- fwrite(&tmp, 2, 1, rs->r_fp);
- rs->r_count++;
- }
- return 0;
- }
- /* unsupported codec or other error */
- else {
- rs->r_saved = FALSE;
- rs->r_error_type = WRONG_CODEC;
- return 0;
- }
- }
-
- return 0;
-}
-
-/* XXX just copied from gtk/rpc_stat.c */
-void protect_thread_critical_region(void);
-void unprotect_thread_critical_region(void);
-
-
-/* here we close the rtp analysis dialog window and remove the tap listener */
-static void rtp_destroy_cb(GtkWidget *win _U_, gpointer data _U_)
-{
- info_stat *rs=(info_stat *)data;
-
- protect_thread_critical_region();
- remove_tap_listener(rs);
- unprotect_thread_critical_region();
-
- /* xxx is this enough? */
- g_free(rs->ssrc_tmp);
- g_free(rs);
-
- if (rs->f_fp != NULL)
- fclose(rs->f_fp);
- if (rs->r_fp != NULL)
- fclose(rs->r_fp);
- remove(f_tempname);
- remove(r_tempname);
-
- /* is there a save window open */
- if (save_w != NULL)
- gtk_widget_destroy(save_w);
-
- /* Is there a save voice window open? */
- if (voice_w != NULL)
- gtk_widget_destroy(voice_w);
-
- /* Note that we no longer have a "RTP Analyse" dialog box. */
- rtp_w = NULL;
-}
-
-/* when the close button in rtp window was clicked */
-/* it seems to me that rtp_destroy_cb is automatically called, so we don't
- * need to do the g_free... and rtp_w = NULL ... */
-static void rtp_destroy (GtkWidget *close_bt _U_, gpointer parent_w)
-{
- gtk_grab_remove(GTK_WIDGET(parent_w));
- gtk_widget_destroy(GTK_WIDGET(parent_w));
-}
-
-/* we search the rtp.ssrc node here (thanks to Guy Harris - code here is magic for me */
-static guint32 process_node(proto_item *ptree_node, header_field_info *hfinformation)
-{
- field_info *finfo;
- proto_item *proto_sibling_node;
- header_field_info *hfssrc;
- guint32 ssrc;
-
- finfo = PITEM_FINFO(ptree_node);
-
- if (hfinformation==(finfo->hfinfo)) {
- hfssrc = proto_registrar_get_byname("rtp.ssrc");
- if (hfssrc == NULL)
- return 0;
- for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL;
- ptree_node=g_node_next_sibling(ptree_node)) {
- finfo=PITEM_FINFO(ptree_node);
- if (hfssrc==finfo->hfinfo) {
- ssrc = fvalue_get_integer(finfo->value);
- return ssrc;
- }
- }
- }
-
- proto_sibling_node = g_node_next_sibling(ptree_node);
-
- if (proto_sibling_node) {
- ssrc = process_node(proto_sibling_node, hfinformation);
- return ssrc;
- }
- else
- return 0;
-}
-
-/* here we search the rtp protocol */
-static guint32 process_tree(proto_tree *protocol_tree)
-{
- proto_item *ptree_node;
- header_field_info *hfinformation;
-
- hfinformation = proto_registrar_get_byname("rtp");
- if (hfinformation == NULL)
- return 0;
-
- ptree_node = g_node_first_child(protocol_tree);
- if (!ptree_node)
- return 0;
-
- return process_node(ptree_node, hfinformation);
-}
-
-/* when we want to update the information */
-static void refresh_cb(GtkWidget *w _U_, void *pri)
-{
- info_stat *rs=pri;
-
- gtk_clist_clear(GTK_CLIST(clist));
- gtk_clist_clear(GTK_CLIST(clist_r));
- redissect_packets(&cfile);
- draw_stat(rs);
-}
-
-/* when the user clicks the close button */
-static void voice_close_cb(GtkWidget *close_bt _U_, gpointer parent_w _U_)
-{
- gtk_widget_destroy(GTK_WIDGET(parent_w));
-}
-
-static void voice_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
-{
- if (save_w != NULL)
- gtk_widget_destroy(GTK_WIDGET(save_w));
-
- /* Note that we no longer have a Save voice info dialog box. */
- voice_w = NULL;
-}
-
-
-/* the user wants to save in a file */
-/* XXX support for different formats is currently commented out */
-static void ok_button_cb(GtkWidget *ok_bt, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
- GtkWidget *entry, *rev, *forw, *both;
- /*GtkWidget *wav, *au, *sw;*/
- gchar *g_dest;
- gint channels /*, format*/;
-
- entry = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "file_entry");
- /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
- au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
- sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
- rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
- forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
- both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
- g_dest = gtk_entry_get_text(GTK_ENTRY(entry));
-
- /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
- * we don't support that codec. So we pop up a warning. Maybe it would be better to
- * disable the ok button or disable the buttons for direction if only one is not ok. The
- * problem is if we open the save voice dialog and then click the refresh button and maybe
- * the state changes, so we can't save anymore. In this case we should be able to update
- * the buttons. For now it is easier if we put the warning when the ok button is pressed.
- */
-
- /* we can not save in both dirctions */
- if ((rs->f_saved == FALSE) && (rs->r_saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
- /* there are many combinations here, we just exit when first matches */
- if ((rs->f_error_type == WRONG_CODEC) || (rs->r_error_type == WRONG_CODEC))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: Unsupported codec!");
- else if ((rs->f_error_type == WRONG_LENGTH) || (rs->r_error_type == WRONG_LENGTH))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: Wrong length of captured packets!");
- else if ((rs->f_error_type == PADDING_SET) || (rs->r_error_type == PADDING_SET))
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: RTP data with padding!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save in a file: File I/O problem!");
- return;
- }
- /* we can not save forward direction */
- else if ((rs->f_saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
- (GTK_TOGGLE_BUTTON (both)->active))) {
- if (rs->f_error_type == WRONG_CODEC)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: Unsupported codec!");
- else if (rs->f_error_type == WRONG_LENGTH)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: Wrong length of captured packets!");
- else if (rs->f_error_type == PADDING_SET)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: RTP data with padding!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save forward direction in a file: File I/O problem!");
- return;
- }
- /* we can not save reversed direction */
- else if ((rs->r_saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
- (GTK_TOGGLE_BUTTON (both)->active))) {
- if (rs->r_error_type == WRONG_CODEC)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: Unsupported codec!");
- else if (rs->r_error_type == WRONG_LENGTH)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: Wrong length of captured packets!");
- else if (rs->r_error_type == PADDING_SET)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: RTP data with padding!");
- else if (rs->r_error_type == NO_DATA)
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: No RTP data!");
- else
- simple_dialog(ESD_TYPE_CRIT, NULL,
- "Can't save reversed direction in a file: File I/O problem!");
- return;
- }
-
- /* if the file text entry is empty */
- if (!g_dest[0]) {
- simple_dialog(ESD_TYPE_CRIT, NULL, "Saving to file, but no file specified.");
- return;
- }
-
- /*if (GTK_TOGGLE_BUTTON (wav)->active)
- format = 1;
- else if (GTK_TOGGLE_BUTTON (au)->active)
- format = 2;
- else if (GTK_TOGGLE_BUTTON (sw)->active)
- format = 3;*/
-
- if (GTK_TOGGLE_BUTTON (rev)->active)
- channels = 2;
- else if (GTK_TOGGLE_BUTTON (both)->active)
- channels = 3;
- else
- channels = 1;
-
- if(!copy_file(g_dest, channels/*, format*/, rs)) {
- simple_dialog(ESD_TYPE_CRIT, NULL, "An error occured while saving voice in a file!");
- return;
- }
-
- if (save_w != NULL)
- gtk_widget_destroy(GTK_WIDGET(save_w));
-
- /* XXX I get GTK warning (sometimes?)!!! */
- gtk_widget_destroy(GTK_WIDGET(voice_w));
-}
-
-static void save_ok_button_cb(GtkWidget *w _U_, gpointer data)
-{
- gchar *f_name;
-
- f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
-
- /* Perhaps the user specified a directory instead of a file.
- Check whether they did. */
- if (test_for_directory(f_name) == EISDIR) {
- /* It's a directory - set the file selection box to display it. */
- set_last_open_dir(f_name);
- g_free(f_name);
- gtk_file_selection_set_filename(GTK_FILE_SELECTION(data), last_open_dir);
- return;
- }
-
- gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, "file_entry")), f_name);
- gtk_widget_destroy(GTK_WIDGET(data));
-
- g_free(f_name);
-}
-
-static void save_cancel_button_cb(GtkWidget *w _U_, gpointer data)
-{
- gtk_widget_destroy(GTK_WIDGET(data));
-}
-
-static void save_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
-{
- /* Note that we no longer have a Save voice info dialog box. */
- save_w = NULL;
-}
-
-/* file selection window */
-static void file_selection_cb(GtkWidget *w _U_, gpointer file_entry)
-{
- if (save_w != NULL) {
- /* Yes. Just re-activate that dialog box. */
- reactivate_window(save_w);
- return;
- }
-
- save_w = gtk_file_selection_new ("Ethereal: Save to File");
- gtk_signal_connect(GTK_OBJECT(save_w), "destroy", GTK_SIGNAL_FUNC(save_destroy_cb), NULL);
-
- OBJECT_SET_DATA(save_w, "file_entry", file_entry);
-
- gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->cancel_button), "clicked",
- GTK_SIGNAL_FUNC(save_cancel_button_cb), GTK_OBJECT(save_w));
-
- gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->ok_button), "clicked",
- GTK_SIGNAL_FUNC(save_ok_button_cb), GTK_OBJECT(save_w));
-
- gtk_widget_show(save_w);
-}
-
-/* when the user wants to save the voice information in a file */
-/* XXX support for different formats is currently commented out */
-static void voice_cb(GtkWidget *w _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
-
- GtkWidget *vertb;
- GtkWidget *table1;
- GtkWidget *label_format;
- GtkWidget *channels_label;
- /*GSList *format_group = NULL;*/
- GSList *channels_group = NULL;
- GtkWidget *forward_rb;
- GtkWidget *reversed_rb;
- GtkWidget *both_rb;
- /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
- GtkWidget *hbox3;
- GtkWidget *file_button;
- GtkWidget *file_entry;
- GtkWidget *hbox4;
- GtkWidget *ok_bt;
- GtkWidget *cancel_bt;
-
- /* if we can't save in a file: wrong codec, cut packets or other errors */
- /* shold the error arise here or later when you click ok button ?
- * if we do it here, then we must disable the refresh button, so we don't do it here */
-
- if (voice_w != NULL) {
- /* There's already a Save voice info dialog box; reactivate it. */
- reactivate_window(voice_w);
- return;
- }
-
- voice_w = dlg_window_new("Ethereal: Save voice data");
- gtk_signal_connect(GTK_OBJECT(voice_w), "destroy",
- GTK_SIGNAL_FUNC(voice_destroy_cb), NULL);
-
- /* Container for each row of widgets */
- vertb = gtk_vbox_new(FALSE, 0);
- gtk_container_border_width(GTK_CONTAINER(vertb), 5);
- gtk_container_add(GTK_CONTAINER(voice_w), vertb);
- gtk_widget_show (vertb);
-
- table1 = gtk_table_new (2, 4, FALSE);
- gtk_widget_show (table1);
- gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
- gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
-
- label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
- gtk_widget_show (label_format);
- gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- /* we support .au - ulaw*/
-/* wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
- gtk_widget_show (wav_rb);
- gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit ");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
- gtk_widget_show (sw_rb);
- gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- au_rb = gtk_radio_button_new_with_label (format_group, ".au");
- format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
- gtk_widget_show (au_rb);
- gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- */
-
- channels_label = gtk_label_new ("Channels:");
- gtk_widget_show (channels_label);
- gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
- gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
-
- forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
- gtk_widget_show (forward_rb);
- gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
- gtk_widget_show (reversed_rb);
- gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- both_rb = gtk_radio_button_new_with_label (channels_group, "both");
- channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
- gtk_widget_show (both_rb);
- gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
- (GtkAttachOptions) (GTK_FILL),
- (GtkAttachOptions) (0), 0, 0);
-
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
-
- /* if one direction is nok we don't allow saving
- XXX this is not ok since the user can click the refresh button and cause changes
- but we can not update this window. So we move all the decision on the time the ok
- button is clicked
- if (rs->f_saved == FALSE) {
- gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
- gtk_widget_set_sensitive(forward_rb, FALSE);
- gtk_widget_set_sensitive(both_rb, FALSE);
- }
- else if (rs->r_saved == FALSE) {
- gtk_widget_set_sensitive(reversed_rb, FALSE);
- gtk_widget_set_sensitive(both_rb, FALSE);
- }
- */
- hbox3 = gtk_hbox_new (FALSE, 0);
- gtk_widget_show (hbox3);
- gtk_box_pack_start (GTK_BOX (vertb), hbox3, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (hbox3), 10);
-
- file_button = gtk_button_new_with_label ("File:");
- gtk_widget_show (file_button);
- gtk_box_pack_start (GTK_BOX (hbox3), file_button, FALSE, FALSE, 0);
-
- file_entry = gtk_entry_new ();
- gtk_widget_show (file_entry);
- gtk_box_pack_start (GTK_BOX (hbox3), file_entry, TRUE, TRUE, 10);
-
- hbox4 = gtk_hbox_new (FALSE, 0);
- gtk_widget_show (hbox4);
- gtk_box_pack_start (GTK_BOX (vertb), hbox4, FALSE, FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (hbox4), 10);
-
- ok_bt = gtk_button_new_with_label ("OK");
- gtk_widget_show (ok_bt);
- gtk_box_pack_start (GTK_BOX (hbox4), ok_bt, TRUE, FALSE, 0);
- gtk_widget_set_usize (ok_bt, 60, -2);
- OBJECT_SET_DATA(ok_bt, "file_entry", file_entry);
- /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
- OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
- OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
- OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
- OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
- OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
-
- cancel_bt = gtk_button_new_with_label (" Cancel ");
- gtk_widget_show (cancel_bt);
- gtk_box_pack_start (GTK_BOX (hbox4), cancel_bt, TRUE, FALSE, 0);
- gtk_widget_set_usize (cancel_bt, 60, -2);
-
- gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
- GTK_SIGNAL_FUNC(voice_close_cb), GTK_OBJECT(voice_w));
-
- gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(ok_button_cb), rs);
-
- gtk_signal_connect(GTK_OBJECT(file_button), "clicked",
- GTK_SIGNAL_FUNC(file_selection_cb), file_entry);
-
- gtk_widget_show(voice_w);
-}
-
-/* all the graphics on the window is done here */
-static void add_rtp_notebook(void *pri)
-{
- info_stat *rs=pri;
-
- GtkWidget *notebook, *page, *page_r, *label, *label1, *label2, *label3;
- GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
- GtkWidget *box4, *voice_bt, *refresh_bt, *close_bn;
-
- gchar *titles[6] = {"Packet nr.", "Sequence", "Delay (s)", "Jitter (s)", "Marker", "Status"};
- gchar label_forward[150];
- gchar label_reverse[150];
-
- /* XXX is it ok to use %lu for guint32? The compiler is not satisfied, but it works
- * with %d the compiler is satisfied, but it doesn't work */
- g_snprintf(label_forward, 149,
- "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
- rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward);
- g_snprintf(label_reverse, 149,
- "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
- rs->destination, rs->dstport, rs->source, rs->srcport, rs->ssrc_reversed);
-
- gtk_widget_destroy(main_vb);
- main_vb = gtk_vbox_new(FALSE, 3);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* Start a nootbook for flipping between sets of changes */
- notebook = gtk_notebook_new();
- gtk_container_add(GTK_CONTAINER(main_vb), notebook);
- gtk_object_set_data(GTK_OBJECT(rtp_w), "notebook", notebook);
-
- /* page for forward connection */
- page = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(page), 20);
-
- /* scrolled window */
- scrolled_window = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_set_usize(scrolled_window, 600, 200);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
-
- /* direction label */
- label1 = gtk_label_new(label_forward);
- gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
-
- /* place for some statistics */
- max = gtk_label_new("\n\n");
- gtk_box_pack_end(GTK_BOX(page), max, FALSE, FALSE, 5);
-
- /* clist for the information */
- clist = gtk_clist_new_with_titles(6, titles);
- gtk_widget_show(clist);
- gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
- gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
-
- /* and the label */
- label = gtk_label_new(" Forward Direction ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
-
- /* column width and justification */
- gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist), 4, 40);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_CENTER);
-
- /* same page for reversed connection */
- page_r = gtk_vbox_new(FALSE, 5);
- gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
- scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
- gtk_widget_set_usize(scrolled_window_r, 600, 200);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
- label3 = gtk_label_new(label_reverse);
- gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
- max_r = gtk_label_new("\n\n");
- gtk_box_pack_end(GTK_BOX(page_r), max_r, FALSE, FALSE, 5);
- clist_r = gtk_clist_new_with_titles(6, titles);
- gtk_widget_show(clist_r);
- gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_r);
- gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
- label2 = gtk_label_new(" Reversed Direction ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
-
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 1, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 2, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 3, 80);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 4, 40);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 0, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 1, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 2, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 3, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 4, GTK_JUSTIFY_CENTER);
- gtk_clist_set_column_justification(GTK_CLIST(clist_r), 5, GTK_JUSTIFY_CENTER);
-
- /* page for help&about or future
- page_help = gtk_hbox_new(FALSE, 5);
- label4 = gtk_label_new(" Future ");
- gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
- frame = gtk_frame_new("");
- text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
- gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
- gtk_container_add(GTK_CONTAINER(frame), text);
- gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
- gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
-*/
- /* show all notebooks */
- gtk_widget_show_all(notebook);
-
- /* and the buttons */
- box4 = gtk_hbutton_box_new();
- gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, TRUE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(box4), GTK_BUTTONBOX_SPREAD);
- gtk_widget_show(box4);
-
- voice_bt = gtk_button_new_with_label("Save voice data");
- gtk_container_add(GTK_CONTAINER(box4), voice_bt);
- gtk_widget_show(voice_bt);
- gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
- GTK_SIGNAL_FUNC(voice_cb), rs);
-
- refresh_bt = gtk_button_new_with_label("Refresh");
- gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
- gtk_widget_show(refresh_bt);
- gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
- GTK_SIGNAL_FUNC(refresh_cb), rs);
-
- close_bn = gtk_button_new_with_label("Close");
- gtk_container_add(GTK_CONTAINER(box4), close_bn);
- gtk_widget_show(close_bn);
- gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
- GTK_SIGNAL_FUNC(rtp_destroy), GTK_OBJECT(rtp_w));
-
- redissect_packets(&cfile);
-
- draw_stat(rs);
-}
-
-
-/* when we click on the selected row it copies that ssrc value into ssrc_reversed */
-static void get_selected_ssrc(GtkWidget *clist_r, gint row, gint column,
- GdkEventButton *event _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
- gchar *text;
-
- gtk_clist_get_text(GTK_CLIST(clist_r), row, column, &text);
- /* XXX is this strtoul portable for guint32? */
- rs->ssrc_reversed = strtoul(text, (char **)NULL, 10);
- return;
-}
-
-/* when we click apply button in ssrc reversed dialog */
-static void apply_selected_ssrc(GtkWidget *w _U_, gpointer data)
-{
- info_stat *rs=(info_stat *)data;
- add_rtp_notebook(rs);
-}
-
-/* this function goes through all the packets that have the same ip and port combination
- * (only inversed) as the forward direction (XXX what if the reversed direction doesn't use
- * the same ports???) and looks for different SSRC values. This can happen if you capture
- * two RTP conversations one after another from the same pair of phones (PC's).
- * Both have same IP's and can also have same port numbers, so they (should) differ only
- * in SSRC values. In such case we get a list of ssrc values and we have to choose the right
- * one from the list. If there is only one or none, we do it automatically */
-static void get_reversed_ssrc(void *prs)
-{
- info_stat *ri = prs;
- GtkWidget *scroll_r, *clist_r, *ok_bt, *label, *label2, *label1, *main_hbnbox;
- gchar temp[150];
- guint i;
-
- switch(ri->reversed_ip_and_port)
- {
- /* in case we haven't found any reversed ssrc */
- /* XXX in this case we could look for the inversed IP only */
- case 0: {
- ri->ssrc_reversed = 0;
- ri->search_ssrc = FALSE;
- add_rtp_notebook(ri);
- return;
- }
- /* in case we found exactly one matching ssrc for reversed connection */
- case 1: {
- ri->ssrc_reversed = ri->ssrc_tmp[0];
- ri->search_ssrc = FALSE;
- add_rtp_notebook(ri);
- return;
- }
- /* there is more then one matching ssrc, so we have to choose between them */
- default: {
- ri->search_ssrc = FALSE;
- /* let's draw the window */
- label = gtk_label_new("Found more SSRC values for the reversed\n"
- "connection with following parameters:\n");
- g_snprintf(temp, 149, "Source %s port %u Destination %s port %u",
- ri->destination, ri->dstport, ri->source, ri->srcport);
- label2 = gtk_label_new(temp);
- gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE, FALSE, 0);
- gtk_box_pack_start(GTK_BOX(main_vb), label2, FALSE, FALSE, 0);
- scroll_r = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_r),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- clist_r = gtk_clist_new(1);
- gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
- gtk_container_add(GTK_CONTAINER(scroll_r), clist_r);
- gtk_box_pack_start(GTK_BOX(main_vb), scroll_r, TRUE, TRUE, 0);
- label1 = gtk_label_new("Select one value and click apply");
- gtk_box_pack_start(GTK_BOX(main_vb), label1, FALSE, FALSE, 0);
-
- main_hbnbox = gtk_hbutton_box_new();
- gtk_box_pack_start(GTK_BOX(main_vb), main_hbnbox, FALSE, TRUE, 0);
- gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);
- gtk_button_box_set_layout(GTK_BUTTON_BOX(main_hbnbox),
- GTK_BUTTONBOX_SPREAD);
- gtk_widget_show(main_hbnbox);
-
- ok_bt = gtk_button_new_with_label("Apply");
- gtk_container_add(GTK_CONTAINER(main_hbnbox), ok_bt);
- gtk_signal_connect(GTK_OBJECT(clist_r), "select_row",
- GTK_SIGNAL_FUNC(get_selected_ssrc), ri);
- gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
- GTK_SIGNAL_FUNC(apply_selected_ssrc), ri);
-
- /* add all the ssrc values in the clist */
- /* XXX I'm sure the tmp variable could be avoided here
- * i tried to assign guint32 from ri->ssrc_tmp somehow to gchar **text
- * but gave up. So if you can do this, just go ahead */
- for (i=0; i < ri->reversed_ip_and_port; i++) {
- gchar *text[0];
- gchar tmp[20];
- g_snprintf(tmp, 20, "%u", ri->ssrc_tmp[i]);
- text[0] = (gchar *)&tmp;
- gtk_clist_append(GTK_CLIST(clist_r), text);
- }
-
- gtk_clist_select_row(GTK_CLIST(clist_r), 0, 0);
-
- gtk_widget_show(label);
- gtk_widget_show(label1);
- gtk_widget_show(label2);
- gtk_widget_show(ok_bt);
- gtk_widget_show(clist_r);
- gtk_widget_show(scroll_r);
- }
- }
-}
-
-/* when the user clicks the RTP dialog button */
-void rtp_analyse_cb(GtkWidget *w _U_, gpointer data _U_)
-{
- info_stat *rs;
- gchar filter_text[]="rtp";
- dfilter_t *sfcode;
- capture_file *cf;
- epan_dissect_t *edt;
- gint err;
- gboolean frame_matched;
- frame_data *fdata;
-
- /* There's already a "Display Options" dialog box; reactivate it. */
- if (rtp_w != NULL) {
- reactivate_window(rtp_w);
- return;
- }
-
- /* Try to compile the filter. */
- if (!dfilter_compile(filter_text, &sfcode)) {
- simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
- return;
- }
- /* we load the current file into cf variable */
- cf = &cfile;
- fdata = cf->current_frame;
-
- /* we are on the selected frame now */
- if (fdata == NULL)
- return; /* if we exit here it's an error */
-
- /* XXX instead of looking for RTP protocol like this, we could do the process_node() staff */
- /* dissect the current frame */
- wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err);
- edt = epan_dissect_new(TRUE, FALSE);
- epan_dissect_prime_dfilter(edt, sfcode);
- epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
- frame_matched = dfilter_apply_edt(sfcode, edt);
-
- /* if it is not an rtp frame, exit */
- frame_matched = dfilter_apply_edt(sfcode, edt);
- if (frame_matched != 1) {
- epan_dissect_free(edt);
- simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a RTP packet!");
- return;
- }
-
- /* in rs we put all the info */
- rs=g_malloc(sizeof(info_stat));
-
- /* ok, it is a RTP frame, so let's get the ip and port values */
- rs->srcport = edt->pi.srcport;
- rs->dstport = edt->pi.destport;
- strncpy(rs->source, ip_to_str(edt->pi.src.data), 16);
- strncpy(rs->destination, ip_to_str(edt->pi.dst.data), 16);
-
- /* now we need the SSRC value of the current frame */
- rs->ssrc_forward = process_tree(edt->tree);
- if (rs->ssrc_forward == 0) {
- simple_dialog(ESD_TYPE_CRIT, NULL, "SSRC value couldn't be found!");
- return;
- }
-
- /* now we have all the information about the forwarding connection
- * we need to go through all the packets and search for reversed connection
- */
- rs->search_ssrc = TRUE;
- rs->ssrc_reversed = 0;
- rs->reversed_ip = 0;
- rs->reversed_ip_and_port = 0;
- rs->ssrc_tmp = NULL;
-
-/* XXX compiler warning:passing arg 5 of `register_tap_listener' from incompatible pointer type */
- if(register_tap_listener("rtp", rs, NULL, rtp_reset, rtp_packet, rtp_draw)){
- printf("ethereal: rtp_init() failed to attach the tap.\n");
- /* XXX is this enough or do I have to free anything else? */
- g_free(rs);
- exit(1);
- }
-
- /* let's draw the window */
- rtp_w = dlg_window_new("Ethereal: RTP Analyse");
- gtk_window_set_position (GTK_WINDOW (rtp_w), GTK_WIN_POS_CENTER);
- gtk_signal_connect(GTK_OBJECT(rtp_w), "destroy",
- GTK_SIGNAL_FUNC(rtp_destroy_cb), rs);
-
- /* Container for each row of widgets */
- main_vb = gtk_vbox_new(FALSE, 3);
- gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
- gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
- gtk_widget_show(main_vb);
-
- /* file names for storing sound data */
- tmpnam(f_tempname);
- tmpnam(r_tempname);
- rs->f_fp = NULL;
- rs->r_fp = NULL;
-
- redissect_packets(cf);
-
- /* so how many reversed connection we have ? */
- get_reversed_ssrc(rs);
-
- /* and finally display this window */
- gtk_widget_show(rtp_w);
-}
-
-static void
-rtp_analyse_init(char *dummy _U_)
-{
- rtp_analyse_cb(NULL, NULL);
-}
-
-/* XXX compiler warning:passing arg 2 of `register_ethereal_tap' from incompatible pointer type */
-void
-register_tap_listener_gtkrtp(void)
-{
- register_ethereal_tap("rtp", rtp_analyse_init, NULL, NULL);
-}
-
-
-/* here we save it into a file that user specified */
-/* XXX what about endians here? could go something wrong? */
-static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ void *data)
-{
- info_stat *rs=(info_stat *)data;
- int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
- gint16 f_pd;
- gint16 r_pd;
- gchar pd[1];
- guint32 f_write_silence = 0;
- guint32 r_write_silence = 0;
- progdlg_t *progbar;
- guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
- gboolean stop_flag = FALSE;
-
- forw_fd = open(f_tempname, O_RDONLY | 0);
- if (forw_fd < 0)
- return FALSE;
- rev_fd = open(r_tempname, O_RDONLY | 0);
- if (rev_fd < 0) {
- close(forw_fd);
- return FALSE;
- }
-
- /* open file for saving */
- to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | 0, 0644);
- if (to_fd < 0) {
- close(forw_fd);
- close(rev_fd);
- return FALSE;
- }
-
- progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
-
- /* First we write the .au header. XXX Hope this is endian independant */
- /* the magic word 0x2e736e64 == .snd */
- *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
- *pd = (unsigned char)0x73; write(to_fd, pd, 1);
- *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
- *pd = (unsigned char)0x64; write(to_fd, pd, 1);
- /* header offset == 24 bytes */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x18; write(to_fd, pd, 1);
- /* total length, it is permited to set this to 0xffffffff */
- *pd = (unsigned char)0xff; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- /* encoding format == 8 bit ulaw */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x01; write(to_fd, pd, 1);
- /* sample rate == 8000 Hz */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
- *pd = (unsigned char)0x40; write(to_fd, pd, 1);
- /* channels == 1 */
- *pd = (unsigned char)0x00; write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- write(to_fd, pd, 1);
- *pd = (unsigned char)0x01; write(to_fd, pd, 1);
-
- switch (channels) {
- /* only forward direction */
- case 1: {
- progbar_count = rs->f_count;
- progbar_quantum = rs->f_count/100;
- while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- *pd = (unsigned char)linear2ulaw(f_pd);
- fwritten = write(to_fd, pd, 1);
- if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- break;
- }
- /* only reversed direction */
- case 2: {
- progbar_count = rs->r_count;
- progbar_quantum = rs->r_count/100;
- while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- *pd = (unsigned char)linear2ulaw(r_pd);
- rwritten = write(to_fd, pd, 1);
- if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- break;
- }
- /* both directions */
- default: {
- (rs->f_count > rs->r_count) ? (progbar_count = rs->f_count) :
- (progbar_count = rs->r_count);
- progbar_quantum = progbar_count/100;
- /* since conversation in one way can start later than in the other one,
- * we have to write some silence information for one channel */
- if (rs->f_start_time > rs->r_start_time) {
- f_write_silence = (rs->f_start_time-rs->r_start_time)*8000;
- }
- else if (rs->f_start_time < rs->r_start_time) {
- r_write_silence = (rs->r_start_time-rs->f_start_time)*8000;
- }
- for(;;) {
- if(stop_flag)
- break;
- if((count > progbar_nextstep) && (count <= progbar_count)) {
- update_progress_dlg(progbar,
- (gfloat) count/progbar_count, "Saving");
- progbar_nextstep = progbar_nextstep + progbar_quantum;
- }
- count++;
- if(f_write_silence > 0) {
- rread = read(rev_fd, &r_pd, 2);
- f_pd = 0;
- fread = 1;
- f_write_silence--;
- }
- else if(r_write_silence > 0) {
- fread = read(forw_fd, &f_pd, 2);
- r_pd = 0;
- rread = 1;
- r_write_silence--;
- }
- else {
- fread = read(forw_fd, &f_pd, 2);
- rread = read(rev_fd, &r_pd, 2);
- }
- if ((rread == 0) && (fread == 0))
- break;
- *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
- rwritten = write(to_fd, pd, 1);
- if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- destroy_progress_dlg(progbar);
- return FALSE;
- }
- }
- }
- }
- destroy_progress_dlg(progbar);
- close(forw_fd);
- close(rev_fd);
- close(to_fd);
- return TRUE;
-
-}
-
+/*
+ * tap_rtp.c
+ *
+ * $Id: tap_rtp.c,v 1.3 2003/03/06 23:09:09 guy Exp $
+ *
+ * RTP analysing addition for ethereal
+ *
+ * Copyright 2003, Iskratel, Ltd, Kranj
+ * By Miha Jemec <m.jemec@iskratel.si>
+ *
+ * Ethereal - Network traffic analyzer
+ * By Gerald Combs <gerald@ethereal.com>
+ * Copyright 1998 Gerald Combs
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * This tap works as follows:
+ * When the user clicks on the RTP analisys button, we first check if it is a RTP packet.
+ * If yes we store the SSRC, ip, and port values. Then the tap is registered and the
+ * redissect_packets() routine is called. So we go through all the RTP packets and search
+ * for SSRC of reversed connection (it has inversed socket parameters). If more than one
+ * is found a window is displayed where the user can select the appropriate from the list.
+ * Rigth now we have the information about the converstion we are looking for (both SSRC).
+ * The redissect_packets() routine is called again. This time whenever a RTP packet with
+ * matching SSRC values arrives, we store all the information we need (number, sequence
+ * number, arrival time, ...) and compute the delay, jitter and wrong sequence number.
+ * We add this values to CList. If the RTP packet carries voice in g711 alaw or ulaw, we
+ * also store this voice information in a temp file. Window is displayed.
+ * Then three buttons are available: Close, Refresh and Save voice.
+ * The Refresh button calls the redissect_packets() routine again. It goes through the packets
+ * again and does all the calculation again (if capturing in real time this means that some
+ * more packets could come and can be computed in statistic). It also writes the sound
+ * data again.
+ * The Save voice button opens the dialog where we can choose the file name, format (not yet)
+ * and direction we want to save. Currently it works only with g711 alaw and ulaw, and if the
+ * length of captured packets is equal the length of packets on wire and if there are no padding
+ * bits.
+ *
+ * To do:
+ * - Support for saving voice in more different formats and with more different codecs:
+ * Since this should be portable to all OS, there is only possibility to save the
+ * voice in a file and not play it directly through the sound card. There are enough
+ * players on all platforms, that are doing right this. What about the format?
+ * Currently there is only support for saving as an .au file (ulaw, 8000 Hz, 8bit)
+ * There are many players for this format on all platforms (for example Windows Media Player
+ * under Windows, command play under Linux). Support will be added for wav format and
+ * possibility to save with two channels (separate channel for each direction)
+ *
+ * - Support for more codecs. Now you can save voice only if the codec is g.711 alaw or ulaw.
+ *
+ * - right now, the reversed connection must have the same (only inversed) ip and port numbers.
+ * I think that there is no reason that in special cases the reversed connection would not use
+ * some different port or even the IP combination (please correct me if I am wrong).
+ * So this will be added soon.
+ *
+ * - some more statistics (delay and jitter distribution)
+ *
+ * - GTK2 implementation
+ *
+ * - grammar correction
+ *
+ * - some more testing (other OS)
+ *
+ * XXX Problems:
+ *
+ * - instead of tmpnam() use of mkstemp().
+ * I tried to do it with mkstemp() but didn't now how to solve following problem:
+ * I call mkstemp() and then write in this temp file and it works fine . But if the user
+ * then hits the refresh button, this temp file should be deleted and opened again. I tried
+ * to call close() and unlink(), but when I call mkstemp() for the second time I always get
+ * an error ( -1) as return value. What is the correct order? Is it possible to call
+ * mkstemp() twice with the same template?
+ *
+ * - problem with statistics for lost (late, duplicated) packets. How to make the statistic
+ * more resistant to special (bizarre) arrival of sequence numbers
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+#include <gtk/gtk.h>
+#include "tap_rtp.h"
+#include "globals.h"
+#include <string.h>
+#include "epan/packet_info.h"
+#include <epan/epan_dissect.h>
+#include <epan/filesystem.h>
+#include "../tap.h"
+#include "../register.h"
+#include "../packet-rtp.h"
+#include "file_dlg.h"
+#include "dlg_utils.h"
+#include "ui_util.h"
+#include "simple_dialog.h"
+#include "main.h"
+#include <math.h>
+#include "progress_dlg.h"
+#include "compat_macros.h"
+#include "../g711.h"
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+static GtkWidget *rtp_w = NULL;
+static GtkWidget *voice_w = NULL;
+static GtkWidget *save_w = NULL;
+static GtkWidget *main_vb;
+static GtkWidget *clist;
+static GtkWidget *clist_r;
+static GtkWidget *max;
+static GtkWidget *max_r;
+
+static gboolean copy_file(gchar *, /*gint,*/ gint, void *);
+
+char f_tempname[100], r_tempname[100];
+
+/* type of error when saving voice in a file didn't succeed */
+typedef enum {
+ WRONG_CODEC,
+ WRONG_LENGTH,
+ PADDING_SET,
+ FILE_OPEN_ERROR,
+ NO_DATA
+} error_type_t;
+
+/* structure that holds the information about the forwarding and reversed connection */
+/* f_* always aplies to the forward direction and r_* to the reversed */
+typedef struct _info_stat {
+ gchar source[16];
+ gchar destination[16];
+ guint16 srcport;
+ guint16 dstport;
+ guint32 ssrc_forward;
+ guint32 ssrc_reversed;
+ guint32 *ssrc_tmp;
+ gboolean search_ssrc;
+ guint reversed_ip;
+ guint reversed_ip_and_port;
+ gboolean f_first_packet;
+ gboolean r_first_packet;
+ guint16 f_seq_num;
+ guint16 r_seq_num;
+ guint32 f_timestamp;
+ guint32 r_timestamp;
+ guint32 f_delta_timestamp;
+ guint32 r_delta_timestamp;
+ double f_delay;
+ double r_delay;
+ double f_jitter;
+ double r_jitter;
+ double f_time;
+ double r_time;
+ double f_start_time;
+ double r_start_time;
+ double f_max_delay;
+ double r_max_delay;
+ guint32 f_max_nr;
+ guint32 r_max_nr;
+ guint16 f_start_seq_nr;
+ guint16 r_start_seq_nr;
+ guint16 f_stop_seq_nr;
+ guint16 r_stop_seq_nr;
+ guint32 f_total_nr;
+ guint32 r_total_nr;
+ guint32 f_sequence;
+ guint32 r_sequence;
+ gint f_cycles;
+ gint r_cycles;
+ gboolean f_under;
+ gboolean r_under;
+ FILE *f_fp;
+ FILE *r_fp;
+ gboolean f_saved;
+ gboolean r_saved;
+ error_type_t f_error_type;
+ error_type_t r_error_type;
+ guint32 f_count;
+ guint32 r_count;
+} info_stat;
+
+
+/* when there is a [re]reading of packet's */
+static void
+rtp_reset(void *prs)
+{
+ info_stat *rs=prs;
+
+ rs->f_first_packet = TRUE;
+ rs->r_first_packet = TRUE;
+ rs->f_max_delay = 0;
+ rs->r_max_delay = 0;
+ rs->f_max_nr = 0;
+ rs->r_max_nr = 0;
+ rs->f_total_nr = 0;
+ rs->r_total_nr = 0;
+ rs->f_sequence = 0;
+ rs->r_sequence = 0;
+ rs->f_start_seq_nr = 0;
+ rs->r_start_seq_nr = 1; /* 1 is ok (for statistics in reversed direction) */
+ rs->f_stop_seq_nr = 0;
+ rs->r_stop_seq_nr = 0;
+ rs->f_cycles = 0;
+ rs->r_cycles = 0;
+ rs->f_under = FALSE;
+ rs->r_under = FALSE;
+ rs->f_saved = FALSE;
+ rs->r_saved = FALSE;
+ rs->f_start_time = 0;
+ rs->r_start_time = 0;
+ rs->f_count = 0;
+ rs->r_count = 0;
+ /* XXX check for error at fclose? */
+ if (rs->f_fp != NULL)
+ fclose(rs->f_fp);
+ if (rs->r_fp != NULL)
+ fclose(rs->r_fp);
+ rs->f_fp = fopen(f_tempname, "wb");
+ if (rs->f_fp == NULL)
+ rs->f_error_type = FILE_OPEN_ERROR;
+ rs->r_fp = fopen(r_tempname, "wb");
+ if (rs->r_fp == NULL)
+ rs->r_error_type = FILE_OPEN_ERROR;
+ return;
+}
+
+/* here we can redraw the output */
+/* not used yet */
+static void rtp_draw(void *prs _U_)
+{
+ return;
+}
+
+/* when we are finished with redisection, we add the label for the statistic */
+static void draw_stat(void *prs)
+{
+ info_stat *rs=prs;
+ gchar label_max[200];
+ guint32 f_expected = (rs->f_stop_seq_nr + rs->f_cycles*65536) - rs->f_start_seq_nr + 1;
+ guint32 r_expected = (rs->r_stop_seq_nr + rs->r_cycles*65536) - rs->r_start_seq_nr + 1;
+ gint32 f_lost = f_expected - rs->f_total_nr;
+ gint32 r_lost = r_expected - rs->r_total_nr;
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence error = %u",
+ rs->f_max_delay, rs->f_max_nr, rs->f_total_nr, f_expected,
+ f_lost, rs->f_sequence);
+
+ gtk_label_set_text(GTK_LABEL(max), label_max);
+
+ g_snprintf(label_max, 199, "Max delay = %f sec at packet nr. %u \n\n"
+ "Total RTP packets = %u (expected %u) Lost RTP packets = %d"
+ " Sequence error = %u",
+ rs->r_max_delay, rs->r_max_nr, rs->r_total_nr, r_expected,
+ r_lost, rs->r_sequence);
+
+ gtk_label_set_text(GTK_LABEL(max_r), label_max);
+
+ /* could be done somewhere else, but can be here as well */
+ /* if this is true, then we don't have any reversed connection, so the error type
+ * will be no data. This applies only the reversed connection */
+ if (rs->reversed_ip_and_port == 0)
+ rs->r_error_type = NO_DATA;
+
+ return ;
+}
+
+/* append a line to clist */
+/* XXX is there a nicer way to make these assignements? */
+static void add_to_clist(gboolean forward, guint32 number, guint16 seq_num,
+ double delay, double jitter, gboolean status, gboolean marker)
+{
+ gchar *data[6];
+ gchar field[6][30];
+
+ data[0]=&field[0][0];
+ data[1]=&field[1][0];
+ data[2]=&field[2][0];
+ data[3]=&field[3][0];
+ data[4]=&field[4][0];
+ data[5]=&field[5][0];
+
+ g_snprintf(field[0], 20, "%u", number);
+ g_snprintf(field[1], 20, "%u", seq_num);
+ g_snprintf(field[2], 20, "%f", delay);
+ g_snprintf(field[3], 20, "%f", jitter);
+ g_snprintf(field[4], 20, "%s", marker? "SET" : "");
+ g_snprintf(field[5], 29, "%s", status? "OK" : "NOK - Wrong sequence nr.");
+
+ gtk_clist_append(GTK_CLIST(forward? clist : clist_r), data);
+
+}
+
+/* whenever a RTP packet is seen by the tap listener */
+/* this function works as follows:
+ * 1) packets that are not displayed are ignored
+ * return
+ * 2) are we searching what could be the reversed connection (looking for reversed SSRC)
+ * if yes, do the parameters match (inversed IP and port combination from the forward one)?
+ * if yes, do we already have this SSRC stored
+ * if not store it
+ * 3) if not, is current packet matching the forward direction
+ * is it the first time we see a packet in this direction
+ * if yes, store some values, add a line to list and save the voice info
+ * in a temporary file if the codec is supported and the RTP data is ok
+ * if not, is it a packet with mark bit set (there was silence surpression)
+ * same as above, only we have to add some silence in front of the voice data
+ * if not, then this must be a normal packet
+ * store the values and voice data
+ * 4) if not, is current packet matching the reversed connection
+ * (same as for number 3)
+ */
+static int rtp_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, void *vpri)
+{
+ info_stat *rs=prs;
+ struct _rtp_info *pri=vpri;
+ guint i;
+ double n_time;
+ double n_jitter;
+ guint8 *data;
+ gint16 tmp;
+
+ /* we ignore packets that are not displayed */
+ if (pinfo->fd->flags.passed_dfilter == 0)
+ return 0;
+
+ /* are we looking for the SSRC of the reversed connection? */
+ if (rs->search_ssrc != FALSE) {
+ /* XXX what should be the rules for reversed connection?
+ * 1. It should should have same inversed IP and port numbers
+ * 2. If none are found, only inversed IP's - is this possible?
+ * 3. If none are found, there isn't any reversed connection
+ * XXX is it possible that the conversation is not P2P?
+ * Curretly it works only if it matches the number 1. */
+
+ /* have we found inverse parameters? */
+ if ( strcmp(ip_to_str(pinfo->src.data), rs->destination) == 0 &&
+ strcmp( ip_to_str(pinfo->dst.data), rs->source) == 0 ) {
+
+ /* do the ports also match? */
+ if ((rs->srcport == pinfo->destport) && (rs->dstport == pinfo->srcport)) {
+ /* ok, the ip and port combination does match
+ * do we already have this ssrc stored */
+ for(i=0; i< rs->reversed_ip_and_port; i++) {
+ if (pri->info_sync_src == *(rs->ssrc_tmp+i) )
+ return 0;
+ }
+
+ /* no, we found new ssrc, let's store it */
+ rs->ssrc_tmp = (guint32*)g_realloc(rs->ssrc_tmp,
+ (i+1)*sizeof(guint32));
+ *(rs->ssrc_tmp+i) = pri->info_sync_src;
+ rs->reversed_ip_and_port++;
+ return 0;
+ }
+ /* no, only ip addresses match */
+ /* XXX not implemented yet */
+ else {
+ rs->reversed_ip++;
+ return 0;
+ }
+
+ }
+ }
+
+ /* ok, we are not looking for SSRC of the reversed connection */
+ /* is it the forward direction?
+ * if yes, there 3 possibilities:
+ * a) is this the first packet we got in this direction?
+ * b) or is it a packet with the mark bit set?
+ * c) if neither then it is a "normal" packet */
+ else if (rs->ssrc_forward == pri->info_sync_src) {
+ /* first packet? */
+ if (rs->f_first_packet != FALSE) {
+ /* we store all the values */
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_delay = 0;
+ rs->f_jitter = 0;
+ rs->f_first_packet = FALSE;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_start_seq_nr = pri->info_seq_num;
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_total_nr++;
+ rs->f_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ rs->f_start_time = rs->f_time;
+ /* and add a row to clist; delay and jitter are 0 for the first packet */
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
+
+ /* and now save the voice info */
+
+ /* if we couldn't open the tmp file for writing, then we set the flag */
+ if (rs->f_fp == NULL) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = FILE_OPEN_ERROR;
+ return 0;
+ }
+ /* if the captured length and packet length aren't equal, we quit
+ * because there is some information missing */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we put the pointer at the beggining of the RTP data, that is
+ * at the end of the current frame minus the length of the
+ * RTP field plus 12 for the RTP header */
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ rs->f_saved = TRUE;
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ rs->f_saved = TRUE;
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* packet with mark bit set? */
+ if (pri->info_marker_set != FALSE) {
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ /* jitter is calculated as for RCTP - RFC 1889
+ * J = J + ( | D(i-1, i) | - J) / 16
+ * XXX the output there should be in timestamp (probably miliseconds)
+ * units expressed as an unsigned integer, so should we do it the same?
+ * (currently we use seconds)
+ *
+ * XXX Packet loss in RTCP is calculated as the difference between the
+ * number of packets expected and actually received, where for actually
+ * received the number is simply the count of packets as they arrive,
+ * including any late or duplicate packets (this means that the number
+ * can be negative). For example, if the seq numbers of the arrived
+ * packets are: 1,2,3,4,5,5,7,7,9,10 the expected number is 10 and the
+ * the number of actually captured frames is also 10. So in upper
+ * calculation there would be no losses. But there are 2 losses and
+ * 2 duplicate packets. Because this kind of statistic is rather
+ * useless (or confusing) we add the information, that there was
+ * an error with sequence number each time the sequence number was
+ * not one bigger than the previous one
+ */
+
+ /* jitter calculation */
+ n_jitter = rs->f_jitter + ( fabs(n_time-(rs->f_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
+
+ /* we add the information into the clist */
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
+ n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
+
+ /* when calculating expected rtp packets the seq number can wrap around
+ * so we have to count the number of cycles
+ * f_cycles counts the wraps around in forwarding connection and
+ * f_under is flag that indicates where we are
+ *
+ * XXX how to determine number of cycles with all possible lost, late
+ * and duplicated packets without any doubt? It seems to me, that
+ * because of all possible combination of late, duplicated or lost
+ * packets, this can only be more or less good approximation
+ *
+ * There are some combinations (rare but theoretically possible),
+ * where below code won't work correctly - statistic may be wrong then.
+ */
+
+ /* so if the current sequence number is less than the start one
+ * we assume, that there is another cycle running */
+ if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* what if the start seq nr was 0. Then the above condition will never
+ * be true, so we add another condition. XXX The problem would arise if
+ * if one of the packets with seq nr 0 or 65535 would be lost or late */
+ else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
+ (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->f_start_seq_nr)&&(rs->f_under!=FALSE)){
+ rs->f_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->f_seq_num+1 == pri->info_seq_num)
+ rs->f_seq_num = pri->info_seq_num;
+ /* XXX same problem as above */
+ else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->f_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->f_seq_num+1 < pri->info_seq_num) {
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->f_seq_num+1 > pri->info_seq_num)
+ rs->f_sequence++;
+
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_time = n_time;
+ rs->f_jitter = n_jitter;
+ rs->f_delta_timestamp = pri->info_timestamp - rs->f_timestamp;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->f_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* because the mark bit is set, we have to add some silence in front */
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we insert some silence */
+ /* XXX the amount of silence should be the difference between
+ * the last timestamp and the current one minus x in the
+ * I am not sure if x is equal the amount of information
+ * current packet? */
+ for(i=0; i<(rs->f_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ for(i=0; i < (rs->f_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ return 0;
+ }
+
+ /* normal packet in forward connection */
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->f_jitter + ( fabs (n_time-(rs->f_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->f_timestamp))/8000) - rs->f_jitter)/16;
+ rs->f_delay = n_time-(rs->f_time);
+ /* the delay is bigger than previous max delay, so store the delay and nr */
+ if (rs->f_delay > rs->f_max_delay) {
+ rs->f_max_delay = rs->f_delay;
+ rs->f_max_nr = pinfo->fd->num;
+ }
+ add_to_clist(TRUE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->f_time),
+ n_jitter, rs->f_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
+
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->f_start_seq_nr) && (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->f_stop_seq_nr == 65535) &&
+ (rs->f_under == FALSE)){
+ rs->f_cycles++;
+ rs->f_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->f_start_seq_nr+1)&&(rs->f_under!=FALSE)){
+ rs->f_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->f_seq_num+1 == pri->info_seq_num)
+ rs->f_seq_num = pri->info_seq_num;
+ else if ( (rs->f_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->f_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->f_seq_num+1 < pri->info_seq_num) {
+ rs->f_seq_num = pri->info_seq_num;
+ rs->f_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->f_seq_num+1 > pri->info_seq_num)
+ rs->f_sequence++;
+
+ rs->f_stop_seq_nr = pri->info_seq_num;
+ rs->f_time = n_time;
+ rs->f_jitter = n_jitter;
+ rs->f_timestamp = pri->info_timestamp;
+ rs->f_total_nr++;
+
+ /* save the voice information */
+ /* we do it only in following cases:
+ * - the codecs we support are g.711 alaw in ulaw
+ * - the captured length must equal the packet length
+ * - XXX we don't support it if there are padding bits
+ */
+ /* if there was already an error, we quit */
+ if (rs->f_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->f_saved = FALSE;
+ rs->f_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* cfile.pd points at the beggining of the actual packet. We have
+ * to move this pointer at the RTP data. This is the packet length,
+ * minus whole RTP data length (including the RTP header, that is
+ * why we add 12) */
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len - 12); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->f_fp);
+ rs->f_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->f_saved = FALSE;
+ rs->f_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* is it the reversed direction? */
+ else if (rs->ssrc_reversed == pri->info_sync_src) {
+ /* first packet? */
+ if (rs->r_first_packet !=FALSE) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_delay = 0;
+ rs->r_jitter = 0;
+ rs->r_first_packet = FALSE;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_start_seq_nr = pri->info_seq_num;
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_total_nr++;
+ rs->r_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ rs->r_start_time = rs->r_time;
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, 0, 0, TRUE, FALSE);
+
+ /* save it */
+ /* if we couldn't open the tmp file for writing, then we set the flag */
+ if (rs->r_fp == NULL) {
+ rs->r_saved = FALSE;
+ return 0;
+ }
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ rs->r_saved = TRUE;
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ rs->r_saved = TRUE;
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ /* packet with mark bit set? */
+ if (pri->info_marker_set != FALSE) {
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
+ n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, TRUE);
+
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
+ (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
+ rs->r_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->r_seq_num+1 == pri->info_seq_num)
+ rs->r_seq_num = pri->info_seq_num;
+ else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->r_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->r_seq_num+1 < pri->info_seq_num) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->r_seq_num+1 > pri->info_seq_num)
+ rs->r_sequence++;
+
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_time = n_time;
+ rs->r_jitter = n_jitter;
+ rs->r_delta_timestamp = pri->info_timestamp - rs->r_timestamp;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->r_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* because the mark bit is set, we have to add some silence in front */
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ /* we insert some silence */
+ for(i=0; i<(rs->r_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ for(i=0; i < (rs->r_delta_timestamp-pri->info_data_len+12); i++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)(0x55));
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ return 0;
+ }
+
+ /* normal packet in reversed connection */
+ n_time = (double)pinfo->fd->rel_secs +
+ (double) pinfo->fd->rel_usecs/1000000;
+ n_jitter = rs->r_jitter + ( fabs (n_time-(rs->r_time) -
+ ((double)(pri->info_timestamp)-
+ (double)(rs->r_timestamp))/8000) - rs->r_jitter)/16;
+ rs->r_delay = n_time-(rs->r_time);
+ if (rs->r_delay > rs->r_max_delay) {
+ rs->r_max_delay = rs->r_delay;
+ rs->r_max_nr = pinfo->fd->num;
+ }
+ add_to_clist(FALSE, pinfo->fd->num, pri->info_seq_num, n_time-(rs->r_time),
+ n_jitter, rs->r_seq_num+1 == pri->info_seq_num?TRUE:FALSE, FALSE);
+ /* count the cycles */
+ if ((pri->info_seq_num < rs->r_start_seq_nr) && (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ else if ((pri->info_seq_num == 0) && (rs->r_stop_seq_nr == 65535) &&
+ (rs->r_under == FALSE)){
+ rs->r_cycles++;
+ rs->r_under = TRUE;
+ }
+ /* the whole round is over, so reset the flag */
+ else if ((pri->info_seq_num>rs->r_start_seq_nr+1)&&(rs->r_under!=FALSE)){
+ rs->r_under = FALSE;
+ }
+
+ /* number of times where sequence number was not ok */
+ if ( rs->r_seq_num+1 == pri->info_seq_num)
+ rs->r_seq_num = pri->info_seq_num;
+ else if ( (rs->r_seq_num == 65535) && (pri->info_seq_num == 0) )
+ rs->r_seq_num = pri->info_seq_num;
+ /* lost packets */
+ else if (rs->r_seq_num+1 < pri->info_seq_num) {
+ rs->r_seq_num = pri->info_seq_num;
+ rs->r_sequence++;
+ }
+ /* late or duplicated */
+ else if (rs->r_seq_num+1 > pri->info_seq_num)
+ rs->r_sequence++;
+
+ rs->r_stop_seq_nr = pri->info_seq_num;
+ rs->r_time = n_time;
+ rs->r_jitter = n_jitter;
+ rs->r_timestamp = pri->info_timestamp;
+ rs->r_total_nr++;
+
+ /* save the voice information */
+ /* if there was already an error, we quit */
+ if (rs->r_saved == FALSE)
+ return 0;
+ /* if the captured length and packet length aren't equal, we quit */
+ if (pinfo->fd->pkt_len != pinfo->fd->cap_len) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_LENGTH;
+ return 0;
+ }
+ /* if padding bit is set, we don't do it yet */
+ if (pri->info_padding_set != FALSE) {
+ rs->r_saved = FALSE;
+ rs->r_error_type = PADDING_SET;
+ return 0;
+ }
+ /* is it the ulaw? */
+ if (pri->info_payload_type == 0) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len-12 ); i++, data++) {
+ tmp = (gint16 )ulaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* alaw? */
+ else if (pri->info_payload_type == 8) {
+ data = cfile.pd + (pinfo->fd->pkt_len - pri->info_data_len + 12);
+ for(i=0; i < (pri->info_data_len -12 ); i++, data++) {
+ tmp = (gint16 )alaw2linear((unsigned char)*data);
+ fwrite(&tmp, 2, 1, rs->r_fp);
+ rs->r_count++;
+ }
+ return 0;
+ }
+ /* unsupported codec or other error */
+ else {
+ rs->r_saved = FALSE;
+ rs->r_error_type = WRONG_CODEC;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/* XXX just copied from gtk/rpc_stat.c */
+void protect_thread_critical_region(void);
+void unprotect_thread_critical_region(void);
+
+
+/* here we close the rtp analysis dialog window and remove the tap listener */
+static void rtp_destroy_cb(GtkWidget *win _U_, gpointer data _U_)
+{
+ info_stat *rs=(info_stat *)data;
+
+ protect_thread_critical_region();
+ remove_tap_listener(rs);
+ unprotect_thread_critical_region();
+
+ /* xxx is this enough? */
+ g_free(rs->ssrc_tmp);
+ g_free(rs);
+
+ if (rs->f_fp != NULL)
+ fclose(rs->f_fp);
+ if (rs->r_fp != NULL)
+ fclose(rs->r_fp);
+ remove(f_tempname);
+ remove(r_tempname);
+
+ /* is there a save window open */
+ if (save_w != NULL)
+ gtk_widget_destroy(save_w);
+
+ /* Is there a save voice window open? */
+ if (voice_w != NULL)
+ gtk_widget_destroy(voice_w);
+
+ /* Note that we no longer have a "RTP Analyse" dialog box. */
+ rtp_w = NULL;
+}
+
+/* when the close button in rtp window was clicked */
+/* it seems to me that rtp_destroy_cb is automatically called, so we don't
+ * need to do the g_free... and rtp_w = NULL ... */
+static void rtp_destroy (GtkWidget *close_bt _U_, gpointer parent_w)
+{
+ gtk_grab_remove(GTK_WIDGET(parent_w));
+ gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+/* we search the rtp.ssrc node here (thanks to Guy Harris - code here is magic for me */
+static guint32 process_node(proto_item *ptree_node, header_field_info *hfinformation)
+{
+ field_info *finfo;
+ proto_item *proto_sibling_node;
+ header_field_info *hfssrc;
+ guint32 ssrc;
+
+ finfo = PITEM_FINFO(ptree_node);
+
+ if (hfinformation==(finfo->hfinfo)) {
+ hfssrc = proto_registrar_get_byname("rtp.ssrc");
+ if (hfssrc == NULL)
+ return 0;
+ for(ptree_node=g_node_first_child(ptree_node); ptree_node!=NULL;
+ ptree_node=g_node_next_sibling(ptree_node)) {
+ finfo=PITEM_FINFO(ptree_node);
+ if (hfssrc==finfo->hfinfo) {
+ ssrc = fvalue_get_integer(finfo->value);
+ return ssrc;
+ }
+ }
+ }
+
+ proto_sibling_node = g_node_next_sibling(ptree_node);
+
+ if (proto_sibling_node) {
+ ssrc = process_node(proto_sibling_node, hfinformation);
+ return ssrc;
+ }
+ else
+ return 0;
+}
+
+/* here we search the rtp protocol */
+static guint32 process_tree(proto_tree *protocol_tree)
+{
+ proto_item *ptree_node;
+ header_field_info *hfinformation;
+
+ hfinformation = proto_registrar_get_byname("rtp");
+ if (hfinformation == NULL)
+ return 0;
+
+ ptree_node = g_node_first_child(protocol_tree);
+ if (!ptree_node)
+ return 0;
+
+ return process_node(ptree_node, hfinformation);
+}
+
+/* when we want to update the information */
+static void refresh_cb(GtkWidget *w _U_, void *pri)
+{
+ info_stat *rs=pri;
+
+ gtk_clist_clear(GTK_CLIST(clist));
+ gtk_clist_clear(GTK_CLIST(clist_r));
+ redissect_packets(&cfile);
+ draw_stat(rs);
+}
+
+/* when the user clicks the close button */
+static void voice_close_cb(GtkWidget *close_bt _U_, gpointer parent_w _U_)
+{
+ gtk_widget_destroy(GTK_WIDGET(parent_w));
+}
+
+static void voice_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+ if (save_w != NULL)
+ gtk_widget_destroy(GTK_WIDGET(save_w));
+
+ /* Note that we no longer have a Save voice info dialog box. */
+ voice_w = NULL;
+}
+
+
+/* the user wants to save in a file */
+/* XXX support for different formats is currently commented out */
+static void ok_button_cb(GtkWidget *ok_bt, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ GtkWidget *entry, *rev, *forw, *both;
+ /*GtkWidget *wav, *au, *sw;*/
+ gchar *g_dest;
+ gint channels /*, format*/;
+
+ entry = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "file_entry");
+ /*wav = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "wav_rb");
+ au = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "au_rb");
+ sw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "sw_rb");*/
+ rev = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "reversed_rb");
+ forw = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "forward_rb");
+ both = (GtkWidget *)OBJECT_GET_DATA(ok_bt, "both_rb");
+ g_dest = gtk_entry_get_text(GTK_ENTRY(entry));
+
+ /* XXX user clicks the ok button, but we know we can't save the voice info because f.e.
+ * we don't support that codec. So we pop up a warning. Maybe it would be better to
+ * disable the ok button or disable the buttons for direction if only one is not ok. The
+ * problem is if we open the save voice dialog and then click the refresh button and maybe
+ * the state changes, so we can't save anymore. In this case we should be able to update
+ * the buttons. For now it is easier if we put the warning when the ok button is pressed.
+ */
+
+ /* we can not save in both dirctions */
+ if ((rs->f_saved == FALSE) && (rs->r_saved == FALSE) && (GTK_TOGGLE_BUTTON (both)->active)) {
+ /* there are many combinations here, we just exit when first matches */
+ if ((rs->f_error_type == WRONG_CODEC) || (rs->r_error_type == WRONG_CODEC))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: Unsupported codec!");
+ else if ((rs->f_error_type == WRONG_LENGTH) || (rs->r_error_type == WRONG_LENGTH))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: Wrong length of captured packets!");
+ else if ((rs->f_error_type == PADDING_SET) || (rs->r_error_type == PADDING_SET))
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save forward direction */
+ else if ((rs->f_saved == FALSE) && ((GTK_TOGGLE_BUTTON (forw)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (rs->f_error_type == WRONG_CODEC)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: Unsupported codec!");
+ else if (rs->f_error_type == WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: Wrong length of captured packets!");
+ else if (rs->f_error_type == PADDING_SET)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: RTP data with padding!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save forward direction in a file: File I/O problem!");
+ return;
+ }
+ /* we can not save reversed direction */
+ else if ((rs->r_saved == FALSE) && ((GTK_TOGGLE_BUTTON (rev)->active) ||
+ (GTK_TOGGLE_BUTTON (both)->active))) {
+ if (rs->r_error_type == WRONG_CODEC)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: Unsupported codec!");
+ else if (rs->r_error_type == WRONG_LENGTH)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: Wrong length of captured packets!");
+ else if (rs->r_error_type == PADDING_SET)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: RTP data with padding!");
+ else if (rs->r_error_type == NO_DATA)
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: No RTP data!");
+ else
+ simple_dialog(ESD_TYPE_CRIT, NULL,
+ "Can't save reversed direction in a file: File I/O problem!");
+ return;
+ }
+
+ /* if the file text entry is empty */
+ if (!g_dest[0]) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "Saving to file, but no file specified.");
+ return;
+ }
+
+ /*if (GTK_TOGGLE_BUTTON (wav)->active)
+ format = 1;
+ else if (GTK_TOGGLE_BUTTON (au)->active)
+ format = 2;
+ else if (GTK_TOGGLE_BUTTON (sw)->active)
+ format = 3;*/
+
+ if (GTK_TOGGLE_BUTTON (rev)->active)
+ channels = 2;
+ else if (GTK_TOGGLE_BUTTON (both)->active)
+ channels = 3;
+ else
+ channels = 1;
+
+ if(!copy_file(g_dest, channels/*, format*/, rs)) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "An error occured while saving voice in a file!");
+ return;
+ }
+
+ if (save_w != NULL)
+ gtk_widget_destroy(GTK_WIDGET(save_w));
+
+ /* XXX I get GTK warning (sometimes?)!!! */
+ gtk_widget_destroy(GTK_WIDGET(voice_w));
+}
+
+static void save_ok_button_cb(GtkWidget *w _U_, gpointer data)
+{
+ gchar *f_name;
+
+ f_name = g_strdup(gtk_file_selection_get_filename(GTK_FILE_SELECTION (data)));
+
+ /* Perhaps the user specified a directory instead of a file.
+ Check whether they did. */
+ if (test_for_directory(f_name) == EISDIR) {
+ /* It's a directory - set the file selection box to display it. */
+ set_last_open_dir(f_name);
+ g_free(f_name);
+ gtk_file_selection_set_filename(GTK_FILE_SELECTION(data), last_open_dir);
+ return;
+ }
+
+ gtk_entry_set_text(GTK_ENTRY(OBJECT_GET_DATA(data, "file_entry")), f_name);
+ gtk_widget_destroy(GTK_WIDGET(data));
+
+ g_free(f_name);
+}
+
+static void save_cancel_button_cb(GtkWidget *w _U_, gpointer data)
+{
+ gtk_widget_destroy(GTK_WIDGET(data));
+}
+
+static void save_destroy_cb(GtkWidget *win _U_, gpointer user_data _U_)
+{
+ /* Note that we no longer have a Save voice info dialog box. */
+ save_w = NULL;
+}
+
+/* file selection window */
+static void file_selection_cb(GtkWidget *w _U_, gpointer file_entry)
+{
+ if (save_w != NULL) {
+ /* Yes. Just re-activate that dialog box. */
+ reactivate_window(save_w);
+ return;
+ }
+
+ save_w = gtk_file_selection_new ("Ethereal: Save to File");
+ gtk_signal_connect(GTK_OBJECT(save_w), "destroy", GTK_SIGNAL_FUNC(save_destroy_cb), NULL);
+
+ OBJECT_SET_DATA(save_w, "file_entry", file_entry);
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->cancel_button), "clicked",
+ GTK_SIGNAL_FUNC(save_cancel_button_cb), GTK_OBJECT(save_w));
+
+ gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(save_w)->ok_button), "clicked",
+ GTK_SIGNAL_FUNC(save_ok_button_cb), GTK_OBJECT(save_w));
+
+ gtk_widget_show(save_w);
+}
+
+/* when the user wants to save the voice information in a file */
+/* XXX support for different formats is currently commented out */
+static void voice_cb(GtkWidget *w _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+
+ GtkWidget *vertb;
+ GtkWidget *table1;
+ GtkWidget *label_format;
+ GtkWidget *channels_label;
+ /*GSList *format_group = NULL;*/
+ GSList *channels_group = NULL;
+ GtkWidget *forward_rb;
+ GtkWidget *reversed_rb;
+ GtkWidget *both_rb;
+ /*GtkWidget *wav_rb; GtkWidget *au_rb; GtkWidget *sw_rb;*/
+ GtkWidget *hbox3;
+ GtkWidget *file_button;
+ GtkWidget *file_entry;
+ GtkWidget *hbox4;
+ GtkWidget *ok_bt;
+ GtkWidget *cancel_bt;
+
+ /* if we can't save in a file: wrong codec, cut packets or other errors */
+ /* shold the error arise here or later when you click ok button ?
+ * if we do it here, then we must disable the refresh button, so we don't do it here */
+
+ if (voice_w != NULL) {
+ /* There's already a Save voice info dialog box; reactivate it. */
+ reactivate_window(voice_w);
+ return;
+ }
+
+ voice_w = dlg_window_new("Ethereal: Save voice data");
+ gtk_signal_connect(GTK_OBJECT(voice_w), "destroy",
+ GTK_SIGNAL_FUNC(voice_destroy_cb), NULL);
+
+ /* Container for each row of widgets */
+ vertb = gtk_vbox_new(FALSE, 0);
+ gtk_container_border_width(GTK_CONTAINER(vertb), 5);
+ gtk_container_add(GTK_CONTAINER(voice_w), vertb);
+ gtk_widget_show (vertb);
+
+ table1 = gtk_table_new (2, 4, FALSE);
+ gtk_widget_show (table1);
+ gtk_box_pack_start (GTK_BOX (vertb), table1, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (table1), 10);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 20);
+
+ label_format = gtk_label_new ("Format: .au (ulaw, 8 bit, 8000 Hz, mono) ");
+ gtk_widget_show (label_format);
+ gtk_table_attach (GTK_TABLE (table1), label_format, 0, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ /* we support .au - ulaw*/
+/* wav_rb = gtk_radio_button_new_with_label (format_group, ".wav");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (wav_rb));
+ gtk_widget_show (wav_rb);
+ gtk_table_attach (GTK_TABLE (table1), wav_rb, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ sw_rb = gtk_radio_button_new_with_label (format_group, "8 kHz, 16 bit ");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (sw_rb));
+ gtk_widget_show (sw_rb);
+ gtk_table_attach (GTK_TABLE (table1), sw_rb, 2, 3, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ au_rb = gtk_radio_button_new_with_label (format_group, ".au");
+ format_group = gtk_radio_button_group (GTK_RADIO_BUTTON (au_rb));
+ gtk_widget_show (au_rb);
+ gtk_table_attach (GTK_TABLE (table1), au_rb, 3, 4, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ */
+
+ channels_label = gtk_label_new ("Channels:");
+ gtk_widget_show (channels_label);
+ gtk_table_attach (GTK_TABLE (table1), channels_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (channels_label), 0, 0.5);
+
+ forward_rb = gtk_radio_button_new_with_label (channels_group, "forward ");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (forward_rb));
+ gtk_widget_show (forward_rb);
+ gtk_table_attach (GTK_TABLE (table1), forward_rb, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ reversed_rb = gtk_radio_button_new_with_label (channels_group, "reversed");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (reversed_rb));
+ gtk_widget_show (reversed_rb);
+ gtk_table_attach (GTK_TABLE (table1), reversed_rb, 2, 3, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ both_rb = gtk_radio_button_new_with_label (channels_group, "both");
+ channels_group = gtk_radio_button_group (GTK_RADIO_BUTTON (both_rb));
+ gtk_widget_show (both_rb);
+ gtk_table_attach (GTK_TABLE (table1), both_rb, 3, 4, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(both_rb), TRUE);
+
+ /* if one direction is nok we don't allow saving
+ XXX this is not ok since the user can click the refresh button and cause changes
+ but we can not update this window. So we move all the decision on the time the ok
+ button is clicked
+ if (rs->f_saved == FALSE) {
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(reversed_rb), TRUE);
+ gtk_widget_set_sensitive(forward_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ else if (rs->r_saved == FALSE) {
+ gtk_widget_set_sensitive(reversed_rb, FALSE);
+ gtk_widget_set_sensitive(both_rb, FALSE);
+ }
+ */
+ hbox3 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox3);
+ gtk_box_pack_start (GTK_BOX (vertb), hbox3, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox3), 10);
+
+ file_button = gtk_button_new_with_label ("File:");
+ gtk_widget_show (file_button);
+ gtk_box_pack_start (GTK_BOX (hbox3), file_button, FALSE, FALSE, 0);
+
+ file_entry = gtk_entry_new ();
+ gtk_widget_show (file_entry);
+ gtk_box_pack_start (GTK_BOX (hbox3), file_entry, TRUE, TRUE, 10);
+
+ hbox4 = gtk_hbox_new (FALSE, 0);
+ gtk_widget_show (hbox4);
+ gtk_box_pack_start (GTK_BOX (vertb), hbox4, FALSE, FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (hbox4), 10);
+
+ ok_bt = gtk_button_new_with_label ("OK");
+ gtk_widget_show (ok_bt);
+ gtk_box_pack_start (GTK_BOX (hbox4), ok_bt, TRUE, FALSE, 0);
+ gtk_widget_set_usize (ok_bt, 60, -2);
+ OBJECT_SET_DATA(ok_bt, "file_entry", file_entry);
+ /*OBJECT_SET_DATA(ok_bt, "wav_rb", wav_rb);
+ OBJECT_SET_DATA(ok_bt, "au_rb", au_rb);
+ OBJECT_SET_DATA(ok_bt, "sw_rb", sw_rb);*/
+ OBJECT_SET_DATA(ok_bt, "forward_rb", forward_rb);
+ OBJECT_SET_DATA(ok_bt, "reversed_rb", reversed_rb);
+ OBJECT_SET_DATA(ok_bt, "both_rb", both_rb);
+
+ cancel_bt = gtk_button_new_with_label (" Cancel ");
+ gtk_widget_show (cancel_bt);
+ gtk_box_pack_start (GTK_BOX (hbox4), cancel_bt, TRUE, FALSE, 0);
+ gtk_widget_set_usize (cancel_bt, 60, -2);
+
+ gtk_signal_connect(GTK_OBJECT(cancel_bt), "clicked",
+ GTK_SIGNAL_FUNC(voice_close_cb), GTK_OBJECT(voice_w));
+
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(ok_button_cb), rs);
+
+ gtk_signal_connect(GTK_OBJECT(file_button), "clicked",
+ GTK_SIGNAL_FUNC(file_selection_cb), file_entry);
+
+ gtk_widget_show(voice_w);
+}
+
+/* all the graphics on the window is done here */
+static void add_rtp_notebook(void *pri)
+{
+ info_stat *rs=pri;
+
+ GtkWidget *notebook, *page, *page_r, *label, *label1, *label2, *label3;
+ GtkWidget *scrolled_window, *scrolled_window_r/*, *frame, *text, *label4, *page_help*/;
+ GtkWidget *box4, *voice_bt, *refresh_bt, *close_bn;
+
+ gchar *titles[6] = {"Packet nr.", "Sequence", "Delay (s)", "Jitter (s)", "Marker", "Status"};
+ gchar label_forward[150];
+ gchar label_reverse[150];
+
+ g_snprintf(label_forward, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ rs->source, rs->srcport, rs->destination, rs->dstport, rs->ssrc_forward);
+ g_snprintf(label_reverse, 149,
+ "Analysing connection from %s port %u to %s port %u SSRC = %u\n",
+ rs->destination, rs->dstport, rs->source, rs->srcport, rs->ssrc_reversed);
+
+ gtk_widget_destroy(main_vb);
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
+ gtk_widget_show(main_vb);
+
+ /* Start a nootbook for flipping between sets of changes */
+ notebook = gtk_notebook_new();
+ gtk_container_add(GTK_CONTAINER(main_vb), notebook);
+ gtk_object_set_data(GTK_OBJECT(rtp_w), "notebook", notebook);
+
+ /* page for forward connection */
+ page = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page), 20);
+
+ /* scrolled window */
+ scrolled_window = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+
+ /* direction label */
+ label1 = gtk_label_new(label_forward);
+ gtk_box_pack_start(GTK_BOX(page), label1, FALSE, FALSE, 0);
+
+ /* place for some statistics */
+ max = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page), max, FALSE, FALSE, 5);
+
+ /* clist for the information */
+ clist = gtk_clist_new_with_titles(6, titles);
+ gtk_widget_show(clist);
+ gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
+ gtk_box_pack_start(GTK_BOX(page), scrolled_window, TRUE, TRUE, 0);
+
+ /* and the label */
+ label = gtk_label_new(" Forward Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, label);
+
+ /* column width and justification */
+ gtk_clist_set_column_width(GTK_CLIST(clist), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist), 5, GTK_JUSTIFY_CENTER);
+
+ /* same page for reversed connection */
+ page_r = gtk_vbox_new(FALSE, 5);
+ gtk_container_set_border_width(GTK_CONTAINER(page_r), 20);
+ scrolled_window_r = gtk_scrolled_window_new(NULL, NULL);
+ gtk_widget_set_usize(scrolled_window_r, 600, 200);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_r),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
+ label3 = gtk_label_new(label_reverse);
+ gtk_box_pack_start(GTK_BOX(page_r), label3, FALSE, FALSE, 0);
+ max_r = gtk_label_new("\n\n");
+ gtk_box_pack_end(GTK_BOX(page_r), max_r, FALSE, FALSE, 5);
+ clist_r = gtk_clist_new_with_titles(6, titles);
+ gtk_widget_show(clist_r);
+ gtk_container_add(GTK_CONTAINER(scrolled_window_r), clist_r);
+ gtk_box_pack_start(GTK_BOX(page_r), scrolled_window_r, TRUE, TRUE, 0);
+ label2 = gtk_label_new(" Reversed Direction ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_r, label2);
+
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 1, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 2, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 3, 80);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 4, 40);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 0, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 1, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 2, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 3, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 4, GTK_JUSTIFY_CENTER);
+ gtk_clist_set_column_justification(GTK_CLIST(clist_r), 5, GTK_JUSTIFY_CENTER);
+
+ /* page for help&about or future
+ page_help = gtk_hbox_new(FALSE, 5);
+ label4 = gtk_label_new(" Future ");
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page_help, label4);
+ frame = gtk_frame_new("");
+ text = gtk_label_new("\n\nMaybe some more statistics: delay and jitter distribution,...");
+ gtk_label_set_justify(GTK_LABEL(text), GTK_JUSTIFY_LEFT);
+ gtk_container_add(GTK_CONTAINER(frame), text);
+ gtk_container_set_border_width(GTK_CONTAINER(frame), 20);
+ gtk_box_pack_start(GTK_BOX(page_help), frame, TRUE, TRUE, 0);
+*/
+ /* show all notebooks */
+ gtk_widget_show_all(notebook);
+
+ /* and the buttons */
+ box4 = gtk_hbutton_box_new();
+ gtk_box_pack_start(GTK_BOX(main_vb), box4, FALSE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(box4), 10);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(box4), GTK_BUTTONBOX_SPREAD);
+ gtk_widget_show(box4);
+
+ voice_bt = gtk_button_new_with_label("Save voice data");
+ gtk_container_add(GTK_CONTAINER(box4), voice_bt);
+ gtk_widget_show(voice_bt);
+ gtk_signal_connect(GTK_OBJECT(voice_bt), "clicked",
+ GTK_SIGNAL_FUNC(voice_cb), rs);
+
+ refresh_bt = gtk_button_new_with_label("Refresh");
+ gtk_container_add(GTK_CONTAINER(box4), refresh_bt);
+ gtk_widget_show(refresh_bt);
+ gtk_signal_connect(GTK_OBJECT(refresh_bt), "clicked",
+ GTK_SIGNAL_FUNC(refresh_cb), rs);
+
+ close_bn = gtk_button_new_with_label("Close");
+ gtk_container_add(GTK_CONTAINER(box4), close_bn);
+ gtk_widget_show(close_bn);
+ gtk_signal_connect(GTK_OBJECT(close_bn), "clicked",
+ GTK_SIGNAL_FUNC(rtp_destroy), GTK_OBJECT(rtp_w));
+
+ redissect_packets(&cfile);
+
+ draw_stat(rs);
+}
+
+
+/* when we click on the selected row it copies that ssrc value into ssrc_reversed */
+static void get_selected_ssrc(GtkWidget *clist_r, gint row, gint column,
+ GdkEventButton *event _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ gchar *text;
+
+ gtk_clist_get_text(GTK_CLIST(clist_r), row, column, &text);
+ /* XXX is this strtoul portable for guint32? */
+ rs->ssrc_reversed = strtoul(text, (char **)NULL, 10);
+ return;
+}
+
+/* when we click apply button in ssrc reversed dialog */
+static void apply_selected_ssrc(GtkWidget *w _U_, gpointer data)
+{
+ info_stat *rs=(info_stat *)data;
+ add_rtp_notebook(rs);
+}
+
+/* this function goes through all the packets that have the same ip and port combination
+ * (only inversed) as the forward direction (XXX what if the reversed direction doesn't use
+ * the same ports???) and looks for different SSRC values. This can happen if you capture
+ * two RTP conversations one after another from the same pair of phones (PC's).
+ * Both have same IP's and can also have same port numbers, so they (should) differ only
+ * in SSRC values. In such case we get a list of ssrc values and we have to choose the right
+ * one from the list. If there is only one or none, we do it automatically */
+static void get_reversed_ssrc(void *prs)
+{
+ info_stat *ri = prs;
+ GtkWidget *scroll_r, *clist_r, *ok_bt, *label, *label2, *label1, *main_hbnbox;
+ gchar temp[150];
+ guint i;
+
+ switch(ri->reversed_ip_and_port)
+ {
+ /* in case we haven't found any reversed ssrc */
+ /* XXX in this case we could look for the inversed IP only */
+ case 0: {
+ ri->ssrc_reversed = 0;
+ ri->search_ssrc = FALSE;
+ add_rtp_notebook(ri);
+ return;
+ }
+ /* in case we found exactly one matching ssrc for reversed connection */
+ case 1: {
+ ri->ssrc_reversed = ri->ssrc_tmp[0];
+ ri->search_ssrc = FALSE;
+ add_rtp_notebook(ri);
+ return;
+ }
+ /* there is more then one matching ssrc, so we have to choose between them */
+ default: {
+ ri->search_ssrc = FALSE;
+ /* let's draw the window */
+ label = gtk_label_new("Found more SSRC values for the reversed\n"
+ "connection with following parameters:\n");
+ g_snprintf(temp, 149, "Source %s port %u Destination %s port %u",
+ ri->destination, ri->dstport, ri->source, ri->srcport);
+ label2 = gtk_label_new(temp);
+ gtk_box_pack_start(GTK_BOX(main_vb), label, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(main_vb), label2, FALSE, FALSE, 0);
+ scroll_r = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll_r),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ clist_r = gtk_clist_new(1);
+ gtk_clist_set_column_width(GTK_CLIST(clist_r), 0, 80);
+ gtk_container_add(GTK_CONTAINER(scroll_r), clist_r);
+ gtk_box_pack_start(GTK_BOX(main_vb), scroll_r, TRUE, TRUE, 0);
+ label1 = gtk_label_new("Select one value and click apply");
+ gtk_box_pack_start(GTK_BOX(main_vb), label1, FALSE, FALSE, 0);
+
+ main_hbnbox = gtk_hbutton_box_new();
+ gtk_box_pack_start(GTK_BOX(main_vb), main_hbnbox, FALSE, TRUE, 0);
+ gtk_container_set_border_width(GTK_CONTAINER(main_hbnbox), 10);
+ gtk_button_box_set_layout(GTK_BUTTON_BOX(main_hbnbox),
+ GTK_BUTTONBOX_SPREAD);
+ gtk_widget_show(main_hbnbox);
+
+ ok_bt = gtk_button_new_with_label("Apply");
+ gtk_container_add(GTK_CONTAINER(main_hbnbox), ok_bt);
+ gtk_signal_connect(GTK_OBJECT(clist_r), "select_row",
+ GTK_SIGNAL_FUNC(get_selected_ssrc), ri);
+ gtk_signal_connect(GTK_OBJECT(ok_bt), "clicked",
+ GTK_SIGNAL_FUNC(apply_selected_ssrc), ri);
+
+ /* add all the ssrc values in the clist */
+ /* XXX I'm sure the tmp variable could be avoided here
+ * i tried to assign guint32 from ri->ssrc_tmp somehow to gchar **text
+ * but gave up. So if you can do this, just go ahead */
+ for (i=0; i < ri->reversed_ip_and_port; i++) {
+ gchar *text[0];
+ gchar tmp[20];
+ g_snprintf(tmp, 20, "%u", ri->ssrc_tmp[i]);
+ text[0] = (gchar *)&tmp;
+ gtk_clist_append(GTK_CLIST(clist_r), text);
+ }
+
+ gtk_clist_select_row(GTK_CLIST(clist_r), 0, 0);
+
+ gtk_widget_show(label);
+ gtk_widget_show(label1);
+ gtk_widget_show(label2);
+ gtk_widget_show(ok_bt);
+ gtk_widget_show(clist_r);
+ gtk_widget_show(scroll_r);
+ }
+ }
+}
+
+/* when the user clicks the RTP dialog button */
+void rtp_analyse_cb(GtkWidget *w _U_, gpointer data _U_)
+{
+ info_stat *rs;
+ gchar filter_text[]="rtp";
+ dfilter_t *sfcode;
+ capture_file *cf;
+ epan_dissect_t *edt;
+ gint err;
+ gboolean frame_matched;
+ frame_data *fdata;
+
+ /* There's already a "Display Options" dialog box; reactivate it. */
+ if (rtp_w != NULL) {
+ reactivate_window(rtp_w);
+ return;
+ }
+
+ /* Try to compile the filter. */
+ if (!dfilter_compile(filter_text, &sfcode)) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, dfilter_error_msg);
+ return;
+ }
+ /* we load the current file into cf variable */
+ cf = &cfile;
+ fdata = cf->current_frame;
+
+ /* we are on the selected frame now */
+ if (fdata == NULL)
+ return; /* if we exit here it's an error */
+
+ /* XXX instead of looking for RTP protocol like this, we could do the process_node() staff */
+ /* dissect the current frame */
+ wtap_seek_read(cf->wth, fdata->file_off, &cf->pseudo_header, cf->pd, fdata->cap_len, &err);
+ edt = epan_dissect_new(TRUE, FALSE);
+ epan_dissect_prime_dfilter(edt, sfcode);
+ epan_dissect_run(edt, &cf->pseudo_header, cf->pd, fdata, &cf->cinfo);
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+
+ /* if it is not an rtp frame, exit */
+ frame_matched = dfilter_apply_edt(sfcode, edt);
+ if (frame_matched != 1) {
+ epan_dissect_free(edt);
+ simple_dialog(ESD_TYPE_CRIT, NULL, "You didn't choose a RTP packet!");
+ return;
+ }
+
+ /* in rs we put all the info */
+ rs=g_malloc(sizeof(info_stat));
+
+ /* ok, it is a RTP frame, so let's get the ip and port values */
+ rs->srcport = edt->pi.srcport;
+ rs->dstport = edt->pi.destport;
+ strncpy(rs->source, ip_to_str(edt->pi.src.data), 16);
+ strncpy(rs->destination, ip_to_str(edt->pi.dst.data), 16);
+
+ /* now we need the SSRC value of the current frame */
+ rs->ssrc_forward = process_tree(edt->tree);
+ if (rs->ssrc_forward == 0) {
+ simple_dialog(ESD_TYPE_CRIT, NULL, "SSRC value couldn't be found!");
+ return;
+ }
+
+ /* now we have all the information about the forwarding connection
+ * we need to go through all the packets and search for reversed connection
+ */
+ rs->search_ssrc = TRUE;
+ rs->ssrc_reversed = 0;
+ rs->reversed_ip = 0;
+ rs->reversed_ip_and_port = 0;
+ rs->ssrc_tmp = NULL;
+
+/* XXX compiler warning:passing arg 5 of `register_tap_listener' from incompatible pointer type */
+ if(register_tap_listener("rtp", rs, NULL, rtp_reset, rtp_packet, rtp_draw)){
+ printf("ethereal: rtp_init() failed to attach the tap.\n");
+ /* XXX is this enough or do I have to free anything else? */
+ g_free(rs);
+ exit(1);
+ }
+
+ /* let's draw the window */
+ rtp_w = dlg_window_new("Ethereal: RTP Analyse");
+ gtk_window_set_position (GTK_WINDOW (rtp_w), GTK_WIN_POS_CENTER);
+ gtk_signal_connect(GTK_OBJECT(rtp_w), "destroy",
+ GTK_SIGNAL_FUNC(rtp_destroy_cb), rs);
+
+ /* Container for each row of widgets */
+ main_vb = gtk_vbox_new(FALSE, 3);
+ gtk_container_border_width(GTK_CONTAINER(main_vb), 5);
+ gtk_container_add(GTK_CONTAINER(rtp_w), main_vb);
+ gtk_widget_show(main_vb);
+
+ /* file names for storing sound data */
+ tmpnam(f_tempname);
+ tmpnam(r_tempname);
+ rs->f_fp = NULL;
+ rs->r_fp = NULL;
+
+ redissect_packets(cf);
+
+ /* so how many reversed connection we have ? */
+ get_reversed_ssrc(rs);
+
+ /* and finally display this window */
+ gtk_widget_show(rtp_w);
+}
+
+static void
+rtp_analyse_init(char *dummy _U_)
+{
+ rtp_analyse_cb(NULL, NULL);
+}
+
+/* XXX compiler warning:passing arg 2 of `register_ethereal_tap' from incompatible pointer type */
+void
+register_tap_listener_gtkrtp(void)
+{
+ register_ethereal_tap("rtp", rtp_analyse_init, NULL, NULL);
+}
+
+
+/* here we save it into a file that user specified */
+/* XXX what about endians here? could go something wrong? */
+static gboolean copy_file(gchar *dest, gint channels, /*gint format,*/ void *data)
+{
+ info_stat *rs=(info_stat *)data;
+ int to_fd, forw_fd, rev_fd, fread = 0, rread = 0, fwritten, rwritten;
+ gint16 f_pd;
+ gint16 r_pd;
+ gchar pd[1];
+ guint32 f_write_silence = 0;
+ guint32 r_write_silence = 0;
+ progdlg_t *progbar;
+ guint32 progbar_count, progbar_quantum, progbar_nextstep = 0, count = 0;
+ gboolean stop_flag = FALSE;
+
+ forw_fd = open(f_tempname, O_RDONLY | O_BINARY);
+ if (forw_fd < 0)
+ return FALSE;
+ rev_fd = open(r_tempname, O_RDONLY | O_BINARY);
+ if (rev_fd < 0) {
+ close(forw_fd);
+ return FALSE;
+ }
+
+ /* open file for saving */
+ to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+ if (to_fd < 0) {
+ close(forw_fd);
+ close(rev_fd);
+ return FALSE;
+ }
+
+ progbar = create_progress_dlg("Saving voice in a file", dest, "Stop", &stop_flag);
+
+ /* First we write the .au header. XXX Hope this is endian independant */
+ /* the magic word 0x2e736e64 == .snd */
+ *pd = (unsigned char)0x2e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x73; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x6e; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x64; write(to_fd, pd, 1);
+ /* header offset == 24 bytes */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x18; write(to_fd, pd, 1);
+ /* total length, it is permited to set this to 0xffffffff */
+ *pd = (unsigned char)0xff; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ /* encoding format == 8 bit ulaw */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+ /* sample rate == 8000 Hz */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x1f; write(to_fd, pd, 1);
+ *pd = (unsigned char)0x40; write(to_fd, pd, 1);
+ /* channels == 1 */
+ *pd = (unsigned char)0x00; write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ write(to_fd, pd, 1);
+ *pd = (unsigned char)0x01; write(to_fd, pd, 1);
+
+ switch (channels) {
+ /* only forward direction */
+ case 1: {
+ progbar_count = rs->f_count;
+ progbar_quantum = rs->f_count/100;
+ while ((fread = read(forw_fd, &f_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(f_pd);
+ fwritten = write(to_fd, pd, 1);
+ if ((fwritten*2 < fread) || (fwritten < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* only reversed direction */
+ case 2: {
+ progbar_count = rs->r_count;
+ progbar_quantum = rs->r_count/100;
+ while ((rread = read(rev_fd, &r_pd, 2)) > 0) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ *pd = (unsigned char)linear2ulaw(r_pd);
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten*2 < rread) || (rwritten < 0) || (rread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ break;
+ }
+ /* both directions */
+ default: {
+ (rs->f_count > rs->r_count) ? (progbar_count = rs->f_count) :
+ (progbar_count = rs->r_count);
+ progbar_quantum = progbar_count/100;
+ /* since conversation in one way can start later than in the other one,
+ * we have to write some silence information for one channel */
+ if (rs->f_start_time > rs->r_start_time) {
+ f_write_silence = (rs->f_start_time-rs->r_start_time)*8000;
+ }
+ else if (rs->f_start_time < rs->r_start_time) {
+ r_write_silence = (rs->r_start_time-rs->f_start_time)*8000;
+ }
+ for(;;) {
+ if(stop_flag)
+ break;
+ if((count > progbar_nextstep) && (count <= progbar_count)) {
+ update_progress_dlg(progbar,
+ (gfloat) count/progbar_count, "Saving");
+ progbar_nextstep = progbar_nextstep + progbar_quantum;
+ }
+ count++;
+ if(f_write_silence > 0) {
+ rread = read(rev_fd, &r_pd, 2);
+ f_pd = 0;
+ fread = 1;
+ f_write_silence--;
+ }
+ else if(r_write_silence > 0) {
+ fread = read(forw_fd, &f_pd, 2);
+ r_pd = 0;
+ rread = 1;
+ r_write_silence--;
+ }
+ else {
+ fread = read(forw_fd, &f_pd, 2);
+ rread = read(rev_fd, &r_pd, 2);
+ }
+ if ((rread == 0) && (fread == 0))
+ break;
+ *pd = (unsigned char)linear2ulaw( (f_pd + r_pd)/2 );
+ rwritten = write(to_fd, pd, 1);
+ if ((rwritten < 0) || (rread < 0) || (fread < 0)) {
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ destroy_progress_dlg(progbar);
+ return FALSE;
+ }
+ }
+ }
+ }
+ destroy_progress_dlg(progbar);
+ close(forw_fd);
+ close(rev_fd);
+ close(to_fd);
+ return TRUE;
+
+}
+