/// <summary>
        /// Ends the client session
        /// </summary>
        /// <param name="request">The Teardown request</param>
        /// <param name="session">The session which recieved the request</param>
        internal void ProcessRtspTeardown(RtspMessage request, ClientSession session, bool sendResponse = true)
        {
            //If there was a location which was not a wildcard attempt to honor it.
            if (request.Location != RtspMessage.Wildcard)
            {

                RtpSource found = FindStreamByLocation(request.Location) as RtpSource;

                if (found == null)
                {
                    ProcessLocationNotFoundRtspRequest(session, sendResponse);
                    return;
                }

                if (false == AuthenticateRequest(request, found))
                {
                    ProcessAuthorizationRequired(found, session, sendResponse);
                    return;
                }

                //Send the response
                var resp = session.ProcessTeardown(request, found);

                ////Keep track if LeaveOpen should be set (based on if the session still shared the socket)
                //if (false == (session.LeaveOpen = session.SharesSocket))
                //{
                //    //if it doesn't then inform that close may occur?
                //    resp.AppendOrSetHeader(RtspHeaders.Connection, "close");
                //}

                ProcessSendRtspMessage(resp, session, sendResponse);

                session.ReleaseUnusedResources();

                resp = null;
                //Attempt to remove the sessionId when nothing is playing... why?
                //10.4 SETUP says we would have to bundle pipelined requests.
                //That is contradictory.

                //if (session.Playing.Count == 0) session.SessionId = null;

                string connectionHeader = request[RtspHeaders.Connection];

                if (false == string.IsNullOrWhiteSpace(connectionHeader))
                {
                    if (string.Compare(connectionHeader.Trim(), "close", true) == 0)
                    {
                        TryDisposeAndRemoveSession(session);
                    }
                }
            }
            else
            {
                //Create the response
                var resp = session.CreateRtspResponse(request);

                //Todo
                //Make a RtpInfo header for each stream ending...

                //Stop transport level activity if required
                if (session.m_RtpClient != null &&
                    session.m_RtpClient.IsActive) session.m_RtpClient.SendGoodbyes();

                //Remove all attachments and clear playing
                session.RemoveAllAttachmentsAndClearPlaying();

                //Send the response
                ProcessSendRtspMessage(resp, session, sendResponse);

                //Release any unused resources at this point
                session.ReleaseUnusedResources();

                //Remove the sessionId
                session.SessionId = null;

                resp = null;

                string connectionHeader = request[RtspHeaders.Connection];

                if (false == string.IsNullOrWhiteSpace(connectionHeader))
                {
                    if (string.Compare(connectionHeader.Trim(), "close", true) == 0)
                    {
                        TryDisposeAndRemoveSession(session);
                    }
                }
            }
        }
 /// <summary>
 /// Handles the SET_PARAMETER RtspRequest
 /// </summary>
 /// <param name="request">The GET_PARAMETER RtspRequest to handle</param>
 /// <param name="ci">The RtspSession from which the request was receieved</param>
 internal void ProcessSetParameter(RtspMessage request, ClientSession session, bool sendResponse = true)
 {
     //Could be used for PTZ or other stuff
     //Should have a way to determine to forward send parameters... public bool ForwardSetParameter { get; set; }
     //Should have a way to call SendSetParamter on the source if required.
     //Should allow sever parameters to be set?
     using (var resp = session.CreateRtspResponse(request))
     {
         //Content type
         ProcessSendRtspMessage(resp, session, sendResponse);
     }
 }
        /// <summary>
        /// Provides the Options this server supports
        /// </summary>
        /// <param name="request"></param>
        /// <param name="session"></param>
        internal void ProcessRtspOptions(RtspMessage request, ClientSession session, bool sendResponse = true)
        {
            //See if the location requires a certain stream
            if (request.Location != RtspMessage.Wildcard && false == string.IsNullOrWhiteSpace(request.Location.LocalPath) && request.Location.LocalPath.Length > 1)
            {
                IMedia found = FindStreamByLocation(request.Location);

                //No stream with name
                if (found == null)
                {
                    ProcessLocationNotFoundRtspRequest(session, sendResponse);
                    return;
                }

                //See if RECORD is supported?

            }

            //Check for additional options of the stream... e.g. allow recording or not

            RtspMessage resp = session.CreateRtspResponse(request);

            resp.SetHeader(RtspHeaders.Public, "OPTIONS, DESCRIBE, SETUP, PLAY, PAUSE, TEARDOWN, GET_PARAMETER");

            //Allow for Authorized
            resp.SetHeader(RtspHeaders.Allow, "ANNOUNCE, RECORD, SET_PARAMETER");

            //Add from handlers?
            //if(m_RequestHandlers.Count > 0) string.Join(" ", m_RequestHandlers.Keys.ToArray())

            //Should allow server to have certain options removed from this result
            //ClientSession.ProcessOptions

            ProcessSendRtspMessage(resp, session, sendResponse);

            resp = null;
        }
        /// <summary>
        /// Decribes the requested stream
        /// </summary>
        /// <param name="request"></param>
        /// <param name="session"></param>
        internal void ProcessRtspDescribe(RtspMessage request, ClientSession session, bool sendResponse = true)
        {
            if (request.Location == RtspMessage.Wildcard)
            {
                var resp = session.CreateRtspResponse(request);

                ProcessSendRtspMessage(resp, session, sendResponse);

                resp = null;
            }
            else
            {
                string acceptHeader = request[RtspHeaders.Accept];

                //If an Accept header was given it must reflect a content-type of SDP.
                if (false == string.IsNullOrWhiteSpace(acceptHeader)
                    &&
                    string.Compare(acceptHeader, Sdp.SessionDescription.MimeType, true, System.Globalization.CultureInfo.InvariantCulture) > 0)
                {
                    ProcessInvalidRtspRequest(session);
                    return;
                }

                RtpSource found = FindStreamByLocation(request.Location) as RtpSource;

                if (found == null)
                {
                    ProcessLocationNotFoundRtspRequest(session, sendResponse);
                    return;
                }

                if (false == AuthenticateRequest(request, found))
                {
                    ProcessAuthorizationRequired(found, session, sendResponse);
                    return;
                }

                if (false == found.Ready)
                {
                    ProcessInvalidRtspRequest(session, RtspStatusCode.PreconditionFailed, null, sendResponse);
                    return;
                }

                var resp = session.ProcessDescribe(request, found);

                ProcessSendRtspMessage(resp, session, sendResponse);

                resp = null;

            }
        }
        internal void ProcessRedirect(RtspMessage request, ClientSession session, bool sendResponse = true)
        {
            var found = FindStreamByLocation(request.Location);

            if (found == null)
            {
                ProcessLocationNotFoundRtspRequest(session, sendResponse);
                return;
            }

            if (false == AuthenticateRequest(request, found))
            {
                ProcessAuthorizationRequired(found, session, sendResponse);
                return;
            }

            if (false == found.Ready)
            {
                ProcessInvalidRtspRequest(session, RtspStatusCode.PreconditionFailed, null, sendResponse);
                return;
            }

            using (var resp = session.CreateRtspResponse(request))
            {
                resp.Method = RtspMethod.REDIRECT;
                resp.AppendOrSetHeader(RtspHeaders.Location, "rtsp://" + session.LocalEndPoint.Address.ToString() + "/live/" + found.Id);
                ProcessSendRtspMessage(resp, session, sendResponse);
            }
        }
 /// <summary>
 /// Sends a Rtsp Response on the given client session
 /// </summary>
 /// <param name="ci">The client session to send the response on</param>
 /// <param name="code">The status code of the response if other than BadRequest</param>
 //Should allow a header to be put into the response or a KeyValuePair<string,string> headers
 internal void ProcessInvalidRtspRequest(ClientSession session, RtspStatusCode code = RtspStatusCode.BadRequest, string body = null, bool sendResponse = true)
 {
     //Create and Send the response
     ProcessInvalidRtspRequest(session != null ? session.CreateRtspResponse(null, code, body) : new RtspMessage(RtspMessageType.Response) { StatusCode = code, Body = body, CSeq = Utility.Random.Next() }, session);
 }
        /// <summary>
        /// Handles the GET_PARAMETER RtspRequest
        /// </summary>
        /// <param name="request">The GET_PARAMETER RtspRequest to handle</param>
        /// <param name="ci">The RtspSession from which the request was receieved</param>
        internal void ProcessGetParameter(RtspMessage request, ClientSession session, bool sendResponse = true)
        {
            //TODO Determine API
            //packets_sent
            //jitter
            //rtcp_interval

            var resp = session.CreateRtspResponse(request);

            resp.SetHeader(RtspHeaders.Connection, "Keep-Alive");

            ProcessSendRtspMessage(resp, session, sendResponse);

            resp = null;
        }