您的位置:首页 > 其它

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

2013-10-08 10:57 453 查看
处理连接请求的基本流程:

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

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

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

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

n OPTIONS→handleCmd_OPTIONS

n DESCRIBE→handleCmd_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 SETUP→handleCmd_SETUP

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

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

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

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

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

n TEARDOWN→handleCmd_TEARDOWN:处理停止请求,将fSessionIsActive置为FALSE。

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

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

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

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

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

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

处理PLAY的基本流程:

l Step 1:对rtspURL及相关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:根据clientSessionId从fDestinationsHashTable中查找到destinations(包括了客户端的IP地址、RTP端口号、RTCP端口号等信息)。

n Step 3.2:调用startPlaying方法,在该方法中根据RTPSink或UDPSink分别调用startPlaying方法。

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

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

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

Step 3.3:针对RTPSink创建RTCP instance(RTP与RTCP的配套使用决定了其必须这么做,否则可能就跟直接使用UDP发送数据包没什么两样了^_^),创建RTCP instance时,将incomingReportHandler句柄作为BackgroundHandlerProc,以便于处理RTCP的报告,并开始startNetworkReading。这里RTP/RTCP的使用方式有两种,一种建立在TCP之上,一种建立在UDP之上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: