public RtcpHeader(Common.MemorySegment memory, bool shouldDispose = true)//, int additionalOffset = 0) : base(shouldDispose) { First16Bits = new Media.RFC3550.CommonHeaderBits(memory);//, additionalOffset); SegmentToLast6Bytes = new Common.MemorySegment(memory.Array, memory.Offset + RFC3550.CommonHeaderBits.Size, Binary.Clamp(memory.Count - RFC3550.CommonHeaderBits.Size, 0, 6)); }
protected override void Dispose(bool disposing) { if (false.Equals(disposing) || false.Equals(ShouldDispose)) { return; } base.Dispose(ShouldDispose); if (false.Equals(IsDisposed)) { return; } if (false.Equals(Common.IDisposedExtensions.IsNullOrDisposed(First16Bits))) { //Dispose the instance First16Bits.Dispose(); //Remove the reference to the CommonHeaderBits instance First16Bits = null; } if (false.Equals(Common.IDisposedExtensions.IsNullOrDisposed(SegmentToLast6Bytes))) { //Invalidate the pointer SegmentToLast6Bytes.Dispose(); SegmentToLast6Bytes = null; } //Remove the reference to the allocated array. Last6Bytes = null; }
public RtcpHeader(RtcpHeader other, bool reference, bool shouldDispose = true) : base(shouldDispose) { if (reference) { First16Bits = other.First16Bits; Last6Bytes = other.Last6Bytes; SegmentToLast6Bytes = other.SegmentToLast6Bytes; } else { First16Bits = new Media.RFC3550.CommonHeaderBits(other.First16Bits, false, shouldDispose); Last6Bytes = new byte[6]; SegmentToLast6Bytes = new Common.MemorySegment(Last6Bytes, 0, 6, shouldDispose); if (other.Last6Bytes != null) { other.Last6Bytes.CopyTo(Last6Bytes, 0); } else { System.Array.Copy(other.SegmentToLast6Bytes.Array, other.SegmentToLast6Bytes.Offset, Last6Bytes, 0, 6); } } }
public RtcpHeader(RtcpHeader other, bool shouldDispose = true) : base(shouldDispose) { First16Bits = new RFC3550.CommonHeaderBits(other.First16Bits, shouldDispose); SegmentToLast6Bytes = new Common.MemorySegment(other.SegmentToLast6Bytes, shouldDispose); }
/// <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 RtcpHeader(RtcpHeader other, bool reference) { if (reference) { First16Bits = other.First16Bits; Last6Bytes = other.Last6Bytes; PointerToLast6Bytes = other.PointerToLast6Bytes; } else { First16Bits = new Media.RFC3550.CommonHeaderBits(other.First16Bits); Last6Bytes = new byte[6]; PointerToLast6Bytes = new Common.MemorySegment(Last6Bytes, 0, 6); if (other.Last6Bytes != null) { other.Last6Bytes.CopyTo(Last6Bytes, 0); } else { System.Array.Copy(other.PointerToLast6Bytes.Array, other.PointerToLast6Bytes.Offset, Last6Bytes, 0, 6); } } }
public RtpHeader(Common.MemorySegment memory, bool shouldDispose = true) : base(shouldDispose) { First16Bits = new Media.RFC3550.CommonHeaderBits(memory); SegmentToLast10Bytes = new Common.MemorySegment(memory.Array, memory.Offset + RFC3550.CommonHeaderBits.Size, Binary.Clamp(memory.Count - RFC3550.CommonHeaderBits.Size, 0, 10)); }
public override void Dispose() { if (IsDisposed) { return; } base.Dispose(); if (ShouldDispose) { //Call dispose First16Bits.Dispose(); //Remove the reference to the CommonHeaderBits instance First16Bits = null; //Invalidate the pointer PointerToLast10Bytes.Dispose(); PointerToLast10Bytes = null; //Remove the reference to the allocated array. Last10Bytes = null; } }
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)); }
/// <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); }
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) } }
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; }
/// <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); } }
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); } }
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); }
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); }
/// <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; }
/// <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; }