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