/// <summary>
        /// Handles the request play.
        /// Do not forward message if already playing
        /// </summary>
        /// <param name="destination">The destination.</param>
        /// <param name="requestPlay">The request play.</param>
        /// <returns>The message to transmit</returns>
        private RtspMessage HandleRequestPlay(ref RtspListener destination, RtspRequestPlay requestPlay)
        {
            Contract.Requires(requestPlay != null);
            Contract.Requires(destination != null);
            Contract.Ensures(Contract.Result <RtspMessage>() != null);
            Contract.Ensures(Contract.ValueAtReturn(out destination) != null);


            string sessionKey = RtspSession.GetSessionName(requestPlay.RtspUri, requestPlay.Session);

            if (_activesSession.ContainsKey(sessionKey))
            {
                RtspSession session = _activesSession[sessionKey];

                // si on est dèjà en play on n'envoie pas la commande a la source.
                if (session.State == RtspSession.SessionState.Playing)
                {
                    session.Start(requestPlay.SourcePort.RemoteAdress);
                    RtspResponse returnValue = requestPlay.CreateResponse();
                    destination = requestPlay.SourcePort;
                    return(returnValue);
                }

                // ajoute un client
                session.Start(requestPlay.SourcePort.RemoteAdress);
            }
            return(requestPlay);
        }
Example #2
0
        private void RTSP_ProcessPlayRequest(RtspRequestPlay message, RtspListener listener)
        {
            OnPlay?.Invoke(Id);

            Play = true;  // ACTUALLY YOU COULD PAUSE JUST THE VIDEO (or JUST THE AUDIO)
            _logger.Info($"Connection {Id} play started");

            string range    = "npt=0-";                                                  // Playing the 'video' from 0 seconds until the end
            string rtp_info = "url=" + message.RtspUri + ";seq=" + _videoSequenceNumber; // TODO Add rtptime  +";rtptime="+session.rtp_initial_timestamp;

            // Send the reply
            Rtsp.Messages.RtspResponse play_response = message.CreateResponse(_logger);
            play_response.AddHeader("Range: " + range);
            play_response.AddHeader("RTP-Info: " + rtp_info);
            listener.SendMessage(play_response);



            //TODO: find a p[lace for this check]
            // Session ID was not found in the list of Sessions. Send a 454 error

            /*   Rtsp.Messages.RtspResponse play_failed_response = (e.Message as Rtsp.Messages.RtspRequestPlay).CreateResponse();
             * play_failed_response.ReturnCode = 454; // Session Not Found
             * listener.SendMessage(play_failed_response);*/
        }
Example #3
0
        private void ProcessSetupRequest(RtspResponse message)
        {
            // If we get a reply to SETUP (which was our third command), then process then send PLAY

            // Got Reply to SETUP
            Logger.Info("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 multicastAddress = transport.Destination;
                    videoDataChannel = transport.Port.First;
                    videoRTCPChannel = transport.Port.Second;

                    // Create the Pair of UDP Sockets in Multicast mode
                    udpPair = new UDPSocketPair(multicastAddress, videoDataChannel, multicastAddress, videoRTCPChannel);
                    udpPair.DataReceived += RtpDataReceived;
                    udpPair.Start();
                }
            }

            RtspRequest play_message = new RtspRequestPlay
            {
                RtspUri = new Uri(url),
                Session = session
            };

            rtspListener.SendMessage(play_message);
        }
Example #4
0
        public void Play()
        {
            RtspRequest playMessage = new RtspRequestPlay
            {
                RtspUri = new Uri(url),
                Session = session
            };

            rtspListener.SendMessage(playMessage);
        }
Example #5
0
        public void Play()
        {
            if (rtsp_client == null)
            {
                return;
            }

            // Send PLAY
            var play_message = new RtspRequestPlay {
                RtspUri = new Uri(Url),
                Session = RtspSession
            };

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

            rtsp_client.SendMessage(play_message);
        }
        /// <summary>
        /// Handles request message.
        /// </summary>
        /// <param name="message">A message, can be rewriten.</param>
        /// <returns>The destination</returns>
        private RtspListener HandleRequest(ref RtspMessage message)
        {
            Contract.Requires(message != null);
            Contract.Requires(message is RtspRequest);
            Contract.Ensures(Contract.Result <RtspListener>() != null);
            Contract.Ensures(Contract.ValueAtReturn(out message) != null);


            RtspRequest request = message as RtspRequest;

            RtspListener destination;

            // Do not forward, direct respond because we do not know where to send.
            if (request.RtspUri == null || request.RtspUri.AbsolutePath.Split(new char[] { '/' }, 3).Length < 3)
            {
                destination = HandleRequestWithoutUrl(ref message);
            }
            else
            {
                try
                {
                    // get the real destination
                    request.RtspUri = RewriteUri(request.RtspUri);
                    destination     = GetRtspListenerForDestination(request.RtspUri);

                    // Handle setup
                    RtspRequestSetup requestSetup = request as RtspRequestSetup;
                    if (requestSetup != null)
                    {
                        message = HandleRequestSetup(ref destination, requestSetup);
                    }

                    //Handle Play Reques
                    RtspRequestPlay requestPlay = request as RtspRequestPlay;
                    if (requestPlay != null)
                    {
                        message = HandleRequestPlay(ref destination, requestPlay);
                    }



                    //Update session state and handle special message
                    if (request.Session != null && request.RtspUri != null)
                    {
                        string sessionKey = RtspSession.GetSessionName(request.RtspUri, request.Session);
                        if (_activesSession.ContainsKey(sessionKey))
                        {
                            _activesSession[sessionKey].Handle(request);
                            switch (request.RequestTyped)
                            {
                            // start here to start early
                            //case RtspRequest.RequestType.PLAY:
                            // _activesSession[sessionKey].Start(request.SourcePort.RemoteAdress);
                            //   break;
                            case RtspRequest.RequestType.TEARDOWN:
                                _activesSession[sessionKey].Stop(request.SourcePort.RemoteAdress);
                                if (!_activesSession[sessionKey].IsNeeded)
                                {
                                    _activesSession.Remove(sessionKey);
                                }
                                else
                                {
                                    // system still need the server to send data do not send him the message.
                                    // reponds to client directly.
                                    destination = request.SourcePort;
                                    message     = request.CreateResponse();
                                }
                                break;
                            }
                        }
                        else
                        {
                            _logger.Warn("Command {0} for session {1} which was not found", request.RequestTyped, sessionKey);
                        }
                    }
                }
                catch (Exception error)
                {
                    _logger.Error("Error during handle of request", error);
                    destination = request.SourcePort;
                    RtspResponse theDirectResponse = request.CreateResponse();
                    theDirectResponse.ReturnCode = 500;
                    message = theDirectResponse;
                }
            }

            return(destination);
        }
Example #7
0
        internal RtspResponse HandlePullPlay(RtspRequestPlay request)
        {
            var response = request.CreateResponse();

            return(response);
        }
Example #8
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);
            }
        }
Example #9
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);
            }
        }