Example #1
0
        private void CheckForSamples()
        {
            try
            {
                Thread.Sleep(CHECK_FORSAMPLE_PERIOD);   // Wait until the first sample is likely to be ready.

                while (m_checkForSamples)
                {
                    RTCPReport report = CheckForAvailableSample(m_windowLastSeqNum);

                    if (report != null && RTCPReportReady != null)
                    {
                        try
                        {
                            RTCPReportReady(report);
                        }
                        catch { }
                    }

                    m_checkForSampleEvent.Reset();
                    m_checkForSampleEvent.WaitOne(CHECK_FORSAMPLE_PERIOD, false);
                }
            }
            catch (Exception excp)
            {
                logger.Debug("Exception CheckForSamples. " + excp.Message);
            }
        }
Example #2
0
        private void m_rtcpSampler_RTCPReportReady(RTCPReport rtcpReport)
        {
            if (rtcpReport != null && RTCPReportReady != null)
            {
                try
                {
                    RTCPReportReady(rtcpReport);
                    rtcpReport.LastReceivedReportNumber = LastReceivedReportNumber;

                    //if (rtcpReport.ReportNumber % 3 != 0)
                    //{
                    SendRTCPReport(RTCPReportTypesEnum.RTCP, rtcpReport.GetBytes());
                    //}
                }
                catch (Exception excp)
                {
                    logger.Error("Exception m_rtcpSampler_RTCPReportReady. " + excp.Message);
                }
            }
        }
Example #3
0
        /// <summary>
        /// All times passed into this method should already be UTC.
        /// </summary>
        private RTCPReport Sample(UInt16 sampleStartSequenceNumber, UInt16 sampleEndSequenceNumber, TimeSpan sampleDuration)
        {
            try
            {
                RTCPReport sample = new RTCPReport(m_rtpStreamId, m_syncSource, m_remoteEndPoint);
                sample.ReportNumber    = m_reportNumber;
                sample.SampleStartTime = DateTime.MinValue;
                //sample.SampleEndTime = DateTime.MinValue;
                sample.StartSequenceNumber = sampleStartSequenceNumber;
                sample.Duration            = Convert.ToUInt64(sampleDuration.TotalMilliseconds);

                double jitterTotal = 0;
                //double transitTotal = 0;

                int endSequence = (sampleEndSequenceNumber < sampleStartSequenceNumber) ? sampleEndSequenceNumber + UInt16.MaxValue + 1 : sampleEndSequenceNumber;

                // logger.Debug("Sampling range " + sampleStartSequenceNumber + " to " + endSequence);

                for (int index = sampleStartSequenceNumber; index <= endSequence; index++)
                {
                    UInt16 testSeqNum = (index > UInt16.MaxValue) ? Convert.ToUInt16((index % UInt16.MaxValue) - 1) : Convert.ToUInt16(index);
                    //logger.Debug("Sampling " + testSeqNum + ".");

                    if (m_rcvdSeqNums.ContainsKey(testSeqNum))
                    {
                        RTPReceiveRecord measurement = m_rcvdSeqNums[testSeqNum];

                        //sample.SampleEndTime = measurement.SendTime;

                        if (sample.SampleStartTime == DateTime.MinValue)
                        {
                            sample.SampleStartTime = measurement.ReceiveTime;
                        }

                        sample.SampleEndTime     = measurement.ReceiveTime;
                        sample.EndSequenceNumber = measurement.SequenceNumber;
                        sample.TotalPackets++;
                        sample.BytesReceived += (uint)measurement.RTPBytes;

                        if (measurement.Duplicates > 0)
                        {
                            logger.Debug("Duplicates for " + testSeqNum + " number " + measurement.Duplicates);
                            sample.Duplicates += (uint)measurement.Duplicates;
                        }

                        if (!measurement.InSequence)
                        {
                            logger.Debug("OutOfOrder for " + testSeqNum);
                            sample.OutOfOrder++;
                        }
                        else
                        {
                            // It is possible for the jitter to be negative as an average measurement is being used for the transit time and
                            // some transits could be slightly less than the average.
                            //double jitter = Math.Abs(measurement.ReceiveTime.Subtract(measurement.SendTime).TotalMilliseconds - averageTransitTime);

                            jitterTotal += measurement.Jitter;
                            //transitTotal += measurement.AverageTransit;

                            if (measurement.Jitter > sample.JitterMaximum)
                            {
                                //logger.Debug("Jitter max set to " + measurement.Jitter + " for sequence number " + measurement.SequenceNumber);
                                sample.JitterMaximum = (uint)measurement.Jitter;
                            }
                        }

                        if (measurement.JitterBufferDiscard)
                        {
                            logger.Debug("Jitter discard for " + testSeqNum);
                            sample.JitterDiscards++;
                        }

                        // Remove the measurement from the buffer.
                        // Remove the RTP measurements now that they have been sampled.
                        lock (m_rcvdSeqNums)
                        {
                            //logger.Debug("Removing " + index);
                            m_rcvdSeqNums.Remove(testSeqNum);
                        }
                    }
                    else
                    {
                        logger.Debug("Packet drop for " + index);
                        sample.PacketsLost++;
                    }
                }

                // Calculate the average jitter.
                if (sample.TotalPackets > 0)
                {
                    sample.JitterAverage = Convert.ToUInt32(jitterTotal / sample.TotalPackets);
                }

                // Calculate the average transit.
                //if (sample.TotalPackets > 0)
                //{
                //    sample.AverageTransitTime = Convert.ToUInt32(transitTotal / sample.TotalPackets);
                //}

                // Calculate the transmission rate.
                double packetRate = 0;
                if (sampleDuration.TotalMilliseconds > 0)
                {
                    sample.TransmissionRate = Convert.ToUInt32(sample.BytesReceived * 8 / sampleDuration.TotalSeconds);
                    packetRate = sample.TotalPackets / sampleDuration.TotalSeconds;
                }

                string rtcpReport = String.Format(RTCP_FORMAT_STRING, new object[] {
                    sample.SyncSource,
                    sample.SampleStartTime.ToString("HH:mm:ss:fff"),
                    sample.SampleEndTime.ToString("HH:mm:ss:fff"),
                    sampleDuration.TotalMilliseconds.ToString("0"),
                    sample.StartSequenceNumber.ToString(),
                    sample.EndSequenceNumber.ToString(),
                    sample.TotalPackets.ToString(),
                    sample.JitterMaximum.ToString("0"),
                    sample.JitterAverage.ToString("0.##"),
                    sample.AverageTransitTime.ToString("0.##"),
                    packetRate.ToString("0.##"),
                    sample.BytesReceived.ToString(),
                    sample.TransmissionRate.ToString("0.##"),
                    sample.PacketsLost.ToString(),
                    sample.JitterDiscards.ToString(),
                    sample.Duplicates.ToString(),
                    sample.OutOfOrder.ToString()
                });

                logger.Info(rtcpReport);

                //logger.Info("start=" + sample.SampleStartTime.ToString("HH:mm:ss:fff") + ",end=" + sample.SampleEndTime.ToString("HH:mm:ss:fff") + ",dur=" + sampleDuration.TotalMilliseconds.ToString("0") + "ms" +
                //    ",seqnnumstart=" + sample.StartSequenceNumber + ",seqnumend=" + sample.EndSequenceNumber + ",pktstotal=" + sample.TotalPackets + "p,pktrate=" + packetRate.ToString("0.##") + "pps,bytestotal=" + sample.BytesReceived + "B,bw=" + sample.TransmissionRate.ToString("0.##") + "Kbps,jitteravg=" +
                //    sample.JitterAverage.ToString("0.##") + ",jittermax=" + sample.JitterMaximum.ToString("0.##") + ",pktslost=" + sample.PacketsLost + ",jitterdiscards=" + sample.JitterDiscards + ",duplicates=" + sample.Duplicates + ",outoforder=" + sample.OutOfOrder);

                return(sample);
            }
            catch (Exception excp)
            {
                logger.Error("Exception Sample. " + excp.Message);
                return(null);
            }
            finally
            {
                m_reportNumber++;
            }
        }
Example #4
0
        /// <summary>
        /// A sample is taken if the last RTP measurement recorded is 4x the sample time since the last last smaple was taken.
        /// The 4x is needed in order to be able to take into account late arriving packets as out of order rather then as drops.
        /// </summary>
        /// <param name="sequenceNumber"></param>
        private RTCPReport CheckForAvailableSample(UInt16 sequenceNumber)
        {
            try
            {
                //logger.Debug("Check for available sample " + sequenceNumber + ".");
                RTCPReport sample = null;

                RTPReceiveRecord measurement = m_rcvdSeqNums[sequenceNumber];

                //logger.Debug("window start seq num=" + m_windowStartSeqNum);
                RTPReceiveRecord startSampleMeasuerment = m_rcvdSeqNums[m_windowStartSeqNum];

                UInt16   endSampleSeqNum         = 0;
                UInt16   endSampleSeqNumMinusOne = 0;
                int      samplesAvailable        = 0;
                DateTime sampleCutOffTime;

                bool sampleAvailable = false;

                // Determine whether a sample of the RTP stream measurements should be taken.
                if (DateTime.Now.Subtract(m_lastSampleTime).TotalMilliseconds > (4 * ReportSampleDuration))
                {
                    // Make the sample a random size between N and 2N
                    int randomElement  = Crypto.GetRandomInt(ReportSampleDuration, 2 * ReportSampleDuration);
                    int sampleDuration = ReportSampleDuration + randomElement;
                    sampleCutOffTime = m_lastSampleTime.AddMilliseconds(sampleDuration);

                    //logger.Debug("Sample duration=" + sampleDuration + "ms, cut off time=" + sampleCutOffTime.ToString("HH:mm:ss:fff") + ".");

                    // Get the list of RTP measurements from last time a sample was taken up to the last receive within the window.
                    int endSeqNum = (sequenceNumber < m_windowStartSeqNum) ? sequenceNumber + UInt16.MaxValue + 1: sequenceNumber;
                    //logger.Debug("Checking for sample from " + m_windowStartSeqNum + " to " + endSeqNum + ".");
                    for (int seqNum = m_windowStartSeqNum; seqNum <= endSeqNum; seqNum++)
                    {
                        UInt16 testSeqNum = (seqNum > UInt16.MaxValue) ? Convert.ToUInt16((seqNum % UInt16.MaxValue) - 1) : Convert.ToUInt16(seqNum);

                        if (m_rcvdSeqNums.ContainsKey(testSeqNum))
                        {
                            //logger.Debug(testSeqNum + " " + m_rcvdSeqNums[testSeqNum].ReceiveTime.ToString("ss:fff") + "<" + sampleCutOffTime.ToString("ss:fff") + ".");

                            if (m_rcvdSeqNums[testSeqNum].ReceiveTime < sampleCutOffTime)
                            {
                                samplesAvailable++;
                                endSampleSeqNum = testSeqNum;
                            }
                            else
                            {
                                endSampleSeqNumMinusOne = endSampleSeqNum;
                                endSampleSeqNum         = testSeqNum;
                                sampleAvailable         = true;
                                break;
                            }
                        }
                    }
                }

                /*if (m_rcvdSeqNums.Count > 200)
                 * {
                 *  endSampleSeqNum = m_windowSecondLastSeqNum;
                 *  sampleAvailable = true;
                 * }*/

                if (sampleAvailable)
                {
                    //logger.Debug(samplesAvailable + " ready for RTCP sampling, start seq num=" + m_windowStartSeqNum + " to " + endSampleSeqNumMinusOne + ".");

                    TimeSpan measurementsSampleDuration = m_rcvdSeqNums[endSampleSeqNumMinusOne].ReceiveTime.Subtract(m_rcvdSeqNums[m_windowStartSeqNum].ReceiveTime);
                    //logger.Debug("Sample available start seq num=" + m_windowStartSeqNum + " end seq num=" + endSampleSeqNumMinusOne + ", " + measurementsSampleDuration.TotalMilliseconds.ToString("0") + ".");

                    sample = Sample(m_windowStartSeqNum, endSampleSeqNumMinusOne, measurementsSampleDuration);

                    m_windowStartSeqNum = endSampleSeqNum;
                    m_lastSampleTime    = m_rcvdSeqNums[endSampleSeqNum].ReceiveTime;
                }

                return(sample);
            }
            catch (Exception excp)
            {
                logger.Error("Exception CheckForAvailableSample. " + excp.Message);
                return(null);
            }
        }