📄 rtspserver.cpp
字号:
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 + -