Darwin RTSP点播流程代码分析

1.      初始化

在dss中runserver.cpp的startserver是整个服务的初始化函数

关于RTSP点播这块的主要初始化内容如下:

1)  sServer->Initialize(inPrefsSource,inMessagesSource, inPortOverride,createListeners);

//RunServer.cpp

sServer的类型是QTSServer,在初始化函数中调用了CreateListeners函数,目的是创建两个监听对象

l  RTSPListenerSocket

l  HTTPListenerSocket

这两个类都继承于TCPListenerSocket类

 

2)  Socket::StartThread();//启动EventThread线程

3)在其他初始化工作完成后,在runserver.cpp中的startserver开始启动任务  sServer->StartTasks();

主要的工作是注册请求事件:fListeners[x]->RequestEvent(EV_RE);

其实就是把sUniqueID与自己类的指针this管理,然后注册到EventThread线程中fRefTable引用表中,然后把文件描述符(socket)加入到select函数监视的集合中

PS:这块设计到dss的网络架构模型,后续会出专门一篇文章进行描述,目前大家知道这个目的就可以了

 

 

2.      点播请求

当客户端发出请求时,EventContext.cpp中void EventThread::Entry()函数中select_waitevent函数会检测到有对象可读,然后然后从fRefTable中解析出来关联的对象类,执行对应的ProcessEvent

说明:大家都知道dss的网络模型是select,select_waitevent是检测是否有可读的对象

fRefTable这个是OSRefTable引用表的类,关于这块代码请参考我另一篇blog

http://blog.csdn.net/wq5866280/article/details/50435974

这里fRefTable中解析出来的对象,其实就是1.3节中说明fListeners[x],这里请求的是RTSP,所以对象是RTSPListenerSocket,这里主要是处理RTSPListenerSocket的ProcessEvent

 

3.      RTSPListenerSocket的ProcessEvent

由于RTSPListenerSocket是TCPListenerSocket的派生类,ProcessEvent的执行是在TCPListenerSocket类中

函数的主要作用:accept客户端

每接收一个客户端,就是创建一个TCPSocket* theSocket = NULL;

theTask = this->GetSessionTask(&theSocket);

//创建一个 RTSPSession* theTask = NEW RTSPSession

然后设置客户端theSocket与task关联,然后注册事件

theSocket->Set(osSocket,&addr);

theSocket->InitNonBlocking(osSocket);

theSocket->SetTask(theTask);

theSocket->RequestEvent(EV_RE);

和1.3节一样

把客户端的socket加入到select监视集合中,如果有数据需要读取,这执行TCPSocket的ProcessEvent函数,其实就是基类EventContext中的ProcessEvent,也就是给把task加入到线程池中某一个线程的 OSQueue_Blocking   fTaskQueue队列中,等待执行task类中的run函数,这里运行的就是RTSPSession中的run函数。

 

后面一个章节主要说明RTSPSession的run函数。


一个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中的大致处理请求的流程,后面章节会具体针对不同的命令结合模块中的代码分析具体的处理


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunxiaopengsun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值