/// <summary>
 /// Constructs a new PayloadSpecificFeedbackReport from the given <see cref="RtcpHeader"/> and payload.
 /// Changes to the header and payload are immediately reflected in this instance.
 /// </summary>
 /// <param name="header"></param>
 /// <param name="payload"></param>
 public PayloadSpecificFeedbackReport(RtcpHeader header, Common.MemorySegment payload, bool shouldDipose = true)
     : base(header, payload, shouldDipose)
 {
     if (Header.PayloadType != PayloadType)
     {
         throw new System.ArgumentException("Header.PayloadType is not equal to the expected type of 206.", "reference");
     }
 }
Exemplo n.º 2
0
        /// <summary>
        /// Allocates 24 octets to represent this ReportBlock instance.
        /// </summary>
        ReportBlock(bool shouldDispose = true)
        {
            m_OwnedOctets = new byte[Size];

            Memory = new Common.MemorySegment(m_OwnedOctets, 0, Size);

            ShouldDispose = shouldDispose;
        }
 /// <summary>
 /// Constructs a new ApplicationSpecificReport from the given <see cref="RtcpHeader"/> and payload.
 /// Changes to the header and payload are immediately reflected in this instance.
 /// </summary>
 /// <param name="header">The header</param>
 /// <param name="payload">The payload</param>
 public ApplicationSpecificReport(RtcpHeader header, Common.MemorySegment payload, bool shouldDispose = true)
     : base(header, payload, shouldDispose)
 {
     if (Header.PayloadType != PayloadType)
     {
         throw new ArgumentException("Header.PayloadType is not equal to the expected type of 204.", "reference");
     }
 }
Exemplo n.º 4
0
 /// <summary>
 /// Constructs a new SendersReport from the given <see cref="RtcpHeader"/> and payload.
 /// Changes to the header and payload are immediately reflected in this instance.
 /// </summary>
 /// <param name="header"></param>
 /// <param name="payload"></param>
 public SendersReport(RtcpHeader header, Common.MemorySegment payload, bool shouldDipose = true)
     : base(header, payload, shouldDipose)
 {
     if (Header.PayloadType != PayloadType)
     {
         throw new ArgumentException("Header.PayloadType is not equal to the expected type of 200.", "reference");
     }
     //RtcpReportExtensions.VerifyPayloadType(this);
 }
Exemplo n.º 5
0
        /// <summary>
        /// Creates a new ReportBlock instance from the given existing reference.
        /// Throws a ArgumentNullException if <paramref name="reference"/> is null.
        /// </summary>
        /// <param name="reference">A reference to a ReportBlock instance.</param>
        public ReportBlock(ReportBlock reference)
        {
            if (reference == null)
            {
                throw new ArgumentNullException();
            }

            Memory = reference.Memory;
        }
Exemplo n.º 6
0
        public BinaryContent(Common.MemorySegment data, string name = null) : base(name)
        {
            if (data == null || data.Count == 0)
            {
                throw new ArgumentException("data cannot be null or empty");
            }

            Data = data;
        }
Exemplo n.º 7
0
        public MultipartContent(Common.MemorySegment boundary)
        {
            if (boundary == null || boundary.Count == 0)
            {
                throw new ArgumentException("boundary cannot be null or empty");
            }

            Boundary = boundary;
        }
Exemplo n.º 8
0
        public static void DisableTcpKeepAlive(System.Net.Sockets.Socket socket)
        {
            using (var optionMemory = new Common.MemorySegment(KeepAliveSize))
            {
                Common.Binary.Write32(optionMemory.Array, 0, false, 0);

                int result = socket.IOControl(System.Net.Sockets.IOControlCode.KeepAliveValues, optionMemory.Array, optionMemory.Array);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Creates a RtcpPacket instance from the given parameters by copying data.
        /// </summary>
        /// <param name="buffer">The buffer which contains the binary RtcpPacket to decode</param>
        /// <param name="offset">The offset to start decoding</param>
        public RtcpPacket(byte[] buffer, int offset, int count, bool shouldDispose = true)
        {
            //The instance owns the header
            ShouldDispose = m_OwnsHeader = shouldDispose;

            //Create the header
            Header = new RtcpHeader(buffer, offset);

            //Determine the amount of bytes in the header and packet
            int headerLength = RtcpHeader.Length, packetLength = Header.LengthInWordsMinusOne;

            switch (packetLength)
            {
            case ushort.MinValue:
            {
                Payload = Common.MemorySegment.Empty;

                if (false == Padding)
                {
                    return;
                }

                break;
            }

            default:
            {
                //Header has another word
                headerLength = Binary.BytesPerLong;

                //Packet length is given by the LengthInWordsMinusOne + 1 * 4
                packetLength = ((ushort)((packetLength + 1) * 4));

                //If there is no data in the payload don't consume it
                if (packetLength < headerLength)
                {
                    goto case ushort.MinValue;
                }

                break;
            }
            }

            //ssrc doesn't technically coun't
            //int nonHeaderBytes = packetLength - headerLength;

            //Project the octets in the sequence taking the minimum of the octets present and the octets required as indicated by the header.
            //m_OwnedOctets = buffer.Skip(offset + headerLength).Take(nonHeaderBytes < 0 ? buffer.Length + nonHeaderBytes : nonHeaderBytes).ToArray();

            //The Payload property must be assigned otherwise the properties will not function in the instance.
            //Payload = new Common.MemorySegment(m_OwnedOctets, shouldDispose);

            Payload = new Common.MemorySegment(buffer, offset + headerLength, count - headerLength, shouldDispose);

            m_OwnedOctets = Payload.Array;
        }
Exemplo n.º 10
0
        /// <summary>
        /// Creates a new ReportBlock instance from the given existing reference.
        /// Throws a ArgumentNullException if <paramref name="reference"/> is null.
        /// </summary>
        /// <param name="reference">A reference to a ReportBlock instance.</param>
        public ReportBlock(ReportBlock reference, bool shouldDispose = true)
            : base(shouldDispose)
        {
            if (reference == null)
            {
                throw new ArgumentNullException();
            }

            Memory = reference.Memory;
        }
Exemplo n.º 11
0
        protected virtual void ParseProgramStreamMap(Container.Node node)
        {
            if (node.Identifier[3] != Mpeg.StreamTypes.ProgramStreamMap)
            {
                return;
            }

            int dataLength = node.Data.Length;

            if (dataLength < 4)
            {
                return;
            }

            byte mapId = node.Data[0];

            byte reserved = node.Data[1];

            ushort infoLength = Common.Binary.ReadU16(node.Data, 2, Common.Binary.IsLittleEndian);

            ushort mapLength = Common.Binary.ReadU16(node.Data, 4 + infoLength, Common.Binary.IsLittleEndian);

            int offset = 4 + infoLength + 2;

            int crcOffset = dataLength - 4;

            //While data remains in the map
            while (offset < crcOffset)
            {
                //Find out the type of item it is
                byte esType = node.Data[offset++];

                //Find out the elementary stream id
                byte esId = node.Data[offset++];

                //find out how long the info is
                ushort esInfoLength = Common.Binary.ReadU16(node.Data, offset, Common.Binary.IsLittleEndian);

                //Get a array containing the info
                Common.MemorySegment esData = esInfoLength == 0 ? Media.Common.MemorySegment.Empty : new Common.MemorySegment(node.Data, offset, esInfoLength); //node.Data.Skip(offset).Take(esInfoLength).ToArray();

                //Create the entry
                var entry = new Tuple <byte, Common.MemorySegment>(esType, esData);

                //should keep entries until crc is updated if present and then insert.

                //Add it to the ProgramStreams
                m_ProgramStreams.AddOrUpdate(esId, entry, (id, old) => entry);

                //Move the offset
                offset += 2 + esInfoLength;
            }

            //Map crc
        }
Exemplo n.º 12
0
        public static bool IsValidPacket(this IRtpProfileInformation profileInfomation, RtpPacket packet)
        {
            if (Common.IDisposedExtensions.IsNullOrDisposed(packet))
            {
                return(false);
            }

            Common.MemorySegment packetData = packet.PayloadDataSegment;

            return(packetData.Count > profileInfomation.MinimumHeaderSize && packetData.Count > profileInfomation.MaximumHeaderSize);
        }
Exemplo n.º 13
0
        public RtcpHeader(Common.MemorySegment memory, int additionalOffset = 0)
        {
            if (Math.Abs(memory.Count - additionalOffset) < RtcpHeader.Length)
            {
                throw new ArgumentException("memory must contain at least 4 elements", "memory");
            }

            First16Bits = new Media.RFC3550.CommonHeaderBits(memory, additionalOffset);

            //das infamous clamp max min
            PointerToLast6Bytes = new Common.MemorySegment(memory.Array, memory.Offset + additionalOffset + RFC3550.CommonHeaderBits.Size, Math.Max(Math.Min(memory.Count - additionalOffset - RFC3550.CommonHeaderBits.Size, 6), RtcpHeader.Length));
        }
Exemplo n.º 14
0
        public virtual int CompleteFrom(System.Net.Sockets.Socket socket, Common.MemorySegment buffer)
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException("Cannot modify a RtcpPacket when IsReadOnly is false.");
            }

            //If the packet is complete then return
            if (IsDisposed || IsComplete)
            {
                return(0);
            }

            //Calulcate the amount of octets remaining in the RtcpPacket including the header
            int octetsRemaining = ((ushort)(Header.LengthInWordsMinusOne + 1)) * 4 - Length, offset = Payload != null ? Payload.Count : 0;

            if (octetsRemaining > 0)
            {
                //There is not enough room in the array to finish the packet
                if (Payload.Count < octetsRemaining)
                {
                    //Allocte the memory for the required data
                    if (m_OwnedOctets == null)
                    {
                        m_OwnedOctets = new byte[octetsRemaining];
                    }
                    else
                    {
                        m_OwnedOctets = m_OwnedOctets.Concat(new byte[octetsRemaining]).ToArray();
                    }
                }

                System.Net.Sockets.SocketError error;

                int recieved = 0;

                //Read from the stream, decrementing from octetsRemaining what was read.
                while (octetsRemaining > 0)
                {
                    int rec = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error);
                    offset          += rec;
                    octetsRemaining -= rec;
                    recieved        += rec;
                }

                //Re-allocate the segment around the received data.
                Payload = new Common.MemorySegment(m_OwnedOctets, 0, m_OwnedOctets.Length);

                return(recieved);
            }

            return(0);
        }
Exemplo n.º 15
0
        public static void EnableTcpKeepAlive(System.Net.Sockets.Socket socket, int time, int interval)
        {
            using (var optionMemory = new Common.MemorySegment(KeepAliveSize))
            {
                Common.Binary.Write32(optionMemory.Array, 0, false, 1);

                Common.Binary.Write32(optionMemory.Array, Common.Binary.BytesPerInteger, false, time);

                Common.Binary.Write32(optionMemory.Array, Common.Binary.BytesPerLong, false, interval);

                int result = socket.IOControl(System.Net.Sockets.IOControlCode.KeepAliveValues, optionMemory.Array, optionMemory.Array);
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Reads an instance of the RtpHeader class and copies 12 octets which make up the RtpHeader.
        /// </summary>
        /// <param name="octets">A reference to a byte array which contains at least 12 octets to copy.</param>
        public RtpHeader(byte[] octets, int offset = 0)
        {
            //If the octets reference is null throw an exception
            if (octets == null)
            {
                throw new ArgumentNullException("octets");
            }

            //Determine the length of the array
            int octetsLength = octets.Length;

            //Check range
            if (offset > octetsLength)
            {
                throw new ArgumentOutOfRangeException("offset", "Cannot be greater than the length of octets");
            }

            //Check for the amount of octets required to build a RtpHeader given by the delination of the offset
            //if (octetsLength == 0 || octetsLength - offset < Length) throw new ArgumentException("octets must contain at least 12 elements given the deleniation of the offset parameter.", "octets");
            if (octetsLength == 0)
            {
                throw new ArgumentException("octets must contain at least 1 element given the deleniation of the offset parameter.", "octets");
            }

            bool hasMoreThanOnebyte = octetsLength > 1;

            if (hasMoreThanOnebyte)
            {
                //Read a managed representation of the first two octets which are stored in Big ByteOrder / Network Byte Order
                First16Bits = new Media.RFC3550.CommonHeaderBits(octets[offset + 0], octets[offset + 1]);

                //Allocate space for the other 10 octets
                Last10Bytes = hasMoreThanOnebyte ? new byte[10] : Media.Common.MemorySegment.EmptyBytes;

                //Copy the remaining bytes of the header which consist of the
                //SequenceNumber (2 octets / U16)
                //Timestamp (4 octets / U32)
                //SSRC (4 octets / U32)
                Array.Copy(octets, offset + 2, Last10Bytes, 0, Math.Min(10, octetsLength - 2));
            }
            else
            {
                //Read a managed representation of the first two octets which are stored in Big ByteOrder / Network Byte Order
                First16Bits = new Media.RFC3550.CommonHeaderBits(octets[offset + 0], default(byte));

                //Allocate space for the other 10 octets
                Last10Bytes = Media.Common.MemorySegment.EmptyBytes;
            }

            PointerToLast10Bytes = new MemorySegment(Last10Bytes, 0, Last10Bytes.Length);
        }
Exemplo n.º 17
0
        public RtcpHeader(int version, int payloadType, bool padding, int blockCount)
        {
            First16Bits = new Media.RFC3550.CommonHeaderBits(version, padding, false, false, payloadType, (byte)blockCount);

            Last6Bytes = new byte[6];

            PointerToLast6Bytes = new Common.MemorySegment(Last6Bytes, 0, 6);

            //The default value must be set into the LengthInWords field otherwise it will reflect 0
            if (blockCount == 0)
            {
                LengthInWordsMinusOne = RtcpHeader.MaximumLengthInWords;                 // ushort (0 - 1)
            }
        }
Exemplo n.º 18
0
        /// <summary>
        /// Creates an RtpExtension from the given binary data which must include the Flags and LengthInWords at the propper offsets.
        /// Data is copied from offset to count.
        /// </summary>
        /// <param name="binary">The binary data of the extensions</param>
        /// <param name="offset">The amount of bytes to skip in binary</param>
        /// <param name="count">The amount of bytes to copy from binary</param>
        public RtpExtension(byte[] binary, int offset, int count)
        {
            if (binary == null)
            {
                throw new ArgumentNullException("binary");
            }
            else if (binary.Length < MinimumSize)
            {
                throw InvalidExtension;
            }

            //Atleast 4 octets are contained in binary
            m_MemorySegment = new Common.MemorySegment(binary, offset, count);
        }
Exemplo n.º 19
0
        public RtpHeader(int version, bool padding, bool extension)
        {
            First16Bits = new Media.RFC3550.CommonHeaderBits(version, padding, extension);

            //Allocate space for the other 10 octets
            Last10Bytes = new byte[10];

            PointerToLast10Bytes = new Common.MemorySegment(Last10Bytes, 0, 10);

            Version = version;

            Padding = padding;

            Extension = extension;
        }
Exemplo n.º 20
0
        public Node(IMediaContainer master, Common.MemorySegment identifierPointer, int identifierSize, int lengthSize, long offset, long size, bool complete, bool shouldDispose = true)
            : base(shouldDispose)
        {
            Master     = master;
            DataOffset = offset;

            IdentifierPointer = identifierPointer;
            Identifier        = IdentifierPointer.Array;

            IdentifierSize = identifierSize;
            LengthSize     = lengthSize;

            DataSize   = size;
            IsComplete = complete; //Should calulcate here?
        }
Exemplo n.º 21
0
 /// <summary>
 /// Creates an exact copy of the RtpHeader from the given RtpHeader
 /// </summary>
 /// <param name="other">The RtpHeader to copy</param>
 /// <param name="reference">A value indicating if the RtpHeader given should be referenced or copied.</param>
 public RtpHeader(RtpHeader other, bool reference)
 {
     if (reference)
     {
         First16Bits          = other.First16Bits;
         Last10Bytes          = other.Last10Bytes;
         PointerToLast10Bytes = other.PointerToLast10Bytes;
     }
     else
     {
         First16Bits          = new Media.RFC3550.CommonHeaderBits(other.First16Bits);
         Last10Bytes          = new byte[10];
         PointerToLast10Bytes = new Common.MemorySegment(Last10Bytes, 0, 10);
         other.Last10Bytes.CopyTo(Last10Bytes, 0);
     }
 }
Exemplo n.º 22
0
 public RtpHeader(RtpHeader other, bool reference, bool shouldDispose = true)
     : base(shouldDispose)
 {
     if (reference)
     {
         First16Bits          = other.First16Bits;
         Last10Bytes          = other.Last10Bytes;
         SegmentToLast10Bytes = other.SegmentToLast10Bytes;
     }
     else
     {
         First16Bits          = new Media.RFC3550.CommonHeaderBits(other.First16Bits);
         Last10Bytes          = new byte[10];
         SegmentToLast10Bytes = new Common.MemorySegment(Last10Bytes, 0, 10);
         other.Last10Bytes.CopyTo(Last10Bytes, 0);
     }
 }
Exemplo n.º 23
0
        public MediaBuffer(MediaFormat mediaFormat, Common.MemorySegment data, Media.Codec.Interfaces.ICodec codec = null, long timestamp = 0, bool shouldDispose = true)
            : base(shouldDispose)
        {
            MediaFormat = mediaFormat;

            Codec = codec;

            Data = data;

            if (Data.Count < SampleLength)
            {
                throw new System.InvalidOperationException(string.Format("Insufficient Data for Sample, found: {0}, expected: {1}", data.Count, SampleLength));
            }

            Timestamp = timestamp;

            //SampleCount = 1;
        }
Exemplo n.º 24
0
 /// <summary>
 /// Constucts a Node instance from the given parameters
 /// </summary>
 /// <param name="master"></param>
 /// <param name="identifier"></param>
 /// <param name="offset"></param>
 /// <param name="size"></param>
 /// <param name="complete"></param>
 public Node(IMediaContainer master, byte[] identifier, int lengthSize, long offset, long size, bool complete, bool shouldDispose = true)
     : base(shouldDispose)
 {
     if (master == null)
     {
         throw new ArgumentNullException("master");
     }
     if (identifier == null)
     {
         throw new ArgumentNullException("identifier");
     }
     Master            = master;
     DataOffset        = offset;
     Identifier        = identifier;
     IdentifierPointer = new Common.MemorySegment(identifier);
     IdentifierSize    = identifier.Length;
     LengthSize        = lengthSize;
     DataSize          = size;
     IsComplete        = complete; //Should calulcate here?
 }
Exemplo n.º 25
0
        /// <summary>
        /// Copies the given octets to the Payload before any Padding and calls <see cref="SetLengthInWordsMinusOne"/>.
        /// </summary>
        /// <param name="octets">The octets to add</param>
        /// <param name="offset">The offset to start copying</param>
        /// <param name="count">The amount of bytes to copy</param>
        internal protected virtual void AddBytesToPayload(IEnumerable <byte> octets, int offset = 0, int count = int.MaxValue, bool setLength = true) //overload for padd if necessary?
        {
            if (IsReadOnly)
            {
                throw new InvalidOperationException("Can only set the AddBytesToPayload when IsReadOnly is false.");
            }

            //Build a seqeuence from the existing octets and the data in the ReportBlock

            //If there are existing owned octets (which may include padding)
            if (Padding)
            {
                //Determine the amount of bytes in the payload
                int payloadCount = Payload.Count,
                //Determine the padding octets offset
                    paddingOctets = PaddingOctets,
                //Determine the amount of octets in the payload
                    payloadOctets = payloadCount - paddingOctets;

                //The owned octets is a projection of the Payload existing, without the padding combined with the given octets from offset to count and subsequently the paddingOctets after the payload
                m_OwnedOctets = Enumerable.Concat(Payload.Take(payloadOctets), octets.Skip(offset).Take(count - offset))
                                .Concat(Payload.Skip(payloadOctets).Take(paddingOctets)).ToArray();
            }
            else if (m_OwnedOctets == null)
            {
                m_OwnedOctets = octets.Skip(offset).Take(count - offset).ToArray();
            }
            else
            {
                m_OwnedOctets = Enumerable.Concat(m_OwnedOctets, octets.Skip(offset).Take(count - offset)).ToArray();
            }

            //Create a pointer to the owned octets.
            Payload = new Common.MemorySegment(m_OwnedOctets);

            //Set the length in words minus one in the header
            if (setLength)
            {
                SetLengthInWordsMinusOne();
            }
        }
Exemplo n.º 26
0
        public RtcpHeader(byte[] octets, int offset = 0, bool shouldDispose = true)
            : base(shouldDispose)
        {
            //If the octets reference is null throw an exception
            if (octets == null)
            {
                throw new ArgumentNullException("octets");
            }

            //Determine the length of the array
            int octetsLength = octets.Length, availableOctets = octetsLength - offset;

            //Check range
            if (offset > octetsLength)
            {
                throw new ArgumentOutOfRangeException("offset", "Cannot be greater than the length of octets");
            }

            //Check for the amount of octets required to build a RtcpHeader given by the delination of the offset
            if (octetsLength == 0 || availableOctets < RtcpHeader.Length)
            {
                throw new ArgumentException("octets must contain at least 4 elements given the deleniation of the offset parameter.", "octets");
            }

            //Read a managed representation of the first two octets which are stored in Big ByteOrder / Network Byte Order
            First16Bits = new Media.RFC3550.CommonHeaderBits(octets, offset);

            //Allocate space for the other 6 octets which consist of the
            //LengthInWordsMinusOne (16 bits)
            //SynchronizationSourceIdentifier (32 bits)
            // 48 Bits = 6 bytes
            Last6Bytes = new byte[6];
            //Copy the remaining bytes of the header which consist of the aformentioned properties

            //If the LengthInWords is FFFF then this is extreanous and probably belongs to any padding...

            Array.Copy(octets, offset + RFC3550.CommonHeaderBits.Size, Last6Bytes, 0, Binary.Min(6, availableOctets - RFC3550.CommonHeaderBits.Size));

            //Make a pointer to the last 6 bytes
            SegmentToLast6Bytes = new Common.MemorySegment(Last6Bytes, 0, 6);
        }
Exemplo n.º 27
0
        public override void Dispose()
        {
            base.Dispose();

            if (ShouldDispose)
            {
                //Dispose the instance
                First16Bits.Dispose();

                //Remove the reference to the CommonHeaderBits instance
                First16Bits = null;

                //Invalidate the pointer
                PointerToLast6Bytes.Dispose();

                PointerToLast6Bytes = null;

                //Remove the reference to the allocated array.
                Last6Bytes = null;
            }
        }
Exemplo n.º 28
0
        public RtpHeader(byte[] octets, int offset = 0, bool shouldDispose = true)
            : base(shouldDispose)
        {
            //Determine the length of the array
            long octetsLength;

            //If the octets reference is null throw an exception
            if (Common.Extensions.Array.ArrayExtensions.IsNullOrEmpty(octets, out octetsLength))
            {
                throw new ArgumentException("octets must not be null and must contain at least 1 element given the deleniation of the offset parameter.", "octets");
            }

            //Check range
            if (offset > octetsLength)
            {
                throw new ArgumentOutOfRangeException("offset", "Cannot be greater than the length of octets");
            }

            //Todo, should not matter since this header instance would be allowed to be modified, saving the allocation here is not necessary.
            //The check is only relevent because octets my have less than 2 bytes which cannot be handled without exception in the CommonHeaderBits
            //Read a managed representation of the first two octets which are stored in Big ByteOrder / Network Byte Order
            First16Bits = octetsLength == 1 ? new Media.RFC3550.CommonHeaderBits(octets[offset], default(byte)) : new Media.RFC3550.CommonHeaderBits(octets, offset);

            //Allocate space for the other 10 octets
            Last10Bytes = new byte[10];

            //If there are octets for those bytes in the source array
            if (octetsLength > 2)
            {
                //Copy the remaining bytes of the header which consist of the
                //SequenceNumber (2 octets / U16)
                //Timestamp (4 octets / U32)
                //SSRC (4 octets / U32)
                Array.Copy(octets, offset + 2, Last10Bytes, 0, Math.Min(10, octetsLength - 2));
            }

            //Assign the segment
            SegmentToLast10Bytes = new MemorySegment(Last10Bytes, 0, Last10Bytes.Length);
        }
Exemplo n.º 29
0
        /// <summary>
        /// Creates a new RtpExtension from the given options and optional data.
        /// </summary>
        /// <param name="sizeInBytes">The known size of the RtpExtension in bytes. The LengthInWords property will reflect this value divided by 4.</param>
        /// <param name="data">The optional extension data itself not including the Flags or LengthInWords fields.</param>
        /// <param name="offset">The optional offset into data to being copying.</param>
        public RtpExtension(int sizeInBytes, short flags = 0, byte[] data = null, int offset = 0)
        {
            //Allocate memory for the binary
            m_MemorySegment = new Common.MemorySegment(new byte[MinimumSize + sizeInBytes], 0, MinimumSize + sizeInBytes);

            //If there are any flags set them
            if (flags > 0)
            {
                Flags = flags;
            }

            //If there is any Extension data then set the LengthInWords field
            if (sizeInBytes > 0)
            {
                LengthInWords = (ushort)(sizeInBytes / MinimumSize);                  //10 = 2.5 becomes (3 words => 12 bytes)
            }
            //If the data is not null and the size in bytes a positive value
            if (data != null && sizeInBytes > 0)
            {
                //Copy the data from to the binary taking only the amount of bytes which can be read within the bounds of the vector.
                Array.Copy(data, offset, m_MemorySegment.Array, 0, Math.Min(data.Length, sizeInBytes));
            }
        }
Exemplo n.º 30
0
        public int CompleteFrom(System.Net.Sockets.Socket socket, Common.MemorySegment buffer)
        {
            if (IsComplete)
            {
                return(0);
            }

            int contained = m_Packet.Length,
                needed = MessageLength - contained - HeaderLength, recieved = 0;

            int r = buffer.Offset;

            while (needed > 0)
            {
                r        += socket.Receive(buffer.Array, r, needed, System.Net.Sockets.SocketFlags.None);
                needed   -= r;
                recieved += r;
            }

            m_Packet = m_Packet.Concat(buffer).ToArray();

            return(recieved);
        }
Exemplo n.º 31
0
        /// <summary>
        /// Calls <see cref="Disconnect"/> and disposes all contained <see cref="RtpClient.TransportContext"/>.
        /// Stops the raising of any events.
        /// Removes the Logger
        /// </summary>
        public override void Dispose()
        {
            if (IsDisposed) return;

            Disconnect();

            base.Dispose();

            if (false == ShouldDispose) return;

            //Dispose contexts
            foreach (TransportContext tc in TransportContexts) tc.Dispose();

            //Counters go away with the transportChannels
            TransportContexts.Clear();

            //Remove my handler (should be done when set to null anyway)
            RtpPacketSent -= new RtpPacketHandler(HandleOutgoingRtpPacket);
            RtcpPacketSent -= new RtcpPacketHandler(HandleOutgoingRtcpPacket);

            //Stop raising events
            RtpPacketSent = null;
            RtcpPacketSent = null;
            RtpPacketReceieved = null;
            RtcpPacketReceieved = null;
            InterleavedData = null;

            //Send abort signal
            Media.Common.Extensions.Thread.ThreadExtensions.TryAbort(ref m_WorkerThread);

            //Send abort signal to all threads contained.
            //Delegate AbortDelegate
            //Media.Common.IThreadReferenceExtensions.AbortAll(this);

            DisableFeedbackReports(this);

            //Empty packet buffers
            m_OutgoingRtpPackets.Clear();
            m_OutgoingRtcpPackets.Clear();

            //Remove the buffer
            m_Buffer.Dispose();
            m_Buffer = null;

            //Unset the logger
            Logger = null;
        }
Exemplo n.º 32
0
        internal void ProcessClientBuffer(ClientSession session, int received)
        {
            if (session == null || session.IsDisposed || received <= 0) return;

            try
            {
                //Use a segment around the data received which is already in the buffer.
                using (Common.MemorySegment data = new Common.MemorySegment(session.m_Buffer.Array, session.m_Buffer.Offset, received))
                {

                    if (data[0] == RtpClient.BigEndianFrameControl)
                    {
                        if (session.m_RtpClient == null) return;

                        received -= session.m_RtpClient.ProcessFrameData(session.m_Buffer.Array, session.m_Buffer.Offset, received, session.m_RtspSocket);
                    }

                    if (received <= 0) return;

                    //Ensure the message is really Rtsp
                    RtspMessage request = new RtspMessage(data);

                    //Check for validity
                    if (request.MessageType != RtspMessageType.Invalid)
                    {
                        //Process the request when complete
                        if (request.IsComplete)
                        {
                            ProcessRtspRequest(request, session);

                            return;
                        }

                    } //Otherwise if LastRequest is not disposed then attempt completion with the invalid data
                    else if (session.LastRequest != null && false == session.LastRequest.IsDisposed)
                    {
                        //Indicate a CompleteFrom is occuring
                        Media.Common.ILoggingExtensions.Log(Logger, "Session:" + session.Id + " Attempting to complete previous mesage with buffer of " + data.Count + " bytes.");

                        //Attempt to complete it
                        received = session.LastRequest.CompleteFrom(null, data);

                        //If nothing was recieved then do nothing.
                        if (received == 0)
                        {
                            Media.Common.ILoggingExtensions.Log(Logger, "Session:" + session.Id + "Did not use buffer of " + data.Count + " bytes.");

                            //return;
                        }

                        Media.Common.ILoggingExtensions.Log(Logger, "Session:" + session.Id + " used " + received + " of buffer bytes");

                        //Account for the received data
                        session.m_Receieved += received;

                        //Determine how to process the messge

                        switch (session.LastRequest.MessageType)
                        {
                            case RtspMessageType.Response:
                            case RtspMessageType.Invalid:
                                {
                                    //Ensure the session is still connected.
                                    session.SendRtspData(Media.Common.MemorySegment.EmptyBytes);

                                    return;
                                }
                            case RtspMessageType.Request:
                                {
                                    //If the request is complete now then process it
                                    if (session.LastRequest.IsComplete)
                                    {
                                        //Process the request (it may not be complete yet)
                                        ProcessRtspRequest(session.LastRequest, session);

                                        return;
                                    }

                                    goto case RtspMessageType.Invalid;
                                }
                        }
                    }

                    //Log the invalid request
                    Media.Common.ILoggingExtensions.Log(Logger, "Received Invalid Message:" + request + " \r\nFor Session:" + session.Id);

                    if (session.LastRequest != null) session.LastRequest.Dispose();

                    //Store it for now to allow completion.
                    session.LastRequest = request;

                    //Ensure the session is still connected.
                    session.SendRtspData(Media.Common.MemorySegment.EmptyBytes);
                }
            }
            catch(Exception ex)
            {
                if (Logger != null) Logger.LogException(ex);
            }
        }
Exemplo n.º 33
0
        /// <summary>
        /// Creates a RtcpPacket instance from the given parameters by copying data.
        /// </summary>
        /// <param name="buffer">The buffer which contains the binary RtcpPacket to decode</param>
        /// <param name="offset">The offset to start decoding</param>
        public RtcpPacket(byte[] buffer, int offset, int count, bool shouldDispose = true)
        {
            //The instance owns the header
            ShouldDispose = m_OwnsHeader = shouldDispose;

            //Create the header
            Header = new RtcpHeader(buffer, offset);

            //Determine the amount of bytes in the header and packet
            int headerLength = RtcpHeader.Length, packetLength = Header.LengthInWordsMinusOne;

            switch (packetLength)
            {
                case ushort.MinValue:
                    {
                        Payload = Common.MemorySegment.Empty;

                        if(false == Padding) return;

                        break;
                    }
                default:
                    {
                        //Header has another word
                        headerLength = Binary.BytesPerLong;

                        //Packet length is given by the LengthInWordsMinusOne + 1 * 4
                        packetLength = ((ushort)((packetLength + 1) * 4));

                        //If there is no data in the payload don't consume it
                        if (packetLength < headerLength) goto case ushort.MinValue;

                        break;
                    }
            }

            //ssrc doesn't technically coun't
            //int nonHeaderBytes = packetLength - headerLength;

            //Project the octets in the sequence taking the minimum of the octets present and the octets required as indicated by the header.
            //m_OwnedOctets = buffer.Skip(offset + headerLength).Take(nonHeaderBytes < 0 ? buffer.Length + nonHeaderBytes : nonHeaderBytes).ToArray();

            //The Payload property must be assigned otherwise the properties will not function in the instance.
            //Payload = new Common.MemorySegment(m_OwnedOctets, shouldDispose);

            Payload = new Common.MemorySegment(buffer, offset + headerLength, count - headerLength, shouldDispose);

            m_OwnedOctets = Payload.Array;
        }
Exemplo n.º 34
0
        public virtual int CompleteFrom(System.Net.Sockets.Socket socket, Common.MemorySegment buffer)
        {
            if (IsReadOnly) throw new InvalidOperationException("Cannot modify a RtcpPacket when IsReadOnly is false.");

            //If the packet is complete then return
            if (IsDisposed || IsComplete) return 0;

            //Calulcate the amount of octets remaining in the RtcpPacket including the header
            int octetsRemaining = ((ushort)(Header.LengthInWordsMinusOne + 1)) * 4 - Length, offset = Payload != null ? Payload.Count : 0;

            if (octetsRemaining > 0)
            {
                //There is not enough room in the array to finish the packet
                if (Payload.Count < octetsRemaining)
                {
                    //Allocte the memory for the required data
                    if (m_OwnedOctets == null) m_OwnedOctets = new byte[octetsRemaining];
                    else m_OwnedOctets = m_OwnedOctets.Concat(new byte[octetsRemaining]).ToArray();
                }

                System.Net.Sockets.SocketError error;

                int recieved = 0;

                //Read from the stream, decrementing from octetsRemaining what was read.
                while (octetsRemaining > 0)
                {
                    int rec = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error);
                    offset += rec;
                    octetsRemaining -= rec;
                    recieved += rec;
                }

                //Re-allocate the segment around the received data.
                Payload = new Common.MemorySegment(m_OwnedOctets, 0, m_OwnedOctets.Length);

                return recieved;
            }

            return 0;
        }
Exemplo n.º 35
0
        public ClientSession(RtspServer server, Socket rtspSocket, Common.MemorySegment buffer = null)
        {
            Id = Guid.NewGuid();

            //The RtspSession ID should be set here to prevent this session from accessing another session,
            //The only problem with this is that is how the nature of TCP may work also... e.g. the client may open and close connections at will in between requests.
            //This means any TCP connection can technially just as in UDP access another session so long as the SessionID is known.
            //Agents will attempt to check the EndPoint however if the packet was forged [and successfully transmitted] then the session is obtained through that mechanism...
            //TCP provides a `stronger` protection against this type of attack (forging) by default where as UDP does not and most large entities are their own provider and thus...

            m_Server = server;

            //Assign the socket and remote endPoint, IPPacketInformation provides thus for UDP
            RtspSocket = rtspSocket;

            if (m_RtspSocket == null) return;

            //m_RtspSocket.Blocking = false;

            //m_RtspSocket.ExclusiveAddressUse = true;

            //Configure TCP Sockets
            if (m_RtspSocket.ProtocolType == ProtocolType.Tcp)
            {
                m_RtspSocket.NoDelay = true;

                m_RtspSocket.SendBufferSize = 0;

                m_RtspSocket.ReceiveBufferSize = 0;

                Media.Common.Extensions.Socket.SocketExtensions.DisableLinger(m_RtspSocket);

                //Use expedited data as defined in RFC-1222. This option can be set only once; after it is set, it cannot be turned off.
                m_RtspSocket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.Expedited, true);
            }

            if (m_RtspSocket.AddressFamily == AddressFamily.InterNetwork) m_RtspSocket.DontFragment = true;

            //m_RtspSocket.SendTimeout = m_RtspSocket.ReceiveTimeout = (int)(m_Server.RtspClientInactivityTimeout.TotalMilliseconds / 3);

            m_RtspSocket.SendTimeout = m_RtspSocket.ReceiveTimeout = (int)RtspClient.DefaultConnectionTime.TotalMilliseconds;

            //Create a buffer using the size of the largest message possible without a Content-Length header.
            //This helps to ensure that partial messages are not recieved by the server from a client if possible (should eventually allow much smaller)
            if (buffer == null)
                m_Buffer = new Common.MemorySegment(RtspMessage.MaximumLength);
            else
                m_Buffer = buffer;

            //Start receiving data
            StartReceive();
        }
Exemplo n.º 36
0
        /// <summary>
        /// Parses the data in the buffer for valid Rtcp and Rtcp packet instances.
        /// </summary>
        /// <param name="memory">The memory to parse</param>
        /// <param name="from">The socket which received the data into memory and may be used for packet completion.</param>
        protected internal virtual void ParseAndCompleteData(Common.MemorySegment memory, bool parseRtcp = true, bool parseRtp = true, int? remaining = null)
        {
            if (memory == null || memory.IsDisposed || memory.Count == 0) return;

            //handle demultiplex scenarios e.g. RFC5761
            if (parseRtcp == parseRtp && memory.Count > RFC3550.CommonHeaderBits.Size)
            {
                //Double Negitive, Demux based on PayloadType? RFC5761?

                //Distinguishable RTP and RTCP Packets
                //http://tools.ietf.org/search/rfc5761#section-4

                //Observation 1) Rtp packets can only have a PayloadType from 64-95
                //However Rtcp Packets may also use PayloadTypes 72- 76.. (Reduced size...)

                //Observation 2) Rtcp Packets defined in RFC3550 Start at 200 (SR -> Goodbye) 204,
                // 209 - 223 is cited in the above as well as below
                //RTCP packet types in the ranges 1-191 and 224-254 SHOULD only be used when other values have been exhausted.

                using (Media.RFC3550.CommonHeaderBits header = new Media.RFC3550.CommonHeaderBits(memory))
                {
                    //Just use the payload type to avoid confusion, payload types for Rtcp and Rtp cannot and should not overlap
                    parseRtcp = !(parseRtp = GetContextByPayloadType(header.RtpPayloadType) != null);

                    //Could also lookup the ssrc
                }
            }

            //Cache start, count and index
            int offset = memory.Offset, count = memory.Count, index = 0,
                //Calulcate remaining
            mRemaining = remaining ?? count - index;

            //If there is nothing left to parse then return
            if (count <= 0) return;

            //If rtcp should be parsed
            if (parseRtcp && mRemaining >= RtcpHeader.Length)
            {
                //Copy valid RtcpPackets out of the buffer now, if any packet is not complete it will be completed only if required.
                foreach (RtcpPacket rtcp in RtcpPacket.GetPackets(memory.Array, offset + index, mRemaining))
                {
                    //Raise an event for each packet.
                    //OnRtcpPacketReceieved(rtcp);
                    HandleIncomingRtcpPacket(this, rtcp);

                    //Move the offset the length of the packet parsed
                    index += rtcp.Length;

                    mRemaining -= rtcp.Length;
                }
            }

            //If rtp is parsed
            if (parseRtp && mRemaining >= RtpHeader.Length)
            {
                using (var subMemory = new Common.MemorySegment(memory.Array, offset + index, mRemaining))
                {
                    using (RtpPacket rtp = new RtpPacket(subMemory))
                    {
                        Console.WriteLine(rtp.SequenceNumber+"===================");
                        //Raise the event
                        HandleIncomingRtpPacket(this, rtp);

                        //Move the index past the length of the packet
                        index += rtp.Length;

                        //Calculate the amount of octets remaining in the segment.
                        mRemaining -= rtp.Length;
                    }
                }
            }

            //If not all data was consumed
            if (mRemaining > 0)
            {
                Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@ParseAndCompleteData - Remaining= " + mRemaining);

                //Only handle when not in TCP?
                //OnInterleavedData(memory.Array, offset + index, mRemaining);
            }

            return;
        }
Exemplo n.º 37
0
        /// <summary>
        /// Recieves data on a given socket and endpoint
        /// </summary>
        /// <param name="socket">The socket to receive data on</param>
        /// <returns>The number of bytes recieved</returns>             
        protected internal virtual int ReceiveData(Socket socket, ref EndPoint remote, out SocketError error, bool expectRtp = true, bool expectRtcp = true, MemorySegment buffer = null)
        {
            //Nothing bad happened yet.
            error = SocketError.SocketError;

            //Ensure the socket can poll
            if (IsDisposed || m_StopRequested || socket == null || m_Buffer.IsDisposed || remote == null) return 0;

            bool tcp = socket.ProtocolType == ProtocolType.Tcp;

            if (buffer == null) buffer = m_Buffer;

            //Cache the offset at the time of the call
            int offset = buffer.Offset, received = 0;

            try
            {
                //Determine how much data is 'Available'
                //int available = socket.ReceiveFrom(m_Buffer.Array, offset, m_Buffer.Count, SocketFlags.Peek, ref remote);

                error = SocketError.Success;

                ////If the receive was a success
                //if (available > 0)
                //{
                received = socket.ReceiveFrom(buffer.Array, offset, buffer.Count, SocketFlags.None, ref remote);

                //Under TCP use Framing to obtain the length of the packet as well as the context.
                if (tcp) return ProcessFrameData(buffer.Array, offset, received, socket);

                //Lookup the context to determine if the packet will fit
                var context = GetContextBySocket(socket);

                //If there was a context and packet cannot fit
                if (context != null && received > context.MaximumPacketSize)
                {
                    //Log the problem
                    Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@ReceiveData - Cannot fit packet in buffer");

                    //Determine if there was enough data to determine if the packet was rtp or rtcp and indicate a failed reception
                    //if (received > RFC3550.CommonHeaderBits.Size)
                    //{
                    //    //context.m_FailedRtcpReceptions++;

                    //    //context.m_FailedRtpReceptions++;
                    //}

                    //remove the reference
                    context = null;
                }

                //Use the data received to parse and complete any recieved packets, should take a parseState
                using (var memory = new Common.MemorySegment(buffer.Array, offset, received))
                    ParseAndCompleteData(memory, expectRtcp, expectRtp);
                //}

            }
            catch (SocketException se)
            {
                error = (SocketError)se.ErrorCode;

                return received;
            }
            catch { throw; }

            //Return the amount of bytes received from this operation
            return received;
        }
Exemplo n.º 38
0
        /// <summary>
        /// Used to handle Tcp framing
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <param name="socket"></param>
        /// <returns></returns>
        protected internal virtual int ProcessFrameData(byte[] buffer, int offset, int count, Socket socket)
        {
            if (count == 0) return 0;

            //If there is no buffer use our own buffer.
            if (buffer == null) buffer = m_Buffer.Array;

            //Determine which TransportContext will receive the data incoming
            TransportContext relevent = null;

            //The channel of the data
            byte frameChannel = 0;

            //Get the length of the given buffer (Should actually use m_Buffer.Count when using our own buffer)
            int bufferLength = buffer.Length,
                //The indicates length of the data
                frameLength = 0,
                //The amount of data remaining in the buffer
                remainingInBuffer = Media.Common.Extensions.Math.MathExtensions.Clamp(count, count, bufferLength - offset),
                //The amount of data received (which is already equal to what is remaining in the buffer)
                recievedTotal = remainingInBuffer;

            //Determine if Rtp or Rtcp is coming in or some other type (could be combined with expectRtcp and expectRtp == false)
            bool expectRtp = false, expectRtcp = false, incompatible = true, raisedEvent = false;

            //If anything remains on the socket the value will be calulcated.
            int remainingOnSocket = 0;

            //TODO handle receiving when no $ and Channel is presenent... e.g. RFC4571
            //Would only be 2 then...

            //if (GetContextBySocket(socket).MediaDescription.MediaProtocol.StartsWith("TCP", StringComparison.OrdinalIgnoreCase))
            //{
            //    //independent = true;
            //}

            int sessionRequired = InterleavedOverhead;

            //While not disposed and there is data remaining (within the buffer)
            while (false == IsDisposed &&
                remainingInBuffer > 0 &&
                offset >= m_Buffer.Offset)
            {
                //Assume not rtp or rtcp and that the data is compatible with the session
                expectRtp = expectRtcp = incompatible = false;

                //If a header can be read
                if (remainingInBuffer >= sessionRequired)
                {
                    //Determine if an event was raised each time there was at least the required amount of data.
                    raisedEvent = false;

                    //Parse the frameLength from the given buffer, take changes to the offset through the function.
                    frameLength = ReadApplicationLayerFraming(remainingInBuffer, out frameChannel, out relevent, ref offset, out raisedEvent, buffer);

                    //If a frame was found (Including the null packet)
                    if (frameLength >= 0)
                    {
                        //If there WAS a context
                        if (relevent != null)
                        {
                            //Verify minimum and maximum packet sizes allowed by context. (taking into account the amount of bytes in the ALF)
                            if (frameLength < relevent.MinimumPacketSize + sessionRequired ||
                                frameLength > relevent.MaximumPacketSize + sessionRequired)
                            {
                                //mark as incompatible
                                incompatible = true;

                                //ToDo
                                //Make CreateLogString function

                                Media.Common.ILoggingExtensions.Log(Logger, ToString() + "@ProcessFrameData - Irregular Packet of " + frameLength + " for Channel " + frameChannel + " remainingInBuffer=" + remainingInBuffer);

                                //jump
                                goto CheckPacketAttributes;
                            }

                            //TODO Independent framing... (e.g. no $)[ only 4 bytes not 6 ]
                            //If all that remains is the frame header then receive more data. 6 comes from (InterleavedOverhead + CommonHeaderBits.Size)
                            //We need more data to be able to verify the frame.
                            if (remainingInBuffer <= 6)
                            {
                                //Remove the context
                                relevent = null;

                                goto CheckRemainingData;

                                ////Only receive this many more bytes for now.
                                //remainingOnSocket = X - remainingInBuffer;

                                ////Receive the rest of the data indicated by frameLength. (Should probably only receive up to X more bytes then make another receive if needed)
                                //goto GetRemainingData;
                            }

                            //Use CommonHeaderBits on the data after the Interleaved Frame Header
                            using (var common = new Media.RFC3550.CommonHeaderBits(buffer[offset + sessionRequired], buffer[offset + sessionRequired + 1]))
                            {
                                //Check the version...
                                incompatible = common.Version != relevent.Version;

                                //If this is a valid context there must be at least a RtpHeader's worth of data in the buffer.
                                //If this was a RtcpPacket with only 4 bytes it wouldn't have a ssrc and wouldn't be valid to be sent.
                                if (false == incompatible &&
                                    (frameChannel == relevent.DataChannel &&
                                    remainingInBuffer <= Rtp.RtpHeader.Length + sessionRequired)
                                    ||
                                    (frameChannel == relevent.ControlChannel &&
                                    remainingInBuffer <= Rtcp.RtcpHeader.Length + sessionRequired))
                                {
                                    //Remove the context
                                    relevent = null;

                                    //Mark as incompatible
                                    incompatible = true;

                                    goto EndUsingHeader;

                                    ////Only receive this many more bytes for now.
                                    //remainingOnSocket = 16 - remainingInBuffer;

                                    ////Receive the rest of the data indicated by frameLength. (Should probably only receive up to 6 more bytes then make another receive if needed)
                                    //goto GetRemainingData;
                                }

                                //Perform a set of checks and set weather or not Rtp or Rtcp was expected.
                                if (false == incompatible)
                                {
                                    //Determine if the packet is Rtcp by looking at the found channel and the relvent control channel
                                    if (frameChannel == relevent.ControlChannel)
                                    {
                                        //Rtcp

                                        if (remainingInBuffer <= sessionRequired + Rtcp.RtcpHeader.Length)
                                        {
                                            //Remove the context
                                            relevent = null;

                                            goto CheckRemainingData;
                                        }

                                        //Store any rtcp length so we can verify its not 0 and then additionally ensure its value is not larger then the frameLength
                                        int rtcpLen;

                                        //use a rtcp header to extract the information in the packet
                                        using (Rtcp.RtcpHeader header = new RtcpHeader(buffer, offset + sessionRequired))
                                        {
                                            //Get the length in 'words' (by adding one)
                                            //A length of 0 means 1 word
                                            //A length of 65535 means only the header (no ssrc [or payload])
                                            ushort lengthInWordsPlusOne = (ushort)(header.LengthInWordsMinusOne + 1);

                                            //Convert to bytes
                                            rtcpLen = lengthInWordsPlusOne * 4;

                                            //Check that the supposed  amount of contained words is greater than or equal to the frame length conveyed by the application layer framing
                                            //it must also be larger than the buffer
                                            incompatible = rtcpLen > frameLength && rtcpLen > bufferLength;

                                            //if rtcpLen >= ushort.MaxValue the packet may possibly span multiple segments unless a large buffer is used.

                                            if (false == incompatible && //It was not already ruled incomaptible
                                                lengthInWordsPlusOne > 0 && //If there is supposed to be SSRC in the packet
                                                header.Size > Rtcp.RtcpHeader.Length && //The header ACTUALLY contains enough bytes to have a SSRC
                                                false == relevent.InDiscovery)//The remote context knowns the identity of the remote stream
                                            {
                                                //Determine if Rtcp is expected
                                                //Perform another lookup and check compatibility
                                                expectRtcp = !(incompatible = (GetContextBySourceId(header.SendersSynchronizationSourceIdentifier)) == null);
                                            }
                                        }
                                    }

                                    //May be mixing channels...
                                    if (false == expectRtcp)
                                    {
                                        //Rtp
                                        if (remainingInBuffer <= sessionRequired + Rtp.RtpHeader.Length)
                                        {
                                            //Remove the context
                                            relevent = null;

                                            goto CheckRemainingData;
                                        }

                                        //the context by payload type is null is not discovering the identity check the SSRC.
                                        if (GetContextByPayloadType(common.RtpPayloadType) == null && false == relevent.InDiscovery)
                                        {
                                            using (Rtp.RtpHeader header = new RtpHeader(buffer, offset + InterleavedOverhead))
                                            {
                                                //The context was obtained by the frameChannel
                                                //Use the SSRC to determine where it should be handled.
                                                //If there is no context the packet is incompatible
                                                expectRtp = !(incompatible = (GetContextBySourceId(header.SynchronizationSourceIdentifier)) == null);

                                                //(Could also check SequenceNumber to prevent duplicate packets from being processed.)

                                                ////Verify extensions (handled by ValidatePacket)
                                                //if (header.Extension)
                                                //{

                                                //}

                                            }
                                        }
                                        else incompatible = false;
                                    }
                                }
                            EndUsingHeader:
                                ;
                            }
                        }

                        //Log state.
                    //if (relevent == null) Media.Common.ILoggingExtensions.Log(Logger, InternalId + "-ProcessFrameData - No Context for Channel " + frameChannel + " frameLength=" + frameLength + " remainingInBuffer=" + remainingInBuffer);
                    //else Media.Common.ILoggingExtensions.Log(Logger, InternalId + "ProcessFrameData " + frameChannel + " frameLength=" + frameLength + " remainingInBuffer=" + remainingInBuffer);

                    CheckPacketAttributes:

                        if (incompatible)
                        {
                            //If there was a context then incrment for failed receptions
                            if (relevent != null)
                            {
                                if (expectRtp) ++relevent.m_FailedRtpReceptions;

                                if (expectRtcp) ++relevent.m_FailedRtcpReceptions;
                            }

                            Media.Common.ILoggingExtensions.Log(Logger, InternalId + "ProcessFrameData - Incompatible Packet frameLength=" + frameLength + " for Channel " + frameChannel + " remainingInBuffer=" + remainingInBuffer);
                        }
                        //If frameLength was 0 or the frame was larger than we can store then interleave the header for handling if required
                        //incompatible may not be true here.
                        else if (frameLength == 0 || frameLength > bufferLength)
                        {
                            //Could check incompatible to determine if to should move further.

                            //Just because there is no assoicated context on the client does not mean the packet is not useful elsewhere in Transport.

                            //TODO It may be possible to let the event reiever known how much is available here.
                            if (frameLength == 0)
                            {
                                Media.Common.ILoggingExtensions.Log(Logger, InternalId + "ProcessFrameData - Null Packet for Channel " + frameChannel + " remainingInBuffer=" + remainingInBuffer);
                            }
                            else //If there was a context then increment for failed receptions only for large packets
                            {
                                if (expectRtp) ++relevent.m_FailedRtpReceptions;

                                if (expectRtcp) ++relevent.m_FailedRtcpReceptions;

                                if (expectRtp || expectRtcp) Media.Common.ILoggingExtensions.Log(Logger, InternalId + "ProcessFrameData - Large Packet of " + frameLength + " for Channel " + frameChannel + " remainingInBuffer=" + remainingInBuffer);
                            }
                        }
                        else goto CheckRemainingData;

                        //The packet was incompatible or larger than the buffer

                        //Determine how much we can move
                        int toMove = Math.Min(remainingInBuffer, sessionRequired);

                        //TODO It may be possible to let the event reiever known how much is available here.

                        //Indicate what was received if not already done
                        if (false == raisedEvent) OnInterleavedData(buffer, offset, toMove);

                        //Move the offset
                        offset += toMove;

                        //Decrease by the length
                        remainingInBuffer -= toMove;

                        //Do another pass
                        continue;

                    }//else there was a frameLength of -1 this indicates there is not enough bytes for a header.
                }
                else//There is not enough data in the buffer as defined by sessionRequired.
                {
                    //unset the frameLength read
                    frameLength = -1;

                    //unset the context read
                    relevent = null;
                }

            //At this point there may be either less sessionRequired or not enough for a complete frame.
            CheckRemainingData:

                //See how many more bytes are required from the wire
                //If the frameLength is less than 0 AND there are less then are sessionRequired remaining in the buffer
                remainingOnSocket = frameLength < 0 && remainingInBuffer < sessionRequired ?
                    sessionRequired - remainingInBuffer //Receive enough to complete the header
                        : //Otherwise if the frameLength larger then what remains in the buffer allow for the buffer to be filled or nothing else remains.
                    frameLength > remainingInBuffer ? frameLength - remainingInBuffer : 0;

                //GetRemainingData:

                //If there is anymore data remaining on the wire
                if (remainingOnSocket > 0)
                {
                    //Align the buffer if anything remains on the socket.
                    Array.Copy(buffer, offset, buffer, m_Buffer.Offset, remainingInBuffer);

                    //Set the correct offset either way.
                    offset = m_Buffer.Offset + remainingInBuffer;

                    //Store the error if any
                    SocketError error = SocketError.SocketError;

                    //Get all the remaining data
                    while (false == IsDisposed && remainingOnSocket > 0)
                    {
                        //Recieve from the wire the amount of bytes required (up to the length of the buffer)
                        int recievedFromWire = socket == null ? 0 : Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(buffer, offset, remainingOnSocket, socket, out error);

                        //Check for an error and then the allowed continue condition
                        if (error != SocketError.Success && error != SocketError.TryAgain) break;

                        //If nothing was recieved try again.
                        if (recievedFromWire <= 0) continue;

                        //Decrease what is remaining from the wire by what was received
                        remainingOnSocket -= recievedFromWire;

                        //Move the offset
                        offset += recievedFromWire;

                        //Increment received
                        recievedTotal += recievedFromWire;

                        //Incrment remaining in buffer for what was recieved.
                        remainingInBuffer += recievedFromWire;
                    }

                    //If a socket error occured remove the context so no parsing occurs
                    if (error != SocketError.Success)
                    {
                        OnInterleavedData(buffer, offset - remainingInBuffer, remainingInBuffer);

                        return recievedTotal;
                    }

                    //Move back to where the frame started
                    offset -= remainingInBuffer;
                }

                //If there was data unrelated to a frame
                if (raisedEvent)
                {
                    if (relevent == null)
                    {
                        offset += frameLength;

                        remainingInBuffer -= frameLength;
                    }

                    continue;
                }
                else if (false == IsDisposed && frameLength > 0)
                {
                    //Parse the data in the buffer
                    using (var memory = new Common.MemorySegment(buffer, offset + InterleavedOverhead, frameLength - InterleavedOverhead))
                        ParseAndCompleteData(memory, expectRtcp, expectRtp, memory.Count);

                    //Decrease remaining in buffer
                    remainingInBuffer -= frameLength;

                    //Move the offset
                    offset += frameLength;

                    //Ensure large frames are completely received by receiving the rest of the frame now. (this only occurs for packets being skipped)
                    if (frameLength > bufferLength)
                    {
                        //Remove the context
                        relevent = null;

                        //Determine how much remains
                        remainingOnSocket = frameLength - bufferLength;

                        //If there is anything left
                        if (remainingOnSocket > 0)
                        {
                            //Set the new length of the frame based on the length of the buffer
                            frameLength -= bufferLength;

                            //Set what is remaining
                            remainingInBuffer = 0;

                            //Use all the buffer
                            offset = m_Buffer.Offset;

                            //go to receive it
                            goto CheckRemainingData;
                        }
                    }
                }
            }

            //Handle any data which remains if not already
            if (false == raisedEvent && remainingInBuffer > 0)
            {
                OnInterleavedData(buffer, offset, remainingInBuffer);
            }

            //Return the number of bytes recieved
            return recievedTotal;
        }
Exemplo n.º 39
0
        //overload for padd if necessary?
        /// <summary>
        /// Copies the given octets to the Payload before any Padding and calls <see cref="SetLengthInWordsMinusOne"/>.
        /// </summary>
        /// <param name="octets">The octets to add</param>
        /// <param name="offset">The offset to start copying</param>
        /// <param name="count">The amount of bytes to copy</param>
        protected internal virtual void AddBytesToPayload(IEnumerable<byte> octets, int offset = 0, int count = int.MaxValue, bool setLength = true)
        {
            if (IsReadOnly) throw new InvalidOperationException("Can only set the AddBytesToPayload when IsReadOnly is false.");

            //Build a seqeuence from the existing octets and the data in the ReportBlock

            //If there are existing owned octets (which may include padding)
            if (Padding)
            {
                //Determine the amount of bytes in the payload
                int payloadCount = Payload.Count,
                    //Determine the padding octets offset
                    paddingOctets = PaddingOctets,
                    //Determine the amount of octets in the payload
                    payloadOctets = payloadCount - paddingOctets;

                //The owned octets is a projection of the Payload existing, without the padding combined with the given octets from offset to count and subsequently the paddingOctets after the payload
                m_OwnedOctets = Enumerable.Concat(Payload.Take(payloadOctets), octets.Skip(offset).Take(count - offset))
                    .Concat(Payload.Skip(payloadOctets).Take(paddingOctets)).ToArray();
            }
            else if (m_OwnedOctets == null) m_OwnedOctets = octets.Skip(offset).Take(count - offset).ToArray();
            else m_OwnedOctets = Enumerable.Concat(m_OwnedOctets, octets.Skip(offset).Take(count - offset)).ToArray();

            //Create a pointer to the owned octets.
            Payload = new Common.MemorySegment(m_OwnedOctets);

            //Set the length in words minus one in the header
            if(setLength) SetLengthInWordsMinusOne();
        }
Exemplo n.º 40
0
        /// <summary>
        /// Assigns the events necessary for operation and creates or assigns memory to use as well as inactivtyTimout.
        /// </summary>
        /// <param name="memory">The optional memory segment to use</param>
        /// <param name="incomingPacketEventsEnabled"><see cref="IncomingPacketEventsEnabled"/></param>
        /// <param name="frameChangedEventsEnabled"><see cref="FrameChangedEventsEnabled"/></param>
        public RtpClient(Common.MemorySegment memory = null, bool incomingPacketEventsEnabled = true, bool frameChangedEventsEnabled = true, bool outgoingPacketEvents = true)
            : this()
        {
            if (memory == null)
            {
                //Determine a good size based on the MTU (this should cover most applications)
                //Need an IP or the default IP to ensure the MTU Matches.
                m_Buffer = new Common.MemorySegment(1500);
            }
            else
            {
                m_Buffer = memory;

                if (m_Buffer.Count < RtpHeader.Length) throw new ArgumentOutOfRangeException("memory", "memory.Count must contain enough space for a RtpHeader");
            }

            //RtpPacketReceieved += new RtpPacketHandler(HandleIncomingRtpPacket);
            //RtcpPacketReceieved += new RtcpPacketHandler(HandleIncomingRtcpPacket);
            RtpPacketSent += new RtpPacketHandler(HandleOutgoingRtpPacket);
            RtcpPacketSent += new RtcpPacketHandler(HandleOutgoingRtcpPacket);
            //InterleavedData += new InterleaveHandler(HandleInterleavedData);

            //Allow events to be raised
            HandleIncomingRtpPackets = HandleIncomingRtcpPackets = IncomingRtpPacketEventsEnabled = IncomingRtcpPacketEventsEnabled = incomingPacketEventsEnabled;

            //Fire events for packets received and Allow events to be raised
            HandleOutgoingRtpPackets = HandleOutgoingRtcpPackets = OutgoingRtpPacketEventsEnabled = OutgoingRtcpPacketEventsEnabled = outgoingPacketEvents;

            //Handle frame changes and Allow frame change events to be raised
            HandleFrameChanges = FrameChangedEventsEnabled = frameChangedEventsEnabled;
        }
Exemplo n.º 41
0
        /// <summary>
        /// Sends the Rtcp Goodbye and detaches all sources
        /// </summary>
        public override void Dispose()
        {
            if (IsDisposed) return;

            base.Dispose();

            RemoveAllAttachmentsAndClearPlaying();

            //Mark as disconnected
            IsDisconnected = true;

            //Disconnect the RtpClient so it's not hanging around wasting resources for nothing
            if (m_RtpClient != null)
            {
                try
                {
                    m_RtpClient.InterleavedData -= m_RtpClient_InterleavedData;

                    m_RtpClient.Dispose();

                    m_RtpClient = null;
                }
                catch { }
            }

            if (m_Buffer != null)
            {
                try
                {
                    m_Buffer.Dispose();

                    m_Buffer = null;
                }
                catch { }
            }

            if (m_RtspSocket != null)
            {
                try
                {
                    if (false == LeaveOpen) m_RtspSocket.Dispose();

                    m_RtspSocket = null;
                }
                catch { }
            }

            if (LastRequest != null)
            {
                try
                {
                    LastRequest.Dispose();

                    LastRequest = null;
                }
                catch { }
            }

            if (LastResponse != null)
            {
                try
                {
                    LastResponse.Dispose();

                    LastResponse = null;
                }
                catch { }
            }

            m_Server = m_Contained = null;
        }