VoIP Calls changes: Add the file name to the title window in VoIP calls, Voip graph...
[obnox/wireshark/wip.git] / gtk / rtp_player.c
1  /* rtp_player.c
2  *
3  * $Id$
4  *
5  *  Copyright 2006, Alejandro Vaquero <alejandrovaquero@yahoo.com>
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1999 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 /*
27  * Here is a summary on how this works:
28  *  - The VoipCalls will call add_rtp_packet() every time there is an RTP
29  *    packet
30  *  - add_rtp_packet() will add the RTP packet in a RTP stream struct, and
31  *    create the RTP stream if it is the  first RTP in the stream.
32  *  - Each new RTP stream will be added to a list of RTP stream, called
33  *    rtp_streams_list
34  *  - When the user clicks "Player" in the VoipCall dialogue,
35  *    rtp_player_init() is called.
36  *  - rtp_player_init() create the main dialog, and it calls:
37  *    + mark_rtp_stream_to_play() to mark the RTP streams that needs to be
38  *      displayed. These are the RTP stream that match the selected calls in
39  *      the VoipCall dlg.
40  *    + decode_rtp_stream() this will decode the RTP packets in each RTP
41  *      stream, and will also create  the RTP channles. An RTP channel is a
42  *      group of RTP stream that have in common the source and destination
43  *      IP and UPD ports. The RTP channels is what the user will listen in
44  *      one of the two Audio channles. 
45  *      The RTP channels are stored in the hash table rtp_channels_hash
46  *    + add_channel_to_window() will create and add the Audio graphic
47  *      representation in the main window
48  *  - When the user click the check box to listen one of the Audio channels,
49  *    the structure rtp_channels is filled  to play one or two RTP channels
50  *    (a max of two channels can be listened at a given moment)
51  */
52
53
54 #ifdef HAVE_CONFIG_H
55 #include "config.h"
56 #endif
57
58 #ifdef HAVE_LIBPORTAUDIO
59 /* TODO: The RTP Player it is only supported for GTK >=2 */
60 #include <gtk/gtk.h>
61 #if GTK_MAJOR_VERSION >= 2
62
63 #include <epan/stats_tree.h>
64 #include <epan/addr_resolv.h>
65 #include <string.h>
66 #include <glib.h>
67 #include "globals.h"
68 #include "portaudio.h"
69 #include "simple_dialog.h"
70 #include "gui_utils.h"
71 #include "dlg_utils.h"
72 #include "compat_macros.h"
73
74 #include "graph_analysis.h"
75 #include "voip_calls_dlg.h"
76 #include "voip_calls.h"
77 #include "gtkglobals.h"
78
79
80 #include <epan/dissectors/packet-rtp.h>
81 #include <epan/rtp_pt.h>
82
83 #include "rtp_player.h"
84 #include "codecs/G711a/G711adecode.h"
85 #include "codecs/G711u/G711udecode.h"
86 #include <math.h>
87
88 #ifndef min
89 #define min(a,b) (((a)<(b))?(a):(b))
90 #endif
91 #ifndef max
92 #define max(a,b) (((a)>(b))?(a):(b))
93 #endif
94
95 /*define this symbol to compile with G729 and G723 codecs*/
96 /*#define HAVE_G729_G723 1*/
97
98 #ifdef HAVE_G729_G723
99 #include "codecs/G729/G729decode.h"
100 #include "codecs/G723/G723decode.h"
101 #endif /* HAVE_G729_G723 */
102
103 static gboolean initialized = FALSE;
104
105 voip_calls_tapinfo_t *voip_calls = NULL;
106
107 /* Hash table with all the RTP streams */
108 static GHashTable*  rtp_streams_hash = NULL;
109
110 /* List with all the RTP streams (this is used to decode them as it is sorted)*/
111 static GList*  rtp_streams_list = NULL;
112
113 /* the window */
114 static GtkWidget *rtp_player_dlg_w;
115 static GtkWidget *channels_vb;
116 static GtkWidget *main_scrolled_window = NULL;
117 static GtkWidget *jitter_spinner;
118 static GtkWidget *bt_decode;
119 static GtkWidget *bt_play;
120 static GtkWidget *bt_pause;
121 static GtkWidget *bt_stop;
122 static GtkWidget *progress_bar;
123 static GtkWidget *info_bar;
124 static GtkWidget *stat_hbox;
125
126 static guint32 total_packets;
127 static guint32 total_frames;
128 static guint32 progbar_count;
129
130 static int new_jitter_buff;
131
132 /* a hash table with the RTP streams to play per audio channel */
133 static GHashTable *rtp_channels_hash = NULL;
134
135 /* Port Audio staff */
136 #define SAMPLE_RATE  (8000)
137 #define NUM_CHANNELS    (2)
138
139 #define PA_SAMPLE_TYPE  paInt16
140 typedef gint16 SAMPLE;
141 #define SAMPLE_SILENCE  (0)
142 #define FRAMES_PER_BUFFER  (512)
143
144 typedef struct _sample_t {
145         SAMPLE val;
146         guint8 status;
147 } sample_t;
148
149 #define S_NORMAL 0
150 #define S_DROP_BY_JITT 1
151 #define S_WRONG_SEQ 2
152
153 /* Display channels constants */
154 #define MULT 80
155 #define CHANNEL_WIDTH 500
156 #define CHANNEL_HEIGHT 100
157 #define MAX_TIME_LABEL 10
158 #define HEIGHT_TIME_LABEL 18
159 #define MAX_NUM_COL_CONV 10
160
161 #if PORTAUDIO_API_1
162 PortAudioStream *pa_stream;
163 #else /* PORTAUDIO_API_1 */
164 PaStream *pa_stream;
165 #endif /* PORTAUDIO_API_1 */
166
167 /* defines a RTP stream */
168 typedef struct _rtp_stream_info {
169         address src_addr;
170         guint16 src_port;
171         address dest_addr;
172         guint16 dest_port;
173         guint32 ssrc;
174         guint32 first_frame_number; /* first RTP frame for the stream */
175         double start_time;                      /* RTP stream start time in ms */
176         gboolean play;
177         guint16 call_num;
178         GList*  rtp_packets_list; /* List of RTP packets in the stream */
179         guint32 num_packets;
180 } rtp_stream_info_t;
181
182
183 /* defines the RTP streams to be played in an audio channel */
184 typedef struct _rtp_channel_info {
185         double start_time;                      /* RTP stream start time in ms */
186         double end_time;                        /* RTP stream end time in ms */
187         GArray *samples;                        /* the array with decoded audio */
188         guint16 call_num;
189         gboolean selected;
190         guint32 frame_index;
191         guint32 drop_by_jitter_buff;
192         guint32 out_of_seq;
193         guint32 max_frame_index;
194         GtkWidget *check_bt;
195         GtkWidget *separator;
196         GtkWidget *scroll_window;
197         GtkWidget *draw_area;
198         GdkPixmap *pixmap;
199         GtkAdjustment *h_scrollbar_adjustment;
200         GdkPixbuf* cursor_pixbuf;
201 #if PORTAUDIO_API_1
202         PaTimestamp cursor_prev;
203 #else /* PORTAUDIO_API_1 */
204         PaTime cursor_prev;
205 #endif /* PORTAUDIO_API_1 */
206         GdkGC *bg_gc[MAX_NUM_COL_CONV+1];
207         gboolean cursor_catch;
208         rtp_stream_info_t *first_stream;        /* This is the first RTP stream in the channel */
209         guint32 num_packets;
210 } rtp_channel_info_t;
211
212 /* defines a RTP packet */
213 typedef struct _rtp_packet {
214         struct _rtp_info *info; /* the RTP dissected info */
215         double arrive_offset;   /* arrive offset time since the begining of the stream in ms */
216         guint8* payload_data;
217 } rtp_packet_t;
218
219 /* defines the two RTP channels to be played */
220 typedef struct _rtp_play_channles {
221         rtp_channel_info_t* rci[2]; /* Channels to be played */
222         guint32 start_index[2];
223         guint32 end_index[2];
224         int channel;
225         guint32 max_frame_index;
226         guint32 frame_index;
227         gboolean pause;
228         gboolean stop;
229         gint32 pause_duration;
230 #if PORTAUDIO_API_1
231         PaTimestamp out_diff_time;
232 #else /* PORTAUDIO_API_1 */
233         PaTime out_diff_time;
234         PaTime pa_start_time;
235 #endif /* PORTAUDIO_API_1 */
236 } rtp_play_channles_t;
237
238 /* The two RTP channles to play */
239 static rtp_play_channles_t *rtp_channels = NULL;
240
241
242 /****************************************************************************/
243 static void 
244 rtp_key_destroy(gpointer key)
245 {
246         g_free(key);
247         key = NULL;
248 }
249
250 /****************************************************************************/
251 static void 
252 rtp_channel_value_destroy(gpointer rci_arg)
253 {
254         rtp_channel_info_t *rci = rci_arg;
255
256         g_array_free(rci->samples, TRUE);
257         g_free(rci);
258         rci = NULL;
259 }
260
261 /****************************************************************************/
262 static void 
263 rtp_stream_value_destroy(gpointer rsi_arg)
264 {
265         rtp_stream_info_t *rsi = rsi_arg;
266         GList*  rtp_packets_list;
267         rtp_packet_t *rp;
268
269         rtp_packets_list = g_list_first(rsi->rtp_packets_list);
270         while (rtp_packets_list)
271         {
272                 rp = rtp_packets_list->data;
273
274                 g_free(rp->info);
275                 g_free(rp->payload_data);
276                 g_free(rp);
277                 rp = NULL;
278         
279                 rtp_packets_list = g_list_next(rtp_packets_list);
280         }
281         g_free(rsi);
282         rsi = NULL;
283 }
284
285 /****************************************************************************/
286 static void
287 set_sensitive_check_bt(gchar *key _U_ , rtp_channel_info_t *rci, guint *stop _U_ ) 
288 {
289         gtk_widget_set_sensitive(rci->check_bt, !(*stop));      
290 }
291
292 /****************************************************************************/
293 static void 
294 bt_state(gboolean decode, gboolean play, gboolean pause, gboolean stop)
295 {
296         gboolean new_jitter_value = FALSE;
297         gboolean false_val = FALSE;
298
299         gtk_widget_set_sensitive(bt_decode, decode);
300         gtk_widget_set_sensitive(jitter_spinner, decode);
301                 
302         if (new_jitter_buff != (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner)) {
303                 new_jitter_value = TRUE;
304         }
305
306         /* set the sensitive state of play only if there is a channel selected */
307         if ( play && (rtp_channels->rci[0] || rtp_channels->rci[1]) && !new_jitter_value) {             
308                 gtk_widget_set_sensitive(bt_play, TRUE);
309         } else {
310                 gtk_widget_set_sensitive(bt_play, FALSE);
311         }
312         
313         if (!new_jitter_value) {
314                 gtk_widget_set_sensitive(bt_pause, pause);
315                 gtk_widget_set_sensitive(bt_stop, stop);
316
317                 /* Set sensitive to the check buttons based on the STOP state */
318                 if (rtp_channels_hash)
319                         g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &stop);        
320         } else {
321                 gtk_widget_set_sensitive(bt_pause, FALSE);
322                 gtk_widget_set_sensitive(bt_stop, FALSE);
323
324                 if (rtp_channels_hash)
325                         g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &false_val);   
326         }
327 }
328
329 /****************************************************************************/
330 void 
331 add_rtp_packet(const struct _rtp_info *rtp_info, packet_info *pinfo)
332 {
333         rtp_stream_info_t *stream_info = NULL;
334         rtp_packet_t *new_rtp_packet;
335         GString *key_str = NULL;
336
337         /* create the the streams hash if it doen't exist */
338         if (!rtp_streams_hash)
339                 rtp_streams_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_stream_value_destroy);
340
341         /* Create a hash key to lookup in the RTP streams hash table
342          * uses: src_ip:src_port dst_ip:dst_port ssrc
343          */
344         key_str = g_string_new("");
345         g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(pinfo->src)),
346                 pinfo->srcport, get_addr_name(&(pinfo->dst)),
347                 pinfo->destport, rtp_info->info_sync_src );
348
349         /* lookup for this rtp packet in the stream hash table*/
350         stream_info =  g_hash_table_lookup( rtp_streams_hash, key_str->str);
351
352         /* if it is not in the hash table, create a new stream */
353         if (stream_info==NULL) {
354                 stream_info = g_malloc(sizeof(rtp_stream_info_t));
355                 COPY_ADDRESS(&(stream_info->src_addr), &(pinfo->src));
356                 stream_info->src_port = pinfo->srcport;
357                 COPY_ADDRESS(&(stream_info->dest_addr), &(pinfo->dst));
358                 stream_info->dest_port = pinfo->destport;
359                 stream_info->ssrc = rtp_info->info_sync_src;
360                 stream_info->rtp_packets_list = NULL;
361                 stream_info->first_frame_number = pinfo->fd->num;
362                 stream_info->start_time = nstime_to_msec(&pinfo->fd->rel_ts);
363                 stream_info->call_num = 0;
364                 stream_info->play = FALSE;
365                 stream_info->num_packets = 0;
366
367                 g_hash_table_insert(rtp_streams_hash, g_strdup(key_str->str), stream_info);
368
369                 /* Add the element to the List too. The List is used to decode the packets because it is sordted */
370                 rtp_streams_list = g_list_append(rtp_streams_list, stream_info);
371         }
372
373         /* increment the number of packets in this stream, this is used for the progress bar and statistics*/
374         stream_info->num_packets++;
375
376         /* Add the RTP packet to the list */
377         new_rtp_packet = g_malloc(sizeof(rtp_packet_t));
378         new_rtp_packet->info = g_malloc(sizeof(struct _rtp_info));
379
380         memcpy(new_rtp_packet->info, rtp_info, sizeof(struct _rtp_info));
381         new_rtp_packet->arrive_offset = nstime_to_msec(&pinfo->fd->rel_ts) - stream_info->start_time;
382         /* copy the RTP payload to the rtp_packet to be decoded later */
383         if (rtp_info->info_payload_len) {
384                 new_rtp_packet->payload_data = g_malloc(rtp_info->info_payload_len);
385                 memcpy(new_rtp_packet->payload_data, &(rtp_info->info_data[rtp_info->info_payload_offset]), rtp_info->info_payload_len);
386         } else {
387                 new_rtp_packet->payload_data = NULL;
388         }
389
390         stream_info->rtp_packets_list = g_list_append(stream_info->rtp_packets_list, new_rtp_packet);
391
392         g_string_free(key_str, TRUE);
393 }
394
395 /****************************************************************************/
396 /* Mark the RTP stream to be played. Use the voip_calls graph to see if the 
397  * setup_frame is there and then if the associated voip_call is selected.
398  */
399 static void 
400 mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
401 {
402         GList*  graph_list;
403         graph_analysis_item_t *graph_item;
404         GList*  voip_calls_list;
405         voip_calls_info_t *tmp_voip_call;
406
407         /* Reset the "to be play" value because the user can close and reopen the RTP Player window
408          * and the streams are nor reset in that case
409          */
410         rsi->play = FALSE;
411
412         /* and associate the RTP stream with a call using the first RTP in the stream*/
413         graph_list = g_list_first(voip_calls->graph_analysis->list);
414         while (graph_list)
415         {
416                 graph_item = graph_list->data;
417                 if (rsi->first_frame_number == graph_item->frame_num) {
418                         rsi->call_num = graph_item->conv_num;
419                         /* if it is in the graph list, then check if the voip_call is selected */
420                         voip_calls_list = g_list_first(voip_calls->strinfo_list);
421                         while (voip_calls_list)
422                         {
423                                 tmp_voip_call = voip_calls_list->data;
424                                 if ( (tmp_voip_call->call_num == rsi->call_num) && (tmp_voip_call->selected == TRUE) ) {
425                                         rsi->play = TRUE;
426                                         total_packets += rsi->num_packets;
427                                         break;
428                                 }
429                                 voip_calls_list = g_list_next(voip_calls_list);
430                         }
431                         break;
432                 }
433                 graph_list = g_list_next(graph_list);
434         }
435 }
436
437
438 /****************************************************************************/
439 /* Decode a RTP packet 
440  * Return the number of decoded bytes
441  */
442 static int 
443 decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff)
444 {
445         unsigned int  payload_type;
446         SAMPLE *tmp_buff = NULL;
447         int decoded_bytes = 0;
448
449         if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
450                 return 0;
451         }
452
453         payload_type = rp->info->info_payload_type;
454         switch (payload_type) {
455
456         case PT_PCMU:   /* G.711 u-law */
457                 tmp_buff = malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
458                 decodeG711u(rp->payload_data, rp->info->info_payload_len,
459                           tmp_buff, &decoded_bytes);
460                 break; 
461
462         case PT_PCMA:   /* G.711 A-law */
463                 tmp_buff = malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
464                 decodeG711a(rp->payload_data, rp->info->info_payload_len,
465                           tmp_buff, &decoded_bytes);
466                 break; 
467
468 #ifdef HAVE_G729_G723
469         case PT_G729:   /* G.729 */
470                 tmp_buff = malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 8); /* G729 8kbps => 64kbps/8kbps = 8  */
471                 decodeG729(rp->payload_data, rp->info->info_payload_len,
472                           tmp_buff, &decoded_bytes);
473                 break; 
474
475         case PT_G723:   /* G.723 */
476                 if (rp->info->info_payload_len%24 == 0) /* G723 High 6.4kbps */
477                         tmp_buff = malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 10); /* G723 High 64kbps/6.4kbps = 10  */       
478                 else if (rp->info->info_payload_len%20 == 0)    /* G723 Low 5.3kbps */
479                         tmp_buff = malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 13); /* G723 High 64kbps/5.3kbps = 13  */       
480                 else {
481                         return 0;
482                 }
483                 decodeG723(rp->payload_data, rp->info->info_payload_len,
484                           tmp_buff, &decoded_bytes);
485                 break;
486 #endif /* HAVE_G729_G723 */
487
488         default:
489                 /*
490                  * XXX - return an error here, so the user gets told that
491                  * we don't support this codec!
492                  */
493                 break;
494         }
495
496         *out_buff = tmp_buff;
497         return decoded_bytes;
498 }
499
500 /****************************************************************************/
501 static void
502 update_progress_bar(gfloat percentage)
503 {
504
505         gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), percentage);
506
507         /* Force gtk to redraw the window before starting decoding the packet */
508         while (gtk_events_pending())
509                 gtk_main_iteration();
510 }
511
512 /****************************************************************************/
513 /* Decode the RTP streams and add them to the RTP channels struct
514  */
515 static void 
516 decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
517 {
518         GString *key_str = NULL;
519         rtp_channel_info_t *rci;
520         gboolean first = TRUE;
521         GList*  rtp_packets_list;
522         rtp_packet_t *rp;
523
524         int i;
525         double rtp_time;
526         double rtp_time_prev;
527         double arrive_time;
528         double arrive_time_prev;
529         double start_time;
530         double start_rtp_time;
531         double diff;
532         double pack_period;
533         double total_time;
534         double total_time_prev;
535         gint32 silence_frames;
536         int seq;
537         double delay;
538         double prev_diff;
539         double mean_delay;
540         double variation;
541         int decoded_bytes;
542         int decoded_bytes_prev;
543         int jitter_buff;
544         SAMPLE *out_buff = NULL;
545         sample_t silence;
546         sample_t sample;
547         guint8 status;
548         guint32 start_timestamp; 
549
550         guint32 progbar_nextstep;
551         int progbar_quantum;
552         gfloat progbar_val;
553
554         silence.val = 0;
555         silence.status = S_NORMAL;
556
557         /* skip it if we are not going to play it */ 
558         if (rsi->play == FALSE) {
559                 return;
560         }
561
562         /* get the static jitter buffer from the spinner gui */
563         jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
564
565         /* Create a hash key to lookup in the RTP channels hash
566          * uses: src_ip:src_port dst_ip:dst_port call_num
567          */
568         key_str = g_string_new("");
569         g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(rsi->src_addr)),
570                 rsi->src_port, get_addr_name(&(rsi->dest_addr)),
571                 rsi->dest_port, rsi->call_num );
572
573         /* create the rtp_channels_hash table if it doesn't exist */
574         if (!rtp_channels_hash) {
575                 rtp_channels_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_channel_value_destroy);
576         }
577
578         /* lookup for this stream in the channel hash table */
579         rci =  g_hash_table_lookup( rtp_channels_hash, key_str->str);
580
581         /* ..if it is not in the hash, create an entry */
582         if (rci == NULL) {
583                 rci = malloc(sizeof(rtp_channel_info_t));
584                 rci->call_num = rsi->call_num;
585                 rci->start_time = rsi->start_time;
586                 rci->end_time = rsi->start_time;                
587                 rci->selected = FALSE;
588                 rci->frame_index = 0;
589                 rci->drop_by_jitter_buff = 0;
590                 rci->out_of_seq = 0;
591                 rci->max_frame_index = 0;
592                 rci->samples = g_array_new (FALSE, FALSE, sizeof(sample_t));
593                 rci->check_bt = NULL;
594                 rci->separator = NULL;
595                 rci->draw_area = NULL;
596                 rci->pixmap = NULL;
597                 rci->h_scrollbar_adjustment = NULL;
598                 rci->cursor_pixbuf = NULL;
599                 rci->cursor_prev = 0;
600                 rci->cursor_catch = FALSE;
601                 rci->first_stream = rsi;
602                 rci->num_packets = rsi->num_packets;
603                 g_hash_table_insert(rtp_channels_hash, g_strdup(key_str->str), rci);
604         } else {
605                 /* Add silence between the two streams if needed */
606                 silence_frames = (gint32)( ((rsi->start_time - rci->end_time)/1000)*SAMPLE_RATE );
607                 for (i = 0; i< silence_frames; i++) {
608                         g_array_append_val(rci->samples, silence);
609                 }
610                 rci->num_packets += rsi->num_packets;
611         }
612
613         /* decode the RTP stream */
614         first = TRUE;
615         rtp_time = 0;
616         rtp_time_prev = 0;
617         decoded_bytes = 0;
618         decoded_bytes_prev = 0;
619         silence_frames = 0;
620         arrive_time = start_time = 0;
621         arrive_time_prev = 0;
622         pack_period = 0;
623         total_time = 0;
624         total_time_prev = 0;
625         seq = 0;
626         delay = 0;
627         prev_diff = 0;
628         mean_delay = 0;
629         variation = 0;
630         start_timestamp = 0;
631
632         /* we update the progress bar 100 times */
633
634         /* Update the progress bar when it gets to this value. */
635         progbar_nextstep = 0;
636         /* When we reach the value that triggers a progress bar update,
637            bump that value by this amount. */
638         progbar_quantum = total_packets/100;
639
640         status = S_NORMAL;
641
642         rtp_packets_list = g_list_first(rsi->rtp_packets_list);
643         while (rtp_packets_list)
644         {
645
646                 if (progbar_count >= progbar_nextstep) {
647                         g_assert(total_packets > 0);
648
649                         progbar_val = (gfloat) progbar_count / total_packets;
650
651                         update_progress_bar(progbar_val);
652
653                         progbar_nextstep += progbar_quantum;
654                 }
655                 
656
657                 rp = rtp_packets_list->data;
658                 if (first == TRUE) {
659                         start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
660                         start_rtp_time = 0;
661                         rtp_time_prev = start_rtp_time;
662                         first = FALSE;
663                         seq = rp->info->info_seq_num - 1;
664                 }
665
666                 decoded_bytes = decode_rtp_packet(rp, &out_buff);
667                 if (decoded_bytes == 0) {
668                         seq = rp->info->info_seq_num;
669                 }
670
671                 rtp_time = (double)(rp->info->info_timestamp-start_timestamp)/SAMPLE_RATE - start_rtp_time;
672                 arrive_time = (double)rp->arrive_offset/1000 - start_time;
673
674                 if (rp->info->info_seq_num != seq+1){
675                         rci->out_of_seq++;
676                         status = S_WRONG_SEQ;
677                 }
678                 seq = rp->info->info_seq_num;
679
680                 diff = arrive_time - rtp_time;
681
682                 delay = diff - prev_diff;
683                 prev_diff = diff;
684                 if (delay<0) delay = -delay;
685
686                 if (diff<0) diff = -diff;
687   
688                 total_time = (double)rp->arrive_offset/1000;
689                 
690                 printf("seq = %d arr = %f abs_diff = %f index = %d tim = %f ji=%d jb=%f\n",rp->info->info_seq_num, 
691                         total_time, diff, rci->samples->len, ((double)rci->samples->len/8000 - total_time)*1000, 0,
692                                 (mean_delay + 4*variation)*1000);
693                 fflush(stdout);
694
695                 /* if the jitter buffer was exceeded */ 
696                 if ( diff*1000 > jitter_buff ) {
697                         printf("Packet drop by jitter buffer exceeded\n");
698                         rci->drop_by_jitter_buff++;
699                         status = S_DROP_BY_JITT;
700
701                         /* if there was a silence period (more than two packetization period) resync the source */
702                         if ( (rtp_time - rtp_time_prev) > pack_period*2 ){
703                                 printf("Resync...\n");
704
705                                 silence_frames = (gint32)((arrive_time - arrive_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
706                                 for (i = 0; i< silence_frames; i++) {
707                                         silence.status = status;
708                                         g_array_append_val(rci->samples, silence);
709
710                                         /* only mark the fisrt in the silence that has the previos problem (S_DROP_BY_JITT  or S_WRONG_SEQ ) */
711                                         status = S_NORMAL;
712                                 }
713
714                                 decoded_bytes_prev = 0;
715                                 start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
716                                 start_rtp_time = 0;
717                                 start_time = (double)rp->arrive_offset/1000;
718                                 rtp_time_prev = 0;
719                         }
720                 } else {
721                         /* Add silence if it is necessary */
722                         silence_frames = (gint32)((rtp_time - rtp_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
723                         for (i = 0; i< silence_frames; i++) {
724                                 silence.status = status;
725                                 g_array_append_val(rci->samples, silence);
726
727                                 /* only mark the fisrt in the silence that has the previos problem (S_DROP_BY_JITT  or S_WRONG_SEQ ) */
728                                 status = S_NORMAL;
729                         }
730
731                         status = S_NORMAL;
732
733                         /* Add the audio */
734                         for (i = 0; i< (decoded_bytes/2); i++) {
735                                 sample.val = out_buff[i];
736                                 sample.status = status;
737                                 g_array_append_val(rci->samples, sample);
738                         }
739         
740                         rtp_time_prev = rtp_time;
741                         pack_period = (double)(decoded_bytes/2)/SAMPLE_RATE;
742                         decoded_bytes_prev = decoded_bytes;
743                         arrive_time_prev = arrive_time;
744
745                 }
746
747                 rtp_packets_list = g_list_next (rtp_packets_list);
748                 progbar_count++;
749         }
750         rci->max_frame_index = rci->samples->len;
751         rci->end_time = rci->start_time + ((double)rci->samples->len/SAMPLE_RATE)*1000;
752
753         g_string_free(key_str, TRUE);
754 }
755
756 /****************************************************************************/
757 static gint 
758 h_scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
759 {
760         rtp_channel_info_t *rci = (rtp_channel_info_t *)user_data;
761         rci->cursor_catch = TRUE;
762         return TRUE;
763 }
764
765 static gboolean draw_cursors(gpointer data);
766
767 /****************************************************************************/
768 static void
769 stop_channels(void) 
770 {       
771         PaError err;
772         GtkWidget *dialog;
773
774         /* we should never be here if we are already in STOP */
775         if(rtp_channels->stop){
776                 exit(10);
777         }
778
779         rtp_channels->stop = TRUE;
780         /* force a draw_cursor to stop it */
781         draw_cursors(NULL);
782
783         err = Pa_StopStream(pa_stream);
784
785         if( err != paNoError ) {
786                 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
787                                                           GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
788                                                           "Can not Stop Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
789                 gtk_dialog_run (GTK_DIALOG (dialog));
790                 gtk_widget_destroy (dialog);
791                 return;
792         }
793
794         err = Pa_CloseStream(pa_stream);
795         if( err != paNoError ) {
796                 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
797                                                           GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
798                                                           "Can not Close Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
799                 gtk_dialog_run (GTK_DIALOG (dialog));
800                 gtk_widget_destroy (dialog);
801                 return;
802         }
803         pa_stream = NULL;       /* to catch errors better */
804
805         rtp_channels->start_index[0] = 0;
806         rtp_channels->start_index[1] = 0;
807         rtp_channels->end_index[0] = 0;
808         rtp_channels->end_index[1] = 0;
809         rtp_channels->max_frame_index = 0;
810         rtp_channels->frame_index = 0;
811         rtp_channels->pause = FALSE;
812         rtp_channels->pause_duration = 0;
813         rtp_channels->stop = TRUE;
814         rtp_channels->out_diff_time = 10000;
815
816         if (rtp_channels->rci[0]) rtp_channels->rci[0]->frame_index = 0;
817         if (rtp_channels->rci[1]) rtp_channels->rci[1]->frame_index = 0;
818
819         /* set the sensitive state of the buttons (decode, play, pause, stop) */
820         bt_state(TRUE, TRUE, FALSE, FALSE);
821
822 }
823
824 /****************************************************************************/
825 /* Draw a cursor in a channel graph 
826  */
827 static void 
828 draw_channel_cursor(rtp_channel_info_t *rci, guint32 start_index)
829 {
830 #if PORTAUDIO_API_1
831         PaTimestamp index;
832 #else /* PORTAUDIO_API_1 */
833         PaTime index;
834 #endif /* PORTAUDIO_API_1 */
835         int i;
836
837         if (!rci) return;
838
839 #if PORTAUDIO_API_1
840         index = Pa_StreamTime( pa_stream ) - rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
841 #else  /* PORTAUDIO_API_1 */
842         index = ((guint32)(SAMPLE_RATE) * (Pa_GetStreamTime(pa_stream)-rtp_channels->pa_start_time))- rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
843 #endif  /* PORTAUDIO_API_1 */
844
845
846         /* If we finished playing both channels, then stop them */
847         if ( (rtp_channels && (!rtp_channels->stop) && (!rtp_channels->pause)) && (index > rtp_channels->max_frame_index) ) {
848                 stop_channels();
849                 return;
850         }
851
852         /* If only this channel finished, then return */
853         if (index > rci->max_frame_index) {
854                 return;
855         }
856
857         /* draw the previous saved pixbuf line */
858         if (rci->cursor_pixbuf && (rci->cursor_prev>=0)) {
859
860                 gdk_draw_pixbuf(rci->pixmap, NULL, rci->cursor_pixbuf, 0, 0, (int) (rci->cursor_prev/MULT), 0, -1, -1, GDK_RGB_DITHER_NONE, 0 ,0);
861
862                 gdk_draw_drawable(rci->draw_area->window,
863                         rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
864                         rci->pixmap,
865                         (int) (rci->cursor_prev/MULT), 0,
866                         (int) (rci->cursor_prev/MULT), 0,
867                         1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
868
869                 g_object_unref(rci->cursor_pixbuf);
870                 rci->cursor_pixbuf = NULL;
871         }
872
873         if (index>0 && (rci->cursor_prev>=0)) {
874                 rci->cursor_pixbuf = gdk_pixbuf_get_from_drawable(NULL, rci->pixmap, NULL, (int) (index/MULT), 0, 0, 0, 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
875
876                 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
877                         (int) (index/MULT),
878                         0,
879                         (int) (index/MULT),
880                         rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
881
882                 gdk_draw_drawable(rci->draw_area->window,
883                         rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)], 
884                         rci->pixmap,
885                         (int) (index/MULT), 0,
886                         (int) (index/MULT), 0,
887                         1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
888         }
889
890         /* Disconnect the scroll bar "value" signal to not be called */
891         SIGNAL_DISCONNECT_BY_FUNC(rci->h_scrollbar_adjustment, h_scrollbar_changed, rci);
892
893         /* Move the horizontal scroll bar */
894 /*      if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) && 
895                 (index/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){             
896                 for (i=1; i<10; i++) {
897                         rci->h_scrollbar_adjustment->value += rci->h_scrollbar_adjustment->page_size/10;
898                         gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
899                 }
900
901         }
902  */
903         if (!rci->cursor_catch) {
904                 if (index/MULT < rci->h_scrollbar_adjustment->page_size/2) {
905                         rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
906                 } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
907                         rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
908                 } else {
909                         rci->h_scrollbar_adjustment->value = index/MULT - rci->h_scrollbar_adjustment->page_size/2;
910                 }
911
912                 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
913         } else if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) && 
914                 (index/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){     
915                 rci->cursor_catch = FALSE;
916                 for (i=1; i<10; i++) {
917                         rci->h_scrollbar_adjustment->value = min(rci->h_scrollbar_adjustment->upper-rci->h_scrollbar_adjustment->page_size, rci->h_scrollbar_adjustment->value + (rci->h_scrollbar_adjustment->page_size/20));
918                         gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
919                 }
920
921         }
922
923
924         /* Connect back the "value" scroll signal */
925         SIGNAL_CONNECT(rci->h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, rci);
926
927
928 /*      if (index/MULT < rci->h_scrollbar_adjustment->page_increment) {
929                 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
930         } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size + rci->h_scrollbar_adjustment->page_increment)) {
931                 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
932         } else {
933                 if ( (index/MULT < rci->h_scrollbar_adjustment->value) || (index/MULT > (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
934                         rci->h_scrollbar_adjustment->value = index/MULT;
935                 }
936         }
937  */
938
939 /*      if (index/MULT < rci->h_scrollbar_adjustment->page_size/2) {
940                 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
941         } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
942                 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
943         } else {
944                 rci->h_scrollbar_adjustment->value = index/MULT - rci->h_scrollbar_adjustment->page_size/2;
945         }
946  */
947 /*      gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
948  */
949         rci->cursor_prev = index;
950 }
951
952 /****************************************************************************/
953 /* Move and draw the cursor in the graph 
954  */
955 static gboolean 
956 draw_cursors(gpointer data _U_)
957 {
958         if (!rtp_channels) return FALSE;
959
960         /* Draw and move each of the two channels */
961         draw_channel_cursor(rtp_channels->rci[0], rtp_channels->start_index[0]);
962         draw_channel_cursor(rtp_channels->rci[1], rtp_channels->start_index[1]);
963
964         if ((rtp_channels->stop) || (rtp_channels->pause)) return FALSE;
965
966         return TRUE;
967 }
968
969 /****************************************************************************/
970 static void
971 init_rtp_channels_vals(void)
972 {
973         rtp_play_channles_t *rpci = rtp_channels; 
974         
975         /* if we only have one channel to play, we just use the info from that channel */
976         if (rpci->rci[0] == NULL) {
977                 rpci->max_frame_index = rpci->rci[1]->max_frame_index;
978                 rpci->start_index[0] = rpci->max_frame_index;
979                 rpci->start_index[1] = 0;
980                 rpci->end_index[0] = rpci->max_frame_index;
981                 rpci->end_index[1] = rpci->max_frame_index;
982         } else if (rpci->rci[1] == NULL) {
983                 rpci->max_frame_index = rpci->rci[0]->max_frame_index;
984                 rpci->start_index[1] = rpci->max_frame_index;
985                 rpci->start_index[0] = 0;
986                 rpci->end_index[0] = rpci->max_frame_index;
987                 rpci->end_index[1] = rpci->max_frame_index;
988
989         /* if the two channels are to be played, then we need to sync both based on the start/end time of each one */
990         } else {
991                 rpci->max_frame_index = (guint32)(SAMPLE_RATE/1000) * (guint32)(max(rpci->rci[0]->end_time, rpci->rci[1]->end_time) -
992                                                         (guint32)min(rpci->rci[0]->start_time, rpci->rci[1]->start_time));
993
994                 if (rpci->rci[0]->start_time < rpci->rci[1]->start_time) {
995                         rpci->start_index[0] = 0;
996                         rpci->start_index[1] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->start_time - rpci->rci[0]->start_time);
997                 } else {
998                         rpci->start_index[1] = 0;
999                         rpci->start_index[0] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->start_time - rpci->rci[1]->start_time);
1000                 } 
1001
1002                 if (rpci->rci[0]->end_time < rpci->rci[1]->end_time) {
1003                         rpci->end_index[0] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->end_time - rpci->rci[0]->end_time));
1004                         rpci->end_index[1] = rpci->max_frame_index;
1005                 } else {
1006                         rpci->end_index[1] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->end_time - rpci->rci[1]->end_time));
1007                         rpci->end_index[0] = rpci->max_frame_index;
1008                 } 
1009         }
1010 }
1011
1012
1013 /****************************************************************************/
1014 /* This routine will be called by the PortAudio engine when audio is needed.
1015  * It may called at interrupt level on some machines so don't do anything
1016  * that could mess up the system like calling malloc() or free().
1017  */
1018 #if PORTAUDIO_API_1
1019
1020 static int paCallback(   void *inputBuffer, void *outputBuffer,
1021                              unsigned long framesPerBuffer,
1022                              PaTimestamp outTime, void *userData)
1023 {
1024 #else /* PORTAUDIO_API_1 */
1025 static int paCallback( const void *inputBuffer, void *outputBuffer,
1026                              unsigned long framesPerBuffer,
1027                                                          const PaStreamCallbackTimeInfo* outTime,
1028                                                          PaStreamCallbackFlags statusFlags _U_,
1029                              void *userData)
1030 {
1031 #endif /* PORTAUDIO_API_1 */
1032         rtp_play_channles_t *rpci = (rtp_play_channles_t*)userData;
1033         SAMPLE *wptr = (SAMPLE*)outputBuffer;
1034         sample_t sample;
1035         unsigned int i;
1036         int finished;
1037         unsigned int framesLeft;
1038         int framesToPlay;
1039
1040         /* if it is pasued, we keep the stream running but with silence only */
1041         if (rtp_channels->pause) {
1042                 for(i=0; i<framesPerBuffer; i++ ) {
1043                         *wptr++ = 0;
1044                         *wptr++ = 0;
1045                 }
1046                 rtp_channels->pause_duration += framesPerBuffer;
1047                 return 0;
1048         }
1049
1050 #if PORTAUDIO_API_1
1051         rpci->out_diff_time = outTime -  Pa_StreamTime(pa_stream) ;
1052 #else /* PORTAUDIO_API_1 */
1053         rpci->out_diff_time = (guint32)(SAMPLE_RATE) * (outTime->outputBufferDacTime - Pa_GetStreamTime(pa_stream)) ; 
1054 #endif /* PORTAUDIO_API_1 */
1055
1056
1057         /* set the values if this is the first time */
1058         if (rpci->max_frame_index == 0) {
1059                 init_rtp_channels_vals();
1060
1061         }
1062
1063         framesLeft = rpci->max_frame_index - rpci->frame_index;
1064
1065         (void) inputBuffer; /* Prevent unused variable warnings. */
1066         (void) outTime;
1067
1068         if( framesLeft < framesPerBuffer )
1069         {
1070                 framesToPlay = framesLeft;
1071                 finished = 1;
1072         }
1073         else
1074         {
1075                 framesToPlay = framesPerBuffer;
1076                 finished = 0;
1077         }
1078
1079         for( i=0; i<(unsigned int)framesToPlay; i++ )
1080         {
1081                 if (rpci->rci[0] && ( (rpci->frame_index >= rpci->start_index[0]) && (rpci->frame_index <= rpci->end_index[0]) )) {
1082                         sample = g_array_index(rpci->rci[0]->samples, sample_t, rpci->rci[0]->frame_index++);
1083                         *wptr++ = sample.val;
1084                 } else {
1085                         *wptr++ = 0;
1086                 }
1087
1088                 if (rpci->rci[1] && ( (rpci->frame_index >= rpci->start_index[1]) && (rpci->frame_index <= rpci->end_index[1]) )) {
1089                         sample = g_array_index(rpci->rci[1]->samples, sample_t, rpci->rci[1]->frame_index++);
1090                         *wptr++ = sample.val;
1091                 } else {
1092                         *wptr++ = 0;
1093                 }
1094         }
1095         for( ; i<framesPerBuffer; i++ )
1096         {
1097                 *wptr++ = 0;
1098                 *wptr++ = 0;
1099         }
1100         rpci->frame_index += framesToPlay;
1101
1102         return finished;
1103 }
1104
1105 /****************************************************************************/
1106 static void 
1107 on_bt_check_clicked(GtkButton *button _U_, gpointer user_data _U_)
1108 {
1109         rtp_channel_info_t *rci = user_data;
1110
1111         if (rci->selected) {
1112                 if (rtp_channels->rci[0] == rci) {
1113                         rtp_channels->rci[0] = NULL;
1114                         rtp_channels->channel = 0;
1115                 } else {
1116                         rtp_channels->rci[1] = NULL;
1117                         rtp_channels->channel = 1;
1118                 }
1119         } else {
1120                 /* if there are already both channels selected, unselect the old one */
1121                 if (rtp_channels->rci[rtp_channels->channel]) {
1122                         /* we disconnect the signal temporarly to avoid been called back */
1123                         SIGNAL_DISCONNECT_BY_FUNC(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1124                         gtk_toggle_button_set_active((GtkToggleButton *)rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1125                         SIGNAL_CONNECT(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1126                         rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1127                 }
1128
1129                 rtp_channels->rci[rtp_channels->channel] = rci;
1130                 rtp_channels->channel = !(rtp_channels->channel);
1131         }
1132
1133         rci->selected = !(rci->selected);
1134
1135         /* set the sensitive state of the buttons (decode, play, pause, stop) */
1136         bt_state(TRUE, TRUE, FALSE, FALSE);
1137 }
1138
1139 /****************************************************************************/
1140 static void channel_draw(rtp_channel_info_t* rci)
1141 {
1142         int i, imax;
1143         int j;
1144         sample_t sample;
1145         SAMPLE min, max;
1146         PangoLayout  *small_layout;
1147         guint32 label_width, label_height;
1148         char label_string[MAX_TIME_LABEL];
1149         double offset;
1150         guint32 progbar_nextstep;
1151         int progbar_quantum;
1152         gfloat progbar_val;
1153         guint status;
1154         GdkGC *gc;
1155         GdkGC *red_gc;
1156         GdkColor red_color = {0, 65535, 0, 0};
1157         
1158         if (GDK_IS_DRAWABLE(rci->pixmap)) {
1159                 /* Clear out old plot */
1160                 gdk_draw_rectangle(rci->pixmap,
1161                         rci->bg_gc[1+rci->call_num%MAX_NUM_COL_CONV],
1162                         TRUE,
1163                         0, 0,
1164                         rci->draw_area->allocation.width,
1165                         rci->draw_area->allocation.height);
1166
1167                 small_layout = gtk_widget_create_pango_layout(rci->draw_area, NULL);
1168                 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica,Sans,Bold 7"));
1169
1170                 /* calculated the pixel offset to display integer seconds */
1171                 offset = ((double)rci->start_time/1000 - floor((double)rci->start_time/1000))*SAMPLE_RATE/MULT;
1172
1173                 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1174                                 0,
1175                                 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1176                                 rci->draw_area->allocation.width,
1177                                 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
1178
1179                 imax = min(rci->draw_area->allocation.width,(gint)(rci->samples->len/MULT));
1180
1181                 /* we update the progress bar 100 times */
1182
1183                 /* Update the progress bar when it gets to this value. */
1184                 progbar_nextstep = 0;
1185                 /* When we reach the value that triggers a progress bar update,
1186                    bump that value by this amount. */
1187                 progbar_quantum = imax/100;
1188
1189                 red_gc = gdk_gc_new(rci->draw_area->window);
1190                 gdk_gc_set_rgb_fg_color(red_gc, &red_color);
1191
1192                 for (i=0; i< imax; i++) {
1193                         sample.val = 0;
1194                         status = S_NORMAL;
1195                         max=(SAMPLE)0xFFFF;
1196                         min=(SAMPLE)0x7FFF;
1197
1198                         if (progbar_count >= progbar_nextstep) {
1199                                 g_assert(total_frames > 0);
1200
1201                                 progbar_val = (gfloat) i / imax;
1202
1203                                 update_progress_bar(progbar_val);
1204
1205                                 progbar_nextstep += progbar_quantum;
1206                         }
1207
1208                         for (j=0; j<MULT; j++) {
1209                                 sample = g_array_index(rci->samples, sample_t, i*MULT+j);
1210                                 max = max(max, sample.val);
1211                                 min = min(min, sample.val);
1212                                 if (sample.status == S_DROP_BY_JITT) status = S_DROP_BY_JITT;
1213                         }
1214
1215                         if (status == S_DROP_BY_JITT) {
1216                                 gc = red_gc;
1217                         } else {
1218                                 gc = rci->draw_area->style->black_gc;
1219                         }
1220
1221                         gdk_draw_line(rci->pixmap, gc,
1222                                 i,
1223                                 (gint)(( (0x7FFF+min) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF),
1224                                 i,
1225                                 (gint)(( (0x7FFF+max) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF));
1226
1227                         /*draw the time label and grid */
1228                         if ( !((i*MULT)%(SAMPLE_RATE)) ) {
1229                                 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1230                                         (int) (i - offset),
1231                                         rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1232                                         (int) (i - offset),
1233                                         rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+4);
1234
1235                                 g_snprintf(label_string, MAX_TIME_LABEL, "%.0f", floor(rci->start_time/1000) + i*MULT/SAMPLE_RATE);
1236
1237                                 pango_layout_set_text(small_layout, label_string, -1);
1238                                 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
1239                                 gdk_draw_layout(rci->pixmap,
1240                                         rci->draw_area->style->black_gc,
1241                                         (int) (i - offset - label_width/2),
1242                                         rci->draw_area->allocation.height - label_height,
1243                                         small_layout);
1244                         /* draw the 1/2 sec grid */
1245                         } else if ( !((i*MULT)%(SAMPLE_RATE/2)) ) {
1246                                 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1247                                         (int) (i - offset),
1248                                         rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1249                                         (int) (i - offset),
1250                                         rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+2);
1251
1252                         }
1253
1254                         progbar_count++;
1255                 }
1256         }
1257
1258 }
1259 /****************************************************************************/
1260 static gint expose_event_channels(GtkWidget *widget, GdkEventExpose *event)
1261 {
1262         rtp_channel_info_t *rci;
1263
1264         rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1265         if(!rci){
1266                 exit(10);
1267         }
1268
1269         if (GDK_IS_DRAWABLE(widget->window))
1270                 gdk_draw_drawable(widget->window,
1271                         widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1272                         rci->pixmap,
1273                         event->area.x, event->area.y,
1274                         event->area.x, event->area.y,
1275                         event->area.width, event->area.height);
1276
1277         return FALSE;
1278 }
1279
1280 /****************************************************************************/
1281 static gint 
1282 configure_event_channels(GtkWidget *widget, GdkEventConfigure *event _U_)
1283 {
1284         rtp_channel_info_t *rci;
1285         int i;
1286
1287         /* the first calor is blue to highlight the selected item 
1288          * the other collors are the same as in the Voip Graph analysys
1289          * to match the same calls 
1290          */
1291         static GdkColor col[MAX_NUM_COL_CONV+1] = {
1292                 {0,     0x00FF, 0x00FF, 0xFFFF},
1293                 {0,     0x33FF, 0xFFFF, 0x33FF},
1294                 {0,     0x00FF, 0xCCFF, 0xCCFF},
1295                 {0,     0x66FF, 0xFFFF, 0xFFFF},
1296                 {0,     0x99FF, 0x66FF, 0xFFFF},
1297                 {0,     0xFFFF, 0xFFFF, 0x33FF},
1298                 {0,     0xCCFF, 0x99FF, 0xFFFF},
1299                 {0,     0xCCFF, 0xFFFF, 0x33FF},
1300                 {0,     0xFFFF, 0xCCFF, 0xCCFF},
1301                 {0,     0xFFFF, 0x99FF, 0x66FF},
1302                 {0,     0xFFFF, 0xFFFF, 0x99FF}
1303         };
1304
1305         rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1306         if(!rci){
1307                 exit(10);
1308         }
1309
1310         if(rci->pixmap){
1311                 g_object_unref(rci->pixmap);
1312                 rci->pixmap=NULL;
1313         }
1314
1315         rci->pixmap = gdk_pixmap_new(widget->window,
1316                                         widget->allocation.width,
1317                                         widget->allocation.height,
1318                                         -1);
1319
1320         if ( GDK_IS_DRAWABLE(rci->pixmap) )
1321                 gdk_draw_rectangle(rci->pixmap,
1322                         widget->style->white_gc,
1323                         TRUE,
1324                         0, 0,
1325                         widget->allocation.width,
1326                         widget->allocation.height);
1327
1328         /* create gcs for the background color of each channel */
1329         for (i=0; i<MAX_NUM_COL_CONV+1; i++){
1330                 rci->bg_gc[i]=gdk_gc_new(rci->pixmap);
1331                 gdk_gc_set_rgb_fg_color(rci->bg_gc[i], &col[i]);
1332         }
1333
1334         channel_draw(rci);
1335
1336         return TRUE;
1337 }
1338
1339 /****************************************************************************/
1340 static gint 
1341 button_press_event_channel(GtkWidget *widget, GdkEventButton *event _U_)
1342 {
1343         rtp_channel_info_t *rci;
1344         int this_channel;
1345         guint32 prev_index;
1346
1347         rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1348         if(!rci){
1349                 exit(10);
1350         }
1351
1352         if (!rci->selected) {
1353
1354                 /* only select a new channels if we are in STOP */
1355                 if (!rtp_channels->stop) return 0;
1356
1357                 /* if there are already both channels selected, unselect the old one */
1358                 if (rtp_channels->rci[rtp_channels->channel]) {
1359                         /* we disconnect the signal temporarly to avoid been called back */
1360                         SIGNAL_DISCONNECT_BY_FUNC(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1361                         gtk_toggle_button_set_active((GtkToggleButton *) rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1362                         SIGNAL_CONNECT(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1363                         rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1364                 }
1365
1366                 /* we disconnect the signal temporarly to avoid been called back */
1367                 SIGNAL_DISCONNECT_BY_FUNC(rci->check_bt, on_bt_check_clicked, rci);
1368                 gtk_toggle_button_set_active((GtkToggleButton *) rci->check_bt, TRUE);
1369                 SIGNAL_CONNECT(rci->check_bt, "clicked", on_bt_check_clicked, rci);
1370
1371                 rtp_channels->rci[rtp_channels->channel] = rci;
1372                 rtp_channels->channel = !(rtp_channels->channel);
1373                 rci->selected = TRUE;
1374
1375                 /* set the sensitive state of the buttons (decode, play, pause, stop) */                
1376                 bt_state(TRUE, TRUE, FALSE, FALSE);
1377         }
1378
1379         if (rci == rtp_channels->rci[0]) {
1380                 this_channel = 0;
1381         } else {
1382                 this_channel = 1;
1383         }
1384
1385         rci->frame_index = (unsigned int) (event->x * MULT);
1386         
1387         prev_index = rtp_channels->frame_index;
1388         rtp_channels->frame_index = rtp_channels->start_index[this_channel] + rci->frame_index;
1389         rtp_channels->pause_duration += prev_index - rtp_channels->frame_index;
1390
1391
1392
1393         /* change the index in the other channel if selected, according with the index position */
1394         if (rtp_channels->rci[!this_channel]) {
1395                 init_rtp_channels_vals();
1396
1397                 if (rtp_channels->frame_index < rtp_channels->start_index[!this_channel]) {
1398                         rtp_channels->rci[!this_channel]->frame_index = 0;
1399                 } else if (rtp_channels->frame_index > rtp_channels->end_index[!this_channel]) {
1400                         rtp_channels->rci[!this_channel]->frame_index = rtp_channels->rci[!this_channel]->max_frame_index;
1401                 } else {
1402                         rtp_channels->rci[!this_channel]->frame_index = rtp_channels->frame_index - rtp_channels->start_index[!this_channel];
1403                 }
1404         } else {
1405                 init_rtp_channels_vals();
1406         }
1407
1408         rtp_channels->out_diff_time = 0;
1409
1410         rci->cursor_catch = TRUE;
1411
1412         /* redraw the cusrsor */
1413         draw_cursors(NULL);
1414
1415         return TRUE;
1416 }
1417
1418 /****************************************************************************/
1419 static void
1420 add_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, guint *counter _U_ )
1421 {
1422         GString *label = NULL;
1423         GtkWidget *viewport;
1424
1425
1426         /* create the channel draw area */
1427         rci->draw_area=gtk_drawing_area_new();
1428         
1429         rci->scroll_window=gtk_scrolled_window_new(NULL, NULL);
1430
1431         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (rci->scroll_window), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1432         rci->h_scrollbar_adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window));
1433
1434         
1435         gtk_widget_set_size_request(rci->draw_area, (gint)(rci->samples->len/MULT), CHANNEL_HEIGHT);
1436
1437
1438         viewport = gtk_viewport_new(rci->h_scrollbar_adjustment, gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window)));
1439         gtk_container_add(GTK_CONTAINER(viewport), rci->draw_area);
1440         gtk_container_add(GTK_CONTAINER(rci->scroll_window), viewport);
1441         gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1442         OBJECT_SET_DATA(rci->draw_area, "rtp_channel_info_t", rci);
1443         gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1444         GTK_WIDGET_SET_FLAGS(rci->draw_area, GTK_CAN_FOCUS);
1445         gtk_widget_grab_focus(rci->draw_area);
1446
1447         gtk_box_pack_start(GTK_BOX (channels_vb), rci->scroll_window, FALSE, FALSE, 0);
1448
1449         /* signals needed to handle backing pixmap */
1450         SIGNAL_CONNECT(rci->draw_area, "expose_event", expose_event_channels, NULL);
1451         SIGNAL_CONNECT(rci->draw_area, "configure_event", configure_event_channels, rci);
1452         gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1453         SIGNAL_CONNECT(rci->draw_area, "button_press_event", button_press_event_channel, rci);
1454         SIGNAL_CONNECT(rci->h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, rci);
1455
1456
1457         label = g_string_new("");
1458         g_string_printf(label, "From %s:%d to %s:%d   Duration:%.2f   Drop by Jitter Buff:%d(%.1f%%)   Out of Seq: %d(%.1f%%)", get_addr_name(&(rci->first_stream->src_addr)), 
1459                 rci->first_stream->src_port, get_addr_name(&(rci->first_stream->dest_addr)), rci->first_stream->dest_port, 
1460                 (double)rci->samples->len/SAMPLE_RATE, rci->drop_by_jitter_buff, (double)rci->drop_by_jitter_buff * 100 / (double)rci->num_packets
1461                 , rci->out_of_seq, (double)rci->out_of_seq * 100 / (double)rci->num_packets);
1462
1463         rci->check_bt = gtk_check_button_new_with_label(label->str);
1464         gtk_box_pack_start(GTK_BOX (channels_vb), rci->check_bt, FALSE, FALSE, 1);
1465         
1466         /* Create the Separator if it is not the last one */
1467         (*counter)++;
1468         if (*counter < g_hash_table_size(rtp_channels_hash)) {
1469             rci->separator = gtk_hseparator_new();
1470                 gtk_box_pack_start(GTK_BOX (channels_vb), rci->separator, FALSE, FALSE, 5);
1471         }
1472
1473         SIGNAL_CONNECT(rci->check_bt, "clicked", on_bt_check_clicked, rci);
1474
1475         g_string_free(label, TRUE);
1476 }
1477
1478 /****************************************************************************/
1479 static void
1480 count_channel_frames(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ ) 
1481 {
1482         total_frames += rci->samples->len;
1483 }
1484
1485 /****************************************************************************/
1486 static void
1487 play_channels(void) 
1488 {       
1489         PaError err;
1490         GtkWidget *dialog;
1491
1492         /* we should never be here if we are in PLAY and !PAUSE */
1493         if(!rtp_channels->stop && !rtp_channels->pause){
1494                 exit(10);
1495         }
1496
1497         /* if we are in PAUSE change the sate */
1498         if (rtp_channels->pause) {
1499                 rtp_channels->pause = FALSE;
1500                 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1501                 bt_state(FALSE, FALSE, TRUE, TRUE);
1502
1503         /* if not PAUSE, then start to PLAY */
1504         } else {
1505 #if PORTAUDIO_API_1
1506                 err = Pa_OpenStream(
1507                           &pa_stream,
1508                           paNoDevice,     /* default input device */
1509                           0,              /* no input */
1510                           PA_SAMPLE_TYPE, /* 16 bit Integer input */
1511                           NULL,
1512                           Pa_GetDefaultOutputDeviceID(),
1513                           NUM_CHANNELS,   /* Stereo output */
1514                           PA_SAMPLE_TYPE, /* 16 bit Integer output */
1515                           NULL,
1516                           SAMPLE_RATE,
1517                           FRAMES_PER_BUFFER,
1518                           0,              /* number of buffers, if zero then use default minimum */
1519                           paClipOff,      /* we won't output out of range samples so don't bother clipping them */
1520                           paCallback,
1521                           rtp_channels );
1522 #else /* PORTAUDIO_API_1 */
1523                 err = Pa_OpenDefaultStream( 
1524                                 &pa_stream,
1525                                 0,
1526                                 NUM_CHANNELS,
1527                                 PA_SAMPLE_TYPE,
1528                                 SAMPLE_RATE,
1529                                 FRAMES_PER_BUFFER,
1530                                 paCallback,
1531                                 rtp_channels );
1532 #endif /* PORTAUDIO_API_1 */
1533
1534                 if( err != paNoError ) {
1535                         dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1536                                                                   GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1537                                                                   "Can not Open Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1538                         gtk_dialog_run (GTK_DIALOG (dialog));
1539                         gtk_widget_destroy (dialog);
1540                         return;
1541                 }
1542
1543                 err = Pa_StartStream( pa_stream );
1544                 if( err != paNoError ) {
1545                         dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1546                                                                   GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1547                                                                   "Can not Start Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1548                         gtk_dialog_run (GTK_DIALOG (dialog));
1549                         gtk_widget_destroy (dialog);
1550                         return;
1551                 }
1552 #if !PORTAUDIO_API_1
1553                 rtp_channels->pa_start_time = Pa_GetStreamTime(pa_stream);
1554 #endif /* PORTAUDIO_API_1 */
1555
1556                 rtp_channels->stop = FALSE;
1557
1558                 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1559                 bt_state(FALSE, FALSE, TRUE, TRUE);
1560         }
1561
1562         /* Draw the cursor in the graph */
1563         g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1564
1565 }
1566
1567 /****************************************************************************/
1568 static void
1569 pause_channels(void) 
1570 {       
1571         rtp_channels->pause = !(rtp_channels->pause);
1572
1573         /* reactivate the cusrosr display if no in pause */
1574         if (!rtp_channels->pause) {
1575                 /* Draw the cursor in the graph */
1576                 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1577         }
1578
1579         /* set the sensitive state of the buttons (decode, play, pause, stop) */        
1580         bt_state(FALSE, TRUE, FALSE, TRUE);
1581 }
1582
1583 /****************************************************************************/
1584 static void 
1585 reset_rtp_channels(void)
1586 {
1587         rtp_channels->channel = 0;
1588         rtp_channels->rci[0] = NULL;
1589         rtp_channels->rci[1] = NULL;
1590         rtp_channels->start_index[0] = 0;
1591         rtp_channels->start_index[1] = 0;
1592         rtp_channels->end_index[0] = 0;
1593         rtp_channels->end_index[1] = 0;
1594         rtp_channels->max_frame_index = 0;
1595         rtp_channels->frame_index = 0;
1596         rtp_channels->pause = FALSE;
1597         rtp_channels->pause_duration = 0;
1598         rtp_channels->stop = TRUE;
1599         rtp_channels->out_diff_time = 10000;
1600 }
1601
1602 /****************************************************************************/
1603 static void
1604 remove_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ ) 
1605 {
1606         g_object_unref(rci->pixmap);
1607         gtk_widget_destroy(rci->draw_area);
1608         gtk_widget_destroy(rci->scroll_window);
1609         gtk_widget_destroy(rci->check_bt);
1610         if (rci->separator)
1611                 gtk_widget_destroy(rci->separator);
1612 }
1613
1614 /****************************************************************************/
1615 static void
1616 reset_channels(void)
1617 {
1618
1619         if (rtp_channels_hash) {
1620                 /* Remove the channels from the main window if there are there */
1621                 g_hash_table_foreach( rtp_channels_hash, (GHFunc)remove_channel_to_window, NULL);
1622
1623
1624                 /* destroy the rtp channels hash table */
1625                 g_hash_table_destroy(rtp_channels_hash);
1626                 rtp_channels_hash = NULL;
1627         }
1628
1629         if (rtp_channels) {
1630                 reset_rtp_channels();
1631         }
1632 }
1633
1634 /****************************************************************************/
1635 void
1636 reset_rtp_player(void)
1637 {
1638         /* Destroy the rtp channels */
1639         reset_channels();
1640
1641         /* destroy the rtp streams hash table */
1642         if (rtp_streams_hash) {
1643                 g_hash_table_destroy(rtp_streams_hash);
1644                 rtp_streams_hash = NULL;
1645         }
1646
1647         /* destroy the rtp streams list */
1648         if (rtp_streams_list) {
1649                 g_list_free (rtp_streams_list);
1650                 rtp_streams_list = NULL;
1651         }
1652
1653 }
1654
1655 /****************************************************************************/
1656 static void
1657 decode_streams(void) 
1658 {       
1659         guint statusbar_context;
1660         guint counter;
1661
1662         /* set the sensitive state of the buttons (decode, play, pause, stop) */
1663         bt_state(FALSE, FALSE, FALSE, FALSE);
1664
1665         reset_channels();
1666
1667         progress_bar = gtk_progress_bar_new();
1668         WIDGET_SET_SIZE(progress_bar, 100, -1);
1669         gtk_box_pack_start(GTK_BOX (stat_hbox), progress_bar, FALSE, FALSE, 2);
1670         gtk_widget_show(progress_bar);
1671         statusbar_context = gtk_statusbar_get_context_id((GtkStatusbar *) info_bar, "main");
1672         gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, "  Decoding RTP packets...");
1673
1674         gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
1675
1676         /* reset the number of packet to be decoded, this is used for the progress bar */
1677         total_packets = 0;
1678         /* reset the Progress Bar count */
1679         progbar_count = 0;
1680
1681         /* Mark the RTP streams to be played using the selected VoipCalls*/
1682         if (rtp_streams_hash)
1683                 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_rtp_stream_to_play, NULL);
1684
1685         /* Decode the RTP streams and add them to the RTP channels to be played */
1686         g_list_foreach( rtp_streams_list, (GFunc)decode_rtp_stream, NULL);
1687
1688         /* reset the number of frames to be displayed, this is used for the progress bar */
1689         total_frames = 0;
1690         /* Count the frames in all the RTP channels */
1691         if (rtp_channels_hash)
1692                 g_hash_table_foreach( rtp_channels_hash, (GHFunc)count_channel_frames, NULL);   
1693
1694         /* reset the Progress Bar count again for the progress of creating the channels view */
1695         progbar_count = 0;
1696         gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1697         gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, "  Creating channels view...");
1698
1699         /* Display the RTP channels in the window */
1700         counter = 0;
1701         if (rtp_channels_hash)
1702                 g_hash_table_foreach( rtp_channels_hash, (GHFunc)add_channel_to_window, &counter);      
1703
1704         /* Resize the main scroll window to display no more than 5 channels, otherwise the scroll bar need to be used */
1705         WIDGET_SET_SIZE(main_scrolled_window, CHANNEL_WIDTH, 
1706                 min(counter, 5) * (CHANNEL_HEIGHT+60));
1707
1708         gtk_widget_show_all(main_scrolled_window);
1709
1710         gtk_widget_destroy(progress_bar);
1711         gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
1712         gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1713
1714         /* blank the status label */
1715         gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1716
1717         /* set the sensitive state of the buttons (decode, play, pause, stop) */
1718         bt_state(TRUE, FALSE, FALSE, FALSE);
1719
1720         /* get the static jitter buffer from the spinner gui */
1721         new_jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
1722
1723 }
1724
1725 /****************************************************************************/
1726 static void 
1727 on_bt_decode_clicked(GtkButton *button _U_, gpointer user_data _U_)
1728 {
1729         decode_streams();
1730 }
1731
1732 /****************************************************************************/
1733 static void 
1734 on_bt_play_clicked(GtkButton *button _U_, gpointer user_data _U_)
1735 {
1736         play_channels();
1737 }
1738
1739 /****************************************************************************/
1740 static void 
1741 on_bt_pause_clicked(GtkButton *button _U_, gpointer user_data _U_)
1742 {
1743         pause_channels();
1744 }
1745
1746 /****************************************************************************/
1747 static void 
1748 on_bt_stop_clicked(GtkButton *button _U_, gpointer user_data _U_)
1749 {
1750         stop_channels();
1751 }
1752
1753 /****************************************************************************/
1754 static void
1755 rtp_player_on_destroy(GtkObject *object _U_, gpointer user_data _U_)
1756 {
1757         /* Stop the channels if necesary */
1758         if(rtp_channels && (!rtp_channels->stop)){
1759                 stop_channels();
1760         }
1761
1762         /* Destroy the rtp channels */
1763         reset_channels();
1764
1765         g_free(rtp_channels);
1766         rtp_channels = NULL;
1767
1768         initialized = FALSE;
1769
1770         gtk_widget_destroy(rtp_player_dlg_w);
1771         main_scrolled_window = NULL;
1772         rtp_player_dlg_w = NULL;
1773 }
1774
1775 /****************************************************************************/
1776 static void
1777 jitter_spinner_value_changed (GtkSpinButton *spinner _U_, gpointer user_data _U_)
1778 {
1779         /* set the sensitive state of the buttons (decode, play, pause, stop) */
1780         bt_state(TRUE, TRUE, FALSE, FALSE);
1781 }
1782
1783 /****************************************************************************/
1784 static void
1785 rtp_player_dlg_create(void)
1786 {
1787         GtkWidget *main_vb;
1788         GtkWidget *hbuttonbox;
1789         GtkWidget *h_jitter_buttons_box;
1790         GtkWidget *bt_close;
1791         GtkAdjustment *jitter_spinner_adj;
1792         GtkWidget *label;
1793         const gchar *title_name_ptr;
1794         gchar   *win_name;
1795
1796         GtkTooltips *tooltips = gtk_tooltips_new();
1797
1798         rtp_player_dlg_w=gtk_window_new(GTK_WINDOW_TOPLEVEL);
1799
1800         title_name_ptr = cf_get_display_name(&cfile);
1801         win_name = g_strdup_printf("%s - VoIP - RTP Player", title_name_ptr);   
1802         gtk_window_set_title(GTK_WINDOW(rtp_player_dlg_w), win_name);
1803         gtk_window_set_position(GTK_WINDOW(rtp_player_dlg_w), GTK_WIN_POS_NONE);
1804
1805         gtk_window_set_default_size(GTK_WINDOW(rtp_player_dlg_w), 400, 50);
1806
1807         main_vb = gtk_vbox_new (FALSE, 0);
1808         gtk_container_add(GTK_CONTAINER(rtp_player_dlg_w), main_vb);
1809         gtk_container_set_border_width (GTK_CONTAINER (main_vb), 2);
1810         
1811         main_scrolled_window=gtk_scrolled_window_new(NULL, NULL);
1812         gtk_container_set_border_width (GTK_CONTAINER (main_scrolled_window), 4);
1813         WIDGET_SET_SIZE(main_scrolled_window, CHANNEL_WIDTH, 0);
1814
1815         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (main_scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1816         gtk_container_add(GTK_CONTAINER(main_vb), main_scrolled_window);
1817
1818         channels_vb = gtk_vbox_new (FALSE, 0);
1819         gtk_container_set_border_width (GTK_CONTAINER (channels_vb), 2);
1820         gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *) main_scrolled_window, channels_vb);
1821
1822         h_jitter_buttons_box = gtk_hbox_new (FALSE, 0);
1823         gtk_container_set_border_width (GTK_CONTAINER (h_jitter_buttons_box), 10);
1824         gtk_box_pack_start (GTK_BOX(main_vb), h_jitter_buttons_box, FALSE, FALSE, 0);
1825         label = gtk_label_new("Jitter buffer [ms] ");
1826         gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), label, FALSE, FALSE, 0);
1827         
1828         jitter_spinner_adj = (GtkAdjustment *) gtk_adjustment_new (50, 0, 500, 5, 10, 10);
1829         jitter_spinner = gtk_spin_button_new (jitter_spinner_adj, 5, 0);
1830         gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), jitter_spinner, FALSE, FALSE, 0);
1831         gtk_tooltips_set_tip (tooltips, jitter_spinner, "The simulated jitter buffer in [ms]", NULL);
1832         SIGNAL_CONNECT(GTK_OBJECT (jitter_spinner_adj), "value_changed", (GtkSignalFunc) jitter_spinner_value_changed, NULL);
1833
1834         /* button row */
1835         hbuttonbox = gtk_hbutton_box_new ();
1836         gtk_box_pack_start (GTK_BOX (h_jitter_buttons_box), hbuttonbox, TRUE, TRUE, 0);
1837         gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
1838         gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
1839
1840         bt_decode = gtk_button_new_with_label("Decode");
1841         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_decode);
1842         SIGNAL_CONNECT(bt_decode, "clicked", on_bt_decode_clicked, NULL);
1843         gtk_tooltips_set_tip (tooltips, bt_decode, "Decode the RTP stream(s)", NULL);
1844
1845         bt_play = gtk_button_new_with_label("Play");
1846         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_play);
1847         SIGNAL_CONNECT(bt_play, "clicked", on_bt_play_clicked, NULL);
1848         gtk_tooltips_set_tip (tooltips, bt_play, "Play the RTP channel(s)", NULL);
1849
1850         bt_pause = gtk_button_new_with_label("Pause");
1851         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_pause);
1852         SIGNAL_CONNECT(bt_pause, "clicked", on_bt_pause_clicked, NULL);
1853         gtk_tooltips_set_tip (tooltips, bt_pause, "Pause the RTP channel(s)", NULL);
1854
1855         bt_stop = gtk_button_new_with_label("Stop");
1856         gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_stop);
1857         SIGNAL_CONNECT(bt_stop, "clicked", on_bt_stop_clicked, NULL);
1858         gtk_tooltips_set_tip (tooltips, bt_stop, "Stop the RTP channel(s)", NULL);
1859
1860         bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
1861         gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
1862         GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
1863         gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
1864
1865         SIGNAL_CONNECT(bt_close, "clicked", rtp_player_on_destroy, NULL);
1866         SIGNAL_CONNECT(rtp_player_dlg_w, "destroy", rtp_player_on_destroy, NULL);
1867
1868         /* button row */
1869         hbuttonbox = gtk_hbutton_box_new ();
1870
1871         /* Filter/status hbox */
1872         stat_hbox = gtk_hbox_new(FALSE, 1);
1873         gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1874
1875         /* statusbar */
1876         info_bar = gtk_statusbar_new();
1877         gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
1878
1879         gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1880
1881         /* statusbar hbox */
1882         gtk_box_pack_start(GTK_BOX(main_vb), stat_hbox, FALSE, TRUE, 0);
1883
1884         /* set the sensitive state of the buttons (decode, play, pause, stop) */
1885         bt_state(TRUE, FALSE, FALSE, FALSE);
1886         
1887         gtk_widget_show_all(rtp_player_dlg_w);
1888
1889         /* Force gtk to redraw the window before starting decoding the packet */
1890         while (g_main_context_iteration(NULL, FALSE));
1891
1892         g_free(win_name);
1893 }
1894
1895 /****************************************************************************/
1896 void
1897 rtp_player_init(voip_calls_tapinfo_t *voip_calls_tap)
1898 {
1899         PaError err;
1900         GtkWidget *dialog;
1901
1902         if (initialized) return;
1903         initialized = TRUE;
1904
1905         voip_calls = voip_calls_tap;
1906         err = Pa_Initialize();
1907         if( err != paNoError ) {
1908                 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1909                                   GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1910                                   "Can not Initialize the PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1911                 gtk_dialog_run (GTK_DIALOG (dialog));
1912                 gtk_widget_destroy (dialog);
1913                 initialized = FALSE;
1914                 return;
1915         }
1916
1917         new_jitter_buff = -1;
1918
1919 #ifdef HAVE_G729_G723
1920         /* Initialize the G729 and G723 decoders */
1921         initG723();
1922         initG729();
1923 #endif /* HAVE_G729_G723 */
1924
1925         if (!rtp_channels) {
1926                 rtp_channels = g_malloc(sizeof(rtp_play_channles_t));
1927         }
1928
1929         reset_rtp_channels();
1930
1931         /* create the dialog window */
1932         rtp_player_dlg_create();
1933         
1934 }
1935
1936 #endif /* GTK_MAJOR_VERSION >= 2 */
1937  
1938 #endif /* HAVE_LIBPORTAUDIO */