private void OnRtspRequest(RtspChunk chunk) { if (chunk is RtspMessage) { _messages.Add(chunk as RtspMessage); } }
private void OnRtspChunk(RtspChunk chunk) { if (chunk is InterleavedData) { var interleaved = chunk as InterleavedData; var buffer = new ByteBuffer(interleaved.Payload, 0, interleaved.Payload.Length, true); buffer.Channel = interleaved.Channel; _rtpQueue.Add(buffer); } else if (chunk is RtspResponse) { var response = chunk as RtspResponse; LOG.Debug($"Received RTSP response from '{_connection.Endpoint}'"); LOG.Debug(response.ToString()); int cseq = response.CSeq; if (cseq <= 0) { LOG.Warn("Receive RTSP response that does not contain cseq header, disgarding."); return; } AsyncResponse cb = null; if (_callbacks.TryRemove(cseq, out cb)) { cb.HandleResponse(response); } } else { var msg = chunk as RtspMessage; LOG.Debug($"Received RTSP request from '{_connection.Endpoint}'"); LOG.Debug(msg.ToString()); // Server sent request. Since we do not support server side requests lets just // respond back with MethodNotAllowed. RtspResponse response = new RtspResponse(RtspResponse.Status.MethodNotAllowed); response.CSeq = msg.CSeq; if (!_connection.WriteMessage(response)) { LOG.Error("Received RTSP request from server but unable to send response."); } } }
public void ReceiveOptionsMessage() { string message = string.Empty; message += "OPTIONS * RTSP/1.0\n"; message += "CSeq: 1\n"; message += "Require: implicit-play\n"; message += "Proxy-Require: gzipped-messages\n"; message += "\n"; MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(message)); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); // Run testedListener.Start(); System.Threading.Thread.Sleep(100); testedListener.Stop(); // Check the transport was closed. _mockTransport.Received().Close(); //Check the message recevied Assert.AreEqual(1, _receivedMessage.Count); RtspChunk theMessage = _receivedMessage[0]; Assert.IsInstanceOf <RtspRequest>(theMessage); Assert.AreEqual(0, theMessage.Data.Length); Assert.AreSame(testedListener, theMessage.SourcePort); RtspRequest theRequest = theMessage as RtspRequest; Assert.AreEqual(RtspRequest.RequestType.OPTIONS, theRequest.RequestTyped); Assert.AreEqual(3, theRequest.Headers.Count); Assert.AreEqual(1, theRequest.CSeq); Assert.Contains("Require", theRequest.Headers.Keys); Assert.Contains("Proxy-Require", theRequest.Headers.Keys); Assert.AreEqual(null, theRequest.RtspUri); Assert.AreEqual(0, _receivedData.Count); }
public void ReceiveResponseMessage() { string message = string.Empty; message += "RTSP/1.0 551 Option not supported\n"; message += "CSeq: 302\n"; message += "Unsupported: funky-feature\n"; message += "\r\n"; MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(message)); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); // Run testedListener.Start(); System.Threading.Thread.Sleep(100); testedListener.Stop(); // Check the transport was closed. _mockTransport.Received().Close(); //Check the message recevied Assert.AreEqual(1, _receivedMessage.Count); RtspChunk theMessage = _receivedMessage[0]; Assert.IsInstanceOf <RtspResponse>(theMessage); Assert.AreEqual(0, theMessage.Data.Length); Assert.AreSame(testedListener, theMessage.SourcePort); RtspResponse theResponse = theMessage as RtspResponse; Assert.AreEqual(551, theResponse.ReturnCode); Assert.AreEqual("Option not supported", theResponse.ReturnMessage); Assert.AreEqual(2, theResponse.Headers.Count); Assert.AreEqual(302, theResponse.CSeq); Assert.AreEqual(0, _receivedData.Count); }
public void ReceivePlayMessage() { string message = string.Empty; message += "PLAY rtsp://audio.example.com/audio RTSP/1.0\r\n"; message += "CSeq: 835\r\n"; message += "\r\n"; MemoryStream stream = new MemoryStream(ASCIIEncoding.UTF8.GetBytes(message)); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); // Run testedListener.Start(); System.Threading.Thread.Sleep(100); testedListener.Stop(); // Check the transport was closed. _mockTransport.Received().Close(); //Check the message recevied Assert.AreEqual(1, _receivedMessage.Count); RtspChunk theMessage = _receivedMessage[0]; Assert.IsInstanceOf <RtspRequest>(theMessage); Assert.AreEqual(0, theMessage.Data.Length); Assert.AreSame(testedListener, theMessage.SourcePort); RtspRequest theRequest = theMessage as RtspRequest; Assert.AreEqual(RtspRequest.RequestType.PLAY, theRequest.RequestTyped); Assert.AreEqual(1, theRequest.Headers.Count); Assert.AreEqual(835, theRequest.CSeq); Assert.AreEqual("rtsp://audio.example.com/audio", theRequest.RtspUri.ToString()); Assert.AreEqual(0, _receivedData.Count); }
/// <summary> /// Initializes a new instance of the <see cref="RtspChunkEventArgs"/> class. /// </summary> /// <param name="aMessage">A message.</param> public RtspChunkEventArgs(RtspChunk aMessage) { Message = aMessage; }
/// <summary> /// Reads one message. /// </summary> /// <param name="commandStream">The Rtsp stream.</param> /// <returns>Message readen</returns> public RtspChunk ReadOneMessage(Stream commandStream) { if (commandStream == null) { throw new ArgumentNullException("commandStream"); } Contract.EndContractBlock(); ReadingState currentReadingState = ReadingState.NewCommand; // current decode message , create a fake new to permit compile. RtspChunk currentMessage = null; int size = 0; int byteReaden = 0; List <byte> buffer = new List <byte>(256); string oneLine = String.Empty; while (currentReadingState != ReadingState.End) { // if the system is not reading binary data. if (currentReadingState != ReadingState.Data && currentReadingState != ReadingState.MoreInterleavedData) { oneLine = String.Empty; bool needMoreChar = true; // I do not know to make readline blocking while (needMoreChar) { int currentByte = commandStream.ReadByte(); switch (currentByte) { case -1: // the read is blocking, so if we got -1 it is because the client close; currentReadingState = ReadingState.End; needMoreChar = false; break; case '\n': oneLine = ASCIIEncoding.UTF8.GetString(buffer.ToArray()); buffer.Clear(); needMoreChar = false; break; case '\r': // simply ignore this break; case '$': // if first caracter of packet is $ it is an interleaved data packet if (currentReadingState == ReadingState.NewCommand && buffer.Count == 0) { currentReadingState = ReadingState.InterleavedData; needMoreChar = false; } else { goto default; } break; default: buffer.Add((byte)currentByte); break; } } } switch (currentReadingState) { case ReadingState.NewCommand: currentMessage = RtspMessage.GetRtspMessage(oneLine); currentReadingState = ReadingState.Headers; break; case ReadingState.Headers: string line = oneLine; if (string.IsNullOrEmpty(line)) { currentReadingState = ReadingState.Data; ((RtspMessage)currentMessage).InitialiseDataFromContentLength(); } else { ((RtspMessage)currentMessage).AddHeader(line); } break; case ReadingState.Data: if (currentMessage.Data.Length > 0) { // Read the remaning data byteReaden += commandStream.Read(currentMessage.Data, byteReaden, currentMessage.Data.Length - byteReaden); //_logger.Debug(CultureInfo.InvariantCulture, "Readen {0} byte of data", byteReaden); } // if we haven't read all go there again else go to end. if (byteReaden >= currentMessage.Data.Length) { currentReadingState = ReadingState.End; } break; case ReadingState.InterleavedData: currentMessage = new RtspData(); ((RtspData)currentMessage).Channel = commandStream.ReadByte(); size = (commandStream.ReadByte() << 8) + commandStream.ReadByte(); currentMessage.Data = new byte[size]; currentReadingState = ReadingState.MoreInterleavedData; break; case ReadingState.MoreInterleavedData: // apparently non blocking byteReaden += commandStream.Read(currentMessage.Data, byteReaden, size - byteReaden); if (byteReaden < size) { currentReadingState = ReadingState.MoreInterleavedData; } else { currentReadingState = ReadingState.End; } break; default: break; } } if (currentMessage != null) { currentMessage.SourcePort = this; } return(currentMessage); }
/// <summary> /// Does the reading job. /// </summary> /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The sopping is made by the closing of the TCP connection. /// </remarks> private void DoJob() { try { // _logger.Debug("Connection Open"); while (_transport.Connected) { // La lectuer est blocking sauf si la connection est coupé RtspChunk currentMessage = ReadOneMessage(_stream); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout //if (currentMessage.SourcePort != null) // _logger.Debug(CultureInfo.InvariantCulture, "Receive from {0}", currentMessage.SourcePort.RemoteAdress); currentMessage.LogMessage(); } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { // _logger.Warn(CultureInfo.InvariantCulture, "Receive response not asked {0}", response.CSeq); } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _stream.Close(); _transport.Close(); } } //_logger.Debug("Connection Close"); } catch (IOException error) { //_logger.Warn("IO Error", error); _stream.Close(); _transport.Close(); } catch (SocketException error) { // _logger.Warn("Socket Error", error); _stream.Close(); _transport.Close(); } catch (Exception error) { // _logger.Warn("Unknow Error", error); throw; } }
/// <summary> /// Does the reading job. /// </summary> /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The stopping is made by the closing of the TCP connection. /// </remarks> private void DoJob() { try { _logger.Debug($"{_sourceId} Connection Open {ConnectionId}"); while (_transport.Connected) { // La lectuer est blocking sauf si la connection est coupé RtspChunk currentMessage = ReadOneMessage(_stream); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout if (currentMessage.SourcePort != null) { _logger.Debug(CultureInfo.InvariantCulture, "Receive from {0}", currentMessage.SourcePort.RemoteAdress); } currentMessage.LogMessage(_logger); } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { _logger.Warn(CultureInfo.InvariantCulture, $"{_sourceId} Receive response not asked {0}", response.CSeq); } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _logger.Warn($"{_sourceId} Transport closed due to receiving null message"); _stream.Close(); _transport.Close(); } } } catch (IOException error) { _logger.Debug($"{_sourceId} IO Error: {error}"); _stream.Close(); _transport.Close(); } catch (SocketException error) { _logger.Debug($"{_sourceId} Socket Error: {error}"); _stream.Close(); _transport.Close(); OnSocketExceptionRaised(new RtspSocketExceptionEventArgs(error)); } catch (ObjectDisposedException error) { _logger.Debug($"{_sourceId} Object Disposed: {error}"); } catch (Exception error) { _logger.Debug($"{_sourceId} Unknow Error: " + error); // throw; } _logger.Debug($"{_sourceId} Connection Close"); OnDisconnected(EventArgs.Empty); }
/// <summary> /// Does the reading job. /// </summary> /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The stopping is made by the closing of the TCP connection. /// </remarks> private void DoJob(CancellationToken token) { try { _logger.Info($"RTSP Connection with {_transport.RemoteAddress} started"); // token & _transport determine object's status while (!token.IsCancellationRequested && _transport?.Connected == true) { // La lectuer est blocking sauf si la connection est coupé RtspChunk currentMessage = ReadOneMessage(); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout if (currentMessage.SourcePort != null) { _logger.Info($"Receive from {currentMessage.SourcePort.RemoteAdress}"); } currentMessage.LogMessage(); } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { _logger.Warn($"Receive response not asked {response.CSeq}"); } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _stream.Close(); break; } } } catch (OperationCanceledException) { _logger.Info("Operation canceled"); _stream.Close(); } // Don't report IO/Socket errors when canceled. // May occur as a result of connection termination catch (IOException error) when(!token.IsCancellationRequested) { _logger.Error("IO Error" + error); _stream.Close(); throw; } catch (SocketException error) when(!token.IsCancellationRequested) { _logger.Error("Socket Error" + error); _stream.Close(); throw; } catch (ObjectDisposedException error) { _logger.Error("Object Disposed" + error); throw; } catch (Exception error) { _logger.Error("Unknown Error" + error); throw; } finally { _logger.Info($"RTSP Connection with {_transport.RemoteAddress} terminated"); } }
/// Does the reading job. /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The stopping is made by the closing of the TCP connection. /// </remarks> private void DoJob() { try { //TODO - log while (_transport.Connected) { // La lectuer est blocking sauf si la connection est coupé RtspChunk currentMessage = ReadOneMessage(_stream); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout if (currentMessage.SourcePort != null) { //TODO - log //TODO - log currentMessage.LogMessage(); } } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { //TODO - log } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _stream.Close(); _transport.Close(); } } } catch (IOException error) { //TODO - log _stream.Close(); _transport.Close(); } catch (SocketException error) { //TODO - log _stream.Close(); _transport.Close(); } catch (ObjectDisposedException error) { //TODO - log } catch (Exception error) { //TODO - log throw; } //TODO - log "Connection Close"; }
/// <summary> /// Does the reading job. /// </summary> /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The stopping is made by the closing of the TCP connection. /// </remarks> private void DoJob() { Profiler.BeginThreadProfiling("RTSP", "RTSPListener.DoJob"); try { _logger.Log("Connection Open"); while (_transport.Connected) { // La lectuer est blocking sauf si la connection est coupé Profiler.BeginSample("Read RTSP Message"); RtspChunk currentMessage = ReadOneMessage(_stream); Profiler.EndSample(); Profiler.BeginSample("Handle RTSP Message"); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout if (currentMessage.SourcePort != null) { _logger.LogFormat(LogType.Log, "Receive from {0}", currentMessage.SourcePort.RemoteAdress); } currentMessage.LogMessage(); } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { _logger.LogFormat(LogType.Warning, "Receive response not asked {0}", response.CSeq); } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _stream.Close(); _transport.Close(); } Profiler.EndSample(); } } catch (IOException error) { _logger.LogFormat(LogType.Warning, "IO Error", error); _stream.Close(); _transport.Close(); } catch (SocketException error) { _logger.LogFormat(LogType.Warning, "Socket Error", error); _stream.Close(); _transport.Close(); } catch (ObjectDisposedException error) { _logger.LogFormat(LogType.Warning, "Object Disposed", error); } catch (Exception error) { _logger.LogFormat(LogType.Warning, "Unknow Error", error); // throw; } _logger.Log("Connection Close"); }
/// <summary> /// Does the reading job. /// </summary> /// <remarks> /// This method read one message from TCP connection. /// If it a response it add the associate question. /// The stopping is made by the closing of the TCP connection. /// </remarks> private void DoJob() { try { System.Diagnostics.Debug.WriteLine("Connection Open"); while (_transport.Connected) { // La lectuer est blocking sauf si la connection est coupé RtspChunk currentMessage = ReadOneMessage(_stream); if (currentMessage != null) { if (!(currentMessage is RtspData)) { // on logue le tout if (currentMessage.SourcePort != null) { System.Diagnostics.Debug.WriteLine($"Receive from {currentMessage.SourcePort.RemoteAdress}"); } currentMessage.LogMessage(); } if (currentMessage is RtspResponse) { RtspResponse response = currentMessage as RtspResponse; lock (_sentMessage) { // add the original question to the response. RtspRequest originalRequest; if (_sentMessage.TryGetValue(response.CSeq, out originalRequest)) { _sentMessage.Remove(response.CSeq); response.OriginalRequest = originalRequest; } else { System.Diagnostics.Debug.WriteLine($"Receive response not asked {response.CSeq}"); } } OnMessageReceived(new RtspChunkEventArgs(response)); } else if (currentMessage is RtspRequest) { OnMessageReceived(new RtspChunkEventArgs(currentMessage)); } else if (currentMessage is RtspData) { OnDataReceived(new RtspChunkEventArgs(currentMessage)); } } else { _stream.Close(); _transport.Close(); } } } catch (IOException error) { System.Diagnostics.Debug.WriteLine($"IO Error {error}"); _stream.Close(); _transport.Close(); } catch (SocketException error) { System.Diagnostics.Debug.WriteLine($"Socket Error {error}"); _stream.Close(); _transport.Close(); } catch (ObjectDisposedException error) { System.Diagnostics.Debug.WriteLine($"Object Disposed {error}"); } catch (Exception error) { System.Diagnostics.Debug.WriteLine($"Unknow Error {error}"); // throw; } System.Diagnostics.Debug.WriteLine("Connection Close"); }