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

📄 rtspserver.cpp.save

📁 流媒体传输协议的实现代码,非常有用.可以支持rtsp mms等流媒体传输协议
💻 SAVE
📖 第 1 页 / 共 3 页
字号:
	   cseq, dateHeader(), allowedCommandNames);}void RTSPServer::RTSPClientSession::handleCmd_DESCRIBE(char const* cseq, char const* urlSuffix,		     char const* fullRequestStr) {  char* sdpDescription = NULL;  char* rtspURL = NULL;  do {    if (!authenticationOK("DESCRIBE", cseq, fullRequestStr)) break;    // 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;}typedef enum StreamingMode {  RTP_UDP,  RTP_TCP,  RAW_UDP};static void parseTransportHeader(char const* buf,				 StreamingMode& streamingMode,				 char*& streamingModeString,				 char*& destinationAddressStr,				 u_int8_t& destinationTTL,				 portNumBits& clientRTPPortNum, // if UDP				 portNumBits& clientRTCPPortNum, // if UDP				 unsigned char& rtpChannelId, // if TCP				 unsigned char& rtcpChannelId // if TCP				 ) {  // Initialize the result parameters to default values:  streamingMode = RTP_UDP;  streamingModeString = NULL;  destinationAddressStr = NULL;  destinationTTL = 255;  clientRTPPortNum = 0;  clientRTCPPortNum = 1;   rtpChannelId = rtcpChannelId = 0xFF;  portNumBits p1, p2;  unsigned ttl, rtpCid, rtcpCid;  // First, find "Transport:"  while (1) {    if (*buf == '\0') return; // not found    if (_strncasecmp(buf, "Transport: ", 11) == 0) break;    ++buf;  }  // Then, run through each of the fields, looking for ones we handle:  char const* fields = buf + 11;  char* field = strDupSize(fields);  while (sscanf(fields, "%[^;]", field) == 1) {    if (strcmp(field, "RTP/AVP/TCP") == 0) {      streamingMode = RTP_TCP;    } else if (strcmp(field, "RAW/RAW/UDP") == 0 ||	       strcmp(field, "MP2T/H2221/UDP") == 0) {      streamingMode = RAW_UDP;      streamingModeString = strDup(field);    } else if (_strncasecmp(field, "destination=", 12) == 0) {      delete[] destinationAddressStr;      destinationAddressStr = strDup(field+12);    } else if (sscanf(field, "ttl%u", &ttl) == 1) {      destinationTTL = (u_int8_t)ttl;    } else if (sscanf(field, "client_port=%hu-%hu", &p1, &p2) == 2) {	clientRTPPortNum = p1;	clientRTCPPortNum = p2;    } else if (sscanf(field, "client_port=%hu", &p1) == 1) {	clientRTPPortNum = p1;	clientRTCPPortNum = streamingMode == RAW_UDP ? 0 : p1 + 1;    } else if (sscanf(field, "interleaved=%u-%u", &rtpCid, &rtcpCid) == 2) {      rtpChannelId = (unsigned char)rtpCid;      rtcpChannelId = (unsigned char)rtcpCid;    }    fields += strlen(field);    while (*fields == ';') ++fields; // skip over separating ';' chars    if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;  }  delete[] field;}static Boolean parseRangeHeader(char const* buf, float& rangeStart, float& rangeEnd) {  // Initialize the result parameters to default values:  rangeStart = rangeEnd = 0.0;  // First, find "Range:"  while (1) {    if (*buf == '\0') return False; // not found    if (_strncasecmp(buf, "Range: ", 7) == 0) break;    ++buf;  }  // Then, run through each of the fields, looking for ones we handle:  char const* fields = buf + 7;  while (*fields == ' ') ++fields;  float start, end;  if (sscanf(fields, "npt = %f - %f", &start, &end) == 2) {    rangeStart = start;    rangeEnd = end;  } else if (sscanf(fields, "npt = %f -", &start) == 1) {    rangeStart = start;  } else {    return False; // The header is malformed  }  return True;}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();    ServerMediaSubsessionIterator iter(*fOurServerMediaSession);    for (fNumStreamStates = 0; iter.next() != NULL; ++fNumStreamStates) {}    fStreamStates = new struct streamState[fNumStreamStates];    iter.reset();    ServerMediaSubsession* subsession;    for (unsigned i = 0; i < fNumStreamStates; ++i) {      subsession = iter.next();      fStreamStates[i].subsession = subsession;      fStreamStates[i].streamToken = NULL; // for now; reset by SETUP later    }  }  // 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);  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;  if (isMulticast) {    if (streamingMode == RTP_TCP) {      // multicast streams can't be sent via TCP      handleCmd_unsupportedTransport(cseq);      return;    }    snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	     "RTSP/1.0 200 OK\r\n"	     "CSeq: %s\r\n"	     "%s"	     "Transport: RTP/AVP;multicast;destination=%s;port=%d;ttl=%d\r\n"	     "Session: %d\r\n\r\n",	     cseq,	     dateHeader(),	     our_inet_ntoa(destinationAddr), ntohs(serverRTPPort.num()), destinationTTL,	     fOurSessionId);  } else {    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;  if (urlSuffix[0] != '\0' &&      strcmp(fOurServerMediaSession->streamName(), urlPreSuffix) == 0) {    // Non-aggregated operation.    // Look up the media subsession whose track id is "urlSuffix":    ServerMediaSubsessionIterator iter(*fOurServerMediaSession);    while ((subsession = iter.next()) != NULL) {      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_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}static Boolean parseScaleHeader(char const* buf, float& scale) {  // Initialize the result parameter to a default value:  scale = 1.0;  // First, find "Scale:"  while (1) {    if (*buf == '\0') return False; // not found    if (_strncasecmp(buf, "Scale: ", 7) == 0) break;    ++buf;  }  // Then, run through each of the fields, looking for ones we handle:  char const* fields = buf + 7;  while (*fields == ' ') ++fields;  float sc;  if (sscanf(fields, "%f", &sc) == 1) {    scale = sc;  } else {    return False; // The header is malformed  }  return True;}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);

⌨️ 快捷键说明

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