Add the missing files from Balint Reczey's patch for bug 2233.
[obnox/wireshark/wip.git] / tap-rtp-common.c
1 /* tap-rtp-common.c
2  * RTP stream handler functions used by tshark and wireshark
3  *
4  * $Id$
5  *
6  * Copyright 2008, Ericsson AB
7  * By Balint Reczey <balint.reczey@ericsson.com>
8  *
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>
12  *
13  * Wireshark - Network traffic analyzer
14  * By Gerald Combs <gerald@wireshark.org>
15  * Copyright 1998 Gerald Combs
16  *
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.
21  *
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.
26  *
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.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include "globals.h"
37
38 #include <epan/tap.h>
39 #include "register.h"
40 #include <string.h>
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"
46
47
48
49 /****************************************************************************/
50 /* GCompareFunc style comparison function for _rtp_stream_info */
51 gint rtp_stream_info_cmp(gconstpointer aa, gconstpointer bb)
52 {
53         const struct _rtp_stream_info* a = aa;
54         const struct _rtp_stream_info* b = bb;
55
56         if (a==b)
57                 return 0;
58         if (a==NULL || b==NULL)
59                 return 1;
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))
65                 return 0;
66         else
67                 return 1;
68 }
69
70
71 /****************************************************************************/
72 /* when there is a [re]reading of packet's */
73 void rtpstream_reset(rtpstream_tapinfo_t *tapinfo)
74 {
75         GList* list;
76
77         if (tapinfo->mode == TAP_ANALYSE) {
78                 /* free the data items first */
79                 list = g_list_first(tapinfo->strinfo_list);
80                 while (list)
81                 {
82                         g_free(list->data);
83                         list = g_list_next(list);
84                 }
85                 g_list_free(tapinfo->strinfo_list);
86                 tapinfo->strinfo_list = NULL;
87                 tapinfo->nstreams = 0;
88                 tapinfo->npackets = 0;
89         }
90
91         ++(tapinfo->launch_count);
92
93         return;
94 }
95
96 void rtpstream_reset_cb(void *arg)
97 {
98         rtpstream_reset(arg);
99 }
100
101 /*
102 * rtpdump file format
103 *
104 * The file starts with the tool to be used for playing this file,
105 * the multicast/unicast receive address and the port.
106 *
107 * #!rtpplay1.0 224.2.0.1/3456\n
108 *
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.
115 */
116
117 #define RTPFILE_VERSION "1.0"
118
119 /*
120 * Write a header to the current output file.
121 * The header consists of an identifying string, followed
122 * by a binary structure.
123 */
124 void rtp_write_header(rtp_stream_info_t *strinfo, FILE *file)
125 {
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) */
129         size_t sourcelen;
130         guint16 port;          /* UDP port */
131         guint16 padding;       /* 2 padding bytes */
132         
133         fprintf(file, "#!rtpplay%s %s/%u\n", RTPFILE_VERSION,
134                 get_addr_name(&(strinfo->dest_addr)),
135                 strinfo->dest_port);
136
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);
146         padding = 0;
147
148         if (fwrite(&start_sec, 4, 1, file) == 0)
149                 return;
150         if (fwrite(&start_usec, 4, 1, file) == 0)
151                 return;
152         if (fwrite(&source, 4, 1, file) == 0)
153                 return;
154         if (fwrite(&port, 2, 1, file) == 0)
155                 return;
156         if (fwrite(&padding, 2, 1, file) == 0)
157                 return;
158 }
159
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)
162 {
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 */
167
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);
171
172         if (fwrite(&length, 2, 1, file) == 0)
173                 return;
174         if (fwrite(&plen, 2, 1, file) == 0)
175                 return;
176         if (fwrite(&offset, 4, 1, file) == 0)
177                 return;
178         if (fwrite(sample->frame, sample->header.frame_length, 1, file) == 0)
179                 return;
180 }
181
182
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)
186 {
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;
191         GList* list;
192         rtp_sample_t sample;
193
194         struct _rtp_conversation_info *p_conv_data = NULL;
195
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;
204
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);
208                 while (list)
209                 {
210                         if (rtp_stream_info_cmp(&tmp_strinfo, (rtp_stream_info_t*)(list->data))==0)
211                         {
212                                 strinfo = (rtp_stream_info_t*)(list->data);  /*found!*/
213                                 break;
214                         }
215                         list = g_list_next(list);
216                 }
217
218                 /* not in the list? then create a new entry */
219                 if (!strinfo) {
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;
230
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;
254
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"));
257             if (p_conv_data)
258                                 tmp_strinfo.setup_frame_number = p_conv_data->frame_number;
259             else
260                 tmp_strinfo.setup_frame_number = 0xFFFFFFFF;
261
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);
265                 }
266
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;
272
273
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;
278
279                 /* increment the packets counter of all streams */
280                 ++(tapinfo->npackets);
281                 
282                 return 1;  /* refresh output */
283         }
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);
294                 }
295         }
296         else if (tapinfo->mode == TAP_MARK) {
297
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)
300                 {
301                         cf_mark_frame(&cfile, pinfo->fd);
302                 }
303         }
304
305         return 0;
306 }
307
308
309 typedef struct _key_value {
310   guint32  key;
311   guint32  value;
312 } key_value;
313
314
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[] = {
318         {PT_PCMU,       8000},
319         {PT_1016,       8000},
320         {PT_G721,       8000},
321         {PT_GSM,        8000},
322         {PT_G723,       8000},
323         {PT_DVI4_8000,  8000},
324         {PT_DVI4_16000, 16000},
325         {PT_LPC,        8000},
326         {PT_PCMA,       8000},
327         {PT_G722,       8000},
328         {PT_L16_STEREO, 44100},
329         {PT_L16_MONO,   44100},
330         {PT_QCELP,      8000},
331         {PT_CN,         8000},
332         {PT_MPA,        90000},
333         {PT_G728,       8000},
334         {PT_G728,       8000},
335         {PT_DVI4_11025, 11025},
336         {PT_DVI4_22050, 22050},
337         {PT_G729,       8000},
338         {PT_CN_OLD,     8000},
339         {PT_CELB,       90000},
340         {PT_JPEG,       90000},
341         {PT_NV,         90000},
342         {PT_H261,       90000},
343         {PT_MPV,        90000},
344         {PT_MP2T,       90000},
345         {PT_H263,       90000},
346 };
347
348 #define NUM_CLOCK_VALUES        (sizeof clock_map / sizeof clock_map[0])
349
350 static guint32
351 get_clock_rate(guint32 key)
352 {
353         size_t i;
354
355         for (i = 0; i < NUM_CLOCK_VALUES; i++) {
356                 if (clock_map[i].key == key)
357                         return clock_map[i].value;
358         }
359         return 1;
360 }
361
362 typedef struct _mimetype_and_clock {
363         const gchar   *pt_mime_name_str;
364         guint32 value;
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
371         MIME subtype"
372         http://www.iana.org/assignments/rtp-parameters.
373 */
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] */
403 };
404
405 #define NUM_DYN_CLOCK_VALUES    (sizeof mimetype_and_clock_map / sizeof mimetype_and_clock_map[0])
406
407 static guint32
408 get_dyn_pt_clock_rate(gchar *payload_type_str)
409 {
410         size_t i;
411
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;
415         }
416
417         return 1;
418 }
419
420 /****************************************************************************/
421 int rtp_packet_analyse(tap_rtp_stat_t *statinfo,
422                               packet_info *pinfo,
423                               const struct _rtp_info *rtpinfo)
424 {
425         double current_time;
426         double current_jitter;
427         double current_diff;
428         guint32 clock_rate;
429
430         statinfo->flags = 0;
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;
441         /*
442          * XXX - should "get_clock_rate()" return 0 for unknown
443          * payload types, presumably meaning that we should
444          * just ignore this packet?
445          */
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);
451                 else
452                         clock_rate = 1;
453         }
454
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;
462
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;
471         };
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;
476
477
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;
482                 statinfo->delta = 0;
483                 statinfo->jitter = 0;
484                 statinfo->diff = 0;
485                 statinfo->flags |= STAT_FLAG_FIRST;
486                 statinfo->first_packet = FALSE;
487         }
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;
493                 }
494                 else{
495                         statinfo->flags |= STAT_FLAG_WRONG_TIMESTAMP;
496                 }
497         }
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;
508                 }
509                 /* maximum and mean jitter calculation */
510                 if (statinfo->jitter > statinfo->max_jitter) {
511                         statinfo->max_jitter = statinfo->jitter;
512                 }
513                 statinfo->mean_jitter = (statinfo->mean_jitter*statinfo->total_nr + current_diff) / (statinfo->total_nr+1);
514         }
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;
521                 }
522         }
523
524         /* set regular payload*/
525         if (!(statinfo->flags & STAT_FLAG_PT_CN)) {
526                 statinfo->reg_pt = statinfo->pt;
527         }
528
529
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
534         *
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
539         *
540         * There are some combinations (rare but theoretically possible),
541         * where below code won't work correctly - statistic may be wrong then.
542         */
543
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)){
547                 statinfo->cycles++;
548                 statinfo->under = TRUE;
549         }
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)){
555                 statinfo->cycles++;
556                 statinfo->under = TRUE;
557         }
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;
561         }
562
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 */
565
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;
573         /* lost packets */
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;
578         }
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;
583         }
584         statinfo->time = current_time;
585         statinfo->timestamp = rtpinfo->info_timestamp;
586         statinfo->stop_seq_nr = rtpinfo->info_seq_num;
587         statinfo->total_nr++;
588
589         return 0;
590 }
591
592