Beispiel #1
0
        /// <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(RtspChunkEventArgs rtspChunkEventArgs)
        {
            EventHandler <RtspChunkEventArgs> handler = DataReceived;

            if (handler != null)
            {
                handler(this, rtspChunkEventArgs);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Raises the <see cref="E:MessageReceived"/> event.
        /// </summary>
        /// <param name="e">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
        protected void OnMessageReceived(RtspChunkEventArgs e)
        {
            EventHandler <RtspChunkEventArgs> handler = MessageReceived;

            if (handler != null)
            {
                handler(this, e);
            }
        }
Beispiel #3
0
        private void ProcessRTPVideo(Rtsp.RtspChunkEventArgs e)
        {
            // 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  rtpVersion        = (e.Message.Data[0] >> 6);
            int  rtpPadding        = (e.Message.Data[0] >> 5) & 0x01;
            int  rtpRxtension      = (e.Message.Data[0] >> 4) & 0x01;
            int  rtpCSRCCount      = (e.Message.Data[0] >> 0) & 0x0F;
            int  rtpMarker         = (e.Message.Data[1] >> 7) & 0x01;
            int  rtpPayloadType    = (e.Message.Data[1] >> 0) & 0x7F;
            uint rtpSequenceNumber = ((uint)e.Message.Data[2] << 8) + (uint)(e.Message.Data[3]);
            uint rtpTimestamp      = ((uint)e.Message.Data[4] << 24) + (uint)(e.Message.Data[5] << 16) + (uint)(e.Message.Data[6] << 8) + (uint)(e.Message.Data[7]);
            uint rtpSSRC           = ((uint)e.Message.Data[8] << 24) + (uint)(e.Message.Data[9] << 16) + (uint)(e.Message.Data[10] << 8) + (uint)(e.Message.Data[11]);

            int rtpPayloadStart = 4                     // V,P,M,SEQ
                                  + 4                   // time stamp
                                  + 4                   // ssrc
                                  + (4 * rtpCSRCCount); // zero or more csrcs

            if (rtpRxtension == 1)
            {
                uint rtpExtensionId   = ((uint)e.Message.Data[rtpPayloadStart + 0] << 8) + (uint)(e.Message.Data[rtpPayloadStart + 1] << 0);
                uint rtpExtensionSize = ((uint)e.Message.Data[rtpPayloadStart + 2] << 8) + (uint)(e.Message.Data[rtpPayloadStart + 3] << 0) * 4; // units of extension_size is 4-bytes
                rtpPayloadStart += 4 + (int)rtpExtensionSize;                                                                                    // extension header and extension payload
            }

            //Logger.Info("RTP Data"
            //                   + " V=" + rtpVersion
            //                   + " P=" + rtpPadding
            //                   + " X=" + rtpRxtension
            //                   + " CC=" + rtpCSRCCount
            //                   + " M=" + rtpMarker
            //                   + " PT=" + rtpPayloadType
            //                   + " Seq=" + rtpSequenceNumber
            //                   + " Time (MS)=" + rtpTimestamp / 90 // convert from 90kHZ clock to ms
            //                   + " SSRC=" + rtpSSRC
            //                   + " Size=" + e.Message.Data.Length);

            // Check the payload type in the RTP packet matches the Payload Type value from the SDP
            if (videoPayloadType > 0 && rtpPayloadType != videoPayloadType)
            {
                Logger.Info("Ignoring this RTP payload: " + rtpPayloadType);
                return; // ignore this data
            }

            byte[] rtp_payload = new byte[e.Message.Data.Length - rtpPayloadStart];          // payload with RTP header removed
            Array.Copy(e.Message.Data, rtpPayloadStart, rtp_payload, 0, rtp_payload.Length); // copy payload
            PushChunk(rtp_payload);
        }
        /// <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>
 /// 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);
 }
Beispiel #6
0
        /// <summary>
        /// Raises the <see cref="E:MessageReceived"/> event.
        /// </summary>
        /// <param name="e">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
        protected void OnMessageReceived(RtspChunkEventArgs e)
        {
            EventHandler<RtspChunkEventArgs> handler = MessageReceived;

            if (handler != null)
                handler(this, e);
        }
Beispiel #7
0
        /// <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(RtspChunkEventArgs rtspChunkEventArgs)
        {
            EventHandler<RtspChunkEventArgs> handler = DataReceived;

            if (handler != null)
                handler(this, rtspChunkEventArgs);
        }
Beispiel #8
0
        // 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());

            // Check if the Message has an Authenticate header and what type it is
            if (message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
            {
                String www_authenticate = message.Headers[RtspHeaderNames.WWWAuthenticate];

                // Parse www_authenticate
                // EG:   WWW-Authenticate: Basic realm="xxxxxxx"
                // EG:   WWW-Authenticate: Digest realm="AXIS_WS_ACCC8E3A0A8F", nonce="000057c3Y810622bff50b36005eb5efeae118626a161bf", stale=FALSE
                string[] items = www_authenticate.Split(new char[] { ',', ' ' });  // split on Comma and Space

                // Process the first item
                if (items.Count() >= 1 && items[0].Equals("Basic"))
                {
                    authentication = AUTHENTICATION.BASIC;
                }
                else if (items.Count() >= 1 && items[0].Equals("Digest"))
                {
                    authentication = AUTHENTICATION.DIGEST;
                }

                // Process the remaining items
                for (int i = 1; i < items.Count(); i++)
                {
                    string[] parts = items[i].Split(new char[] { '=' }); // Split on Equals
                    if (parts.Count() >= 2 && parts[0].Trim().Equals("realm"))
                    {
                        realm = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                    }
                    else if (parts.Count() >= 2 && parts[0].Trim().Equals("nonce"))
                    {
                        nonce = parts[1].Trim(new char[] { ' ', '\"' }); // trim space and quotes
                    }
                }
            }


            // 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. First time around we have no WWW-Authorise
                    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

                // First time we send DESCRIBE we do not add any authorization (and we could not add it even if we wanted to
                // as we will not have the authorization Nonce value required for Digest mode
                // So we have to handle the Unauthorized 401 error here and send a new DESCRIBE message

                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);

                    if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == false))
                    {
                        // Error 401 - Unauthorized, but the original request did not use Authorization so try again with Authorization added

                        if (username == null || password == null)
                        {
                            // we do nothave a username or password. Abort
                            return;
                        }
                        // Send a new DESCRIBE with authorization
                        Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                        describe_message.RtspUri = new Uri(url);
                        if (authentication != AUTHENTICATION.NONE)
                        {
                            String authorization_string = GenerateAuthorization(username, password, authentication,
                                                                                realm, nonce, url, "DESCRIBE");
                            if (authorization_string != null)
                            {
                                describe_message.Headers.Add("Authorization", authorization_string);
                            }
                        }
                        rtsp_client.SendMessage(describe_message);
                        return;
                    }
                    else if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == true))
                    {
                        // Authorization failed
                        return;
                    }
                    else
                    {
                        // some other error
                        return;
                    }
                }

                // 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].MediaType == Rtsp.Sdp.Media.MediaTypes.video)
                    {
                        // We only want the first video sub-stream
                        if (video_payload == -1)
                        {
                            video_payload = sdp_data.Medias[x].PayloadType;

                            // search the attributes for control, fmtp and rtpmap
                            String control = "";                   // the "track" or "stream id"
                            Rtsp.Sdp.AttributFmtp   fmtp   = null; // holds SPS and PPS in base64 (h264)
                            Rtsp.Sdp.AttributRtpMap rtpmap = null; // custom payload (>=96) details
                            foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[x].Attributs)
                            {
                                if (attrib.Key.Equals("control"))
                                {
                                    String sdp_control = attrib.Value;
                                    if (sdp_control.ToLower().StartsWith("rtsp://"))
                                    {
                                        control = sdp_control; //absolute path
                                    }
                                    else
                                    {
                                        control = url + "/" + sdp_control; // relative path
                                    }
                                }
                                if (attrib.Key.Equals("fmtp"))
                                {
                                    fmtp = attrib as Rtsp.Sdp.AttributFmtp;
                                }
                                if (attrib.Key.Equals("rtpmap"))
                                {
                                    rtpmap = attrib as Rtsp.Sdp.AttributRtpMap;
                                }
                            }

                            // If the rtpmap contains H264 then split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                            if (rtpmap != null && rtpmap.Value.Contains("H264") && fmtp != null)
                            {
                                video_codec = "H264";
                                var param   = Rtsp.Sdp.H264Parameters.Parse(fmtp.FormatParameter);
                                var sps_pps = param.SpropParameterSets;
                                if (sps_pps.Count() >= 2)
                                {
                                    byte[] sps = sps_pps[0];
                                    byte[] pps = sps_pps[1];
                                    Output_SPS_PPS(sps, pps); // output SPS and PPS
                                }
                            }

                            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
                                };
                            }

                            // Send SETUP
                            Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                            setup_message.RtspUri = new Uri(control);
                            setup_message.AddTransport(transport);
                            if (authentication != AUTHENTICATION.NONE)
                            {
                                String authorization_string = GenerateAuthorization(username, password, authentication,
                                                                                    realm, nonce, url, "SETUP");
                                if (authorization_string != null)
                                {
                                    setup_message.Headers.Add("Authorization", authorization_string);
                                }
                            }
                            rtsp_client.SendMessage(setup_message);
                        }
                    }
                }
            }


            // If we get a reply to SETUP (which was our third command), then process and then send PLAY
            if (message.OriginalRequest != null && message.OriginalRequest is Rtsp.Messages.RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                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();
                    }
                }

                // Send PLAY
                Rtsp.Messages.RtspRequest play_message = new Rtsp.Messages.RtspRequestPlay();
                play_message.RtspUri = new Uri(url);
                play_message.Session = session;
                if (authentication != AUTHENTICATION.NONE)
                {
                    String authorization_string = GenerateAuthorization(username, password, authentication,
                                                                        realm, nonce, url, "PLAY");
                    if (authorization_string != null)
                    {
                        play_message.Headers.Add("Authorization", authorization_string);
                    }
                }

                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
                if (message.IsOk == false)
                {
                    Console.WriteLine("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                Console.WriteLine("Got reply from Play  " + message.Command);
            }
        }
Beispiel #9
0
        int rtp_count = 0; // used for statistics
        // RTP packet (or RTCP packet) has been received.
        private 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) * 4; // units of extension_size is 4-bytes
                    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;
                if (fs2 != null)
                {
                    fs2.WriteLine(msg);
                }
                if (fs2 != null)
                {
                    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_payload_type >= 96 && rtp_payload_type <= 127 && video_codec.Equals("H264"))
                {
                    // H264 RTP Packet

                    // 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
                    // Add the RTP packet to the tempoary_rtp list until we have a complete 'Frame'

                    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

                    List <byte[]> nal_units = h264Payload.Process_H264_RTP_Packet(rtp_payload, rtp_marker);   // this will cache the Packets until there is a Frame

                    if (nal_units == null)
                    {
                        // we have not passed in enough RTP packets to make a Frame of video
                    }
                    else
                    {
                        // we have a frame of NAL Units. Write them to the file
                        Output_NAL(nal_units);
                    }
                }

                else if (rtp_payload_type == 26)
                {
                    Console.WriteLine("No parser for JPEG RTP packets");
                }
                else
                {
                    Console.WriteLine("No parser for this RTP payload");
                }
            }
        }
Beispiel #10
0
    // Process each RTSP message that is received
    private void RTSP_Message_Received(object sender, RtspChunkEventArgs e)
    {
        // Cast the 'sender' and 'e' into the RTSP Listener (the Socket) and the RTSP Message
            Rtsp.RtspListener listener = sender as Rtsp.RtspListener;
            Rtsp.Messages.RtspMessage message = e.Message as Rtsp.Messages.RtspMessage;

            Console.WriteLine("RTSP message received " + message);

            // Handle OPTIONS message
            if (message is Rtsp.Messages.RtspRequestOptions)
            {
                // Create the reponse to OPTIONS
                Rtsp.Messages.RtspResponse options_response = (e.Message as Rtsp.Messages.RtspRequestOptions).CreateResponse();
                listener.SendMessage(options_response);
            }

            // Handle DESCRIBE message
            if (message is Rtsp.Messages.RtspRequestDescribe)
            {
                String requested_url = (message as Rtsp.Messages.RtspRequestDescribe).RtspUri.ToString();
                Console.WriteLine("Request for " + requested_url);

                // TODO. Check the requsted_url is valid. In this example we accept any RTSP URL

                // Make the Base64 SPS and PPS
                byte[] raw_sps = h264_encoder.GetRawSPS(); // no 0x00 0x00 0x00 0x01 or 32 bit size header
                byte[] raw_pps = h264_encoder.GetRawPPS(); // no 0x00 0x00 0x00 0x01 or 32 bit size header
                String sps_str = Convert.ToBase64String(raw_sps);
                String pps_str = Convert.ToBase64String(raw_pps);

                StringBuilder sdp = new StringBuilder();

                // Generate the SDP
                // The sprop-parameter-sets provide the SPS and PPS for H264 video
                // The packetization-mode defines the H264 over RTP payloads used but is Optional
                sdp.Append("v=0\n");
                sdp.Append("o=user 123 0 IN IP4 0.0.0.0\n");
                sdp.Append("s=SharpRTSP Test Camera\n");
                sdp.Append("m=video 0 RTP/AVP 96\n");
                sdp.Append("c=IN IP4 0.0.0.0\n");
                sdp.Append("a=control:trackID=0\n");
                sdp.Append("a=rtpmap:96 H264/90000\n");
                sdp.Append("a=fmtp:96 profile-level-id=42A01E; sprop-parameter-sets="+sps_str+","+pps_str+";\n");

                byte[] sdp_bytes = Encoding.ASCII.GetBytes(sdp.ToString());

                // Create the reponse to DESCRIBE
                // This must include the Session Description Protocol (SDP)
                Rtsp.Messages.RtspResponse describe_response = (e.Message as Rtsp.Messages.RtspRequestDescribe).CreateResponse();

                describe_response.AddHeader("Content-Base: " + requested_url);
                describe_response.AddHeader("Content-Type: application/sdp");
                describe_response.Data = sdp_bytes;
                describe_response.AdjustContentLength();
                listener.SendMessage(describe_response);
            }

            // Handle SETUP message
            if (message is Rtsp.Messages.RtspRequestSetup)
            {

                //
                var setupMessage = message as Rtsp.Messages.RtspRequestSetup;

                // Check the RTSP transport
                // If it is UDP or Multicast, create the sockets
                // If it is RTP over RTSP we send data via the RTSP Listener

                // FIXME client may send more than one possible transport.
                // very rare
                Rtsp.Messages.RtspTransport transport = setupMessage.GetTransports()[0];

                // Create a 'Session' and add it to the Session List
                // ToDo - Check the Track ID. In the SDP the H264 video track is TrackID 0
                RTPSession new_session = new RTPSession();
                new_session.session_id = session_count.ToString();
                new_session.listener = listener;
                new_session.sequence_number = (UInt16)rnd.Next(65535); // start with a random 16 bit sequence number
                new_session.ssrc = 1;

                // Construct the Transport: reply from the Server to the client
                Rtsp.Messages.RtspTransport transport_reply = new Rtsp.Messages.RtspTransport();

                if (transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.TCP) {
                    // RTP over RTSP mode}
                    transport_reply.LowerTransport = Rtsp.Messages.RtspTransport.LowerTransportType.TCP;
                    transport_reply.Interleaved = new Rtsp.Messages.PortCouple(transport.Interleaved.First,transport.Interleaved.Second);
                }

                if (transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.UDP
                    && transport.IsMulticast == false) {
                    // RTP over UDP mode}
                    // Create a pair of UDP sockets
                    // Pass the Port of the two sockets back in the reply
                    transport_reply.LowerTransport = Rtsp.Messages.RtspTransport.LowerTransportType.UDP;
                    transport_reply.IsMulticast = false;
                    transport_reply.ClientPort = transport.ClientPort;  // FIX
                    // for now until implemented
                    transport_reply = null;
                }

                if (transport.LowerTransport == Rtsp.Messages.RtspTransport.LowerTransportType.UDP
                    && transport.IsMulticast == true) {
                    // RTP over Multicast UDP mode}
                    // Create a pair of UDP sockets in Multicast Mode
                    // Pass the Ports of the two sockets back in the reply
                    transport_reply.LowerTransport = Rtsp.Messages.RtspTransport.LowerTransportType.UDP;
                    transport_reply.IsMulticast = true;
                    transport_reply.Port = new Rtsp.Messages.PortCouple(7000,7001);  // FIX

                    // for now until implemented
                    transport_reply = null;
                }

                if (transport_reply != null)
                {
                    // Add the transports to the Session
                    new_session.client_transport = transport;
                    new_session.transport_reply = transport_reply;

                    // Add the new session to the Sessions List
                    rtp_list.Add(new_session);
                    session_count++;

                    Rtsp.Messages.RtspResponse setup_response = setupMessage.CreateResponse();
                    setup_response.Headers[Rtsp.Messages.RtspHeaderNames.Transport] = transport_reply.ToString();
                    setup_response.Session = new_session.session_id;
                    listener.SendMessage(setup_response);
                }
                else
                {
                    Rtsp.Messages.RtspResponse setup_response = setupMessage.CreateResponse();
                    // unsuported transport
                    setup_response.ReturnCode =461;
                    listener.SendMessage(setup_response);
                }

            }

            // Handle PLAY message
            if (message is Rtsp.Messages.RtspRequestPlay)
            {
                lock (rtp_list)
                {
                    // Search for the Session in the Sessions List. Change the state of "PLAY"
                    foreach (RTPSession session in rtp_list)
                    {
                        if (session.session_id.Equals(message.Session)) {
                            // found the session
                            session.play = true;
                            break;
                        }
                    }
                }

                // ToDo - only send back the OK response if the Session in the RTSP message was found
                Rtsp.Messages.RtspResponse play_response = (e.Message as Rtsp.Messages.RtspRequestPlay).CreateResponse();
                listener.SendMessage(play_response);
            }

            // Handle PLAUSE message
            if (message is Rtsp.Messages.RtspRequestPause)
            {
                lock (rtp_list)
                {
                    // Search for the Session in the Sessions List. Change the state of "PLAY"
                    foreach (RTPSession session in rtp_list)
                    {
                        if (session.session_id.Equals(message.Session))
                        {
                            // found the session
                            session.play = false;
                            break;
                        }
                    }
                }

                // ToDo - only send back the OK response if the Session in the RTSP message was found
                Rtsp.Messages.RtspResponse pause_response = (e.Message as Rtsp.Messages.RtspRequestPause).CreateResponse();
                listener.SendMessage(pause_response);
            }

            // Handle GET_PARAMETER message, often used as a Keep Alive
            if (message is Rtsp.Messages.RtspRequestGetParameter)
            {
                // Create the reponse to GET_PARAMETER
                Rtsp.Messages.RtspResponse getparameter_response = (e.Message as Rtsp.Messages.RtspRequestGetParameter).CreateResponse();
                listener.SendMessage(getparameter_response);
            }
    }
Beispiel #11
0
 /// <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(RtspChunkEventArgs rtspChunkEventArgs)
 {
     DataReceived?.Invoke(this, rtspChunkEventArgs);
 }
Beispiel #12
0
 /// <summary>
 /// Raises the <see cref="E:MessageReceived"/> event.
 /// </summary>
 /// <param name="e">The <see cref="Rtsp.RtspChunkEventArgs"/> instance containing the event data.</param>
 protected void OnMessageReceived(RtspChunkEventArgs e)
 {
     MessageReceived?.Invoke(this, e);
 }