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 in the stream.
32 * - Each new RTP stream will be added to a list of RTP stream, called
34 * - When the user clicks "Player" in the VoipCall dialogue,
35 * rtp_player_init() is called.
36 * - rtp_player_init() create the main dialog, and it calls:
37 * + mark_rtp_stream_to_play() to mark the RTP streams that needs to be
38 * displayed. These are the RTP stream 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 channles. An RTP channel is a
42 * group of RTP stream that have in common the source and destination
43 * IP and UPD ports. The RTP channels is what the user will listen in
44 * one of the two Audio channles.
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 click 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
59 /* TODO: The RTP Player it is only supported for GTK >=2 */
62 #include <epan/stats_tree.h>
63 #include <epan/addr_resolv.h>
67 #include "portaudio.h"
68 #include "simple_dialog.h"
69 #include "gui_utils.h"
70 #include "dlg_utils.h"
71 #include "compat_macros.h"
73 #include "graph_analysis.h"
74 #include "voip_calls_dlg.h"
75 #include "voip_calls.h"
76 #include "gtkglobals.h"
79 #include <epan/dissectors/packet-rtp.h>
80 #include <epan/rtp_pt.h>
81 #include <epan/codecs.h>
83 #include "rtp_player.h"
84 #include "codecs/G711a/G711adecode.h"
85 #include "codecs/G711u/G711udecode.h"
87 #include <epan/prefs.h> /* For prefs.rtp_player_max_visible and RTP_PLAYER_DEFAULT_VISIBLE */
90 #define min(a,b) (((a)<(b))?(a):(b))
93 #define max(a,b) (((a)>(b))?(a):(b))
96 /*define this symbol to compile with G729 and G723 codecs*/
97 /*#define HAVE_G729_G723 1*/
100 #include "codecs/G729/G729decode.h"
101 #include "codecs/G723/G723decode.h"
102 #endif /* HAVE_G729_G723 */
104 static gboolean initialized = FALSE;
106 voip_calls_tapinfo_t *voip_calls = NULL;
108 /* Hash table with all the RTP streams */
109 static GHashTable* rtp_streams_hash = NULL;
111 /* List with all the RTP streams (this is used to decode them as it is sorted)*/
112 static GList* rtp_streams_list = NULL;
115 static GtkWidget *rtp_player_dlg_w;
116 static GtkWidget *channels_vb;
117 static GtkWidget *main_scrolled_window = NULL;
118 static GtkWidget *jitter_spinner;
119 static GtkWidget *bt_decode;
120 static GtkWidget *bt_play;
121 static GtkWidget *bt_pause;
122 static GtkWidget *bt_stop;
123 static GtkWidget *progress_bar;
124 static GtkWidget *info_bar;
125 static GtkWidget *stat_hbox;
127 static guint32 total_packets;
128 static guint32 total_frames;
129 static guint32 progbar_count;
131 static int new_jitter_buff;
133 /* a hash table with the RTP streams to play per audio channel */
134 static GHashTable *rtp_channels_hash = NULL;
136 /* Port Audio staff */
137 #define SAMPLE_RATE (8000)
138 #define NUM_CHANNELS (2)
140 #define PA_SAMPLE_TYPE paInt16
141 typedef gint16 SAMPLE;
142 #define SAMPLE_SILENCE (0)
143 #define FRAMES_PER_BUFFER (512)
145 typedef struct _sample_t {
151 #define S_DROP_BY_JITT 1
152 #define S_WRONG_SEQ 2
154 /* Display channels constants */
156 #define CHANNEL_WIDTH 500
157 #define CHANNEL_HEIGHT 100
158 #define MAX_TIME_LABEL 10
159 #define HEIGHT_TIME_LABEL 18
160 #define MAX_NUM_COL_CONV 10
163 PortAudioStream *pa_stream;
164 #else /* PORTAUDIO_API_1 */
166 #endif /* PORTAUDIO_API_1 */
168 /* defines a RTP stream */
169 typedef struct _rtp_stream_info {
175 guint32 first_frame_number; /* first RTP frame for the stream */
176 double start_time; /* RTP stream start time in ms */
179 GList* rtp_packets_list; /* List of RTP packets in the stream */
184 /* defines the RTP streams to be played in an audio channel */
185 typedef struct _rtp_channel_info {
186 double start_time; /* RTP stream start time in ms */
187 double end_time; /* RTP stream end time in ms */
188 GArray *samples; /* the array with decoded audio */
192 guint32 drop_by_jitter_buff;
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_channles_t;
239 /* The two RTP channles to play */
240 static rtp_play_channles_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);
291 /****************************************************************************/
293 rtp_decoder_value_destroy(gpointer dec_arg)
295 rtp_decoder_t *dec = dec_arg;
298 codec_release(dec->handle, dec->context);
302 /****************************************************************************/
304 set_sensitive_check_bt(gchar *key _U_ , rtp_channel_info_t *rci, guint *stop _U_ )
306 gtk_widget_set_sensitive(rci->check_bt, !(*stop));
309 /****************************************************************************/
311 bt_state(gboolean decode, gboolean play, gboolean pause, gboolean stop)
313 gboolean new_jitter_value = FALSE;
314 gboolean false_val = FALSE;
316 gtk_widget_set_sensitive(bt_decode, decode);
317 gtk_widget_set_sensitive(jitter_spinner, decode);
319 if (new_jitter_buff != (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner)) {
320 new_jitter_value = TRUE;
323 /* set the sensitive state of play only if there is a channel selected */
324 if ( play && (rtp_channels->rci[0] || rtp_channels->rci[1]) && !new_jitter_value) {
325 gtk_widget_set_sensitive(bt_play, TRUE);
327 gtk_widget_set_sensitive(bt_play, FALSE);
330 if (!new_jitter_value) {
331 gtk_widget_set_sensitive(bt_pause, pause);
332 gtk_widget_set_sensitive(bt_stop, stop);
334 /* Set sensitive to the check buttons based on the STOP state */
335 if (rtp_channels_hash)
336 g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &stop);
338 gtk_widget_set_sensitive(bt_pause, FALSE);
339 gtk_widget_set_sensitive(bt_stop, FALSE);
341 if (rtp_channels_hash)
342 g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &false_val);
346 /****************************************************************************/
348 add_rtp_packet(const struct _rtp_info *rtp_info, packet_info *pinfo)
350 rtp_stream_info_t *stream_info = NULL;
351 rtp_packet_t *new_rtp_packet;
352 GString *key_str = NULL;
354 /* create the the streams hash if it doen't exist */
355 if (!rtp_streams_hash)
356 rtp_streams_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_stream_value_destroy);
358 /* Create a hash key to lookup in the RTP streams hash table
359 * uses: src_ip:src_port dst_ip:dst_port ssrc
361 key_str = g_string_new("");
362 g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(pinfo->src)),
363 pinfo->srcport, get_addr_name(&(pinfo->dst)),
364 pinfo->destport, rtp_info->info_sync_src );
366 /* lookup for this rtp packet in the stream hash table*/
367 stream_info = g_hash_table_lookup( rtp_streams_hash, key_str->str);
369 /* if it is not in the hash table, create a new stream */
370 if (stream_info==NULL) {
371 stream_info = g_malloc(sizeof(rtp_stream_info_t));
372 COPY_ADDRESS(&(stream_info->src_addr), &(pinfo->src));
373 stream_info->src_port = pinfo->srcport;
374 COPY_ADDRESS(&(stream_info->dest_addr), &(pinfo->dst));
375 stream_info->dest_port = pinfo->destport;
376 stream_info->ssrc = rtp_info->info_sync_src;
377 stream_info->rtp_packets_list = NULL;
378 stream_info->first_frame_number = pinfo->fd->num;
379 stream_info->start_time = nstime_to_msec(&pinfo->fd->rel_ts);
380 stream_info->call_num = 0;
381 stream_info->play = FALSE;
382 stream_info->num_packets = 0;
384 g_hash_table_insert(rtp_streams_hash, g_strdup(key_str->str), stream_info);
386 /* Add the element to the List too. The List is used to decode the packets because it is sordted */
387 rtp_streams_list = g_list_append(rtp_streams_list, stream_info);
390 /* increment the number of packets in this stream, this is used for the progress bar and statistics*/
391 stream_info->num_packets++;
393 /* Add the RTP packet to the list */
394 new_rtp_packet = g_malloc(sizeof(rtp_packet_t));
395 new_rtp_packet->info = g_malloc(sizeof(struct _rtp_info));
397 memcpy(new_rtp_packet->info, rtp_info, sizeof(struct _rtp_info));
398 new_rtp_packet->arrive_offset = nstime_to_msec(&pinfo->fd->rel_ts) - stream_info->start_time;
399 /* copy the RTP payload to the rtp_packet to be decoded later */
400 if (rtp_info->info_payload_len) {
401 new_rtp_packet->payload_data = g_malloc(rtp_info->info_payload_len);
402 memcpy(new_rtp_packet->payload_data, &(rtp_info->info_data[rtp_info->info_payload_offset]), rtp_info->info_payload_len);
404 new_rtp_packet->payload_data = NULL;
407 stream_info->rtp_packets_list = g_list_append(stream_info->rtp_packets_list, new_rtp_packet);
409 g_string_free(key_str, TRUE);
412 /****************************************************************************/
413 /* Mark the RTP stream to be played. Use the voip_calls graph to see if the
414 * setup_frame is there and then if the associated voip_call is selected.
417 mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
420 graph_analysis_item_t *graph_item;
421 GList* voip_calls_list;
422 voip_calls_info_t *tmp_voip_call;
424 /* Reset the "to be play" value because the user can close and reopen the RTP Player window
425 * and the streams are nor reset in that case
429 /* and associate the RTP stream with a call using the first RTP in the stream*/
430 graph_list = g_list_first(voip_calls->graph_analysis->list);
433 graph_item = graph_list->data;
434 if (rsi->first_frame_number == graph_item->frame_num) {
435 rsi->call_num = graph_item->conv_num;
436 /* if it is in the graph list, then check if the voip_call is selected */
437 voip_calls_list = g_list_first(voip_calls->callsinfo_list);
438 while (voip_calls_list)
440 tmp_voip_call = voip_calls_list->data;
441 if ( (tmp_voip_call->call_num == rsi->call_num) && (tmp_voip_call->selected == TRUE) ) {
443 total_packets += rsi->num_packets;
446 voip_calls_list = g_list_next(voip_calls_list);
450 graph_list = g_list_next(graph_list);
455 /****************************************************************************/
456 /* Decode a RTP packet
457 * Return the number of decoded bytes
460 decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash)
462 unsigned int payload_type;
464 rtp_decoder_t *decoder;
465 SAMPLE *tmp_buff = NULL;
467 int decoded_bytes = 0;
469 if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
473 payload_type = rp->info->info_payload_type;
475 /* Look for registered codecs */
476 decoder = g_hash_table_lookup(decoders_hash, GUINT_TO_POINTER(payload_type));
477 if (!decoder) { /* Put either valid or empty decoder into the hash table */
478 decoder = g_malloc(sizeof(rtp_decoder_t));
479 decoder->handle = NULL;
480 decoder->context = NULL;
481 p = match_strval(payload_type, rtp_payload_type_short_vals);
483 decoder->handle = find_codec(p);
485 decoder->context = codec_init(decoder->handle);
487 g_hash_table_insert(decoders_hash, GUINT_TO_POINTER(payload_type), decoder);
489 if (decoder->handle) { /* Decode with registered codec */
490 tmp_buff_len = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, NULL, NULL);
491 tmp_buff = g_malloc(tmp_buff_len);
492 decoded_bytes = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, tmp_buff, &tmp_buff_len);
493 *out_buff = tmp_buff;
494 return decoded_bytes;
497 /* Try to decode with built-in codec */
499 switch (payload_type) {
501 case PT_PCMU: /* G.711 u-law */
502 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
503 decodeG711u(rp->payload_data, rp->info->info_payload_len,
504 tmp_buff, &decoded_bytes);
507 case PT_PCMA: /* G.711 A-law */
508 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
509 decodeG711a(rp->payload_data, rp->info->info_payload_len,
510 tmp_buff, &decoded_bytes);
513 #ifdef HAVE_G729_G723
514 case PT_G729: /* G.729 */
515 /* G729 8kbps => 64kbps/8kbps = 8 */
516 /* Compensate for possible 2 octet SID frame (G.729B) */
517 tmp_buff = g_malloc(sizeof(SAMPLE) * ((rp->info->info_payload_len + 8) / 10) * 80);
518 decodeG729(rp->payload_data, rp->info->info_payload_len,
519 tmp_buff, &decoded_bytes);
522 case PT_G723: /* G.723 */
523 if (rp->info->info_payload_len%24 == 0) /* G723 High 6.4kbps */
524 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 10); /* G723 High 64kbps/6.4kbps = 10 */
525 else if (rp->info->info_payload_len%20 == 0) /* G723 Low 5.3kbps */
526 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 13); /* G723 High 64kbps/5.3kbps = 13 */
530 decodeG723(rp->payload_data, rp->info->info_payload_len,
531 tmp_buff, &decoded_bytes);
533 #endif /* HAVE_G729_G723 */
537 * XXX - return an error here, so the user gets told that
538 * we don't support this codec!
543 *out_buff = tmp_buff;
544 return decoded_bytes;
547 /****************************************************************************/
549 update_progress_bar(gfloat percentage)
552 gtk_progress_bar_update(GTK_PROGRESS_BAR(progress_bar), percentage);
554 /* Force gtk to redraw the window before starting decoding the packet */
555 while (gtk_events_pending())
556 gtk_main_iteration();
559 /****************************************************************************/
560 /* Decode the RTP streams and add them to the RTP channels struct
563 decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
565 GString *key_str = NULL;
566 rtp_channel_info_t *rci;
567 gboolean first = TRUE;
568 GList* rtp_packets_list;
573 double rtp_time_prev;
575 double arrive_time_prev;
577 double start_rtp_time = 0;
581 double total_time_prev;
582 gint32 silence_frames;
589 int decoded_bytes_prev;
591 SAMPLE *out_buff = NULL;
595 guint32 start_timestamp;
596 GHashTable *decoders_hash = NULL;
598 guint32 progbar_nextstep;
603 silence.status = S_NORMAL;
605 /* skip it if we are not going to play it */
606 if (rsi->play == FALSE) {
610 /* get the static jitter buffer from the spinner gui */
611 jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
613 /* Create a hash key to lookup in the RTP channels hash
614 * uses: src_ip:src_port dst_ip:dst_port call_num
616 key_str = g_string_new("");
617 g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(rsi->src_addr)),
618 rsi->src_port, get_addr_name(&(rsi->dest_addr)),
619 rsi->dest_port, rsi->call_num );
621 /* create the rtp_channels_hash table if it doesn't exist */
622 if (!rtp_channels_hash) {
623 rtp_channels_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_channel_value_destroy);
626 /* lookup for this stream in the channel hash table */
627 rci = g_hash_table_lookup( rtp_channels_hash, key_str->str);
629 /* ..if it is not in the hash, create an entry */
631 rci = g_malloc(sizeof(rtp_channel_info_t));
632 rci->call_num = rsi->call_num;
633 rci->start_time = rsi->start_time;
634 rci->end_time = rsi->start_time;
635 rci->selected = FALSE;
636 rci->frame_index = 0;
637 rci->drop_by_jitter_buff = 0;
639 rci->max_frame_index = 0;
640 rci->samples = g_array_new (FALSE, FALSE, sizeof(sample_t));
641 rci->check_bt = NULL;
642 rci->separator = NULL;
643 rci->draw_area = NULL;
645 rci->h_scrollbar_adjustment = NULL;
646 rci->cursor_pixbuf = NULL;
647 rci->cursor_prev = 0;
648 rci->cursor_catch = FALSE;
649 rci->first_stream = rsi;
650 rci->num_packets = rsi->num_packets;
651 g_hash_table_insert(rtp_channels_hash, g_strdup(key_str->str), rci);
653 /* Add silence between the two streams if needed */
654 silence_frames = (gint32)( ((rsi->start_time - rci->end_time)/1000)*SAMPLE_RATE );
655 for (i = 0; i< silence_frames; i++) {
656 g_array_append_val(rci->samples, silence);
658 rci->num_packets += rsi->num_packets;
661 /* decode the RTP stream */
666 decoded_bytes_prev = 0;
668 arrive_time = start_time = 0;
669 arrive_time_prev = 0;
679 decoders_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, rtp_decoder_value_destroy);
681 /* we update the progress bar 100 times */
683 /* Update the progress bar when it gets to this value. */
684 progbar_nextstep = 0;
685 /* When we reach the value that triggers a progress bar update,
686 bump that value by this amount. */
687 progbar_quantum = total_packets/100;
691 rtp_packets_list = g_list_first(rsi->rtp_packets_list);
692 while (rtp_packets_list)
695 if (progbar_count >= progbar_nextstep) {
696 g_assert(total_packets > 0);
698 progbar_val = (gfloat) progbar_count / total_packets;
700 update_progress_bar(progbar_val);
702 progbar_nextstep += progbar_quantum;
706 rp = rtp_packets_list->data;
708 start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
710 rtp_time_prev = start_rtp_time;
712 seq = rp->info->info_seq_num - 1;
715 decoded_bytes = decode_rtp_packet(rp, &out_buff, decoders_hash);
716 if (decoded_bytes == 0) {
717 seq = rp->info->info_seq_num;
720 rtp_time = (double)(rp->info->info_timestamp-start_timestamp)/SAMPLE_RATE - start_rtp_time;
721 arrive_time = (double)rp->arrive_offset/1000 - start_time;
723 if (rp->info->info_seq_num != seq+1){
725 status = S_WRONG_SEQ;
727 seq = rp->info->info_seq_num;
729 diff = arrive_time - rtp_time;
731 delay = diff - prev_diff;
733 if (delay<0) delay = -delay;
735 if (diff<0) diff = -diff;
737 total_time = (double)rp->arrive_offset/1000;
739 printf("seq = %d arr = %f abs_diff = %f index = %d tim = %f ji=%d jb=%f\n",rp->info->info_seq_num,
740 total_time, diff, rci->samples->len, ((double)rci->samples->len/8000 - total_time)*1000, 0,
741 (mean_delay + 4*variation)*1000);
744 /* if the jitter buffer was exceeded */
745 if ( diff*1000 > jitter_buff ) {
747 printf("Packet drop by jitter buffer exceeded\n");
749 rci->drop_by_jitter_buff++;
750 status = S_DROP_BY_JITT;
752 /* if there was a silence period (more than two packetization period) resync the source */
753 if ( (rtp_time - rtp_time_prev) > pack_period*2 ){
755 printf("Resync...\n");
758 silence_frames = (gint32)((arrive_time - arrive_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
759 for (i = 0; i< silence_frames; i++) {
760 silence.status = status;
761 g_array_append_val(rci->samples, silence);
763 /* only mark the fisrt in the silence that has the previos problem (S_DROP_BY_JITT or S_WRONG_SEQ ) */
767 decoded_bytes_prev = 0;
768 start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
770 start_time = (double)rp->arrive_offset/1000;
774 /* Add silence if it is necessary */
775 silence_frames = (gint32)((rtp_time - rtp_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
776 for (i = 0; i< silence_frames; i++) {
777 silence.status = status;
778 g_array_append_val(rci->samples, silence);
780 /* only mark the fisrt in the silence that has the previos problem (S_DROP_BY_JITT or S_WRONG_SEQ ) */
787 for (i = 0; i< (decoded_bytes/2); i++) {
788 sample.val = out_buff[i];
789 sample.status = status;
790 g_array_append_val(rci->samples, sample);
793 rtp_time_prev = rtp_time;
794 pack_period = (double)(decoded_bytes/2)/SAMPLE_RATE;
795 decoded_bytes_prev = decoded_bytes;
796 arrive_time_prev = arrive_time;
804 rtp_packets_list = g_list_next (rtp_packets_list);
807 rci->max_frame_index = rci->samples->len;
808 rci->end_time = rci->start_time + ((double)rci->samples->len/SAMPLE_RATE)*1000;
810 g_string_free(key_str, TRUE);
811 g_hash_table_destroy(decoders_hash);
814 /****************************************************************************/
816 h_scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
818 rtp_channel_info_t *rci = (rtp_channel_info_t *)user_data;
819 rci->cursor_catch = TRUE;
823 static gboolean draw_cursors(gpointer data);
825 /****************************************************************************/
832 /* we should never be here if we are already in STOP */
833 if(rtp_channels->stop){
837 rtp_channels->stop = TRUE;
838 /* force a draw_cursor to stop it */
841 err = Pa_StopStream(pa_stream);
843 if( err != paNoError ) {
844 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
845 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
846 "Can not Stop Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
847 gtk_dialog_run (GTK_DIALOG (dialog));
848 gtk_widget_destroy (dialog);
852 err = Pa_CloseStream(pa_stream);
853 if( err != paNoError ) {
854 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
855 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
856 "Can not Close Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
857 gtk_dialog_run (GTK_DIALOG (dialog));
858 gtk_widget_destroy (dialog);
861 pa_stream = NULL; /* to catch errors better */
863 rtp_channels->start_index[0] = 0;
864 rtp_channels->start_index[1] = 0;
865 rtp_channels->end_index[0] = 0;
866 rtp_channels->end_index[1] = 0;
867 rtp_channels->max_frame_index = 0;
868 rtp_channels->frame_index = 0;
869 rtp_channels->pause = FALSE;
870 rtp_channels->pause_duration = 0;
871 rtp_channels->stop = TRUE;
872 rtp_channels->out_diff_time = 10000;
874 if (rtp_channels->rci[0]) rtp_channels->rci[0]->frame_index = 0;
875 if (rtp_channels->rci[1]) rtp_channels->rci[1]->frame_index = 0;
877 /* set the sensitive state of the buttons (decode, play, pause, stop) */
878 bt_state(TRUE, TRUE, FALSE, FALSE);
882 /****************************************************************************/
883 /* Draw a cursor in a channel graph
886 draw_channel_cursor(rtp_channel_info_t *rci, guint32 start_index)
890 #else /* PORTAUDIO_API_1 */
892 #endif /* PORTAUDIO_API_1 */
898 index = Pa_StreamTime( pa_stream ) - rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
899 #else /* PORTAUDIO_API_1 */
900 index = ((guint32)(SAMPLE_RATE) * (Pa_GetStreamTime(pa_stream)-rtp_channels->pa_start_time))- rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
901 #endif /* PORTAUDIO_API_1 */
904 /* If we finished playing both channels, then stop them */
905 if ( (rtp_channels && (!rtp_channels->stop) && (!rtp_channels->pause)) && (index > rtp_channels->max_frame_index) ) {
910 /* If only this channel finished, then return */
911 if (index > rci->max_frame_index) {
915 /* draw the previous saved pixbuf line */
916 if (rci->cursor_pixbuf && (rci->cursor_prev>=0)) {
918 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);
920 gdk_draw_drawable(rci->draw_area->window,
921 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
923 (int) (rci->cursor_prev/MULT), 0,
924 (int) (rci->cursor_prev/MULT), 0,
925 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
927 g_object_unref(rci->cursor_pixbuf);
928 rci->cursor_pixbuf = NULL;
931 if (index>0 && (rci->cursor_prev>=0)) {
932 rci->cursor_pixbuf = gdk_pixbuf_get_from_drawable(NULL, rci->pixmap, NULL, (int) (index/MULT), 0, 0, 0, 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
934 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
938 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
940 gdk_draw_drawable(rci->draw_area->window,
941 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
943 (int) (index/MULT), 0,
944 (int) (index/MULT), 0,
945 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
948 /* Disconnect the scroll bar "value" signal to not be called */
949 SIGNAL_DISCONNECT_BY_FUNC(rci->h_scrollbar_adjustment, h_scrollbar_changed, rci);
951 /* Move the horizontal scroll bar */
952 /* if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) &&
953 (index/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
954 for (i=1; i<10; i++) {
955 rci->h_scrollbar_adjustment->value += rci->h_scrollbar_adjustment->page_size/10;
956 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
961 if (!rci->cursor_catch) {
962 if (index/MULT < rci->h_scrollbar_adjustment->page_size/2) {
963 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
964 } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
965 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
967 rci->h_scrollbar_adjustment->value = index/MULT - rci->h_scrollbar_adjustment->page_size/2;
970 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
971 } else if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) &&
972 (index/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
973 rci->cursor_catch = FALSE;
974 for (i=1; i<10; i++) {
975 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));
976 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
982 /* Connect back the "value" scroll signal */
983 SIGNAL_CONNECT(rci->h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, rci);
986 /* if (index/MULT < rci->h_scrollbar_adjustment->page_increment) {
987 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
988 } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size + rci->h_scrollbar_adjustment->page_increment)) {
989 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
991 if ( (index/MULT < rci->h_scrollbar_adjustment->value) || (index/MULT > (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
992 rci->h_scrollbar_adjustment->value = index/MULT;
997 /* if (index/MULT < rci->h_scrollbar_adjustment->page_size/2) {
998 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
999 } else if (index/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
1000 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
1002 rci->h_scrollbar_adjustment->value = index/MULT - rci->h_scrollbar_adjustment->page_size/2;
1005 /* gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
1007 rci->cursor_prev = index;
1010 /****************************************************************************/
1011 /* Move and draw the cursor in the graph
1014 draw_cursors(gpointer data _U_)
1016 if (!rtp_channels) return FALSE;
1018 /* Draw and move each of the two channels */
1019 draw_channel_cursor(rtp_channels->rci[0], rtp_channels->start_index[0]);
1020 draw_channel_cursor(rtp_channels->rci[1], rtp_channels->start_index[1]);
1022 if ((rtp_channels->stop) || (rtp_channels->pause)) return FALSE;
1027 /****************************************************************************/
1029 init_rtp_channels_vals(void)
1031 rtp_play_channles_t *rpci = rtp_channels;
1033 /* if we only have one channel to play, we just use the info from that channel */
1034 if (rpci->rci[0] == NULL) {
1035 rpci->max_frame_index = rpci->rci[1]->max_frame_index;
1036 rpci->start_index[0] = rpci->max_frame_index;
1037 rpci->start_index[1] = 0;
1038 rpci->end_index[0] = rpci->max_frame_index;
1039 rpci->end_index[1] = rpci->max_frame_index;
1040 } else if (rpci->rci[1] == NULL) {
1041 rpci->max_frame_index = rpci->rci[0]->max_frame_index;
1042 rpci->start_index[1] = rpci->max_frame_index;
1043 rpci->start_index[0] = 0;
1044 rpci->end_index[0] = rpci->max_frame_index;
1045 rpci->end_index[1] = rpci->max_frame_index;
1047 /* if the two channels are to be played, then we need to sync both based on the start/end time of each one */
1049 rpci->max_frame_index = (guint32)(SAMPLE_RATE/1000) * (guint32)(max(rpci->rci[0]->end_time, rpci->rci[1]->end_time) -
1050 (guint32)min(rpci->rci[0]->start_time, rpci->rci[1]->start_time));
1052 if (rpci->rci[0]->start_time < rpci->rci[1]->start_time) {
1053 rpci->start_index[0] = 0;
1054 rpci->start_index[1] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->start_time - rpci->rci[0]->start_time);
1056 rpci->start_index[1] = 0;
1057 rpci->start_index[0] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->start_time - rpci->rci[1]->start_time);
1060 if (rpci->rci[0]->end_time < rpci->rci[1]->end_time) {
1061 rpci->end_index[0] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->end_time - rpci->rci[0]->end_time));
1062 rpci->end_index[1] = rpci->max_frame_index;
1064 rpci->end_index[1] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->end_time - rpci->rci[1]->end_time));
1065 rpci->end_index[0] = rpci->max_frame_index;
1071 /****************************************************************************/
1072 /* This routine will be called by the PortAudio engine when audio is needed.
1073 * It may called at interrupt level on some machines so don't do anything
1074 * that could mess up the system like calling malloc() or free().
1078 static int paCallback( void *inputBuffer, void *outputBuffer,
1079 unsigned long framesPerBuffer,
1080 PaTimestamp outTime, void *userData)
1082 #else /* PORTAUDIO_API_1 */
1083 static int paCallback( const void *inputBuffer, void *outputBuffer,
1084 unsigned long framesPerBuffer,
1085 const PaStreamCallbackTimeInfo* outTime,
1086 PaStreamCallbackFlags statusFlags _U_,
1089 #endif /* PORTAUDIO_API_1 */
1090 rtp_play_channles_t *rpci = (rtp_play_channles_t*)userData;
1091 SAMPLE *wptr = (SAMPLE*)outputBuffer;
1095 unsigned int framesLeft;
1098 /* if it is pasued, we keep the stream running but with silence only */
1099 if (rtp_channels->pause) {
1100 for(i=0; i<framesPerBuffer; i++ ) {
1104 rtp_channels->pause_duration += framesPerBuffer;
1109 rpci->out_diff_time = outTime - Pa_StreamTime(pa_stream) ;
1110 #else /* PORTAUDIO_API_1 */
1111 rpci->out_diff_time = (guint32)(SAMPLE_RATE) * (outTime->outputBufferDacTime - Pa_GetStreamTime(pa_stream)) ;
1112 #endif /* PORTAUDIO_API_1 */
1115 /* set the values if this is the first time */
1116 if (rpci->max_frame_index == 0) {
1117 init_rtp_channels_vals();
1121 framesLeft = rpci->max_frame_index - rpci->frame_index;
1123 (void) inputBuffer; /* Prevent unused variable warnings. */
1126 if( framesLeft < framesPerBuffer )
1128 framesToPlay = framesLeft;
1133 framesToPlay = framesPerBuffer;
1137 for( i=0; i<(unsigned int)framesToPlay; i++ )
1139 if (rpci->rci[0] && ( (rpci->frame_index >= rpci->start_index[0]) && (rpci->frame_index <= rpci->end_index[0]) )) {
1140 sample = g_array_index(rpci->rci[0]->samples, sample_t, rpci->rci[0]->frame_index++);
1141 *wptr++ = sample.val;
1146 if (rpci->rci[1] && ( (rpci->frame_index >= rpci->start_index[1]) && (rpci->frame_index <= rpci->end_index[1]) )) {
1147 sample = g_array_index(rpci->rci[1]->samples, sample_t, rpci->rci[1]->frame_index++);
1148 *wptr++ = sample.val;
1153 for( ; i<framesPerBuffer; i++ )
1158 rpci->frame_index += framesToPlay;
1163 /****************************************************************************/
1165 on_bt_check_clicked(GtkButton *button _U_, gpointer user_data _U_)
1167 rtp_channel_info_t *rci = user_data;
1169 if (rci->selected) {
1170 if (rtp_channels->rci[0] == rci) {
1171 rtp_channels->rci[0] = NULL;
1172 rtp_channels->channel = 0;
1174 rtp_channels->rci[1] = NULL;
1175 rtp_channels->channel = 1;
1178 /* if there are already both channels selected, unselect the old one */
1179 if (rtp_channels->rci[rtp_channels->channel]) {
1180 /* we disconnect the signal temporarly to avoid been called back */
1181 SIGNAL_DISCONNECT_BY_FUNC(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1182 gtk_toggle_button_set_active((GtkToggleButton *)rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1183 SIGNAL_CONNECT(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1184 rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1187 rtp_channels->rci[rtp_channels->channel] = rci;
1188 rtp_channels->channel = !(rtp_channels->channel);
1191 rci->selected = !(rci->selected);
1193 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1194 bt_state(TRUE, TRUE, FALSE, FALSE);
1197 /****************************************************************************/
1198 static void channel_draw(rtp_channel_info_t* rci)
1204 PangoLayout *small_layout;
1205 guint32 label_width, label_height;
1206 char label_string[MAX_TIME_LABEL];
1208 guint32 progbar_nextstep;
1209 int progbar_quantum;
1214 GdkColor red_color = {0, 65535, 0, 0};
1216 if (GDK_IS_DRAWABLE(rci->pixmap)) {
1217 /* Clear out old plot */
1218 gdk_draw_rectangle(rci->pixmap,
1219 rci->bg_gc[1+rci->call_num%MAX_NUM_COL_CONV],
1222 rci->draw_area->allocation.width,
1223 rci->draw_area->allocation.height);
1225 small_layout = gtk_widget_create_pango_layout(rci->draw_area, NULL);
1226 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica,Sans,Bold 7"));
1228 /* calculated the pixel offset to display integer seconds */
1229 offset = ((double)rci->start_time/1000 - floor((double)rci->start_time/1000))*SAMPLE_RATE/MULT;
1231 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1233 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1234 rci->draw_area->allocation.width,
1235 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
1237 imax = min(rci->draw_area->allocation.width,(gint)(rci->samples->len/MULT));
1239 /* we update the progress bar 100 times */
1241 /* Update the progress bar when it gets to this value. */
1242 progbar_nextstep = 0;
1243 /* When we reach the value that triggers a progress bar update,
1244 bump that value by this amount. */
1245 progbar_quantum = imax/100;
1247 red_gc = gdk_gc_new(rci->draw_area->window);
1248 gdk_gc_set_rgb_fg_color(red_gc, &red_color);
1250 for (i=0; i< imax; i++) {
1256 if (progbar_count >= progbar_nextstep) {
1257 g_assert(total_frames > 0);
1259 progbar_val = (gfloat) i / imax;
1261 update_progress_bar(progbar_val);
1263 progbar_nextstep += progbar_quantum;
1266 for (j=0; j<MULT; j++) {
1267 sample = g_array_index(rci->samples, sample_t, i*MULT+j);
1268 max = max(max, sample.val);
1269 min = min(min, sample.val);
1270 if (sample.status == S_DROP_BY_JITT) status = S_DROP_BY_JITT;
1273 if (status == S_DROP_BY_JITT) {
1276 gc = rci->draw_area->style->black_gc;
1279 gdk_draw_line(rci->pixmap, gc,
1281 (gint)(( (0x7FFF+min) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF),
1283 (gint)(( (0x7FFF+max) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF));
1285 /*draw the time label and grid */
1286 if ( !((i*MULT)%(SAMPLE_RATE)) ) {
1287 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1289 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1291 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+4);
1293 g_snprintf(label_string, MAX_TIME_LABEL, "%.0f", floor(rci->start_time/1000) + i*MULT/SAMPLE_RATE);
1295 pango_layout_set_text(small_layout, label_string, -1);
1296 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
1297 gdk_draw_layout(rci->pixmap,
1298 rci->draw_area->style->black_gc,
1299 (int) (i - offset - label_width/2),
1300 rci->draw_area->allocation.height - label_height,
1302 /* draw the 1/2 sec grid */
1303 } else if ( !((i*MULT)%(SAMPLE_RATE/2)) ) {
1304 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1306 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1308 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+2);
1317 /****************************************************************************/
1318 static gint expose_event_channels(GtkWidget *widget, GdkEventExpose *event)
1320 rtp_channel_info_t *rci;
1322 rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1327 if (GDK_IS_DRAWABLE(widget->window))
1328 gdk_draw_drawable(widget->window,
1329 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1331 event->area.x, event->area.y,
1332 event->area.x, event->area.y,
1333 event->area.width, event->area.height);
1338 /****************************************************************************/
1340 configure_event_channels(GtkWidget *widget, GdkEventConfigure *event _U_)
1342 rtp_channel_info_t *rci;
1345 /* the first calor is blue to highlight the selected item
1346 * the other collors are the same as in the Voip Graph analysys
1347 * to match the same calls
1349 static GdkColor col[MAX_NUM_COL_CONV+1] = {
1350 {0, 0x00FF, 0x00FF, 0xFFFF},
1351 {0, 0x33FF, 0xFFFF, 0x33FF},
1352 {0, 0x00FF, 0xCCFF, 0xCCFF},
1353 {0, 0x66FF, 0xFFFF, 0xFFFF},
1354 {0, 0x99FF, 0x66FF, 0xFFFF},
1355 {0, 0xFFFF, 0xFFFF, 0x33FF},
1356 {0, 0xCCFF, 0x99FF, 0xFFFF},
1357 {0, 0xCCFF, 0xFFFF, 0x33FF},
1358 {0, 0xFFFF, 0xCCFF, 0xCCFF},
1359 {0, 0xFFFF, 0x99FF, 0x66FF},
1360 {0, 0xFFFF, 0xFFFF, 0x99FF}
1363 rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1369 g_object_unref(rci->pixmap);
1373 rci->pixmap = gdk_pixmap_new(widget->window,
1374 widget->allocation.width,
1375 widget->allocation.height,
1378 if ( GDK_IS_DRAWABLE(rci->pixmap) )
1379 gdk_draw_rectangle(rci->pixmap,
1380 widget->style->white_gc,
1383 widget->allocation.width,
1384 widget->allocation.height);
1386 /* create gcs for the background color of each channel */
1387 for (i=0; i<MAX_NUM_COL_CONV+1; i++){
1388 rci->bg_gc[i]=gdk_gc_new(rci->pixmap);
1389 gdk_gc_set_rgb_fg_color(rci->bg_gc[i], &col[i]);
1397 /****************************************************************************/
1399 button_press_event_channel(GtkWidget *widget, GdkEventButton *event _U_)
1401 rtp_channel_info_t *rci;
1405 rci=(rtp_channel_info_t *)OBJECT_GET_DATA(widget, "rtp_channel_info_t");
1410 if (!rci->selected) {
1412 /* only select a new channels if we are in STOP */
1413 if (!rtp_channels->stop) return 0;
1415 /* if there are already both channels selected, unselect the old one */
1416 if (rtp_channels->rci[rtp_channels->channel]) {
1417 /* we disconnect the signal temporarly to avoid been called back */
1418 SIGNAL_DISCONNECT_BY_FUNC(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1419 gtk_toggle_button_set_active((GtkToggleButton *) rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1420 SIGNAL_CONNECT(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1421 rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1424 /* we disconnect the signal temporarly to avoid been called back */
1425 SIGNAL_DISCONNECT_BY_FUNC(rci->check_bt, on_bt_check_clicked, rci);
1426 gtk_toggle_button_set_active((GtkToggleButton *) rci->check_bt, TRUE);
1427 SIGNAL_CONNECT(rci->check_bt, "clicked", on_bt_check_clicked, rci);
1429 rtp_channels->rci[rtp_channels->channel] = rci;
1430 rtp_channels->channel = !(rtp_channels->channel);
1431 rci->selected = TRUE;
1433 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1434 bt_state(TRUE, TRUE, FALSE, FALSE);
1437 if (rci == rtp_channels->rci[0]) {
1443 rci->frame_index = (unsigned int) (event->x * MULT);
1445 prev_index = rtp_channels->frame_index;
1446 rtp_channels->frame_index = rtp_channels->start_index[this_channel] + rci->frame_index;
1447 rtp_channels->pause_duration += prev_index - rtp_channels->frame_index;
1451 /* change the index in the other channel if selected, according with the index position */
1452 if (rtp_channels->rci[!this_channel]) {
1453 init_rtp_channels_vals();
1455 if (rtp_channels->frame_index < rtp_channels->start_index[!this_channel]) {
1456 rtp_channels->rci[!this_channel]->frame_index = 0;
1457 } else if (rtp_channels->frame_index > rtp_channels->end_index[!this_channel]) {
1458 rtp_channels->rci[!this_channel]->frame_index = rtp_channels->rci[!this_channel]->max_frame_index;
1460 rtp_channels->rci[!this_channel]->frame_index = rtp_channels->frame_index - rtp_channels->start_index[!this_channel];
1463 init_rtp_channels_vals();
1466 rtp_channels->out_diff_time = 0;
1468 rci->cursor_catch = TRUE;
1470 /* redraw the cusrsor */
1476 /****************************************************************************/
1478 add_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, guint *counter _U_ )
1480 GString *label = NULL;
1481 GtkWidget *viewport;
1484 /* create the channel draw area */
1485 rci->draw_area=gtk_drawing_area_new();
1487 rci->scroll_window=gtk_scrolled_window_new(NULL, NULL);
1489 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (rci->scroll_window), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1490 rci->h_scrollbar_adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window));
1493 gtk_widget_set_size_request(rci->draw_area, (gint)(rci->samples->len/MULT), CHANNEL_HEIGHT);
1496 viewport = gtk_viewport_new(rci->h_scrollbar_adjustment, gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window)));
1497 gtk_container_add(GTK_CONTAINER(viewport), rci->draw_area);
1498 gtk_container_add(GTK_CONTAINER(rci->scroll_window), viewport);
1499 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1500 OBJECT_SET_DATA(rci->draw_area, "rtp_channel_info_t", rci);
1501 gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1502 GTK_WIDGET_SET_FLAGS(rci->draw_area, GTK_CAN_FOCUS);
1503 gtk_widget_grab_focus(rci->draw_area);
1505 gtk_box_pack_start(GTK_BOX (channels_vb), rci->scroll_window, FALSE, FALSE, 0);
1507 /* signals needed to handle backing pixmap */
1508 SIGNAL_CONNECT(rci->draw_area, "expose_event", expose_event_channels, NULL);
1509 SIGNAL_CONNECT(rci->draw_area, "configure_event", configure_event_channels, rci);
1510 gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1511 SIGNAL_CONNECT(rci->draw_area, "button_press_event", button_press_event_channel, rci);
1512 SIGNAL_CONNECT(rci->h_scrollbar_adjustment, "value_changed", h_scrollbar_changed, rci);
1515 label = g_string_new("");
1516 g_string_printf(label, "From %s:%d to %s:%d Duration:%.2f Drop by Jitter Buff:%d(%.1f%%) Out of Seq: %d(%.1f%%)", get_addr_name(&(rci->first_stream->src_addr)),
1517 rci->first_stream->src_port, get_addr_name(&(rci->first_stream->dest_addr)), rci->first_stream->dest_port,
1518 (double)rci->samples->len/SAMPLE_RATE, rci->drop_by_jitter_buff, (double)rci->drop_by_jitter_buff * 100 / (double)rci->num_packets
1519 , rci->out_of_seq, (double)rci->out_of_seq * 100 / (double)rci->num_packets);
1521 rci->check_bt = gtk_check_button_new_with_label(label->str);
1522 gtk_box_pack_start(GTK_BOX (channels_vb), rci->check_bt, FALSE, FALSE, 1);
1524 /* Create the Separator if it is not the last one */
1526 if (*counter < g_hash_table_size(rtp_channels_hash)) {
1527 rci->separator = gtk_hseparator_new();
1528 gtk_box_pack_start(GTK_BOX (channels_vb), rci->separator, FALSE, FALSE, 5);
1531 SIGNAL_CONNECT(rci->check_bt, "clicked", on_bt_check_clicked, rci);
1533 g_string_free(label, TRUE);
1536 /****************************************************************************/
1538 count_channel_frames(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
1540 total_frames += rci->samples->len;
1543 /****************************************************************************/
1550 /* we should never be here if we are in PLAY and !PAUSE */
1551 if(!rtp_channels->stop && !rtp_channels->pause){
1555 /* if we are in PAUSE change the sate */
1556 if (rtp_channels->pause) {
1557 rtp_channels->pause = FALSE;
1558 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1559 bt_state(FALSE, FALSE, TRUE, TRUE);
1561 /* if not PAUSE, then start to PLAY */
1564 err = Pa_OpenStream(
1566 paNoDevice, /* default input device */
1568 PA_SAMPLE_TYPE, /* 16 bit Integer input */
1570 Pa_GetDefaultOutputDeviceID(),
1571 NUM_CHANNELS, /* Stereo output */
1572 PA_SAMPLE_TYPE, /* 16 bit Integer output */
1576 0, /* number of buffers, if zero then use default minimum */
1577 paClipOff, /* we won't output out of range samples so don't bother clipping them */
1580 #else /* PORTAUDIO_API_1 */
1581 err = Pa_OpenDefaultStream(
1590 #endif /* PORTAUDIO_API_1 */
1592 if( err != paNoError ) {
1593 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1594 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1595 "Can not Open Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1596 gtk_dialog_run (GTK_DIALOG (dialog));
1597 gtk_widget_destroy (dialog);
1601 err = Pa_StartStream( pa_stream );
1602 if( err != paNoError ) {
1603 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1604 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1605 "Can not Start Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1606 gtk_dialog_run (GTK_DIALOG (dialog));
1607 gtk_widget_destroy (dialog);
1610 #if !PORTAUDIO_API_1
1611 rtp_channels->pa_start_time = Pa_GetStreamTime(pa_stream);
1612 #endif /* PORTAUDIO_API_1 */
1614 rtp_channels->stop = FALSE;
1616 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1617 bt_state(FALSE, FALSE, TRUE, TRUE);
1620 /* Draw the cursor in the graph */
1621 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1625 /****************************************************************************/
1627 pause_channels(void)
1629 rtp_channels->pause = !(rtp_channels->pause);
1631 /* reactivate the cusrosr display if no in pause */
1632 if (!rtp_channels->pause) {
1633 /* Draw the cursor in the graph */
1634 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1637 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1638 bt_state(FALSE, TRUE, FALSE, TRUE);
1641 /****************************************************************************/
1643 reset_rtp_channels(void)
1645 rtp_channels->channel = 0;
1646 rtp_channels->rci[0] = NULL;
1647 rtp_channels->rci[1] = NULL;
1648 rtp_channels->start_index[0] = 0;
1649 rtp_channels->start_index[1] = 0;
1650 rtp_channels->end_index[0] = 0;
1651 rtp_channels->end_index[1] = 0;
1652 rtp_channels->max_frame_index = 0;
1653 rtp_channels->frame_index = 0;
1654 rtp_channels->pause = FALSE;
1655 rtp_channels->pause_duration = 0;
1656 rtp_channels->stop = TRUE;
1657 rtp_channels->out_diff_time = 10000;
1660 /****************************************************************************/
1662 remove_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
1664 g_object_unref(rci->pixmap);
1665 gtk_widget_destroy(rci->draw_area);
1666 gtk_widget_destroy(rci->scroll_window);
1667 gtk_widget_destroy(rci->check_bt);
1669 gtk_widget_destroy(rci->separator);
1672 /****************************************************************************/
1674 reset_channels(void)
1677 if (rtp_channels_hash) {
1678 /* Remove the channels from the main window if there are there */
1679 g_hash_table_foreach( rtp_channels_hash, (GHFunc)remove_channel_to_window, NULL);
1682 /* destroy the rtp channels hash table */
1683 g_hash_table_destroy(rtp_channels_hash);
1684 rtp_channels_hash = NULL;
1688 reset_rtp_channels();
1692 /****************************************************************************/
1694 reset_rtp_player(void)
1696 /* Destroy the rtp channels */
1699 /* destroy the rtp streams hash table */
1700 if (rtp_streams_hash) {
1701 g_hash_table_destroy(rtp_streams_hash);
1702 rtp_streams_hash = NULL;
1705 /* destroy the rtp streams list */
1706 if (rtp_streams_list) {
1707 g_list_free (rtp_streams_list);
1708 rtp_streams_list = NULL;
1713 /****************************************************************************/
1715 decode_streams(void)
1717 guint statusbar_context;
1720 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1721 bt_state(FALSE, FALSE, FALSE, FALSE);
1725 progress_bar = gtk_progress_bar_new();
1726 WIDGET_SET_SIZE(progress_bar, 100, -1);
1727 gtk_box_pack_start(GTK_BOX (stat_hbox), progress_bar, FALSE, FALSE, 2);
1728 gtk_widget_show(progress_bar);
1729 statusbar_context = gtk_statusbar_get_context_id((GtkStatusbar *) info_bar, "main");
1730 gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, " Decoding RTP packets...");
1732 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
1734 /* reset the number of packet to be decoded, this is used for the progress bar */
1736 /* reset the Progress Bar count */
1739 /* Mark the RTP streams to be played using the selected VoipCalls*/
1740 if (rtp_streams_hash)
1741 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_rtp_stream_to_play, NULL);
1743 /* Decode the RTP streams and add them to the RTP channels to be played */
1744 g_list_foreach( rtp_streams_list, (GFunc)decode_rtp_stream, NULL);
1746 /* reset the number of frames to be displayed, this is used for the progress bar */
1748 /* Count the frames in all the RTP channels */
1749 if (rtp_channels_hash)
1750 g_hash_table_foreach( rtp_channels_hash, (GHFunc)count_channel_frames, NULL);
1752 /* reset the Progress Bar count again for the progress of creating the channels view */
1754 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1755 gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, " Creating channels view...");
1757 /* Display the RTP channels in the window */
1759 if (rtp_channels_hash)
1760 g_hash_table_foreach( rtp_channels_hash, (GHFunc)add_channel_to_window, &counter);
1762 /* Resize the main scroll window to display no more than preferred (or default) max channels, scroll bar will be used if needed */
1764 if (prefs.rtp_player_max_visible < 1 || prefs.rtp_player_max_visible > 10)
1765 prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
1767 WIDGET_SET_SIZE(main_scrolled_window, CHANNEL_WIDTH,
1768 min(counter, prefs.rtp_player_max_visible) * (CHANNEL_HEIGHT+60));
1770 gtk_widget_show_all(main_scrolled_window);
1772 gtk_widget_destroy(progress_bar);
1773 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
1774 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1776 /* blank the status label */
1777 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1779 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1780 bt_state(TRUE, FALSE, FALSE, FALSE);
1782 /* get the static jitter buffer from the spinner gui */
1783 new_jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
1787 /****************************************************************************/
1789 on_bt_decode_clicked(GtkButton *button _U_, gpointer user_data _U_)
1794 /****************************************************************************/
1796 on_bt_play_clicked(GtkButton *button _U_, gpointer user_data _U_)
1801 /****************************************************************************/
1803 on_bt_pause_clicked(GtkButton *button _U_, gpointer user_data _U_)
1808 /****************************************************************************/
1810 on_bt_stop_clicked(GtkButton *button _U_, gpointer user_data _U_)
1815 /****************************************************************************/
1817 rtp_player_on_destroy(GtkObject *object _U_, gpointer user_data _U_)
1819 /* Stop the channels if necesary */
1820 if(rtp_channels && (!rtp_channels->stop)){
1824 /* Destroy the rtp channels */
1827 g_free(rtp_channels);
1828 rtp_channels = NULL;
1830 initialized = FALSE;
1832 gtk_widget_destroy(rtp_player_dlg_w);
1833 main_scrolled_window = NULL;
1834 rtp_player_dlg_w = NULL;
1837 /****************************************************************************/
1839 jitter_spinner_value_changed (GtkSpinButton *spinner _U_, gpointer user_data _U_)
1841 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1842 bt_state(TRUE, TRUE, FALSE, FALSE);
1845 /****************************************************************************/
1847 rtp_player_dlg_create(void)
1850 GtkWidget *hbuttonbox;
1851 GtkWidget *h_jitter_buttons_box;
1852 GtkWidget *bt_close;
1853 GtkAdjustment *jitter_spinner_adj;
1855 const gchar *title_name_ptr;
1858 GtkTooltips *tooltips = gtk_tooltips_new();
1860 rtp_player_dlg_w=gtk_window_new(GTK_WINDOW_TOPLEVEL);
1862 title_name_ptr = cf_get_display_name(&cfile);
1863 win_name = g_strdup_printf("%s - VoIP - RTP Player", title_name_ptr);
1864 gtk_window_set_title(GTK_WINDOW(rtp_player_dlg_w), win_name);
1865 gtk_window_set_position(GTK_WINDOW(rtp_player_dlg_w), GTK_WIN_POS_NONE);
1867 gtk_window_set_default_size(GTK_WINDOW(rtp_player_dlg_w), 400, 50);
1869 main_vb = gtk_vbox_new (FALSE, 0);
1870 gtk_container_add(GTK_CONTAINER(rtp_player_dlg_w), main_vb);
1871 gtk_container_set_border_width (GTK_CONTAINER (main_vb), 2);
1873 main_scrolled_window=gtk_scrolled_window_new(NULL, NULL);
1874 gtk_container_set_border_width (GTK_CONTAINER (main_scrolled_window), 4);
1875 WIDGET_SET_SIZE(main_scrolled_window, CHANNEL_WIDTH, 0);
1877 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (main_scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1878 gtk_container_add(GTK_CONTAINER(main_vb), main_scrolled_window);
1880 channels_vb = gtk_vbox_new (FALSE, 0);
1881 gtk_container_set_border_width (GTK_CONTAINER (channels_vb), 2);
1882 gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *) main_scrolled_window, channels_vb);
1884 h_jitter_buttons_box = gtk_hbox_new (FALSE, 0);
1885 gtk_container_set_border_width (GTK_CONTAINER (h_jitter_buttons_box), 10);
1886 gtk_box_pack_start (GTK_BOX(main_vb), h_jitter_buttons_box, FALSE, FALSE, 0);
1887 label = gtk_label_new("Jitter buffer [ms] ");
1888 gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), label, FALSE, FALSE, 0);
1890 jitter_spinner_adj = (GtkAdjustment *) gtk_adjustment_new (50, 0, 500, 5, 10, 10);
1891 jitter_spinner = gtk_spin_button_new (jitter_spinner_adj, 5, 0);
1892 gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), jitter_spinner, FALSE, FALSE, 0);
1893 gtk_tooltips_set_tip (tooltips, jitter_spinner, "The simulated jitter buffer in [ms]", NULL);
1894 SIGNAL_CONNECT(GTK_OBJECT (jitter_spinner_adj), "value_changed", (GtkSignalFunc) jitter_spinner_value_changed, NULL);
1897 hbuttonbox = gtk_hbutton_box_new ();
1898 gtk_box_pack_start (GTK_BOX (h_jitter_buttons_box), hbuttonbox, TRUE, TRUE, 0);
1899 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
1900 gtk_button_box_set_spacing (GTK_BUTTON_BOX (hbuttonbox), 30);
1902 bt_decode = gtk_button_new_with_label("Decode");
1903 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_decode);
1904 SIGNAL_CONNECT(bt_decode, "clicked", on_bt_decode_clicked, NULL);
1905 gtk_tooltips_set_tip (tooltips, bt_decode, "Decode the RTP stream(s)", NULL);
1907 bt_play = gtk_button_new_with_label("Play");
1908 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_play);
1909 SIGNAL_CONNECT(bt_play, "clicked", on_bt_play_clicked, NULL);
1910 gtk_tooltips_set_tip (tooltips, bt_play, "Play the RTP channel(s)", NULL);
1912 bt_pause = gtk_button_new_with_label("Pause");
1913 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_pause);
1914 SIGNAL_CONNECT(bt_pause, "clicked", on_bt_pause_clicked, NULL);
1915 gtk_tooltips_set_tip (tooltips, bt_pause, "Pause the RTP channel(s)", NULL);
1917 bt_stop = gtk_button_new_with_label("Stop");
1918 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_stop);
1919 SIGNAL_CONNECT(bt_stop, "clicked", on_bt_stop_clicked, NULL);
1920 gtk_tooltips_set_tip (tooltips, bt_stop, "Stop the RTP channel(s)", NULL);
1922 bt_close = BUTTON_NEW_FROM_STOCK(GTK_STOCK_CLOSE);
1923 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
1924 GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
1925 gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
1927 SIGNAL_CONNECT(bt_close, "clicked", rtp_player_on_destroy, NULL);
1928 SIGNAL_CONNECT(rtp_player_dlg_w, "destroy", rtp_player_on_destroy, NULL);
1931 hbuttonbox = gtk_hbutton_box_new ();
1933 /* Filter/status hbox */
1934 stat_hbox = gtk_hbox_new(FALSE, 1);
1935 gtk_container_border_width(GTK_CONTAINER(stat_hbox), 0);
1938 info_bar = gtk_statusbar_new();
1939 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
1941 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
1943 /* statusbar hbox */
1944 gtk_box_pack_start(GTK_BOX(main_vb), stat_hbox, FALSE, TRUE, 0);
1946 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1947 bt_state(TRUE, FALSE, FALSE, FALSE);
1949 gtk_widget_show_all(rtp_player_dlg_w);
1951 /* Force gtk to redraw the window before starting decoding the packet */
1952 while (g_main_context_iteration(NULL, FALSE));
1957 /****************************************************************************/
1959 rtp_player_init(voip_calls_tapinfo_t *voip_calls_tap)
1964 if (initialized) return;
1967 voip_calls = voip_calls_tap;
1968 err = Pa_Initialize();
1969 if( err != paNoError ) {
1970 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1971 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1972 "Can not Initialize the PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1973 gtk_dialog_run (GTK_DIALOG (dialog));
1974 gtk_widget_destroy (dialog);
1975 initialized = FALSE;
1979 new_jitter_buff = -1;
1981 #ifdef HAVE_G729_G723
1982 /* Initialize the G729 and G723 decoders */
1985 #endif /* HAVE_G729_G723 */
1987 if (!rtp_channels) {
1988 rtp_channels = g_malloc(sizeof(rtp_play_channles_t));
1991 reset_rtp_channels();
1993 /* create the dialog window */
1994 rtp_player_dlg_create();
1998 #endif /* HAVE_LIBPORTAUDIO */