/// <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); }
public void rtmptConnect(string[] c_params) { PersistantHTTPConnection connection = new PersistantHTTPConnection(sParams.ServerURL, sParams.Port); req = (HttpWebRequest)WebRequest.Create( "http://" + sParams.ServerURL + ":" + sParams.Port + "/send/" + clientIndex + "/" + pollCount ); req.ContentType = "application/x-fcs"; req.Method = "POST"; req.KeepAlive = true; //using the client index connect to the application AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x3); header.EndPoint = 0; header.TimeStamp = 1; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; requestStream = req.GetRequestStream(); //write the method name (connect); AMFString aString = new AMFString("connect"); aString.write(buffer); buffer.Write(reserved1, 0, reserved1.Length); AMFObject aConnParams = new AMFObject(); aConnParams.addParameter("app", new AMFString(sParams.ApplicationName)); aConnParams.addParameter("flashVer", new AMFString("WIN 8,0,24,0")); aConnParams.addParameter("swfUrl", new AMFString("xfile://c:\\swfurl.swf")); aConnParams.addParameter("tcUrl", new AMFString("rtmp://" + sParams.ServerURL + "/" + sParams.ApplicationName)); aConnParams.addParameter("fpad", new AMFBoolean(false)); aConnParams.addParameter("name", new AMFString("ePresence")); aConnParams.write(buffer); foreach (string s in c_params) { new AMFString(s).write(buffer); } header.BodySize = (int)buffer.Position; Console.Write(header.BodySize); header.writeHeader(requestStream); requestStream.Write(buffer.GetBuffer(), 0, (int)buffer.Position); resp = (HttpWebResponse)req.GetResponse(); responseReader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8); Console.WriteLine(responseReader.ReadToEnd()); }
/// <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; }
/// <summary> /// Publish a stream on the server. /// </summary> private void rtmpPublish() { outputBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x8); header.EndPoint = 0x1; header.TimeStamp = 0x25; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; AMFString func = new AMFString("publish"); func.write(outputBuff); byte[] n_reserved = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; outputBuff.Write(n_reserved, 0, n_reserved.Length); new AMFNull().write(outputBuff); new AMFString(sParams.PublishName).write(outputBuff); AMFString live = new AMFString(sParams.Record ? "record" : "live"); live.write(outputBuff); header.BodySize = (int)outputBuff.Position; //send the information chunkBufferAndSend(header); int l = connectionSocket.Receive(dataBuffer); }
public override void call(string methodName, fMethodCallback callbackFunc, params object[] pobject) { outputBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x3); header.EndPoint = 0; header.TimeStamp = 1; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; AMFString func = new AMFString(methodName); func.write(outputBuff); outputBuff.Write(c_reserved, 0, c_reserved.Length); new AMFNull().write(outputBuff); foreach (object o in pobject) { AMFDataType dObj = AMFDataType.findDataHandler(o); dObj.write(outputBuff); } header.BodySize = (int)outputBuff.Position; chunkBufferAndSend(header); }
/// <summary> /// Create a Live Stream on the server /// </summary> private void rtmpCreateStream() { outputBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x3); header.EndPoint = 0; header.TimeStamp = 1; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; AMFString func = new AMFString("createStream"); func.write(outputBuff); outputBuff.Write(c_reserved, 0, c_reserved.Length); new AMFNull().write(outputBuff); header.BodySize = (int)outputBuff.Position; //send the information chunkBufferAndSend(header); int l = connectionSocket.Receive(dataBuffer); }
/// <summary> /// Performs the "connect" method on the server. /// </summary> private void rtmpConnect(string[] c_params) { //reset the output buffer position outputBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x3); header.EndPoint = 0; header.TimeStamp = 1; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; //write the method name (connect); AMFString aString = new AMFString("connect"); aString.write(outputBuff); outputBuff.Write(reserved1, 0, reserved1.Length); AMFObject aConnParams = new AMFObject(); aConnParams.addParameter("app", new AMFString(sParams.ApplicationName)); aConnParams.addParameter("flashVer", new AMFString("WIN 8,0,24,0")); aConnParams.addParameter("swfUrl", new AMFString("xfile://c:\\swfurl.swf")); aConnParams.addParameter("tcUrl", new AMFString("rtmp://" + sParams.ServerURL +"/" + sParams.ApplicationName)); aConnParams.addParameter("fpad", new AMFBoolean(false)); aConnParams.addParameter("name", new AMFString("ePresence")); aConnParams.write(outputBuff); foreach (string s in c_params) { new AMFString(s).write(outputBuff); } //since we only wrote the body, the body size is the positiin //in the buffer header.BodySize = (int)outputBuff.Position; //send the information chunkBufferAndSend(header); //receive the connection information int l =connectionSocket.Receive(dataBuffer); //receive the connection information l = connectionSocket.Receive(dataBuffer); }
public override bool disconnect() { isConnected = false; outputBuff.Position = 0; AMFHeader header = new AMFHeader(AMFHeader.HEADER_12, 0x8); header.EndPoint = 0x00000001; header.TimeStamp = 0; header.RTMPType = AMFHeader.RTMP_TYPE_FUNCTION; header.BodySize = 0; AMFString func = new AMFString("publish"); func.write(outputBuff); byte[] n_reserved = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; outputBuff.Write(n_reserved, 0, n_reserved.Length); new AMFNull().write(outputBuff); new AMFString(sParams.PublishName).write(outputBuff); new AMFBoolean(false).write(outputBuff); header.BodySize = (int)outputBuff.Position; //send the information chunkBufferAndSend(header); connectionSocket.Disconnect(true); return true; }