1 /**
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 
18 enum {
19 	RTP_SEQ_MOD = 1<<16,
20 };
21 
22 
source_init_seq(struct rtp_source * s,uint16_t seq)23 void 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  */
source_update_seq(struct rtp_source * s,uint16_t seq)42 int 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  */
source_calc_jitter(struct rtp_source * s,uint32_t rtp_ts,uint32_t arrival)114 void 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 */
source_calc_lost(const struct rtp_source * s)135 int 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 */
source_calc_fraction_lost(struct rtp_source * s)154 uint8_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 }
178