SETUP命令概述
SETUP命令,主要用于协商客户端与服务器的通信细节,如通信协议、地址等等,SETUP请求中最重要的是"Transport"头部。
客户端需要对,文件中的每一个流发送一个SETUP命令。
客户端还可以通过其中的"destination"属性来重定向RTP数据的接收地址,不过这是需要服务器支持的,在live555中需要定义宏RTSP_ALLOW_CLIENT_DESTINATION_SETTING。
SETUP的响应中,包含一个"Session"头部,这是服务器产生的一个随机数,用于标识特定的客户端。
来看一个具体的SETUP消息实例SETUP rtsp://192.168.9.80/123.264/track1 RTSP/1.0
CSeq: 31
Transport: RTP/AVP/TCP;unicast;interleaved=0-1
User-Agent: LibVLC/1.1.0 (LIVE555 Streaming Media v2010.03.16)
response: RTSP/1.0 200 OK
CSeq: 31
Date: Wed, Nov 30 2011 06:40:49 GMT
Transport: RTP/AVP/TCP;unicast;destination=192.168.9.80;source=192.168.9.80;interleaved=0-1
Session: A00F79DE
1.命令处理函数handleCmd_SETUP
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 {
//根据媒体流名称(文件名)查找相应的session, session是在DSCRIBE命令处理过程中创建的
// First, make sure the specified stream name exists:
fOurServerMediaSession = fOurServer.lookupServerMediaSession(streamName);
//下面处理URL中不带 track id 的情况,当文件中只有一个流时,充许这种情况的出现,这里流名称保存在urlSuffix变量中
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); //重新查找session
}
if (fOurServerMediaSession == NULL) {
handleCmd_notFound(cseq);
break;
}
fOurServerMediaSession->incrementReferenceCount(); //增加session的引用计数
//若这是这个session所处理的第一个"SETUP"命令,需要构建一个streamState型的数组,并初化
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 (fNumStreamSt