| 1 | package cz.vutbr.feec.session.rtprtcp.internal; |
| 2 | |
| 3 | import org.apache.commons.lang.builder.CompareToBuilder; |
| 4 | import org.apache.commons.lang.builder.ToStringBuilder; |
| 5 | |
| 6 | import cz.vutbr.feec.packets.PacketUtils; |
| 7 | |
| 8 | /** |
| 9 | * This class encapsulates all the per source state information. Every source |
| 10 | * keeps track of all the other sources in the multicast group, from which it |
| 11 | * has received a RTP or RTCP Packet. It is necessry to keep track of per state |
| 12 | * source information in order to provide effective reception quality feedback |
| 13 | * to all the sources that are in the multicast group. |
| 14 | */ |
| 15 | |
| 16 | public class Source extends SourceExt { |
| 17 | |
| 18 | /** The max_seq. */ |
| 19 | private long max_seq; /* highest seq. number seen */ |
| 20 | |
| 21 | /** The last_seq. */ |
| 22 | private long last_seq; /* highest seq. number seen */ |
| 23 | |
| 24 | /** The cycles. */ |
| 25 | private int cycles; /* shifted count of seq. number cycles */ |
| 26 | |
| 27 | /** The base_seq. */ |
| 28 | private long base_seq; /* base seq number (started at) */ |
| 29 | |
| 30 | /** The bad_seq. */ |
| 31 | private long bad_seq; /* last 'bad' seq number + 1 */ |
| 32 | |
| 33 | /** The probation. */ |
| 34 | protected int probation; /* sequ. packets till source is valid */ |
| 35 | |
| 36 | /** The received. */ |
| 37 | private long received; /* packets received */ |
| 38 | |
| 39 | /** The expected_prior. */ |
| 40 | private int expected_prior; /* packet expected at last private interval */ |
| 41 | |
| 42 | /** The received_prior. */ |
| 43 | private int received_prior; /* packet received at last private interval */ |
| 44 | |
| 45 | /** The last_ts. */ |
| 46 | private long last_ts; /* last timestamp */ |
| 47 | |
| 48 | /** The last_time. */ |
| 49 | private long last_time; |
| 50 | |
| 51 | /** The jitter. */ |
| 52 | private long jitter; /* estimated jitter */ |
| 53 | |
| 54 | /** The lsr. */ |
| 55 | private long lsr; |
| 56 | |
| 57 | // private double fraction; |
| 58 | |
| 59 | /** The lost. */ |
| 60 | private long lost; /* time of the last sender report */ |
| 61 | |
| 62 | /** The frac_lost. */ |
| 63 | private double frac_lost; |
| 64 | // ############################################################ |
| 65 | /** The Constant RTP_SEQ_MOD. */ |
| 66 | final static int RTP_SEQ_MOD = (1 << 16); |
| 67 | |
| 68 | /** The Constant MIN_SEQUENTIAL. */ |
| 69 | final static int MIN_SEQUENTIAL = 5; |
| 70 | |
| 71 | // ############################################################ |
| 72 | /** |
| 73 | * The Constructor. |
| 74 | * |
| 75 | * @param seqNo |
| 76 | * the seq no |
| 77 | * @param SSRC |
| 78 | * the SSRC |
| 79 | */ |
| 80 | public Source(long SSRC, long seqNo) { |
| 81 | assert PacketUtils.checkSize(seqNo, 32) : "seqNo presahuje svou mez!!" |
| 82 | + seqNo; |
| 83 | init_seq(seqNo, System.currentTimeMillis()); |
| 84 | max_seq = (base_seq - 1) & 0xffff; |
| 85 | probation = MIN_SEQUENTIAL; |
| 86 | |
| 87 | this.ssrc = SSRC; |
| 88 | this.m_timeout = 0; |
| 89 | this.s_timeout = 0; |
| 90 | this.CNAME = ""; |
| 91 | this.ignore = false; |
| 92 | } |
| 93 | |
| 94 | /** |
| 95 | * Init_seq. |
| 96 | * |
| 97 | * @param seqNo |
| 98 | * the seq no |
| 99 | * @param timestamp |
| 100 | * the timestamp |
| 101 | */ |
| 102 | public void init_seq(long seqNo, long timestamp) { |
| 103 | assert PacketUtils.checkSize(seqNo, 32) : "seqNo presahuje svou mez!!" |
| 104 | + seqNo; |
| 105 | |
| 106 | this.base_seq = seqNo & 0xffffffffL; |
| 107 | this.max_seq = seqNo & 0xffff; |
| 108 | this.bad_seq = (RTP_SEQ_MOD + 1) & 0xffffffffL; // so seq == bad_seq is |
| 109 | // false |
| 110 | this.cycles = 0; |
| 111 | this.received = 0; |
| 112 | this.received_prior = 0; |
| 113 | this.expected_prior = 0; |
| 114 | |
| 115 | this.last_ts = timestamp; |
| 116 | this.last_time = System.currentTimeMillis(); |
| 117 | this.jitter = 0; |
| 118 | this.lsr = 0; |
| 119 | this.timeOfLastSRArrival = 0; |
| 120 | |
| 121 | // System.out.println("########### init_seq: base_seq = "+base_seq); |
| 122 | // System.out.println("########### bad_seq: bad_seq = "+bad_seq); |
| 123 | } |
| 124 | |
| 125 | /** |
| 126 | * ensures that a source (SENDER OF RTP DATA) is declared valid only after |
| 127 | * MIN_SEQUENTIAL packets have been received in sequence. It also validates |
| 128 | * the sequence number seq of a newly received packet and updates the |
| 129 | * sequence state for the packet's source in the structure to which s |
| 130 | * points. |
| 131 | * |
| 132 | * @param seqNo |
| 133 | * the seq no |
| 134 | * @param timestamp |
| 135 | * the timestamp |
| 136 | * |
| 137 | * @return source could be considered as a valid member |
| 138 | */ |
| 139 | public boolean update_seq(long seqNo, long timestamp) { |
| 140 | assert PacketUtils.checkSize(seqNo, 32) : "seqNo presahuje svou mez!!"; |
| 141 | |
| 142 | long udelta = seqNo - this.max_seq; |
| 143 | final int MAX_DROPOUT = 3000; |
| 144 | final int MAX_MISORDER = 100; |
| 145 | |
| 146 | /* |
| 147 | * Source is not valid until MIN_seqNoUENTIAL packets with seqNouential |
| 148 | * seqNouence numbers have been received. |
| 149 | */ |
| 150 | if (this.probation != 0) { |
| 151 | /* packet is in seqNouence */ |
| 152 | if (seqNo == this.max_seq + 1) { |
| 153 | this.probation--; |
| 154 | this.max_seq = seqNo & 0xffff; |
| 155 | if (this.probation == 0) { |
| 156 | // System.out.println("%%%%%%%%%%% SRC VALIDATED!!!!!"); |
| 157 | init_seq(seqNo, timestamp); |
| 158 | this.received = (this.received + 1) & 0xffffffffL; |
| 159 | // System.out.println("(" + this.ssrc +")RECEIVED = " + |
| 160 | // received); |
| 161 | return true; |
| 162 | } |
| 163 | } else { |
| 164 | this.probation = MIN_SEQUENTIAL - 1; |
| 165 | this.max_seq = seqNo & 0xffff; |
| 166 | } |
| 167 | return false; |
| 168 | } else if (udelta < MAX_DROPOUT) { |
| 169 | /* in order, with permissible gap */ |
| 170 | if (seqNo < this.max_seq) { |
| 171 | /* |
| 172 | * seqNouence number wrapped - count another 64K cycle. |
| 173 | */ |
| 174 | // System.out.println("mmmCYCLES:" + this.cycles |
| 175 | // + " RTP_SEQ_MOD:"+RTP_SEQ_MOD ); |
| 176 | this.cycles += RTP_SEQ_MOD & 0xffffffffL; |
| 177 | // System.out.println("mmmResult cycles:" + this.cycles ); |
| 178 | // System.out.println("("+ssrc+")BASE SEQ:"+base_seq); |
| 179 | } |
| 180 | this.max_seq = seqNo & 0xffff; |
| 181 | } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) { |
| 182 | /* the seqNouence number made a very large jump */ |
| 183 | if (seqNo == this.bad_seq) { |
| 184 | /* |
| 185 | * Two seqNouential packets -- assume that the other side |
| 186 | * restarted without telling us so just re-sync (i.e., pretend |
| 187 | * this was the first packet). |
| 188 | */ |
| 189 | // System.out.println("%%%%%%%%%%% SRC RESET!!!!!, bad_seq:" |
| 190 | // +bad_seq+" seqNo:"+seqNo); |
| 191 | init_seq(seqNo, timestamp); |
| 192 | } else { |
| 193 | // System.out.println("%%%%%%%%%%% SRC BIG DELAY!!!!!, udelta:" |
| 194 | // +udelta+" = seqNo("+seqNo+") - this.max_seq("+max_seq+")"); |
| 195 | this.bad_seq = ((seqNo + 1) & (RTP_SEQ_MOD - 1)) & 0xffffffffL; |
| 196 | return false; |
| 197 | } |
| 198 | } else { |
| 199 | /* duplicate or reordered packet */ |
| 200 | } |
| 201 | this.received = (this.received + 1) & 0xffffffffL; |
| 202 | // System.out.println("(" + this.ssrc +")RECEIVED = " + received); |
| 203 | // System.out.println("("+ssrc+")BASE SEQ:"+base_seq); |
| 204 | return true; |
| 205 | } |
| 206 | |
| 207 | /** |
| 208 | * Refresh sender. |
| 209 | * |
| 210 | * @return true if is sender and data could be refreshed. |
| 211 | */ |
| 212 | |
| 213 | public boolean refreshSender() { |
| 214 | long extended_max, expected, expected_interval, received_interval, lost_interval; |
| 215 | if (this.isSender()) { |
| 216 | // System.out.println("##########################"); |
| 217 | // v s->cycles je ulozena hodnota (1 << 16) * pocet cyklu (vyssi |
| 218 | // rozash nez smx_seq) |
| 219 | // s->max_seq je maximalni seq. cislo, ktere bylo prijato (RTP |
| 220 | // packet) |
| 221 | // System.out.print("extended_max = this.cycles + this.max_seq = "+ |
| 222 | // this.cycles +" + "+ this.max_seq+" = "); |
| 223 | extended_max = this.cycles + this.max_seq; |
| 224 | // System.out.println(extended_max); |
| 225 | |
| 226 | // base_seq je hodnota, na kterou byl aplikace inicializovana pri |
| 227 | // startu |
| 228 | // System.out.print("expected = extended_max - this.base_seq + 1 ="+ |
| 229 | // extended_max +" - "+this.base_seq +"+ 1 = "); |
| 230 | expected = extended_max - this.base_seq + 1; |
| 231 | |
| 232 | // expected... odeslano, received... prijato |
| 233 | // System.out.print("this.lost = expected - this.received = "+ |
| 234 | // expected+" - "+ this.received +" = "); |
| 235 | this.lost = expected - this.received; |
| 236 | // ocekavano v tomto intervalu (interval = odeslani RTP packetu) |
| 237 | expected_interval = expected - this.expected_prior; |
| 238 | // prijato v tomto RTCP intervalu |
| 239 | received_interval = this.received - this.received_prior; |
| 240 | // lost in this interval |
| 241 | lost_interval = expected_interval - received_interval; |
| 242 | // fract_lost |
| 243 | if (expected_interval == 0 || lost_interval <= 0) { |
| 244 | this.frac_lost = 0.; |
| 245 | } else { |
| 246 | this.frac_lost = (double) lost_interval |
| 247 | / (double) expected_interval; |
| 248 | } |
| 249 | // pocet seq + uvazovani i s jitter |
| 250 | // System.out.print("("+this.ssrc+")this.last_seq = this.max_seq | |
| 251 | // this.cycles; = "+ this.max_seq +" | " + this.cycles + " = "); |
| 252 | this.last_seq = (this.max_seq | this.cycles) & 0xffffffffL; |
| 253 | // System.out.println(this.last_seq); |
| 254 | |
| 255 | // this.last_seq = this.max_seq | this.cycles << 16; |
| 256 | // hitter >> 4 |
| 257 | this.jitter = (this.jitter >> 4) & 0xffffffffL; |
| 258 | // |
| 259 | if (this.timeOfLastSRArrival == 0) { |
| 260 | this.DLSR = 0; |
| 261 | } else { |
| 262 | this.DLSR = System.currentTimeMillis() |
| 263 | - this.timeOfLastSRArrival; |
| 264 | } |
| 265 | } else { |
| 266 | return false; |
| 267 | } |
| 268 | return true; |
| 269 | } |
| 270 | |
| 271 | /** |
| 272 | * Gets the received count. |
| 273 | * |
| 274 | * @return the received count |
| 275 | */ |
| 276 | public long getReceivedCount() { |
| 277 | return received; |
| 278 | } |
| 279 | |
| 280 | // public void setBase_seq(long base_seq) { |
| 281 | // this.base_seq = base_seq & 0xffffffffL; |
| 282 | // } |
| 283 | |
| 284 | /** |
| 285 | * Gets the last_ts. |
| 286 | * |
| 287 | * @return the last_ts |
| 288 | */ |
| 289 | public long getLast_ts() { |
| 290 | return last_ts; |
| 291 | } |
| 292 | |
| 293 | /** |
| 294 | * Gets the last_time. |
| 295 | * |
| 296 | * @return the last_time |
| 297 | */ |
| 298 | public long getLast_time() { |
| 299 | return last_time; |
| 300 | } |
| 301 | |
| 302 | /** |
| 303 | * Sets the last_ts. |
| 304 | * |
| 305 | * @param last_ts |
| 306 | * the last_ts |
| 307 | */ |
| 308 | public void setLast_ts(long last_ts) { |
| 309 | this.last_ts = last_ts; |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * Sets the last_time. |
| 314 | * |
| 315 | * @param last_time |
| 316 | * the last_time |
| 317 | */ |
| 318 | public void setLast_time(long last_time) { |
| 319 | this.last_time = last_time; |
| 320 | } |
| 321 | |
| 322 | /** |
| 323 | * Gets the jitter. |
| 324 | * |
| 325 | * @return the jitter |
| 326 | */ |
| 327 | public long getJitter() { |
| 328 | return jitter; |
| 329 | } |
| 330 | |
| 331 | /** |
| 332 | * Sets the jitter. |
| 333 | * |
| 334 | * @param jitter |
| 335 | * the jitter |
| 336 | */ |
| 337 | public void setJitter(long jitter) { |
| 338 | this.jitter = jitter; |
| 339 | } |
| 340 | |
| 341 | /** |
| 342 | * Sets the lost. |
| 343 | * |
| 344 | * @param lost |
| 345 | * the lost |
| 346 | */ |
| 347 | public void setLost(long lost) { |
| 348 | this.lost = lost; |
| 349 | } |
| 350 | |
| 351 | /** |
| 352 | * Sets the fraction. |
| 353 | * |
| 354 | * @param fraction |
| 355 | * the fraction |
| 356 | */ |
| 357 | public void setFraction(double fraction) { |
| 358 | this.frac_lost = fraction; |
| 359 | } |
| 360 | |
| 361 | /** |
| 362 | * Sets the lsr. |
| 363 | * |
| 364 | * @param lsr |
| 365 | * the lsr |
| 366 | */ |
| 367 | public void setLsr(long lsr) { |
| 368 | this.lsr = lsr; |
| 369 | } |
| 370 | |
| 371 | /** |
| 372 | * Gets the lost. |
| 373 | * |
| 374 | * @return the lost |
| 375 | */ |
| 376 | public long getLost() { |
| 377 | return lost; |
| 378 | } |
| 379 | |
| 380 | /** |
| 381 | * Gets the last_seq. |
| 382 | * |
| 383 | * @return the last_seq |
| 384 | */ |
| 385 | public long getLast_seq() { |
| 386 | return last_seq; |
| 387 | } |
| 388 | |
| 389 | /** |
| 390 | * Gets the fraction. |
| 391 | * |
| 392 | * @return the fraction |
| 393 | */ |
| 394 | public double getFraction() { |
| 395 | return frac_lost; |
| 396 | } |
| 397 | |
| 398 | /** |
| 399 | * Gets the lsr. |
| 400 | * |
| 401 | * @return the lsr |
| 402 | */ |
| 403 | public long getLsr() { |
| 404 | return lsr; |
| 405 | } |
| 406 | |
| 407 | /** |
| 408 | * Compare to. |
| 409 | * |
| 410 | * @param object |
| 411 | * the object |
| 412 | * |
| 413 | * @return the int |
| 414 | * |
| 415 | * @see java.lang.Comparable#compareTo(Object) |
| 416 | */ |
| 417 | public int compareTo(Object object) { |
| 418 | Source myClass = (Source) object; |
| 419 | return new CompareToBuilder() |
| 420 | .append(this.timeOfLastRTPSent, myClass.timeOfLastRTPSent) |
| 421 | .append(this.lsr, myClass.lsr) |
| 422 | .append(this.ignore, myClass.ignore) |
| 423 | .append(this.received_prior, myClass.received_prior) |
| 424 | .append(this.TOOL, myClass.TOOL) |
| 425 | .append(this.rtcp_ip, myClass.rtcp_ip) |
| 426 | .append(this.PRIV, myClass.PRIV) |
| 427 | .append(this.last_time, myClass.last_time) |
| 428 | .append(this.base_seq, myClass.base_seq) |
| 429 | .append(this.PHONE, myClass.PHONE) |
| 430 | .append(this.EMAIL, myClass.EMAIL) |
| 431 | .append(this.s_timeout, myClass.s_timeout) |
| 432 | .append(this.CNAME, myClass.CNAME) |
| 433 | .append(this.probation, myClass.probation) |
| 434 | .append(this.timeOfLastRTCPArrival, |
| 435 | myClass.timeOfLastRTCPArrival) |
| 436 | .append(this.DLSR, myClass.DLSR) |
| 437 | .append(this.NOTE, myClass.NOTE) |
| 438 | .append(this.expected_prior, myClass.expected_prior) |
| 439 | .append(this.ssrc, myClass.ssrc) |
| 440 | .append(this.rtp_port, myClass.rtp_port) |
| 441 | .append(this.max_seq, myClass.max_seq) |
| 442 | .append(this.frac_lost, myClass.frac_lost) |
| 443 | .append(this.LOC, myClass.LOC) |
| 444 | .append(this.received, myClass.received) |
| 445 | .append(this.cycles, myClass.cycles) |
| 446 | .append(this.bad_seq, myClass.bad_seq) |
| 447 | .append(this.rtp_ip, myClass.rtp_ip) |
| 448 | .append(this.last_seq, myClass.last_seq) |
| 449 | .append(this.lost, myClass.lost) |
| 450 | .append(this.timeOfLastSRArrival, myClass.timeOfLastSRArrival) |
| 451 | .append(this.timeOfLastSRSent, myClass.timeOfLastSRSent) |
| 452 | .append(this.jitter, myClass.jitter) |
| 453 | .append(this.timeOfLastRTPArrival, myClass.timeOfLastRTPArrival) |
| 454 | .append(this.BYE, myClass.BYE).append(this.timeOfLastRTCPSent, |
| 455 | myClass.timeOfLastRTCPSent).append(this.m_timeout, |
| 456 | myClass.m_timeout).append(this.NAME, myClass.NAME) |
| 457 | .append(this.last_ts, myClass.last_ts).append(this.rtcp_port, |
| 458 | myClass.rtcp_port).toComparison(); |
| 459 | } |
| 460 | |
| 461 | /** |
| 462 | * To string. |
| 463 | * |
| 464 | * @return the string |
| 465 | * |
| 466 | * @see java.lang.Object#toString() |
| 467 | */ |
| 468 | public String toString() { |
| 469 | return new ToStringBuilder(this).append("lsr", this.lsr) |
| 470 | // .append( |
| 471 | // "receivedCount", this.getReceivedCount()).append("last_seq", |
| 472 | // this.last_seq).append("last_time", this.last_time).append( |
| 473 | // "sender", this.isSender()).append("lost", this.lost).append( |
| 474 | // "jitter", this.jitter).append("last_ts", |
| 475 | // this.last_ts).append( |
| 476 | // "fraction", this.getFraction()) |
| 477 | .append("SSRC", this.getSSRC()).toString(); |
| 478 | } |
| 479 | |
| 480 | } |