blob: c6a324229390397f642237c901e4b94ca24124ae [file] [log] [blame]
James Kuszmaul82f6c042021-01-17 11:30:16 -08001/**
2 * @file source.c Real-time Transport Control Protocol source
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6#include <string.h>
7#include <re_types.h>
8#include <re_fmt.h>
9#include <re_mem.h>
10#include <re_mbuf.h>
11#include <re_list.h>
12#include <re_hash.h>
13#include <re_sa.h>
14#include <re_rtp.h>
15#include "rtcp.h"
16
17
18enum {
19 RTP_SEQ_MOD = 1<<16,
20};
21
22
23void source_init_seq(struct rtp_source *s, uint16_t seq)
24{
25 if (!s)
26 return;
27
28 s->base_seq = seq;
29 s->max_seq = seq;
30 s->bad_seq = RTP_SEQ_MOD + 1; /* so seq == bad_seq is false */
31 s->cycles = 0;
32 s->received = 0;
33 s->received_prior = 0;
34 s->expected_prior = 0;
35 /* other initialization */
36}
37
38
39/*
40 * See RFC 3550 - A.1 RTP Data Header Validity Checks
41 */
42int source_update_seq(struct rtp_source *s, uint16_t seq)
43{
44 uint16_t udelta = seq - s->max_seq;
45 const int MAX_DROPOUT = 3000;
46 const int MAX_MISORDER = 100;
47 const int MIN_SEQUENTIAL = 2;
48
49 /*
50 * Source is not valid until MIN_SEQUENTIAL packets with
51 * sequential sequence numbers have been received.
52 */
53 if (s->probation) {
54
55 /* packet is in sequence */
56 if (seq == s->max_seq + 1) {
57 s->probation--;
58 s->max_seq = seq;
59 if (s->probation == 0) {
60 source_init_seq(s, seq);
61 s->received++;
62 return 1;
63 }
64 }
65 else {
66 s->probation = MIN_SEQUENTIAL - 1;
67 s->max_seq = seq;
68 }
69 return 0;
70 }
71 else if (udelta < MAX_DROPOUT) {
72
73 /* in order, with permissible gap */
74 if (seq < s->max_seq) {
75 /*
76 * Sequence number wrapped - count another 64K cycle.
77 */
78 s->cycles += RTP_SEQ_MOD;
79 }
80 s->max_seq = seq;
81 }
82 else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
83
84 /* the sequence number made a very large jump */
85 if (seq == s->bad_seq) {
86 /*
87 * Two sequential packets -- assume that the other side
88 * restarted without telling us so just re-sync
89 * (i.e., pretend this was the first packet).
90 */
91 source_init_seq(s, seq);
92 }
93 else {
94 s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
95 return 0;
96 }
97 }
98 else {
99 /* duplicate or reordered packet */
100 }
101
102 s->received++;
103 return 1;
104}
105
106
107/* RFC 3550 A.8
108 *
109 * The inputs are:
110 *
111 * rtp_ts: the timestamp from the incoming RTP packet
112 * arrival: the current time in the same units.
113 */
114void source_calc_jitter(struct rtp_source *s, uint32_t rtp_ts,
115 uint32_t arrival)
116{
117 const int transit = arrival - rtp_ts;
118 int d = transit - s->transit;
119
120 if (!s->transit) {
121 s->transit = transit;
122 return;
123 }
124
125 s->transit = transit;
126
127 if (d < 0)
128 d = -d;
129
130 s->jitter += d - ((s->jitter + 8) >> 4);
131}
132
133
134/* A.3 */
135int source_calc_lost(const struct rtp_source *s)
136{
137 int extended_max = s->cycles + s->max_seq;
138 int expected = extended_max - s->base_seq + 1;
139 int lost;
140
141 lost = expected - s->received;
142
143 /* Clamp at 24 bits */
144 if (lost > 0x7fffff)
145 lost = 0x7fffff;
146 else if (lost < -0x7fffff)
147 lost = -0x7fffff;
148
149 return lost;
150}
151
152
153/* A.3 */
154uint8_t source_calc_fraction_lost(struct rtp_source *s)
155{
156 int extended_max = s->cycles + s->max_seq;
157 int expected = extended_max - s->base_seq + 1;
158 int expected_interval = expected - s->expected_prior;
159 int received_interval;
160 int lost_interval;
161 uint8_t fraction;
162
163 s->expected_prior = expected;
164
165 received_interval = s->received - s->received_prior;
166
167 s->received_prior = s->received;
168
169 lost_interval = expected_interval - received_interval;
170
171 if (expected_interval == 0 || lost_interval <= 0)
172 fraction = 0;
173 else
174 fraction = (lost_interval << 8) / expected_interval;
175
176 return fraction;
177}