一个rtsp请求对应一个RTSPSession,核心处理流程是在run函数switch块中,类似状态机处理
1.当一个新的rtsp请求处理时,首先会经过kReadingFirstRequest分支
1) if ((err =fInputStream.ReadRequest()) == QTSS_NoErr)
{
fInputSocketP->RequestEvent(EV_RE);
return 0;
}
fInputStream.ReadRequest()函数作用,就是读取客户端一个完整的RTSP包,把状态赋值为kHTTPFilteringRequest,然后continue,继续循环,switch到kHTTPFilteringRequest
fInputSocketP->RequestEvent(EV_RE);//根据原注释,应该是fInputStream中的fSocket读取数据出现错误时,才执行的,把fInputSocketP加入事件监视中读取,可能读取的数据不同,实际上fInputSocketP就是指向fSocket的指针
比如我们用vlc播放本地的MP4文件,第一包请求的buffer如下:
2. kHTTPFilteringRequest分支处理
fState = kHaveNonTunnelMessage; // assumeit's not a tunnel setup message
QTSS_Error preFilterErr = this->PreFilterForHTTPProxyTunnel();
if ( preFilterErr == QTSS_NoErr )
{
HTTP_TRACE("RTSPSession::Run kHTTPFilteringRequest\n" )
continue;
}
PreFilterForHTTPProxyTunnel函数是对报文内容进行check,判读是否有HTTP报文的内容
,是则直接进入RTSP-over-HTTP状态处理的下一步:kSocketHasBeenBoundIntoHTTPTunnel(此处因为并没有这种需求,所以没有研究),下一步进入kHaveNonTunnelMessage分支
3. kHaveNonTunnelMessage分支处理
fRequest = NEW RTSPRequest(this);//创建一个新的RTSPRequest对象
fRoleParams.rtspRequestParams.inRTSPRequest= fRequest;
fRoleParams.rtspRequestParams.inRTSPHeaders= fRequest->GetHeaderDictionary();
//给rtspRequestParams赋值
fReadMutex.Lock();
fSessionMutex.Lock();
//加锁,说明RTSP请求已经开始被处理,要确保处理请求不会被竞争
fOutputStream.ResetBytesWritten();//重置输出流
下一步进入kFilteringRequest
4. kFilteringRequest分支处理
1)调用所有注册过kRTSPFilterRole角色的模块
PS:模块的注册流程是在服务初始化的时候注册了,不同模块注册了不同角色,后续会专门写篇文章进行描述
numModules =QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPFilterRole);
for (; (fCurrentModule < numModules)&& ((!fRequest->HasResponseBeenSent())|| fModuleState.eventRequested); fCurrentModule++)
{
…..
}
此处执行的kRTSPFilterRole角色的模块是以下模块,执行相应的FilterRequest函数
l QTSSAdminModule:判断是否是admin请求,此处未进入流程,所以不分析
l QTSSMP3StreamingModule:判断是否是rtsp请求,如果是则退出不处理,所以不分析
注意红色标记代码:如果任何模块赋值了响应的数据,就是准备像客户端发送数据,都会导致跳过其他注册相关角色的模块处理
this->SetupRequest();//解析一个正常的请求,判断是rtsp的哪一步请求,进行处理
if (fRequest->HasResponseBeenSent())
{
fState =kPostProcessingRequest;
break;
}
//执行以上代码,只会在option请求时,或者有错误,这表明在option请求时才会进入kPostProcessingRequest分支,否则进入kRoutingRequest分支,下面我们先以kPostProcessingRequest分支为例
此时fRequest的fOutputStream对象已经准备好了回复客户端,如下图
5. kPostProcessingRequest分支处理
if (fRTPSession != NULL) //在option时,rtpsession还未创建,所以不会执行相关代码,直接进入kSendingResponse分支
6. kSendingResponse处理
该分支的作用就是把fOutputStream对象中的数据发给客户端,然后进入kCleaningUp分支
7. kCleaningUp分支处理
顾名思义,该分支主要做清理工作,此处不再详细分析
华丽分割线=========================
上面分析,在第4步的时候,只有option请求才会进入kPostProcessingRequest分支,其他请求会进入kRoutingRequest分支处理,所以我们再从kRoutingRequest分支分析下
5. kRoutingRequest分支处理
// Invoke router modules
numModules =QTSServerInterface::GetNumModulesInRole(QTSSModule::kRTSPRouteRole);
for (; (fCurrentModule < numModules)&& ((!fRequest->HasResponseBeenSent())|| fModuleState.eventRequested); fCurrentModule++)
{
….
}
此处kFilteringRequest分支处理一样,是调用注册了kRTSPRouteRole角色的模块,同时注意点也和kFilteringRequest分支一样
此处调用的模块只有QTSSReflectorModule模块
QTSSReflectorModule模块执行RedirectBroadcast函数,主要设置RTSPRequest对象的某些属性,由于判断条件未通过,其实没做什么操作
fRequest->SetupAuthLocalPath();
//设置路径属性
if (fRequest->HasResponseBeenSent())
{
fState= kPostProcessingRequest;
break;
}//此处跳过
if(fRequest->SkipAuthorization())//跳过认证,默认为true
{
fState = kPreprocessingRequest;
}
开始进入kPreprocessingRequest分支
6. kPreprocessingRequest分支处理
7.kProcessingRequest分支处理
8.kPostProcessingRequest分支处理
6,7,8分支按顺序执行,这三块的处理主要是调用相应模块注册的kRTSPPreProcessorRole,kRTSPRequestRole,kRTSPPostProcessorRole这三种角色的函数,用于具体处理RTSP的相关命令处理,比如QTSSFileModule.cpp文件中,有对descirbe,play等请求命令的处理,如下
9.kCleaningUp分支处理
同上面的kCleaningUp分支处理
总结:以上说明了RTSPSession中的大致处理请求的流程,后面章节会具体针对不同的命令结合模块中的代码分析具体的处理
以上内容是个人研究,如有错处,欢迎加本人的QQ 272706196一起讨论学习,或者加入我们的EasyDarwin的群288214068,496258327