Coverage Report

Created: 2025-07-12 06:36

/src/rtpproxy/src/rtp_analyze.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2009 Sippy Software, Inc., http://www.sippysoft.com
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 *
26
 */
27
28
#include <sys/types.h>
29
#include <stdint.h>
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <string.h>
33
34
#include "config.h"
35
36
#include "rtpp_types.h"
37
#include "rtpp_ssrc.h"
38
#include "rtpa_stats.h"
39
#include "rtpp_debug.h"
40
#include "rtpp_mallocs.h"
41
#include "rtpp_log.h"
42
#include "rtpp_log_obj.h"
43
#include "rtp_info.h"
44
#include "rtp.h"
45
#include "rtp_analyze.h"
46
#include "rtpp_math.h"
47
#include "rtpp_codeptr.h"
48
#include "rtpp_refcnt.h"
49
#include "rtpp_ringbuf.h"
50
51
#define FIX_TIMESTAMP_RESET    1
52
#define DEBUG_TIMESTAMP_RESET  1
53
54
struct rtp_analyze_jdata;
55
56
struct rtp_analyze_jitter {
57
    int jdlen;
58
    double jmax_acum;
59
    double jtotal_acum;
60
    long long jvcount_acum;
61
    long long pcount_acum;
62
    struct rtp_analyze_jdata *first;
63
};
64
65
struct rtp_analyze_jdata_ssrc {
66
    uint64_t prev_rtime_ts;
67
    uint32_t prev_ts;
68
#if FIX_TIMESTAMP_RESET
69
    long long ts_rcount;
70
    long long ts_jcount;
71
#endif
72
    long long ts_dcount;
73
    long long seq_rcount;
74
    double jlast;
75
    double jmax;
76
    double jtotal;
77
    long long pcount;
78
};
79
80
struct rtp_analyze_jdata {
81
    struct rtp_analyze_jdata_ssrc jss;
82
    struct rtpp_ringbuf *ts_dedup;
83
    struct rtpp_ssrc ssrc;
84
    struct rtp_analyze_jdata *next;
85
};
86
87
static double
88
rtp_ts2dtime(int ts_rate, uint32_t ts)
89
0
{
90
91
0
    return ((double)ts) / ((double)ts_rate);
92
0
}
93
94
static uint64_t
95
rtp_dtime2time_ts64(int ts_rate, double dtime)
96
0
{
97
98
0
    return (uint64_t)(dtime * (double)ts_rate);
99
0
}
100
101
/* rlog can be null in this context, when compiled for the extractaudio context */
102
#define LOGD_IF_NOT_NULL(log, args...) \
103
0
    if ((log) != NULL) { \
104
0
        RTPP_LOG((log), RTPP_LOG_DBUG, ## args); \
105
0
    }
106
#define LOGI_IF_NOT_NULL(log, args...) \
107
    if ((log) != NULL) { \
108
        RTPP_LOG((log), RTPP_LOG_INFO, ## args); \
109
    }
110
111
0
#define RTP_NORMAL     0
112
0
#define RTP_SEQ_RESET  1
113
0
#define RTP_SSRC_RESET 2
114
115
0
#define RTPC_JDATA_MAX 10
116
117
static void
118
update_jitter_stats(struct rtp_analyze_jdata *jdp, struct rtp_info *rinfo,
119
  double rtime, int hint, struct rtpp_log *rlog)
120
0
{
121
0
    int64_t dval;
122
0
    uint64_t rtime_ts, wrcorr;
123
0
#if FIX_TIMESTAMP_RESET
124
0
    int64_t rtime_ts_delta;
125
0
#endif
126
127
0
    rtime_ts = rtp_dtime2time_ts64(rinfo->rtp_profile->ts_rate, rtime);
128
0
    if (rinfo->rtp_profile->pt_kind == RTP_PTK_AUDIO &&
129
0
      CALL_SMETHOD(jdp->ts_dedup, locate, &rinfo->ts) >= 0) {
130
0
        jdp->jss.ts_dcount++;
131
0
        if (jdp->jss.pcount == 1) {
132
0
            jdp->jss.prev_rtime_ts = rtime_ts;
133
0
            jdp->jss.prev_ts = rinfo->ts;
134
0
        }
135
0
        return;
136
0
    }
137
0
    if (jdp->jss.prev_rtime_ts != 0) {
138
0
        if (hint == RTP_SEQ_RESET) {
139
0
            jdp->jss.seq_rcount++;
140
0
            goto saveandexit;
141
0
        }
142
0
#if FIX_TIMESTAMP_RESET
143
0
        rtime_ts_delta = jdp->jss.prev_rtime_ts - rtime_ts;
144
0
#endif
145
0
        if (jdp->jss.prev_ts > rinfo->ts) {
146
0
            if (((uint64_t)jdp->jss.prev_ts - (uint64_t)rinfo->ts) > ((uint32_t)1 << 31)) {
147
                /* Normal case, timestamp wrap */
148
0
                wrcorr = (uint64_t)1 << 32;
149
0
#if FIX_TIMESTAMP_RESET
150
0
            } else if (rtime_ts_delta != 0 && ((uint64_t)jdp->jss.prev_ts - (uint64_t)rinfo->ts) >
151
0
              ABS(rtime_ts_delta) * 50) {
152
                /* Timestamp reset */
153
0
#if DEBUG_TIMESTAMP_RESET
154
0
                LOGD_IF_NOT_NULL(rlog, "update_jitter_stats() : timestamp reset : " SSRC_FMT ", %lld, %llu",
155
0
                  rinfo->ssrc, T_printf(ABS(rtime_ts_delta)),
156
0
                  T_printf((uint64_t)jdp->jss.prev_ts - (uint64_t)rinfo->ts));
157
0
#endif
158
0
                jdp->jss.ts_rcount++;
159
0
                goto saveandexit;
160
0
#endif
161
0
            } else {
162
0
                wrcorr = 0;
163
0
            }
164
0
        } else {
165
0
# if FIX_TIMESTAMP_RESET
166
0
            if (rtime_ts_delta != 0 && ((uint64_t)rinfo->ts - (uint64_t)jdp->jss.prev_ts) >
167
0
              ABS(rtime_ts_delta) * 1024) {
168
                /* Timestamp jump */
169
0
#if DEBUG_TIMESTAMP_RESET
170
0
                LOGD_IF_NOT_NULL(rlog,"update_jitter_stats() : timestamp jump : " SSRC_FMT ", %lld, %lld",
171
0
                  rinfo->ssrc, T_printf(ABS(rtime_ts_delta)),
172
0
                  T_printf((uint64_t)rinfo->ts - (uint64_t)jdp->jss.prev_ts));
173
0
#endif
174
0
                jdp->jss.ts_jcount++;
175
0
                goto saveandexit;
176
0
            }
177
0
#endif
178
0
            wrcorr = 0;
179
0
        }
180
0
        dval = (rtime_ts - ((uint64_t)rinfo->ts + wrcorr)) -
181
0
          (jdp->jss.prev_rtime_ts - (uint64_t)jdp->jss.prev_ts);
182
0
#if DEBUG_TIMESTAMP_RESET
183
0
        if (dval > 10000)
184
0
            LOGD_IF_NOT_NULL(rlog, "##### LARGE VALUE #####" SSRC_FMT ",%lld,%llu,%u,%llu,%u,%llu,%lld",
185
0
              rinfo->ssrc, jdp->jss.pcount, T_printf(rtime_ts), rinfo->ts,
186
0
              T_printf(jdp->jss.prev_rtime_ts), jdp->jss.prev_ts,
187
0
              T_printf(wrcorr), T_printf(dval));
188
0
#endif
189
0
        jdp->jss.jlast = jdp->jss.jlast + (double)(ABS(dval) - jdp->jss.jlast) / 16.0;
190
0
        if (jdp->jss.jlast > jdp->jss.jmax) {
191
0
            jdp->jss.jmax = jdp->jss.jlast;
192
0
        }
193
0
        jdp->jss.jtotal += jdp->jss.jlast;
194
0
    }
195
0
    RTPP_DBGCODE(analyze > 1) {
196
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT ",%lld,%llu,%u,%f", rinfo->ssrc, jdp->jss.pcount,
197
0
          T_printf(rtime_ts), rinfo->ts, jdp->jss.jlast);
198
0
    }
199
0
    jdp->jss.pcount++;
200
0
saveandexit:
201
0
    if (rinfo->rtp_profile->pt_kind == RTP_PTK_AUDIO) {
202
0
        CALL_SMETHOD(jdp->ts_dedup, push, &rinfo->ts);
203
0
    }
204
0
    jdp->jss.prev_rtime_ts = rtime_ts;
205
0
    jdp->jss.prev_ts = rinfo->ts;
206
0
}
207
208
static struct rtp_analyze_jitter *rtp_analyze_jt_ctor(void);
209
210
int
211
rtpp_stats_init(struct rtpp_session_stat *stat)
212
0
{
213
214
0
    memset(stat, '\0', sizeof(struct rtpp_session_stat));
215
0
    stat->jdata = rtp_analyze_jt_ctor();
216
0
    if (stat->jdata == NULL) {
217
0
        return (-1);
218
0
    }
219
0
    stat->last.pt = PT_UNKN;
220
0
    return (0);
221
0
}
222
223
static struct rtp_analyze_jdata *
224
rtp_analyze_jdata_ctor()
225
0
{
226
0
    struct rtp_analyze_jdata *jdp;
227
228
0
    jdp = rtpp_zmalloc(sizeof(*jdp));
229
0
    if (jdp == NULL) {
230
0
        goto e0;
231
0
    }
232
0
    jdp->ts_dedup = rtpp_ringbuf_ctor(sizeof(jdp->jss.prev_ts), 10);
233
0
    if (jdp->ts_dedup == NULL) {
234
0
        goto e1;
235
0
    }
236
0
    return (jdp);
237
238
0
e1:
239
0
    free(jdp);
240
0
e0:
241
0
    return (NULL);
242
0
}
243
244
static struct rtp_analyze_jitter *
245
rtp_analyze_jt_ctor()
246
0
{
247
0
    struct rtp_analyze_jitter *jp;
248
249
0
    jp = rtpp_zmalloc(sizeof(*jp));
250
0
    if (jp == NULL) {
251
0
        goto e0;
252
0
    }
253
0
    jp->first = rtp_analyze_jdata_ctor();
254
0
    if (jp->first == NULL) {
255
0
        goto e1;
256
0
    }
257
0
    jp->jdlen = 1;
258
0
    return (jp);
259
260
0
e1:
261
0
    free(jp);
262
0
e0:
263
0
    return (NULL);
264
0
}
265
266
267
static void rtp_analyze_jt_destroy(struct rtp_analyze_jitter *);
268
269
void
270
rtpp_stats_destroy(struct rtpp_session_stat *stat)
271
0
{
272
273
0
    rtp_analyze_jt_destroy(stat->jdata);
274
0
}
275
276
static void
277
rtp_analyze_jt_destroy(struct rtp_analyze_jitter *jp)
278
0
{
279
0
    struct rtp_analyze_jdata *jdp, *jdp_next;
280
281
0
    for (jdp = jp->first; jdp != NULL; jdp = jdp_next) {
282
0
        jdp_next = jdp->next;
283
0
        RTPP_OBJ_DECREF(jdp->ts_dedup);
284
0
        free(jdp);
285
0
        jp->jdlen -= 1;
286
0
    }
287
0
    RTPP_DBG_ASSERT(jp->jdlen == 0);
288
0
    free(jp);
289
0
}
290
291
static struct rtp_analyze_jdata *
292
jdata_by_ssrc(struct rtp_analyze_jitter *jp, uint32_t ssrc)
293
0
{
294
0
    struct rtp_analyze_jdata *rjdp, *jdp_last, *jdp_prelast;
295
296
0
    if (jp->first->ssrc.inited == 0) {
297
0
        jp->first->ssrc.val = ssrc;
298
0
        jp->first->ssrc.inited = 1;
299
0
        return (jp->first);
300
0
    }
301
302
0
    jdp_last = jdp_prelast = NULL;
303
0
    for (rjdp = jp->first; rjdp != NULL; rjdp = rjdp->next) {
304
0
        if (rjdp->ssrc.val == ssrc) {
305
0
            return (rjdp);
306
0
        }
307
0
        jdp_prelast = jdp_last;
308
0
        jdp_last = rjdp;
309
0
    }
310
311
0
    if (jp->jdlen == RTPC_JDATA_MAX) {
312
        /* Re-use the last per-ssrc data */
313
0
        rjdp = jdp_last;
314
0
        if (jdp_prelast != NULL) {
315
0
            RTPP_DBG_ASSERT(jdp_prelast->next == jdp_last);
316
0
            jdp_prelast->next = NULL;
317
0
        } else {
318
0
            jp->first = NULL;
319
0
        }
320
0
        CALL_SMETHOD(rjdp->ts_dedup, flush);
321
0
        if (rjdp->jss.pcount >= 2) {
322
0
            if (jp->jmax_acum < rjdp->jss.jmax) {
323
0
                jp->jmax_acum = rjdp->jss.jmax;
324
0
            }
325
0
            jp->jtotal_acum += rjdp->jss.jtotal;
326
0
            jp->jvcount_acum += rjdp->jss.pcount - 1;
327
0
            jp->pcount_acum += rjdp->jss.pcount;
328
0
        }
329
0
        memset(&rjdp->jss, '\0', sizeof(rjdp->jss));
330
0
        RTPP_DBG_ASSERT(rjdp->ssrc.inited == 1);
331
0
    } else {
332
        /* Allocate per-ssrc data */
333
0
        rjdp = rtp_analyze_jdata_ctor();
334
0
        if (rjdp == NULL) {
335
0
            return (NULL);
336
0
        }
337
0
        rjdp->ssrc.inited = 1;
338
0
        jp->jdlen += 1;
339
0
    }
340
0
    rjdp->ssrc.val = ssrc;
341
0
    rjdp->next = jp->first;
342
0
    jp->first = rjdp;
343
0
    return (rjdp);
344
0
}
345
346
enum update_rtpp_stats_rval
347
update_rtpp_stats(struct rtpp_log *rlog, struct rtpp_session_stat *stat, rtp_hdr_t *header,
348
  struct rtp_info *rinfo, double rtime)
349
0
{
350
0
    uint32_t seq;
351
0
    uint16_t idx;
352
0
    uint32_t mask;
353
0
    const struct rtp_profile *rpp;
354
0
    struct rtp_analyze_jdata *jdp;
355
356
0
    rpp = rinfo->rtp_profile;
357
0
    jdp = jdata_by_ssrc(stat->jdata, rinfo->ssrc);
358
0
    if (jdp == NULL)
359
0
        return (UPDATE_ERR);
360
0
    if (stat->ssrc_changes == 0) {
361
0
        RTPP_DBG_ASSERT(stat->last.pcount == 0);
362
0
        RTPP_DBG_ASSERT(stat->psent == 0);
363
0
        RTPP_DBG_ASSERT(stat->precvd == 0);
364
0
        stat->last.ssrc.val = rinfo->ssrc;
365
0
        stat->last.ssrc.inited = 1;
366
0
        stat->last.max_seq = stat->last.min_seq = rinfo->seq;
367
0
        stat->last.base_ts = rinfo->ts;
368
0
        stat->last.base_rtime = rtime;
369
0
        stat->last.pcount = 1;
370
0
        stat->ssrc_changes = 1;
371
0
        idx = (rinfo->seq % 131072) >> 5;
372
0
        stat->last.seen[idx] |= (uint32_t)1 << (rinfo->seq & 31);
373
0
        stat->last.seq = rinfo->seq;
374
0
        if (rpp->ts_rate > 0) {
375
0
            update_jitter_stats(jdp, rinfo, rtime, RTP_NORMAL, rlog);
376
0
        }
377
0
        return (UPDATE_OK);
378
0
    }
379
0
    RTPP_DBG_ASSERT(stat->last.ssrc.inited == 1);
380
0
    if (stat->last.ssrc.val != rinfo->ssrc) {
381
0
        update_rtpp_totals(stat, stat);
382
0
        stat->last.duplicates = 0;
383
0
        memset(stat->last.seen, '\0', sizeof(stat->last.seen));
384
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
385
        LOGI_IF_NOT_NULL(rlog, "SSRC changed from " SSRC_FMT "/%d to "
386
          SSRC_FMT "/%d", stat->last.ssrc.val, stat->last.seq, rinfo->ssrc,
387
          rinfo->seq); 
388
#endif
389
0
        stat->last.ssrc.val = rinfo->ssrc;
390
0
        stat->last.max_seq = stat->last.min_seq = rinfo->seq;
391
0
        stat->last.base_ts = rinfo->ts;
392
0
        stat->last.base_rtime = rtime;
393
0
        stat->last.pcount = 1;
394
0
        stat->ssrc_changes += 1;
395
0
        if ((stat->psent > 0 || stat->precvd > 0) && rlog != NULL) {
396
0
            LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: ssrc_changes=%u, psent=%u, precvd=%u",
397
0
              rinfo->ssrc, rinfo->seq, stat->ssrc_changes, stat->psent, stat->precvd);
398
0
        }
399
0
        idx = (rinfo->seq % 131072) >> 5;
400
0
        stat->last.seen[idx] |= (uint32_t)1 << (rinfo->seq & 31);
401
0
        stat->last.seq = rinfo->seq;
402
0
        if (rpp->ts_rate > 0) {
403
0
            update_jitter_stats(jdp, rinfo, rtime, RTP_SSRC_RESET, rlog);
404
0
        }
405
0
        return (UPDATE_SSRC_CHG);
406
0
    }
407
0
    seq = rinfo->seq + stat->last.seq_offset;
408
0
    if (header->mbt && (seq < stat->last.max_seq && (stat->last.max_seq & 0xffff) != 65535)) {
409
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: seq reset last->max_seq=%u, seq=%u, m=%u",
410
0
          rinfo->ssrc, rinfo->seq, stat->last.max_seq, seq, header->mbt);
411
        /* Seq reset has happened. Treat it as a ssrc change */
412
0
        update_rtpp_totals(stat, stat);
413
0
        stat->last.duplicates = 0;
414
0
        memset(stat->last.seen, '\0', sizeof(stat->last.seen));
415
0
        stat->last.max_seq = stat->last.min_seq = seq;
416
0
        stat->last.base_ts = rinfo->ts;
417
0
        stat->last.base_rtime = rtime;
418
0
        stat->last.pcount = 1;
419
0
        stat->seq_res_count += 1;
420
0
        idx = (seq % 131072) >> 5;
421
0
        stat->last.seen[idx] |= (uint32_t)1 << (rinfo->seq & 31);
422
0
        stat->last.seq = rinfo->seq;
423
0
        if (rpp->ts_rate > 0) {
424
0
            update_jitter_stats(jdp, rinfo, rtime, RTP_SEQ_RESET, rlog);
425
0
        }
426
0
        return (UPDATE_OK);
427
0
    } else {
428
0
        if (rpp->ts_rate > 0) {
429
0
            if (seq == 0 && (stat->last.max_seq & 0xffff) < 65500) {
430
0
                update_jitter_stats(jdp, rinfo, rtime, RTP_SEQ_RESET, rlog);
431
0
            } else {
432
0
                update_jitter_stats(jdp, rinfo, rtime, RTP_NORMAL, rlog);
433
0
            }
434
0
        }
435
0
    }
436
0
    if (rpp->ts_rate != 0 && ABS(rtime - stat->last.base_rtime -
437
0
      rtp_ts2dtime(rpp->ts_rate, rinfo->ts - stat->last.base_ts)) > 0.1) {
438
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: delta rtime=%f, delta ts=%f",
439
0
          rinfo->ssrc, rinfo->seq, rtime - stat->last.base_rtime,
440
0
          rtp_ts2dtime(rpp->ts_rate, rinfo->ts - stat->last.base_ts));
441
0
        stat->last.base_rtime = rtime;
442
0
    }
443
0
    if (stat->last.max_seq % 65536 < 536 && rinfo->seq > 65000) {
444
        /* Pre-wrap packet received after a wrap */
445
0
        seq -= 65536;
446
0
    } else if (stat->last.max_seq > 65000 && seq < stat->last.max_seq - 65000) {
447
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: wrap last->max_seq=%u, seq=%u",
448
0
          rinfo->ssrc, rinfo->seq, stat->last.max_seq, seq);
449
        /* Wrap up has happened */
450
0
        stat->last.seq_offset += 65536;
451
0
        seq += 65536;
452
0
        if (stat->last.seq_offset % 131072 == 65536) {
453
0
            memset(stat->last.seen + 2048, '\0', sizeof(stat->last.seen) / 2);
454
0
        } else {
455
0
            memset(stat->last.seen, '\0', sizeof(stat->last.seen) / 2);
456
0
        }
457
0
    } else if (seq + 536 < stat->last.max_seq || seq > stat->last.max_seq + 536) {
458
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: desync last->max_seq=%u, seq=%u, m=%u",
459
0
          rinfo->ssrc, rinfo->seq, stat->last.max_seq, seq, header->mbt);
460
        /* Desynchronization has happened. Treat it as a ssrc change */
461
0
        update_rtpp_totals(stat, stat);
462
0
        stat->last.duplicates = 0;
463
0
        memset(stat->last.seen, '\0', sizeof(stat->last.seen));
464
0
        stat->last.max_seq = stat->last.min_seq = seq;
465
0
        stat->last.pcount = 1;
466
0
        stat->desync_count += 1;
467
0
        idx = (seq % 131072) >> 5;
468
0
        stat->last.seen[idx] |= (uint32_t)1 << (rinfo->seq & 31);
469
0
        stat->last.seq = rinfo->seq;
470
0
        return (UPDATE_OK);
471
0
    }
472
        /* printf("last->max_seq=%u, seq=%u, m=%u\n", stat->last.max_seq, seq, header->mbt);*/
473
0
    idx = (seq % 131072) >> 5;
474
0
    mask = stat->last.seen[idx];
475
0
    if (((mask >> (seq & 31)) & 1) != 0) {
476
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: DUP",
477
0
          rinfo->ssrc, rinfo->seq);
478
0
        stat->last.duplicates += 1;
479
0
        stat->last.seq = rinfo->seq;
480
0
        return (UPDATE_OK);
481
0
    }
482
0
    stat->last.seen[idx] |= (uint32_t)1 << (rinfo->seq & 31);
483
0
    if (seq - stat->last.max_seq != 1)
484
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: delta = %d",
485
0
          rinfo->ssrc, rinfo->seq, seq - stat->last.max_seq);
486
0
    if (seq >= stat->last.max_seq) {
487
0
        stat->last.max_seq = seq;
488
0
        stat->last.pcount += 1;
489
0
        stat->last.seq = rinfo->seq;
490
0
        return (UPDATE_OK);
491
0
    }
492
0
    if (seq >= stat->last.min_seq) {
493
0
        stat->last.pcount += 1;
494
0
        stat->last.seq = rinfo->seq;
495
0
        return (UPDATE_OK);
496
0
    }
497
0
    if (stat->last.seq_offset == 0 && seq < stat->last.min_seq) {
498
0
        stat->last.min_seq = seq;
499
0
        stat->last.pcount += 1;
500
0
        LOGD_IF_NOT_NULL(rlog, SSRC_FMT "/%d: last->min_seq=%u",
501
0
          rinfo->ssrc, rinfo->seq, stat->last.min_seq);
502
0
        stat->last.seq = rinfo->seq;
503
0
        return (UPDATE_OK);
504
0
    }
505
    /* XXX something wrong with the stream */
506
0
    stat->last.seq = rinfo->seq;
507
0
    return (UPDATE_ERR);
508
0
}
509
510
void
511
update_rtpp_totals(struct rtpp_session_stat *wstat, struct rtpp_session_stat *ostat)
512
0
{
513
514
0
    if (ostat != wstat) {
515
0
        ostat->psent = wstat->psent;
516
0
        ostat->precvd = wstat->precvd;
517
0
        ostat->duplicates = wstat->duplicates;
518
0
    }
519
0
    if (wstat->last.pcount == 0)
520
0
        return;
521
0
    ostat->psent += wstat->last.max_seq - wstat->last.min_seq + 1;
522
0
    ostat->precvd += wstat->last.pcount;
523
0
    ostat->duplicates += wstat->last.duplicates;
524
0
}
525
526
int
527
get_jitter_stats(struct rtp_analyze_jitter *jp, struct rtpa_stats_jitter *jst,
528
  struct rtpp_log *rlog)
529
0
{
530
0
    int i;
531
0
    struct rtp_analyze_jdata *rjdp;
532
0
    double jtotal;
533
534
0
    i = 0;
535
0
    for (rjdp = jp->first; rjdp != NULL && rjdp->ssrc.inited == 1; rjdp = rjdp->next) {
536
0
        if (rjdp->jss.pcount < 2) {
537
0
            continue;
538
0
        }
539
0
#if DEBUG_TIMESTAMP_RESET
540
0
        LOGD_IF_NOT_NULL(rlog, "get_jitter_stats() : " SSRC_FMT ", jss.jmax=%f",
541
0
          rjdp->ssrc.val, rjdp->jss.jmax);
542
0
#endif
543
0
        if (i == 0) {
544
0
            jst->jlast = rjdp->jss.jlast;
545
0
            jst->jmax = MAX(jp->jmax_acum, rjdp->jss.jmax);
546
0
            jtotal = jp->jtotal_acum + rjdp->jss.jtotal;
547
0
            jst->jvcount = jp->jvcount_acum + rjdp->jss.pcount - 1;
548
0
            jst->pcount = jp->pcount_acum + rjdp->jss.pcount;
549
0
        } else {
550
0
            if (jst->jmax < rjdp->jss.jmax) {
551
0
                jst->jmax = rjdp->jss.jmax;
552
0
            }
553
0
            jtotal += rjdp->jss.jtotal;
554
0
            jst->jvcount += rjdp->jss.pcount - 1;
555
0
            jst->pcount += rjdp->jss.pcount;
556
0
        }
557
0
        i += 1;
558
0
    }
559
0
    if (i > 0) {
560
0
        jst->javg = jtotal / (double)(jst->jvcount);
561
0
    }
562
0
    return (i);
563
0
}