示例#1
0
        //Test AddReports And Enumerator And Reserialization

        public static void Test_RFC3550_Page40_Figure2()
        {
            //Create a random id
            int RandomId = RFC3550.Random32(Utility.Random.Next());

            //Create a SendersReport instance using the specified options.
            using (Media.Rtcp.SendersReport p = new Rtcp.SendersReport(2, 0, 0, RandomId))
            {
                //Let LSR =
                DateTime ExpectedDateTime = new DateTime(1995, 11, 10, 11, 33, 25, 125, DateTimeKind.Utc); //n = LSR //

                //sec = 0xb44d_b705
                p.NtpMSW = -1269975291; //unchecked((int)3024992005);

                //frac = 0x2000_0000
                p.NtpLSW = 536870912;

                //Ensure was written and read correctly
                if (p.NtpDateTime != ExpectedDateTime)
                {
                    throw new Exception("NtpDateTime does not equal ExpectedDate: " + p.NtpDateTime);
                }

                //The middle 32 bits out of 64 in the NTP timestamp (as explained in Section 4) received as part of the most recent RTCP sender report (SR) packet from source SSRC_n. If no SR has been received yet, the field is set to zero.
                if ((ulong)((p.NtpTimestamp) >> 16) << 32 != 0xB705200000000000)
                {
                    throw new Exception();
                }

                //In Seconds, DSLR = 0x0005:4000 (5.250s)
                const double ExpectedDelay = 5.250;

                //Let A =
                DateTime A = new DateTime(1995, 11, 10, 11, 33, 36, 500, DateTimeKind.Utc); //.ToString("s.ffff")

                //The delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from source SSRC_n and sending this reception report block. If no SR packet has been received yet from SSRC_n, the DLSR field is set to zero.
                TimeSpan delay = A.Subtract(TimeSpan.FromSeconds(ExpectedDelay)).Subtract(ExpectedDateTime);

                //46864.500 - 5.250 - 46853.125 = 6.125
                if (delay.TotalSeconds != 6.125)
                {
                    throw new Exception("Unexpected delay of: " + delay.ToString());
                }
            }
        }
示例#2
0
        /// <summary>
        /// O( )
        /// </summary>
        public static void TestAConstructor_And_Reserialization()
        {
            //Permute every possible value in the 5 bit BlockCount
            for (byte ReportBlockCounter = byte.MinValue; ReportBlockCounter <= Media.Common.Binary.FiveBitMaxValue; ++ReportBlockCounter)
            {
                //Permute every possible value in the Padding field.
                for (byte PaddingCounter = byte.MinValue; PaddingCounter <= Media.Common.Binary.FiveBitMaxValue; ++PaddingCounter)
                {
                    //Create a random id
                    int RandomId = RFC3550.Random32(Utility.Random.Next());

                    //Create a SendersReport instance using the specified options.
                    using (Media.Rtcp.SendersReport p = new Rtcp.SendersReport(0, PaddingCounter, ReportBlockCounter, RandomId))
                    {
                        //Check SendersInformation
                        System.Diagnostics.Debug.Assert(p.SendersInformation.Count() == Rtcp.SendersReport.SendersInformationSize && p.SendersInformation.All(s=> s== 0), "Unexpected SendersInformation");

                        //Check IsComplete
                        System.Diagnostics.Debug.Assert(p.IsComplete, "IsComplete must be true.");

                        //Check Length
                        System.Diagnostics.Debug.Assert(p.Length == Binary.BitsPerByte + Rtcp.ReportBlock.ReportBlockSize * ReportBlockCounter + Rtcp.SendersReport.SendersInformationSize + PaddingCounter, "Unexpected Length");

                        //Check SynchronizationSourceIdentifier
                        System.Diagnostics.Debug.Assert(p.SynchronizationSourceIdentifier == RandomId, "Unexpected SynchronizationSourceIdentifier");

                        //Check the BlockCount count
                        System.Diagnostics.Debug.Assert(p.BlockCount == ReportBlockCounter, "Unexpected BlockCount");

                        //Check the PaddingOctets count
                        System.Diagnostics.Debug.Assert(p.PaddingOctets == PaddingCounter, "Unexpected PaddingOctets");

                        //Check all data in the padding but not the padding octet itself.
                        System.Diagnostics.Debug.Assert(p.PaddingData.Take(PaddingCounter - 1).All(b => b == 0), "Unexpected PaddingData");

                        //Verify all IReportBlock
                        foreach (Rtcp.IReportBlock rb in p)
                        {
                            System.Diagnostics.Debug.Assert(rb.BlockIdentifier == 0, "Unexpected ChunkIdentifier");

                            System.Diagnostics.Debug.Assert(rb.BlockData.All(b => b == 0), "Unexpected BlockData");

                            System.Diagnostics.Debug.Assert(rb.Size == Media.Rtcp.ReportBlock.ReportBlockSize, "Unexpected Size");
                        }

                        //Serialize and Deserialize and verify again
                        using (Rtcp.SendersReport s = new Rtcp.SendersReport(new Rtcp.RtcpPacket(p.Prepare().ToArray(), 0), true))
                        {
                            //Check SynchronizationSourceIdentifier
                            System.Diagnostics.Debug.Assert(s.SynchronizationSourceIdentifier == p.SynchronizationSourceIdentifier, "Unexpected SynchronizationSourceIdentifier");

                            //Check the Payload.Count
                            System.Diagnostics.Debug.Assert(s.Payload.Count == p.Payload.Count, "Unexpected Payload Count");

                            //Check the Length,
                            System.Diagnostics.Debug.Assert(s.Length == p.Length, "Unexpected Length");

                            //Check the BlockCount count
                            System.Diagnostics.Debug.Assert(s.BlockCount == p.BlockCount, "Unexpected BlockCount");

                            //Verify all IReportBlock
                            foreach (Rtcp.IReportBlock rb in s)
                            {
                                System.Diagnostics.Debug.Assert(rb.BlockIdentifier == 0, "Unexpected ChunkIdentifier");

                                System.Diagnostics.Debug.Assert(rb.BlockData.All(b => b == 0), "Unexpected BlockData");

                                System.Diagnostics.Debug.Assert(rb.Size == Media.Rtcp.ReportBlock.ReportBlockSize, "Unexpected Size");
                            }

                            //Check the RtcpData
                            System.Diagnostics.Debug.Assert(p.RtcpData.SequenceEqual(s.RtcpData), "Unexpected RtcpData");

                            //Check the PaddingOctets
                            System.Diagnostics.Debug.Assert(s.PaddingOctets == p.PaddingOctets, "Unexpected PaddingOctets");

                            //Check all data in the padding but not the padding octet itself.
                            System.Diagnostics.Debug.Assert(s.PaddingData.SequenceEqual(p.PaddingData), "Unexpected PaddingData");

                            //Check SendersInformation
                            System.Diagnostics.Debug.Assert(s.SendersInformation.Count() == Rtcp.SendersReport.SendersInformationSize && s.SendersInformation.All(o => o == 0), "Unexpected SendersInformation");
                        }
                    }
                }
            }
        }
示例#3
0
        /// <summary>
        /// Prepares the text in the stream which corresponds to the RtcpData of a Rtcp.RtcpPacket.
        /// </summary>
        /// <param name="format">The <see cref="FileFormat"/> to output.</param>
        /// <param name="packet">The <see cref="Rtcp.RtcpPacket"/> to describe</param>
        /// <returns>The text describes the packet if the <paramref name="format"/> is a text format, otherwise an empty string</returns>
        public static string ToTextualConvention(FileFormat format, Rtcp.RtcpPacket packet)
        {
            if (packet == null || packet.Payload.Count == 0 || format < FileFormat.Text || format == FileFormat.Short) return string.Empty;

            if(format == FileFormat.Unknown) return UnknownSpecifier;

            //Determine the format to use as well as the `Conventional Abbreviation`
            switch (packet.PayloadType)
            {
                case Rtcp.SourceDescriptionReport.PayloadType:
                    //Use a SourceDescriptionReport to enumerate the SourceDescriptionChunk's and SourceDescriptionItem's contained in the packet.
                    using (var sdes = new Rtcp.SourceDescriptionReport(packet, false)) //Don't dispose the packet when done.
                    {
                        return string.Format(RtcpExpressionFormat,
                            "SDES",
                            packet.SynchronizationSourceIdentifier,
                            packet.Padding ? 1.ToString() : 0.ToString(),
                            packet.BlockCount,
                            packet.Header.LengthInWordsMinusOne, ToTextualConvention(sdes));
                    }
                case Rtcp.SendersReport.PayloadType:
                    using (var sr = new Rtcp.SendersReport(packet, false))
                    {
                        return string.Format(RtcpExpressionFormat,
                            "SR",
                            packet.SynchronizationSourceIdentifier,
                            packet.Padding ? 1.ToString() : 0.ToString(),
                            packet.BlockCount,
                            packet.Header.LengthInWordsMinusOne,
                            (ToTextualConvention(sr) + (char)Common.ASCII.Space + string.Format(RtcpSendersInformationFormat,
                            //0
                                (DateTime.UtcNow - sr.NtpTime).TotalSeconds.ToString("0.000000"), //ts=
                            //1
                                sr.NtpTimestamp, //ntp=
                            //2
                                sr.SendersOctetCount, //osent=
                            //3
                                sr.SendersPacketCount))); //psent=
                    }
                case Rtcp.ReceiversReport.PayloadType:
                    using (var rr = new Rtcp.ReceiversReport(packet, false))
                    {
                        return string.Format(RtcpExpressionFormat,
                            "RR",
                            packet.SynchronizationSourceIdentifier,
                            packet.Padding ? 1.ToString() : 0.ToString(),
                            packet.BlockCount,
                            packet.Header.LengthInWordsMinusOne,
                            ToTextualConvention(rr));
                    }
                case Rtcp.GoodbyeReport.PayloadType:
                    using (var bye = new Rtcp.GoodbyeReport(packet, false))
                    {
                        return string.Format(RtcpExpressionFormat,
                            "BYE",
                            packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(),
                            packet.BlockCount,
                            packet.Header.LengthInWordsMinusOne, ToTextualConvention(bye));
                    }
                case Rtcp.ApplicationSpecificReport.PayloadType:
                    return string.Format(RtcpExpressionFormat, "APP", packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, string.Empty);
                default:
                    //Unknown PayloadType use a Hex Representation of the PayloadType
                    return string.Format(RtcpExpressionFormat, packet.PayloadType.ToString("X"), packet.SynchronizationSourceIdentifier, packet.Padding ? 1.ToString() : 0.ToString(), packet.BlockCount, packet.Header.LengthInWordsMinusOne, string.Empty);
            }
        }
示例#4
0
        /// <summary>
        /// O( )
        /// </summary>
        public static void TestAConstructor_And_Reserialization()
        {
            //Permute every possible value in the 5 bit BlockCount
            for (byte ReportBlockCounter = byte.MinValue; ReportBlockCounter <= Media.Common.Binary.FiveBitMaxValue; ++ReportBlockCounter)
            {
                //Permute every possible value in the Padding field.
                for (byte PaddingCounter = byte.MinValue; PaddingCounter <= Media.Common.Binary.FiveBitMaxValue; ++PaddingCounter)
                {
                    //Create a random id
                    int RandomId = RFC3550.Random32(Utility.Random.Next());

                    //Create a SendersReport instance using the specified options.
                    using (Media.Rtcp.SendersReport p = new Rtcp.SendersReport(0, PaddingCounter, ReportBlockCounter, RandomId))
                    {
                        //Check SendersInformation
                        System.Diagnostics.Debug.Assert(p.SendersInformation.Count() == Rtcp.SendersReport.SendersInformationSize, "Unexpected SendersInformation Count");

                        System.Diagnostics.Debug.Assert(p.SendersInformation.All(s => s == 0), "Unexpected SendersInformation Data");

                        //Check IsComplete
                        System.Diagnostics.Debug.Assert(p.IsComplete, "IsComplete must be true.");

                        //Check Length
                        System.Diagnostics.Debug.Assert(p.Length == Binary.BitsPerByte + Rtcp.ReportBlock.ReportBlockSize * ReportBlockCounter + Rtcp.SendersReport.SendersInformationSize + PaddingCounter, "Unexpected Length");

                        //Check SynchronizationSourceIdentifier
                        System.Diagnostics.Debug.Assert(p.SynchronizationSourceIdentifier == RandomId, "Unexpected SynchronizationSourceIdentifier");

                        //Check the BlockCount count
                        System.Diagnostics.Debug.Assert(p.BlockCount == ReportBlockCounter, "Unexpected BlockCount");

                        //Check the PaddingOctets count
                        System.Diagnostics.Debug.Assert(p.PaddingOctets == PaddingCounter, "Unexpected PaddingOctets");

                        //Check all data in the padding but not the padding octet itself.
                        System.Diagnostics.Debug.Assert(p.PaddingData.Take(PaddingCounter - 1).All(b => b == 0), "Unexpected PaddingData");

                        //Verify all IReportBlock
                        foreach (Rtcp.IReportBlock rb in p)
                        {
                            System.Diagnostics.Debug.Assert(rb.BlockIdentifier == 0, "Unexpected ChunkIdentifier");

                            System.Diagnostics.Debug.Assert(rb.BlockData.All(b => b == 0), "Unexpected BlockData");

                            System.Diagnostics.Debug.Assert(rb.Size == Media.Rtcp.ReportBlock.ReportBlockSize, "Unexpected Size");
                        }

                        //Serialize and Deserialize and verify again
                        using (Rtcp.SendersReport s = new Rtcp.SendersReport(new Rtcp.RtcpPacket(p.Prepare().ToArray(), 0), true))
                        {
                            //Check SynchronizationSourceIdentifier
                            System.Diagnostics.Debug.Assert(s.SynchronizationSourceIdentifier == p.SynchronizationSourceIdentifier, "Unexpected SynchronizationSourceIdentifier");

                            //Check the Payload.Count
                            System.Diagnostics.Debug.Assert(s.Payload.Count == p.Payload.Count, "Unexpected Payload Count");

                            //Check the Length,
                            System.Diagnostics.Debug.Assert(s.Length == p.Length, "Unexpected Length");

                            //Check the BlockCount count
                            System.Diagnostics.Debug.Assert(s.BlockCount == p.BlockCount, "Unexpected BlockCount");

                            //Verify all IReportBlock
                            foreach (Rtcp.IReportBlock rb in s)
                            {
                                System.Diagnostics.Debug.Assert(rb.BlockIdentifier == 0, "Unexpected ChunkIdentifier");

                                System.Diagnostics.Debug.Assert(rb.BlockData.All(b => b == 0), "Unexpected BlockData");

                                System.Diagnostics.Debug.Assert(rb.Size == Media.Rtcp.ReportBlock.ReportBlockSize, "Unexpected Size");
                            }

                            //Check the RtcpData
                            System.Diagnostics.Debug.Assert(p.RtcpData.SequenceEqual(s.RtcpData), "Unexpected RtcpData");

                            //Check the PaddingOctets
                            System.Diagnostics.Debug.Assert(s.PaddingOctets == p.PaddingOctets, "Unexpected PaddingOctets");

                            //Check all data in the padding but not the padding octet itself.
                            System.Diagnostics.Debug.Assert(s.PaddingData.SequenceEqual(p.PaddingData), "Unexpected PaddingData");

                            //Check SendersInformation
                            System.Diagnostics.Debug.Assert(s.SendersInformation.Count() == Rtcp.SendersReport.SendersInformationSize && s.SendersInformation.All(o => o == 0), "Unexpected SendersInformation");
                        }
                    }
                }
            }
        }
示例#5
0
        //6.3.2 Initialization....
        //I will do no such thing, I will no have no table when no table is required such as be the case when no expectance is put on the identity of the recipient.
        //All such packets should be considered equal unless specifically negioated by means provided by an alternate mechanism such as SDP or the RTP-Info header and is beyond the scope of the RtpClient implementation [based on my interpretation that is.]
        //I could go on and on about this but I think we all get the point
        //6.3.3 Rtp or Rtcp
        protected internal virtual void HandleIncomingRtcpPacket(object rtpClient, RtcpPacket packet)
        {
            //Determine if the packet can be handled
            if (IsDisposed || false == RtcpEnabled || false == HandleIncomingRtcpPackets || packet == null || packet.IsDisposed) return;

            //Raise an event for the rtcp packet received
            OnRtcpPacketReceieved(packet);

            //Get a context for the packet by the identity of the receiver
            TransportContext transportContext = null;

            //Cache the ssrc of the packet's sender.
            int partyId = packet.SynchronizationSourceIdentifier;

            //See if there is a context for the remote party. (Allows 0)
            transportContext = GetContextBySourceId(partyId);

            //Only if the packet was not addressed to a unique party with the id of 0
            if (partyId != 0 &&
                transportContext == null ||
                transportContext.InDiscovery) //The remote party has not yet been identified.
            {
                //Cache the payloadType and blockCount
                int payloadType = packet.PayloadType,
                    blockCount = packet.BlockCount;

                //Check the type

                if (payloadType == Rtcp.ReceiversReport.PayloadType &&  //The packet is a RecieversReport
                    blockCount > 0)//There is at least 1 block
                {
                    //Create a wrapper around the packet to access the ReportBlocks
                    using (var rr = new Rtcp.ReceiversReport(packet, false))
                    {
                        //Iterate each contained ReportBlock
                        foreach (Rtcp.IReportBlock reportBlock in rr)
                        {
                            int blockId = reportBlock.BlockIdentifier;

                            //Attempt to obtain a context by the identifier in the report block
                            transportContext = GetContextBySourceId(blockId);

                            //If there was a context and the remote party has not yet been identified.
                            if (transportContext != null && transportContext.InDiscovery)
                            {
                                //Identify the remote party by this id.
                                transportContext.RemoteSynchronizationSourceIdentifier = partyId;

                                Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleIncomingRtcpPacket Set RemoteSynchronizationSourceIdentifier @ " + transportContext.SynchronizationSourceIdentifier + " to=" + transportContext.RemoteSynchronizationSourceIdentifier + "RR blockId=" + blockId);

                                //Stop looking for a context.
                                break;
                            }
                        }
                    }
                }
                else if (payloadType == Rtcp.GoodbyeReport.PayloadType &&
                    blockCount > 0) //The GoodbyeReport report from a remote party
                {
                    //Create a wrapper around the packet to access the source list
                    using (var gb = new Rtcp.GoodbyeReport(packet, false))
                    {
                        using (var sl = gb.GetSourceList())
                        {
                            //Iterate each party leaving
                            foreach (int party in sl)
                            {
                                //Attempt to obtain a context by the identifier in the report block
                                transportContext = GetContextBySourceId(party);

                                //If there was a context
                                if (transportContext != null &&
                                    false == transportContext.IsDisposed)
                                {
                                    //Send report now if possible.
                                    bool reportsSent = SendReports(transportContext);

                                    Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleIncomingRtcpPacket Recieved Goodbye @ " + transportContext.SynchronizationSourceIdentifier + " from=" + partyId + " reportSent=" + reportsSent);

                                    //Stop looking for a context.
                                    break;
                                }
                            }
                        }
                    }
                }
                else if (payloadType == Rtcp.SendersReport.PayloadType) //The senders report from a remote party
                {
                    //If there is a context
                    if (transportContext != null)
                    {
                        //The context is valid and still discovering a remote identity
                        if (transportContext.IsValid && transportContext.InDiscovery)
                        {
                            //Assign it
                            transportContext.RemoteSynchronizationSourceIdentifier = partyId;

                            Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleIncomingRtcpPacket Set RemoteSynchronizationSourceIdentifier @ " + transportContext.SynchronizationSourceIdentifier + " to=" + transportContext.RemoteSynchronizationSourceIdentifier + " SR=" + partyId);

                        } //If the context has been identified by an identity other than the remote party of the packet
                        else if (transportContext.RemoteSynchronizationSourceIdentifier != partyId)
                        {
                            //Attempt to obtain a context by the identity used previously
                            transportContext = GetContextBySourceId(partyId);

                            //If ther is no longer a context or the context cannot handle the packet
                            if (transportContext == null ||
                                transportContext.IsDisposed)
                            {
                                goto NoContext;
                            }

                            //If the context needs a remote identity and is still not yet valid
                            if (transportContext.InDiscovery && false == transportContext.IsValid)
                            {
                                //Assign it
                                transportContext.RemoteSynchronizationSourceIdentifier = partyId;

                                Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleIncomingRtcpPacket Set RemoteSynchronizationSourceIdentifier @ " + transportContext.SynchronizationSourceIdentifier + " to=" + transportContext.RemoteSynchronizationSourceIdentifier + " SR=" + partyId);
                            }

                        }
                    }//Validate by using the blocks of the report if possible
                    else if (blockCount > 0)
                    {
                        //Create a wrapper around the packet to access the ReportBlocks
                        using (var sr = new Rtcp.SendersReport(packet, false))
                        {
                            //Iterate each contained ReportBlock
                            foreach (Rtcp.IReportBlock reportBlock in sr)
                            {
                                int blockId = reportBlock.BlockIdentifier;

                                //Attempt to obtain a context by the identifier in the report block
                                var context = GetContextBySourceId(reportBlock.BlockIdentifier);

                                //If there was a context
                                if (context != null)
                                {
                                    //if the context found identifies the context assumed
                                    if (context.SynchronizationSourceIdentifier == transportContext.SynchronizationSourceIdentifier)
                                    {
                                        //Identify the remote party by this id.
                                        transportContext.RemoteSynchronizationSourceIdentifier = packet.SynchronizationSourceIdentifier;

                                        Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@HandleIncomingRtcpPacket Set RemoteSynchronizationSourceIdentifier @ " + transportContext.SynchronizationSourceIdentifier + " to=" + transportContext.RemoteSynchronizationSourceIdentifier + "SR blockId=" + blockId);

                                        //Remove any reference
                                        context = null;

                                        //Stop looking for a context.
                                        break;
                                    }
                                }
                            }

                            //might not have checked anything if the list was 'incomplete'..
                        }
                    }
                }
            }

            //Handle Goodbyes with a positive blockcount but no  sourcelist...?

            NoContext:

            //If no transportContext could be found
            if (transportContext == null)
            {
                //Attempt to see if this was a rtp packet by using the RtpPayloadType
                int rtpPayloadType = packet.Header.First16Bits.RtpPayloadType;

                if (rtpPayloadType == 13 || GetContextByPayloadType(rtpPayloadType) != null)
                {
                    Media.Common.ILoggingExtensions.Log(Logger, InternalId + "HandleIncomingRtcpPacket - Incoming RtcpPacket actually was Rtp. Ssrc= " + partyId + " Type=" + rtpPayloadType + " Len=" + packet.Length);

                    //Raise an event for the 'RtpPacket' received.
                    //Todo Use the existing reference / memory of the RtcpPacket)
                    OnRtpPacketReceieved(new RtpPacket(packet.Prepare().ToArray(), 0));

                    //Don't do anything else
                    return;
                }

                //Could attempt to find the context in which this packet is trying to communicate with if we had a RemoteEndPoint indicating where the packet was received from...
                //Cannot find a context because there may be more then one context which has not yet been identified
                //Could attempt to check that there is only 1 context and then if not yet valid assign the identity...
                //if(TransportContexts.Count == 1) ...

                Media.Common.ILoggingExtensions.Log(Logger, InternalId + "HandleIncomingRtcpPacket - No Context for packet " + partyId + "@" + packet.PayloadType);

                //Don't do anything else.
                return;
            }

            //There is a transportContext

            //If there is a collision in the unique identifiers
            if (transportContext.SynchronizationSourceIdentifier == partyId)
            {
                //Handle it.
                HandleCollision(transportContext);
            }

            //Make a copy of the packet now and only refer to this copy
            RtcpPacket localPacket = packet;

            #region Unused [Packet Completion]

            //Complete the RtcpPacket if required.
            //while (!localPacket.IsComplete)
            //{
            //    //Complete the packet.
            //    int received = localPacket.CompleteFrom(transportContext.RtcpSocket, localPacket.Payload);
            //}

            #endregion

            //Last Rtcp packet was received right now now.
            transportContext.m_LastRtcpIn = packet.Created;

            //The context is active.
            transportContext.m_InactiveTime = Media.Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan;

            //Don't worry about overflow
            unchecked
            {
                //Increment packets received for the valid context.
                ++transportContext.RtcpPacketsReceived;

                //Keep track of the the bytes sent in the context
                transportContext.RtcpBytesRecieved += localPacket.Length;

                //Set the time when the first rtcp packet was recieved
                if (transportContext.m_FirstPacketReceived == DateTime.MinValue) transportContext.m_FirstPacketReceived = packet.Created;
            }

            #region Unused [Handle if packet was Goodbye]

            //bool goodBye = packet.PayloadType == Rtcp.GoodbyeReport.PayloadType;

            ////If the context is valid, AND the remote identify has a value and the packet identity is not the same then reset the state and account for the new identity
            //if (transportContext.IsValid && transportContext.RemoteSynchronizationSourceIdentifier.HasValue && localPacket.SynchronizationSourceIdentifier != transportContext.RemoteSynchronizationSourceIdentifier)
            //{
            //    //Tell the source we are no longer listening to the old identity
            //    //SendGoodbye(transportContext);

            //    //Reset state for the counters
            //    //transportContext.ResetState();

            //    //Assign the new remote ID (EVENT?)
            //    transportContext.RemoteSynchronizationSourceIdentifier = localPacket.SynchronizationSourceIdentifier;

            //    //Send reports if we can unless this is a Goodbye
            //    /*if (!goodBye) */SendReports(transportContext);
            //}

            //if (goodBye && packet.BlockCount > 0) transportContext.m_SendInterval = Media.Common.Extensions.TimeSpan.TimeSpanExtensions.InfiniteTimeSpan; //Then never send reports again?

            #endregion
        }