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