using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Net; namespace RtpLib { public class RtcpReceiverReport : RtcpPacket { #region Public Methods public override void ParseData(Stream stream) { byte[] bytes = new byte[28]; int length = stream.Read(bytes, 0, bytes.Length); // The receiver report may only contain the SSRC, but may contain more // So as long as we have at least 4 bytes then we have valid data if (length < 4) throw new InvalidDataException(); this.Ssrc = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 0)); this.SsrcOnly = (length == bytes.Length); if (!this.SsrcOnly) { this.ReporteeSsrc = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 4)); this.LossFraction = bytes[4]; this.CumulativeLoss = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 4)) & 0x00FFFFFF; this.ExtendedHighestSequenceNumber = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 8)); this.InterarrivalJitter = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 12)); this.LastSenderReportTimestamp = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 16)); this.LastSenderReportDelay = (uint)IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 20)); // Need to sign-extend this value. if ((0x00800000 & this.CumulativeLoss) != 0) { this.CumulativeLoss |= 0xFF000000; } } else { this.ReporteeSsrc = 0; this.LossFraction = 0; this.CumulativeLoss = 0; this.ExtendedHighestSequenceNumber = 0; this.InterarrivalJitter = 0; this.LastSenderReportTimestamp = 0; this.LastSenderReportDelay = 0; } } #endregion #region Protected Methods protected override int GetByteCount() { return (this.SsrcOnly ? 4 : 24); } protected override void ToStreamInternal(Stream stream) { var writer = new BinaryWriter(stream); writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.Ssrc)); // If we're only writing the SSRC then we're done if (this.SsrcOnly) return; writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.ReporteeSsrc)); writer.Write(this.LossFraction); writer.Write(BitConverter.GetBytes(IPAddress.HostToNetworkOrder((int)this.CumulativeLoss)), 1, 3); writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.ExtendedHighestSequenceNumber)); writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.InterarrivalJitter)); writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.LastSenderReportTimestamp)); writer.Write((uint)IPAddress.HostToNetworkOrder((int)this.LastSenderReportDelay)); } #endregion #region public override Rtcp.PacketType PacketType { get { return Rtcp.PacketType.ReceiverReport; } } public bool SsrcOnly { get; set; } public uint Ssrc { get; set; } public uint ReporteeSsrc { get; set; } public byte LossFraction { get; set; } public uint CumulativeLoss { get; set; } public uint ExtendedHighestSequenceNumber { get; set; } public uint InterarrivalJitter { get; set; } public uint LastSenderReportTimestamp { get; set; } public uint LastSenderReportDelay { get; set; } #endregion #region ICloneable Implementation public override object Clone() { var packet = this.MemberwiseClone() as RtcpReceiverReport; packet.Header = packet.Header.Clone() as RtcpHeader; return packet; } #endregion } }