5 * Copyright 2006, Alejandro Vaquero <alejandrovaquero@yahoo.com>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1999 Gerald Combs
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.
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.
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.
27 * Here is a summary on how this works:
28 * - The VoipCalls will call add_rtp_packet() every time there is an RTP
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
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
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)
58 #ifdef HAVE_LIBPORTAUDIO
61 #include "portaudio.h"
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>
72 #include "../globals.h"
73 #include "../simple_dialog.h"
74 #include "../codecs/G711a/G711adecode.h"
75 #include "../codecs/G711u/G711udecode.h"
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"
87 #define min(a,b) (((a)<(b))?(a):(b))
90 #define max(a,b) (((a)>(b))?(a):(b))
93 /*define this symbol to compile with G729 and G723 codecs*/
94 /*#define HAVE_G729_G723 1*/
97 #include "codecs/G729/G729decode.h"
98 #include "codecs/G723/G723decode.h"
99 #endif /* HAVE_G729_G723 */
101 static gboolean initialized = FALSE;
103 voip_calls_tapinfo_t *voip_calls = NULL;
105 /* Hash table with all the RTP streams */
106 static GHashTable* rtp_streams_hash = NULL;
108 /* List with all the RTP streams (this is used to decode them as it is sorted)*/
109 static GList* rtp_streams_list = NULL;
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;
125 static guint32 total_packets;
126 static guint32 total_frames;
127 static guint32 progbar_count;
129 static int new_jitter_buff;
131 /* a hash table with the RTP streams to play per audio channel */
132 static GHashTable *rtp_channels_hash = NULL;
134 /* Port Audio stuff */
135 #define SAMPLE_RATE (8000)
136 #define NUM_CHANNELS (2)
138 #define PA_SAMPLE_TYPE paInt16
139 typedef gint16 SAMPLE;
140 #define SAMPLE_SILENCE (0)
141 #define FRAMES_PER_BUFFER (512)
143 typedef struct _sample_t {
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 */
153 /* Display channels constants */
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
162 PortAudioStream *pa_stream;
163 #else /* PORTAUDIO_API_1 */
165 #endif /* PORTAUDIO_API_1 */
167 /* defines a RTP stream */
168 typedef struct _rtp_stream_info {
174 guint32 first_frame_number; /* first RTP frame for the stream */
175 double start_time; /* RTP stream start time in ms */
178 GList* rtp_packets_list; /* List of RTP packets in the stream */
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 */
191 guint32 drop_by_jitter_buff;
193 guint32 wrong_timestamp;
194 guint32 max_frame_index;
196 GtkWidget *separator;
197 GtkWidget *scroll_window;
198 GtkWidget *draw_area;
200 GtkAdjustment *h_scrollbar_adjustment;
201 GdkPixbuf* cursor_pixbuf;
203 PaTimestamp cursor_prev;
204 #else /* PORTAUDIO_API_1 */
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 */
211 } rtp_channel_info_t;
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;
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];
226 guint32 max_frame_index;
230 gint32 pause_duration;
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;
239 /* The two RTP channels to play */
240 static rtp_play_channels_t *rtp_channels = NULL;
242 typedef struct _rtp_decoder_t {
243 codec_handle_t handle;
248 /****************************************************************************/
250 rtp_key_destroy(gpointer key)
256 /****************************************************************************/
258 rtp_channel_value_destroy(gpointer rci_arg)
260 rtp_channel_info_t *rci = rci_arg;
262 g_array_free(rci->samples, TRUE);
267 /****************************************************************************/
269 rtp_stream_value_destroy(gpointer rsi_arg)
271 rtp_stream_info_t *rsi = rsi_arg;
272 GList* rtp_packets_list;
275 rtp_packets_list = g_list_first(rsi->rtp_packets_list);
276 while (rtp_packets_list)
278 rp = rtp_packets_list->data;
281 g_free(rp->payload_data);
285 rtp_packets_list = g_list_next(rtp_packets_list);
287 g_free((void *)(rsi->src_addr.data));
288 g_free((void *)(rsi->dest_addr.data));
293 /****************************************************************************/
295 rtp_decoder_value_destroy(gpointer dec_arg)
297 rtp_decoder_t *dec = dec_arg;
300 codec_release(dec->handle, dec->context);
304 /****************************************************************************/
306 set_sensitive_check_bt(gchar *key _U_ , rtp_channel_info_t *rci, guint *stop _U_ )
308 gtk_widget_set_sensitive(rci->check_bt, !(*stop));
311 /****************************************************************************/
313 bt_state(gboolean decode, gboolean play, gboolean pause, gboolean stop)
315 gboolean new_jitter_value = FALSE;
316 gboolean false_val = FALSE;
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);
323 gtk_widget_set_sensitive(jitter_spinner, decode);
326 if (new_jitter_buff != (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner)) {
327 new_jitter_value = TRUE;
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);
334 gtk_widget_set_sensitive(bt_play, FALSE);
337 if (!new_jitter_value) {
338 gtk_widget_set_sensitive(bt_pause, pause);
339 gtk_widget_set_sensitive(bt_stop, stop);
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);
345 gtk_widget_set_sensitive(bt_pause, FALSE);
346 gtk_widget_set_sensitive(bt_stop, FALSE);
348 if (rtp_channels_hash)
349 g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &false_val);
353 /****************************************************************************/
355 add_rtp_packet(const struct _rtp_info *rtp_info, packet_info *pinfo)
357 rtp_stream_info_t *stream_info = NULL;
358 rtp_packet_t *new_rtp_packet;
359 GString *key_str = NULL;
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);
365 /* Create a hash key to lookup in the RTP streams hash table
366 * uses: src_ip:src_port dst_ip:dst_port ssrc
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 );
373 /* lookup for this RTP packet in the stream hash table */
374 stream_info = g_hash_table_lookup( rtp_streams_hash, key_str->str);
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;
391 g_hash_table_insert(rtp_streams_hash, g_strdup(key_str->str), stream_info);
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);
397 /* increment the number of packets in this stream, this is used for the progress bar and statistics */
398 stream_info->num_packets++;
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));
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);
411 new_rtp_packet->payload_data = NULL;
414 stream_info->rtp_packets_list = g_list_append(stream_info->rtp_packets_list, new_rtp_packet);
416 g_string_free(key_str, TRUE);
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.
424 mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
427 graph_analysis_item_t *graph_item;
428 GList* voip_calls_list;
429 voip_calls_info_t *tmp_voip_call;
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
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);
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)
447 tmp_voip_call = voip_calls_list->data;
448 if ( (tmp_voip_call->call_num == rsi->call_num) && (tmp_voip_call->selected == TRUE) ) {
450 total_packets += rsi->num_packets;
453 voip_calls_list = g_list_next(voip_calls_list);
457 graph_list = g_list_next(graph_list);
461 /****************************************************************************/
462 /* Mark the ALL RTP stream to be played. This is called when calling the
463 * RTP player from the "RTP Analysis" window
466 mark_all_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
469 total_packets += rsi->num_packets;
472 /****************************************************************************/
473 /* Decode a RTP packet
474 * Return the number of decoded bytes
477 decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash)
479 unsigned int payload_type;
481 rtp_decoder_t *decoder;
482 SAMPLE *tmp_buff = NULL;
484 int decoded_bytes = 0;
486 if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
490 payload_type = rp->info->info_payload_type;
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);
500 decoder->handle = find_codec(p);
502 decoder->context = codec_init(decoder->handle);
504 g_hash_table_insert(decoders_hash, GUINT_TO_POINTER(payload_type), decoder);
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;
514 /* Try to decode with built-in codec */
516 switch (payload_type) {
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);
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);
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);
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 */
547 decodeG723(rp->payload_data, rp->info->info_payload_len,
548 tmp_buff, &decoded_bytes);
550 #endif /* HAVE_G729_G723 */
554 * XXX - return an error here, so the user gets told that
555 * we don't support this codec!
560 *out_buff = tmp_buff;
561 return decoded_bytes;
564 /****************************************************************************/
566 update_progress_bar(gfloat fraction)
569 if GTK_IS_PROGRESS_BAR(progress_bar)
570 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), fraction);
572 /* Force gtk to redraw the window before starting decoding the packet */
573 while (gtk_events_pending())
574 gtk_main_iteration();
577 /****************************************************************************/
578 /* Decode the RTP streams and add them to the RTP channels struct
581 decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
583 GString *key_str = NULL;
584 rtp_channel_info_t *rci;
585 gboolean first = TRUE;
586 GList* rtp_packets_list;
591 double rtp_time_prev;
593 double arrive_time_prev;
595 double start_rtp_time = 0;
599 double total_time_prev;
600 gint32 silence_frames;
607 int decoded_bytes_prev;
609 SAMPLE *out_buff = NULL;
613 guint32 start_timestamp;
614 GHashTable *decoders_hash = NULL;
616 guint32 progbar_nextstep;
621 silence.status = S_NORMAL;
623 /* skip it if we are not going to play it */
624 if (rsi->play == FALSE) {
628 /* get the static jitter buffer from the spinner gui */
629 jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
631 /* Create a hash key to lookup in the RTP channels hash
632 * uses: src_ip:src_port dst_ip:dst_port call_num
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 );
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);
644 /* lookup for this stream in the channel hash table */
645 rci = g_hash_table_lookup( rtp_channels_hash, key_str->str);
647 /* ..if it is not in the hash, create an entry */
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;
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;
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);
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);
677 rci->num_packets += rsi->num_packets;
680 /* decode the RTP stream */
685 decoded_bytes_prev = 0;
687 arrive_time = start_time = 0;
688 arrive_time_prev = 0;
698 decoders_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, rtp_decoder_value_destroy);
700 /* we update the progress bar 100 times */
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;
710 rtp_packets_list = g_list_first(rsi->rtp_packets_list);
711 while (rtp_packets_list)
714 if (progbar_count >= progbar_nextstep) {
715 g_assert(total_packets > 0);
717 progbar_val = (gfloat) progbar_count / total_packets;
719 update_progress_bar(progbar_val);
721 progbar_nextstep += progbar_quantum;
725 rp = rtp_packets_list->data;
727 start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
729 rtp_time_prev = start_rtp_time;
731 seq = rp->info->info_seq_num - 1;
734 decoded_bytes = decode_rtp_packet(rp, &out_buff, decoders_hash);
735 if (decoded_bytes == 0) {
736 seq = rp->info->info_seq_num;
739 rtp_time = (double)(rp->info->info_timestamp-start_timestamp)/SAMPLE_RATE - start_rtp_time;
741 if (GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp)->active) {
742 arrive_time = rtp_time;
744 arrive_time = (double)rp->arrive_offset/1000 - start_time;
747 if (rp->info->info_seq_num != seq+1){
749 status = S_WRONG_SEQ;
751 seq = rp->info->info_seq_num;
753 diff = arrive_time - rtp_time;
755 delay = diff - prev_diff;
757 if (delay<0) delay = -delay;
759 if (diff<0) diff = -diff;
761 total_time = (double)rp->arrive_offset/1000;
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);
768 /* if the jitter buffer was exceeded */
769 if ( diff*1000 > jitter_buff ) {
771 printf("Packet drop by jitter buffer exceeded\n");
773 rci->drop_by_jitter_buff++;
774 status = S_DROP_BY_JITT;
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 ){
779 printf("Resync...\n");
781 silence_frames = (gint32)((arrive_time - arrive_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
783 /* Fix for bug 4119: don't insert more than 1000 silence frames.
784 * XXX - is there a better thing to do here?
786 if (silence_frames > 1000)
787 silence_frames = 1000;
789 for (i = 0; i< silence_frames; i++) {
790 silence.status = status;
791 g_array_append_val(rci->samples, silence);
793 /* only mark the first in the silence that has the previous problem (S_DROP_BY_JITT or S_WRONG_SEQ) */
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 */
800 start_time = (double)rp->arrive_offset/1000;
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;
811 /* Fix for bug 4119: don't insert more than 1000 silence frames.
812 * XXX - is there a better thing to do here?
814 if (silence_frames > 1000)
815 silence_frames = 1000;
817 for (i = 0; i< silence_frames; i++) {
818 silence.status = status;
819 g_array_append_val(rci->samples, silence);
821 /* only mark the first in the silence that has the previous problem (S_DROP_BY_JITT or S_WRONG_SEQ) */
826 if (silence_frames > 0) {
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);
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;
847 rtp_packets_list = g_list_next (rtp_packets_list);
850 rci->max_frame_index = rci->samples->len;
851 rci->end_time = rci->start_time + ((double)rci->samples->len/SAMPLE_RATE)*1000;
853 g_string_free(key_str, TRUE);
854 g_hash_table_destroy(decoders_hash);
857 /****************************************************************************/
859 h_scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
861 rtp_channel_info_t *rci = (rtp_channel_info_t *)user_data;
862 rci->cursor_catch = TRUE;
866 static gboolean draw_cursors(gpointer data);
868 /****************************************************************************/
875 /* we should never be here if we are already in STOP */
876 if(rtp_channels->stop){
880 rtp_channels->stop = TRUE;
881 /* force a draw_cursor to stop it */
884 err = Pa_StopStream(pa_stream);
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);
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);
904 pa_stream = NULL; /* to catch errors better */
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;
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;
920 /* set the sensitive state of the buttons (decode, play, pause, stop) */
921 bt_state(TRUE, TRUE, FALSE, FALSE);
925 /****************************************************************************/
926 /* Draw a cursor in a channel graph
929 draw_channel_cursor(rtp_channel_info_t *rci, guint32 start_index)
933 #else /* PORTAUDIO_API_1 */
935 #endif /* 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 */
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) ) {
953 /* If only this channel finished, then return */
954 if (idx > rci->max_frame_index) {
958 /* draw the previous saved pixbuf line */
959 if (rci->cursor_pixbuf && (rci->cursor_prev>=0)) {
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);
963 gdk_draw_drawable(rci->draw_area->window,
964 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
966 (int) (rci->cursor_prev/MULT), 0,
967 (int) (rci->cursor_prev/MULT), 0,
968 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
970 g_object_unref(rci->cursor_pixbuf);
971 rci->cursor_pixbuf = NULL;
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);
977 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
981 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
983 gdk_draw_drawable(rci->draw_area->window,
984 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
988 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
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);
994 /* Move the horizontal scroll bar */
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);
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;
1010 rci->h_scrollbar_adjustment->value = idx/MULT - rci->h_scrollbar_adjustment->page_size/2;
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);
1025 /* Connect back the "value" scroll signal */
1026 g_signal_connect(rci->h_scrollbar_adjustment, "value_changed", G_CALLBACK(h_scrollbar_changed), rci);
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;
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;
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;
1046 rci->h_scrollbar_adjustment->value = idx/MULT - rci->h_scrollbar_adjustment->page_size/2;
1051 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
1053 rci->cursor_prev = idx;
1056 /****************************************************************************/
1057 /* Move and draw the cursor in the graph
1060 draw_cursors(gpointer data _U_)
1062 if (!rtp_channels) return FALSE;
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]);
1068 if ((rtp_channels->stop) || (rtp_channels->pause)) return FALSE;
1073 /****************************************************************************/
1075 init_rtp_channels_vals(void)
1077 rtp_play_channels_t *rpci = rtp_channels;
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;
1093 /* if the two channels are to be played, then we need to sync both based on the start/end time of each one */
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));
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);
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);
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;
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;
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().
1124 static int paCallback( void *inputBuffer, void *outputBuffer,
1125 unsigned long framesPerBuffer,
1126 PaTimestamp outTime, void *userData)
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_,
1135 #endif /* PORTAUDIO_API_1 */
1136 rtp_play_channels_t *rpci = (rtp_play_channels_t *)userData;
1137 SAMPLE *wptr = (SAMPLE*)outputBuffer;
1141 unsigned int framesLeft;
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++ ) {
1150 rtp_channels->pause_duration += framesPerBuffer;
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 */
1161 /* set the values if this is the first time */
1162 if (rpci->max_frame_index == 0) {
1163 init_rtp_channels_vals();
1167 framesLeft = rpci->max_frame_index - rpci->frame_index;
1169 (void) inputBuffer; /* Prevent unused variable warnings. */
1172 if( framesLeft < framesPerBuffer )
1174 framesToPlay = framesLeft;
1179 framesToPlay = framesPerBuffer;
1183 for( i=0; i<(unsigned int)framesToPlay; i++ )
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;
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;
1199 for( ; i<framesPerBuffer; i++ )
1204 rpci->frame_index += framesToPlay;
1209 /****************************************************************************/
1211 on_bt_check_clicked(GtkButton *button _U_, gpointer user_data _U_)
1213 rtp_channel_info_t *rci = user_data;
1215 if (rci->selected) {
1216 if (rtp_channels->rci[0] == rci) {
1217 rtp_channels->rci[0] = NULL;
1218 rtp_channels->channel = 0;
1220 rtp_channels->rci[1] = NULL;
1221 rtp_channels->channel = 1;
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;
1233 rtp_channels->rci[rtp_channels->channel] = rci;
1234 rtp_channels->channel = !(rtp_channels->channel);
1237 rci->selected = !(rci->selected);
1239 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1240 bt_state(TRUE, TRUE, FALSE, FALSE);
1243 /****************************************************************************/
1244 static void channel_draw(rtp_channel_info_t* rci)
1250 PangoLayout *small_layout;
1251 guint32 label_width, label_height;
1252 char label_string[MAX_TIME_LABEL];
1254 guint32 progbar_nextstep;
1255 int progbar_quantum;
1261 GdkColor red_color = {0, 65535, 0, 0};
1262 GdkColor amber_color = {0, 65535, 49152, 0};
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],
1270 rci->draw_area->allocation.width,
1271 rci->draw_area->allocation.height);
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"));
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;
1279 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1281 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1282 rci->draw_area->allocation.width,
1283 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
1285 imax = min(rci->draw_area->allocation.width,(gint)(rci->samples->len/MULT));
1287 /* we update the progress bar 100 times */
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;
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);
1300 for (i=0; i< imax; i++) {
1306 if (progbar_count >= progbar_nextstep) {
1307 g_assert(total_frames > 0);
1309 progbar_val = (gfloat) i / imax;
1311 update_progress_bar(progbar_val);
1313 progbar_nextstep += progbar_quantum;
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;
1324 if (status == S_DROP_BY_JITT) {
1326 } else if (status == S_WRONG_TIMESTAMP) {
1329 gc = rci->draw_area->style->black_gc;
1332 gdk_draw_line(rci->pixmap, gc,
1334 (gint)(( (0x7FFF+min) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF),
1336 (gint)(( (0x7FFF+max) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF));
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,
1342 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1344 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+4);
1346 g_snprintf(label_string, MAX_TIME_LABEL, "%.0f", floor(rci->start_time/1000) + i*MULT/SAMPLE_RATE);
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,
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,
1359 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1361 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+2);
1370 /****************************************************************************/
1371 static gint expose_event_channels(GtkWidget *widget, GdkEventExpose *event)
1373 rtp_channel_info_t *rci;
1375 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1380 if (GDK_IS_DRAWABLE(widget->window))
1381 gdk_draw_drawable(widget->window,
1382 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1384 event->area.x, event->area.y,
1385 event->area.x, event->area.y,
1386 event->area.width, event->area.height);
1391 /****************************************************************************/
1393 configure_event_channels(GtkWidget *widget, GdkEventConfigure *event _U_)
1395 rtp_channel_info_t *rci;
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
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}
1416 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1422 g_object_unref(rci->pixmap);
1426 rci->pixmap = gdk_pixmap_new(widget->window,
1427 widget->allocation.width,
1428 widget->allocation.height,
1431 if ( GDK_IS_DRAWABLE(rci->pixmap) )
1432 gdk_draw_rectangle(rci->pixmap,
1433 widget->style->white_gc,
1436 widget->allocation.width,
1437 widget->allocation.height);
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]);
1450 /****************************************************************************/
1452 button_press_event_channel(GtkWidget *widget, GdkEventButton *event _U_)
1454 rtp_channel_info_t *rci;
1458 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1463 if (!rci->selected) {
1465 /* only select a new channels if we are in STOP */
1466 if (!rtp_channels->stop) return 0;
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;
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);
1482 rtp_channels->rci[rtp_channels->channel] = rci;
1483 rtp_channels->channel = !(rtp_channels->channel);
1484 rci->selected = TRUE;
1486 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1487 bt_state(TRUE, TRUE, FALSE, FALSE);
1490 if (rci == rtp_channels->rci[0]) {
1496 rci->frame_index = (unsigned int) (event->x * MULT);
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;
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();
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;
1513 rtp_channels->rci[!this_channel]->frame_index = rtp_channels->frame_index - rtp_channels->start_index[!this_channel];
1516 init_rtp_channels_vals();
1519 rtp_channels->out_diff_time = 0;
1521 rci->cursor_catch = TRUE;
1523 /* redraw the cusrsor */
1529 /****************************************************************************/
1531 add_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, guint *counter _U_ )
1533 GString *label = NULL;
1534 GtkWidget *viewport;
1537 /* create the channel draw area */
1538 rci->draw_area=gtk_drawing_area_new();
1540 rci->scroll_window=gtk_scrolled_window_new(NULL, NULL);
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));
1546 gtk_widget_set_size_request(rci->draw_area, (gint)(rci->samples->len/MULT), CHANNEL_HEIGHT);
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);
1558 gtk_box_pack_start(GTK_BOX (channels_vb), rci->scroll_window, FALSE, FALSE, 0);
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);
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);
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);
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);
1589 /* Create the Separator if it is not the last one */
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);
1596 g_signal_connect(rci->check_bt, "clicked", G_CALLBACK(on_bt_check_clicked), rci);
1598 g_string_free(label, TRUE);
1601 /****************************************************************************/
1603 count_channel_frames(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
1605 total_frames += rci->samples->len;
1608 /****************************************************************************/
1615 /* we should never be here if we are in PLAY and !PAUSE */
1616 if(!rtp_channels->stop && !rtp_channels->pause){
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);
1626 /* if not PAUSE, then start to PLAY */
1629 err = Pa_OpenStream(
1631 paNoDevice, /* default input device */
1633 PA_SAMPLE_TYPE, /* 16 bit Integer input */
1635 Pa_GetDefaultOutputDeviceID(),
1636 NUM_CHANNELS, /* Stereo output */
1637 PA_SAMPLE_TYPE, /* 16 bit Integer output */
1639 SAMPLE_RATE, /* 8 kHz */
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 */
1646 if( err != paNoError ) {
1647 const char *deviceName = "No Device";
1649 PaDeviceID device = Pa_GetDefaultOutputDeviceID();
1651 if (device != paNoDevice)
1653 const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo( device );
1655 deviceName = deviceInfo->name;
1657 deviceName = "(No device info)";
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);
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);
1674 #else /* PORTAUDIO_API_1 */
1675 if (Pa_GetDefaultOutputDevice() != paNoDevice) {
1676 err = Pa_OpenDefaultStream(
1679 NUM_CHANNELS, /* Stereo output */
1680 PA_SAMPLE_TYPE, /* 16 bit Integer output */
1681 SAMPLE_RATE, /* 8 kHz */
1686 /* If the Default Host API doesn't even provide a device
1687 * we might as well go look for another.
1689 PaHostApiIndex host_api_count = Pa_GetHostApiCount();
1690 PaHostApiIndex default_host_api_index = Pa_GetDefaultHostApi();
1692 PaHostApiIndex host_api_index;
1693 const PaHostApiInfo *host_api_info;
1695 for (host_api_index=0; host_api_index<host_api_count; host_api_index++)
1697 /* Skip the default host API, that didn't work before */
1698 if (host_api_index == default_host_api_index)
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)
1707 if (host_api_index<host_api_count)
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;
1716 g_print("Trying Host API: %s\n", host_api_info->name);
1718 err = Pa_OpenStream(
1720 NULL, /* no input */
1722 SAMPLE_RATE, /* 8 kHz */
1724 paClipOff, /* we won't output out of range samples so don't bother clipping them */
1734 if( err != paNoError ) {
1735 PaHostApiIndex hostApi = Pa_GetDefaultHostApi();
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);
1747 const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo( hostApi );
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);
1759 const char *hostApiName = hostApiInfo->name;
1760 const char *deviceName = "No Device";
1762 PaDeviceIndex device = hostApiInfo->defaultOutputDevice;
1764 if (device != paNoDevice)
1766 const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo( device );
1768 deviceName = deviceInfo->name;
1770 deviceName = "(No device info)";
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);
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);
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);
1801 #if !PORTAUDIO_API_1
1802 rtp_channels->pa_start_time = Pa_GetStreamTime(pa_stream);
1803 #endif /* PORTAUDIO_API_1 */
1805 rtp_channels->stop = FALSE;
1807 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1808 bt_state(FALSE, FALSE, TRUE, TRUE);
1811 /* Draw the cursor in the graph */
1812 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1816 /****************************************************************************/
1818 pause_channels(void)
1820 rtp_channels->pause = !(rtp_channels->pause);
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);
1828 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1829 bt_state(FALSE, TRUE, FALSE, TRUE);
1832 /****************************************************************************/
1834 reset_rtp_channels(void)
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;
1851 /****************************************************************************/
1853 remove_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
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);
1860 gtk_widget_destroy(rci->separator);
1863 /****************************************************************************/
1865 reset_channels(void)
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);
1873 /* destroy the rtp channels hash table */
1874 g_hash_table_destroy(rtp_channels_hash);
1875 rtp_channels_hash = NULL;
1879 reset_rtp_channels();
1883 /****************************************************************************/
1885 reset_rtp_player(void)
1887 /* Destroy the rtp channels */
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;
1896 /* destroy the rtp streams list */
1897 if (rtp_streams_list) {
1898 g_list_free (rtp_streams_list);
1899 rtp_streams_list = NULL;
1904 /****************************************************************************/
1906 decode_streams(void)
1908 guint statusbar_context;
1911 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1912 bt_state(FALSE, FALSE, FALSE, FALSE);
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...");
1923 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
1925 /* reset the number of packet to be decoded, this is used for the progress bar */
1927 /* reset the Progress Bar count */
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) {
1934 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_rtp_stream_to_play, NULL);
1936 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_all_rtp_stream_to_play, NULL);
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);
1942 /* reset the number of frames to be displayed, this is used for the progress bar */
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);
1948 /* reset the Progress Bar count again for the progress of creating the channels view */
1950 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1951 gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, " Creating channels view...");
1953 /* Display the RTP channels in the window */
1955 if (rtp_channels_hash)
1956 g_hash_table_foreach( rtp_channels_hash, (GHFunc)add_channel_to_window, &counter);
1958 /* Resize the main scroll window to display no more than preferred (or default) max channels, scroll bar will be used if needed */
1960 if (prefs.rtp_player_max_visible < 1 || prefs.rtp_player_max_visible > 10)
1961 prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
1963 gtk_widget_set_size_request(main_scrolled_window, CHANNEL_WIDTH,
1964 min(counter, prefs.rtp_player_max_visible) * (CHANNEL_HEIGHT+60));
1966 gtk_widget_show_all(main_scrolled_window);
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);
1972 /* blank the status label */
1973 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1975 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1976 bt_state(TRUE, FALSE, FALSE, FALSE);
1978 /* get the static jitter buffer from the spinner gui */
1979 new_jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
1983 /****************************************************************************/
1985 on_cb_use_rtp_clicked(GtkToggleButton *button _U_, gpointer user_data _U_)
1987 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1988 bt_state(TRUE, FALSE, FALSE, FALSE);
1991 /****************************************************************************/
1993 on_bt_decode_clicked(GtkButton *button _U_, gpointer user_data _U_)
1998 /****************************************************************************/
2000 on_bt_play_clicked(GtkButton *button _U_, gpointer user_data _U_)
2005 /****************************************************************************/
2007 on_bt_pause_clicked(GtkButton *button _U_, gpointer user_data _U_)
2012 /****************************************************************************/
2014 on_bt_stop_clicked(GtkButton *button _U_, gpointer user_data _U_)
2019 /****************************************************************************/
2021 rtp_player_on_destroy(GtkObject *object _U_, gpointer user_data _U_)
2026 /* Stop the channels if necesary */
2027 if(rtp_channels && (!rtp_channels->stop)){
2031 /* Destroy the rtp channels */
2034 g_free(rtp_channels);
2035 rtp_channels = NULL;
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);
2048 gtk_widget_destroy(rtp_player_dlg_w);
2049 main_scrolled_window = NULL;
2050 rtp_player_dlg_w = NULL;
2053 /****************************************************************************/
2055 jitter_spinner_value_changed (GtkSpinButton *spinner _U_, gpointer user_data _U_)
2057 /* set the sensitive state of the buttons (decode, play, pause, stop) */
2058 bt_state(TRUE, TRUE, FALSE, FALSE);
2061 /****************************************************************************/
2063 rtp_player_dlg_create(void)
2066 GtkWidget *hbuttonbox;
2067 GtkWidget *h_jitter_buttons_box;
2068 GtkWidget *bt_close;
2069 GtkAdjustment *jitter_spinner_adj;
2071 const gchar *title_name_ptr;
2074 GtkTooltips *tooltips = gtk_tooltips_new();
2076 title_name_ptr = cf_get_display_name(&cfile);
2077 win_name = g_strdup_printf("%s - VoIP - RTP Player", title_name_ptr);
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);
2083 gtk_window_set_default_size(GTK_WINDOW(rtp_player_dlg_w), 400, 50);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
2155 hbuttonbox = gtk_hbutton_box_new ();
2157 /* Filter/status hbox */
2158 stat_hbox = gtk_hbox_new(FALSE, 1);
2159 gtk_container_set_border_width(GTK_CONTAINER(stat_hbox), 0);
2162 info_bar = gtk_statusbar_new();
2163 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
2165 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2167 /* statusbar hbox */
2168 gtk_box_pack_start(GTK_BOX(main_vb), stat_hbox, FALSE, TRUE, 0);
2170 /* set the sensitive state of the buttons (decode, play, pause, stop) */
2171 bt_state(TRUE, FALSE, FALSE, FALSE);
2173 gtk_widget_show_all(rtp_player_dlg_w);
2175 /* Force gtk to redraw the window before starting decoding the packet */
2176 while (g_main_context_iteration(NULL, FALSE));
2181 /****************************************************************************/
2183 rtp_player_init(voip_calls_tapinfo_t *voip_calls_tap)
2188 if (initialized) return;
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;
2203 new_jitter_buff = -1;
2205 #ifdef HAVE_G729_G723
2206 /* Initialize the G729 and G723 decoders */
2209 #endif /* HAVE_G729_G723 */
2211 if (!rtp_channels) {
2212 rtp_channels = g_malloc(sizeof(rtp_play_channels_t));
2215 reset_rtp_channels();
2218 g_print("Pa_GetHostApiCount() = %d\n", Pa_GetHostApiCount());
2219 g_print("Pa_GetDefaultHostApi() = %d\n", Pa_GetDefaultHostApi());
2221 if ((Pa_GetHostApiCount() >= 0) && (Pa_GetDefaultHostApi() >= 0))
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);
2228 for (i=0; i<(unsigned int)Pa_GetHostApiCount(); i++)
2230 api_info = Pa_GetHostApiInfo( i );
2231 g_print("PaHostApiInfo[%u].type = %d (%s)\n", i, api_info->type, api_info->name);
2234 api_index = Pa_HostApiTypeIdToHostApiIndex( paALSA );
2237 g_print("api_index for paALSA not found (%d)\n", api_index);
2241 api_info = Pa_GetHostApiInfo( (unsigned int)api_index );
2242 g_print("This should be ALSA: %s\n", api_info->name);
2247 /* create the dialog window */
2248 rtp_player_dlg_create();
2252 #endif /* HAVE_LIBPORTAUDIO */