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