Beispiel #1
0
 /// <summary>
 /// Constructs a new GoodbyeReport from the given values.
 /// </summary>
 /// <param name="version">The version of the report</param>
 /// <param name="padding"></param>
 /// <param name="ssrc">The id of the senders of the report</param>
 /// <param name="sourcesLeaving">The SourceList which describes the sources who are leaving</param>
 /// <param name="reasonForLeaving">An optional reason for leaving(only the first 255 octets will be used)</param>
 internal GoodbyeReport(int version, int padding, int ssrc, Media.RFC3550.SourceList sourcesLeaving, byte[] reasonForLeaving)
     : this(version, padding, ssrc,
            sourcesLeaving.Count + 1,                          //BlockCount, + 1 because the ssrc is present.
            0,                                                 // 0 is extensionSize which is assigned by the size of reasonForLeaving in the constructor via ref.
            sourcesLeaving.Count *RFC3550.SourceList.ItemSize, //bytesInSourceList
            reasonForLeaving)
 {
     sourcesLeaving.TryCopyTo(m_OwnedOctets, Payload.Offset);
 }
Beispiel #2
0
        /// <summary>
        /// Prepares a text description which is compatible with 'rtpsend' among other 'rtp tools'.
        /// </summary>
        /// <param name="format">The <see cref="FileFormat"/> to output.</param>
        /// <param name="packet">The <see cref="Rtp.RtpPacket"/> to describe</param>
        /// <param name="time">Timeoffset from when recoding began, should be 0 for the first packet.</param>
        /// <param name="source">The <see cref="System.Net.IPEndPoint"/> from which the packet was received.</param>
        /// <returns>The text which describes the packet if the <paramref name="format"/> is a text format, otherwise an empty string</returns>
        public static string ToTextualConvention(FileFormat format, Rtp.RtpPacket packet, TimeSpan time, System.Net.IPEndPoint source)
        {
            //StringBuilder?

            //If the format is Short (Vat or Rtp Data in tablular form)
            if (format == FileFormat.Short)
            {
                //Then return that format
                return string.Format(RtpSend.ShortFormat,
                    //0
                    time.TotalSeconds.ToString("0.000000"),
                    //1
                    (packet.Marker ? (-packet.SequenceNumber) : packet.SequenceNumber).ToString(),
                    //2
                    source.Port.ToString());
            }

            StringBuilder builder = new StringBuilder(64);

            //All Rtp are described with this format
            builder.Append(string.Format(RtpSend.Format,
                //0
                time.TotalSeconds.ToString("0.000000"),
                //1
                string.Format(RtpSend.RtpPacketFormat,
                    //0
                    packet.Length, //Packet size in bytes including header
                    //1
                    source.Address.ToString() + ':' + source.Port.ToString(),
                    //2
                    packet.Version.ToString(),
                    //3
                    packet.Padding ? "1" : "0",
                    //4
                    packet.Extension ? "1" : "0",
                    //5
                    packet.ContributingSourceCount.ToString(),
                    //6
                    packet.Marker ? "1" : "0",
                    //7
                    packet.PayloadType,
                    //8 (Format description)
                    string.Format(RtpSend.PayloadDescriptionFormat, packet.PayloadType, RtpSendExtensions.PayloadDescription(packet)),
                    //9
                    packet.SequenceNumber,
                    //10
                    packet.SynchronizationSourceIdentifier,
                    //11
                    packet.Timestamp                )));

            //Write the textual representation of the items in the sourceList
            if (packet.ContributingSourceCount > 0)
            {

                //Note
                //http://www.cs.columbia.edu/irt/software/rtptools/ChangeLog.html
                //States the format is not hex when in the format csrc[n]
                //However -
                //http://www.cs.columbia.edu/irt/software/rtptools/#rtpsend
                //States that the format is :
                //cc=<CSRC count>
                //csrc=<CSRC>
                //This is basically the same thing and a parsing semantic.

                using (Media.RFC3550.SourceList sl = new Media.RFC3550.SourceList(packet))
                {

                    if (sl == null)
                    {
                        builder.Append("#Incomplete Source List Not Included");
                        builder.Append((char)Common.ASCII.LineFeed);
                    }
                    else
                    {
                        //csrc=
                        while (sl.MoveNext())
                        {
                            builder.Append(string.Format(RtpSend.HexFormat, "csrc", HexSpecifier, sl.CurrentSource.ToString("X"), (char)Common.ASCII.LineFeed));
                        }
                    }
                }
            }

            //Write the textual representation of the Extension
            if (packet.Extension)
            {
                using (var rtpExtension = packet.GetExtension())
                {

                    if (rtpExtension == null)
                    {
                        builder.Append("#Incomplete Extension Not Included");
                        builder.Append((char)Common.ASCII.LineFeed);
                    }
                    else
                    {
                        builder.Append(string.Format(RtpSend.HexFormat, "ext_type", HexSpecifier + rtpExtension.Flags.ToString("X"), (char)Common.ASCII.LineFeed));

                        builder.Append(string.Format(RtpSend.NonQuotedFormat, "ext_len", rtpExtension.LengthInWords));
                        builder.Append((char)Common.ASCII.LineFeed);

                        builder.Append(string.Format(RtpSend.HexFormat, "ext_data",  BitConverter.ToString(rtpExtension.Data.ToArray()).Replace("-", string.Empty), (char)Common.ASCII.LineFeed));
                    }
                }
            }

            //If the format is hex then add the payload dump
            if (format == FileFormat.Hex)
            {
                var data = packet.PayloadData;
                if (data.Any()) builder.Append(string.Format(RtpSend.HexFormat, "data", BitConverter.ToString(data.ToArray()).Replace("-", string.Empty), (char)Common.ASCII.LineFeed));
                else builder.Append(string.Format(HexFormat, "data", NullSpecifier, (char)Common.ASCII.LineFeed));
            }

            //Return the result
            return builder.ToString();
        }
Beispiel #3
0
        /// <summary>
        /// O( )
        /// </summary>
        public static void TestAConstructor_And_Reserialization()
        {
            //Permute every possible value in the 5 bit BlockCount except the last, it is possible to have 32 with there are 31 entries in the SourceList, this logic should be tested seperately.
            for (byte SourceCounter = byte.MinValue; SourceCounter <= Media.Common.Binary.FiveBitMaxValue - 1; ++SourceCounter)
            {
                //Permute every possible value in the Padding field.
                for (byte PaddingCounter = byte.MinValue; PaddingCounter <= Media.Common.Binary.FiveBitMaxValue; ++PaddingCounter)
                {
                    //Enumerate every possible reason length within reason.
                    for (byte ReasonLength = byte.MinValue; ReasonLength <= Media.Common.Binary.FiveBitMaxValue; ++ReasonLength)
                    {
                        //Create the RandomId and ReasonForLeaving

                        int RandomId = RFC3550.Random32(Utility.Random.Next());

                        IEnumerable <byte> ReasonForLeaving = Array.ConvertAll(Enumerable.Range(1, (int)ReasonLength).ToArray(), Convert.ToByte);

                        //Create a GoodbyeReport instance using the specified options.
                        using (Media.Rtcp.GoodbyeReport p = new Rtcp.GoodbyeReport(0, PaddingCounter, RandomId, new RFC3550.SourceList(SourceCounter), ReasonForLeaving.ToArray()))
                        {
                            //Check IsComplete
                            System.Diagnostics.Debug.Assert(p.IsComplete, "IsComplete must be true.");

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

                            //Calculate the length of the ReasonForLeaving, should always be padded to 32 bits for octet alignment.
                            int expectedReasonLength = ReasonLength > 0 ? Binary.BytesToMachineWords(ReasonLength + 1) * Binary.BytesPerInteger : 0;

                            //Check HasReasonForLeaving
                            System.Diagnostics.Debug.Assert(expectedReasonLength > 0 == p.HasReasonForLeaving, "Unexpected HasReasonForLeaving");

                            //The ssrc is always present in these tests.
                            int expectedBlockCount = SourceCounter + 1;

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

                            //Check the SourceList
                            int expectedSourceListSize = expectedBlockCount * RFC3550.SourceList.ItemSize;

                            //The first entry is in the header....
                            if (expectedSourceListSize > 0)
                            {
                                //Use the SourceList
                                using (Media.RFC3550.SourceList sourceList = p.GetSourceList())
                                {
                                    System.Diagnostics.Debug.Assert(sourceList.IsComplete == true, "SourceList.IsComplete");

                                    System.Diagnostics.Debug.Assert(expectedSourceListSize == sourceList.Size, "Unexpected SourceList Size");

                                    System.Diagnostics.Debug.Assert(expectedBlockCount == sourceList.Count, "Unexpected SourceList Count");

                                    System.Diagnostics.Debug.Assert(RandomId == sourceList.CurrentSource, "Unexpected Source in SourceList");

                                    System.Diagnostics.Debug.Assert((uint)RandomId == sourceList.First(), "Unexpected Source in SourceList");

                                    System.Diagnostics.Debug.Assert(sourceList.Skip(1).All(s => s == uint.MinValue), "Unexpected Source in SourceList");

                                    System.Diagnostics.Debug.Assert(sourceList.ToArray().SequenceEqual(Enumerable.Concat <uint>(LinqExtensions.Yield((uint)RandomId), Enumerable.Repeat(uint.MinValue, SourceCounter))), "Unexpected Source in SourceList");
                                }
                            }

                            //The amount of bytes expected in the payload does not contain the first entry of the list.
                            int expectedInPayload = expectedSourceListSize - RFC3550.SourceList.ItemSize;

                            //Check the Payload.Count
                            System.Diagnostics.Debug.Assert(p.Payload.Count == expectedInPayload + PaddingCounter + expectedReasonLength, "Unexpected Payload Count");

                            //Check the Length,
                            System.Diagnostics.Debug.Assert(p.Length == p.Header.Size + expectedInPayload + PaddingCounter + expectedReasonLength, "Unexpected Length");

                            //Check the reaosn for leaving
                            System.Diagnostics.Debug.Assert(p.ReasonForLeavingData.SequenceEqual(ReasonForLeaving), "Unexpected ReasonForLeaving data");

                            //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");

                            //Add remaining amount of reports to test the Add method

                            //Enumerate the RtcpReport version of the instance

                            //Serialize and Deserialize and verify again
                            using (Rtcp.GoodbyeReport s = new Rtcp.GoodbyeReport(new Rtcp.RtcpPacket(p.Prepare().ToArray(), 0), true))
                            {
                                //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");

                                //Check the reaosn for leaving
                                System.Diagnostics.Debug.Assert(s.ReasonForLeavingData.SequenceEqual(ReasonForLeaving) && s.ReasonForLeavingData.Count() == ReasonLength, "Unexpected ReasonForLeaving data");

                                //Check the PaddingOctets count
                                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");
                            }
                        }
                    }
                }
            }
        }
Beispiel #4
0
 public GoodbyeReport(int version, int ssrc, Media.RFC3550.SourceList sourcesLeaving, byte[] reasonForLeaving)
     : this(version, 0, ssrc, sourcesLeaving == null ? Media.RFC3550.SourceList.Empty : sourcesLeaving, reasonForLeaving)
 {
 }
Beispiel #5
0
        /// <summary>
        /// Constructs a new GoodbyeReport from the given values.
        /// </summary>
        /// <param name="version">The version of the report</param>
        /// <param name="padding"></param>
        /// <param name="ssrc">The id of the senders of the report</param>
        /// <param name="sourcesLeaving">The SourceList which describes the sources who are leaving</param>
        /// <param name="reasonForLeaving">An optional reason for leaving(only the first 255 octets will be used)</param>
        public GoodbyeReport(int version, int padding, int ssrc, Media.RFC3550.SourceList sourcesLeaving, byte[] reasonForLeaving)
            : base(version, PayloadType, padding, ssrc,
                   sourcesLeaving != null ? sourcesLeaving.Count : 0,                                                               //BlockCount
                   Media.RFC3550.SourceList.ItemSize,                                                                               //Size in bytes of each block
                   Media.Common.Extensions.Array.ArrayExtensions.IsNullOrEmpty(reasonForLeaving) ? 0 : 1 + reasonForLeaving.Length) //Extension size in bytes
        {
            //The working offset in the payload
            int offset = Payload.Offset;

            //Copy the source list (IMHO it should be before the reason...)
            if (sourcesLeaving != null)
            {
                sourcesLeaving.TryCopyTo(Payload.Array, offset);

                offset += sourcesLeaving.Size;
            }

            #region Babble

            /* If I won't have a participant list then I sure as shit won't make thing as they shouldn't be here just for [Wireshark, et al]
             * 6.6 BYE: Goodbye 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
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             |V=2|P|    SC   |   PT=BYE=203  |             length            |
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             |                           SSRC/CSRC                           |
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             | :                              ...                              : (THIS IS WHERE THE SOURCE LIST GOES FYI)
             +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
             | (opt) |     length    |               reason for leaving            ...
             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
             |
             * When SC = 0 the packet is useless.
             * When SC >= 1 the SourceList appears BEFORE the (opt) Length, The id there may be different from SSRC/CSRC
             * Length is optional and a 0 value should not HAVE to be present as including a 0 value forces you to inlcude 3 more 0's to octet align the payload
             */

            #endregion

            //If a reason was given there will be extension data

            if (HasExtensionData)
            {
                int extensionLength = Media.Common.Extensions.Array.ArrayExtensions.IsNullOrEmpty(reasonForLeaving) ? 0 : reasonForLeaving.Length;

                if (extensionLength > 0)
                {
                    //Ensure it will fit
                    if (extensionLength > byte.MaxValue)
                    {
                        throw new InvalidOperationException("Only 255 octets can occupy the ReasonForLeaving in a GoodbyeReport.");
                    }

                    //The length before the string
                    Payload.Array[offset++] = (byte)extensionLength;

                    //Copy it to the payload
                    reasonForLeaving.CopyTo(Payload.Array, offset);
                }
            }
        }