/// Version 1.0.0 /// Last modified 23.5.2014 /// /// Copyright (C) 2014 Veli-Mikko Puupponen /// /// Halyri-system is a prototype emergency call system. Its purpose is to /// demonstrate the use of the advanced capabilities available in the current /// generation smartphones in facilitating the emergency service dispatcher's /// capability to determine the nature of the emergency and to dispatch help. /// /// For more information, see the README file of this package. /// /// The MIT License (MIT) /// /// Permission is hereby granted, free of charge, to any person obtaining a copy /// of this software and associated documentation files (the "Software"), to /// deal in the Software without restriction, including without limitation the /// rights to use, copy, modify, merge, publish, distribute, sublicense, /// and/or sell copies of the Software, and to permit persons to whom the /// Software is furnished to do so, subject to the following conditions: /// /// The above copyright notice and this permission notice shall be included in /// all copies or substantial portions of the Software. /// /// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR /// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, /// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE /// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER /// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING /// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS /// IN THE SOFTWARE. /// using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SimpleUdpMediaClient.Packets { /// Veli-Mikko Puupponen /// /// The class represents media information and payload data /// up to one network MTU in length from a MediaPacket. /// MediaHeaderPackets are used to transfer a portion of /// payload data and the media information from a MediaPacket. /// The combination of a MediaHeaderPacket and the subsequent /// MediaContinuationPackets is a transfer sequence. /// /// The packet consist of a packet type identifier, sender GUID, /// a Int64 sequence number, media type identifier, media compression /// identified, payload data length and originating data length. /// /// The packet must always have payload data. If the payload data /// length is smaller than network MTU, the transfer sequence /// can consist of only a single MediaHeaderPacket. /// public class MediaHeaderPacket : INetworkPacket { /// /// The specified length of the packet header in octets. /// public const int HeaderLengthInOctets = 41; /// /// The specified id of the packet type. It is used to identify a packet. /// public const byte PacketId = 0; private const int packetIdHeaderIndex = 0; private const int sourceGuidHeaderIndex = 1; private const int sequenceHeaderIndex = 17; private const int mediaTypeHeaderIndex = 25; private const int mediaTransferCompressionHeaderIndex = 27; private const int totalPacketCountHeaderIndex = 29; private const int dataLengthHeaderIndex = 33; private const int originatingLengthHeaderIndex = 37; private byte[] sourceGuid; /// /// The function to get the Guid identifying the sender. /// public string SourceGuid { get { return (sourceGuid == null || sourceGuid.Length != 16) ? "" : new Guid(sourceGuid).ToString(); } } private Int64 sequence; /// /// The function to get and set the sequence number of this packet. /// public Int64 Sequence { get { return sequence; } set { sequence = value; } } private Int32 totalPackets; /// /// The function to get the total count of packets in the related transfer sequence. /// public Int32 TotalPacketCount { get { return totalPackets; } } private Int32 totalPayloadLength; /// /// The function to get the total length of payload data in the related transfer sequence. /// public Int32 TotalPayloadDataLength { get { return totalPayloadLength; } } private Int32 originatingLength; /// /// The function to get the original length of the data prior to encoding it into the transfer format. /// public Int32 OriginatingDataLength { get { return originatingLength; } } private Int16 mediaFormat; /// /// The function to get the format of media in the packet. /// public Int16 MediaFormat { get { return mediaFormat; } } private Int16 mediaTransferCompression; /// /// The function to get the compression format of media in the packet. /// public Int16 MediaTransferCompression { get { return mediaTransferCompression; } } private byte[] payloadData; /// /// The function to get the payload data in this packet. /// public byte[] PayloadData { get { return payloadData; } } /// /// The function initializes a new MediaHeaderPacket instance with no /// parameters. /// public MediaHeaderPacket() { } /// /// The function initializes a new MediaHeaderPacket instance that has the /// specified source Guid, media type identified, media transfer /// compression identified, packet count, total payload data length, /// originating data length, sequence number and payload data /// /// Sthe string representation of the sender's Guid. /// The payload media type. /// The payload media transfer compression type. /// Total count of packets in the related trasfer sequence. /// The total number of payload octets in the complete /// related trasfer sequence. /// The original length of the data before /// encoding into the transfer format. /// The payload data in this packet. /// The squence number for this packet, must not /// vary within a transfer sequence. public MediaHeaderPacket(byte[] guid, Int16 mediaTypeIdentifier, Int16 mediaTransferCompressioIdentifier, Int32 packetCount, Int32 totalPayloadDataLength, Int32 originatingDataLength, byte[] payload, Int64 sequenceNumber) : this(guid, mediaTypeIdentifier, mediaTransferCompressioIdentifier, packetCount, totalPayloadDataLength, originatingDataLength, payload) { sequence = sequenceNumber; } /// /// The function initializes a new MediaHeaderPacket instance that has the /// specified source Guid, media type identified, media transfer /// compression identified, packet count, total payload data length, /// originating data length and payload data /// /// The sequence number must be provided prior any calls to the parameterless GetBytes. /// /// Sthe string representation of the sender's Guid. /// The payload media type. /// The payload media transfer compression type. /// Total count of packets in the related trasfer sequence. /// The total number of payload octets in the complete /// related trasfer sequence. /// The original length of the data before /// encoding into the transfer format. /// The payload data in this packet. public MediaHeaderPacket(byte[] guid, Int16 mediaTypeIdentifier, Int16 mediaTransferCompressioIdentifier, Int32 packetCount, Int32 totalPayloadDataLength, Int32 originatingDataLength, byte[] payload) { sourceGuid = guid; mediaFormat = mediaTypeIdentifier; mediaTransferCompression = mediaTransferCompressioIdentifier; totalPackets = packetCount; totalPayloadLength = totalPayloadDataLength; originatingLength = originatingDataLength; payloadData = payload; } /// /// The function saves the given sequence number and returns the data header of the given sequence. /// /// The sequence to retrieve. /// The data header of given the sequence. public byte[] GetBytes(long sequenceNumber) { sequence = sequenceNumber; return GetBytes(); } /// /// The function gets the media data, the packet control data and the packet data from the given packet and saves them. /// /// The given data. public void FromBytes(byte[] packetBytes) { if (packetBytes.Length < HeaderLengthInOctets) throw new ArgumentException("Data length insufficient for headers."); if(packetBytes[packetIdHeaderIndex] != PacketId) throw new ArgumentException("Incompatible packet type."); byte[] guidBytes = new byte[sequenceHeaderIndex - sourceGuidHeaderIndex]; Array.Copy(packetBytes, sourceGuidHeaderIndex, guidBytes, 0, guidBytes.Length); sourceGuid = guidBytes; sequence = BitConverter.ToInt64(packetBytes, sequenceHeaderIndex); mediaFormat = BitConverter.ToInt16(packetBytes, mediaTypeHeaderIndex); mediaTransferCompression = BitConverter.ToInt16(packetBytes, mediaTransferCompressionHeaderIndex); totalPackets = BitConverter.ToInt32(packetBytes, totalPacketCountHeaderIndex); totalPayloadLength = BitConverter.ToInt32(packetBytes, dataLengthHeaderIndex); originatingLength = BitConverter.ToInt32(packetBytes, originatingLengthHeaderIndex); if (packetBytes.Length > HeaderLengthInOctets) { payloadData = new byte[packetBytes.Length - HeaderLengthInOctets]; Array.Copy(packetBytes, HeaderLengthInOctets, payloadData, 0, payloadData.Length); } } /// /// The function returns the data header of the currently saved sequence. /// /// The data header of current the sequence. public byte[] GetBytes() { int payloadLength = (payloadData == null) ? 0 : payloadData.Length; byte[] networkPacketData = new byte[HeaderLengthInOctets + payloadLength]; networkPacketData[packetIdHeaderIndex] = PacketId; Array.Copy(sourceGuid, 0, networkPacketData, sourceGuidHeaderIndex, sourceGuid.Length); byte[] sequenceBytes = BitConverter.GetBytes(sequence); Array.Copy(sequenceBytes, 0, networkPacketData, sequenceHeaderIndex, sequenceBytes.Length); byte[] mediaTypeBytes = BitConverter.GetBytes(mediaFormat); Array.Copy(mediaTypeBytes, 0, networkPacketData, mediaTypeHeaderIndex, mediaTypeBytes.Length); byte[] mediaTransferCompressionBytes = BitConverter.GetBytes(mediaTransferCompression); Array.Copy(mediaTransferCompressionBytes, 0, networkPacketData, mediaTransferCompressionHeaderIndex, mediaTransferCompressionBytes.Length); byte[] totalPacketsBytes = BitConverter.GetBytes(totalPackets); Array.Copy(totalPacketsBytes, 0, networkPacketData, totalPacketCountHeaderIndex, totalPacketsBytes.Length); byte[] dataLengthBytes = BitConverter.GetBytes(totalPayloadLength); Array.Copy(dataLengthBytes, 0, networkPacketData, dataLengthHeaderIndex, dataLengthBytes.Length); byte[] originatingLengthBytes = BitConverter.GetBytes(originatingLength); Array.Copy(originatingLengthBytes, 0, networkPacketData, originatingLengthHeaderIndex, originatingLengthBytes.Length); if (payloadLength > 0) Array.Copy(payloadData, 0, networkPacketData, HeaderLengthInOctets, payloadData.Length); return networkPacketData; } } }