Ejemplo n.º 1
0
        private void ProcessDescribeResponse(RtspResponse message)
        {
            // Got a reply for DESCRIBE
            // Examine the SDP
            Logger.Info(System.Text.Encoding.UTF8.GetString(message.Data));

            Rtsp.Sdp.SdpFile sdpData;
            using (StreamReader sdpStream = new StreamReader(new MemoryStream(message.Data)))
            {
                sdpData = Rtsp.Sdp.SdpFile.Read(sdpStream);
            }

            // 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 < sdpData.Medias.Count; x++)
            {
                if (sdpData.Medias[x].MediaType == Media.MediaTypes.video)
                {
                    // We only want the first video sub-stream
                    if (videoPayloadType != -1)
                    {
                        return;
                    }

                    // search the attributes for control, fmtp and rtpmap
                    ParseAttributes(sdpData, x, out string control, out Rtsp.Sdp.AttributFmtp fmtp, out Rtsp.Sdp.AttributRtpMap rtpmap);

                    // 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);
                        OutputNal(param.SpropParameterSets); // output SPS and PPS
                    }

                    // Split the rtpmap to get the Payload Type
                    videoPayloadType = 0;
                    if (rtpmap != null)
                    {
                        videoPayloadType = rtpmap.PayloadNumber;
                    }

                    RtspRequestSetup setupMessage = new RtspRequestSetup();
                    setupMessage.RtspUri = new Uri(rtspUrl + "/" + control);

                    var transport = GetRTSPTransport();
                    setupMessage.AddTransport(transport);

                    PostRequest(setupMessage);
                }
            }
        }
Ejemplo n.º 2
0
        // RTSP Messages are OPTIONS, DESCRIBE, SETUP, PLAY etc
        void Rtsp_MessageReceived(object sender, RtspChunkEventArgs e)
        {
            var message = e.Message as RtspResponse;

            //logger.Debug ("Received " + message.OriginalRequest.Method);

            // If message has a 401 - Unauthorised Error, then we re-send the message with Authorization
            // using the most recently received 'realm' and 'nonce'
            if (!message.IsOk)
            {
                logger.Warn("Got Error in RTSP Reply " + message.ReturnCode + " " + message.ReturnMessage);

                if (message.ReturnCode == 401 && (message.OriginalRequest.Headers.ContainsKey(RtspHeaderNames.Authorization) == true))
                {
                    // the authorization failed.
                    Stop();
                    return;
                }

                // Check if the Reply has an Authenticate header.
                if (message.ReturnCode == 401 && message.Headers.ContainsKey(RtspHeaderNames.WWWAuthenticate))
                {
                    // Process the WWW-Authenticate header
                    // EG:   Basic realm="AProxy"
                    // EG:   Digest realm="AXIS_WS_ACCC8E3A0A8F", nonce="000057c3Y810622bff50b36005eb5efeae118626a161bf", stale=FALSE

                    string    www_authenticate = message.Headers [RtspHeaderNames.WWWAuthenticate];
                    string [] items            = www_authenticate.Split(new char [] { ',', ' ' });

                    foreach (string item in items)
                    {
                        if (item.ToLower().Equals("basic"))
                        {
                            auth_type = "Basic";
                        }
                        else if (item.ToLower().Equals("digest"))
                        {
                            auth_type = "Digest";
                        }
                        else
                        {
                            // Split on the = symbol and update the realm and nonce
                            string [] parts = item.Split(new char [] { '=' }, 2);                              // max 2 parts in the results array
                            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
                            }
                        }
                    }

                    //logger.Debug ("WWW Authorize parsed for " + auth_type + " " + realm + " " + nonce);
                }

                var resend_message = message.OriginalRequest.Clone() as RtspMessage;

                if (auth_type != null)
                {
                    AddAuthorization(resend_message, Username, Password, auth_type, realm, nonce, Url);
                }

                rtsp_client.SendMessage(resend_message);

                return;
            }

            // If we get a reply to OPTIONS then start the Keepalive Timer and send DESCRIBE
            if (message.OriginalRequest != null && message.OriginalRequest is RtspRequestOptions)
            {
                string public_methods = message.Headers [RtspHeaderNames.Public];

                SupportedMethods.Clear();

                foreach (string method in public_methods.Split(','))
                {
                    SupportedMethods.Add(method.Trim());
                }

                if (keepalive_timer == null)
                {
                    // 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 = 5 * 1000;
                    keepalive_timer.Enabled  = true;

                    // Send DESCRIBE
                    var describe_message = new RtspRequestDescribe();
                    describe_message.RtspUri = new Uri(Url);
                    describe_message.AddAccept("application/sdp");

                    if (auth_type != null)
                    {
                        AddAuthorization(describe_message, Username, Password, auth_type, realm, nonce, Url);
                    }

                    rtsp_client.SendMessage(describe_message);
                }
            }

            // 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 Mictlanix.DotNet.Rtsp.Messages.RtspRequestDescribe)
            {
                // Got a reply for DESCRIBE
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in DESCRIBE Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                // Examine the SDP
                //logger.Debug (Encoding.UTF8.GetString (message.Data));

                Sdp.SdpFile sdp_data;
                using (var sdp_stream = new StreamReader(new MemoryStream(message.Data))) {
                    sdp_data = Sdp.SdpFile.Read(sdp_stream);
                }

                // Process each 'Media' Attribute in the SDP (each sub-stream)
                for (int x = 0; x < sdp_data.Medias.Count; x++)
                {
                    bool video = (sdp_data.Medias [x].MediaType == Mictlanix.DotNet.Rtsp.Sdp.Media.MediaTypes.video);

                    if (video && video_payload != -1)
                    {
                        continue;                                                   // have already matched an video payload
                    }
                    if (video)
                    {
                        // search the attributes for control, rtpmap and fmtp
                        // (fmtp only applies to video)
                        string            control = "";               // the "track" or "stream id"
                        Sdp.FmtpAttribute fmtp    = null;             // holds SPS and PPS in base64 (h264 video)

                        foreach (var attrib in sdp_data.Medias[x].Attributs)
                        {
                            if (attrib.Key.Equals("control"))
                            {
                                string sdp_control = attrib.Value;
                                if (sdp_control.ToLower().StartsWith("rtsp://", StringComparison.Ordinal))
                                {
                                    control = sdp_control;                                     //absolute path
                                }
                                else if (message.Headers.ContainsKey(RtspHeaderNames.ContentBase))
                                {
                                    control = message.Headers [RtspHeaderNames.ContentBase] + sdp_control;                                     // relative path
                                }
                                else
                                {
                                    control = Url + "/" + sdp_control;                                     // relative path
                                }
                            }
                            if (attrib.Key.Equals("fmtp"))
                            {
                                fmtp = attrib as Sdp.FmtpAttribute;
                            }
                            if (attrib.Key.Equals("rtpmap"))
                            {
                                var rtpmap = attrib as Sdp.RtpMapAttribute;

                                // Check if the Codec Used (EncodingName) is one we support
                                string [] valid_video_codecs = { "H264" };

                                if (video && Array.IndexOf(valid_video_codecs, rtpmap.EncodingName) >= 0)
                                {
                                    // found a valid codec
                                    video_codec   = rtpmap.EncodingName;
                                    video_payload = sdp_data.Medias [x].PayloadType;
                                }
                            }
                        }

                        // If the rtpmap contains H264 then split the fmtp to get the sprop-parameter-sets which hold the SPS and PPS in base64
                        if (video && video_codec.Contains("H264") && fmtp != null)
                        {
                            var param   = 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];
                                ParameterSetsReceived?.Invoke(sps, pps);
                            }
                        }

                        // Send the SETUP RTSP command if we have a matching Payload Decoder
                        if (video && video_payload == -1)
                        {
                            continue;
                        }

                        // Server interleaves the RTP packets over the RTSP connection
                        // TCP mode (RTP over RTSP)   Transport: RTP/AVP/TCP;interleaved=0-1
                        video_data_channel = 0;
                        video_rtcp_channel = 1;

                        var transport = new RtspTransport()
                        {
                            LowerTransport = RtspTransport.LowerTransportType.TCP,
                            Interleaved    = new PortCouple(video_data_channel, video_rtcp_channel),                           // Eg Channel 0 for video. Channel 1 for RTCP status reports
                        };

                        // Send SETUP
                        var setup_message = new RtspRequestSetup();
                        setup_message.RtspUri = new Uri(control);
                        setup_message.AddTransport(transport);

                        if (auth_type != null)
                        {
                            AddAuthorization(setup_message, Username, Password, auth_type, realm, nonce, Url);
                        }

                        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 RtspRequestSetup)
            {
                // Got Reply to SETUP
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in SETUP Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                //logger.Debug ("Got reply from SETUP Session=" + message.Session);

                RtspSession = message.Session;                 // Session value used with Play, Pause, Teardown

                // Send PLAY
                RtspRequest play_message = new RtspRequestPlay();
                play_message.RtspUri = new Uri(Url);
                play_message.Session = RtspSession;

                if (auth_type != null)
                {
                    AddAuthorization(play_message, Username, Password, auth_type, realm, nonce, Url);
                }

                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 RtspRequestPlay)
            {
                // Got Reply to PLAY
                if (!message.IsOk)
                {
                    logger.Warn("Got Error in PLAY Reply " + message.ReturnCode + " " + message.ReturnMessage);
                    return;
                }

                //logger.Debug ("Got reply from PLAY " + message.Command);
            }
        }
Ejemplo n.º 3
0
        private void MessageReceived(object sender, RtspChunkEventArgs e)
        {
            RtspResponse message = e.Message as RtspResponse;

            // If we get a reply to OPTIONS then start the Keepalive Timer and send DESCRIBE
            if (message.OriginalRequest != null && message.OriginalRequest is RtspRequestOptions)
            {
                // Start a Timer to send an Keepalive RTSP command every 20 seconds
                _keepaliveTimer          = new Timer();
                _keepaliveTimer.Elapsed += SendKeepalive;
                _keepaliveTimer.Interval = 20 * 1000;
                _keepaliveTimer.Enabled  = true;

                // Send DESCRIBE
                RtspRequest describe_message = new RtspRequestDescribe();
                describe_message.RtspUri = new Uri(_url);
                _client.SendMessage(describe_message);
            }


            if (message.OriginalRequest != null && message.OriginalRequest is RtspRequestDescribe)
            {
                Rtsp.Sdp.SdpFile sdp_data;
                using (StreamReader sdp_stream = new StreamReader(new MemoryStream(message.Data)))
                {
                    sdp_data = Rtsp.Sdp.SdpFile.Read(sdp_stream);
                }

                Uri video_uri = null;
                foreach (Rtsp.Sdp.Attribut attrib in sdp_data.Medias[0].Attributs)
                {
                    if (attrib.Key.Equals("control"))
                    {
                        video_uri = new Uri(attrib.Value);
                    }
                }

                RtspTransport transport = new RtspTransport()
                {
                    LowerTransport = RtspTransport.LowerTransportType.TCP,
                    Interleaved    = new PortCouple(0, 1),
                };

                // Generate SETUP messages
                RtspRequestSetup setup_message = new RtspRequestSetup();
                setup_message.RtspUri = video_uri;
                setup_message.AddTransport(transport);

                _client.SendMessage(setup_message);
            }


            if (message.OriginalRequest != null && message.OriginalRequest is RtspRequestSetup)
            {
                if (message.Timeout > 0 && message.Timeout > _keepaliveTimer.Interval / 1000)
                {
                    _keepaliveTimer.Interval = message.Timeout * 1000 / 2;
                }

                // Send PLAY
                RtspRequest play_message = new RtspRequestPlay();
                play_message.RtspUri = new Uri(_url);
                play_message.Session = message.Session;
                _client.SendMessage(play_message);
            }
        }