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