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