private bool ParseMessage(MessageID id, byte[] payload) { switch (id) { //Parse control messages 1-7 case MessageID.SetChunkSize: options.ChunkSize = ArrayUtil.BigIndianInt(payload, 0, 4); break; case MessageID.WindowAcknowledge: options.WindowSize = ArrayUtil.BigIndianInt(payload, 0, 4); break; // Parse commands like connect case MessageID.CommandAMF0: var command = ArrayUtil.AMF0String(payload, 0); switch (command.ToLower()) { case "connect": var cmdConnect = new CmdConnect(payload); if (OnConnect != null) { OnConnect(this, new ConnectData(cmdConnect)); } break; case "releasestream": if (OnReleaseStream != null) { OnReleaseStream(this, new AMFCallData(payload)); } break; case "fcpublish": if (OnFCPublish != null) { OnFCPublish(this, new AMFCallData(payload)); } break; case "createstream": if (OnCreateStream != null) { OnCreateStream(this, new AMFCallData(payload)); } break; case "publish": if (OnPublish != null) { OnPublish(this, new AMFCallData(payload)); } break; default: return(false); } break; default: return(false); } return(true); }
private int ParseReceivedData() { if (currentData.Length <= 0) { return(0); } RTMPPacket packet = new RTMPPacket(PacketType.Unknown); switch (CurrentState) { case RTMPState.Unitialized: { packet = new RTMPPacket(PacketType.VersionNumber); if (packet.InitWith(currentData)) { CurrentState = RTMPState.VersionReceived; } } break; case RTMPState.VersionReceived: { packet = new RTMPPacket(PacketType.Handshake); if (packet.InitWith(currentData)) { var sendData = ArrayUtil.ConcatArrays(new byte[1] { versionNumber }, packet.RawData); sendData = ArrayUtil.ConcatArrays(sendData, packet.RawData); Socket.Send(sendData); CurrentState = RTMPState.VersionSent; } } break; case RTMPState.VersionSent: packet = new RTMPPacket(PacketType.Handshake); if (packet.InitWith(currentData)) { CurrentState = RTMPState.HandshakeDone; } break; case RTMPState.HandshakeDone: { if (previousPacket == null) { previousPacket = new RTMPPacket(PacketType.Chunk); if (!previousPacket.InitWith(currentData)) { return(0); } packet = previousPacket; } else { packet = new RTMPPacket(PacketType.Chunk); if (!packet.InitWith(currentData, previousPacket)) { return(0); } else { previousPacket = packet; } } if (packet.MessageLength > 0 && packet.MessageLength < packet.MessageData.Length) { return(0); } Debug.Print(String.Format("Received RTMP chunk {0} bytes, Msg Id: {1} : {2}", packet.RawData.Length, packet.MessageTypeId, BitConverter.ToString(packet.RawData))); Debug.Print(String.Format("Chunk payload: {0}", BitConverter.ToString(packet.MessageData))); var msgID = packet.MessageTypeId; if (!ParseMessage((MessageID)msgID, packet.MessageData)) { Debug.Print("Failed to parse control message"); } } break; default: break; } return(packet.RawLength); }
public bool InitWith(byte[] data, RTMPPacket previousPacket = null) { if (data == null) { throw new Exception("Can't create packet with null payload"); } var dataLength = data.Length; if (dataLength < 1) { return(false); } RawLength = 0; switch (Type) { case PacketType.VersionNumber: { RawData = new byte[1] { data[0] }; //RTMP protocol version. Normally == 3 RawLength = 1; } break; case PacketType.Handshake: { if (dataLength < handshakeLength) { return(false); } if (dataLength == handshakeLength) { RawData = data; } else { RawData = new byte[handshakeLength]; //First 8 bytes should be timestamp[4] & zero[4] by Adobe's specs. It seems XSplit doesn't care about specs. So do I :D Buffer.BlockCopy(data, 0, RawData, 0, handshakeLength); } RawLength = handshakeLength; } break; case PacketType.Chunk: { // Fill message/basic header lengths and Chunk Type ParseChunkType(data[0]); var chunkLength = BasicHeaderLength + MessageHeaderLength; // Incomplete packet ? if (dataLength < chunkLength) { return(false); } if (ChunkType == rtmpproxy.ChunkType.Undefined) { throw new Exception("Packet with unknown RTMP header received!"); } switch (ChunkType) { // If header is empty - init this packet with properties from the previous packet case rtmpproxy.ChunkType.Header0: { if (previousPacket == null) { throw new Exception("Can't calculate RTMP chunk length. Previous packet is null"); } MessageLength = previousPacket.MessageLength; ChunkStreamId = previousPacket.ChunkStreamId; } break; default: { RawBasicHeader = ArrayUtil.Mid(data, 0, BasicHeaderLength); RawMessageHeader = ArrayUtil.Mid(data, BasicHeaderLength, MessageHeaderLength); ParseBasicHeader(); ParseMessageHeader(); if (ExtendedTimestamp >= 0x00ffffff) { RawExtendedTimeStamp = ArrayUtil.Mid(data, BasicHeaderLength + MessageHeaderLength, 4); ExtendedTimeStampLength = 4; } else { ExtendedTimeStampLength = 0; } chunkLength += (ExtendedTimeStampLength + MessageLength); if (chunkLength <= dataLength) { RawLength = chunkLength; RawData = new byte[RawLength]; Buffer.BlockCopy(data, 0, RawData, 0, RawLength); MessageData = new byte[MessageLength]; Buffer.BlockCopy(data, RawLength - MessageLength, MessageData, 0, MessageLength); } } break; } } break; } if (RawLength > 0) { return(true); } else { return(false); } }