public void RtpDataReceived(object sender, RtspChunkEventArgs chunkEventArgs) { try { RtspData rtpData = chunkEventArgs.Message as RtspData; if (IsRtcpGoodbye(rtpData)) { ProcessTeardownResponse(); return; } // Check which channel the Data was received on. // eg the Video Channel, the Video Control Channel (RTCP) // In the future would also check the Audio Channel and Audio Control Channel if (rtpData.Channel == videoRTCPChannel) { Logger.Info("Received a RTCP message on channel " + rtpData.Channel); return; } if (rtpData.Channel == videoDataChannel) { ProcessRTPVideo(chunkEventArgs); } } catch (Exception e) { Logger.Error(e); rtspErrorSubject.OnNext(e.Message); } }
private bool IsRtcpGoodbye(RtspData rtspData) { int RTCPSenderReport = 200; // RTCP.PT=SR=200 ; RFC3550 int RTCPGoodbye = 203; // RTCP.PT=BYE=203 ; RFC3550 int firstPacketType = rtspData.Data[1]; if (firstPacketType != RTCPSenderReport) { return(false); } int firstPacketLength = 4 * ((rtspData.Data[2] << 8) + rtspData.Data[3]) + 4; bool isThisACompoundPacket = rtspData.Data.Length > firstPacketLength; if (!isThisACompoundPacket) { return(false); } int secondPacketType = rtspData.Data[firstPacketLength + 1]; if (secondPacketType != RTCPGoodbye) { return(false); } return(true); // It's a RTCP Sender Report Goodbye compound packet, EoS. }
public void SendDataTooLargeSync() { const int dataLenght = 0x10001; MemoryStream stream = new MemoryStream(); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); RtspData data = new RtspData(); data.Channel = 12; data.Data = new byte[dataLenght]; TestDelegate test = () => testedListener.SendData(data.Channel, data.Data); Assert.That(test, Throws.InstanceOf <ArgumentException>()); }
/// <summary> /// Begins the send data. /// </summary> /// <param name="aRtspData">A Rtsp data.</param> /// <param name="asyncCallback">The async callback.</param> /// <param name="aState">A state.</param> public IAsyncResult BeginSendData(RtspData aRtspData, AsyncCallback asyncCallback, object state) { if (aRtspData == null) { throw new ArgumentNullException("aRtspData"); } Contract.EndContractBlock(); return(BeginSendData(aRtspData.Channel, aRtspData.Data, asyncCallback, state)); }
/// <summary> /// Clones this instance. /// <remarks>Listner is not cloned</remarks> /// </summary> /// <returns>a clone of this instance</returns> public override object Clone() { RtspData result = new RtspData(); result.Channel = this.Channel; if (this.Data != null) { result.Data = this.Data.Clone() as byte[]; } result.SourcePort = this.SourcePort; return(result); }
public void Clone() { RtspData testObject = new RtspData(); testObject.Channel = 1234; testObject.Data = new byte[] { 45, 63, 36, 42, 65, 00, 99 }; testObject.SourcePort = new RtspListener(Substitute.For <IRtspTransport>()); RtspData cloneObject = testObject.Clone() as RtspData; Assert.IsNotNull(cloneObject); Assert.AreEqual(testObject.Channel, cloneObject.Channel); Assert.AreEqual(testObject.Data, cloneObject.Data); Assert.AreSame(testObject.SourcePort, cloneObject.SourcePort); }
public void RtpDataReceived(object sender, Rtsp.RtspChunkEventArgs e) { RtspData rtpData = e.Message as RtspData; // Check which channel the Data was received on. // eg the Video Channel, the Video Control Channel (RTCP) // In the future would also check the Audio Channel and Audio Control Channel if (rtpData.Channel == videoRTCPChannel) { Logger.Info("Received a RTCP message on channel " + rtpData.Channel); return; } if (rtpData.Channel == videoDataChannel) { ProcessRTPVideo(e); } }
public void SendDataAsync() { const int dataLenght = 45; MemoryStream stream = new MemoryStream(); _mockTransport.GetStream().Returns(stream); // Setup test object. RtspListener testedListener = new RtspListener(_mockTransport); testedListener.MessageReceived += new EventHandler <RtspChunkEventArgs>(MessageReceived); testedListener.DataReceived += new EventHandler <RtspChunkEventArgs>(DataReceived); RtspData data = new RtspData(); data.Channel = 12; data.Data = new byte[dataLenght]; for (int i = 0; i < dataLenght; i++) { data.Data[i] = (byte)i; } // Run var asyncResult = testedListener.BeginSendData(data, null, null); testedListener.EndSendData(asyncResult); var result = stream.GetBuffer(); int index = 0; Assert.That(result[index++], Is.EqualTo((byte)'$')); Assert.That(result[index++], Is.EqualTo(data.Channel)); Assert.That(result[index++], Is.EqualTo((dataLenght & 0xFF00) >> 8)); Assert.That(result[index++], Is.EqualTo(dataLenght & 0x00FF)); for (int i = 0; i < dataLenght; i++) { Assert.That(result[index++], Is.EqualTo(data.Data[i])); } }
public void ReceiveData() { Random rnd = new Random(); byte[] data = new byte[0x0234]; rnd.NextBytes(data); byte[] buffer = new byte[data.Length + 4]; buffer[0] = 0x24; // $ buffer[1] = 11; buffer[2] = 0x02; buffer[3] = 0x34; Buffer.BlockCopy(data, 0, buffer, 4, data.Length); MemoryStream stream = new MemoryStream(buffer); _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(500); testedListener.Stop(); // Check the transport was closed. _mockTransport.Received().Close(); //Check the message recevied Assert.AreEqual(0, _receivedMessage.Count); Assert.AreEqual(1, _receivedData.Count); Assert.IsInstanceOf <RtspData>(_receivedData[0]); RtspData dataMessage = _receivedData[0] as RtspData; Assert.AreEqual(11, dataMessage.Channel); Assert.AreSame(testedListener, dataMessage.SourcePort); Assert.AreEqual(data, dataMessage.Data); }
/// <summary> /// Handles the data receive. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="RTSP.RTSPChunkEventArgs"/> instance containing the event data.</param> public void HandleDataReceive(object sender, RtspChunkEventArgs e) { if (e == null) { throw new ArgumentNullException("e"); } Contract.EndContractBlock(); try { RtspData data = e.Message as RtspData; if (data != null) { byte[] frame = data.Data; if (data.Channel == this.SourceInterleavedVideo) { ForwardVUdpPort.BeginSend(frame, frame.Length, new AsyncCallback(EndSendVideo), frame); } } } catch (Exception error) { _logger.Warn("Error during frame forwarding", error); } }
/// <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); }
private void DataReceived(object sender, RtspChunkEventArgs e) { RtspData data_received = e.Message as RtspData; if (data_received.Channel == _videoDataChannel) { // Received some Video or Audio Data on the correct channel. // RTP Packet Header // 0 - Version, P, X, CC, M, PT and Sequence Number //32 - Timestamp //64 - SSRC //96 - CSRCs (optional) //nn - Extension ID and Length //nn - Extension header int rtp_version = (e.Message.Data[0] >> 6); int rtp_padding = (e.Message.Data[0] >> 5) & 0x01; int rtp_extension = (e.Message.Data[0] >> 4) & 0x01; int rtp_csrc_count = (e.Message.Data[0] >> 0) & 0x0F; int rtp_marker = (e.Message.Data[1] >> 7) & 0x01; int rtp_payload_type = (e.Message.Data[1] >> 0) & 0x7F; uint rtp_sequence_number = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]); uint rtp_timestamp = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]); uint rtp_ssrc = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]); int rtp_payload_start = 4 // V,P,M,SEQ + 4 // time stamp + 4 // ssrc + (4 * rtp_csrc_count); // zero or more csrcs uint rtp_extension_id = 0; uint rtp_extension_size = 0; if (rtp_extension == 1) { rtp_extension_id = ((uint)e.Message.Data[rtp_payload_start + 0] << 8) + (uint)(e.Message.Data[rtp_payload_start + 1] << 0); rtp_extension_size = ((uint)e.Message.Data[rtp_payload_start + 2] << 8) + (uint)(e.Message.Data[rtp_payload_start + 3] << 0) * 4; // units of extension_size is 4-bytes rtp_payload_start += 4 + (int)rtp_extension_size; // extension header and extension payload } if (data_received.Channel == _videoDataChannel && rtp_payload_type == 96) { byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start]; Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); List <byte[]> nal_units = _h264Payload.Process_H264_RTP_Packet(rtp_payload, rtp_marker); if (nal_units != null) { // we have passed in enough RTP packets to make a Frame of video try { if (_decoder == null) { _decoder = new H264Decoder(nal_units); } _currentBitmap = _decoder.Update(nal_units); NewBitmapAvailable.Set(); } catch (Exception error) { Console.WriteLine(error.Message); } } } } }