⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtspserver.cpp

📁 rtsp协议的主要实现代码.对开发流媒体
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		       unsigned resultURLSuffixMaxSize,
		       char* resultCSeq,
		       unsigned resultCSeqMaxSize) {
  // This parser is currently rather dumb; it should be made smarter #####

  // Read everything up to the first space as the command name:
  Boolean parseSucceeded = False;
  unsigned i;
  for (i = 0; i < resultCmdNameMaxSize-1 && i < reqStrSize; ++i) {
    char c = reqStr[i];
    if (c == ' ' || c == '\t') {
      parseSucceeded = True;
      break;
    }

    resultCmdName[i] = c;
  }
  resultCmdName[i] = '\0';
  if (!parseSucceeded) return False;
      
  // Skip over the prefix of any "rtsp://" or "rtsp:/" URL that follows:
  unsigned j = i+1;
  while (j < reqStrSize && (reqStr[j] == ' ' || reqStr[j] == '\t')) ++j; // skip over any additional white space
  for (j = i+1; j < reqStrSize-8; ++j) {
    if ((reqStr[j] == 'r' || reqStr[j] == 'R')
	&& (reqStr[j+1] == 't' || reqStr[j+1] == 'T')
	&& (reqStr[j+2] == 's' || reqStr[j+2] == 'S')
	&& (reqStr[j+3] == 'p' || reqStr[j+3] == 'P')
	&& reqStr[j+4] == ':' && reqStr[j+5] == '/') {
      j += 6;
      if (reqStr[j] == '/') {
	// This is a "rtsp://" URL; skip over the host:port part that follows:
	++j;
	while (j < reqStrSize && reqStr[j] != '/' && reqStr[j] != ' ') ++j;
      } else {
	// This is a "rtsp:/" URL; back up to the "/":
	--j;
      }
      i = j;
      break;
    }
  }

  // Look for the URL suffix (before the following "RTSP/"):
  parseSucceeded = False;
  for (unsigned k = i+1; k < reqStrSize-5; ++k) {
    if (reqStr[k] == 'R' && reqStr[k+1] == 'T' &&
	reqStr[k+2] == 'S' && reqStr[k+3] == 'P' && reqStr[k+4] == '/') {
      while (--k >= i && reqStr[k] == ' ') {} // go back over all spaces before "RTSP/"
      unsigned k1 = k;
      while (k1 > i && reqStr[k1] != '/' && reqStr[k1] != ' ') --k1;
      // the URL suffix comes from [k1+1,k]

      // Copy "resultURLSuffix":
      if (k - k1 + 1 > resultURLSuffixMaxSize) return False; // there's no room
      unsigned n = 0, k2 = k1+1;
      while (k2 <= k) resultURLSuffix[n++] = reqStr[k2++];
      resultURLSuffix[n] = '\0';

      // Also look for the URL 'pre-suffix' before this:
      unsigned k3 = --k1;
      while (k3 > i && reqStr[k3] != '/' && reqStr[k3] != ' ') --k3;
      // the URL pre-suffix comes from [k3+1,k1]

      // Copy "resultURLPreSuffix":
      if (k1 - k3 + 1 > resultURLPreSuffixMaxSize) return False; // there's no room
      n = 0; k2 = k3+1;
      while (k2 <= k1) resultURLPreSuffix[n++] = reqStr[k2++];
      resultURLPreSuffix[n] = '\0';

      i = k + 7; // to go past " RTSP/"
      parseSucceeded = True;
      break;
    }
  }
  if (!parseSucceeded) return False;

  // Look for "CSeq:", skip whitespace,
  // then read everything up to the next \r or \n as 'CSeq':
  parseSucceeded = False;
  for (j = i; j < reqStrSize-5; ++j) {
    if (reqStr[j] == 'C' && reqStr[j+1] == 'S' && reqStr[j+2] == 'e' &&
	reqStr[j+3] == 'q' && reqStr[j+4] == ':') {
      j += 5;
      unsigned n;
      while (j < reqStrSize && (reqStr[j] ==  ' ' || reqStr[j] == '\t')) ++j;
      for (n = 0; n < resultCSeqMaxSize-1 && j < reqStrSize; ++n,++j) {
	char c = reqStr[j];
	if (c == '\r' || c == '\n') {
	  parseSucceeded = True;
	  break;
	}

	resultCSeq[n] = c;
      }
      resultCSeq[n] = '\0';
      break;
    }
  }
  if (!parseSucceeded) return False;

  return True;
}

// Handler routines for specific RTSP commands:

// Generate a "Date:" header for use in a RTSP response:
static char const* dateHeader() {
	static char buf[200];
#if !defined(_WIN32_WCE)
	time_t tt = time(NULL);
	strftime(buf, sizeof buf, "Date: %a, %b %d %Y %H:%M:%S GMT\r\n", gmtime(&tt));
#else
	// WinCE apparently doesn't have "time()", "strftime()", or "gmtime()",
	// so generate the "Date:" header a different, WinCE-specific way.
	// (Thanks to Pierre l'Hussiez for this code)
	SYSTEMTIME SystemTime;
	GetSystemTime(&SystemTime);
	WCHAR dateFormat[] = L"ddd, MMM dd yyyy";
	WCHAR timeFormat[] = L"HH:mm:ss GMT\r\n";
	WCHAR inBuf[200];
	DWORD locale = LOCALE_NEUTRAL;
	
	int ret = GetDateFormat(locale, 0, &SystemTime,
		(LPTSTR)dateFormat, (LPTSTR)inBuf, sizeof inBuf);
	inBuf[ret - 1] = ' ';
	ret = GetTimeFormat(locale, 0, &SystemTime,
		      (LPTSTR)timeFormat,
			  (LPTSTR)inBuf + ret, (sizeof inBuf) - ret);
	wcstombs(buf, inBuf, wcslen(inBuf));
#endif
	return buf;
}

static char const* allowedCommandNames
= "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE";

void RTSPServer::RTSPClientSession::handleCmd_notSupported(char const* cseq) {
	snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
		"RTSP/1.0 405 Method Not Allowed\r\nCSeq: %s\r\n%sAllow: %s\r\n\r\n",
		cseq, dateHeader(), allowedCommandNames);
	fSessionIsActive = False; // triggers deletion of ourself after responding
}

void RTSPServer::RTSPClientSession::handleCmd_notFound(char const* cseq) {
	snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
		"RTSP/1.0 404 Stream Not Found\r\nCSeq: %s\r\n%s\r\n",
		cseq, dateHeader());
	fSessionIsActive = False; // triggers deletion of ourself after responding
}

void RTSPServer::RTSPClientSession::handleCmd_unsupportedTransport(char const* cseq) {
	snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
		"RTSP/1.0 461 Unsupported Transport\r\nCSeq: %s\r\n%s\r\n",
		cseq, dateHeader());
	fSessionIsActive = False; // triggers deletion of ourself after responding
}

void RTSPServer::RTSPClientSession
:: handleCmd_OPTIONS(char const* cseq)
{
	snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
		"RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sPublic: %s\r\n\r\n",
		cseq, dateHeader(), allowedCommandNames);
}
void RTSPServer::RTSPClientSession
:: handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,
						char const* fullRequestStr)
{
	char* sdpDescription = NULL;
	char* rtspURL = NULL;
	do {
		// We should really check that the request contains an "Accept:" #####
		// for "application/sdp", because that's what we're sending back #####
		
		// Begin by looking up the "ServerMediaSession" object for the
		// specified "urlSuffix":
		ServerMediaSession* session = fOurServer.lookupServerMediaSession(urlSuffix);
		if (session == NULL) {
			handleCmd_notFound(cseq);
			break;
		}
		
		// Then, assemble a SDP description for this session:
		sdpDescription = session->generateSDPDescription();
		if (sdpDescription == NULL) {
			// This usually means that a file name that was specified for a
			// "ServerMediaSubsession" does not exist.
			snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
				"RTSP/1.0 404 File Not Found, Or In Incorrect Format\r\n"
				"CSeq: %s\r\n"
				"%s\r\n",
				cseq,
				dateHeader());
			break;
		}
		unsigned sdpDescriptionSize = strlen(sdpDescription);
		
		// Also, generate our RTSP URL, for the "Content-Base:" header
		// (which is necessary to ensure that the correct URL gets used in
		// subsequent "SETUP" requests).
		rtspURL = fOurServer.rtspURL(session);
		
		snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
			"RTSP/1.0 200 OK\r\nCSeq: %s\r\n"
			"%s"
			"Content-Base: %s/\r\n"
			"Content-Type: application/sdp\r\n"
			"Content-Length: %d\r\n\r\n"
			"%s",
			cseq,
			dateHeader(),
			rtspURL,
			sdpDescriptionSize,
			sdpDescription);
	} while (0);
	
	delete[] sdpDescription;
	delete[] rtspURL;
}

char* RTSPServer
::rtspURL(ServerMediaSession const* serverMediaSession) const {
	struct in_addr ourAddress;
	if(ReceivingInterfaceAddr != 0)
		ourAddress.s_addr = ReceivingInterfaceAddr;
	else
		ourAddress = CUtility::GetLocalAddr();
	
	char const* sessionName = serverMediaSession->streamName();
	unsigned sessionNameLength = strlen(sessionName);
	
	char* urlBuffer = new char[100 + sessionNameLength];
	char* resultURL;
	
	portNumBits portNumHostOrder = ntohs(fServerPort.num());
	if (portNumHostOrder == 554 /* the default port number */) {
		sprintf(urlBuffer, "rtsp://%s/%s", our_inet_ntoa(ourAddress),
			sessionName);
	} else {
		sprintf(urlBuffer, "rtsp://%s:%hu/%s",
			our_inet_ntoa(ourAddress), portNumHostOrder,
			sessionName);
	}
	
	resultURL = strDup(urlBuffer);
	delete[] urlBuffer;
	return resultURL;
}

void RTSPServer::RTSPClientSession
:: handleCmd_SETUP(char const* cseq,
					 char const* urlPreSuffix, char const* urlSuffix,
					 char const* fullRequestStr)
{
 // "urlPreSuffix" should be the session (stream) name, and
  // "urlSuffix" should be the subsession (track) name.
  char const* streamName = urlPreSuffix;
  char const* trackId = urlSuffix;

  // Check whether we have existing session state, and, if so, whether it's
  // for the session that's named in "streamName".  (Note that we don't
  // support more than one concurrent session on the same client connection.) #####
  if (fOurServerMediaSession != NULL
      && strcmp(streamName, fOurServerMediaSession->streamName()) != 0) 
  {
    fOurServerMediaSession = NULL;
  }
  if (fOurServerMediaSession == NULL)
  {
    // Set up this session's state.

    // Look up the "ServerMediaSession" object for the specified stream:
    if (streamName[0] != '\0' ||
	fOurServer.lookupServerMediaSession("") != NULL) 
	{ // normal case
    } else 
	{ // weird case: there was no track id in the URL
      streamName = urlSuffix;
      trackId = NULL;
    }
    fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
    if (fOurServerMediaSession == NULL) 
	{
      handleCmd_notFound(cseq);
      return;
    }

    fOurServerMediaSession->incrementReferenceCount();

    // Set up our array of states for this session's subsessions (tracks):
    reclaimStreamStates();
	LSTServerMediaSubsession::iterator it;
	fNumStreamStates = fOurServerMediaSession->fServerMediaSubSession.size();
	fStreamStates = new struct streamState[fNumStreamStates];
	ServerMediaSubsession* subsession = NULL;
	unsigned i = 0;
	for(it = fOurServerMediaSession->fServerMediaSubSession.begin(); 
		it != fOurServerMediaSession->fServerMediaSubSession.end(); it++)
	{
		subsession = (*it);
		fStreamStates[i].subsession = subsession;
		fStreamStates[i].streamToken = NULL; // for now; reset by SETUP later
		i++;
	}
  }
   // Look up information for the specified subsession (track):
  ServerMediaSubsession* subsession = NULL;
  unsigned streamNum;
  if (trackId != NULL) 
  { // normal case
    for (streamNum = 0; streamNum < fNumStreamStates; ++streamNum) 
	{
      subsession = fStreamStates[streamNum].subsession;
      if (subsession != NULL && strcmp(trackId, subsession->trackId()) == 0) break;
    }
    if (streamNum >= fNumStreamStates) 
	{
      // The specified track id doesn't exist, so this request fails:
      handleCmd_notFound(cseq);
      return;
    }
  }
  else 
  {
    // Weird case: there was no track id in the URL.
    // This works only if we have only one subsession:
    if (fNumStreamStates != 1) 
	{
      handleCmd_bad(cseq);
      return;
    }
    streamNum = 0;
    subsession = fStreamStates[streamNum].subsession;
  }
  // ASSERT: subsession != NULL

  // Look for a "Transport:" header in the request string,
  // to extract client parameters:
  StreamingMode streamingMode;
  char* streamingModeString; // set when RAW_UDP streaming is specified
  char* clientsDestinationAddressStr;
  u_int8_t clientsDestinationTTL;
  portNumBits clientRTPPortNum, clientRTCPPortNum;
  unsigned char rtpChannelId, rtcpChannelId;
  parseTransportHeader(fullRequestStr, streamingMode, streamingModeString,
		       clientsDestinationAddressStr, clientsDestinationTTL,
		       clientRTPPortNum, clientRTCPPortNum,
		       rtpChannelId, rtcpChannelId);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -