private void HandleRequest(MemoryStream stream) { // Keep iterating until we have consumed the full buffer. while (stream.Position < stream.Length) { try { RtspChunk chunk = null; if (_decoder.Decode(stream, out chunk)) { _chunkHandler?.Invoke(chunk); } } catch (Exception e) { if (e is EndOfStreamException) { // We reached the end of the stream. return; } LOG.Error(e, $"Error occured while decoding buffer, reason: {e.Message}"); } } }
public bool Decode(MemoryStream stream, out RtspChunk chunk) { chunk = null; using (var reader = new BinaryReader(stream, Encoding.UTF8, true)) { switch (_state) { case ReadingState.SkipControlChars: { SkipControlCharacters(reader); _state = ReadingState.ReadInitial; break; } case ReadingState.ReadInitial: { char currentChar = Convert.ToChar(reader.PeekChar()); if (currentChar == INTERLEAVED_MARKER) { _state = ReadingState.ReadInterleavedData; return(false); } else { try { string line = _lineReader.Read(reader); string[] parts = SplitInitialLine(line); if (parts.Length < 3) { // This is an invalid initial line just ignore it. LOG.Warn($"Invalid start of RTSP message: '{line}', ignoring..."); _state = ReadingState.SkipControlChars; return(false); } else { _message = RtspMessage.CreateNewMessage(parts, _remoteEndpoint); _state = ReadingState.ReadHeader; } } catch (Exception e) { LOG.Error($"Failed to parse RTSP message, reason: {e.Message}"); _state = ReadingState.BadMessage; } } break; } case ReadingState.ReadHeader: { _state = ReadHeaders(_message, reader); // If the check size is greater than zero it will be decreased as the // ReadFixedContentLength state reads the body chunk by chunk. _chunkSize = _message.ContentLength; if (_state == ReadingState.SkipControlChars || (_chunkSize <= 0)) { // No content data expected. // TODO(frank.lamar): Add support for chunking. Not important // at the moment because I have yet to see a device use chunking. chunk = _message; Reset(); return(true); } break; } case ReadingState.ReadFixedContentLength: { if (_bufferIdx == 0) { // We are reading the first chunk of data. We need to first // allocate the message's data array. _message.Body = new byte[_chunkSize]; } int bytesRead = reader.Read(_message.Body, _bufferIdx, _chunkSize); _chunkSize -= bytesRead; // Decrement the bytes read from the chunk size. _bufferIdx += bytesRead; // Increment the index to write next chunk to. if (_chunkSize == 0) { chunk = _message; Reset(); return(true); } break; } case ReadingState.ReadInterleavedData: { if (_chunkSize == 0 && _bufferIdx == 0) { reader.ReadByte(); // Consume the '$' marker left in the buffer. byte channel = reader.ReadByte(); _chunkSize = GetUint16(reader); _interleavedPacket = new InterleavedData(channel); _interleavedPacket.Payload = new byte[_chunkSize]; } int bytesRead = reader.Read(_interleavedPacket.Payload, _bufferIdx, _chunkSize); _chunkSize -= bytesRead; // Decrement the bytes read from the chunk size. _bufferIdx += bytesRead; // Increment the index to write next chunk to. if (_chunkSize == 0) { chunk = _interleavedPacket; Reset(); return(true); } break; } case ReadingState.BadMessage: { LOG.Debug("Unable to decode RTSP message, ignoring messsage"); stream.Seek(0, SeekOrigin.End); // Skip the remaining buffer. Reset(); break; } default: { LOG.Warn($"Unknown state: {_state}"); Reset(); break; } } } return(false); }