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

📄 rtspserver.cpp

📁 rtsp协议的主要实现代码.对开发流媒体
💻 CPP
📖 第 1 页 / 共 3 页
字号:
  if (streamingMode == RTP_TCP && rtpChannelId == 0xFF)
  {
    // TCP streaming was requested, but with no "interleaving=" fields.
    // (QuickTime Player sometimes does this.)  Set the RTP and RTCP channel ids to
    // proper values:
    //rtpChannelId = fTCPStreamIdCount; rtcpChannelId = fTCPStreamIdCount+1;
  }
  //fTCPStreamIdCount += 2;

  Port clientRTPPort(clientRTPPortNum);
  Port clientRTCPPort(clientRTCPPortNum);

  // Next, check whether a "Range:" header is present in the request.
  // This isn't legal, but some clients do this to combine "SETUP" and "PLAY":
  float rangeStart, rangeEnd;
  fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);

  // Then, get server parameters from the 'subsession':
  int tcpSocketNum = streamingMode == RTP_TCP ? fClientSocket : -1;
  netAddressBits destinationAddress = 0;
  u_int8_t destinationTTL = 255;
#ifdef RTSP_ALLOW_CLIENT_DESTINATION_SETTING
  if (clientsDestinationAddressStr != NULL) 
  {
    // Use the client-provided "destination" address.
    // Note: This potentially allows the server to be used in denial-of-service
    // attacks, so don't enable this code unless you're sure that clients are
    // trusted.
    destinationAddress = our_inet_addr(clientsDestinationAddressStr);
  }
  // Also use the client-provided TTL.
  destinationTTL = clientsDestinationTTL;
#endif
  delete[] clientsDestinationAddressStr;
  Boolean isMulticast;
  Port serverRTPPort(0);
  Port serverRTCPPort(0);
  subsession->getStreamParameters(fOurSessionId, fClientAddr.sin_addr.s_addr,
				  clientRTPPort, clientRTCPPort,
				  tcpSocketNum, rtpChannelId, rtcpChannelId,
				  destinationAddress, destinationTTL, isMulticast,
				  serverRTPPort, serverRTCPPort,
				  fStreamStates[streamNum].streamToken);
  struct in_addr destinationAddr; destinationAddr.s_addr = destinationAddress;
  
	switch (streamingMode) 
	{
	case RTP_UDP: 
		{
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
			   "RTSP/1.0 200 OK\r\n"
			   "CSeq: %s\r\n"
			   "%s"
			   "Transport: RTP/AVP;unicast;destination=%s;client_port=%d-%d;server_port=%d-%d\r\n"
			   "Session: %d\r\n\r\n",
			   cseq,
			   dateHeader(),
			   our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(clientRTCPPort.num()), ntohs(serverRTPPort.num()), ntohs(serverRTCPPort.num()),
			   fOurSessionId);
		  break;
		}
	case RTP_TCP: 
		{
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
			   "RTSP/1.0 200 OK\r\n"
			   "CSeq: %s\r\n"
			   "%s"
			   "Transport: RTP/AVP/TCP;unicast;destination=%s;interleaved=%d-%d\r\n"
			   "Session: %d\r\n\r\n",
			   cseq,
			   dateHeader(),
			   our_inet_ntoa(destinationAddr), rtpChannelId, rtcpChannelId,fOurSessionId);
		  break;
		}
	case RAW_UDP: 
		{
		  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
			   "RTSP/1.0 200 OK\r\n"
			   "CSeq: %s\r\n"
			   "%s"
			   "Transport: %s;unicast;destination=%s;client_port=%d;server_port=%d\r\n"
			   "Session: %d\r\n\r\n",
			   cseq,
			   dateHeader(),
			   streamingModeString, our_inet_ntoa(destinationAddr), ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),
			   fOurSessionId);
		  delete[] streamingModeString;
		  break;
		}
	}
}

void RTSPServer::RTSPClientSession
::handleCmd_withinSession(char const* cmdName,
						  char const* urlPreSuffix, char const* urlSuffix,
						  char const* cseq, char const* fullRequestStr) {
	// This will either be:
	// - a non-aggregated operation, if "urlPreSuffix" is the session (stream)
	//   name and "urlSuffix" is the subsession (track) name, or
	// - a aggregated operation, if "urlSuffix" is the session (stream) name,
	//   or "urlPreSuffix" is the session (stream) name, and "urlSuffix"
	//   is empty.
	// First, figure out which of these it is:
	if (fOurServerMediaSession == NULL) { // There wasn't a previous SETUP!
		handleCmd_notSupported(cseq);
		return;
	}
	ServerMediaSubsession* subsession = NULL;
	LSTServerMediaSubsession::iterator it;
	if (urlSuffix[0] != '\0' &&
		strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
		// Non-aggregated operation.
		// Look up the media subsession whose track id is "urlSuffix":
		for(it = fOurServerMediaSession->fServerMediaSubSession.begin();
			it != fOurServerMediaSession->fServerMediaSubSession.end(); it++)
			{
				subsession = (*it);
				if (strcmp(subsession->trackId(), urlSuffix) == 0) break; // success
			}
		if (subsession == NULL) { // no such track!
			handleCmd_notFound(cseq);
			return;
		}
	} else if (strcmp(fOurServerMediaSession->streamName(), urlSuffix) == 0 ||
		strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {
		// Aggregated operation
		subsession = NULL;
	} else { // the request doesn't match a known stream and/or track at all!
		handleCmd_notFound(cseq);
		return;
	}
	
	if (strcmp(cmdName, "TEARDOWN") == 0) {
		handleCmd_TEARDOWN(subsession, cseq);
	} else if (strcmp(cmdName, "PLAY") == 0) {
		handleCmd_PLAY(subsession, cseq, fullRequestStr);
	} else if (strcmp(cmdName, "PAUSE") == 0) {
		handleCmd_PAUSE(subsession, cseq);
	} else if (strcmp(cmdName, "GET_PARAMETER") == 0) {
		handleCmd_GET_PARAMETER(subsession, cseq, fullRequestStr);
	}
}

void RTSPServer::RTSPClientSession::handleCmd_bad(char const* /*cseq*/) {
	// Don't do anything with "cseq", because it might be nonsense
	snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
		"RTSP/1.0 400 Bad Request\r\n%sAllow: %s\r\n\r\n",
		dateHeader(), allowedCommandNames);
	fSessionIsActive = False; // triggers deletion of ourself after responding
}

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

void RTSPServer::RTSPClientSession
:: handleCmd_PLAY(ServerMediaSubsession* subsession,
					char const* cseq, char const* fullRequestStr)
{
  char* rtspURL = fOurServer.rtspURL(fOurServerMediaSession);
  unsigned rtspURLSize = strlen(rtspURL);

  //// Parse the client's "Scale:" header, if any: 
  float scale;
  Boolean sawScaleHeader = parseScaleHeader(fullRequestStr, scale);

  // Try to set the stream's scale factor to this value:
  if (subsession == NULL /*aggregate op*/) {
    scale = 1;
  } else {
    subsession->testScaleFactor(scale);
  }

  char buf[100];
  char* scaleHeader;
  if (!sawScaleHeader) {
    buf[0] = '\0'; // Because we didn't see a Scale: header, don't send one back
  } else {
    sprintf(buf, "Scale: %f\r\n", scale);
  }
  scaleHeader = strDup(buf);

  //// Parse the client's "Range:" header, if any: 
  float rangeStart, rangeEnd;
  Boolean sawRangeHeader = parseRangeHeader(fullRequestStr, rangeStart, rangeEnd);

  // Use this information, plus the stream's duration (if known), to create
  // our own "Range:" header, for the response:
  float duration = subsession == NULL /*aggregate op*/
    ? fOurServerMediaSession->duration() : subsession->duration();
  if (duration < 0.0) {
    // We're an aggregate PLAY, but the subsessions have different durations.
    // Use the largest of these durations in our header
    duration = -duration;
  }

  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;
  }

  char* rangeHeader;
  if (!sawRangeHeader) {
    buf[0] = '\0'; // Because we didn't see a Range: header, don't send one back
  } else if (rangeEnd == 0.0 && scale >= 0.0) {
    sprintf(buf, "Range: npt=%.3f-\r\n", rangeStart);
  } else {
    sprintf(buf, "Range: npt=%.3f-%.3f\r\n", rangeStart, rangeEnd);
  }
  rangeHeader = strDup(buf);

  // Create a "RTP-Info:" line.  It will get filled in from each subsession's state:
  char const* rtpInfoFmt =
    "%s" // "RTP-Info:", plus any preceding rtpInfo items
    "%s" // comma separator, if needed 
    "url=%s/%s"
    ";seq=%d"
#ifdef RTPINFO_INCLUDE_RTPTIME
    ";rtptime=%u"
#endif
    ;
  unsigned rtpInfoFmtSize = strlen(rtpInfoFmt);
  char* rtpInfo = strDup("RTP-Info: ");
  unsigned i, numRTPInfoItems = 0;

  // Do any required seeking/scaling on each subsession, before starting streaming:
  /*
  for (i = 0; i < fNumStreamStates; ++i) {
    if (subsession == NULL // means: aggregated operation 
	|| subsession == fStreamStates[i].subsession) {
      if (sawScaleHeader) {
	fStreamStates[i].subsession->setStreamScale(fOurSessionId,
						    fStreamStates[i].streamToken,
						    scale);
      }
      if (sawRangeHeader) {
	fStreamStates[i].subsession->seekStream(fOurSessionId,
						fStreamStates[i].streamToken,
						rangeStart);
      }
    }
  }*/

  // Now, start streaming:
  for (i = 0; i < fNumStreamStates; ++i) {
    if (subsession == NULL /* means: aggregated operation */
	|| subsession == fStreamStates[i].subsession) {
      unsigned short rtpSeqNum = 0;
      unsigned rtpTimestamp = 0;
      fStreamStates[i].subsession->startStream(fOurSessionId,
					       fStreamStates[i].streamToken,
					       rtpSeqNum, rtpTimestamp);
      const char *urlSuffix = fStreamStates[i].subsession->trackId();
      char* prevRTPInfo = rtpInfo;
      unsigned rtpInfoSize = rtpInfoFmtSize
	+ strlen(prevRTPInfo)
	+ 1
	+ rtspURLSize + strlen(urlSuffix)
	+ 5 /*max unsigned short len*/
#ifdef RTPINFO_INCLUDE_RTPTIME
	+ 10 /*max unsigned (32-bit) len*/
#endif
	+ 2 /*allows for trailing \r\n at final end of string*/; 
      rtpInfo = new char[rtpInfoSize];
      sprintf(rtpInfo, rtpInfoFmt,
	      prevRTPInfo,
	      numRTPInfoItems++ == 0 ? "" : ",",
	      rtspURL, urlSuffix,
	      rtpSeqNum
#ifdef RTPINFO_INCLUDE_RTPTIME
	      ,rtpTimestamp
#endif
	      );
      delete[] prevRTPInfo;
    }
  }
  if (numRTPInfoItems == 0) {
    rtpInfo[0] = '\0';
  } else {
    unsigned rtpInfoLen = strlen(rtpInfo);
    rtpInfo[rtpInfoLen] = '\r';
    rtpInfo[rtpInfoLen+1] = '\n';
    rtpInfo[rtpInfoLen+2] = '\0';
  }

  // Fill in the response:
  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,
	   "RTSP/1.0 200 OK\r\n"
	   "CSeq: %s\r\n"
	   "%s"
	   "%s"
	   "%s"
	   "Session: %d\r\n"
	   "%s\r\n",
	   cseq,
	   dateHeader(),
	   scaleHeader,
	   rangeHeader,
	   fOurSessionId,
	   rtpInfo);
  delete[] rtpInfo; delete[] rangeHeader;
  delete[] scaleHeader; delete[] rtspURL;
}

void RTSPServer::RTSPClientSession
:: handleCmd_PAUSE(ServerMediaSubsession* subsession,
					 char const* cseq)
{
}
void RTSPServer::RTSPClientSession
:: handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession,
				 char const* cseq, char const* fullRequestStr)
{
}

void RTSPServer::addServerMediaSession(ServerMediaSession* serverMediaSession) {
	if (serverMediaSession == NULL) return;
	
	char const* sessionName = serverMediaSession->streamName();
	if (sessionName == NULL) sessionName = "";
	fServerMediaSession.insert(pair<string,ServerMediaSession*>(string(sessionName),serverMediaSession));
}

ServerMediaSession* RTSPServer::lookupServerMediaSession(char const* streamName) 
{
	map<string,ServerMediaSession*>::iterator it;
	it = fServerMediaSession.find(string(streamName));
	if(it == fServerMediaSession.end())
		return NULL;
	return it->second;
}

void RTSPServer::RTSPClientSession::reclaimStreamStates() {
	for (unsigned i = 0; i < fNumStreamStates; ++i) {
		if (fStreamStates[i].subsession != NULL) {
			fStreamStates[i].subsession->deleteStream(fOurSessionId,
				fStreamStates[i].streamToken);
		}
	}
	delete[] fStreamStates; fStreamStates = NULL;
	fNumStreamStates = 0;
}

⌨️ 快捷键说明

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