2 * RTP stream handler functions used by tshark and wireshark
6 * Copyright 2008, Ericsson AB
7 * By Balint Reczey <balint.reczey@ericsson.com>
9 * most functions are copied from gtk/rtp_stream.c and 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
41 #include <epan/rtp_pt.h>
42 #include <epan/addr_resolv.h>
43 #include <epan/dissectors/packet-rtp.h>
44 #include "gtk/rtp_stream.h"
45 #include "tap-rtp-common.h"
49 /****************************************************************************/
50 /* GCompareFunc style comparison function for _rtp_stream_info */
51 gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb)
53 const struct _rtp_stream_info* a = aa;
54 const struct _rtp_stream_info* b = bb;
58 if (a==NULL || b==NULL)
60 if (ADDRESSES_EQUAL(&(a->src_addr), &(b->src_addr))
61 && (a->src_port == b->src_port)
62 && ADDRESSES_EQUAL(&(a->dest_addr), &(b->dest_addr))
63 && (a->dest_port == b->dest_port)
64 && (a->ssrc == b->ssrc))
71 /****************************************************************************/
72 /* when there is a [re]reading of packet's */
73 void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
77 if (tapinfo->mode == TAP_ANALYSE) {
78 /* free the data items first */
79 list = g_list_first(tapinfo->strinfo_list);
83 list = g_list_next(list);
85 g_list_free(tapinfo->strinfo_list);
86 tapinfo->strinfo_list = NULL;
87 tapinfo->nstreams = 0;
88 tapinfo->npackets = 0;
91 ++(tapinfo->launch_count);
96 void rtpstream_reset_cb(void *arg)
102 * rtpdump file format
104 * The file starts with the tool to be used for playing this file,
105 * the multicast/unicast receive address and the port.
107 * #!rtpplay1.0 224.2.0.1/3456\n
109 * This is followed by one binary header (RD_hdr_t) and one RD_packet_t
110 * structure for each received packet. All fields are in network byte
111 * order. We don't need the source IP address since we can do mapping
112 * based on SSRC. This saves (a little) space, avoids non-IPv4
113 * problems and privacy/security concerns. The header is followed by
114 * the RTP/RTCP header and (optionally) the actual payload.
117 #define RTPFILE_VERSION "1.0"
120 * Write a header to the current output file.
121 * The header consists of an identifying string, followed
122 * by a binary structure.
124 void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file)
126 guint32 start_sec; /* start of recording (GMT) (seconds) */
127 guint32 start_usec; /* start of recording (GMT) (microseconds)*/
128 guint32 source; /* network source (multicast address) */
130 guint16 port; /* UDP port */
131 guint16 padding; /* 2 padding bytes */
133 fprintf(file, "#!rtpplay%s %s/%u\n", RTPFILE_VERSION,
134 get_addr_name(&(strinfo->dest_addr)),
137 start_sec = g_htonl(strinfo->start_sec);
138 start_usec = g_htonl(strinfo->start_usec);
139 /* rtpdump only accepts guint32 as source, will be fake for IPv6 */
140 memset(&source, 0, sizeof source);
141 sourcelen = strinfo->src_addr.len;
142 if (sourcelen > sizeof source)
143 sourcelen = sizeof source;
144 memcpy(&source, strinfo->src_addr.data, sourcelen);
145 port = g_htons(strinfo->src_port);
148 if (fwrite(&start_sec, 4, 1, file) == 0)
150 if (fwrite(&start_usec, 4, 1, file) == 0)
152 if (fwrite(&source, 4, 1, file) == 0)
154 if (fwrite(&port, 2, 1, file) == 0)
156 if (fwrite(&padding, 2, 1, file) == 0)
160 /* utility function for writing a sample to file in rtpdump -F dump format (.rtp)*/
161 void rtp_write_sample(rtp_sample_t* sample, FILE* file)
163 guint16 length; /* length of packet, including this header (may
164 be smaller than plen if not whole packet recorded) */
165 guint16 plen; /* actual header+payload length for RTP, 0 for RTCP */
166 guint32 offset; /* milliseconds since the start of recording */
168 length = g_htons(sample->header.frame_length + 8);
169 plen = g_htons(sample->header.frame_length);
170 offset = g_htonl(sample->header.rec_time);
172 if (fwrite(&length, 2, 1, file) == 0)
174 if (fwrite(&plen, 2, 1, file) == 0)
176 if (fwrite(&offset, 4, 1, file) == 0)
178 if (fwrite(sample->frame, sample->header.frame_length, 1, file) == 0)
183 /****************************************************************************/
184 /* whenever a RTP packet is seen by the tap listener */
185 int rtpstream_packet(void *arg, packet_info *pinfo, epan_dissect_t *edt _U_, const void *arg2)
187 rtpstream_tapinfo_t *tapinfo = arg;
188 const struct _rtp_info *rtpinfo = arg2;
189 rtp_stream_info_t tmp_strinfo;
190 rtp_stream_info_t *strinfo = NULL;
194 struct _rtp_conversation_info *p_conv_data = NULL;
196 /* gather infos on the stream this packet is part of */
197 COPY_ADDRESS(&(tmp_strinfo.src_addr), &(pinfo->src));
198 tmp_strinfo.src_port = pinfo->srcport;
199 COPY_ADDRESS(&(tmp_strinfo.dest_addr), &(pinfo->dst));
200 tmp_strinfo.dest_port = pinfo->destport;
201 tmp_strinfo.ssrc = rtpinfo->info_sync_src;
202 tmp_strinfo.pt = rtpinfo->info_payload_type;
203 tmp_strinfo.info_payload_type_str = rtpinfo->info_payload_type_str;
205 if (tapinfo->mode == TAP_ANALYSE) {
206 /* check wether we already have a stream with these parameters in the list */
207 list = g_list_first(tapinfo->strinfo_list);
210 if (rtp_stream_info_cmp(&tmp_strinfo, (rtp_stream_info_t*)(list->data))==0)
212 strinfo = (rtp_stream_info_t*)(list->data); /*found!*/
215 list = g_list_next(list);
218 /* not in the list? then create a new entry */
220 tmp_strinfo.npackets = 0;
221 tmp_strinfo.first_frame_num = pinfo->fd->num;
222 tmp_strinfo.start_sec = (guint32) pinfo->fd->abs_ts.secs;
223 tmp_strinfo.start_usec = pinfo->fd->abs_ts.nsecs/1000;
224 tmp_strinfo.start_rel_sec = (guint32) pinfo->fd->rel_ts.secs;
225 tmp_strinfo.start_rel_usec = pinfo->fd->rel_ts.nsecs/1000;
226 tmp_strinfo.tag_vlan_error = 0;
227 tmp_strinfo.tag_diffserv_error = 0;
228 tmp_strinfo.vlan_id = 0;
229 tmp_strinfo.problem = FALSE;
231 /* reset RTP stats */
232 tmp_strinfo.rtp_stats.first_packet = TRUE;
233 tmp_strinfo.rtp_stats.max_delta = 0;
234 tmp_strinfo.rtp_stats.max_jitter = 0;
235 tmp_strinfo.rtp_stats.mean_jitter = 0;
236 tmp_strinfo.rtp_stats.delta = 0;
237 tmp_strinfo.rtp_stats.diff = 0;
238 tmp_strinfo.rtp_stats.jitter = 0;
239 tmp_strinfo.rtp_stats.bandwidth = 0;
240 tmp_strinfo.rtp_stats.total_bytes = 0;
241 tmp_strinfo.rtp_stats.bw_start_index = 0;
242 tmp_strinfo.rtp_stats.bw_index = 0;
243 tmp_strinfo.rtp_stats.timestamp = 0;
244 tmp_strinfo.rtp_stats.max_nr = 0;
245 tmp_strinfo.rtp_stats.total_nr = 0;
246 tmp_strinfo.rtp_stats.sequence = 0;
247 tmp_strinfo.rtp_stats.start_seq_nr = 0;
248 tmp_strinfo.rtp_stats.stop_seq_nr = 0;
249 tmp_strinfo.rtp_stats.cycles = 0;
250 tmp_strinfo.rtp_stats.under = FALSE;
251 tmp_strinfo.rtp_stats.start_time = 0;
252 tmp_strinfo.rtp_stats.time = 0;
253 tmp_strinfo.rtp_stats.reg_pt = PT_UNDEFINED;
255 /* Get the Setup frame number who set this RTP stream */
256 p_conv_data = p_get_proto_data(pinfo->fd, proto_get_id_by_filter_name("rtp"));
258 tmp_strinfo.setup_frame_number = p_conv_data->frame_number;
260 tmp_strinfo.setup_frame_number = 0xFFFFFFFF;
262 strinfo = g_malloc(sizeof(rtp_stream_info_t));
263 *strinfo = tmp_strinfo; /* memberwise copy of struct */
264 tapinfo->strinfo_list = g_list_append(tapinfo->strinfo_list, strinfo);
267 /* get RTP stats for the packet */
268 rtp_packet_analyse(&(strinfo->rtp_stats), pinfo, rtpinfo);
269 if (strinfo->rtp_stats.flags & STAT_FLAG_WRONG_TIMESTAMP
270 || strinfo->rtp_stats.flags & STAT_FLAG_WRONG_SEQ)
271 strinfo->problem = TRUE;
274 /* increment the packets counter for this stream */
275 ++(strinfo->npackets);
276 strinfo->stop_rel_sec = (guint32) pinfo->fd->rel_ts.secs;
277 strinfo->stop_rel_usec = pinfo->fd->rel_ts.nsecs/1000;
279 /* increment the packets counter of all streams */
280 ++(tapinfo->npackets);
282 return 1; /* refresh output */
284 else if (tapinfo->mode == TAP_SAVE) {
285 if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0) {
286 /* XXX - what if rtpinfo->info_all_data_present is
287 FALSE, so that we don't *have* all the data? */
288 sample.header.rec_time =
289 (pinfo->fd->abs_ts.nsecs/1000 + 1000000 - tapinfo->filter_stream_fwd->start_usec)/1000
290 + (guint32) (pinfo->fd->abs_ts.secs - tapinfo->filter_stream_fwd->start_sec - 1)*1000;
291 sample.header.frame_length = rtpinfo->info_data_len;
292 sample.frame = rtpinfo->info_data;
293 rtp_write_sample(&sample, tapinfo->save_file);
296 else if (tapinfo->mode == TAP_MARK) {
298 if (rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_fwd)==0
299 || rtp_stream_info_cmp(&tmp_strinfo, tapinfo->filter_stream_rev)==0)
301 cf_mark_frame(&cfile, pinfo->fd);
309 typedef struct _key_value {
315 /* RTP sampling clock rates for fixed payload types as defined in
316 http://www.iana.org/assignments/rtp-parameters */
317 static const key_value clock_map[] = {
323 {PT_DVI4_8000, 8000},
324 {PT_DVI4_16000, 16000},
328 {PT_L16_STEREO, 44100},
329 {PT_L16_MONO, 44100},
335 {PT_DVI4_11025, 11025},
336 {PT_DVI4_22050, 22050},
348 #define NUM_CLOCK_VALUES (sizeof clock_map / sizeof clock_map[0])
351 get_clock_rate(guint32 key)
355 for (i = 0; i < NUM_CLOCK_VALUES; i++) {
356 if (clock_map[i].key == key)
357 return clock_map[i].value;
362 typedef struct _mimetype_and_clock {
363 const gchar *pt_mime_name_str;
365 } mimetype_and_clock;
366 /* RTP sampling clock rates for
367 "In addition to the RTP payload formats (encodings) listed in the RTP
368 Payload Types table, there are additional payload formats that do not
369 have static RTP payload types assigned but instead use dynamic payload
370 type number assignment. Each payload format is named by a registered
372 http://www.iana.org/assignments/rtp-parameters.
374 static const mimetype_and_clock mimetype_and_clock_map[] = {
375 {"AMR", 8000}, /* [RFC3267] */
376 {"AMR-WB", 16000}, /* [RFC3267] */
377 {"EVRC", 8000}, /* [RFC3558] */
378 {"EVRC0", 8000}, /* [RFC3558] */
379 {"G7221", 16000}, /* [RFC3047] */
380 {"G726-16", 8000}, /* [RFC3551] */
381 {"G726-24", 8000}, /* [RFC3551] */
382 {"G726-32", 8000}, /* [RFC3551] */
383 {"G726-40", 8000}, /* [RFC3551] */
384 {"G729D", 8000}, /* [RFC3551] */
385 {"G729E", 8000}, /* [RFC3551] */
386 {"GSM-EFR", 8000}, /* [RFC3551] */
387 {"mpa-robust", 90000}, /* [RFC3119] */
388 {"SMV", 8000}, /* [RFC3558] */
389 {"SMV0", 8000}, /* [RFC3558] */
390 {"red", 1000}, /* [RFC4102] */
391 {"t140", 1000}, /* [RFC4103] */
392 {"BMPEG", 90000}, /* [RFC2343],[RFC3555] */
393 {"BT656", 90000}, /* [RFC2431],[RFC3555] */
394 {"DV", 90000}, /* [RFC3189] */
395 {"H263-1998", 90000}, /* [RFC2429],[RFC3555] */
396 {"H263-2000", 90000}, /* [RFC2429],[RFC3555] */
397 {"MP1S", 90000}, /* [RFC2250],[RFC3555] */
398 {"MP2P", 90000}, /* [RFC2250],[RFC3555] */
399 {"MP4V-ES", 90000}, /* [RFC3016] */
400 {"pointer", 90000}, /* [RFC2862] */
401 {"raw", 90000}, /* [RFC4175] */
402 {"telephone-event", 8000}, /* [RFC4733] */
405 #define NUM_DYN_CLOCK_VALUES (sizeof mimetype_and_clock_map / sizeof mimetype_and_clock_map[0])
408 get_dyn_pt_clock_rate(gchar *payload_type_str)
412 for (i = 0; i < NUM_DYN_CLOCK_VALUES; i++) {
413 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)
414 return mimetype_and_clock_map[i].value;
420 /****************************************************************************/
421 int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
423 const struct _rtp_info *rtpinfo)
426 double current_jitter;
431 /* check payload type */
432 if (rtpinfo->info_payload_type == PT_CN
433 || rtpinfo->info_payload_type == PT_CN_OLD)
434 statinfo->flags |= STAT_FLAG_PT_CN;
435 if (statinfo->pt == PT_CN
436 || statinfo->pt == PT_CN_OLD)
437 statinfo->flags |= STAT_FLAG_FOLLOW_PT_CN;
438 if (rtpinfo->info_payload_type != statinfo->pt)
439 statinfo->flags |= STAT_FLAG_PT_CHANGE;
440 statinfo->pt = rtpinfo->info_payload_type;
442 * XXX - should "get_clock_rate()" return 0 for unknown
443 * payload types, presumably meaning that we should
444 * just ignore this packet?
446 if (statinfo->pt < 96 ){
447 clock_rate = get_clock_rate(statinfo->pt);
448 }else{ /* dynamic PT */
449 if ( rtpinfo->info_payload_type_str != NULL )
450 clock_rate = get_dyn_pt_clock_rate(rtpinfo-> info_payload_type_str);
455 /* store the current time and calculate the current jitter */
456 current_time = nstime_to_sec(&pinfo->fd->rel_ts);
457 current_diff = fabs (current_time - (statinfo->time) - ((double)(rtpinfo->info_timestamp)-(double)(statinfo->timestamp))/clock_rate);
458 current_jitter = statinfo->jitter + ( current_diff - statinfo->jitter)/16;
459 statinfo->delta = current_time-(statinfo->time);
460 statinfo->jitter = current_jitter;
461 statinfo->diff = current_diff;
463 /* calculate the BW in Kbps adding the IP+UDP header to the RTP -> 20bytes(IP)+8bytes(UDP) = 28bytes */
464 statinfo->bw_history[statinfo->bw_index].bytes = rtpinfo->info_data_len + 28;
465 statinfo->bw_history[statinfo->bw_index].time = current_time;
466 /* check if there are more than 1sec in the history buffer to calculate BW in bps. If so, remove those for the calculation */
467 while ((statinfo->bw_history[statinfo->bw_start_index].time+1)<current_time){
468 statinfo->total_bytes -= statinfo->bw_history[statinfo->bw_start_index].bytes;
469 statinfo->bw_start_index++;
470 if (statinfo->bw_start_index == BUFF_BW) statinfo->bw_start_index=0;
472 statinfo->total_bytes += rtpinfo->info_data_len + 28;
473 statinfo->bandwidth = (double)(statinfo->total_bytes*8)/1000;
474 statinfo->bw_index++;
475 if (statinfo->bw_index == BUFF_BW) statinfo->bw_index = 0;
478 /* is this the first packet we got in this direction? */
479 if (statinfo->first_packet) {
480 statinfo->start_seq_nr = rtpinfo->info_seq_num;
481 statinfo->start_time = current_time;
483 statinfo->jitter = 0;
485 statinfo->flags |= STAT_FLAG_FIRST;
486 statinfo->first_packet = FALSE;
488 /* is it a packet with the mark bit set? */
489 if (rtpinfo->info_marker_set) {
490 statinfo->delta_timestamp = rtpinfo->info_timestamp - statinfo->timestamp;
491 if (rtpinfo->info_timestamp > statinfo->timestamp){
492 statinfo->flags |= STAT_FLAG_MARKER;
495 statinfo->flags |= STAT_FLAG_WRONG_TIMESTAMP;
498 /* is it a regular packet? */
499 if (!(statinfo->flags & STAT_FLAG_FIRST)
500 && !(statinfo->flags & STAT_FLAG_MARKER)
501 && !(statinfo->flags & STAT_FLAG_PT_CN)
502 && !(statinfo->flags & STAT_FLAG_WRONG_TIMESTAMP)
503 && !(statinfo->flags & STAT_FLAG_FOLLOW_PT_CN)) {
504 /* include it in maximum delta calculation */
505 if (statinfo->delta > statinfo->max_delta) {
506 statinfo->max_delta = statinfo->delta;
507 statinfo->max_nr = pinfo->fd->num;
509 /* maximum and mean jitter calculation */
510 if (statinfo->jitter > statinfo->max_jitter) {
511 statinfo->max_jitter = statinfo->jitter;
513 statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
515 /* regular payload change? (CN ignored) */
516 if (!(statinfo->flags & STAT_FLAG_FIRST)
517 && !(statinfo->flags & STAT_FLAG_PT_CN)) {
518 if ((statinfo->pt != statinfo->reg_pt)
519 && (statinfo->reg_pt != PT_UNDEFINED)) {
520 statinfo->flags |= STAT_FLAG_REG_PT_CHANGE;
524 /* set regular payload*/
525 if (!(statinfo->flags & STAT_FLAG_PT_CN)) {
526 statinfo->reg_pt = statinfo->pt;
530 /* When calculating expected rtp packets the seq number can wrap around
531 * so we have to count the number of cycles
532 * Variable cycles counts the wraps around in forwarding connection and
533 * under is flag that indicates where we are
535 * XXX how to determine number of cycles with all possible lost, late
536 * and duplicated packets without any doubt? It seems to me, that
537 * because of all possible combination of late, duplicated or lost
538 * packets, this can only be more or less good approximation
540 * There are some combinations (rare but theoretically possible),
541 * where below code won't work correctly - statistic may be wrong then.
544 /* so if the current sequence number is less than the start one
545 * we assume, that there is another cycle running */
546 if ((rtpinfo->info_seq_num < statinfo->start_seq_nr) && (statinfo->under == FALSE)){
548 statinfo->under = TRUE;
550 /* what if the start seq nr was 0? Then the above condition will never
551 * be true, so we add another condition. XXX The problem would arise
552 * if one of the packets with seq nr 0 or 65535 would be lost or late */
553 else if ((rtpinfo->info_seq_num == 0) && (statinfo->stop_seq_nr == 65535) &&
554 (statinfo->under == FALSE)){
556 statinfo->under = TRUE;
558 /* the whole round is over, so reset the flag */
559 else if ((rtpinfo->info_seq_num > statinfo->start_seq_nr) && (statinfo->under != FALSE)) {
560 statinfo->under = FALSE;
563 /* Since it is difficult to count lost, duplicate or late packets separately,
564 * we would like to know at least how many times the sequence number was not ok */
566 /* if the current seq number equals the last one or if we are here for
567 * the first time, then it is ok, we just store the current one as the last one */
568 if ( (statinfo->seq_num+1 == rtpinfo->info_seq_num) || (statinfo->flags & STAT_FLAG_FIRST) )
569 statinfo->seq_num = rtpinfo->info_seq_num;
570 /* if the first one is 65535. XXX same problem as above: if seq 65535 or 0 is lost... */
571 else if ( (statinfo->seq_num == 65535) && (rtpinfo->info_seq_num == 0) )
572 statinfo->seq_num = rtpinfo->info_seq_num;
574 else if (statinfo->seq_num+1 < rtpinfo->info_seq_num) {
575 statinfo->seq_num = rtpinfo->info_seq_num;
576 statinfo->sequence++;
577 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
579 /* late or duplicated */
580 else if (statinfo->seq_num+1 > rtpinfo->info_seq_num) {
581 statinfo->sequence++;
582 statinfo->flags |= STAT_FLAG_WRONG_SEQ;
584 statinfo->time = current_time;
585 statinfo->timestamp = rtpinfo->info_timestamp;
586 statinfo->stop_seq_nr = rtpinfo->info_seq_num;
587 statinfo->total_nr++;