/// <summary> /// Handles the setup CMD. /// </summary> /// <param name="cseq">The cseq.</param> /// <param name="urlPreSuffix">The URL pre suffix.</param> /// <param name="urlSuffix">The URL suffix.</param> /// <param name="request">The request string.</param> private void HandleSetupCmd(string cseq, string urlPreSuffix, string urlSuffix, string request) { // Note: At present, I will use only one streaming mode of RTP_UDP // to transfer the data between server and client. // First, judges that the server media session exists or not. if (serverMediaSession == null) { serverMediaSession = rtspServer.LookupServerMediaSession(urlPreSuffix); if (serverMediaSession == null) { HandleNotFoundCmd(cseq); return; } } // Looks for a "Transport:" header in the request string, // to extract client parameters: int clientRtpPort; int clientRtcpPort; bool result = RtspCommon.ParseClientTransportHeader(request, out clientRtpPort, out clientRtcpPort); if (!result) { HandleUnsupportedTransportCmd(cseq); return; } // Then, gets the server parameters from the server media session: streamState = null; string destinationAddr = base.ClientSessionIP; string sourceAddr = Utils.GetLocalAddresses()[0]; int serverRtpPort = rtspServer.GenerateRtpPortNumber(); int serverRtcpPort = serverRtpPort + 1; result = serverMediaSession.GetStreamParameters(base.ClientSessionId, base.ClientSessionIP, clientRtpPort, clientRtcpPort, serverRtpPort, serverRtcpPort, ref streamState); if (!result) { HandleUnsupportedTransportCmd(cseq); return; } // Generates the response information now. StringBuilder sb = new StringBuilder(); sb.Append("RTSP/1.0 200 OK\r\n"); sb.AppendFormat("CSeq: {0}\r\n", cseq); sb.AppendFormat("Date: {0}\r\n", DateTime.Now.ToLocalTime()); sb.Append("Transport: RTP/AVP;unicast;"); sb.AppendFormat("destination={0};source={1};", destinationAddr, sourceAddr); sb.AppendFormat("client_port={0}-{1};", clientRtpPort, clientRtcpPort); sb.AppendFormat("server_port={0}-{1}\r\n", serverRtpPort, serverRtcpPort); sb.AppendFormat("Session: {0}\r\n\r\n", base.ClientSessionId); response = sb.ToString(); }
/// <summary> /// Sends the setup CMD. /// </summary> /// <returns>Succeeded or failed.</returns> private bool SendSetupCmd() { if (socket == null || !socket.Connected) { return(false); } bool result = false; clientRtpPort = Utils.GenerateRandomNumber(8000, 9000); clientRtcpPort = clientRtpPort + 1; sessionId = string.Empty; StringBuilder sb = new StringBuilder(); sb.AppendFormat("{0} ", Constants.RTSP_CMD_SETUP); // command name of 'SETUP' sb.AppendFormat("{0} RTSP/1.0\r\n", requestUrl); // request url sb.AppendFormat("CSeq: {0}\r\n", (++rtspSeqNum).ToString()); // sequence number sb.AppendFormat("Transport: client_port={0}-{1};\r\n", clientRtpPort.ToString(), clientRtcpPort.ToString()); // transport string sb.AppendFormat("Session: {0}\r\n", sessionId); // session id sb.AppendFormat("User-Agent: {0}\r\n\r\n", Constants.USER_AGENT_HEADER); // user agent header result = SendRtspRequest(sb.ToString()); if (!result) { return(false); } result = GetRtspResponse(); if (!result) { return(false); } result = RtspCommon.ParseServerTransportHeader(response, out clientAddress, out serverAddress, out serverRtpPort, out serverRtcpPort); if (!result) { return(false); } sessionId = RtspCommon.ParseSessionHeader(response); return(true); }
/// <summary> /// Handles the play CMD. /// </summary> /// <param name="cseq">The cseq.</param> /// <param name="rtspUrl">The rtsp url.</param> /// <param name="request">The request string.</param> private void HandlePlayCmd(string cseq, string rtspUrl, string request) { if (serverMediaSession == null || streamState == null) { return; } // Parses the client's "Scale:" header: string scaleHeader = string.Empty; float scale; bool hasScaleHeader = RtspCommon.ParseScaleHeader(request, out scale); if (hasScaleHeader) { scaleHeader = string.Format("Scale: {0}\r\n", scale); } // Parses the client's "Range:" header: string rangeHeader = string.Empty; double rangeStart = 0.0; double rangeEnd = 0.0; bool hasRangeHeader = RtspCommon.ParseRangeHeader(request, out rangeStart, out rangeEnd); double duration = this.serverMediaSession.GetDuration(); if (rangeEnd <= 0.0 || rangeEnd > duration) { rangeEnd = duration; } if (rangeStart < 0.0) { rangeStart = 0.0; } else if (rangeEnd > 0.0 && scale > 0.0 && rangeStart > rangeEnd) { rangeStart = rangeEnd; } if (hasRangeHeader) { if (rangeStart == 0.0 && scale >= 0.0) { rangeHeader = string.Format("Range: npt={0}-\r\n", rangeStart); } else { rangeHeader = string.Format("Range: npt={0}-{1}\r\n", rangeStart, rangeEnd); } } // Handles any require of scaling on session before starting streaming: if (hasScaleHeader) { // No implementation at present. } // Handles any require of seeking on session before starting streaming: if (hasRangeHeader) { serverMediaSession.SeekStream(streamState, rangeStart); } // Now, starts the stream: int rtpSeqNum = 0; int rtpTimestamp = 0; serverMediaSession.StartStream(streamState, ref rtpSeqNum, ref rtpTimestamp); string rtpInfo = string.Format("RTP-Info: url={0}/{1};seq={2};rtptime={3}\r\n", rtspUrl, serverMediaSession.TrackId, rtpSeqNum, rtpTimestamp); // Generates the response information now. StringBuilder sb = new StringBuilder(); sb.Append("RTSP/1.0 200 OK\r\n"); sb.AppendFormat("CSeq: {0}\r\n", cseq); sb.AppendFormat("Date: {0}\r\n", DateTime.Now.ToLocalTime()); sb.AppendFormat("{0}\r\n{1}\r\n", scaleHeader, rangeHeader); sb.AppendFormat("Session: {0}\r\n{1}\r\n", base.ClientSessionId, rtpInfo); response = sb.ToString(); }
/// <summary> /// Handles the incoming request. /// </summary> /// <param name="recvBuffer">The receive buffer.</param> /// <param name="recvBufferSize">Size of the receive buffer.</param> private void HandleIncomingRequest(byte[] recvBuffer, int recvBufferSize) { string cmdName; string rtspUrl; string urlPreSuffix; string urlSuffix; string cseq; string request = Utils.BytesToString(recvBuffer, recvBufferSize); Utils.OutputMessage(false, MsgLevel.Debug, string.Empty, request); // Parses the request string into command name and 'CSeq', then handle the command. bool isSucceeded = RtspCommon.ParseRequestString( request, out cmdName, out rtspUrl, out urlPreSuffix, out urlSuffix, out cseq); if (isSucceeded) { switch (cmdName) { case Constants.RTSP_CMD_OPTIONS: HandleOptionsCmd(cseq); break; case Constants.RTSP_CMD_DESCRIBE: HandleDescribeCmd(cseq, rtspUrl, urlSuffix, request); break; case Constants.RTSP_CMD_SETUP: HandleSetupCmd(cseq, urlPreSuffix, urlSuffix, request); break; case Constants.RTSP_CMD_PLAY: HandlePlayCmd(cseq, rtspUrl, request); break; case Constants.RTSP_CMD_PAUSE: HandlePauseCmd(cseq); break; case Constants.RTSP_CMD_TEARDOWN: HandleTearDownCmd(cseq); break; default: HandleNotSupportCmd(cseq); break; } SessionState = cmdName; this.OnClientSessionUpdated(this); } else { // Parses request string failed! HandleBadCmd(); } // After we handle the client request, we must send the response to the client. // ***** //Converts string to bytes. byte[] sendBuffer = Utils.StringToBytes(response); // Sends the rtsp response to the client. clientSocket.SendDatagram(sendBuffer, sendBuffer.Length); }