开源项目live555学习心得(三)

RTSP服务器处理客户端点播的基本流程

*  处理连接请求的基本流程:

l  Step 1与客户端建立RTSP连接(调用incomingConnectionHandler方法),创建ClientSession并关联fClientSocketincomingRequestHandler(调用incomingConnectionHandler1

l  Step 2接收客户端请求(调用incomingRequestHandler方法)。

l  Step 3从客户端Socket读取数据,并对请求数据(即the request string)进行转换(调用parseRTSPRequestString方法,该方法在RTSPCommon类中)。

l  Step 4根据分离出来的指令进行分别处理:

n  OPTIONShandleCmd_OPTIONS 

n  DESCRIBEhandleCmd_DESCRIBE

handleCmd_DESCRIBE这一个方法比较重要,首先根据urlSuffix查找ServerMediaSession是否存在(调用lookupServerMediaSession方法,该方法中通过HashTable来查找)。

testOnDemandRTSPServer项目工程中,仅仅是通过streamName来确认session是否为NULL。而在完整的live555MediaServer项目工程中,则是通过DynamicRTSPServer类来处理,其首先是查找文件是否存在,若文件不存在,则判断ServerMediaSession(即smsExists)是否存在,如果存在则将其remove(调用removeServerMediaSession方法);若文件存在,则根据文件名创建一个ServerMediaSession(调用createNewSMS方法,若在该方法中找不到对应的文件扩展名,则将返回NULL)。

如果通过lookupServerMediaSession返回的是NULL,则向客户端发送响应消息并将fSessionIsActive置为FALSE;否则,为该session组装一个SDP描述信息(调用generateSDPDescription方法,该方法在ServerMediaSession类中),组装完成后,生成一个RTSP URL(调用rtspURL方法,该方法在RTSPServer类中)。

n  SETUPhandleCmd_SETUP

handleCmd_SETUP方法中,有两个关键的名词,一个是urlPreSuffix,代表了session name(即stream name);一个是urlSuffix,代表了subsession name(即track name),后面经常用到的streamNametrackId分别与这两个名词有关。

接下来会创建session's state,包括incrementReferenceCount等。紧接着,会针对确定的subsessiontrack)查找相应的信息。接着,在request string查找一个"Transport:" header,目的是为了从中提取客户端请求的一些参数(调用parseTransportHeader方法,该方法在RTSPServer类中),如clientsDestinationAddressStrClientRTPPortNum等。

再接着是getStreamParameters(该方法在ServerMediaSession类中被定义为纯虚函数并在OnDemandServerMediaSubsession类中被重定义),然后通过fIsMulticaststreamingMode来组装不同的响应消息。

n  PLAYhandleCmd_PLAY处理播放请求,具体的实现流程请参见后面的步骤。

n  PAUSEhandleCmd_PAUSE处理暂停请求,在执行了该请求后,最终会调用StopPlaying方法,并将fAreCurrentlyPlaying置为FALSE

n  TEARDOWNhandleCmd_TEARDOWN处理停止请求,将fSessionIsActive置为FALSE

n  GET_PARAMETERhandleCmd_GET_PARAMETER该方法主要是维持客户端与服务器通信的生存状态,just for keep alive

n  SET_PARAMETERhandleCmd_SET_PARAMETER该方法未针对SET_PARAMETER作实现,使用该方法会调用handleCmd_notSupported方法,并将最终引发与客户端断开连接。

l  Step 5根据Step 4的不同指令进行消息响应(调用send方法),该消息响应是即时的。

l  Step 6处理客户端发送“SETUP”指令后即开始播放的特殊情况。

l  Step 7RequestBuffer进行重置,以便于为之后到来的请求做好准备。

l  Step 8检查fSessionIsActive是否为FALSE,如果是则删除当前的ClientSession

 

*  处理PLAY的基本流程:

l  Step 1rtspURL及相关header的处理,涉及较多的细节。

l  Step 2根据不同的header对流进行缩放比例或定位的处理。

如果为sawScaleHeader,则进行缩放比例的处理(调用setStreamScale方法,该方法在OnDemandServerMediaSubsession类中实现)。

如果为sawRangeHeader,则进行寻找流的处理(即是对流进行定位,调用seekStream方法,该方法在OnDemandServerMediaSubsession类中实现;同时,该方法的调用是在初始播放前及播放过程中由于用户拖动播放进度条而产生的系列请求)。

OnDemandServerMediaSubsession类中,seekStream方法中调用了seekStreamSource方法,该方法在对应的媒体格式文件的FileServerMediaSubsession类中实现(如针对WAV格式,则在WAVAudioFileServerMediaSubsession类中实现;针对MP3格式,则在MP3AudioFileServerMediaSubsession类中实现)。

同理,OnDemandServerMediaSubsession类中的setStreamScale方法中所调用的setStreamSourceScale方法亦是类似的实现机制。

l  Step 3开始进行流式播放(调用startStream方法,该方法在OnDemandServerMediaSubsession类中实现)。

n  Step 3.1根据clientSessionIdfDestinationsHashTable中查找到destinations(包括了客户端的IP地址、RTP端口号、RTCP端口号等信息)。

n  Step 3.2调用startPlaying方法,在该方法中根据RTPSinkUDPSink分别调用startPlaying方法。

如果是调用RTPSinkstartPlaying方法,则接着会调用MediaSink类中的startPlaying方法,并在该方法中调用MultiFramedRTPSink类中的continuePlaying方法,之后便是buildAndSendPacket了。这里已经来到重点了,即是关于不断读取FrameSend的要点。在MultiFramedRTPSink类中,通过buildAndSendPacketpackFrameafterGettingFrameafterGettingFrame1sendPacketIfNecessarysendNext构成了一个循环圈,数据包的读取和发送在这里循环进行着。特别注意的是sendPacketIfNecessary方法中的后面代码(nextTask() = envir().taskScheduler().scheduleDelayedTask(uSecondsToGo, (TaskFunc*)sendNext, this);),通过Delay amount of time后,继续下一个Task,并回过来继续调用buildAndSendPacket方法。

packFrame方法中,正常情况下,需要调用getNextFrame方法(该方法在FramedSource类中,并且对不同媒体格式的Frame的获取出现在FramedSource类的getNextFrame方法中,通过调用doGetNextFrame方法来实现)来获取新的Frame

如果是调用UDPSinkstartPlaying方法,则接着会调用MediaSink类中的startPlaying方法,并在该方法中调用BasicUDPSink类中的continuePlaying方法。在这之后由若干个方法构成了一个循环圈:continuePlaying1afterGettingFrameafterGettingFrame1sendNext。并在afterGettingFrame1方法中实现了packet的发送(fGS->output(envir(), fGS->ttl(), fOutputBuffer, frameSize);)。

Step 3.3针对RTPSink创建RTCP instanceRTPRTCP的配套使用决定了其必须这么做,否则可能就跟直接使用UDP发送数据包没什么两样了^_^),创建RTCP instance时,将incomingReportHandler句柄作为BackgroundHandlerProc,以便于处理RTCP的报告,并开始startNetworkReading。这里RTP/RTCP的使用方式有两种,一种建立在TCP之上,一种建立在UDP之上。

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

踏雪无痕大黄蜂

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

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

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

打赏作者

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

抵扣说明:

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

余额充值