| 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 | |