/// <summary> /// Parses the given packet contained in the byte buffer array and returns /// a list of packets /// </summary> /// <param name="buffer"></param> /// <param name="length"></param> /// <returns></returns> public static LinkedList <AMFDataType> getPacketVars(byte[] buffer, int length, int offset) { //the linked list of packet vars LinkedList <AMFDataType> packetVars = new LinkedList <AMFDataType>(); //read the header byte to determine size MemoryStream packetStream = new MemoryStream(buffer, offset, length); byte header = (byte)packetStream.ReadByte(); header &= 0xC0; // isolate the size information //seek into the packet packetStream.Seek(AMFHeader.getHeaderSize(header) - 1, SeekOrigin.Current); while (packetStream.Position < length) { byte type = (byte)packetStream.ReadByte(); Console.WriteLine("Looking at type: " + type); AMFDataType var = findAppropriateReader(type); var.read(packetStream); packetVars.AddLast(var); } return(packetVars); }
/// <summary> /// Reads the header information from the given byte[] data. /// </summary> /// <param name="offset">The offset in the data buffer to look at</param> /// <param name="data">The data to look at</param> /// <returns>null if the data is not valid, or an AMFHeader object representing /// the information</returns> public static AMFHeader readHeader(int offset, byte[] data) { AMFHeader header = new AMFHeader(0, 0); header.ChannelId = (byte)(data[offset] & 0x3F); header.HeaderTypeSize = (byte)(data[offset] & 0xC0); offset++; if (header.getHeaderSize() > 4) { //read the timestamp portion header.TimeStamp |= data[offset] << 16; header.TimeStamp |= data[offset + 1] << 8; header.TimeStamp |= data[offset + 2]; offset += 3; } if (header.getHeaderSize() > 8) { //read the AMF body size header.BodySize |= data[offset] << 16; header.BodySize |= data[offset + 1] << 8; header.BodySize |= data[offset + 2]; offset += 3; } if (header.getHeaderSize() > 8) { //read the AMF type header.RTMPType = data[offset]; offset++; } if (header.getHeaderSize() > 12) { //write the endpoint bytes ( or stream ID if video ) header.endPoint |= data[offset]; header.endPoint |= (data[offset + 1] << 8); header.endPoint |= (data[offset + 2] << 16); header.endPoint |= (data[offset + 3] << 24); } return(header); }
/// <summary> /// Reads the header information from the given byte[] data. /// </summary> /// <param name="offset">The offset in the data buffer to look at</param> /// <param name="data">The data to look at</param> /// <returns>null if the data is not valid, or an AMFHeader object representing /// the information</returns> public static AMFHeader readHeader(int offset, byte[] data) { AMFHeader header = new AMFHeader(0, 0); header.ChannelId = (byte)(data[offset] & 0x3F); header.HeaderTypeSize = (byte)(data[offset] & 0xC0); offset++; if (header.getHeaderSize() > 4) { //read the timestamp portion header.TimeStamp |= data[offset] << 16; header.TimeStamp |= data[offset + 1] << 8; header.TimeStamp |= data[offset + 2]; offset += 3; } if (header.getHeaderSize() > 8) { //read the AMF body size header.BodySize |= data[offset] << 16; header.BodySize |= data[offset + 1] << 8; header.BodySize |= data[offset + 2]; offset += 3; } if (header.getHeaderSize() > 8) { //read the AMF type header.RTMPType = data[offset]; offset++; } if (header.getHeaderSize() > 12) { //write the endpoint bytes ( or stream ID if video ) header.endPoint |= data[offset]; header.endPoint |= (data[offset + 1] << 8); header.endPoint |= (data[offset + 2] << 16); header.endPoint |= (data[offset + 3] << 24); } return header; }
/// <summary> /// Sends the current buffer using data_buffer as the source of data. The size /// is determined from the position in outputBuff. /// </summary> /// <param name="header">The header to prepend to the amf packet.</param> private void chunkBufferAndSend(AMFHeader header) { //the size remaining in the data buffer int size = (int)outputBuff.Position; //the position in the data buffer (from which to start sending bytes) int position = 0; //reset the chunkBuff position chunkBuff.Position = 0; //write the header to the chunk buffer header.writeHeader(chunkBuff); //copy <= 128 bytes from the data buffer into the chunk buffer to send. Array.Copy(dataBuffer, 0, chunk_buffer, header.getHeaderSize(), size > 128 ? 128 : size); //send the first packet of information connectionSocket.Send(chunk_buffer, (header.getHeaderSize() + (size > 128 ? 128 : size)), SocketFlags.None); size -= 128; position += 128; while (size > 0) { //add a header byte dataBuffer[position - 1] = header.get_1_HeaderByte(); //send out the data connectionSocket.Send(dataBuffer, position - 1, size > 128 ? 129 : size + 1, SocketFlags.None); position += 128; size -= 128; } }
/// <summary> /// Sends the flv tag to the RTMP server. /// </summary> /// <param name="tagData"></param> /// <param name="tag"></param> public override bool sendFLVTag(byte[] tagData, FLVTag tag) { if (!isConnected) return false; outputBuff.Position = 0; chunkBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x8); header.RTMPType = AMFHeader.RTMP_TYPE_VIDEO; header.TimeStamp = tag.TimeStamp; header.EndPoint = 0x00000001; header.BodySize = tag.getTagSizeInBytes() - 11; //write the header to teh chunkbuffer header.writeHeader(chunkBuff); //the size remaining in the data buffer int size = tag.getTagSizeInBytes() - 11; //the position in the data buffer (from which to start sending bytes) int position = 0; //write the header to the chunk buffer header.writeHeader(chunkBuff); //copy <= 128 bytes from the tagData into the chunk buffer to send. Array.Copy(tagData, 11, chunk_buffer, header.getHeaderSize(), size > 128 ? 128 : size); //send the first packet of information connectionSocket.Send(chunk_buffer, (header.getHeaderSize() + (size > 128 ? 128 : size)), SocketFlags.None); size -= 128; position += 128 + 11; //while there is still bytes while (size > 0) { //add a header byte byte t = tagData[position - 1]; tagData[position - 1] = header.get_1_HeaderByte(); //send out the data connectionSocket.Send(tagData, position - 1, size > 128 ? 129 : size + 1, SocketFlags.None); //restore where the header was tagData[position - 1] = t; position += 128; size -= 128; } return true; }