/// <summary> /// Assembles the RtpFrame into a byte[] by combining the ExtensionBytes and Payload of all contained RtpPackets into a single byte array (excluding the RtpHeader) /// </summary> /// <returns>The byte array containing the assembled frame</returns> public virtual IEnumerable <byte> Assemble(bool useExtensions = false, int profileHeaderSize = 0) { //The sequence IEnumerable <byte> sequence = Enumerable.Empty <byte>(); //Iterate the packets foreach (RtpPacket packet in this) { //Should be handled by derived implementation because it is known if the flags are relevent to the data. if (useExtensions && packet.Extension) { using (RtpExtension extension = packet.GetExtension()) { if (extension != null) { /*if (extension.IsComplete) */ sequence = sequence.Concat(extension.Data); } } } //Should chyeck PayloadData is > profileHeaderSize ? sequence = sequence.Concat(packet.PayloadData.Skip(profileHeaderSize)); } return(sequence); }
public virtual int CompleteFrom(System.Net.Sockets.Socket socket, Common.MemorySegment buffer) { if (IsReadOnly) { throw new InvalidOperationException("Cannot modify a RtpPacket when IsReadOnly is false."); } //If the packet is complete then return if (IsDisposed || IsComplete) { return(0); } // Cache the size of the original payload int payloadCount = Payload.Count, octetsRemaining = payloadCount, //Cache how many octets remain in the payload offset = Payload.Offset, //Cache the offset in parsing sourceListOctets = ContributingSourceListOctets, //Cache the amount of octets required in the ContributingSourceList. extensionSize = Header.Extension ? RtpExtension.MinimumSize : 0, //Cache the amount of octets required to read the ExtensionHeader recieved = 0; //If the ContributingSourceList is not complete if (payloadCount < sourceListOctets) { //Calulcate the amount of octets to receive octetsRemaining = Math.Abs(payloadCount - sourceListOctets); //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; //Read from the stream, decrementing from octetsRemaining what was read. while (octetsRemaining > 0) { //Receive octetsRemaining or less int justReceived = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error); //Move the offset offset += justReceived; //Decrement how many octets were receieved octetsRemaining -= justReceived; recieved += justReceived; } } //At the end of the sourceList offset = sourceListOctets; //ContribuingSourceList is now Complete //If there is a RtpExtension indicated by the RtpHeader if (Header.Extension) { //Determine if the extension header was read octetsRemaining = RtpExtension.MinimumSize - (payloadCount - offset); //If the extension header is not yet read if (octetsRemaining > 0) { //Allocte the memory for the extension header if (m_OwnedOctets == null) { m_OwnedOctets = new byte[octetsRemaining]; } else { m_OwnedOctets = m_OwnedOctets.Concat(new byte[octetsRemaining]).ToArray(); } System.Net.Sockets.SocketError error; //Read from the socket, decrementing from octetsRemaining what was read. while (octetsRemaining > 0) { //Receive octetsRemaining or less int justReceived = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error); //Move the offset offset += justReceived; //Decrement how many octets were receieved octetsRemaining -= justReceived; recieved += justReceived; } } //at least 4 octets are now present in Payload @ Payload.Offset //Use a RtpExtension instance to read the Extension Header and data. using (RtpExtension extension = GetExtension()) { if (extension != null && !extension.IsComplete) { //Cache the size of the RtpExtension (not including the Flags and LengthInWords [The Extension Header]) extensionSize = extension.Size - RtpExtension.MinimumSize; //The amount of octets required for for completion are indicated by the Size property of the RtpExtension. //Calulcate the amount of octets to receive octetsRemaining = (payloadCount - offset) - RtpExtension.MinimumSize; if (octetsRemaining > 0 && octetsRemaining < extensionSize) { //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; //Read from the stream, decrementing from octetsRemaining what was read. while (octetsRemaining > 0) { //Receive octetsRemaining or less int justReceived = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error); //Move the offset offset += justReceived; //Decrement how many octets were receieved octetsRemaining -= justReceived; recieved += justReceived; } } } } } //RtpExtension is now Complete //If the header indicates the payload has padding if (Header.Padding) { octetsRemaining = PaddingOctets - payloadCount; if (octetsRemaining > 0) { //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(); } offset = payloadCount; //If the amount of bytes read in the padding is NOT equal to the last byte in the segment the RtpPacket is NOT complete while (octetsRemaining > 0) { System.Net.Sockets.SocketError error; //Receive 1 byte //Receive octetsRemaining or less int justReceived = Media.Common.Extensions.Socket.SocketExtensions.AlignedReceive(m_OwnedOctets, offset, octetsRemaining, socket, out error); //Move the offset offset += justReceived; recieved += justReceived; octetsRemaining -= justReceived; } } } //Padding is now complete //Re allocate the payload segment to include any completed data Payload = new Common.MemorySegment(m_OwnedOctets, Payload.Offset, m_OwnedOctets.Length); //RtpPacket is complete return(recieved); }
/// <summary> /// Provides the logic for cloning a RtpPacket instance. /// The RtpPacket class does not have a Copy Constructor because of the variations in which a RtpPacket can be cloned. /// </summary> /// <param name="includeSourceList">Indicates if the SourceList should be copied.</param> /// <param name="includeExtension">Indicates if the Extension should be copied.</param> /// <param name="includePadding">Indicates if the Padding should be copied.</param> /// <param name="selfReference">Indicates if the new instance should reference the data contained in this instance.</param> /// <returns>The RtpPacket cloned as result of calling this function</returns> public RtpPacket Clone(bool includeSourceList, bool includeExtension, bool includePadding, bool includeCoeffecients, bool selfReference) { //Get the bytes which correspond to the header IEnumerable <byte> binarySequence = Enumerable.Empty <byte>(); //If the sourcelist and extensions are to be included and selfReference is true then return the new instance using the a reference to the data already contained. if (includeSourceList && includeExtension && selfReference) { return(new RtpPacket(Header.Clone(), Payload)); } bool hasSourceList = ContributingSourceCount > 0; //If the source list is included then include it. if (includeSourceList && hasSourceList) { var sourceList = GetSourceList(); if (sourceList != null) { binarySequence = GetSourceList().AsBinaryEnumerable(); } else { binarySequence = Media.Common.MemorySegment.EmptyBytes; } } //Determine if the clone should have extenison bool hasExtension = Header.Extension; //If there is a header extension to be included in the clone if (hasExtension && includeExtension) { //Get the Extension using (RtpExtension extension = GetExtension()) { //If an extension could be obtained include it if (extension != null) { binarySequence = binarySequence.Concat(extension); } } } //if the video data is required in the clone then include it if (includeCoeffecients) { binarySequence = binarySequence.Concat(PayloadData); //Add the binary data to the packet except any padding } //Determine if padding is present bool hasPadding = Header.Padding; //if padding is to be included in the clone then obtain the original padding directly from the packet if (hasPadding && includePadding) { binarySequence = binarySequence.Concat(Payload.Array.Skip(Payload.Offset + Payload.Count - PaddingOctets)); //If just the padding is required the skip the Coefficients } //Return the result of creating the new instance with the given binary return(new RtpPacket(new RtpHeader(Header.Version, includePadding && hasPadding, includeExtension && hasExtension) { Timestamp = Header.Timestamp, SequenceNumber = Header.SequenceNumber, SynchronizationSourceIdentifier = Header.SynchronizationSourceIdentifier, PayloadType = Header.PayloadType, ContributingSourceCount = includeSourceList ? Header.ContributingSourceCount : 0 }.Concat(binarySequence).ToArray(), 0) { Transferred = this.Transferred }); }