Live555源代码解读(5-3)

void RTSPServer::RTSPClientSession::handleCmd_SETUP(

char const* cseq,

char const* urlPreSuffix,

char const* urlSuffix,

char const* fullRequestStr)

{

// Normally, "urlPreSuffix" should be the session (stream) name,

// and "urlSuffix" should be the subsession (track) name.

// However (being "liberal in what we accept"), we also handle

// 'aggregate' SETUP requests (i.e., without a track name),

// in the special case where we have only a single track.  I.e.,

// in this case, we also handle:

//    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or

//    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween)

//    is the session (stream) name.

char const* streamName = urlPreSuffix; // in the normal case

char const* trackId = urlSuffix; // in the normal case

char* concatenatedStreamName = NULL; // in the normal case



do {

// First, make sure the specified stream name exists:

fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);

if (fOurServerMediaSession == NULL) {

// Check for the special case (noted above), before we up:

if (urlPreSuffix[0] == '\0') {

streamName = urlSuffix;

} else {

concatenatedStreamName = new char[strlen(urlPreSuffix)

+ strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'

sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix,

urlSuffix);

streamName = concatenatedStreamName;

}

trackId = NULL;



// Check again:

fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);

}

if (fOurServerMediaSession == NULL) {

handleCmd_notFound(cseq);

break;

}



fOurServerMediaSession->incrementReferenceCount();



//为一个流中所有的track都分配一个stream state

if (fStreamStates == NULL) {

// This is the first "SETUP" for this session.  Set up our

// array of states for all of this session's subsessions (tracks):

ServerMediaSubsessionIterator iter(*fOurServerMediaSession);

for (fNumStreamStates = 0; iter.next() != NULL;++fNumStreamStates) {

} // begin by counting the number of subsessions (tracks)



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; it may be changed by the "getStreamParameters()" call that comes later

}

}



//查找当前请求的track的信息

// Look up information for the specified subsession (track):

ServerMediaSubsession* subsession = NULL;

unsigned streamNum;

if (trackId != NULL && trackId[0] != '\0') { // 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);

break;

}

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

break;

}

streamNum = 0;

subsession = fStreamStates[streamNum].subsession;

}

// ASSERT: subsession != NULL



//分析RTSP请求字符串中的传输要求

// Look for a "Transport:" header in the request string, to extract client parameters:

StreamingMode streamingMode;

char* streamingModeString = NULL; // 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

|| streamingMode != RTP_TCP&&

fClientOutputSocket != fClientInputSocket) {

// An anomolous situation, caused by a buggy client.  Either:

//     1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or

//     2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).

// In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values:

streamingMode = RTP_TCP;

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":

double rangeStart = 0.0, rangeEnd = 0.0;

fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart,

rangeEnd) || parsePlayNowHeader(fullRequestStr);



// Then, get server parameters from the 'subsession':

int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -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;

Port serverRTPPort(0);

Port serverRTCPPort(0);



// Make sure that we transmit on the same interface that's used by

// the client (in case we're a multi-homed server):

struct sockaddr_in sourceAddr;

SOCKLEN_T namelen = sizeof sourceAddr;

getsockname(fClientInputSocket, (struct sockaddr*) &sourceAddr,&namelen);

netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;

netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;

// NOTE: The following might not work properly, so we ifdef it out for now:

#ifdef HACK_FOR_MULTIHOMED_SERVERS

ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;

#endif



//获取rtp连接信息,在其中已建立起了server端的rtp和rtcp socket,返回

//fStreamStates[streamNum].streamToken表示数据流已经建立起来了

subsession->getStreamParameters(fOurSessionId,

fClientAddr.sin_addr.s_addr, clientRTPPort, clientRTCPPort,

tcpSocketNum, rtpChannelId, rtcpChannelId, destinationAddress,

destinationTTL, fIsMulticast, serverRTPPort, serverRTCPPort,

fStreamStates[streamNum].streamToken);

SendingInterfaceAddr = origSendingInterfaceAddr;

ReceivingInterfaceAddr = origReceivingInterfaceAddr;



//形成RTSP回应字符串

struct in_addr destinationAddr;

destinationAddr.s_addr = destinationAddress;

char* destAddrStr = strDup(our_inet_ntoa(destinationAddr));

char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr));

if (fIsMulticast) {

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;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()),

ntohs(serverRTCPPort.num()), destinationTTL,

fOurSessionId);

break;

case RTP_TCP:

// multicast streams can't be sent via TCP

handleCmd_unsupportedTransport(cseq);

break;

case RAW_UDP:

snprintf(

(char*) fResponseBuffer,

sizeof fResponseBuffer,

"RTSP/1.0 200 OK\r\n"

"CSeq: %s\r\n"

"%s"

"Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

streamingModeString, destAddrStr, sourceAddrStr,

ntohs(serverRTPPort.num()), destinationTTL,

fOurSessionId);

break;

}

} 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;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, 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;source=%s;interleaved=%d-%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, 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;source=%s;client_port=%d;server_port=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

streamingModeString, destAddrStr, sourceAddrStr,

ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),

fOurSessionId);

break;

}

}

}

delete[] destAddrStr;

delete[] sourceAddrStr;

delete[] streamingModeString;

} while (0);



delete[] concatenatedStreamName;

//返回后,回应字符串会被立即发送

}

有个问题,如果这个streamToken使用的是已存在的(还记得ReuseFirstSource吗),为它再次调用startStream()时,究竟会做什么呢?你猜啊!呵呵我猜吧:应该是把这个客户端的地址和rtp/rtcp端口传给rtp server的groupSocket,rtp server自然就开始向这个客户端发送数据了。是不是这样尼?看代码吧:

void RTSPServer::RTSPClientSession::handleCmd_SETUP(

char const* cseq,

char const* urlPreSuffix,

char const* urlSuffix,

char const* fullRequestStr)

{

// Normally, "urlPreSuffix" should be the session (stream) name,

// and "urlSuffix" should be the subsession (track) name.

// However (being "liberal in what we accept"), we also handle

// 'aggregate' SETUP requests (i.e., without a track name),

// in the special case where we have only a single track.  I.e.,

// in this case, we also handle:

//    "urlPreSuffix" is empty and "urlSuffix" is the session (stream) name, or

//    "urlPreSuffix" concatenated with "urlSuffix" (with "/" inbetween)

//    is the session (stream) name.

char const* streamName = urlPreSuffix; // in the normal case

char const* trackId = urlSuffix; // in the normal case

char* concatenatedStreamName = NULL; // in the normal case



do {

// First, make sure the specified stream name exists:

fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);

if (fOurServerMediaSession == NULL) {

// Check for the special case (noted above), before we up:

if (urlPreSuffix[0] == '\0') {

streamName = urlSuffix;

} else {

concatenatedStreamName = new char[strlen(urlPreSuffix)

+ strlen(urlSuffix) + 2]; // allow for the "/" and the trailing '\0'

sprintf(concatenatedStreamName, "%s/%s", urlPreSuffix,

urlSuffix);

streamName = concatenatedStreamName;

}

trackId = NULL;



// Check again:

fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);

}

if (fOurServerMediaSession == NULL) {

handleCmd_notFound(cseq);

break;

}



fOurServerMediaSession->incrementReferenceCount();



//为一个流中所有的track都分配一个stream state

if (fStreamStates == NULL) {

// This is the first "SETUP" for this session.  Set up our

// array of states for all of this session's subsessions (tracks):

ServerMediaSubsessionIterator iter(*fOurServerMediaSession);

for (fNumStreamStates = 0; iter.next() != NULL;++fNumStreamStates) {

} // begin by counting the number of subsessions (tracks)



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; it may be changed by the "getStreamParameters()" call that comes later

}

}



//查找当前请求的track的信息

// Look up information for the specified subsession (track):

ServerMediaSubsession* subsession = NULL;

unsigned streamNum;

if (trackId != NULL && trackId[0] != '\0') { // 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);

break;

}

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

break;

}

streamNum = 0;

subsession = fStreamStates[streamNum].subsession;

}

// ASSERT: subsession != NULL



//分析RTSP请求字符串中的传输要求

// Look for a "Transport:" header in the request string, to extract client parameters:

StreamingMode streamingMode;

char* streamingModeString = NULL; // 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

|| streamingMode != RTP_TCP&&

fClientOutputSocket != fClientInputSocket) {

// An anomolous situation, caused by a buggy client.  Either:

//     1/ TCP streaming was requested, but with no "interleaving=" fields.  (QuickTime Player sometimes does this.), or

//     2/ TCP streaming was not requested, but we're doing RTSP-over-HTTP tunneling (which implies TCP streaming).

// In either case, we assume TCP streaming, and set the RTP and RTCP channel ids to proper values:

streamingMode = RTP_TCP;

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":

double rangeStart = 0.0, rangeEnd = 0.0;

fStreamAfterSETUP = parseRangeHeader(fullRequestStr, rangeStart,

rangeEnd) || parsePlayNowHeader(fullRequestStr);



// Then, get server parameters from the 'subsession':

int tcpSocketNum = streamingMode == RTP_TCP ? fClientOutputSocket : -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;

Port serverRTPPort(0);

Port serverRTCPPort(0);



// Make sure that we transmit on the same interface that's used by

// the client (in case we're a multi-homed server):

struct sockaddr_in sourceAddr;

SOCKLEN_T namelen = sizeof sourceAddr;

getsockname(fClientInputSocket, (struct sockaddr*) &sourceAddr,&namelen);

netAddressBits origSendingInterfaceAddr = SendingInterfaceAddr;

netAddressBits origReceivingInterfaceAddr = ReceivingInterfaceAddr;

// NOTE: The following might not work properly, so we ifdef it out for now:

#ifdef HACK_FOR_MULTIHOMED_SERVERS

ReceivingInterfaceAddr = SendingInterfaceAddr = sourceAddr.sin_addr.s_addr;

#endif



//获取rtp连接信息,在其中已建立起了server端的rtp和rtcp socket,返回

//fStreamStates[streamNum].streamToken表示数据流已经建立起来了

subsession->getStreamParameters(fOurSessionId,

fClientAddr.sin_addr.s_addr, clientRTPPort, clientRTCPPort,

tcpSocketNum, rtpChannelId, rtcpChannelId, destinationAddress,

destinationTTL, fIsMulticast, serverRTPPort, serverRTCPPort,

fStreamStates[streamNum].streamToken);

SendingInterfaceAddr = origSendingInterfaceAddr;

ReceivingInterfaceAddr = origReceivingInterfaceAddr;



//形成RTSP回应字符串

struct in_addr destinationAddr;

destinationAddr.s_addr = destinationAddress;

char* destAddrStr = strDup(our_inet_ntoa(destinationAddr));

char* sourceAddrStr = strDup(our_inet_ntoa(sourceAddr.sin_addr));

if (fIsMulticast) {

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;multicast;destination=%s;source=%s;port=%d-%d;ttl=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, ntohs(serverRTPPort.num()),

ntohs(serverRTCPPort.num()), destinationTTL,

fOurSessionId);

break;

case RTP_TCP:

// multicast streams can't be sent via TCP

handleCmd_unsupportedTransport(cseq);

break;

case RAW_UDP:

snprintf(

(char*) fResponseBuffer,

sizeof fResponseBuffer,

"RTSP/1.0 200 OK\r\n"

"CSeq: %s\r\n"

"%s"

"Transport: %s;multicast;destination=%s;source=%s;port=%d;ttl=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

streamingModeString, destAddrStr, sourceAddrStr,

ntohs(serverRTPPort.num()), destinationTTL,

fOurSessionId);

break;

}

} 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;source=%s;client_port=%d-%d;server_port=%d-%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, 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;source=%s;interleaved=%d-%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

destAddrStr, sourceAddrStr, 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;source=%s;client_port=%d;server_port=%d\r\n"

"Session: %08X\r\n\r\n", cseq, dateHeader(),

streamingModeString, destAddrStr, sourceAddrStr,

ntohs(clientRTPPort.num()), ntohs(serverRTPPort.num()),

fOurSessionId);

break;

}

}

}

delete[] destAddrStr;

delete[] sourceAddrStr;

delete[] streamingModeString;

} while (0);



delete[] concatenatedStreamName;

//返回后,回应字符串会被立即发送

}


转载于:https://my.oschina.net/seanx/blog/621683

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值