public RtspSource(string name, string sourceLocation, NetworkCredential credential = null, AuthenticationSchemes authType = AuthenticationSchemes.None, Rtsp.RtspClient.ClientProtocolType? rtpProtocolType = null, int bufferSize = RtspClient.DefaultBufferSize, Sdp.MediaType? specificMedia = null, TimeSpan? startTime = null, TimeSpan? endTime = null) : this(name, new Uri(sourceLocation), credential, authType, rtpProtocolType, bufferSize, specificMedia, startTime, endTime) { //Check for a null Credential and UserInfo in the Location given. if (credential == null && !string.IsNullOrWhiteSpace(m_Source.UserInfo)) { RtspClient.Credential = Media.Common.Extensions.Uri.UriExtensions.ParseUserInfo(m_Source); //Remove the user info from the location RtspClient.CurrentLocation = new Uri(RtspClient.CurrentLocation.AbsoluteUri.Replace(RtspClient.CurrentLocation.UserInfo + (char)Common.ASCII.AtSign, string.Empty).Replace(RtspClient.CurrentLocation.UserInfo, string.Empty)); } }
public async Task StartReceive() { QuitFlag = false; while (!QuitFlag) { List <byte[]> datas; bool succeed; if (DataChannel) { succeed = Rtsp.TryDequeData(out datas, 10); } else { succeed = Rtsp.TryDequeControl(out datas, 1); } if (succeed) { foreach (byte[] data in datas) { if (!DataChannel) { SocketRtspResponse response = new SocketRtspResponse { Seq = Seq, RtspBuffer = data }; await TcpClient.Client.SendAsync(response.ToArray(), SocketFlags.None, CancellationToken.None); } else { await TcpClient.Client.SendAsync(data, SocketFlags.None, CancellationToken.None); } } } else { if (DataChannel) { await Task.Delay(1); } else { await Task.Delay(10); } } } }
/// <summary> /// Handles the MessageReceived event of the Listener control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RTSP.RTSPChunkEventArgs"/> instance containing the event data.</param> private void Listener_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e) { Contract.Requires(e.Message != null); this.Enqueue(e.Message as RtspMessage); }
public async Task Send(byte[] buffer) { await Rtsp.Send(buffer); }
private void Rtsp_client_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e) { Console.WriteLine("Message Received " + e.ToString()); Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse; Console.WriteLine("Received " + message.OriginalRequest.ToString()); if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions) { // send the Describe Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe(); describe_message.RtspUri = new Uri(url); rtsp_client.SendMessage(describe_message); } if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe) { // Got a reply for DESCRIBE // Examine the SDP Console.Write(System.Text.Encoding.UTF8.GetString(message.Data)); Rtsp.Sdp.SdpFile sdp_data; using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data))) { sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream); } // Process each 'Media' Attribute in the SDP. // If the attribute is for Video, then carry out a SETUP and a PLAY for (int x = 0; x < sdp_data.Medias.Count; x++) { if (sdp_data.Medias[x].GetMediaType() == Rtsp.Sdp.Media.MediaType.video) { // seach the atributes for control, fmtp and rtpmap String control = ""; // the "track" or "stream id" String fmtp = ""; // holds SPS and PPS String rtpmap = ""; // holds Payload format, eg 96 often used with H264 as first dynamic payload value foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs) { if (attrib.Key.Equals("control")) control = attrib.Value; if (attrib.Key.Equals("fmtp")) fmtp = attrib.Value; if (attrib.Key.Equals("rtpmap")) rtpmap = attrib.Value; } String[] split_rtpmap = rtpmap.Split(' '); video_payload = 0; bool result = Int32.TryParse(split_rtpmap[0], out video_payload); // Transport: RTP/AVP;unicast;client_port=8000-8001 // Transport: RTP/AVP/TCP;interleaved=0-1 Rtsp.Messages.RtspRequest setup_message = new Rtsp.Messages.RtspRequestSetup(); setup_message.RtspUri = new Uri(url + "/" + control); setup_message.AddHeader("Transport: RTP/AVP/TCP;interleaved=0"); rtsp_client.SendMessage(setup_message); } } } if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup) { // Got Reply to SETUP Console.WriteLine("Got reply from Setup. Session is " + message.Session); String session = message.Session; // Session value used with Play, Pause, Teardown Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay(); play_message.RtspUri = new Uri(url); play_message.Session = session; // play_message.Timeout = 65; rtsp_client.SendMessage(play_message); } if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay) { // Got Reply to PLAU Console.WriteLine("Got reply from Play " + message.Command); } }
private void Rtsp_client_DataReceived(object sender, Rtsp.RtspChunkEventArgs e) { // 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); rtp_payload_start += 4 + (int)rtp_extension_size; // extension header and extension payload } Console.WriteLine("RTP Data" + " V=" + rtp_version + " P=" + rtp_padding + " X=" + rtp_extension + " CC=" + rtp_csrc_count + " M=" + rtp_marker + " PT=" + rtp_payload_type + " Seq=" + rtp_sequence_number + " Time=" + rtp_timestamp + " SSRC=" + rtp_ssrc + " Size=" + e.Message.Data.Length); if (rtp_payload_type != video_payload) { Console.WriteLine("Ignoring this RTP payload"); return; // ignore this data } // If rtp_marker is '1' then this is the final transmission for this packet. // If rtp_marker is '0' we need to accumulate data with the same timestamp // ToDo - Check Timestamp // ToDo - could avoid a copy if there is only one RTP frame for the data (temp list is zero) // Add to the tempoary_rtp List byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start]; // payload with RTP header removed System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload temporary_rtp_payloads.Add(rtp_payload); if (rtp_marker == 1) { // Process the RTP frame Process_RTP_Frame(temporary_rtp_payloads); temporary_rtp_payloads.Clear(); } }
// RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc private void Rtsp_MessageReceived(object sender, Rtsp.RtspChunkEventArgs e) { Rtsp.Messages.RtspResponse message = e.Message as Rtsp.Messages.RtspResponse; Console.WriteLine("Received " + message.OriginalRequest.ToString()); // If we get a reply to OPTIONS and CSEQ is 1 (which was our first command), then send the DESCRIBE // If we fer a reply to OPTIONS and CSEQ is not 1, it must have been a keepalive command if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestOptions) { if (message.CSeq == 1) { // Start a Timer to send an OPTIONS command (for keepalive) every 20 seconds keepalive_timer = new System.Timers.Timer(); keepalive_timer.Elapsed += Timer_Elapsed; keepalive_timer.Interval = 20 * 1000; keepalive_timer.Enabled = true; // send the Describe Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe(); describe_message.RtspUri = new Uri(url); rtsp_client.SendMessage(describe_message); } else { // do nothing } } // If we get a reply to DESCRIBE (which was our second command), then prosess SDP and send the SETUP if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestDescribe) { // Got a reply for DESCRIBE // Examine the SDP Console.Write(System.Text.Encoding.UTF8.GetString(message.Data)); Rtsp.Sdp.SdpFile sdp_data; using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data))) { sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream); } // Process each 'Media' Attribute in the SDP (each sub-stream) // If the attribute is for Video, then carry out a SETUP and a PLAY // Only do this for the first Video attribute in case there is more than one in the SDP for (int x = 0; x < sdp_data.Medias.Count; x++) { if (sdp_data.Medias[x].GetMediaType() == Rtsp.Sdp.Media.MediaType.video) { // We only want the first video sub-stream if (video_payload == -1) { // seach the atributes for control, fmtp and rtpmap String control = ""; // the "track" or "stream id" Rtsp.Sdp.AttributFmtp fmtp = null; // holds SPS and PPS in base64 Rtsp.Sdp.AttributRtpMap rtpmap = null; // holds Payload format, eg 96 often used with H264 as first dynamic payload value foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs) { if (attrib.Key.Equals("control")) control = attrib.Value; if (attrib.Key.Equals("fmtp")) fmtp = attrib as Rtsp.Sdp.AttributFmtp; if (attrib.Key.Equals("rtpmap")) rtpmap = attrib as Rtsp.Sdp.AttributRtpMap; } // Split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64 if (fmtp != null) { var param = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter); var sps_pps = param.SpropParameterSets; if (sps_pps.Count > 0) video_sps = sps_pps[0]; if (sps_pps.Count > 1) video_pps = sps_pps[1]; Output_NAL(sps_pps); // output SPS and PPS } // Split the rtpmap to get the Payload Type video_payload = 0; if (rtpmap != null) video_payload = rtpmap.PayloadNumber; Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup(); setup_message.RtspUri = new Uri(url + "/" + control); RtspTransport transport = null; if (rtp_transport == RTP_TRANSPORT.TCP) { // Server interleaves the RTP packets over the RTSP connection // Example for TCP mode (RTP over RTSP) Transport: RTP/AVP/TCP;interleaved=0-1 video_data_channel = 0; // Used in DataReceived event handler video_rtcp_channel = 1; // Used in DataReceived event handler transport = new RtspTransport() { LowerTransport = RtspTransport.LowerTransportType.TCP, Interleaved = new PortCouple(video_data_channel, video_rtcp_channel), // Channel 0 for video. Channel 1 for RTCP status reports }; } if (rtp_transport == RTP_TRANSPORT.UDP) { // Server sends the RTP packets to a Pair of UDP Ports (one for data, one for rtcp control messages) // Example for UDP mode Transport: RTP/AVP;unicast;client_port=8000-8001 video_data_channel = udp_pair.data_port; // Used in DataReceived event handler video_rtcp_channel = udp_pair.control_port; // Used in DataReceived event handler transport = new RtspTransport() { LowerTransport = RtspTransport.LowerTransportType.UDP, IsMulticast = false, ClientPort = new PortCouple(video_data_channel, video_rtcp_channel), // a Channel for video. a Channel for RTCP status reports }; } if (rtp_transport == RTP_TRANSPORT.MULTICAST) { // Server sends the RTP packets to a Pair of UDP ports (one for data, one for rtcp control messages) // using Multicast Address and Ports that are in the reply to the SETUP message // Example for MULTICAST mode Transport: RTP/AVP;multicast video_data_channel = 0; // we get this information in the SETUP message reply video_rtcp_channel = 0; // we get this information in the SETUP message reply transport = new RtspTransport() { LowerTransport = RtspTransport.LowerTransportType.UDP, IsMulticast = true }; } setup_message.AddTransport(transport); rtsp_client.SendMessage(setup_message); } } } } // If we get a reply to SETUP (which was our third command), then process then send PLAY if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup) { // Got Reply to SETUP Console.WriteLine("Got reply from Setup. Session is " + message.Session); session = message.Session; // Session value used with Play, Pause, Teardown // Check the Transport header if (message.Headers.ContainsKey(RtspHeaderNames.Transport)) { RtspTransport transport = RtspTransport.Parse(message.Headers[RtspHeaderNames.Transport]); // Check if Transport header includes Multicast if (transport.IsMulticast) { String multicast_address = transport.Destination; video_data_channel = transport.Port.First; video_rtcp_channel = transport.Port.Second; // Create the Pair of UDP Sockets in Multicast mode udp_pair = new UDPSocket(multicast_address, video_data_channel, multicast_address, video_rtcp_channel); udp_pair.DataReceived += Rtp_DataReceived; udp_pair.Start(); } } Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay(); play_message.RtspUri = new Uri(url); play_message.Session = session; rtsp_client.SendMessage(play_message); } // If we get a reply to PLAY (which was our fourth command), then we should have video being received if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestPlay) { // Got Reply to PLAY Console.WriteLine("Got reply from Play " + message.Command); } }
// RTP packet (or RTCP packet) has been received. public void Rtp_DataReceived(object sender, Rtsp.RtspChunkEventArgs e) { Rtsp.Messages.RtspData data_received = e.Message as Rtsp.Messages.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 (data_received.Channel == video_rtcp_channel) { Console.WriteLine("Received a RTCP message on channel " + data_received.Channel); return; } if (data_received.Channel == video_data_channel) { // Received some Video 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); rtp_payload_start += 4 + (int)rtp_extension_size; // extension header and extension payload } Console.WriteLine("RTP Data" + " V=" + rtp_version + " P=" + rtp_padding + " X=" + rtp_extension + " CC=" + rtp_csrc_count + " M=" + rtp_marker + " PT=" + rtp_payload_type + " Seq=" + rtp_sequence_number + " Time (MS)=" + rtp_timestamp / 90 // convert from 90kHZ clock to ms + " SSRC=" + rtp_ssrc + " Size=" + e.Message.Data.Length); String msg = "RTP Data " + rtp_count++ + " V=" + rtp_version + " P=" + rtp_padding + " X=" + rtp_extension + " CC=" + rtp_csrc_count + " M=" + rtp_marker + " PT=" + rtp_payload_type // + " Seq=" + rtp_sequence_number // + " Time=" + rtp_timestamp // + " SSRC=" + rtp_ssrc + " Size=" + e.Message.Data.Length; fs2.WriteLine(msg); fs2.Flush(); // Check the payload type in the RTP packet matches the Payload Type value from the SDP if (rtp_payload_type != video_payload) { Console.WriteLine("Ignoring this RTP payload"); return; // ignore this data } // If rtp_marker is '1' then this is the final transmission for this packet. // If rtp_marker is '0' we need to accumulate data with the same timestamp // ToDo - Check Timestamp // ToDo - Could avoid a copy if there is only one RTP frame for the data (temp list is zero) // Add the RTP packet to the tempoary_rtp list byte[] rtp_payload = new byte[e.Message.Data.Length - rtp_payload_start]; // payload with RTP header removed System.Array.Copy(e.Message.Data, rtp_payload_start, rtp_payload, 0, rtp_payload.Length); // copy payload temporary_rtp_payloads.Add(rtp_payload); if (rtp_marker == 1) { // End Marker is set. Process the RTP frame Process_RTP_Frame(temporary_rtp_payloads); temporary_rtp_payloads.Clear(); } } }
/// <summary> /// Raises the <see cref="E:DataReceived"/> event. /// </summary> /// <param name="rtspChunkEventArgs">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param> protected void OnDataReceived(Rtsp.RtspChunkEventArgs rtspChunkEventArgs) { EventHandler<Rtsp.RtspChunkEventArgs> handler = DataReceived; if (handler != null) handler(this, rtspChunkEventArgs); }
/// <summary> /// Constructs a RtspStream for use in a RtspServer /// </summary> /// <param name="name">The name given to the stream on the RtspServer</param> /// <param name="sourceLocation">The rtsp uri to the media</param> /// <param name="credential">The network credential the stream requires</param> /// /// <param name="authType">The AuthenticationSchemes the stream requires</param> public RtspSource(string name, Uri sourceLocation, NetworkCredential credential = null, AuthenticationSchemes authType = AuthenticationSchemes.None, Rtsp.RtspClient.ClientProtocolType? rtpProtocolType = null, int bufferSize = RtspClient.DefaultBufferSize, Sdp.MediaType? specificMedia = null, TimeSpan? startTime = null, TimeSpan? endTime = null, bool perPacket = false) : base(name, sourceLocation, perPacket) { //Create the listener if we are the top level stream (Parent) if (IsParent) { RtspClient = new RtspClient(m_Source, rtpProtocolType, bufferSize); } //else it is already assigned via the child if (credential != null) { RtspClient.Credential = SourceCredential = credential; if (authType != AuthenticationSchemes.None) RtspClient.AuthenticationScheme = SourceAuthenticationScheme = authType; } //If only certain media should be setup if (specificMedia.HasValue) SpecificMediaType = specificMedia; //If there was a start time given if (startTime.HasValue) MediaStartTime = startTime; if (endTime.HasValue) MediaEndTime = endTime; }