/// <summary> /// Sets property LastRR value. /// </summary> /// <param name="rr">RTCP RR report.</param> /// <exception cref="ArgumentNullException">Is raised when <b>rr</b> is null reference.</exception> internal void SetRR(RTCP_Packet_ReportBlock rr) { if (rr == null) { throw new ArgumentNullException("rr"); } }
/// <summary> /// Parses receiver report(RR) from byte buffer. /// </summary> /// <param name="buffer">Buffer wihich contains receiver report.</param> /// <param name="offset">Offset in buufer.</param> /// <exception cref="ArgumentNullException">Is raised when <b>buffer</b> is null.</exception> /// <exception cref="ArgumentException">Is raised when any of the arguments has invalid value.</exception> protected override void ParseInternal(byte[] buffer, ref int offset) { /* RFC 3550 6.4.2 RR: Receiver Report RTCP Packet. * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * header |V=2|P| RC | PT=RR=201 | length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | SSRC of packet sender | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | report | SSRC_1 (SSRC of first source) | | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 1 | fraction lost | cumulative number of packets lost | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | extended highest sequence number received | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | interarrival jitter | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | last SR (LSR) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | delay since last SR (DLSR) | +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | report | SSRC_2 (SSRC of second source) | | block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 2 : ... : +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | profile-specific extensions | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentException("Argument 'offset' value must be >= 0."); } m_Version = buffer[offset] >> 6; bool isPadded = Convert.ToBoolean((buffer[offset] >> 5) & 0x1); int reportBlockCount = buffer[offset++] & 0x1F; int type = buffer[offset++]; int length = buffer[offset++] << 8 | buffer[offset++]; if (isPadded) { this.PaddBytesCount = buffer[offset + length]; } m_SSRC = (uint)(buffer[offset++] << 24 | buffer[offset++] << 16 | buffer[offset++] << 8 | buffer[offset++]); for (int i = 0; i < reportBlockCount; i++) { RTCP_Packet_ReportBlock reportBlock = new RTCP_Packet_ReportBlock(); reportBlock.Parse(buffer, offset); m_pReportBlocks.Add(reportBlock); offset += 24; } // TODO: profile-specific extensions }
/// <summary> /// Default constructor. /// </summary> /// <param name="rr">RTCP RR report.</param> /// <exception cref="ArgumentNullException">Is raised when <b>rr</b> is null reference.</exception> internal RTCP_Report_Receiver(RTCP_Packet_ReportBlock rr) { if (rr == null) { throw new ArgumentNullException("rr"); } m_FractionLost = rr.FractionLost; m_CumulativePacketsLost = rr.CumulativePacketsLost; m_ExtHigestSeqNumber = rr.ExtendedHighestSeqNo; m_Jitter = rr.Jitter; m_LastSR = rr.LastSR; m_DelaySinceLastSR = rr.DelaySinceLastSR; }
/// <summary> /// Creates receiver report. /// </summary> /// <returns>Returns created receiver report.</returns> internal RTCP_Packet_ReportBlock CreateReceiverReport() { /* RFC 3550 A.3 Determining Number of Packets Expected and Lost. * In order to compute packet loss rates, the number of RTP packets * expected and actually received from each source needs to be known, * using per-source state information defined in struct source * referenced via pointer s in the code below. The number of packets * received is simply the count of packets as they arrive, including any * late or duplicate packets. The number of packets expected can be * computed by the receiver as the difference between the highest * sequence number received (s->max_seq) and the first sequence number * received (s->base_seq). Since the sequence number is only 16 bits * and will wrap around, it is necessary to extend the highest sequence * number with the (shifted) count of sequence number wraparounds * (s->cycles). Both the received packet count and the count of cycles * are maintained the RTP header validity check routine in Appendix A.1. * * extended_max = s->cycles + s->max_seq; * expected = extended_max - s->base_seq + 1; * * The number of packets lost is defined to be the number of packets * expected less the number of packets actually received: * * lost = expected - s->received; * * Since this signed number is carried in 24 bits, it should be clamped * at 0x7fffff for positive loss or 0x800000 for negative loss rather * than wrapping around. * * The fraction of packets lost during the last reporting interval * (since the previous SR or RR packet was sent) is calculated from * differences in the expected and received packet counts across the * interval, where expected_prior and received_prior are the values * saved when the previous reception report was generated: * * expected_interval = expected - s->expected_prior; * s->expected_prior = expected; * received_interval = s->received - s->received_prior; * s->received_prior = s->received; * lost_interval = expected_interval - received_interval; * if(expected_interval == 0 || lost_interval <= 0) * fraction = 0; * else * fraction = (lost_interval << 8) / expected_interval; * * The resulting fraction is an 8-bit fixed point number with the binary * point at the left edge. */ uint extHighestSeqNo = (uint)(m_SeqNoWrapCount << 16 + m_MaxSeqNo); uint expected = extHighestSeqNo - m_BaseSeq + 1; int expected_interval = (int)(expected - m_ExpectedPrior); m_ExpectedPrior = expected; int received_interval = (int)(m_PacketsReceived - m_ReceivedPrior); m_ReceivedPrior = m_PacketsReceived; int lost_interval = expected_interval - received_interval; int fraction = 0; if (expected_interval == 0 || lost_interval <= 0) { fraction = 0; } else { fraction = (lost_interval << 8) / expected_interval; } RTCP_Packet_ReportBlock rr = new RTCP_Packet_ReportBlock(this.SSRC.SSRC); rr.FractionLost = (uint)fraction; rr.CumulativePacketsLost = (uint)this.PacketsLost; rr.ExtendedHighestSeqNo = extHighestSeqNo; rr.Jitter = (uint)m_Jitter; rr.LastSR = (m_pLastSR == null ? 0 : ((uint)((long)m_pLastSR.NtpTimestamp >> 8) & 0xFFFF)); rr.DelaySinceLastSR = (uint)Math.Max(0, this.DelaySinceLastSR / 65.536); return(rr); }