Пример #1
0
        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}");
                }
            }
        }
Пример #2
0
        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);
        }