Witness: enum witness_notifyResponse_type
[wireshark-wip.git] / ui / tap-rtp-common.c
blob9f9c070f6c5d54a6d991cc3debbd7abeddac2920
1 /* tap-rtp-common.c
2 * RTP stream handler functions used by tshark and wireshark
4 * $Id$
6 * Copyright 2008, Ericsson AB
7 * By Balint Reczey <balint.reczey@ericsson.com>
9 * most functions are copied from ui/gtk/rtp_stream.c and ui/gtk/rtp_analisys.c
10 * Copyright 2003, Alcatel Business Systems
11 * By Lars Ruoff <lars.ruoff@gmx.net>
13 * Wireshark - Network traffic analyzer
14 * By Gerald Combs <gerald@wireshark.org>
15 * Copyright 1998 Gerald Combs
17 * This program is free software; you can redistribute it and/or
18 * modify it under the terms of the GNU General Public License
19 * as published by the Free Software Foundation; either version 2
20 * of the License, or (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "config.h"
34 #include <stdio.h>
35 #include <math.h>
36 #include "globals.h"
38 #include <epan/tap.h>
39 #include <string.h>
40 #include <epan/rtp_pt.h>
41 #include <epan/addr_resolv.h>
42 #include <epan/dissectors/packet-rtp.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 /* GCompareFunc style comparison function for _rtp_stream_info */
53 gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb)
55 const struct _rtp_stream_info* a = (const struct _rtp_stream_info*)aa;
56 const struct _rtp_stream_info* b = (const struct _rtp_stream_info*)bb;
58 if (a==b)
59 return 0;
60 if (a==NULL || b==NULL)
61 return 1;
62 if (ADDRESSES_EQUAL(&(a->src_addr), &(b->src_addr))
63 && (a->src_port == b->src_port)
64 && ADDRESSES_EQUAL(&(a->dest_addr), &(b->dest_addr))
65 && (a->dest_port == b->dest_port)
66 && (a->ssrc == b->ssrc))
67 return 0;
68 else
69 return 1;
73 /****************************************************************************/
74 /* when there is a [re]reading of packet's */
75 void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
77 GList* list;
79 if (tapinfo->mode == TAP_ANALYSE) {
80 /* free the data items first */
81 list = g_list_first(tapinfo->strinfo_list);
82 while (list)
84 g_free(list->data);
85 list = g_list_next(list);
87 g_list_free(tapinfo->strinfo_list);
88 tapinfo->strinfo_list = NULL;
89 tapinfo->nstreams = 0;
90 tapinfo->npackets = 0;
93 ++(tapinfo->launch_count);
95 return;
98 void rtpstream_reset_cb(void *arg)
100 rtpstream_reset((rtpstream_tapinfo_t *)arg);
104 * rtpdump file format
106 * The file starts with the tool to be used for playing this file,
107 * the multicast/unicast receive address and the port.
109 * #!rtpplay1.0 224.2.0.1/3456\n
111 * This is followed by one binary header (RD_hdr_t) and one RD_packet_t
112 * structure for each received packet. All fields are in network byte
113 * order. We don't need the source IP address since we can do mapping
114 * based on SSRC. This saves (a little) space, avoids non-IPv4
115 * problems and privacy/security concerns. The header is followed by
116 * the RTP/RTCP header and (optionally) the actual payload.
119 #define RTPFILE_VERSION "1.0"
122 * Write a header to the current output file.
123 * The header consists of an identifying string, followed
124 * by a binary structure.
126 void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file)
128 guint32 start_sec; /* start of recording (GMT) (seconds) */
129 guint32 start_usec; /* start of recording (GMT) (microseconds)*/
130 guint32 source; /* network source (multicast address) */
131 size_t sourcelen;
132 guint16 port; /* UDP port */
133 guint16 padding; /* 2 padding bytes */
135 fprintf(file, "#!rtpplay%s %s/%u\n", RTPFILE_VERSION,
136 get_addr_name(&(strinfo->dest_addr)),
137 strinfo->dest_port);
139 start_sec = g_htonl(strinfo->start_sec);
140 start_usec = g_htonl(strinfo->start_usec);
141 /* rtpdump only accepts guint32 as source, will be fake for IPv6 */
142 memset(&source, 0, sizeof source);
143 sourcelen = strinfo->src_addr.len;
144 if (sourcelen > sizeof source)
145 sourcelen = sizeof source;
146 memcpy(&source, strinfo->src_addr.data, sourcelen);
147 port = g_htons(strinfo->src_port);
148 padding = 0;
150 if (fwrite(&start_sec, 4, 1, file) == 0)
151 return;
152 if (fwrite(&start_usec, 4, 1, file) == 0)
153 return;
154 if (fwrite(&source, 4, 1, file) == 0)
155 return;
156 if (fwrite(&port, 2, 1, file) == 0)
157 return;
158 if (fwrite(&padding, 2, 1, file) == 0)
159 return;
162 /* utility function for writing a sample to file in rtpdump -F dump format (.rtp)*/
163 void rtp_write_sample(rtp_sample_t* sample, FILE* file)
165 guint16 length; /* length of packet, including this header (may
166 be smaller than plen if not whole packet recorded) */
167 guint16 plen; /* actual header+payload length for RTP, 0 for RTCP */
168 guint32 offset; /* milliseconds since the start of recording */
170 length = g_htons(sample->header.frame_length + 8);
171 plen = g_htons(sample->header.frame_length);
172 offset = g_htonl(sample->header.rec_time);
174 if (fwrite(&length, 2, 1, file) == 0)
175 return;
176 if (fwrite(&plen, 2, 1, file) == 0)
177 return;
178 if (fwrite(&offset, 4, 1, file) == 0)
179 return;
180 if (fwrite(sample->frame, sample->header.frame_length, 1, file) == 0)
181 return;
185 /****************************************************************************/
186 /* whenever a RTP packet is seen by the tap listener */
187 int rtpstream_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *arg2)
189 rtpstream_tapinfo_t *tapinfo = (rtpstream_tapinfo_t *)arg;
190 const struct _rtp_info *rtpinfo = (const struct _rtp_info *)arg2;
191 rtp_stream_info_t tmp_strinfo;
192 rtp_stream_info_t *strinfo = NULL;
193 GList* list;
194 rtp_sample_t sample;
196 struct _rtp_conversation_info *p_conv_data = NULL;
198 /* gather infos on the stream this packet is part of */
199 COPY_ADDRESS(&(tmp_strinfo.src_addr), &(pinfo->src));
200 tmp_strinfo.src_port = pinfo->srcport;
201 COPY_ADDRESS(&(tmp_strinfo.dest_addr), &(pinfo->dst));
202 tmp_strinfo.dest_port = pinfo->destport;
203 tmp_strinfo.ssrc = rtpinfo->info_sync_src;
204 tmp_strinfo.pt = rtpinfo->info_payload_type;
205 tmp_strinfo.info_payload_type_str = rtpinfo->info_payload_type_str;
207 if (tapinfo->mode == TAP_ANALYSE) {
208 /* check whether we already have a stream with these parameters in the list */
209 list = g_list_first(tapinfo->strinfo_list);
210 while (list)
212 if (rtp_stream_info_cmp(&tmp_strinfo, (rtp_stream_info_t*)(list->data))==0)
214 strinfo = (rtp_stream_info_t*)(list->data); /*found!*/
215 break;
217 list = g_list_next(list);
220 /* not in the list? then create a new entry */
221 if (!strinfo) {
222 tmp_strinfo.npackets = 0;
223 tmp_strinfo.first_frame_num = pinfo->fd->num;
224 tmp_strinfo.start_sec = (guint32) pinfo->fd->abs_ts.secs;
225 tmp_strinfo.start_usec = pinfo->fd->abs_ts.nsecs/1000;
226 tmp_strinfo.start_rel_sec = (guint32) pinfo->rel_ts.secs;
227 tmp_strinfo.start_rel_usec = pinfo->rel_ts.nsecs/1000;
228 tmp_strinfo.tag_vlan_error = 0;
229 tmp_strinfo.tag_diffserv_error = 0;
230 tmp_strinfo.vlan_id = 0;
231 tmp_strinfo.problem = FALSE;
233 /* reset RTP stats */
234 tmp_strinfo.rtp_stats.first_packet = TRUE;
235 tmp_strinfo.rtp_stats.max_delta = 0;
236 tmp_strinfo.rtp_stats.max_jitter = 0;
237 tmp_strinfo.rtp_stats.mean_jitter = 0;
238 tmp_strinfo.rtp_stats.delta = 0;
239 tmp_strinfo.rtp_stats.diff = 0;
240 tmp_strinfo.rtp_stats.jitter = 0;
241 tmp_strinfo.rtp_stats.bandwidth = 0;
242 tmp_strinfo.rtp_stats.total_bytes = 0;
243 tmp_strinfo.rtp_stats.bw_start_index = 0;
244 tmp_strinfo.rtp_stats.bw_index = 0;
245 tmp_strinfo.rtp_stats.timestamp = 0;
246 tmp_strinfo.rtp_stats.max_nr = 0;
247 tmp_strinfo.rtp_stats.total_nr = 0;
248 tmp_strinfo.rtp_stats.sequence = 0;
249 tmp_strinfo.rtp_stats.start_seq_nr = 0;
250 tmp_strinfo.rtp_stats.stop_seq_nr = 0;
251 tmp_strinfo.rtp_stats.cycles = 0;
252 tmp_strinfo.rtp_stats.under = FALSE;
253 tmp_strinfo.rtp_stats.start_time = 0;
254 tmp_strinfo.rtp_stats.time = 0;
255 tmp_strinfo.rtp_stats.reg_pt = PT_UNDEFINED;
257 /* Get the Setup frame number who set this RTP stream */
258 p_conv_data = (struct _rtp_conversation_info *)p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name("rtp"), 0);
259 if (p_conv_data)
260 tmp_strinfo.setup_frame_number = p_conv_data->frame_number;
261 else
262 tmp_strinfo.setup_frame_number = 0xFFFFFFFF;
264 strinfo = g_new(rtp_stream_info_t,1);
265 *strinfo = tmp_strinfo; /* memberwise copy of struct */
266 tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
269 /* get RTP stats for the packet */
270 rtp_packet_analyse(&(strinfo->rtp_stats), pinfo, rtpinfo);
271 if (strinfo->rtp_stats.flags & STAT_FLAG_WRONG_TIMESTAMP
272 || strinfo->rtp_stats.flags & STAT_FLAG_WRONG_SEQ)
273 strinfo->problem = TRUE;
276 /* increment the packets counter for this stream */
277 ++(strinfo->npackets);
278 strinfo->stop_rel_sec = (guint32) pinfo->rel_ts.secs;
279 strinfo->stop_rel_usec = pinfo->rel_ts.nsecs/1000;
281 /* increment the packets counter of all streams */
282 ++(tapinfo->npackets);
284 return 1; /* refresh output */
286 else if (tapinfo->mode == TAP_SAVE) {
287 if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0) {
288 /* XXX - what if rtpinfo->info_all_data_present is
289 FALSE, so that we don't *have* all the data? */
290 sample.header.rec_time =
291 (pinfo->fd->abs_ts.nsecs/1000 + 1000000 - tapinfo->filter_stream_fwd->start_usec)/1000
292 + (guint32) (pinfo->fd->abs_ts.secs - tapinfo->filter_stream_fwd->start_sec - 1)*1000;
293 sample.header.frame_length = rtpinfo->info_data_len;
294 sample.frame = rtpinfo->info_data;
295 rtp_write_sample(&sample, tapinfo->save_file);
298 #ifdef __GTK_H__
299 else if (tapinfo->mode == TAP_MARK) {
300 if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0
301 || rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_rev)==0)
303 cf_mark_frame(&cfile, pinfo->fd);
306 #endif
307 return 0;
311 typedef struct _key_value {
312 guint32 key;
313 guint32 value;
314 } key_value;
317 /* RTP sampling clock rates for fixed payload types as defined in
318 http://www.iana.org/assignments/rtp-parameters */
319 static const key_value clock_map[] = {
320 {PT_PCMU, 8000},
321 {PT_1016, 8000},
322 {PT_G721, 8000},
323 {PT_GSM, 8000},
324 {PT_G723, 8000},
325 {PT_DVI4_8000, 8000},
326 {PT_DVI4_16000, 16000},
327 {PT_LPC, 8000},
328 {PT_PCMA, 8000},
329 {PT_G722, 8000},
330 {PT_L16_STEREO, 44100},
331 {PT_L16_MONO, 44100},
332 {PT_QCELP, 8000},
333 {PT_CN, 8000},
334 {PT_MPA, 90000},
335 {PT_G728, 8000},
336 {PT_G728, 8000},
337 {PT_DVI4_11025, 11025},
338 {PT_DVI4_22050, 22050},
339 {PT_G729, 8000},
340 {PT_CN_OLD, 8000},
341 {PT_CELB, 90000},
342 {PT_JPEG, 90000},
343 {PT_NV, 90000},
344 {PT_H261, 90000},
345 {PT_MPV, 90000},
346 {PT_MP2T, 90000},
347 {PT_H263, 90000},
350 #define NUM_CLOCK_VALUES (sizeof clock_map / sizeof clock_map[0])
352 static guint32
353 get_clock_rate(guint32 key)
355 size_t i;
357 for (i = 0; i < NUM_CLOCK_VALUES; i++) {
358 if (clock_map[i].key == key)
359 return clock_map[i].value;
361 return 0;
364 typedef struct _mimetype_and_clock {
365 const gchar *pt_mime_name_str;
366 guint32 value;
367 } mimetype_and_clock;
368 /* RTP sampling clock rates for
369 "In addition to the RTP payload formats (encodings) listed in the RTP
370 Payload Types table, there are additional payload formats that do not
371 have static RTP payload types assigned but instead use dynamic payload
372 type number assignment. Each payload format is named by a registered
373 MIME subtype"
374 http://www.iana.org/assignments/rtp-parameters.
376 NOTE: Please keep the mimetypes in case insensitive alphabetical order.
378 static const mimetype_and_clock mimetype_and_clock_map[] = {
379 {"AMR", 8000}, /* [RFC4867][RFC3267] */
380 {"AMR-WB", 16000}, /* [RFC4867][RFC3267] */
381 {"BMPEG", 90000}, /* [RFC2343],[RFC3555] */
382 {"BT656", 90000}, /* [RFC2431],[RFC3555] */
383 {"DV", 90000}, /* [RFC3189] */
384 {"EVRC", 8000}, /* [RFC3558] */
385 {"EVRC0", 8000}, /* [RFC4788] */
386 {"EVRC1", 8000}, /* [RFC4788] */
387 {"EVRCB", 8000}, /* [RFC4788] */
388 {"EVRCB0", 8000}, /* [RFC4788] */
389 {"EVRCB1", 8000}, /* [RFC4788] */
390 {"EVRCWB", 16000}, /* [RFC5188] */
391 {"EVRCWB0", 16000}, /* [RFC5188] */
392 {"EVRCWB1", 16000}, /* [RFC5188] */
393 {"G7221", 16000}, /* [RFC3047] */
394 {"G726-16", 8000}, /* [RFC3551][RFC4856] */
395 {"G726-24", 8000}, /* [RFC3551][RFC4856] */
396 {"G726-32", 8000}, /* [RFC3551][RFC4856] */
397 {"G726-40", 8000}, /* [RFC3551][RFC4856] */
398 {"G729D", 8000}, /* [RFC3551][RFC4856] */
399 {"G729E", 8000}, /* [RFC3551][RFC4856] */
400 {"GSM-EFR", 8000}, /* [RFC3551] */
401 {"H263-1998", 90000}, /* [RFC2429],[RFC3555] */
402 {"H263-2000", 90000}, /* [RFC2429],[RFC3555] */
403 {"H264", 90000}, /* [RFC3984] */
404 {"MP1S", 90000}, /* [RFC2250],[RFC3555] */
405 {"MP2P", 90000}, /* [RFC2250],[RFC3555] */
406 {"MP4V-ES", 90000}, /* [RFC3016] */
407 {"mpa-robust", 90000}, /* [RFC3119] */
408 {"pointer", 90000}, /* [RFC2862] */
409 {"raw", 90000}, /* [RFC4175] */
410 {"red", 1000}, /* [RFC4102] */
411 {"SMV", 8000}, /* [RFC3558] */
412 {"SMV0", 8000}, /* [RFC3558] */
413 {"t140", 1000}, /* [RFC4103] */
414 {"telephone-event", 8000}, /* [RFC4733] */
417 #define NUM_DYN_CLOCK_VALUES (sizeof mimetype_and_clock_map / sizeof mimetype_and_clock_map[0])
419 static guint32
420 get_dyn_pt_clock_rate(const gchar *payload_type_str)
422 int i;
424 /* Search for matching mimetype in reverse order to avoid false matches
425 * when pt_mime_name_str is the prefix of payload_type_str */
426 for (i = NUM_DYN_CLOCK_VALUES - 1; i > -1 ; i--) {
427 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)
428 return mimetype_and_clock_map[i].value;
431 return 0;
434 /****************************************************************************/
435 int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
436 packet_info *pinfo,
437 const struct _rtp_info *rtpinfo)
439 double current_time;
440 double current_jitter;
441 double current_diff = 0;
442 double nominaltime;
443 double arrivaltime; /* Time relative to start_time */
444 double expected_time;
445 double absskew;
446 guint32 clock_rate;
448 /* Store the current time */
449 current_time = nstime_to_msec(&pinfo->rel_ts);
451 /* Is this the first packet we got in this direction? */
452 if (statinfo->first_packet) {
453 /* Save the MAC address of the first RTP frame */
454 if( pinfo->dl_src.type == AT_ETHER){
455 COPY_ADDRESS(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src));
457 statinfo->start_seq_nr = rtpinfo->info_seq_num;
458 statinfo->stop_seq_nr = rtpinfo->info_seq_num;
459 statinfo->seq_num = rtpinfo->info_seq_num;
460 statinfo->start_time = current_time;
461 statinfo->timestamp = rtpinfo->info_timestamp;
462 statinfo->first_timestamp = rtpinfo->info_timestamp;
463 statinfo->time = current_time;
464 statinfo->lastnominaltime = 0;
465 statinfo->pt = rtpinfo->info_payload_type;
466 statinfo->reg_pt = rtpinfo->info_payload_type;
467 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
468 statinfo->bw_history[statinfo->bw_index].time = current_time;
469 statinfo->bw_index++;
470 statinfo->total_bytes += rtpinfo->info_data_len + 28;
471 statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000;
472 /* Not needed ? initialised to zero? */
473 statinfo->delta = 0;
474 statinfo->jitter = 0;
475 statinfo->diff = 0;
477 statinfo->total_nr++;
478 statinfo->flags |= STAT_FLAG_FIRST;
479 if (rtpinfo->info_marker_set) {
480 statinfo->flags |= STAT_FLAG_MARKER;
482 statinfo->first_packet = FALSE;
483 return 0;
486 /* Reset flags */
487 statinfo->flags = 0;
489 /* Chek for duplicates (src mac differs from first_packet_mac_addr) */
490 if( pinfo->dl_src.type == AT_ETHER){
491 if(!ADDRESSES_EQUAL(&(statinfo->first_packet_mac_addr), &(pinfo->dl_src))){
492 statinfo->flags |= STAT_FLAG_DUP_PKT;
493 statinfo->delta = current_time-(statinfo->time);
494 return 0;
498 /* When calculating expected rtp packets the seq number can wrap around
499 * so we have to count the number of cycles
500 * Variable cycles counts the wraps around in forwarding connection and
501 * under is flag that indicates where we are
503 * XXX How to determine number of cycles with all possible lost, late
504 * and duplicated packets without any doubt? It seems to me, that
505 * because of all possible combination of late, duplicated or lost
506 * packets, this can only be more or less good approximation
508 * There are some combinations (rare but theoretically possible),
509 * where below code won't work correctly - statistic may be wrong then.
512 /* So if the current sequence number is less than the start one
513 * we assume, that there is another cycle running
515 if ((rtpinfo->info_seq_num < statinfo->start_seq_nr) && (statinfo->under == FALSE)){
516 statinfo->cycles++;
517 statinfo->under = TRUE;
519 /* what if the start seq nr was 0? Then the above condition will never
520 * be true, so we add another condition. XXX The problem would arise
521 * if one of the packets with seq nr 0 or 65535 would be lost or late
523 else if ((rtpinfo->info_seq_num == 0) && (statinfo->stop_seq_nr == 65535) &&
524 (statinfo->under == FALSE)){
525 statinfo->cycles++;
526 statinfo->under = TRUE;
528 /* the whole round is over, so reset the flag */
529 else if ((rtpinfo->info_seq_num > statinfo->start_seq_nr) && (statinfo->under != FALSE)) {
530 statinfo->under = FALSE;
533 /* Since it is difficult to count lost, duplicate or late packets separately,
534 * we would like to know at least how many times the sequence number was not ok
537 /* If the current seq number equals the last one or if we are here for
538 * the first time, then it is ok, we just store the current one as the last one
540 if ( (statinfo->seq_num+1 == rtpinfo->info_seq_num) || (statinfo->flags & STAT_FLAG_FIRST) )
541 statinfo->seq_num = rtpinfo->info_seq_num;
542 /* If the first one is 65535 we wrap */
543 else if ( (statinfo->seq_num == 65535) && (rtpinfo->info_seq_num == 0) )
544 statinfo->seq_num = rtpinfo->info_seq_num;
545 /* Lost packets. If the prev seq is enourmously larger than the cur seq
546 * we assume that instead of being massively late we lost the packet(s)
547 * that would have indicated the sequence number wrapping. An imprecise
548 * heuristic at best, but it seems to work well enough.
549 * https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=5958 */
550 else if (statinfo->seq_num+1 < rtpinfo->info_seq_num || statinfo->seq_num - rtpinfo->info_seq_num > 0xFF00) {
551 statinfo->seq_num = rtpinfo->info_seq_num;
552 statinfo->sequence++;
553 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
555 /* Late or duplicated */
556 else if (statinfo->seq_num+1 > rtpinfo->info_seq_num) {
557 statinfo->sequence++;
558 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
561 /* Check payload type */
562 if (rtpinfo->info_payload_type == PT_CN
563 || rtpinfo->info_payload_type == PT_CN_OLD)
564 statinfo->flags |= STAT_FLAG_PT_CN;
565 if (statinfo->pt == PT_CN
566 || statinfo->pt == PT_CN_OLD)
567 statinfo->flags |= STAT_FLAG_FOLLOW_PT_CN;
568 if (rtpinfo->info_payload_type != statinfo->pt)
569 statinfo->flags |= STAT_FLAG_PT_CHANGE;
570 statinfo->pt = rtpinfo->info_payload_type;
573 * Return 0 for unknown payload types
574 * Ignore jitter calculation for clockrate = 0
576 if (statinfo->pt < 96 ){
577 clock_rate = get_clock_rate(statinfo->pt);
578 }else{ /* Dynamic PT */
579 if ( rtpinfo->info_payload_type_str != NULL ){
580 /* Is it a "telephone-event" ?
581 * Timestamp is not increased for telepone-event packets impacting
582 * calculation of Jitter Skew and clock drift.
583 * see 2.2.1 of RFC 4733
585 if (g_ascii_strncasecmp("telephone-event",rtpinfo->info_payload_type_str,(strlen("telephone-event")))==0){
586 clock_rate = 0;
587 statinfo->flags |= STAT_FLAG_PT_T_EVENT;
588 }else{
589 if(rtpinfo->info_payload_rate !=0){
590 clock_rate = rtpinfo->info_payload_rate;
591 }else{
592 clock_rate = get_dyn_pt_clock_rate(rtpinfo-> info_payload_type_str);
595 }else{
596 clock_rate = 0;
600 /* Handle wraparound ? */
601 arrivaltime = current_time - statinfo->start_time;
603 if (statinfo->first_timestamp > rtpinfo->info_timestamp){
604 /* Handle wraparound */
605 nominaltime = (double)(rtpinfo->info_timestamp + 0xffffffff - statinfo->first_timestamp + 1);
606 }else{
607 nominaltime = (double)(rtpinfo->info_timestamp - statinfo->first_timestamp);
610 /* Can only analyze defined sampling rates */
611 if (clock_rate != 0) {
612 statinfo->clock_rate = clock_rate;
613 /* Convert from sampling clock to ms */
614 nominaltime = nominaltime /(clock_rate/1000);
616 /* Calculate the current jitter(in ms) */
617 if (!statinfo->first_packet) {
618 expected_time = statinfo->time + (nominaltime - statinfo->lastnominaltime);
619 current_diff = fabs(current_time - expected_time);
620 current_jitter = (15 * statinfo->jitter + current_diff) / 16;
622 statinfo->delta = current_time-(statinfo->time);
623 statinfo->jitter = current_jitter;
624 statinfo->diff = current_diff;
626 statinfo->lastnominaltime = nominaltime;
627 /* Calculate skew, i.e. absolute jitter that also catches clock drift
628 * Skew is positive if TS (nominal) is too fast
630 statinfo->skew = nominaltime - arrivaltime;
631 absskew = fabs(statinfo->skew);
632 if(absskew > fabs(statinfo->max_skew)){
633 statinfo->max_skew = statinfo->skew;
635 /* Gather data for calculation of average, minimum and maximum framerate based on timestamp */
636 #if 0
637 if (numPackets > 0 && (!hardPayloadType || !alternatePayloadType)) {
638 /* Skip first packet and possibly alternate payload type packets */
639 double dt;
640 dt = nominaltime - statinfo->lastnominaltime;
641 sumdt += 1.0 * dt;
642 numdt += (dt != 0 ? 1 : 0);
643 mindt = (dt < mindt ? dt : mindt);
644 maxdt = (dt > maxdt ? dt : maxdt);
646 #endif
647 /* Gather data for calculation of skew least square */
648 statinfo->sumt += 1.0 * current_time;
649 statinfo->sumTS += 1.0 * nominaltime;
650 statinfo->sumt2 += 1.0 * current_time * current_time;
651 statinfo->sumtTS += 1.0 * current_time * nominaltime;
654 /* Calculate the BW in Kbps adding the IP+UDP header to the RTP -> 20bytes(IP) + 8bytes(UDP) */
655 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
656 statinfo->bw_history[statinfo->bw_index].time = current_time;
658 /* Check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */
659 while ((statinfo->bw_history[statinfo->bw_start_index].time+1000/* ms */)<current_time){
660 statinfo->total_bytes -= statinfo->bw_history[statinfo->bw_start_index].bytes;
661 statinfo->bw_start_index++;
662 if (statinfo->bw_start_index == BUFF_BW) statinfo->bw_start_index=0;
664 /* IP hdr + UDP + RTP */
665 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 /* Is it a packet with the mark bit set? */
672 if (rtpinfo->info_marker_set) {
673 statinfo->delta_timestamp = rtpinfo->info_timestamp - statinfo->timestamp;
674 if (rtpinfo->info_timestamp > statinfo->timestamp){
675 statinfo->flags |= STAT_FLAG_MARKER;
677 else{
678 statinfo->flags |= STAT_FLAG_WRONG_TIMESTAMP;
681 /* Is it a regular packet? */
682 if (!(statinfo->flags & STAT_FLAG_FIRST)
683 && !(statinfo->flags & STAT_FLAG_MARKER)
684 && !(statinfo->flags & STAT_FLAG_PT_CN)
685 && !(statinfo->flags & STAT_FLAG_WRONG_TIMESTAMP)
686 && !(statinfo->flags & STAT_FLAG_FOLLOW_PT_CN)) {
687 /* Include it in maximum delta calculation */
688 if (statinfo->delta > statinfo->max_delta) {
689 statinfo->max_delta = statinfo->delta;
690 statinfo->max_nr = pinfo->fd->num;
692 if (clock_rate != 0) {
693 /* Maximum and mean jitter calculation */
694 if (statinfo->jitter > statinfo->max_jitter) {
695 statinfo->max_jitter = statinfo->jitter;
697 statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
700 /* Regular payload change? (CN ignored) */
701 if (!(statinfo->flags & STAT_FLAG_FIRST)
702 && !(statinfo->flags & STAT_FLAG_PT_CN)) {
703 if ((statinfo->pt != statinfo->reg_pt)
704 && (statinfo->reg_pt != PT_UNDEFINED)) {
705 statinfo->flags |= STAT_FLAG_REG_PT_CHANGE;
709 /* Set regular payload*/
710 if (!(statinfo->flags & STAT_FLAG_PT_CN)) {
711 statinfo->reg_pt = statinfo->pt;
714 statinfo->time = current_time;
715 statinfo->timestamp = rtpinfo->info_timestamp;
716 statinfo->stop_seq_nr = rtpinfo->info_seq_num;
717 statinfo->total_nr++;
719 return 0;
723 * Editor modelines - http://www.wireshark.org/tools/modelines.html
725 * Local variables:
726 * c-basic-offset: 8
727 * tab-width: 8
728 * indent-tabs-mode: t
729 * End:
731 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
732 * :indentSize=8:tabSize=8:noTabs=false: