1/* RTCP code taken directly from the most recent RTP specification:
2 * RFC 3550
3 * Implementation
4 */
5
6#include "rtcp_from_spec.h"
7
8/*****
9
10A.7 Computing the RTCP Transmission Interval
11
12 The following functions implement the RTCP transmission and reception
13 rules described in Section 6.2. These rules are coded in several
14 functions:
15
16 o rtcp_interval() computes the deterministic calculated
17 interval, measured in seconds. The parameters are defined in
18 Section 6.3.
19
20 o OnExpire() is called when the RTCP transmission timer expires.
21
22 o OnReceive() is called whenever an RTCP packet is received.
23
24 Both OnExpire() and OnReceive() have event e as an argument. This is
25 the next scheduled event for that participant, either an RTCP report
26 or a BYE packet. It is assumed that the following functions are
27 available:
28
29 o Schedule(time t, event e) schedules an event e to occur at
30 time t. When time t arrives, the function OnExpire is called
31 with e as an argument.
32
33 o Reschedule(time t, event e) reschedules a previously scheduled
34 event e for time t.
35
36 o SendRTCPReport(event e) sends an RTCP report.
37
38 o SendBYEPacket(event e) sends a BYE packet.
39
40 o TypeOfEvent(event e) returns EVENT_BYE if the event being
41 processed is for a BYE packet to be sent, else it returns
42 EVENT_REPORT.
43
44 o PacketType(p) returns PACKET_RTCP_REPORT if packet p is an
45 RTCP report (not BYE), PACKET_BYE if its a BYE RTCP packet,
46 and PACKET_RTP if its a regular RTP data packet.
47
48 o ReceivedPacketSize() and SentPacketSize() return the size of
49 the referenced packet in octets.
50
51 o NewMember(p) returns a 1 if the participant who sent packet p
52 is not currently in the member list, 0 otherwise. Note this
53 function is not sufficient for a complete implementation
54 because each CSRC identifier in an RTP packet and each SSRC in
55 a BYE packet should be processed.
56
57 o NewSender(p) returns a 1 if the participant who sent packet p
58 is not currently in the sender sublist of the member list, 0
59 otherwise.
60
61 o AddMember() and RemoveMember() to add and remove participants
62 from the member list.
63
64 o AddSender() and RemoveSender() to add and remove participants
65 from the sender sublist of the member list.
66*****/
67
68
69 double rtcp_interval(int members,
70 int senders,
71 double rtcp_bw,
72 int we_sent,
73 double avg_rtcp_size,
74 int initial)
75 {
76 /*
77 * Minimum average time between RTCP packets from this site (in
78 * seconds). This time prevents the reports from `clumping' when
79 * sessions are small and the law of large numbers isn't helping
80 * to smooth out the traffic. It also keeps the report interval
81 * from becoming ridiculously small during transient outages like
82 * a network partition.
83 */
84 double const RTCP_MIN_TIME = 5.;
85 /*
86 * Fraction of the RTCP bandwidth to be shared among active
87 * senders. (This fraction was chosen so that in a typical
88 * session with one or two active senders, the computed report
89 * time would be roughly equal to the minimum report time so that
90 * we don't unnecessarily slow down receiver reports.) The
91 * receiver fraction must be 1 - the sender fraction.
92 */
93 double const RTCP_SENDER_BW_FRACTION = 0.25;
94 double const RTCP_RCVR_BW_FRACTION = (1-RTCP_SENDER_BW_FRACTION);
95 /*
96 * To compensate for "unconditional reconsideration" converging to a
97 * value below the intended average.
98 */
99 double const COMPENSATION = 2.71828 - 1.5;
100
101 double t; /* interval */
102 double rtcp_min_time = RTCP_MIN_TIME;
103 int n; /* no. of members for computation */
104
105 /*
106 * Very first call at application start-up uses half the min
107 * delay for quicker notification while still allowing some time
108 * before reporting for randomization and to learn about other
109 * sources so the report interval will converge to the correct
110 * interval more quickly.
111 */
112 if (initial) {
113 rtcp_min_time /= 2;
114 }
115
116 /*
117 * If there were active senders, give them at least a minimum
118 * share of the RTCP bandwidth. Otherwise all participants share
119 * the RTCP bandwidth equally.
120 */
121 n = members;
122 if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) {
123 if (we_sent) {
124 rtcp_bw *= RTCP_SENDER_BW_FRACTION;
125 n = senders;
126 } else {
127 rtcp_bw *= RTCP_RCVR_BW_FRACTION;
128 n -= senders;
129 }
130 }
131
132 /*
133 * The effective number of sites times the average packet size is
134 * the total number of octets sent when each site sends a report.
135 * Dividing this by the effective bandwidth gives the time
136 * interval over which those packets must be sent in order to
137 * meet the bandwidth target, with a minimum enforced. In that
138 * time interval we send one report so this time is also our
139 * average time between reports.
140 */
141 t = avg_rtcp_size * n / rtcp_bw;
142 if (t < rtcp_min_time) t = rtcp_min_time;
143
144 /*
145 * To avoid traffic bursts from unintended synchronization with
146 * other sites, we then pick our actual next report interval as a
147 * random number uniformly distributed between 0.5*t and 1.5*t.
148 */
149 t = t * (drand48() + 0.5);
150 t = t / COMPENSATION;
151 return t;
152 }
153
154 void OnExpire(event e,
155 int members,
156 int senders,
157 double rtcp_bw,
158 int we_sent,
159 double *avg_rtcp_size,
160 int *initial,
161 time_tp tc,
162 time_tp *tp,
163 int *pmembers)
164 {
165 /* This function is responsible for deciding whether to send
166 * an RTCP report or BYE packet now, or to reschedule transmission.
167 * It is also responsible for updating the pmembers, initial, tp,
168 * and avg_rtcp_size state variables. This function should be called
169 * upon expiration of the event timer used by Schedule(). */
170
171 double t; /* Interval */
172 double tn; /* Next transmit time */
173
174 /* In the case of a BYE, we use "unconditional reconsideration" to
175 * reschedule the transmission of the BYE if necessary */
176
177 if (TypeOfEvent(e) == EVENT_BYE) {
178 t = rtcp_interval(members,
179 senders,
180 rtcp_bw,
181 we_sent,
182 *avg_rtcp_size,
183 *initial);
184 tn = *tp + t;
185 if (tn <= tc) {
186 SendBYEPacket(e);
187 exit(1);
188 } else {
189 Schedule(tn, e);
190 }
191
192 } else if (TypeOfEvent(e) == EVENT_REPORT) {
193 t = rtcp_interval(members,
194 senders,
195 rtcp_bw,
196 we_sent,
197 *avg_rtcp_size,
198 *initial);
199 tn = *tp + t;
200
201 if (tn <= tc) {
202 SendRTCPReport(e);
203 *avg_rtcp_size = (1./16.)*SentPacketSize(e) +
204 (15./16.)*(*avg_rtcp_size);
205 *tp = tc;
206
207 /* We must redraw the interval. Don't reuse the
208 one computed above, since its not actually
209 distributed the same, as we are conditioned
210 on it being small enough to cause a packet to
211 be sent */
212
213 t = rtcp_interval(members,
214 senders,
215 rtcp_bw,
216 we_sent,
217 *avg_rtcp_size,
218 *initial);
219
220 Schedule(t+tc,e);
221 *initial = 0;
222 } else {
223 Schedule(tn, e);
224 }
225 *pmembers = members;
226 }
227 }
228
229
230 void OnReceive(packet p,
231 event e,
232 int *members,
233 int *pmembers,
234 int *senders,
235 double *avg_rtcp_size,
236 double *tp,
237 double tc,
238 double tn)
239 {
240 /* What we do depends on whether we have left the group, and
241 * are waiting to send a BYE (TypeOfEvent(e) == EVENT_BYE) or
242 * an RTCP report. p represents the packet that was just received. */
243
244 if (PacketType(p) == PACKET_RTCP_REPORT) {
245 if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) {
246 AddMember(p);
247 *members += 1;
248 }
249 *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) +
250 (15./16.)*(*avg_rtcp_size);
251 } else if (PacketType(p) == PACKET_RTP) {
252 if (NewMember(p) && (TypeOfEvent(e) == EVENT_REPORT)) {
253 AddMember(p);
254 *members += 1;
255 }
256 if (NewSender(p) && (TypeOfEvent(e) == EVENT_REPORT)) {
257 AddSender(p);
258 *senders += 1;
259 }
260 } else if (PacketType(p) == PACKET_BYE) {
261 *avg_rtcp_size = (1./16.)*ReceivedPacketSize(p) +
262 (15./16.)*(*avg_rtcp_size);
263
264 if (TypeOfEvent(e) == EVENT_REPORT) {
265 if (NewSender(p) == FALSE) {
266 RemoveSender(p);
267 *senders -= 1;
268 }
269
270 if (NewMember(p) == FALSE) {
271 RemoveMember(p);
272 *members -= 1;
273 }
274
275 if(*members < *pmembers) {
276 tn = tc + (((double) *members)/(*pmembers))*(tn - tc);
277 *tp = tc - (((double) *members)/(*pmembers))*(tc - *tp);
278
279 /* Reschedule the next report for time tn */
280
281 Reschedule(tn, e);
282 *pmembers = *members;
283 }
284
285 } else if (TypeOfEvent(e) == EVENT_BYE) {
286 *members += 1;
287 }
288 }
289 }
290