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

📄 rtspserver.cpp

📁 c++实现的流媒体库,和mplayer结合就可以实现多媒体的网络播放,属于开源项目,很值得研究.
💻 CPP
📖 第 1 页 / 共 3 页
字号:
    // 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, fClientSocket);  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*/) {    fOurServerMediaSession->testScaleFactor(scale);  } 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 = 0.0, rangeEnd = 0.0;  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,					       (TaskFunc*)noteClientLiveness,					       this,					       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) {  for (unsigned i = 0; i < fNumStreamStates; ++i) {    if (subsession == NULL /* means: aggregated operation */	|| subsession == fStreamStates[i].subsession) {      fStreamStates[i].subsession->pauseStream(fOurSessionId,					       fStreamStates[i].streamToken);    }  }  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",	   cseq, dateHeader(), fOurSessionId);}void RTSPServer::RTSPClientSession::handleCmd_GET_PARAMETER(ServerMediaSubsession* subsession, char const* cseq,			  char const* /*fullRequestStr*/) {  // We implement "GET_PARAMETER" just as a 'keep alive',  // and send back an empty response:  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 200 OK\r\nCSeq: %s\r\n%sSession: %d\r\n\r\n",	   cseq, dateHeader(), fOurSessionId);}static Boolean parseAuthorizationHeader(char const* buf,					char const*& username,					char const*& realm,					char const*& nonce, char const*& uri,					char const*& response) {  // Initialize the result parameters to default values:  username = realm = nonce = uri = response = NULL;  // First, find "Authorization:"  while (1) {    if (*buf == '\0') return False; // not found    if (_strncasecmp(buf, "Authorization: Digest ", 22) == 0) break;    ++buf;  }  // Then, run through each of the fields, looking for ones we handle:  char const* fields = buf + 22;  while (*fields == ' ') ++fields;  char* parameter = strDupSize(fields);  char* value = strDupSize(fields);  while (1) {    value[0] = '\0';    if (sscanf(fields, "%[^=]=\"%[^\"]\"", parameter, value) != 2 &&	sscanf(fields, "%[^=]=\"\"", parameter) != 1) {      break;    }    if (strcmp(parameter, "username") == 0) {      username = strDup(value);    } else if (strcmp(parameter, "realm") == 0) {      realm = strDup(value);    } else if (strcmp(parameter, "nonce") == 0) {      nonce = strDup(value);    } else if (strcmp(parameter, "uri") == 0) {      uri = strDup(value);    } else if (strcmp(parameter, "response") == 0) {      response = strDup(value);    }    fields += strlen(parameter) + 2 /*="*/ + strlen(value) + 1 /*"*/;    while (*fields == ',' || *fields == ' ') ++fields;        // skip over any separating ',' and ' ' chars    if (*fields == '\0' || *fields == '\r' || *fields == '\n') break;  }  delete[] parameter; delete[] value;  return True;}Boolean RTSPServer::RTSPClientSession::authenticationOK(char const* cmdName, char const* cseq,		   char const* urlSuffix, char const* fullRequestStr) {  if (!fOurServer.specialClientAccessCheck(fClientSocket, fClientAddr, urlSuffix)) {    snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,             "RTSP/1.0 401 Unauthorized\r\n"             "CSeq: %s\r\n"             "%s"             "\r\n",             cseq, dateHeader());    return False;  }  // If we weren't set up with an authentication database, we're OK:  if (fOurServer.fAuthDB == NULL) return True;  char const* username = NULL; char const* realm = NULL; char const* nonce = NULL;  char const* uri = NULL; char const* response = NULL;  Boolean success = False;  do {    // To authenticate, we first need to have a nonce set up    // from a previous attempt:    if (fCurrentAuthenticator.nonce() == NULL) break;    // Next, the request needs to contain an "Authorization:" header,    // containing a username, (our) realm, (our) nonce, uri,    // and response string:    if (!parseAuthorizationHeader(fullRequestStr,				  username, realm, nonce, uri, response)	|| username == NULL	|| realm == NULL || strcmp(realm, fCurrentAuthenticator.realm()) != 0	|| nonce == NULL || strcmp(nonce, fCurrentAuthenticator.nonce()) != 0	|| uri == NULL || response == NULL) {      break;    }    // Next, the username has to be known to us:    char const* password = fOurServer.fAuthDB->lookupPassword(username);#ifdef DEBUG    fprintf(stderr, "lookupPassword(%s) returned password %s\n", username, password);#endif    if (password == NULL) break;    fCurrentAuthenticator.      setUsernameAndPassword(username, password,			     fOurServer.fAuthDB->passwordsAreMD5());    // Finally, compute a digest response from the information that we have,    // and compare it to the one that we were given:    char const* ourResponse      = fCurrentAuthenticator.computeDigestResponse(cmdName, uri);    success = (strcmp(ourResponse, response) == 0);    fCurrentAuthenticator.reclaimDigestResponse(ourResponse);  } while (0);  delete[] (char*)username; delete[] (char*)realm; delete[] (char*)nonce;  delete[] (char*)uri; delete[] (char*)response;  if (success) return True;  // If we get here, there was some kind of authentication failure.  // Send back a "401 Unauthorized" response, with a new random nonce:  fCurrentAuthenticator.setRealmAndRandomNonce(fOurServer.fAuthDB->realm());  snprintf((char*)fResponseBuffer, sizeof fResponseBuffer,	   "RTSP/1.0 401 Unauthorized\r\n"	   "CSeq: %s\r\n"	   "%s"	   "WWW-Authenticate: Digest realm=\"%s\", nonce=\"%s\"\r\n\r\n",	   cseq,	   dateHeader(),	   fCurrentAuthenticator.realm(), fCurrentAuthenticator.nonce());  return False;}void RTSPServer::RTSPClientSession::noteLiveness() {  if (fOurServer.fReclamationTestSeconds > 0) {    envir().taskScheduler()      .rescheduleDelayedTask(fLivenessCheckTask,			     fOurServer.fReclamationTestSeconds*1000000,			     (TaskFunc*)livenessTimeoutTask, this);  }}void RTSPServer::RTSPClientSession::noteClientLiveness(RTSPClientSession* clientSession) {  clientSession->noteLiveness();}void RTSPServer::RTSPClientSession::livenessTimeoutTask(RTSPClientSession* clientSession) {  // If this gets called, the client session is assumed to have timed out,  // so delete it:  // However, we don't timeout multicast sessions, because to do so would require  // closing all client sessions that have requested the stream - not just this one.  // Also, the multicast stream itself would usually not be halted, in any case.  if (clientSession->isMulticast()) return;#ifdef DEBUG  fprintf(stderr, "RTSP client session from %s has timed out (due to inactivity)\n", our_inet_ntoa(clientSession->fClientAddr.sin_addr));#endif  delete clientSession;}////////// UserAuthenticationDatabase implementation //////////UserAuthenticationDatabase::UserAuthenticationDatabase(char const* realm,						       Boolean passwordsAreMD5)  : fTable(HashTable::create(STRING_HASH_KEYS)),    fRealm(strDup(realm == NULL ? "LIVE555 Streaming Media" : realm)),    fPasswordsAreMD5(passwordsAreMD5) {}UserAuthenticationDatabase::~UserAuthenticationDatabase() {  delete[] fRealm;  delete fTable;}void UserAuthenticationDatabase::addUserRecord(char const* username,					       char const* password) {  fTable->Add(username, (void*)(strDup(password)));}void UserAuthenticationDatabase::removeUserRecord(char const* username) {  char* password = (char*)(fTable->Lookup(username));  fTable->Remove(username);  delete[] password;}char const* UserAuthenticationDatabase::lookupPassword(char const* username) {  return (char const*)(fTable->Lookup(username));}

⌨️ 快捷键说明

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