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 | |
10 | A.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 | |