Darwin RTSP点播流程代码分析2

来源:互联网 发布:如何评价b站 知乎 编辑:程序博客网 时间:2024/05/18 09:06

一个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,继续循环,switchkHTTPFilteringRequest

 

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的群288214068496258327

0 0
原创粉丝点击