internal void AddReceiverReport(CompoundPacketBuilder cpb) { // Update the values rr.SSRC = ssrc; rr.PacketsLost = packetsLost; rr.FractionLost = (byte)((float)packetsLost / (float)(packetsReceived + packetsLost) * 100F); // TODO - figure out how to calculate / interpret these values, especially Seq - JVE // rr.Jitter = ?; // rr.LastSenderReport = ?; // rr.DelaySinceLastSenderReport = ?; // rr.ExtendedHighestSequence = ?; cpb.Add_ReceiverReport(rr); }
internal void AddReceiverReport(CompoundPacketBuilder cpb) { // Update the values rr.SSRC = ssrc; rr.PacketsLost = packetsLost; // andrew: this is obviously not what the spec says, but it's easier to compute and // to use for diagnostics... rr.ExtendedHighestSequence = packetsReceived; // andrew: this also is incorrect: the spec says this should be calculated per // interval rather than per session rr.FractionLost = (byte)((float)packetsLost / (float)(packetsReceived + packetsLost) * 100F); // TODO - figure out how to calculate / interpret these values, especially Seq - JVE // rr.Jitter = ?; // rr.LastSenderReport = ?; // rr.DelaySinceLastSenderReport = ?; // rr.ExtendedHighestSequence = ?; cpb.Add_ReceiverReport(rr); }
/// <summary> /// Collects the Rtcp data from the session, assembles it into CompoundPackets (via the /// CompoundPacketBuilder) and sends the packets /// /// The current design has a "forced" Send occurring on the thread that makes the call, and /// a normal Send occurring on the dedicated RtcpSender thread. /// /// To make sure that multiple threads aren't making the call at the same time, which can /// lead to data access exceptions (e.g. Queue empty), we lock here. /// </summary> /// <param name="forced">Is Send being called due to timing rules, or forced?</param> private void Send(bool forced) { lock (this) { try { // We're Sending despite timing rules if (forced) { lastSendForced = true; } else // We're Sending due to timing rules { // The timing rules may now be in conflict with a previous forced Send // Ask the timing rules to reconsider again before Sending if (lastSendForced) { lastSendForced = false; return; } } CompoundPacketBuilder cpb = rtpSession.RtcpReportIntervalReached(); cpb.BuildCompoundPackets(); Debug.Assert(cpb.PacketCount > 0); // Send all compound packets (in case there is more than 1) short packetCount = cpb.PacketCount; int bytes = 0; foreach (CompoundPacket cp in cpb) { BufferChunk data = cp.Data; bytes += data.Length; rtcpNetworkSender.Send(data); if (diagnosticSender != null) { // andrew: send a "carbon-copy" to the diagnostic server // this is done over unicast to avoid entangling diagnosis with multicast diagnosticSender.Send(data); } } // How long between the last send time and now TimeSpan interval = DateTime.Now - lastSendTime; // Update lastSendTime lastSendTime = DateTime.Now; // Update performance data // Packets before bytes, since packets doesn't have any dependencies // but BytesPerPacket requires a correct reading on the packet count UpdatePerformancePackets(packetCount); UpdatePerformanceBytes(bytes); UpdatePerformanceInterval(interval, forced); } catch (ThreadAbortException) {} catch (Exception e) { // AAA debugging only System.Console.WriteLine(e.StackTrace); if (e is System.Net.Sockets.SocketException) { Object[] args = new Object[] { this, new RtpEvents.HiddenSocketExceptionEventArgs((RtpSession)rtpSession, (System.Net.Sockets.SocketException)e) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseHiddenSocketExceptionEvent), args); } rtpSession.LogEvent("RtcpSender", e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error); } } }