2 * RTP stream handler functions used by tshark and wireshark
4 * Copyright 2008, Ericsson AB
5 * By Balint Reczey <balint.reczey@ericsson.com>
7 * most functions are copied from ui/gtk/rtp_stream.c and ui/gtk/rtp_analysis.c
8 * Copyright 2003, Alcatel Business Systems
9 * By Lars Ruoff <lars.ruoff@gmx.net>
11 * Wireshark - Network traffic analyzer
12 * By Gerald Combs <gerald@wireshark.org>
13 * Copyright 1998 Gerald Combs
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
38 #include <epan/rtp_pt.h>
39 #include <epan/addr_resolv.h>
40 #include <epan/proto_data.h>
41 #include <epan/dissectors/packet-rtp.h>
42 #include <wsutil/pint.h>
43 #include "rtp_stream.h"
44 #include "tap-rtp-common.h"
46 /* XXX: are changes needed to properly handle situations where
47 info_all_data_present == FALSE ?
48 E.G., when captured frames are truncated.
51 /****************************************************************************/
52 /* Type for storing and writing rtpdump information */
53 typedef struct st_rtpdump_info {
54 double rec_time; /**< milliseconds since start of recording */
55 guint16 num_samples; /**< number of bytes in *frame */
56 const guint8 *samples; /**< data bytes */
59 /****************************************************************************/
60 /* GCompareFunc style comparison function for _rtp_stream_info */
61 static gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb)
63 const struct _rtp_stream_info* a = (const struct _rtp_stream_info*)aa;
64 const struct _rtp_stream_info* b = (const struct _rtp_stream_info*)bb;
68 if (a==NULL || b==NULL)
70 if (addresses_equal(&(a->src_addr), &(b->src_addr))
71 && (a->src_port == b->src_port)
72 && addresses_equal(&(a->dest_addr), &(b->dest_addr))
73 && (a->dest_port == b->dest_port)
74 && (a->ssrc == b->ssrc))
81 /****************************************************************************/
82 /* when there is a [re]reading of packet's */
83 void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
87 if (tapinfo->mode == TAP_ANALYSE) {
88 /* free the data items first */
89 list = g_list_first(tapinfo->strinfo_list);
93 list = g_list_next(list);
95 g_list_free(tapinfo->strinfo_list);
96 tapinfo->strinfo_list = NULL;
97 tapinfo->nstreams = 0;
98 tapinfo->npackets = 0;
104 void rtpstream_reset_cb(void *arg)
106 rtpstream_tapinfo_t *ti =(rtpstream_tapinfo_t *)arg;
108 /* Give listeners a chance to cleanup references. */
115 * rtpdump file format
117 * The file starts with the tool to be used for playing this file,
118 * the multicast/unicast receive address and the port.
120 * #!rtpplay1.0 224.2.0.1/3456\n
122 * This is followed by one binary header (RD_hdr_t) and one RD_packet_t
123 * structure for each received packet. All fields are in network byte
124 * order. We don't need the source IP address since we can do mapping
125 * based on SSRC. This saves (a little) space, avoids non-IPv4
126 * problems and privacy/security concerns. The header is followed by
127 * the RTP/RTCP header and (optionally) the actual payload.
130 #define RTPFILE_VERSION "1.0"
133 * Write a header to the current output file.
134 * The header consists of an identifying string, followed
135 * by a binary structure.
137 void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file)
139 guint32 start_sec; /* start of recording (GMT) (seconds) */
140 guint32 start_usec; /* start of recording (GMT) (microseconds)*/
141 guint32 source; /* network source (multicast address) */
143 guint16 port; /* UDP port */
144 guint16 padding; /* 2 padding bytes */
145 char* addr_str = address_to_display(NULL, &(strinfo->dest_addr));
147 fprintf(file, "#!rtpplay%s %s/%u\n", RTPFILE_VERSION,
150 wmem_free(NULL, addr_str);
152 start_sec = g_htonl(strinfo->start_fd->abs_ts.secs);
153 start_usec = g_htonl(strinfo->start_fd->abs_ts.nsecs / 1000000);
154 /* rtpdump only accepts guint32 as source, will be fake for IPv6 */
155 memset(&source, 0, sizeof source);
156 sourcelen = strinfo->src_addr.len;
157 if (sourcelen > sizeof source)
158 sourcelen = sizeof source;
159 memcpy(&source, strinfo->src_addr.data, sourcelen);
160 port = g_htons(strinfo->src_port);
163 if (fwrite(&start_sec, 4, 1, file) == 0)
165 if (fwrite(&start_usec, 4, 1, file) == 0)
167 if (fwrite(&source, 4, 1, file) == 0)
169 if (fwrite(&port, 2, 1, file) == 0)
171 if (fwrite(&padding, 2, 1, file) == 0)
175 /* utility function for writing a sample to file in rtpdump -F dump format (.rtp)*/
176 static void rtp_write_sample(rtpdump_info_t* rtpdump_info, FILE* file)
178 guint16 length; /* length of packet, including this header (may
179 be smaller than plen if not whole packet recorded) */
180 guint16 plen; /* actual header+payload length for RTP, 0 for RTCP */
181 guint32 offset; /* milliseconds since the start of recording */
183 length = g_htons(rtpdump_info->num_samples + 8);
184 plen = g_htons(rtpdump_info->num_samples);
185 offset = g_htonl(rtpdump_info->rec_time);
187 if (fwrite(&length, 2, 1, file) == 0)
189 if (fwrite(&plen, 2, 1, file) == 0)
191 if (fwrite(&offset, 4, 1, file) == 0)
193 if (fwrite(rtpdump_info->samples, rtpdump_info->num_samples, 1, file) == 0)
198 /****************************************************************************/
199 /* whenever a RTP packet is seen by the tap listener */
200 int rtpstream_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *arg2)
202 rtpstream_tapinfo_t *tapinfo = (rtpstream_tapinfo_t *)arg;
203 const struct _rtp_info *rtpinfo = (const struct _rtp_info *)arg2;
204 rtp_stream_info_t new_stream_info;
205 rtp_stream_info_t *stream_info = NULL;
207 rtpdump_info_t rtpdump_info;
209 struct _rtp_conversation_info *p_conv_data = NULL;
211 /* gather infos on the stream this packet is part of */
212 memset(&new_stream_info, 0, sizeof(rtp_stream_info_t));
213 copy_address(&(new_stream_info.src_addr), &(pinfo->src));
214 new_stream_info.src_port = pinfo->srcport;
215 copy_address(&(new_stream_info.dest_addr), &(pinfo->dst));
216 new_stream_info.dest_port = pinfo->destport;
217 new_stream_info.ssrc = rtpinfo->info_sync_src;
218 new_stream_info.payload_type = rtpinfo->info_payload_type;
219 new_stream_info.payload_type_name = g_strdup(rtpinfo->info_payload_type_str);
221 if (tapinfo->mode == TAP_ANALYSE) {
222 /* check whether we already have a stream with these parameters in the list */
223 list = g_list_first(tapinfo->strinfo_list);
226 if (rtp_stream_info_cmp(&new_stream_info, (rtp_stream_info_t*)(list->data))==0)
228 stream_info = (rtp_stream_info_t*)(list->data); /*found!*/
231 list = g_list_next(list);
234 /* not in the list? then create a new entry */
236 new_stream_info.start_fd = pinfo->fd;
237 new_stream_info.start_rel_time = pinfo->rel_ts;
239 /* reset RTP stats */
240 new_stream_info.rtp_stats.first_packet = TRUE;
241 new_stream_info.rtp_stats.reg_pt = PT_UNDEFINED;
243 /* Get the Setup frame number who set this RTP stream */
244 p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(wmem_file_scope(), pinfo, proto_get_id_by_filter_name("rtp"), 0);
246 new_stream_info.setup_frame_number = p_conv_data->frame_number;
248 new_stream_info.setup_frame_number = 0xFFFFFFFF;
250 stream_info = g_new(rtp_stream_info_t,1);
251 *stream_info = new_stream_info; /* memberwise copy of struct */
252 tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, stream_info);
255 /* get RTP stats for the packet */
256 rtp_packet_analyse(&(stream_info->rtp_stats), pinfo, rtpinfo);
257 if (stream_info->rtp_stats.flags & STAT_FLAG_WRONG_TIMESTAMP
258 || stream_info->rtp_stats.flags & STAT_FLAG_WRONG_SEQ)
259 stream_info->problem = TRUE;
262 /* increment the packets counter for this stream */
263 ++(stream_info->packet_count);
264 stream_info->stop_rel_time = pinfo->rel_ts;
266 /* increment the packets counter of all streams */
267 ++(tapinfo->npackets);
269 return 1; /* refresh output */
271 else if (tapinfo->mode == TAP_SAVE) {
272 if (rtp_stream_info_cmp(&new_stream_info, tapinfo->filter_stream_fwd)==0) {
273 /* XXX - what if rtpinfo->info_all_data_present is
274 FALSE, so that we don't *have* all the data? */
275 rtpdump_info.rec_time = nstime_to_msec(&pinfo->abs_ts) -
276 nstime_to_msec(&tapinfo->filter_stream_fwd->start_fd->abs_ts);
277 rtpdump_info.num_samples = rtpinfo->info_data_len;
278 rtpdump_info.samples = rtpinfo->info_data;
279 rtp_write_sample(&rtpdump_info, tapinfo->save_file);
282 else if (tapinfo->mode == TAP_MARK && tapinfo->tap_mark_packet) {
283 if (rtp_stream_info_cmp(&new_stream_info, tapinfo->filter_stream_fwd)==0
284 || rtp_stream_info_cmp(&new_stream_info, tapinfo->filter_stream_rev)==0)
286 tapinfo->tap_mark_packet(tapinfo, pinfo->fd);
293 typedef struct _key_value {
299 /* RTP sampling clock rates for fixed payload types as defined in
300 http://www.iana.org/assignments/rtp-parameters */
301 static const key_value clock_map[] = {
307 {PT_DVI4_8000, 8000},
308 {PT_DVI4_16000, 16000},
312 {PT_L16_STEREO, 44100},
313 {PT_L16_MONO, 44100},
319 {PT_DVI4_11025, 11025},
320 {PT_DVI4_22050, 22050},
332 #define NUM_CLOCK_VALUES (sizeof clock_map / sizeof clock_map[0])
335 get_clock_rate(guint32 key)
339 for (i = 0; i < NUM_CLOCK_VALUES; i++) {
340 if (clock_map[i].key == key)
341 return clock_map[i].value;
346 typedef struct _mimetype_and_clock {
347 const gchar *pt_mime_name_str;
349 } mimetype_and_clock;
350 /* RTP sampling clock rates for
351 "In addition to the RTP payload formats (encodings) listed in the RTP
352 Payload Types table, there are additional payload formats that do not
353 have static RTP payload types assigned but instead use dynamic payload
354 type number assignment. Each payload format is named by a registered
356 http://www.iana.org/assignments/rtp-parameters.
358 NOTE: Please keep the mimetypes in case insensitive alphabetical order.
360 static const mimetype_and_clock mimetype_and_clock_map[] = {
361 {"AMR", 8000}, /* [RFC4867][RFC3267] */
362 {"AMR-WB", 16000}, /* [RFC4867][RFC3267] */
363 {"BMPEG", 90000}, /* [RFC2343],[RFC3555] */
364 {"BT656", 90000}, /* [RFC2431],[RFC3555] */
365 {"DV", 90000}, /* [RFC3189] */
366 {"EVRC", 8000}, /* [RFC3558] */
367 {"EVRC0", 8000}, /* [RFC4788] */
368 {"EVRC1", 8000}, /* [RFC4788] */
369 {"EVRCB", 8000}, /* [RFC4788] */
370 {"EVRCB0", 8000}, /* [RFC4788] */
371 {"EVRCB1", 8000}, /* [RFC4788] */
372 {"EVRCWB", 16000}, /* [RFC5188] */
373 {"EVRCWB0", 16000}, /* [RFC5188] */
374 {"EVRCWB1", 16000}, /* [RFC5188] */
375 {"EVS", 16000}, /* [3GPP TS 26.445] */
376 {"G7221", 16000}, /* [RFC3047] */
377 {"G726-16", 8000}, /* [RFC3551][RFC4856] */
378 {"G726-24", 8000}, /* [RFC3551][RFC4856] */
379 {"G726-32", 8000}, /* [RFC3551][RFC4856] */
380 {"G726-40", 8000}, /* [RFC3551][RFC4856] */
381 {"G729D", 8000}, /* [RFC3551][RFC4856] */
382 {"G729E", 8000}, /* [RFC3551][RFC4856] */
383 {"GSM-EFR", 8000}, /* [RFC3551] */
384 {"H263-1998", 90000}, /* [RFC2429],[RFC3555] */
385 {"H263-2000", 90000}, /* [RFC2429],[RFC3555] */
386 {"H264", 90000}, /* [RFC3984] */
387 {"MP1S", 90000}, /* [RFC2250],[RFC3555] */
388 {"MP2P", 90000}, /* [RFC2250],[RFC3555] */
389 {"MP4V-ES", 90000}, /* [RFC3016] */
390 {"mpa-robust", 90000}, /* [RFC3119] */
391 {"pointer", 90000}, /* [RFC2862] */
392 {"raw", 90000}, /* [RFC4175] */
393 {"red", 1000}, /* [RFC4102] */
394 {"SMV", 8000}, /* [RFC3558] */
395 {"SMV0", 8000}, /* [RFC3558] */
396 {"t140", 1000}, /* [RFC4103] */
397 {"telephone-event", 8000}, /* [RFC4733] */
400 #define NUM_DYN_CLOCK_VALUES (sizeof mimetype_and_clock_map / sizeof mimetype_and_clock_map[0])
403 get_dyn_pt_clock_rate(const gchar *payload_type_str)
407 /* Search for matching mimetype in reverse order to avoid false matches
408 * when pt_mime_name_str is the prefix of payload_type_str */
409 for (i = NUM_DYN_CLOCK_VALUES - 1; i > -1 ; i--) {
410 if (g_ascii_strncasecmp(mimetype_and_clock_map[i].pt_mime_name_str,payload_type_str,(strlen(mimetype_and_clock_map[i].pt_mime_name_str))) == 0)
411 return mimetype_and_clock_map[i].value;
417 /****************************************************************************/
419 rtp_packet_analyse(tap_rtp_stat_t *statinfo,
421 const struct _rtp_info *rtpinfo)
424 double current_jitter;
425 double current_diff = 0;
427 double arrivaltime; /* Time relative to start_time */
428 double expected_time;
432 /* Store the current time */
433 current_time = nstime_to_msec(&pinfo->rel_ts);
435 /* Is this the first packet we got in this direction? */
436 if (statinfo->first_packet) {
437 /* Save the MAC address of the first RTP frame */
438 if( pinfo->dl_src.type == AT_ETHER){
439 copy_address(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src));
441 statinfo->start_seq_nr = rtpinfo->info_seq_num;
442 statinfo->stop_seq_nr = rtpinfo->info_seq_num;
443 statinfo->seq_num = rtpinfo->info_seq_num;
444 statinfo->start_time = current_time;
445 statinfo->timestamp = rtpinfo->info_timestamp;
446 statinfo->first_timestamp = rtpinfo->info_timestamp;
447 statinfo->time = current_time;
448 statinfo->lastnominaltime = 0;
449 statinfo->pt = rtpinfo->info_payload_type;
450 statinfo->reg_pt = rtpinfo->info_payload_type;
451 if (pinfo->net_src.type == AT_IPv6) {
452 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 48;
454 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
456 statinfo->bw_history[statinfo->bw_index].time = current_time;
457 statinfo->bw_index++;
458 if (pinfo->net_src.type == AT_IPv6) {
459 statinfo->total_bytes += rtpinfo->info_data_len + 48;
461 statinfo->total_bytes += rtpinfo->info_data_len + 28;
463 statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000;
464 /* Not needed ? initialised to zero? */
466 statinfo->jitter = 0;
469 statinfo->total_nr++;
470 statinfo->flags |= STAT_FLAG_FIRST;
471 if (rtpinfo->info_marker_set) {
472 statinfo->flags |= STAT_FLAG_MARKER;
474 statinfo->first_packet_num = pinfo->num;
475 statinfo->first_packet = FALSE;
482 /*According to bug https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=11478
483 * this code causes problems. A better solution is needed if there is need for the functionality */
484 /* Try to detect duplicated packets due to mirroring/span ports by comparing src MAC addresses.
485 * Chek for duplicates (src mac differs from first_packet_mac_addr) */
487 if( pinfo->dl_src.type == AT_ETHER){
488 if(!addresses_equal(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src))){
489 statinfo->flags |= STAT_FLAG_DUP_PKT;
490 statinfo->delta = current_time-(statinfo->time);
495 /* When calculating expected rtp packets the seq number can wrap around
496 * so we have to count the number of cycles
497 * Variable cycles counts the wraps around in forwarding connection and
498 * under is flag that indicates where we are
500 * XXX How to determine number of cycles with all possible lost, late
501 * and duplicated packets without any doubt? It seems to me, that
502 * because of all possible combination of late, duplicated or lost
503 * packets, this can only be more or less good approximation
505 * There are some combinations (rare but theoretically possible),
506 * where below code won't work correctly - statistic may be wrong then.
509 /* So if the current sequence number is less than the start one
510 * we assume, that there is another cycle running
512 if ((rtpinfo->info_seq_num < statinfo->start_seq_nr) && (statinfo->under == FALSE)){
514 statinfo->under = TRUE;
516 /* what if the start seq nr was 0? Then the above condition will never
517 * be true, so we add another condition. XXX The problem would arise
518 * if one of the packets with seq nr 0 or 65535 would be lost or late
520 else if ((rtpinfo->info_seq_num == 0) && (statinfo->stop_seq_nr == 65535) &&
521 (statinfo->under == FALSE)){
523 statinfo->under = TRUE;
525 /* the whole round is over, so reset the flag */
526 else if ((rtpinfo->info_seq_num > statinfo->start_seq_nr) && (statinfo->under != FALSE)) {
527 statinfo->under = FALSE;
530 /* Since it is difficult to count lost, duplicate or late packets separately,
531 * we would like to know at least how many times the sequence number was not ok
534 /* If the current seq number equals the last one or if we are here for
535 * the first time, then it is ok, we just store the current one as the last one
537 if ( (statinfo->seq_num+1 == rtpinfo->info_seq_num) || (statinfo->flags & STAT_FLAG_FIRST) )
538 statinfo->seq_num = rtpinfo->info_seq_num;
539 /* If the first one is 65535 we wrap */
540 else if ( (statinfo->seq_num == 65535) && (rtpinfo->info_seq_num == 0) )
541 statinfo->seq_num = rtpinfo->info_seq_num;
542 /* Lost packets. If the prev seq is enormously larger than the cur seq
543 * we assume that instead of being massively late we lost the packet(s)
544 * that would have indicated the sequence number wrapping. An imprecise
545 * heuristic at best, but it seems to work well enough.
546 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5958 */
547 else if (statinfo->seq_num+1 < rtpinfo->info_seq_num || statinfo->seq_num - rtpinfo->info_seq_num > 0xFF00) {
548 statinfo->seq_num = rtpinfo->info_seq_num;
549 statinfo->sequence++;
550 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
552 /* Late or duplicated */
553 else if (statinfo->seq_num+1 > rtpinfo->info_seq_num) {
554 statinfo->sequence++;
555 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
558 /* Check payload type */
559 if (rtpinfo->info_payload_type == PT_CN
560 || rtpinfo->info_payload_type == PT_CN_OLD)
561 statinfo->flags |= STAT_FLAG_PT_CN;
562 if (statinfo->pt == PT_CN
563 || statinfo->pt == PT_CN_OLD)
564 statinfo->flags |= STAT_FLAG_FOLLOW_PT_CN;
565 if (rtpinfo->info_payload_type != statinfo->pt)
566 statinfo->flags |= STAT_FLAG_PT_CHANGE;
567 statinfo->pt = rtpinfo->info_payload_type;
570 * Return for unknown payload types
571 * Ignore jitter calculation for clockrate = 0
573 if (statinfo->pt < 96 ){
574 clock_rate = get_clock_rate(statinfo->pt);
575 }else{ /* Dynamic PT */
576 if ( rtpinfo->info_payload_type_str != NULL ){
577 /* Is it a "telephone-event" ?
578 * Timestamp is not increased for telepone-event packets impacting
579 * calculation of Jitter Skew and clock drift.
580 * see 2.2.1 of RFC 4733
582 if (g_ascii_strncasecmp("telephone-event",rtpinfo->info_payload_type_str,(strlen("telephone-event")))==0){
584 statinfo->flags |= STAT_FLAG_PT_T_EVENT;
586 if(rtpinfo->info_payload_rate !=0){
587 clock_rate = rtpinfo->info_payload_rate;
589 clock_rate = get_dyn_pt_clock_rate(rtpinfo->info_payload_type_str);
597 /* Handle wraparound ? */
598 arrivaltime = current_time - statinfo->start_time;
600 nominaltime = (double)(guint32_wraparound_diff(rtpinfo->info_timestamp, statinfo->first_timestamp));
602 /* Can only analyze defined sampling rates */
603 if (clock_rate != 0) {
604 statinfo->clock_rate = clock_rate;
605 /* Convert from sampling clock to ms */
606 nominaltime = nominaltime /(clock_rate/1000);
608 /* Calculate the current jitter(in ms) */
609 if (!statinfo->first_packet) {
610 expected_time = statinfo->time + (nominaltime - statinfo->lastnominaltime);
611 current_diff = fabs(current_time - expected_time);
612 current_jitter = (15 * statinfo->jitter + current_diff) / 16;
614 statinfo->delta = current_time-(statinfo->time);
615 statinfo->jitter = current_jitter;
616 statinfo->diff = current_diff;
618 statinfo->lastnominaltime = nominaltime;
619 /* Calculate skew, i.e. absolute jitter that also catches clock drift
620 * Skew is positive if TS (nominal) is too fast
622 statinfo->skew = nominaltime - arrivaltime;
623 absskew = fabs(statinfo->skew);
624 if(absskew > fabs(statinfo->max_skew)){
625 statinfo->max_skew = statinfo->skew;
627 /* Gather data for calculation of average, minimum and maximum framerate based on timestamp */
629 if (numPackets > 0 && (!hardPayloadType || !alternatePayloadType)) {
630 /* Skip first packet and possibly alternate payload type packets */
632 dt = nominaltime - statinfo->lastnominaltime;
634 numdt += (dt != 0 ? 1 : 0);
635 mindt = (dt < mindt ? dt : mindt);
636 maxdt = (dt > maxdt ? dt : maxdt);
639 /* Gather data for calculation of skew least square */
640 statinfo->sumt += 1.0 * current_time;
641 statinfo->sumTS += 1.0 * nominaltime;
642 statinfo->sumt2 += 1.0 * current_time * current_time;
643 statinfo->sumtTS += 1.0 * current_time * nominaltime;
646 /* Calculate the BW in Kbps adding the IP+UDP header to the RTP -> 20bytes(IP) + 8bytes(UDP) */
647 if (pinfo->net_src.type == AT_IPv6) {
648 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 48;
650 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
652 statinfo->bw_history[statinfo->bw_index].time = current_time;
654 /* Check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */
655 while ((statinfo->bw_history[statinfo->bw_start_index].time+1000/* ms */)<current_time){
656 statinfo->total_bytes -= statinfo->bw_history[statinfo->bw_start_index].bytes;
657 statinfo->bw_start_index++;
658 if (statinfo->bw_start_index == BUFF_BW) statinfo->bw_start_index=0;
660 /* IP hdr + UDP + RTP */
661 if (pinfo->net_src.type == AT_IPv6){
662 statinfo->total_bytes += rtpinfo->info_data_len + 48;
664 statinfo->total_bytes += rtpinfo->info_data_len + 28;
666 statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000;
667 statinfo->bw_index++;
668 if (statinfo->bw_index == BUFF_BW) statinfo->bw_index = 0;
671 /* Used by GTK code only */
672 statinfo->delta_timestamp = guint32_wraparound_diff(rtpinfo->info_timestamp, statinfo->timestamp);
674 /* Is it a packet with the mark bit set? */
675 if (rtpinfo->info_marker_set) {
676 statinfo->flags |= STAT_FLAG_MARKER;
679 /* Difference can be negative. We don't expect difference bigger than 31 bits. Difference don't care about wrap around. */
680 gint32 tsdelta=rtpinfo->info_timestamp - statinfo->timestamp;
682 statinfo->flags |= STAT_FLAG_WRONG_TIMESTAMP;
684 /* Is it a regular packet? */
685 if (!(statinfo->flags & STAT_FLAG_FIRST)
686 && !(statinfo->flags & STAT_FLAG_MARKER)
687 && !(statinfo->flags & STAT_FLAG_PT_CN)
688 && !(statinfo->flags & STAT_FLAG_WRONG_TIMESTAMP)
689 && !(statinfo->flags & STAT_FLAG_FOLLOW_PT_CN)) {
690 /* Include it in maximum delta calculation */
691 if (statinfo->delta > statinfo->max_delta) {
692 statinfo->max_delta = statinfo->delta;
693 statinfo->max_nr = pinfo->num;
695 if (clock_rate != 0) {
696 /* Maximum and mean jitter calculation */
697 if (statinfo->jitter > statinfo->max_jitter) {
698 statinfo->max_jitter = statinfo->jitter;
700 statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
703 /* Regular payload change? (CN ignored) */
704 if (!(statinfo->flags & STAT_FLAG_FIRST)
705 && !(statinfo->flags & STAT_FLAG_PT_CN)) {
706 if ((statinfo->pt != statinfo->reg_pt)
707 && (statinfo->reg_pt != PT_UNDEFINED)) {
708 statinfo->flags |= STAT_FLAG_REG_PT_CHANGE;
712 /* Set regular payload*/
713 if (!(statinfo->flags & STAT_FLAG_PT_CN)) {
714 statinfo->reg_pt = statinfo->pt;
717 statinfo->time = current_time;
718 statinfo->timestamp = rtpinfo->info_timestamp;
719 statinfo->stop_seq_nr = rtpinfo->info_seq_num;
720 statinfo->total_nr++;
721 statinfo->last_payload_len = rtpinfo->info_payload_len - rtpinfo->info_padding_count;
727 * Editor modelines - http://www.wireshark.org/tools/modelines.html
732 * indent-tabs-mode: t
735 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
736 * :indentSize=8:tabSize=8:noTabs=false: