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 this symbol to compile with G729 and G723 codecs*/
88 /*#define HAVE_G729_G723 1*/
91 #include "codecs/G729/G729decode.h"
92 #include "codecs/G723/G723decode.h"
93 #endif /* HAVE_G729_G723 */
95 static gboolean initialized = FALSE;
97 static voip_calls_tapinfo_t *voip_calls = NULL;
99 /* Hash table with all the RTP streams */
100 static GHashTable* rtp_streams_hash = NULL;
102 /* List with all the RTP streams (this is used to decode them as it is sorted)*/
103 static GList* rtp_streams_list = NULL;
106 static GtkWidget *rtp_player_dlg_w;
107 static GtkWidget *channels_vb;
108 static GtkWidget *main_scrolled_window = NULL;
109 static GtkWidget *jitter_spinner;
110 static GtkWidget *cb_use_rtp_timestamp;
111 static GtkWidget *bt_decode;
112 static GtkWidget *bt_play;
113 static GtkWidget *bt_pause;
114 static GtkWidget *bt_stop;
115 static GtkWidget *progress_bar;
116 static GtkWidget *info_bar;
117 static GtkWidget *stat_hbox;
119 static guint32 total_packets;
120 static guint32 total_frames;
121 static guint32 progbar_count;
123 static int new_jitter_buff;
125 /* a hash table with the RTP streams to play per audio channel */
126 static GHashTable *rtp_channels_hash = NULL;
128 /* Port Audio stuff */
129 #define SAMPLE_RATE (8000)
130 #define NUM_CHANNELS (2)
132 #define PA_SAMPLE_TYPE paInt16
133 typedef gint16 SAMPLE;
134 #define SAMPLE_SILENCE (0)
135 #define FRAMES_PER_BUFFER (512)
137 typedef struct _sample_t {
143 #define S_DROP_BY_JITT 1
144 #define S_WRONG_SEQ 2
145 #define S_WRONG_TIMESTAMP 3 /* The timestamp does not reflect the number of samples - samples have been dropped or silence inserted to match timestamp */
147 /* Display channels constants */
149 #define CHANNEL_WIDTH 500
150 #define CHANNEL_HEIGHT 100
151 #define MAX_TIME_LABEL 10
152 #define HEIGHT_TIME_LABEL 18
153 #define MAX_NUM_COL_CONV 10
156 static PortAudioStream *pa_stream;
157 #else /* PORTAUDIO_API_1 */
158 static PaStream *pa_stream;
159 #endif /* PORTAUDIO_API_1 */
161 /* defines a RTP stream */
162 typedef struct _rtp_stream_info {
168 guint32 first_frame_number; /* first RTP frame for the stream */
169 double start_time; /* RTP stream start time in ms */
172 GList* rtp_packets_list; /* List of RTP packets in the stream */
177 /* defines the RTP streams to be played in an audio channel */
178 typedef struct _rtp_channel_info {
179 double start_time; /* RTP stream start time in ms */
180 double end_time; /* RTP stream end time in ms */
181 GArray *samples; /* the array with decoded audio */
185 guint32 drop_by_jitter_buff;
187 guint32 wrong_timestamp;
188 guint32 max_frame_index;
190 GtkWidget *separator;
191 GtkWidget *scroll_window;
192 GtkWidget *draw_area;
194 GtkAdjustment *h_scrollbar_adjustment;
195 GdkPixbuf* cursor_pixbuf;
197 PaTimestamp cursor_prev;
198 #else /* PORTAUDIO_API_1 */
200 #endif /* PORTAUDIO_API_1 */
201 GdkGC *bg_gc[MAX_NUM_COL_CONV+1];
202 gboolean cursor_catch;
203 rtp_stream_info_t *first_stream; /* This is the first RTP stream in the channel */
205 } rtp_channel_info_t;
207 /* defines a RTP packet */
208 typedef struct _rtp_packet {
209 struct _rtp_info *info; /* the RTP dissected info */
210 double arrive_offset; /* arrive offset time since the begining of the stream in ms */
211 guint8* payload_data;
214 /* defines the two RTP channels to be played */
215 typedef struct _rtp_play_channles {
216 rtp_channel_info_t* rci[2]; /* Channels to be played */
217 guint32 start_index[2];
218 guint32 end_index[2];
220 guint32 max_frame_index;
224 gint32 pause_duration;
226 PaTimestamp out_diff_time;
227 #else /* PORTAUDIO_API_1 */
228 PaTime out_diff_time;
229 PaTime pa_start_time;
230 #endif /* PORTAUDIO_API_1 */
231 } rtp_play_channels_t;
233 /* The two RTP channels to play */
234 static rtp_play_channels_t *rtp_channels = NULL;
236 typedef struct _rtp_decoder_t {
237 codec_handle_t handle;
242 /****************************************************************************/
244 rtp_key_destroy(gpointer key)
250 /****************************************************************************/
252 rtp_channel_value_destroy(gpointer rci_arg)
254 rtp_channel_info_t *rci = rci_arg;
256 g_array_free(rci->samples, TRUE);
261 /****************************************************************************/
263 rtp_stream_value_destroy(gpointer rsi_arg)
265 rtp_stream_info_t *rsi = rsi_arg;
266 GList* rtp_packets_list;
269 rtp_packets_list = g_list_first(rsi->rtp_packets_list);
270 while (rtp_packets_list)
272 rp = rtp_packets_list->data;
275 g_free(rp->payload_data);
279 rtp_packets_list = g_list_next(rtp_packets_list);
281 g_free((void *)(rsi->src_addr.data));
282 g_free((void *)(rsi->dest_addr.data));
287 /****************************************************************************/
289 rtp_decoder_value_destroy(gpointer dec_arg)
291 rtp_decoder_t *dec = dec_arg;
294 codec_release(dec->handle, dec->context);
298 /****************************************************************************/
300 set_sensitive_check_bt(gchar *key _U_ , rtp_channel_info_t *rci, guint *stop _U_ )
302 gtk_widget_set_sensitive(rci->check_bt, !(*stop));
305 /****************************************************************************/
307 bt_state(gboolean decode, gboolean play, gboolean pause, gboolean stop)
309 gboolean new_jitter_value = FALSE;
310 gboolean false_val = FALSE;
312 gtk_widget_set_sensitive(bt_decode, decode);
313 gtk_widget_set_sensitive(cb_use_rtp_timestamp, decode);
314 if (GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp)->active) {
315 gtk_widget_set_sensitive(jitter_spinner, FALSE);
317 gtk_widget_set_sensitive(jitter_spinner, decode);
320 if (new_jitter_buff != (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner)) {
321 new_jitter_value = TRUE;
324 /* set the sensitive state of play only if there is a channel selected */
325 if ( play && (rtp_channels->rci[0] || rtp_channels->rci[1]) && !new_jitter_value) {
326 gtk_widget_set_sensitive(bt_play, TRUE);
328 gtk_widget_set_sensitive(bt_play, FALSE);
331 if (!new_jitter_value) {
332 gtk_widget_set_sensitive(bt_pause, pause);
333 gtk_widget_set_sensitive(bt_stop, stop);
335 /* Set sensitive to the check buttons based on the STOP state */
336 if (rtp_channels_hash)
337 g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &stop);
339 gtk_widget_set_sensitive(bt_pause, FALSE);
340 gtk_widget_set_sensitive(bt_stop, FALSE);
342 if (rtp_channels_hash)
343 g_hash_table_foreach( rtp_channels_hash, (GHFunc)set_sensitive_check_bt, &false_val);
347 /****************************************************************************/
349 add_rtp_packet(const struct _rtp_info *rtp_info, packet_info *pinfo)
351 rtp_stream_info_t *stream_info = NULL;
352 rtp_packet_t *new_rtp_packet;
353 GString *key_str = NULL;
355 /* create the streams hash if it doen't exist */
356 if (!rtp_streams_hash)
357 rtp_streams_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_stream_value_destroy);
359 /* Create a hash key to lookup in the RTP streams hash table
360 * uses: src_ip:src_port dst_ip:dst_port ssrc
362 key_str = g_string_new("");
363 g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(pinfo->src)),
364 pinfo->srcport, get_addr_name(&(pinfo->dst)),
365 pinfo->destport, rtp_info->info_sync_src );
367 /* lookup for this RTP packet in the stream hash table */
368 stream_info = g_hash_table_lookup( rtp_streams_hash, key_str->str);
370 /* if it is not in the hash table, create a new stream */
371 if (stream_info==NULL) {
372 stream_info = g_malloc(sizeof(rtp_stream_info_t));
373 COPY_ADDRESS(&(stream_info->src_addr), &(pinfo->src));
374 stream_info->src_port = pinfo->srcport;
375 COPY_ADDRESS(&(stream_info->dest_addr), &(pinfo->dst));
376 stream_info->dest_port = pinfo->destport;
377 stream_info->ssrc = rtp_info->info_sync_src;
378 stream_info->rtp_packets_list = NULL;
379 stream_info->first_frame_number = pinfo->fd->num;
380 stream_info->start_time = nstime_to_msec(&pinfo->fd->rel_ts);
381 stream_info->call_num = 0;
382 stream_info->play = FALSE;
383 stream_info->num_packets = 0;
385 g_hash_table_insert(rtp_streams_hash, g_strdup(key_str->str), stream_info);
387 /* Add the element to the List too. The List is used to decode the packets because it is sorted */
388 rtp_streams_list = g_list_append(rtp_streams_list, stream_info);
391 /* increment the number of packets in this stream, this is used for the progress bar and statistics */
392 stream_info->num_packets++;
394 /* Add the RTP packet to the list */
395 new_rtp_packet = g_malloc(sizeof(rtp_packet_t));
396 new_rtp_packet->info = g_malloc(sizeof(struct _rtp_info));
398 memcpy(new_rtp_packet->info, rtp_info, sizeof(struct _rtp_info));
399 new_rtp_packet->arrive_offset = nstime_to_msec(&pinfo->fd->rel_ts) - stream_info->start_time;
400 /* copy the RTP payload to the rtp_packet to be decoded later */
401 if (rtp_info->info_payload_len) {
402 new_rtp_packet->payload_data = g_malloc(rtp_info->info_payload_len);
403 memcpy(new_rtp_packet->payload_data, &(rtp_info->info_data[rtp_info->info_payload_offset]), rtp_info->info_payload_len);
405 new_rtp_packet->payload_data = NULL;
408 stream_info->rtp_packets_list = g_list_append(stream_info->rtp_packets_list, new_rtp_packet);
410 g_string_free(key_str, TRUE);
413 /****************************************************************************/
414 /* Mark the RTP stream to be played. Use the voip_calls graph to see if the
415 * setup_frame is there and then if the associated voip_call is selected.
418 mark_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
421 graph_analysis_item_t *graph_item;
422 GList* voip_calls_list;
423 voip_calls_info_t *tmp_voip_call;
425 /* Reset the "to be play" value because the user can close and reopen the RTP Player window
426 * and the streams are not reset in that case
430 /* and associate the RTP stream with a call using the first RTP packet in the stream */
431 graph_list = g_list_first(voip_calls->graph_analysis->list);
434 graph_item = graph_list->data;
435 if (rsi->first_frame_number == graph_item->frame_num) {
436 rsi->call_num = graph_item->conv_num;
437 /* if it is in the graph list, then check if the voip_call is selected */
438 voip_calls_list = g_list_first(voip_calls->callsinfo_list);
439 while (voip_calls_list)
441 tmp_voip_call = voip_calls_list->data;
442 if ( (tmp_voip_call->call_num == rsi->call_num) && (tmp_voip_call->selected == TRUE) ) {
444 total_packets += rsi->num_packets;
447 voip_calls_list = g_list_next(voip_calls_list);
451 graph_list = g_list_next(graph_list);
455 /****************************************************************************/
456 /* Mark the ALL RTP stream to be played. This is called when calling the
457 * RTP player from the "RTP Analysis" window
460 mark_all_rtp_stream_to_play(gchar *key _U_ , rtp_stream_info_t *rsi, gpointer ptr _U_)
463 total_packets += rsi->num_packets;
466 /****************************************************************************/
467 /* Decode a RTP packet
468 * Return the number of decoded bytes
471 decode_rtp_packet(rtp_packet_t *rp, SAMPLE **out_buff, GHashTable *decoders_hash)
473 unsigned int payload_type;
475 rtp_decoder_t *decoder;
476 SAMPLE *tmp_buff = NULL;
478 int decoded_bytes = 0;
480 if ((rp->payload_data == NULL) || (rp->info->info_payload_len == 0) ) {
484 payload_type = rp->info->info_payload_type;
486 /* Look for registered codecs */
487 decoder = g_hash_table_lookup(decoders_hash, GUINT_TO_POINTER(payload_type));
488 if (!decoder) { /* Put either valid or empty decoder into the hash table */
489 decoder = g_malloc(sizeof(rtp_decoder_t));
490 decoder->handle = NULL;
491 decoder->context = NULL;
492 p = match_strval(payload_type, rtp_payload_type_short_vals);
494 decoder->handle = find_codec(p);
496 decoder->context = codec_init(decoder->handle);
498 g_hash_table_insert(decoders_hash, GUINT_TO_POINTER(payload_type), decoder);
500 if (decoder->handle) { /* Decode with registered codec */
501 tmp_buff_len = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, NULL, NULL);
502 tmp_buff = g_malloc(tmp_buff_len);
503 decoded_bytes = codec_decode(decoder->handle, decoder->context, rp->payload_data, rp->info->info_payload_len, tmp_buff, &tmp_buff_len);
504 *out_buff = tmp_buff;
505 return decoded_bytes;
508 /* Try to decode with built-in codec */
510 switch (payload_type) {
512 case PT_PCMU: /* G.711 u-law */
513 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
514 decodeG711u(rp->payload_data, rp->info->info_payload_len,
515 tmp_buff, &decoded_bytes);
518 case PT_PCMA: /* G.711 A-law */
519 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 1);
520 decodeG711a(rp->payload_data, rp->info->info_payload_len,
521 tmp_buff, &decoded_bytes);
524 #ifdef HAVE_G729_G723
525 case PT_G729: /* G.729 */
526 /* G729 8kbps => 64kbps/8kbps = 8 */
527 /* Compensate for possible 2 octet SID frame (G.729B) */
528 tmp_buff = g_malloc(sizeof(SAMPLE) * ((rp->info->info_payload_len + 8) / 10) * 80);
529 decodeG729(rp->payload_data, rp->info->info_payload_len,
530 tmp_buff, &decoded_bytes);
533 case PT_G723: /* G.723 */
534 if (rp->info->info_payload_len%24 == 0) /* G723 High 6.4kbps */
535 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 10); /* G723 High 64kbps/6.4kbps = 10 */
536 else if (rp->info->info_payload_len%20 == 0) /* G723 Low 5.3kbps */
537 tmp_buff = g_malloc(sizeof(SAMPLE) * rp->info->info_payload_len * 13); /* G723 High 64kbps/5.3kbps = 13 */
541 decodeG723(rp->payload_data, rp->info->info_payload_len,
542 tmp_buff, &decoded_bytes);
544 #endif /* HAVE_G729_G723 */
548 * XXX - return an error here, so the user gets told that
549 * we don't support this codec!
554 *out_buff = tmp_buff;
555 return decoded_bytes;
558 /****************************************************************************/
560 update_progress_bar(gfloat fraction)
563 if GTK_IS_PROGRESS_BAR(progress_bar)
564 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress_bar), fraction);
566 /* Force gtk to redraw the window before starting decoding the packet */
567 while (gtk_events_pending())
568 gtk_main_iteration();
571 /****************************************************************************/
572 /* Decode the RTP streams and add them to the RTP channels struct
575 decode_rtp_stream(rtp_stream_info_t *rsi, gpointer ptr _U_)
577 GString *key_str = NULL;
578 rtp_channel_info_t *rci;
579 gboolean first = TRUE;
580 GList* rtp_packets_list;
585 double rtp_time_prev;
587 double arrive_time_prev;
589 double start_rtp_time = 0;
593 double total_time_prev;
594 gint32 silence_frames;
601 int decoded_bytes_prev;
603 SAMPLE *out_buff = NULL;
607 guint32 start_timestamp;
608 GHashTable *decoders_hash = NULL;
610 guint32 progbar_nextstep;
615 silence.status = S_NORMAL;
617 /* skip it if we are not going to play it */
618 if (rsi->play == FALSE) {
622 /* get the static jitter buffer from the spinner gui */
623 jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
625 /* Create a hash key to lookup in the RTP channels hash
626 * uses: src_ip:src_port dst_ip:dst_port call_num
628 key_str = g_string_new("");
629 g_string_printf(key_str, "%s:%d %s:%d %d", get_addr_name(&(rsi->src_addr)),
630 rsi->src_port, get_addr_name(&(rsi->dest_addr)),
631 rsi->dest_port, rsi->call_num );
633 /* create the rtp_channels_hash table if it doesn't exist */
634 if (!rtp_channels_hash) {
635 rtp_channels_hash = g_hash_table_new_full( g_str_hash, g_str_equal, rtp_key_destroy, rtp_channel_value_destroy);
638 /* lookup for this stream in the channel hash table */
639 rci = g_hash_table_lookup( rtp_channels_hash, key_str->str);
641 /* ..if it is not in the hash, create an entry */
643 rci = g_malloc(sizeof(rtp_channel_info_t));
644 rci->call_num = rsi->call_num;
645 rci->start_time = rsi->start_time;
646 rci->end_time = rsi->start_time;
647 rci->selected = FALSE;
648 rci->frame_index = 0;
649 rci->drop_by_jitter_buff = 0;
651 rci->wrong_timestamp = 0;
652 rci->max_frame_index = 0;
653 rci->samples = g_array_new (FALSE, FALSE, sizeof(sample_t));
654 rci->check_bt = NULL;
655 rci->separator = NULL;
656 rci->draw_area = NULL;
658 rci->h_scrollbar_adjustment = NULL;
659 rci->cursor_pixbuf = NULL;
660 rci->cursor_prev = 0;
661 rci->cursor_catch = FALSE;
662 rci->first_stream = rsi;
663 rci->num_packets = rsi->num_packets;
664 g_hash_table_insert(rtp_channels_hash, g_strdup(key_str->str), rci);
666 /* Add silence between the two streams if needed */
667 silence_frames = (gint32)( ((rsi->start_time - rci->end_time)/1000)*SAMPLE_RATE );
668 for (i = 0; i< silence_frames; i++) {
669 g_array_append_val(rci->samples, silence);
671 rci->num_packets += rsi->num_packets;
674 /* decode the RTP stream */
679 decoded_bytes_prev = 0;
681 arrive_time = start_time = 0;
682 arrive_time_prev = 0;
692 decoders_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, rtp_decoder_value_destroy);
694 /* we update the progress bar 100 times */
696 /* Update the progress bar when it gets to this value. */
697 progbar_nextstep = 0;
698 /* When we reach the value that triggers a progress bar update,
699 bump that value by this amount. */
700 progbar_quantum = total_packets/100;
704 rtp_packets_list = g_list_first(rsi->rtp_packets_list);
705 while (rtp_packets_list)
708 if (progbar_count >= progbar_nextstep) {
709 g_assert(total_packets > 0);
711 progbar_val = (gfloat) progbar_count / total_packets;
713 update_progress_bar(progbar_val);
715 progbar_nextstep += progbar_quantum;
719 rp = rtp_packets_list->data;
721 start_timestamp = rp->info->info_timestamp; /* defined start_timestmp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
723 rtp_time_prev = start_rtp_time;
725 seq = rp->info->info_seq_num - 1;
728 decoded_bytes = decode_rtp_packet(rp, &out_buff, decoders_hash);
729 if (decoded_bytes == 0) {
730 seq = rp->info->info_seq_num;
733 rtp_time = (double)(rp->info->info_timestamp-start_timestamp)/SAMPLE_RATE - start_rtp_time;
735 if (GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp)->active) {
736 arrive_time = rtp_time;
738 arrive_time = (double)rp->arrive_offset/1000 - start_time;
741 if (rp->info->info_seq_num != seq+1){
743 status = S_WRONG_SEQ;
745 seq = rp->info->info_seq_num;
747 diff = arrive_time - rtp_time;
749 delay = diff - prev_diff;
751 if (delay<0) delay = -delay;
753 if (diff<0) diff = -diff;
755 total_time = (double)rp->arrive_offset/1000;
757 printf("seq = %d arr = %f abs_diff = %f index = %d tim = %f ji=%d jb=%f\n",rp->info->info_seq_num,
758 total_time, diff, rci->samples->len, ((double)rci->samples->len/8000 - total_time)*1000, 0,
759 (mean_delay + 4*variation)*1000);
762 /* if the jitter buffer was exceeded */
763 if ( diff*1000 > jitter_buff ) {
765 printf("Packet drop by jitter buffer exceeded\n");
767 rci->drop_by_jitter_buff++;
768 status = S_DROP_BY_JITT;
770 /* if there was a silence period (more than two packetization period) resync the source */
771 if ( (rtp_time - rtp_time_prev) > pack_period*2 ){
773 printf("Resync...\n");
775 silence_frames = (gint32)((arrive_time - arrive_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
777 /* Fix for bug 4119: don't insert more than 1000 silence frames.
778 * XXX - is there a better thing to do here?
780 if (silence_frames > 1000)
781 silence_frames = 1000;
783 for (i = 0; i< silence_frames; i++) {
784 silence.status = status;
785 g_array_append_val(rci->samples, silence);
787 /* only mark the first in the silence that has the previous problem (S_DROP_BY_JITT or S_WRONG_SEQ) */
791 decoded_bytes_prev = 0;
792 start_timestamp = rp->info->info_timestamp; /* defined start_timestamp to avoid overflow in timestamp. TODO: handle the timestamp correctly */
794 start_time = (double)rp->arrive_offset/1000;
798 /* Add silence if it is necessary */
799 silence_frames = (gint32)((rtp_time - rtp_time_prev)*SAMPLE_RATE - decoded_bytes_prev/2);
800 if (silence_frames != 0) {
801 rci->wrong_timestamp++;
802 status = S_WRONG_TIMESTAMP;
805 /* Fix for bug 4119: don't insert more than 1000 silence frames.
806 * XXX - is there a better thing to do here?
808 if (silence_frames > 1000)
809 silence_frames = 1000;
811 for (i = 0; i< silence_frames; i++) {
812 silence.status = status;
813 g_array_append_val(rci->samples, silence);
815 /* only mark the first in the silence that has the previous problem (S_DROP_BY_JITT or S_WRONG_SEQ) */
820 if (silence_frames > 0) {
824 for (i = - silence_frames; i< (decoded_bytes/2); i++) {
825 sample.val = out_buff[i];
826 sample.status = status;
827 g_array_append_val(rci->samples, sample);
831 rtp_time_prev = rtp_time;
832 pack_period = (double)(decoded_bytes/2)/SAMPLE_RATE;
833 decoded_bytes_prev = decoded_bytes;
834 arrive_time_prev = arrive_time;
841 rtp_packets_list = g_list_next (rtp_packets_list);
844 rci->max_frame_index = rci->samples->len;
845 rci->end_time = rci->start_time + ((double)rci->samples->len/SAMPLE_RATE)*1000;
847 g_string_free(key_str, TRUE);
848 g_hash_table_destroy(decoders_hash);
851 /****************************************************************************/
853 h_scrollbar_changed(GtkWidget *widget _U_, gpointer user_data)
855 rtp_channel_info_t *rci = (rtp_channel_info_t *)user_data;
856 rci->cursor_catch = TRUE;
860 static gboolean draw_cursors(gpointer data);
862 /****************************************************************************/
869 /* we should never be here if we are already in STOP */
870 if(rtp_channels->stop){
874 rtp_channels->stop = TRUE;
875 /* force a draw_cursor to stop it */
878 err = Pa_StopStream(pa_stream);
880 if( err != paNoError ) {
881 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
882 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
883 "Can not Stop Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
884 gtk_dialog_run (GTK_DIALOG (dialog));
885 gtk_widget_destroy (dialog);
889 err = Pa_CloseStream(pa_stream);
890 if( err != paNoError ) {
891 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
892 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
893 "Can not Close Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
894 gtk_dialog_run (GTK_DIALOG (dialog));
895 gtk_widget_destroy (dialog);
898 pa_stream = NULL; /* to catch errors better */
900 rtp_channels->start_index[0] = 0;
901 rtp_channels->start_index[1] = 0;
902 rtp_channels->end_index[0] = 0;
903 rtp_channels->end_index[1] = 0;
904 rtp_channels->max_frame_index = 0;
905 rtp_channels->frame_index = 0;
906 rtp_channels->pause = FALSE;
907 rtp_channels->pause_duration = 0;
908 rtp_channels->stop = TRUE;
909 rtp_channels->out_diff_time = 10000;
911 if (rtp_channels->rci[0]) rtp_channels->rci[0]->frame_index = 0;
912 if (rtp_channels->rci[1]) rtp_channels->rci[1]->frame_index = 0;
914 /* set the sensitive state of the buttons (decode, play, pause, stop) */
915 bt_state(TRUE, TRUE, FALSE, FALSE);
919 /****************************************************************************/
920 /* Draw a cursor in a channel graph
923 draw_channel_cursor(rtp_channel_info_t *rci, guint32 start_index)
927 #else /* PORTAUDIO_API_1 */
929 #endif /* PORTAUDIO_API_1 */
935 idx = Pa_StreamTime( pa_stream ) - rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
936 #else /* PORTAUDIO_API_1 */
937 idx = ((guint32)(SAMPLE_RATE) * (Pa_GetStreamTime(pa_stream)-rtp_channels->pa_start_time))- rtp_channels->pause_duration - rtp_channels->out_diff_time - start_index;
938 #endif /* PORTAUDIO_API_1 */
941 /* If we finished playing both channels, then stop them */
942 if ( (rtp_channels && (!rtp_channels->stop) && (!rtp_channels->pause)) && (idx > rtp_channels->max_frame_index) ) {
947 /* If only this channel finished, then return */
948 if (idx > rci->max_frame_index) {
952 /* draw the previous saved pixbuf line */
953 if (rci->cursor_pixbuf && (rci->cursor_prev>=0)) {
955 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);
957 gdk_draw_drawable(rci->draw_area->window,
958 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
960 (int) (rci->cursor_prev/MULT), 0,
961 (int) (rci->cursor_prev/MULT), 0,
962 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
964 g_object_unref(rci->cursor_pixbuf);
965 rci->cursor_pixbuf = NULL;
968 if (idx>0 && (rci->cursor_prev>=0)) {
969 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);
971 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
975 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
977 gdk_draw_drawable(rci->draw_area->window,
978 rci->draw_area->style->fg_gc[GTK_WIDGET_STATE(rci->draw_area)],
982 1, rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
985 /* Disconnect the scroll bar "value" signal to not be called */
986 g_signal_handlers_disconnect_by_func(rci->h_scrollbar_adjustment, h_scrollbar_changed, rci);
988 /* Move the horizontal scroll bar */
990 if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) &&
991 (idx/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
992 for (i=1; i<10; i++) {
993 rci->h_scrollbar_adjustment->value += rci->h_scrollbar_adjustment->page_size/10;
994 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
998 if (!rci->cursor_catch) {
999 if (idx/MULT < rci->h_scrollbar_adjustment->page_size/2) {
1000 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
1001 } else if (idx/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
1002 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
1004 rci->h_scrollbar_adjustment->value = idx/MULT - rci->h_scrollbar_adjustment->page_size/2;
1007 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
1008 } else if ( (rci->cursor_prev/MULT < (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) &&
1009 (idx/MULT >= (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
1010 rci->cursor_catch = FALSE;
1011 for (i=1; i<10; i++) {
1012 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));
1013 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
1019 /* Connect back the "value" scroll signal */
1020 g_signal_connect(rci->h_scrollbar_adjustment, "value_changed", G_CALLBACK(h_scrollbar_changed), rci);
1023 if (idx/MULT < rci->h_scrollbar_adjustment->page_increment) {
1024 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
1025 } else if (idx/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size + rci->h_scrollbar_adjustment->page_increment)) {
1026 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
1028 if ( (idx/MULT < rci->h_scrollbar_adjustment->value) || (idx/MULT > (rci->h_scrollbar_adjustment->value+rci->h_scrollbar_adjustment->page_increment)) ){
1029 rci->h_scrollbar_adjustment->value = idx/MULT;
1035 if (idx/MULT < rci->h_scrollbar_adjustment->page_size/2) {
1036 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->lower;
1037 } else if (idx/MULT > (rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size/2)) {
1038 rci->h_scrollbar_adjustment->value = rci->h_scrollbar_adjustment->upper - rci->h_scrollbar_adjustment->page_size;
1040 rci->h_scrollbar_adjustment->value = idx/MULT - rci->h_scrollbar_adjustment->page_size/2;
1045 gtk_adjustment_value_changed(rci->h_scrollbar_adjustment);
1047 rci->cursor_prev = idx;
1050 /****************************************************************************/
1051 /* Move and draw the cursor in the graph
1054 draw_cursors(gpointer data _U_)
1056 if (!rtp_channels) return FALSE;
1058 /* Draw and move each of the two channels */
1059 draw_channel_cursor(rtp_channels->rci[0], rtp_channels->start_index[0]);
1060 draw_channel_cursor(rtp_channels->rci[1], rtp_channels->start_index[1]);
1062 if ((rtp_channels->stop) || (rtp_channels->pause)) return FALSE;
1067 /****************************************************************************/
1069 init_rtp_channels_vals(void)
1071 rtp_play_channels_t *rpci = rtp_channels;
1073 /* if we only have one channel to play, we just use the info from that channel */
1074 if (rpci->rci[0] == NULL) {
1075 rpci->max_frame_index = rpci->rci[1]->max_frame_index;
1076 rpci->start_index[0] = rpci->max_frame_index;
1077 rpci->start_index[1] = 0;
1078 rpci->end_index[0] = rpci->max_frame_index;
1079 rpci->end_index[1] = rpci->max_frame_index;
1080 } else if (rpci->rci[1] == NULL) {
1081 rpci->max_frame_index = rpci->rci[0]->max_frame_index;
1082 rpci->start_index[1] = rpci->max_frame_index;
1083 rpci->start_index[0] = 0;
1084 rpci->end_index[0] = rpci->max_frame_index;
1085 rpci->end_index[1] = rpci->max_frame_index;
1087 /* if the two channels are to be played, then we need to sync both based on the start/end time of each one */
1089 rpci->max_frame_index = (guint32)(SAMPLE_RATE/1000) * (guint32)(MAX(rpci->rci[0]->end_time, rpci->rci[1]->end_time) -
1090 (guint32)MIN(rpci->rci[0]->start_time, rpci->rci[1]->start_time));
1092 if (rpci->rci[0]->start_time < rpci->rci[1]->start_time) {
1093 rpci->start_index[0] = 0;
1094 rpci->start_index[1] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->start_time - rpci->rci[0]->start_time);
1096 rpci->start_index[1] = 0;
1097 rpci->start_index[0] = (guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->start_time - rpci->rci[1]->start_time);
1100 if (rpci->rci[0]->end_time < rpci->rci[1]->end_time) {
1101 rpci->end_index[0] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[1]->end_time - rpci->rci[0]->end_time));
1102 rpci->end_index[1] = rpci->max_frame_index;
1104 rpci->end_index[1] = rpci->max_frame_index - ((guint32)(SAMPLE_RATE/1000) * (guint32)(rpci->rci[0]->end_time - rpci->rci[1]->end_time));
1105 rpci->end_index[0] = rpci->max_frame_index;
1111 /****************************************************************************/
1112 /* This routine will be called by the PortAudio engine when audio is needed.
1113 * It may called at interrupt level on some machines so don't do anything
1114 * that could mess up the system like calling malloc() or free().
1118 static int paCallback( void *inputBuffer, void *outputBuffer,
1119 unsigned long framesPerBuffer,
1120 PaTimestamp outTime, void *userData)
1122 #else /* PORTAUDIO_API_1 */
1123 static int paCallback( const void *inputBuffer, void *outputBuffer,
1124 unsigned long framesPerBuffer,
1125 const PaStreamCallbackTimeInfo* outTime,
1126 PaStreamCallbackFlags statusFlags _U_,
1129 #endif /* PORTAUDIO_API_1 */
1130 rtp_play_channels_t *rpci = (rtp_play_channels_t *)userData;
1131 SAMPLE *wptr = (SAMPLE*)outputBuffer;
1135 unsigned int framesLeft;
1138 /* if it is pasued, we keep the stream running but with silence only */
1139 if (rtp_channels->pause) {
1140 for(i=0; i<framesPerBuffer; i++ ) {
1144 rtp_channels->pause_duration += framesPerBuffer;
1149 rpci->out_diff_time = outTime - Pa_StreamTime(pa_stream) ;
1150 #else /* PORTAUDIO_API_1 */
1151 rpci->out_diff_time = (guint32)(SAMPLE_RATE) * (outTime->outputBufferDacTime - Pa_GetStreamTime(pa_stream)) ;
1152 #endif /* PORTAUDIO_API_1 */
1155 /* set the values if this is the first time */
1156 if (rpci->max_frame_index == 0) {
1157 init_rtp_channels_vals();
1161 framesLeft = rpci->max_frame_index - rpci->frame_index;
1163 (void) inputBuffer; /* Prevent unused variable warnings. */
1166 if( framesLeft < framesPerBuffer )
1168 framesToPlay = framesLeft;
1173 framesToPlay = framesPerBuffer;
1177 for( i=0; i<(unsigned int)framesToPlay; i++ )
1179 if (rpci->rci[0] && ( (rpci->frame_index >= rpci->start_index[0]) && (rpci->frame_index <= rpci->end_index[0]) )) {
1180 sample = g_array_index(rpci->rci[0]->samples, sample_t, rpci->rci[0]->frame_index++);
1181 *wptr++ = sample.val;
1186 if (rpci->rci[1] && ( (rpci->frame_index >= rpci->start_index[1]) && (rpci->frame_index <= rpci->end_index[1]) )) {
1187 sample = g_array_index(rpci->rci[1]->samples, sample_t, rpci->rci[1]->frame_index++);
1188 *wptr++ = sample.val;
1193 for( ; i<framesPerBuffer; i++ )
1198 rpci->frame_index += framesToPlay;
1203 /****************************************************************************/
1205 on_bt_check_clicked(GtkButton *button _U_, gpointer user_data _U_)
1207 rtp_channel_info_t *rci = user_data;
1209 if (rci->selected) {
1210 if (rtp_channels->rci[0] == rci) {
1211 rtp_channels->rci[0] = NULL;
1212 rtp_channels->channel = 0;
1214 rtp_channels->rci[1] = NULL;
1215 rtp_channels->channel = 1;
1218 /* if there are already both channels selected, unselect the old one */
1219 if (rtp_channels->rci[rtp_channels->channel]) {
1220 /* we disconnect the signal temporarly to avoid been called back */
1221 g_signal_handlers_disconnect_by_func(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1222 gtk_toggle_button_set_active((GtkToggleButton *)rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1223 g_signal_connect(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", G_CALLBACK(on_bt_check_clicked), rtp_channels->rci[rtp_channels->channel]);
1224 rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1227 rtp_channels->rci[rtp_channels->channel] = rci;
1228 rtp_channels->channel = !(rtp_channels->channel);
1231 rci->selected = !(rci->selected);
1233 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1234 bt_state(TRUE, TRUE, FALSE, FALSE);
1237 /****************************************************************************/
1238 static void channel_draw(rtp_channel_info_t* rci)
1244 PangoLayout *small_layout;
1245 guint32 label_width, label_height;
1246 char label_string[MAX_TIME_LABEL];
1248 guint32 progbar_nextstep;
1249 int progbar_quantum;
1255 GdkColor red_color = {0, 65535, 0, 0};
1256 GdkColor amber_color = {0, 65535, 49152, 0};
1258 if (GDK_IS_DRAWABLE(rci->pixmap)) {
1259 /* Clear out old plot */
1260 gdk_draw_rectangle(rci->pixmap,
1261 rci->bg_gc[1+rci->call_num%MAX_NUM_COL_CONV],
1264 rci->draw_area->allocation.width,
1265 rci->draw_area->allocation.height);
1267 small_layout = gtk_widget_create_pango_layout(rci->draw_area, NULL);
1268 pango_layout_set_font_description(small_layout, pango_font_description_from_string("Helvetica,Sans,Bold 7"));
1270 /* calculated the pixel offset to display integer seconds */
1271 offset = ((double)rci->start_time/1000 - floor((double)rci->start_time/1000))*SAMPLE_RATE/MULT;
1273 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1275 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1276 rci->draw_area->allocation.width,
1277 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL);
1279 imax = MIN(rci->draw_area->allocation.width,(gint)(rci->samples->len/MULT));
1281 /* we update the progress bar 100 times */
1283 /* Update the progress bar when it gets to this value. */
1284 progbar_nextstep = 0;
1285 /* When we reach the value that triggers a progress bar update,
1286 bump that value by this amount. */
1287 progbar_quantum = imax/100;
1289 red_gc = gdk_gc_new(rci->draw_area->window);
1290 gdk_gc_set_rgb_fg_color(red_gc, &red_color);
1291 amber_gc = gdk_gc_new(rci->draw_area->window);
1292 gdk_gc_set_rgb_fg_color(amber_gc, &amber_color);
1294 for (i=0; i< imax; i++) {
1300 if (progbar_count >= progbar_nextstep) {
1301 g_assert(total_frames > 0);
1303 progbar_val = (gfloat) i / imax;
1305 update_progress_bar(progbar_val);
1307 progbar_nextstep += progbar_quantum;
1310 for (j=0; j<MULT; j++) {
1311 sample = g_array_index(rci->samples, sample_t, i*MULT+j);
1312 max = MAX(max, sample.val);
1313 min = MIN(min, sample.val);
1314 if (sample.status == S_DROP_BY_JITT) status = S_DROP_BY_JITT;
1315 if (sample.status == S_WRONG_TIMESTAMP) status = S_WRONG_TIMESTAMP;
1318 if (status == S_DROP_BY_JITT) {
1320 } else if (status == S_WRONG_TIMESTAMP) {
1323 gc = rci->draw_area->style->black_gc;
1326 gdk_draw_line(rci->pixmap, gc,
1328 (gint)(( (0x7FFF+min) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF),
1330 (gint)(( (0x7FFF+max) * (rci->draw_area->allocation.height-HEIGHT_TIME_LABEL))/0xFFFF));
1332 /*draw the time label and grid */
1333 if ( !((i*MULT)%(SAMPLE_RATE)) ) {
1334 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1336 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1338 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+4);
1340 g_snprintf(label_string, MAX_TIME_LABEL, "%.0f", floor(rci->start_time/1000) + i*MULT/SAMPLE_RATE);
1342 pango_layout_set_text(small_layout, label_string, -1);
1343 pango_layout_get_pixel_size(small_layout, &label_width, &label_height);
1344 gdk_draw_layout(rci->pixmap,
1345 rci->draw_area->style->black_gc,
1346 (int) (i - offset - label_width/2),
1347 rci->draw_area->allocation.height - label_height,
1349 /* draw the 1/2 sec grid */
1350 } else if ( !((i*MULT)%(SAMPLE_RATE/2)) ) {
1351 gdk_draw_line(rci->pixmap, rci->draw_area->style->black_gc,
1353 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL,
1355 rci->draw_area->allocation.height-HEIGHT_TIME_LABEL+2);
1364 /****************************************************************************/
1365 static gint expose_event_channels(GtkWidget *widget, GdkEventExpose *event)
1367 rtp_channel_info_t *rci;
1369 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1374 if (GDK_IS_DRAWABLE(widget->window))
1375 gdk_draw_drawable(widget->window,
1376 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
1378 event->area.x, event->area.y,
1379 event->area.x, event->area.y,
1380 event->area.width, event->area.height);
1385 /****************************************************************************/
1387 configure_event_channels(GtkWidget *widget, GdkEventConfigure *event _U_)
1389 rtp_channel_info_t *rci;
1392 /* the first color is blue to highlight the selected item
1393 * the other collors are the same as in the Voip Graph analysys
1394 * to match the same calls
1396 static GdkColor col[MAX_NUM_COL_CONV+1] = {
1397 {0, 0x00FF, 0x00FF, 0xFFFF},
1398 {0, 0x90FF, 0xEEFF, 0x90FF},
1399 {0, 0xFFFF, 0xA0FF, 0x7AFF},
1400 {0, 0xFFFF, 0xB6FF, 0xC1FF},
1401 {0, 0xFAFF, 0xFAFF, 0xD2FF},
1402 {0, 0xFFFF, 0xFFFF, 0x33FF},
1403 {0, 0x66FF, 0xCDFF, 0xAAFF},
1404 {0, 0xE0FF, 0xFFFF, 0xFFFF},
1405 {0, 0xB0FF, 0xC4FF, 0xDEFF},
1406 {0, 0x87FF, 0xCEFF, 0xFAFF},
1407 {0, 0xD3FF, 0xD3FF, 0xD3FF}
1410 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1416 g_object_unref(rci->pixmap);
1420 rci->pixmap = gdk_pixmap_new(widget->window,
1421 widget->allocation.width,
1422 widget->allocation.height,
1425 if ( GDK_IS_DRAWABLE(rci->pixmap) )
1426 gdk_draw_rectangle(rci->pixmap,
1427 widget->style->white_gc,
1430 widget->allocation.width,
1431 widget->allocation.height);
1433 /* create gc's for the background color of each channel */
1434 for (i=0; i<MAX_NUM_COL_CONV+1; i++){
1435 rci->bg_gc[i]=gdk_gc_new(rci->pixmap);
1436 gdk_gc_set_rgb_fg_color(rci->bg_gc[i], &col[i]);
1444 /****************************************************************************/
1446 button_press_event_channel(GtkWidget *widget, GdkEventButton *event _U_)
1448 rtp_channel_info_t *rci;
1452 rci=(rtp_channel_info_t *)g_object_get_data(G_OBJECT(widget), "rtp_channel_info_t");
1457 if (!rci->selected) {
1459 /* only select a new channels if we are in STOP */
1460 if (!rtp_channels->stop) return 0;
1462 /* if there are already both channels selected, unselect the old one */
1463 if (rtp_channels->rci[rtp_channels->channel]) {
1464 /* we disconnect the signal temporarly to avoid been called back */
1465 g_signal_handlers_disconnect_by_func(rtp_channels->rci[rtp_channels->channel]->check_bt, on_bt_check_clicked, rtp_channels->rci[rtp_channels->channel]);
1466 gtk_toggle_button_set_active((GtkToggleButton *) rtp_channels->rci[rtp_channels->channel]->check_bt, FALSE);
1467 g_signal_connect(rtp_channels->rci[rtp_channels->channel]->check_bt, "clicked", G_CALLBACK(on_bt_check_clicked), rtp_channels->rci[rtp_channels->channel]);
1468 rtp_channels->rci[rtp_channels->channel]->selected = FALSE;
1471 /* we disconnect the signal temporarly to avoid been called back */
1472 g_signal_handlers_disconnect_by_func(rci->check_bt, on_bt_check_clicked, rci);
1473 gtk_toggle_button_set_active((GtkToggleButton *) rci->check_bt, TRUE);
1474 g_signal_connect(rci->check_bt, "clicked", G_CALLBACK(on_bt_check_clicked), rci);
1476 rtp_channels->rci[rtp_channels->channel] = rci;
1477 rtp_channels->channel = !(rtp_channels->channel);
1478 rci->selected = TRUE;
1480 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1481 bt_state(TRUE, TRUE, FALSE, FALSE);
1484 if (rci == rtp_channels->rci[0]) {
1490 rci->frame_index = (unsigned int) (event->x * MULT);
1492 prev_index = rtp_channels->frame_index;
1493 rtp_channels->frame_index = rtp_channels->start_index[this_channel] + rci->frame_index;
1494 rtp_channels->pause_duration += prev_index - rtp_channels->frame_index;
1498 /* change the index in the other channel if selected, according with the index position */
1499 if (rtp_channels->rci[!this_channel]) {
1500 init_rtp_channels_vals();
1502 if (rtp_channels->frame_index < rtp_channels->start_index[!this_channel]) {
1503 rtp_channels->rci[!this_channel]->frame_index = 0;
1504 } else if (rtp_channels->frame_index > rtp_channels->end_index[!this_channel]) {
1505 rtp_channels->rci[!this_channel]->frame_index = rtp_channels->rci[!this_channel]->max_frame_index;
1507 rtp_channels->rci[!this_channel]->frame_index = rtp_channels->frame_index - rtp_channels->start_index[!this_channel];
1510 init_rtp_channels_vals();
1513 rtp_channels->out_diff_time = 0;
1515 rci->cursor_catch = TRUE;
1517 /* redraw the cusrsor */
1523 /****************************************************************************/
1525 add_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, guint *counter _U_ )
1527 GString *label = NULL;
1528 GtkWidget *viewport;
1531 /* create the channel draw area */
1532 rci->draw_area=gtk_drawing_area_new();
1534 rci->scroll_window=gtk_scrolled_window_new(NULL, NULL);
1536 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (rci->scroll_window), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER);
1537 rci->h_scrollbar_adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window));
1540 gtk_widget_set_size_request(rci->draw_area, (gint)(rci->samples->len/MULT), CHANNEL_HEIGHT);
1543 viewport = gtk_viewport_new(rci->h_scrollbar_adjustment, gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(rci->scroll_window)));
1544 gtk_container_add(GTK_CONTAINER(viewport), rci->draw_area);
1545 gtk_container_add(GTK_CONTAINER(rci->scroll_window), viewport);
1546 gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE);
1547 g_object_set_data(G_OBJECT(rci->draw_area), "rtp_channel_info_t", rci);
1548 gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1549 GTK_WIDGET_SET_FLAGS(rci->draw_area, GTK_CAN_FOCUS);
1550 gtk_widget_grab_focus(rci->draw_area);
1552 gtk_box_pack_start(GTK_BOX (channels_vb), rci->scroll_window, FALSE, FALSE, 0);
1554 /* signals needed to handle backing pixmap */
1555 g_signal_connect(rci->draw_area, "expose_event", G_CALLBACK(expose_event_channels), NULL);
1556 g_signal_connect(rci->draw_area, "configure_event", G_CALLBACK(configure_event_channels), rci);
1557 gtk_widget_add_events (rci->draw_area, GDK_BUTTON_PRESS_MASK);
1558 g_signal_connect(rci->draw_area, "button_press_event", G_CALLBACK(button_press_event_channel), rci);
1559 g_signal_connect(rci->h_scrollbar_adjustment, "value_changed", G_CALLBACK(h_scrollbar_changed), rci);
1562 label = g_string_new("");
1563 if (GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp)->active) {
1564 g_string_printf(label, "From %s:%d to %s:%d Duration:%.2f Out of Seq: %d(%.1f%%) Wrong Timestamp: %d(%.1f%%)",
1565 get_addr_name(&(rci->first_stream->src_addr)), rci->first_stream->src_port,
1566 get_addr_name(&(rci->first_stream->dest_addr)), rci->first_stream->dest_port,
1567 (double)rci->samples->len/SAMPLE_RATE,
1568 rci->out_of_seq, (double)rci->out_of_seq * 100 / (double)rci->num_packets,
1569 rci->wrong_timestamp, (double)rci->wrong_timestamp * 100 / (double)rci->num_packets);
1571 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%%)",
1572 get_addr_name(&(rci->first_stream->src_addr)), rci->first_stream->src_port,
1573 get_addr_name(&(rci->first_stream->dest_addr)), rci->first_stream->dest_port,
1574 (double)rci->samples->len/SAMPLE_RATE,
1575 rci->drop_by_jitter_buff, (double)rci->drop_by_jitter_buff * 100 / (double)rci->num_packets,
1576 rci->out_of_seq, (double)rci->out_of_seq * 100 / (double)rci->num_packets,
1577 rci->wrong_timestamp, (double)rci->wrong_timestamp * 100 / (double)rci->num_packets);
1580 rci->check_bt = gtk_check_button_new_with_label(label->str);
1581 gtk_box_pack_start(GTK_BOX (channels_vb), rci->check_bt, FALSE, FALSE, 1);
1583 /* Create the Separator if it is not the last one */
1585 if (*counter < g_hash_table_size(rtp_channels_hash)) {
1586 rci->separator = gtk_hseparator_new();
1587 gtk_box_pack_start(GTK_BOX (channels_vb), rci->separator, FALSE, FALSE, 5);
1590 g_signal_connect(rci->check_bt, "clicked", G_CALLBACK(on_bt_check_clicked), rci);
1592 g_string_free(label, TRUE);
1595 /****************************************************************************/
1597 count_channel_frames(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
1599 total_frames += rci->samples->len;
1602 /****************************************************************************/
1609 /* we should never be here if we are in PLAY and !PAUSE */
1610 if(!rtp_channels->stop && !rtp_channels->pause){
1614 /* if we are in PAUSE change the state */
1615 if (rtp_channels->pause) {
1616 rtp_channels->pause = FALSE;
1617 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1618 bt_state(FALSE, FALSE, TRUE, TRUE);
1620 /* if not PAUSE, then start to PLAY */
1623 err = Pa_OpenStream(
1625 paNoDevice, /* default input device */
1627 PA_SAMPLE_TYPE, /* 16 bit Integer input */
1629 Pa_GetDefaultOutputDeviceID(),
1630 NUM_CHANNELS, /* Stereo output */
1631 PA_SAMPLE_TYPE, /* 16 bit Integer output */
1633 SAMPLE_RATE, /* 8 kHz */
1635 0, /* number of buffers, if zero then use default minimum */
1636 paClipOff, /* we won't output out of range samples so don't bother clipping them */
1640 if( err != paNoError ) {
1641 const char *deviceName = "No Device";
1643 PaDeviceID device = Pa_GetDefaultOutputDeviceID();
1645 if (device != paNoDevice)
1647 const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo( device );
1649 deviceName = deviceInfo->name;
1651 deviceName = "(No device info)";
1654 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1655 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1656 "Got this info from PortAudio Library:\n"
1657 " Default deviceName: %s (%d)", deviceName, device);
1658 gtk_dialog_run (GTK_DIALOG (dialog));
1659 gtk_widget_destroy (dialog);
1661 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1662 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1663 "Can not Open Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1664 gtk_dialog_run (GTK_DIALOG (dialog));
1665 gtk_widget_destroy (dialog);
1668 #else /* PORTAUDIO_API_1 */
1669 if (Pa_GetDefaultOutputDevice() != paNoDevice) {
1670 err = Pa_OpenDefaultStream(
1673 NUM_CHANNELS, /* Stereo output */
1674 PA_SAMPLE_TYPE, /* 16 bit Integer output */
1675 SAMPLE_RATE, /* 8 kHz */
1680 /* If the Default Host API doesn't even provide a device
1681 * we might as well go look for another.
1683 PaHostApiIndex host_api_count = Pa_GetHostApiCount();
1684 PaHostApiIndex default_host_api_index = Pa_GetDefaultHostApi();
1686 PaHostApiIndex host_api_index;
1687 const PaHostApiInfo *host_api_info;
1689 for (host_api_index=0; host_api_index<host_api_count; host_api_index++)
1691 /* Skip the default host API, that didn't work before */
1692 if (host_api_index == default_host_api_index)
1695 /* If we find a host API with a device, then take it. */
1696 host_api_info = Pa_GetHostApiInfo(host_api_index);
1697 if (host_api_info->deviceCount > 0)
1701 if (host_api_index<host_api_count)
1703 PaStreamParameters stream_parameters;
1704 stream_parameters.device = host_api_info->defaultOutputDevice;
1705 stream_parameters.channelCount = NUM_CHANNELS; /* Stereo output */
1706 stream_parameters.sampleFormat = PA_SAMPLE_TYPE; /* 16 bit Integer output */
1707 stream_parameters.suggestedLatency = 0;
1708 stream_parameters.hostApiSpecificStreamInfo = NULL;
1710 g_print("Trying Host API: %s\n", host_api_info->name);
1712 err = Pa_OpenStream(
1714 NULL, /* no input */
1716 SAMPLE_RATE, /* 8 kHz */
1718 paClipOff, /* we won't output out of range samples so don't bother clipping them */
1728 if( err != paNoError ) {
1729 PaHostApiIndex hostApi = Pa_GetDefaultHostApi();
1732 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1733 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1734 "Can not even get the default host API from PortAudio Library.\n Error: %s",
1735 Pa_GetErrorText( hostApi ));
1736 gtk_dialog_run (GTK_DIALOG (dialog));
1737 gtk_widget_destroy (dialog);
1741 const PaHostApiInfo *hostApiInfo = Pa_GetHostApiInfo( hostApi );
1745 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1746 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1747 "Can not even get the host API info from PortAudio Library.");
1748 gtk_dialog_run (GTK_DIALOG (dialog));
1749 gtk_widget_destroy (dialog);
1753 const char *hostApiName = hostApiInfo->name;
1754 const char *deviceName = "No Device";
1756 PaDeviceIndex device = hostApiInfo->defaultOutputDevice;
1758 if (device != paNoDevice)
1760 const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo( device );
1762 deviceName = deviceInfo->name;
1764 deviceName = "(No device info)";
1767 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1768 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1769 "Got this info from PortAudio Library:\n"
1770 " Default hostApiName: %s\n"
1771 " Default deviceName: %s (%d)", hostApiName, deviceName, device);
1772 gtk_dialog_run (GTK_DIALOG (dialog));
1773 gtk_widget_destroy (dialog);
1777 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1778 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1779 "Can not Open Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1780 gtk_dialog_run (GTK_DIALOG (dialog));
1781 gtk_widget_destroy (dialog);
1786 err = Pa_StartStream( pa_stream );
1787 if( err != paNoError ) {
1788 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
1789 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
1790 "Can not Start Stream in PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
1791 gtk_dialog_run (GTK_DIALOG (dialog));
1792 gtk_widget_destroy (dialog);
1795 #if !PORTAUDIO_API_1
1796 rtp_channels->pa_start_time = Pa_GetStreamTime(pa_stream);
1797 #endif /* PORTAUDIO_API_1 */
1799 rtp_channels->stop = FALSE;
1801 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1802 bt_state(FALSE, FALSE, TRUE, TRUE);
1805 /* Draw the cursor in the graph */
1806 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1810 /****************************************************************************/
1812 pause_channels(void)
1814 rtp_channels->pause = !(rtp_channels->pause);
1816 /* reactivate the cusrosr display if no in pause */
1817 if (!rtp_channels->pause) {
1818 /* Draw the cursor in the graph */
1819 g_timeout_add_full(G_PRIORITY_DEFAULT_IDLE, MULT*1000/SAMPLE_RATE, draw_cursors, NULL, NULL);
1822 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1823 bt_state(FALSE, TRUE, FALSE, TRUE);
1826 /****************************************************************************/
1828 reset_rtp_channels(void)
1830 rtp_channels->channel = 0;
1831 rtp_channels->rci[0] = NULL;
1832 rtp_channels->rci[1] = NULL;
1833 rtp_channels->start_index[0] = 0;
1834 rtp_channels->start_index[1] = 0;
1835 rtp_channels->end_index[0] = 0;
1836 rtp_channels->end_index[1] = 0;
1837 rtp_channels->max_frame_index = 0;
1838 rtp_channels->frame_index = 0;
1839 rtp_channels->pause = FALSE;
1840 rtp_channels->pause_duration = 0;
1841 rtp_channels->stop = TRUE;
1842 rtp_channels->out_diff_time = 10000;
1845 /****************************************************************************/
1847 remove_channel_to_window(gchar *key _U_ , rtp_channel_info_t *rci, gpointer ptr _U_ )
1849 g_object_unref(rci->pixmap);
1850 gtk_widget_destroy(rci->draw_area);
1851 gtk_widget_destroy(rci->scroll_window);
1852 gtk_widget_destroy(rci->check_bt);
1854 gtk_widget_destroy(rci->separator);
1857 /****************************************************************************/
1859 reset_channels(void)
1862 if (rtp_channels_hash) {
1863 /* Remove the channels from the main window if there are there */
1864 g_hash_table_foreach( rtp_channels_hash, (GHFunc)remove_channel_to_window, NULL);
1867 /* destroy the rtp channels hash table */
1868 g_hash_table_destroy(rtp_channels_hash);
1869 rtp_channels_hash = NULL;
1873 reset_rtp_channels();
1877 /****************************************************************************/
1879 reset_rtp_player(void)
1881 /* Destroy the rtp channels */
1884 /* destroy the rtp streams hash table */
1885 if (rtp_streams_hash) {
1886 g_hash_table_destroy(rtp_streams_hash);
1887 rtp_streams_hash = NULL;
1890 /* destroy the rtp streams list */
1891 if (rtp_streams_list) {
1892 g_list_free (rtp_streams_list);
1893 rtp_streams_list = NULL;
1898 /****************************************************************************/
1900 decode_streams(void)
1902 guint statusbar_context;
1905 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1906 bt_state(FALSE, FALSE, FALSE, FALSE);
1910 progress_bar = gtk_progress_bar_new();
1911 gtk_widget_set_size_request(progress_bar, 100, -1);
1912 gtk_box_pack_start(GTK_BOX (stat_hbox), progress_bar, FALSE, FALSE, 2);
1913 gtk_widget_show(progress_bar);
1914 statusbar_context = gtk_statusbar_get_context_id((GtkStatusbar *) info_bar, "main");
1915 gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, " Decoding RTP packets...");
1917 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), FALSE);
1919 /* reset the number of packet to be decoded, this is used for the progress bar */
1921 /* reset the Progress Bar count */
1924 /* Mark the RTP streams to be played using the selected VoipCalls. If voip_calls is NULL
1925 then this was called from "RTP Analysis" so mark all strams */
1926 if (rtp_streams_hash) {
1928 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_rtp_stream_to_play, NULL);
1930 g_hash_table_foreach( rtp_streams_hash, (GHFunc)mark_all_rtp_stream_to_play, NULL);
1933 /* Decode the RTP streams and add them to the RTP channels to be played */
1934 g_list_foreach( rtp_streams_list, (GFunc)decode_rtp_stream, NULL);
1936 /* reset the number of frames to be displayed, this is used for the progress bar */
1938 /* Count the frames in all the RTP channels */
1939 if (rtp_channels_hash)
1940 g_hash_table_foreach( rtp_channels_hash, (GHFunc)count_channel_frames, NULL);
1942 /* reset the Progress Bar count again for the progress of creating the channels view */
1944 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1945 gtk_statusbar_push((GtkStatusbar *) info_bar, statusbar_context, " Creating channels view...");
1947 /* Display the RTP channels in the window */
1949 if (rtp_channels_hash)
1950 g_hash_table_foreach( rtp_channels_hash, (GHFunc)add_channel_to_window, &counter);
1952 /* Resize the main scroll window to display no more than preferred (or default) max channels, scroll bar will be used if needed */
1954 if (prefs.rtp_player_max_visible < 1 || prefs.rtp_player_max_visible > 10)
1955 prefs.rtp_player_max_visible = RTP_PLAYER_DEFAULT_VISIBLE;
1957 gtk_widget_set_size_request(main_scrolled_window, CHANNEL_WIDTH,
1958 MIN(counter, prefs.rtp_player_max_visible) * (CHANNEL_HEIGHT+60));
1960 gtk_widget_show_all(main_scrolled_window);
1962 gtk_widget_destroy(progress_bar);
1963 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
1964 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1966 /* blank the status label */
1967 gtk_statusbar_pop((GtkStatusbar *) info_bar, statusbar_context);
1969 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1970 bt_state(TRUE, FALSE, FALSE, FALSE);
1972 /* get the static jitter buffer from the spinner gui */
1973 new_jitter_buff = (int) gtk_spin_button_get_value((GtkSpinButton * )jitter_spinner);
1977 /****************************************************************************/
1979 on_cb_use_rtp_clicked(GtkToggleButton *button _U_, gpointer user_data _U_)
1981 /* set the sensitive state of the buttons (decode, play, pause, stop) */
1982 bt_state(TRUE, FALSE, FALSE, FALSE);
1985 /****************************************************************************/
1987 on_bt_decode_clicked(GtkButton *button _U_, gpointer user_data _U_)
1992 /****************************************************************************/
1994 on_bt_play_clicked(GtkButton *button _U_, gpointer user_data _U_)
1999 /****************************************************************************/
2001 on_bt_pause_clicked(GtkButton *button _U_, gpointer user_data _U_)
2006 /****************************************************************************/
2008 on_bt_stop_clicked(GtkButton *button _U_, gpointer user_data _U_)
2013 /****************************************************************************/
2015 rtp_player_on_destroy(GtkObject *object _U_, gpointer user_data _U_)
2020 /* Stop the channels if necesary */
2021 if(rtp_channels && (!rtp_channels->stop)){
2025 /* Destroy the rtp channels */
2028 g_free(rtp_channels);
2029 rtp_channels = NULL;
2031 /* Terminate the use of PortAudio library */
2032 err = Pa_Terminate();
2033 initialized = FALSE;
2034 if( err != paNoError ) {
2035 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
2036 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
2037 "Can not terminate the PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
2038 gtk_dialog_run (GTK_DIALOG (dialog));
2039 gtk_widget_destroy (dialog);
2042 gtk_widget_destroy(rtp_player_dlg_w);
2043 main_scrolled_window = NULL;
2044 rtp_player_dlg_w = NULL;
2047 /****************************************************************************/
2049 jitter_spinner_value_changed (GtkSpinButton *spinner _U_, gpointer user_data _U_)
2051 /* set the sensitive state of the buttons (decode, play, pause, stop) */
2052 bt_state(TRUE, TRUE, FALSE, FALSE);
2055 /****************************************************************************/
2057 rtp_player_dlg_create(void)
2060 GtkWidget *hbuttonbox;
2061 GtkWidget *h_jitter_buttons_box;
2062 GtkWidget *bt_close;
2063 GtkAdjustment *jitter_spinner_adj;
2065 const gchar *title_name_ptr;
2068 GtkTooltips *tooltips = gtk_tooltips_new();
2070 title_name_ptr = cf_get_display_name(&cfile);
2071 win_name = g_strdup_printf("%s - VoIP - RTP Player", title_name_ptr);
2073 rtp_player_dlg_w = dlg_window_new(win_name); /* transient_for top_level */
2074 gtk_window_set_destroy_with_parent (GTK_WINDOW(rtp_player_dlg_w), TRUE);
2075 gtk_window_set_position(GTK_WINDOW(rtp_player_dlg_w), GTK_WIN_POS_NONE);
2077 gtk_window_set_default_size(GTK_WINDOW(rtp_player_dlg_w), 400, 50);
2079 main_vb = gtk_vbox_new (FALSE, 0);
2080 gtk_container_add(GTK_CONTAINER(rtp_player_dlg_w), main_vb);
2081 gtk_container_set_border_width (GTK_CONTAINER (main_vb), 2);
2083 main_scrolled_window=gtk_scrolled_window_new(NULL, NULL);
2084 gtk_container_set_border_width (GTK_CONTAINER (main_scrolled_window), 4);
2085 gtk_widget_set_size_request(main_scrolled_window, CHANNEL_WIDTH, 0);
2087 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (main_scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
2088 gtk_container_add(GTK_CONTAINER(main_vb), main_scrolled_window);
2090 channels_vb = gtk_vbox_new (FALSE, 0);
2091 gtk_container_set_border_width (GTK_CONTAINER (channels_vb), 2);
2092 gtk_scrolled_window_add_with_viewport((GtkScrolledWindow *) main_scrolled_window, channels_vb);
2094 h_jitter_buttons_box = gtk_hbox_new (FALSE, 0);
2095 gtk_container_set_border_width (GTK_CONTAINER (h_jitter_buttons_box), 10);
2096 gtk_box_pack_start (GTK_BOX(main_vb), h_jitter_buttons_box, FALSE, FALSE, 0);
2097 label = gtk_label_new("Jitter buffer [ms] ");
2098 gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), label, FALSE, FALSE, 0);
2100 jitter_spinner_adj = (GtkAdjustment *) gtk_adjustment_new (50, 0, 500, 5, 10, 0);
2101 jitter_spinner = gtk_spin_button_new (jitter_spinner_adj, 5, 0);
2102 gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), jitter_spinner, FALSE, FALSE, 0);
2103 gtk_tooltips_set_tip (tooltips, jitter_spinner, "The simulated jitter buffer in [ms]", NULL);
2104 g_signal_connect(GTK_OBJECT (jitter_spinner_adj), "value_changed", G_CALLBACK(jitter_spinner_value_changed), NULL);
2107 cb_use_rtp_timestamp = gtk_check_button_new_with_label("Use RTP timestamp");
2108 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cb_use_rtp_timestamp), FALSE);
2109 gtk_box_pack_start(GTK_BOX(h_jitter_buttons_box), cb_use_rtp_timestamp, FALSE, FALSE, 10);
2110 g_signal_connect(cb_use_rtp_timestamp, "toggled", G_CALLBACK(on_cb_use_rtp_clicked), NULL);
2111 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);
2114 hbuttonbox = gtk_hbutton_box_new ();
2115 gtk_box_pack_start (GTK_BOX (h_jitter_buttons_box), hbuttonbox, TRUE, TRUE, 0);
2116 gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox), GTK_BUTTONBOX_SPREAD);
2117 gtk_box_set_spacing (GTK_BOX (hbuttonbox), 10);
2119 bt_decode = gtk_button_new_from_stock(WIRESHARK_STOCK_DECODE);
2120 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_decode);
2121 g_signal_connect(bt_decode, "clicked", G_CALLBACK(on_bt_decode_clicked), NULL);
2122 gtk_tooltips_set_tip (tooltips, bt_decode, "Decode the RTP stream(s)", NULL);
2124 bt_play = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);
2125 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_play);
2126 g_signal_connect(bt_play, "clicked", G_CALLBACK(on_bt_play_clicked), NULL);
2127 gtk_tooltips_set_tip (tooltips, bt_play, "Play the RTP channel(s)", NULL);
2129 bt_pause = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PAUSE);
2130 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_pause);
2131 g_signal_connect(bt_pause, "clicked", G_CALLBACK(on_bt_pause_clicked), NULL);
2132 gtk_tooltips_set_tip (tooltips, bt_pause, "Pause the RTP channel(s)", NULL);
2134 bt_stop = gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
2135 gtk_container_add(GTK_CONTAINER(hbuttonbox), bt_stop);
2136 g_signal_connect(bt_stop, "clicked", G_CALLBACK(on_bt_stop_clicked), NULL);
2137 gtk_tooltips_set_tip (tooltips, bt_stop, "Stop the RTP channel(s)", NULL);
2139 bt_close = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
2140 gtk_container_add (GTK_CONTAINER (hbuttonbox), bt_close);
2141 GTK_WIDGET_SET_FLAGS(bt_close, GTK_CAN_DEFAULT);
2142 gtk_tooltips_set_tip (tooltips, bt_close, "Close this dialog", NULL);
2143 window_set_cancel_button(rtp_player_dlg_w, bt_close, window_cancel_button_cb);
2145 g_signal_connect(rtp_player_dlg_w, "delete_event", G_CALLBACK(window_delete_event_cb), NULL);
2146 g_signal_connect(rtp_player_dlg_w, "destroy", G_CALLBACK(rtp_player_on_destroy), NULL);
2149 hbuttonbox = gtk_hbutton_box_new ();
2151 /* Filter/status hbox */
2152 stat_hbox = gtk_hbox_new(FALSE, 1);
2153 gtk_container_set_border_width(GTK_CONTAINER(stat_hbox), 0);
2156 info_bar = gtk_statusbar_new();
2157 gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(info_bar), TRUE);
2159 gtk_box_pack_start(GTK_BOX(stat_hbox), info_bar, TRUE, TRUE, 0);
2161 /* statusbar hbox */
2162 gtk_box_pack_start(GTK_BOX(main_vb), stat_hbox, FALSE, TRUE, 0);
2164 /* set the sensitive state of the buttons (decode, play, pause, stop) */
2165 bt_state(TRUE, FALSE, FALSE, FALSE);
2167 gtk_widget_show_all(rtp_player_dlg_w);
2169 /* Force gtk to redraw the window before starting decoding the packet */
2170 while (g_main_context_iteration(NULL, FALSE));
2175 /****************************************************************************/
2177 rtp_player_init(voip_calls_tapinfo_t *voip_calls_tap)
2182 if (initialized) return;
2185 voip_calls = voip_calls_tap;
2186 err = Pa_Initialize();
2187 if( err != paNoError ) {
2188 dialog = gtk_message_dialog_new ((GtkWindow *) rtp_player_dlg_w,
2189 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR,GTK_BUTTONS_CLOSE,
2190 "Can not Initialize the PortAudio Library.\n Error: %s", Pa_GetErrorText( err ));
2191 gtk_dialog_run (GTK_DIALOG (dialog));
2192 gtk_widget_destroy (dialog);
2193 initialized = FALSE;
2197 new_jitter_buff = -1;
2199 #ifdef HAVE_G729_G723
2200 /* Initialize the G729 and G723 decoders */
2203 #endif /* HAVE_G729_G723 */
2205 if (!rtp_channels) {
2206 rtp_channels = g_malloc(sizeof(rtp_play_channels_t));
2209 reset_rtp_channels();
2212 g_print("Pa_GetHostApiCount() = %d\n", Pa_GetHostApiCount());
2213 g_print("Pa_GetDefaultHostApi() = %d\n", Pa_GetDefaultHostApi());
2215 if ((Pa_GetHostApiCount() >= 0) && (Pa_GetDefaultHostApi() >= 0))
2218 PaHostApiIndex api_index;
2219 const PaHostApiInfo *api_info = Pa_GetHostApiInfo( (unsigned int)Pa_GetDefaultHostApi() );
2220 g_print("Default PaHostApiInfo.type = %d (%s)\n", api_info->type, api_info->name);
2222 for (i=0; i<(unsigned int)Pa_GetHostApiCount(); i++)
2224 api_info = Pa_GetHostApiInfo( i );
2225 g_print("PaHostApiInfo[%u].type = %d (%s)\n", i, api_info->type, api_info->name);
2228 api_index = Pa_HostApiTypeIdToHostApiIndex( paALSA );
2231 g_print("api_index for paALSA not found (%d)\n", api_index);
2235 api_info = Pa_GetHostApiInfo( (unsigned int)api_index );
2236 g_print("This should be ALSA: %s\n", api_info->name);
2241 /* create the dialog window */
2242 rtp_player_dlg_create();
2246 #endif /* HAVE_LIBPORTAUDIO */