从零开始学习EasyDarwin之RTSP请求处理过程
2016-03-22 13:05
399 查看
今天详细的看了下RTSPSession的会话处理代码,该模块主要是Run方法内对会话的状态机进行管理,实现对RTSP会话的处理,我以点播Movie文件夹下的视频文件为例,并按照状态机的处理顺序对他们进行一一解析,如下:
进入到RTSPSession::Run()函数中进行请求报文的处理。处理RTSP请求的流程中,DSS主要采用了状态机(state machine)的处理方式
通过fInputStream.ReadRequest()调用Session绑定的socket,获取数据,该函数有两个返回码:
a) QTSS_NoErr,意味着已经收到该socket的完整数据,但是没有收集到本次请求的全部数据,这时需要接着请求监听读事件,获取更多数据组成完整的RTSP请求消息。
b) QTSS_RequestArrived,意味着此时已经收到完整请求的报文,可以正常进入下一状态机了。
c) E2BIG,表示缓存区已经溢出,默认缓存区的大小为( kRequestBufferSizeInBytes = 4096),进入kHaveNonTunnelMessage状态机,然后在该状态机下响应错误
是则直接进入RTSP-over-HTTP状态处理的下一步:kSocketHasBeenBoundIntoHTTPTunnel状态
否的话进入kHaveNonTunnelMessage状态。
//检测是否为RTSP-over-HTTP tunneling的函数:
QTSS_Error preFilterErr = this->PreFilterForHTTPProxyTunnel();
切入PreFilterForHTTPProxyTunnel(),调用RTSPSession::ParseProxyTunnelHTTP()函数,
在ParseProxyTunnelHTTP函数中,判断HTTP报文中一些关键字
a) 创建RTSPRequest对象,用于解析RTSP消息;
b) 进入此状态,说明请求报文格式是正确的,请求已进入受理状态,此状态中对fReadMutex,fSessionMutex进行加锁,禁止在处理报文的过程中发送interleaved RTP报文,或者在处理报文过程中插入一个POST Session
c) 对错误码E2BIG、QTSS_BadArgument进行处理,响应qtssClientBadRequest;
d) 将状态机跳转到kFilteringRequest下;
b) 通过IsDataPacket属性进行判断当前数据是否是一个数据包,而不是一个信令消息。该属性判断方法在RTSPRequestStream::ReadRequest()中。RTP包格式以$字符开头,后面紧跟着一个字节是信道标示符,后面两个字节是数字长度,Darwin就用这个字符区分是否为数据包。
c) 这时第一次开始调用module了,角色为kRTSPFilterRole。注册了该角色模块只有一个QTSSRefMovieModule
d) 在SetupRequest()函数中,解析RTSP消息,同时创建一个客户会话(RTPSession),和产生当前请求的客户端连接相关联,这个会话会一直保持,直到客户端的流播放结束。
注意:服务器根据被调用的模块是否对请求做了应答来决定后面的调用(方法HasResponseBeenSent()),如果注册了RTSP Filter Role的某一个模块在被调用的时候对请求作出了应答,服务器将立即调用注册了RTSPPostprocessorRole的模块,不再调用其他尚未调用的注册了RTSP Filter Role的模块,否则服务器调用其它注册了RTSP Filter Role的模块。
kPreprocessingRequest:如果请求的类型互相匹配,则RTSP Preprocessor角色就调用QTSS_Write或者QTSS_WriteV函数来向客户发送数据,对客户端进行响应。如果只需要发送标准响应,则模块可以调用QTSS_SendStandardRTSPResponse,或者QTSS_AppendRTSPHeader和QTSS_SendRTSPHeaders函数。
重要提示
任何处理RTSP Preprocessor角色的模块对客户端进行响应,都会导致服务器跳过注册了RTSP Preprocessor角色的所有其它模块,以及跳过注册了其它RTSP角色的所有模块,并且立即调用响应模块的RTSP Postprocessor角色。
如果没有RTSP Preprocessor角色对RTSP的请求进行响应,则服务器就以RTSP Request(请求)角色调用成功注册了该角色的模块(第一个注册RTSP Request角色的模块,是唯一一个可以注册RTSP Request角色的模块)。RTSP Request角色负责响应所有没有被RTSP Preprocessor角色(的模块)处理过的RTSP请求。
处理RTSP Preprocessor或者RTSP Request角色的模块可能需要为特定的客户会话生成一些媒体数据。如果这样的话,模块可以通过调用QTSS_Play函数来实现,这个函数会使模块的RTP Send Packets(RTP发送数据包)角色被调用。
进入到RTSPSession::Run()函数中进行请求报文的处理。处理RTSP请求的流程中,DSS主要采用了状态机(state machine)的处理方式
1. 状态机 kReadingFirstRequest
进入初始化状态,实际在此状态中读取请求报文的方式与后续在kReadingRequest状态的读取及处理的方式是一致的,只不过在第一次进行Request处理时,需要检测该请求的方式是以普通RTSP的方式,还是以RTSP-over-HTTP tunneling方式进行报文交互通过fInputStream.ReadRequest()调用Session绑定的socket,获取数据,该函数有两个返回码:
a) QTSS_NoErr,意味着已经收到该socket的完整数据,但是没有收集到本次请求的全部数据,这时需要接着请求监听读事件,获取更多数据组成完整的RTSP请求消息。
b) QTSS_RequestArrived,意味着此时已经收到完整请求的报文,可以正常进入下一状态机了。
c) E2BIG,表示缓存区已经溢出,默认缓存区的大小为( kRequestBufferSizeInBytes = 4096),进入kHaveNonTunnelMessage状态机,然后在该状态机下响应错误
2. 状态机 kHTTPFilteringRequest
对报文内容进行过滤,检查是否有HTTP报文中一些关键字(POST/GET等),是则直接进入RTSP-over-HTTP状态处理的下一步:kSocketHasBeenBoundIntoHTTPTunnel状态
否的话进入kHaveNonTunnelMessage状态。
//检测是否为RTSP-over-HTTP tunneling的函数:
QTSS_Error preFilterErr = this->PreFilterForHTTPProxyTunnel();
切入PreFilterForHTTPProxyTunnel(),调用RTSPSession::ParseProxyTunnelHTTP()函数,
在ParseProxyTunnelHTTP函数中,判断HTTP报文中一些关键字
if (theParsedData.EqualIgnoreCase("post", 4 )) { fHTTPMethod = kHTTPMethodPost;//Post } else if (theParsedData.EqualIgnoreCase("get", 3 )) { fHTTPMethod = kHTTPMethodGet;//Get }
3. 状态机 kHaveNonTunnelMessage
进入此状态,说明请求报文格式是正确的,请求已进入受理状态,具体操作步骤如下:a) 创建RTSPRequest对象,用于解析RTSP消息;
b) 进入此状态,说明请求报文格式是正确的,请求已进入受理状态,此状态中对fReadMutex,fSessionMutex进行加锁,禁止在处理报文的过程中发送interleaved RTP报文,或者在处理报文过程中插入一个POST Session
c) 对错误码E2BIG、QTSS_BadArgument进行处理,响应qtssClientBadRequest;
d) 将状态机跳转到kFilteringRequest下;
4. 状态机kFilteringRequest
a) 刷新超时任务fTimeoutTask,运转RTSP会话的超时机制。b) 通过IsDataPacket属性进行判断当前数据是否是一个数据包,而不是一个信令消息。该属性判断方法在RTSPRequestStream::ReadRequest()中。RTP包格式以$字符开头,后面紧跟着一个字节是信道标示符,后面两个字节是数字长度,Darwin就用这个字符区分是否为数据包。
c) 这时第一次开始调用module了,角色为kRTSPFilterRole。注册了该角色模块只有一个QTSSRefMovieModule
d) 在SetupRequest()函数中,解析RTSP消息,同时创建一个客户会话(RTPSession),和产生当前请求的客户端连接相关联,这个会话会一直保持,直到客户端的流播放结束。
// We have an RTSP request and are about to begin processing. We need to // make sure that anyone sending interleaved data on this session won't // be allowed to do so until we are done sending our response // We also make sure that a POST session can't snarf in while we're // processing the request. fReadMutex.Lock(); fSessionMutex.Lock();
注意:服务器根据被调用的模块是否对请求做了应答来决定后面的调用(方法HasResponseBeenSent()),如果注册了RTSP Filter Role的某一个模块在被调用的时候对请求作出了应答,服务器将立即调用注册了RTSPPostprocessorRole的模块,不再调用其他尚未调用的注册了RTSP Filter Role的模块,否则服务器调用其它注册了RTSP Filter Role的模块。
5. 状态机kRoutingRequest
这里只走到一个模块QTSSReflectorModule中,调用其RedirectBroadcast()方法,主要是增加两个字段到inParams->inRTSPRequest中。key值分别为qtssRTSPReqRootDir、qtssRTSPReqFilePath。6. 状态机kPreprocessingRequest
遍历调用所有注册了QTSS_RTSPPreProcessor_Role角色的模块。在这个角色模式下,分别处理了每种RTSP消息,比如本次的点播请求的Describe、Setup、Play指令,模块中针对各种消息都有对应的单独函数处理。 处理完每次RTSP请求后即进入下一状态kPostProcessingRequest,待下轮循环进入本状态机再处理下一个RTSP消息。kPreprocessingRequest:如果请求的类型互相匹配,则RTSP Preprocessor角色就调用QTSS_Write或者QTSS_WriteV函数来向客户发送数据,对客户端进行响应。如果只需要发送标准响应,则模块可以调用QTSS_SendStandardRTSPResponse,或者QTSS_AppendRTSPHeader和QTSS_SendRTSPHeaders函数。
重要提示
任何处理RTSP Preprocessor角色的模块对客户端进行响应,都会导致服务器跳过注册了RTSP Preprocessor角色的所有其它模块,以及跳过注册了其它RTSP角色的所有模块,并且立即调用响应模块的RTSP Postprocessor角色。
如果没有RTSP Preprocessor角色对RTSP的请求进行响应,则服务器就以RTSP Request(请求)角色调用成功注册了该角色的模块(第一个注册RTSP Request角色的模块,是唯一一个可以注册RTSP Request角色的模块)。RTSP Request角色负责响应所有没有被RTSP Preprocessor角色(的模块)处理过的RTSP请求。
7.状态机kProcessingRequest
RTSP Request角色对请求进行处理之后,服务器就调用注册了RTSP Postprocessor角色的模块。RTSP Postprocessor角色通常执行一些统计任务,比如记录各种统计信息。处理RTSP Preprocessor或者RTSP Request角色的模块可能需要为特定的客户会话生成一些媒体数据。如果这样的话,模块可以通过调用QTSS_Play函数来实现,这个函数会使模块的RTP Send Packets(RTP发送数据包)角色被调用。
8.RTP数据包发送
RTP Send Packets角色调用QTSS_Write或者QTSS_WriteV函数,在RTP会话的基础上向客户发送数据。当RTP Send Packets角色发送完成一些数据包之后,就会把控制权返回给服务器,并指定服务器下次调用模块的RTP Send Packets角色的间隔时间。这个周期会一直重复,直到所有的媒体数据包被发送完成,或者由于客户请求的原因需要暂停或中止客户会话为止。相关文章推荐
- Managed Media Aggregation using Rtsp and Rtp
- javascript与有限状态机详解
- 让android支持RTSP及live555分析
- 一种手游中实时战斗系统的设计思路
- 实时流协议 RTSP
- 剖析 Qt 实现动画状态机实例
- RTSP 协议分析(—)
- RTSP 协议分析(二)
- 去掉C/C++源程序中的注释
- Android StateMachine解析( 1 )
- EasyDarwin调研报告
- 三段式状态机
- [LeetCode] Valid Number 使用有限状态机
- RTSP协议
- DSS源码分析--对RTSP请求的状态机处理机制
- 作为一个状态机的OpenGL
- 最佳实践----状态机对多步骤异步操作建模
- 关于rtsp server的连接保持问题
- 软件作品
- 有限状态机(FSM)