Beispiel #1
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());

            // 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);
            }
        }
Beispiel #2
0
        byte[] video_sps = null; // SPS from SDP prop-parameter-set

        #endregion Fields

        #region Constructors

        // Constructor
        public RTSPClient(String url, RTP_TRANSPORT rtp_transport)
        {
            Rtsp.RtspUtils.RegisterUri();

            if (fs == null)
            {
                String filename = "rtsp_capture_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".264";
                fs = new FileStream(filename, FileMode.Create);

                String filename2 = "rtsp_capture_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".raw";
                fs2 = new StreamWriter(filename2);
            }

            Console.WriteLine("Connecting to " + url);
            this.url = url;

            // Use URI to extract hostname and port
            Uri uri = new Uri(url);

            // Connect to a RTSP Server. The RTSP session is a TCP connection
            try
            {
                rtsp_socket = new Rtsp.RtspTcpTransport(uri.Host, uri.Port);
            }
            catch
            {
                Console.WriteLine("Error - did not connect");
                return;
            }

            if (rtsp_socket.Connected == false)
            {
                Console.WriteLine("Error - did not connect");
                return;
            }

            // Connect a RTSP Listener to the RTSP Socket (or other Stream) to send RTSP messages and listen for RTSP replies
            rtsp_client = new Rtsp.RtspListener(rtsp_socket);

            rtsp_client.MessageReceived += Rtsp_MessageReceived;
            rtsp_client.DataReceived += Rtp_DataReceived;

            rtsp_client.Start(); // start listening for messages from the server (messages fire the MessageReceived event)

            // Check the RTP Transport
            // If the RTP transport is TCP then we interleave the RTP packets in the RTSP stream
            // If the RTP transport is UDP, we initialise two UDP sockets (one for video, one for RTCP status messages)
            // If the RTP transport is MULTICAST, we have to wait for the SETUP message to get the Multicast Address from the RTSP server
            this.rtp_transport = rtp_transport;
            if (rtp_transport == RTP_TRANSPORT.UDP)
            {
                udp_pair = new UDPSocket(50000, 50020); // give a range of 10 pairs (20 addresses) to try incase some address are in use
                udp_pair.DataReceived += Rtp_DataReceived;
                udp_pair.Start(); // start listening for data on the UDP ports
            }
            if (rtp_transport == RTP_TRANSPORT.TCP)
            {
                // Nothing to do. Data will arrive in the RTSP Listener
            }
            if (rtp_transport == RTP_TRANSPORT.MULTICAST)
            {
                // Nothing to do. Will open Multicast UDP sockets after the SETUP command
            }

            // Send OPTIONS
            // In the Received Message handler we will send DESCRIBE, SETUP and PLAY
            Rtsp.Messages.RtspRequest options_message = new Rtsp.Messages.RtspRequestOptions();
            options_message.RtspUri = new Uri(url);
            rtsp_client.SendMessage(options_message);
        }
Beispiel #3
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());

            // 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);
            }
        }
Beispiel #4
0
        // Constructor
        public RTSPClient(String url, RTP_TRANSPORT rtp_transport)
        {
            Rtsp.RtspUtils.RegisterUri();

            if (fs == null)
            {
                String filename = "rtsp_capture_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".264";
                fs = new FileStream(filename, FileMode.Create);

                String filename2 = "rtsp_capture_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".raw";
                fs2 = new StreamWriter(filename2);
            }


            Console.WriteLine("Connecting to " + url);
            this.url = url;

            // Use URI to extract hostname and port
            Uri uri = new Uri(url);

            // Connect to a RTSP Server. The RTSP session is a TCP connection
            try
            {
                rtsp_socket = new Rtsp.RtspTcpTransport(uri.Host, uri.Port);
            }
            catch
            {
                Console.WriteLine("Error - did not connect");
                return;
            }

            if (rtsp_socket.Connected == false)
            {
                Console.WriteLine("Error - did not connect");
                return;
            }

            // Connect a RTSP Listener to the RTSP Socket (or other Stream) to send RTSP messages and listen for RTSP replies
            rtsp_client = new Rtsp.RtspListener(rtsp_socket);

            rtsp_client.MessageReceived += Rtsp_MessageReceived;
            rtsp_client.DataReceived    += Rtp_DataReceived;

            rtsp_client.Start(); // start listening for messages from the server (messages fire the MessageReceived event)


            // Check the RTP Transport
            // If the RTP transport is TCP then we interleave the RTP packets in the RTSP stream
            // If the RTP transport is UDP, we initialise two UDP sockets (one for video, one for RTCP status messages)
            // If the RTP transport is MULTICAST, we have to wait for the SETUP message to get the Multicast Address from the RTSP server
            this.rtp_transport = rtp_transport;
            if (rtp_transport == RTP_TRANSPORT.UDP)
            {
                udp_pair = new UDPSocket(50000, 50020); // give a range of 10 pairs (20 addresses) to try incase some address are in use
                udp_pair.DataReceived += Rtp_DataReceived;
                udp_pair.Start();                       // start listening for data on the UDP ports
            }
            if (rtp_transport == RTP_TRANSPORT.TCP)
            {
                // Nothing to do. Data will arrive in the RTSP Listener
            }
            if (rtp_transport == RTP_TRANSPORT.MULTICAST)
            {
                // Nothing to do. Will open Multicast UDP sockets after the SETUP command
            }


            // Send OPTIONS
            // In the Received Message handler we will send DESCRIBE, SETUP and PLAY
            Rtsp.Messages.RtspRequest options_message = new Rtsp.Messages.RtspRequestOptions();
            options_message.RtspUri = new Uri(url);
            rtsp_client.SendMessage(options_message);
        }
Beispiel #5
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. If so we update the 'realm' and 'nonce'
            if (message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
            {
                String www_authenticate = message.Headers[RtspHeaderNames.WWWAuthenticate];

                // Parse www_authenticate
                // EG:   Digest realm="AXIS_WS_ACCC8E3A0A8F", nonce="000057c3Y810622bff50b36005eb5efeae118626a161bf", stale=FALSE
                string[] items = www_authenticate.Split(new char[] { ',', ' ' });
                foreach (string item in items)
                {
                    // Split on the = symbol and load in
                    string[] parts = item.Split(new char[] { '=' });
                    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
                    }
                }

                Console.WriteLine("WWW Authorize parsed for " + realm + " " + nonce);
            }


            // 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 will not have the authorization Nonce so we
                // 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 request did not use Authorizarion.

                        if (username == null || password == null)
                        {
                            // we do nothave a username or password. Abort
                            return;
                        }
                        // Send a new DESCRIBE with authorization
                        String digest_authorization = GenerateDigestAuthorization(username, password,
                                                                                  realm, nonce, url, "DESCRIBE");

                        Rtsp.Messages.RtspRequest describe_message = new Rtsp.Messages.RtspRequestDescribe();
                        describe_message.RtspUri = new Uri(url);
                        if (digest_authorization != null)
                        {
                            describe_message.Headers.Add(RtspHeaderNames.Authorization, digest_authorization);
                        }
                        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
                                };
                            }

                            // Add authorization (if there is a username and password)
                            String digest_authorization = GenerateDigestAuthorization(username, password,
                                                                                      realm, nonce, url, "SETUP");

                            // Send SETUP
                            Rtsp.Messages.RtspRequestSetup setup_message = new Rtsp.Messages.RtspRequestSetup();
                            setup_message.RtspUri = new Uri(control);
                            setup_message.AddTransport(transport);
                            if (digest_authorization != null)
                            {
                                setup_message.Headers.Add("Authorization", digest_authorization);
                            }
                            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;
                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);
            }
        }