live555学习之RTSP连接建立以及请求消息处理过程_第1页
live555学习之RTSP连接建立以及请求消息处理过程_第2页
live555学习之RTSP连接建立以及请求消息处理过程_第3页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、live555 学习之 RTSP 连接建立以及请求消息处理过程1,RTSP 连接的建立过程RTSPServer 类用于构建一个RTSP 服务器,该类同时在其内部定义了一个RTSPClientSession 类,用于处理单独的客户会话。首先创建 RTSP 服务器 (具体实现类是DynamicRTSPServer) ,在创建过程中,先建立Socket(ourSocket)在 TCP 的 554 端口进行监听,然后把连接处理函数句柄(RTSPServer: incomingConnectionHandler) 和 socket 句柄传给任务调度器 (taskScheduler)。任务调度器把sock

2、et 句柄放入后面select 调用中用到的socket 句柄集 (fReadSet)中,同时将socket 句柄和incomingConnectionHandler 始进入任务调度器的主循环(句柄关联起来。接着,主程序开doEventLoop ),在主循环中调用系统函数select 阻塞,等待网络连接。当 RTSP 客户端输入 (rtsp:/09/1.mpg) 连接服务器时, select 返回对应的 scoket,进而根据前面保存的对应关系,可找到对应处理函数句柄,这里就是前面提到的incomingConnectionHandler 了。在incomingConnec

3、tionHandler 中创建了 RTSPClientSession,开始对这个客户端的会话进行处理。具体分析如下:DynamicRTSPServer:creatnew() :1.调用继承自RTPSever:setUpOurSocket:1.调用 GroupsockHelper的 setupStreamSocket创建一个 socket 连接,并绑定,2.设置 socket 的发送缓存大小,3.调用 listen 开始监听端口,设置同时最大能处理连接数 LISTEN_BACKLOG_SIZE=20 ,如果达到这个上限则 client 端将收到 ECONNERREFUSED 的错误4.测试绑定端

4、口是否为0,为 0 的话重新绑定断口,并返回系统自己选择的新的端口。5.返回建立的socket 文件描述符2.调用自己和RTPSever 的构造函数:RTPSever 构造函数 :1.用一个 UsageEnvironment 对象的引用构造其父类Medium2.设置最大等待回收连接时间reclamationTestSeconds,超过这个时间从客户端没有RTSP命令或者 RTSP 的 RR 包则收回其RTSPClientSession3.建立一个HashTable(实际上是一个BasicHashTable),fServerMediaSessions 指向这个表。4.调用参数UsageEnvir

5、onment 对象 env 的成员 ,一个TaskScheduler 指针所指对象(实际就是一个BasicTaskScheduler 对象)的成员函数turnOnBackgroundReadHandling() :1.调用一个 HandlerSet:assignHandler() 创建一个 Handler ,把 socketNum【此处为服务器监听的socket描述符】和处理函数RTSPServer:incomingConnectionHandler() ,还有指向RTSPSever 的指针绑定在一起。incomingConnectionHandler 作用:1.调用 accept 返回服务器

6、与客户端连接的 socket 描述符2.设置客户端描述符为非阻塞3.增加客户端socket 描述符的发送缓存为 50*10244.为此客户端随机分配一个sessionId5.用客户端 socket 描述符clientSocket,sessionId,和客户端地址clientAddr 调用creatNewClientSession 创建一个 clientSession。2,请求消息处理过程上节我们谈到RTSP 服务器收到客户端的连接请求,建立了 RTSPClientSession 类,处理单独的客户会话。在建立RTSPClientSession 的过程中,将新建立的socket 句柄( clie

7、ntSocket )和 RTSP 请求处理函数句柄RTSPClientSession:incomingRequestHandler 传给任务调度器,由任务调度器对两者进行一对一关联。当客户端发出RTSP 请求后,服务器主循环中的select 调用返回,根据 socket句柄找到对应的incomingRequestHandler ,开始消息处理。先进行消息的解析。RTSPClientSession:RTSPClientSession() 构造函数:1.重置请求缓存2.调用envir().taskScheduler().turnOnBackgroundReadHandling() ,这次 sock

8、etnumber 为客户端 socket 描述符这次的处理函数是RTSPServer:RTSPClientSession:incomingRequestHandler()RTSPServer:RTSPClientSession:incomingRequestHandler():调用 handleAlternativeRequestByte1(uint8_trequestByte):1.fRequestBufferfRequestBytesAlreadySeen=requestByte;把请求字符放入请求缓存fRequestBuffer2.调用 handleRequestBytes(1) 处理请

9、求缓存handleRequestBytes(int newBytesRead):1.调用 noteLiveness()查看请求是否到期 ,如果服务器的reclamationTestSeconds> 0 ,调用taskScheduler 对象的 rescheduleDelayedTask 函数 : 参数为( fLivenessCheckTask,fOurServer.fReclamationTestSeconds*1000000,(TaskFunc*)livenessTimeoutTask, this )其中 livenessTimeoutTask() 函数作用是删除new 出来的

10、clientSession.1.调用unscheduleDelayedTask(TaskToken&prevTask):从 DelayQueue 中删除prevTask 项,prevTask 置空 .2.调用scheduleDelayedTask(int64_t microseconds,TaskFunc* proc, void*clientData) :1.创建一个 DelayInterval对象 timeToDelay ,用 microseconds 初始化。2.创建一个AlarmHandler 对象,用 proc, clientData, timeToDelay 初始化3

11、.调用fDelayQueue.addEntry(), 把这个 AlarmHandler 对象加入到延迟队列中4.返回 AlarmHandler 对象的 tokenlong 类型 的指针2.如果请求的的长度超过请求缓存可读长度 fRequestBufferBytesLeft ,结束这个连接。3.找到请求消息的结尾: 。4.如果找到消息结尾,调用RTSPServer:RTSPClientSession:handleRequestBytes() 值得关注此函数 把请求字符串转换成命令各部分包括:cmdName 方法 , urlPreSuffixurl地址 ,urlSuffix 要读取的文件名 ,sc

12、eq消息的 Cseq,否则函数返回需要继续从连接中读取请求。分别存入对应的数组。5.如果转换成功,调用handleCmd_xxx() 处理对应的 cmdName: xxx 此处实现了: OPTIONS ,DESCRIBE ,SETUP , TEARDOWN ,PLAY ,PAUSE, GET_PARAMETER , SET_PARAMETER其中 PLAY ,PAUSE,GET_PARAMETER ,SET_PARAMETER 调用 handleCmd_withinSession (cmdName,urlPreSuffix, urlSuffix,cseq,(char const*)fReque

13、stBuffer);6.清空 RequestBuffer比如:消息解析后, 如果发现客户端的请求是 DESCRIBE 则进入 handleCmd_DESCRIBE 函数。 RTSP 服务器收到客户端的 DESCRIBE 请求后,根据请求URL(rtsp:/09/1.mpg) ,找到对应的流媒体资源,返回响应消息。live555 中的 ServerMediaSession 类用来处理会话中描述,它包含多个(音频或视频)的子会话描述(ServerMediaSubsession)。根据客户端请求URL 的后缀 (例如是 1.mpg), 调用成员函数DynamicRTSPServ

14、er:lookupServerMediaSession 查找对应的流媒体信息ServerMediaSession。(根据 urlSuffix 查找)。如果 ServerMediaSession 不存在,查找文件是否存在,若文件不存在,则判断ServerMediaSession(即smsExists)是否存在,如果存在则将其remove(调用removeServerMediaSession 方法)。但是如果本地存在1.mpg文件,则根据文件名创建一个新的ServerMediaSession(调用 createNewSMS 方法,若在该方法中找不到对应的文件扩展名,则将返回 NULL )。如果通过

15、 lookupServerMediaSession 返回的是NULL ,则向客户端发送响应消息并将fSessionIsActive 置为 FALSE ;否则,为该 session 组装一个 SDP 描述信息(调用generateSDPDescription 方法,该方法在ServerMediaSession类中),组装完成后,生成一个RTSP URL(调用 rtspURL 方法,该方法在RTSPServer 类中)。在创建 ServerMediaSession 过程中,根据文件后缀.mpg,创建媒体 MPEG-1or2 的解复用器(MPEG1or2FileServerDemux) 。再由MPE

16、G1or2FileServerDemux 创建一个子会话描述MPEG1or2DemuxedServerMediaSubsession 。最后由ServerMediaSession 完成组装响应消息中的SDP 信息( SDP组装过程见下面的描述) ,然后将响应消息发给客户端,完成一次消息交互。=RTSP 服务器处理客户端点播的基本流程处理连接请求的基本流程:l Step 1:与客户端建立 RTSP 连接(调用incomingConnectionHandler 方法),创建 ClientSession 并关联fClientSocket 与 incomingRequestHandler (调用inc

17、omingConnectionHandler1 )。lStep 2:接收客户端请求(调用incomingRequestHandler方法)。l Step 3:从客户端 Socket 读取数据, 并对请求数据 (即 therequest string)进行转换(调用 parseRTSPRequestString 方法,该方法在 RTSPCommon 类中)。l Step 4:根据分离出来的指令进行分别处理:nOPTIONS handleCmd_OPTIONSnDESCRIBE handleCmd_DESCRIBEhandleCmd_DESCRIBE 这一个方法比较重要,首先根据 urlSuffi

18、x 查找 ServerMediaSession 是否存在(调用 lookupServerMediaSession 方法,该方法中通过 HashTable 来查找)。在 testOnDemandRTSPServer 项目工程中,仅仅是通过streamName 来确认 session 是否为 NULL 。而在完整的live555MediaServer 项目工程中,则是通过DynamicRTSPServer 类来处理,其首先是查找文件是否存在,若文件不存在,则判断ServerMediaSession(即 smsExists)是否存在,如果存在则将其remove(调用removeServerMedia

19、Session 方法);若文件存在,则根据文件名创建一个ServerMediaSession(调用 createNewSMS 方法,若在该方法中找不到对应的文件扩展名,则将返回NULL)。如果通过lookupServerMediaSession返回的是NULL,则向客户端发送响应消息并将fSessionIsActive 置为 FALSE ;否则,为该 session 组装一个 SDP 描述信息(调用generateSDPDescription 方法,该方法在ServerMediaSession类中),组装完成后,生成一个RTSP URL(调用 rtspURL 方法,该方法在RTSPServer

20、 类中)。nSETUP handleCmd_SETUPhandleCmd_SETUP 方法中,有两个关键的名词,一个是urlPreSuffix ,代表了 session name(即 stream name);一个是urlSuffix ,代表了 subsession name(即 track name),后面经常用到的 streamName 和 trackId 分别与这两个名词有关。接下来会创建session's state,包括 incrementReferenceCount等。紧接着,会针对确定的subsession( track)查找相应的信息。接着,在request strin

21、g 查找一个 "Transport:" header ,目的是为了从中提取客户端请求的一些参数(调用parseTransportHeader 方法,该方法在RTSPServer 类中),如clientsDestinationAddressStr 、ClientRTPPortNum 等。再接着是 getStreamParameters(该方法在ServerMediaSession类中被定义为纯虚函数并在OnDemandServerMediaSubsession 类中被重定义) ,然后通过 fIsMulticast 和 streamingMode 来组装不同的响应消息。n PL

22、AY handleCmd_PLAY :处理播放请求,具体的实现流程请参见后面的步骤。n PAUSE handleCmd_PAUSE :处理暂停请求,在执行了该请求后,最终会调用 StopPlaying 方法,并将fAreCurrentlyPlaying置为 FALSE 。n TEARDOWN handleCmd_TEARDOWN :处理停止请求,将 fSessionIsActive 置为 FALSE 。nGET_PARAMETER handleCmd_GET_PARAMETER :该方法主要是维持客户端与服务器通信的生存状态,just forkeep alive。n SET_PARAMETER

23、 handleCmd_SET_PARAMETER :该方法未针对 SET_PARAMETER 作实现,使用该方法会调用handleCmd_notSupported 方法,并将最终引发与客户端断开连接。lStep 5:根据 Step 4 的不同指令进行消息响应(调用send方法),该消息响应是即时的。l Step 6:处理客户端发送“ SETUP”指令后即开始播放的特殊情况。l Step 7:将 RequestBuffer 进行重置,以便于为之后到来的请求做好准备。l Step 8:检查 fSessionIsActive 是否为 FALSE ,如果是则删除当前的 ClientSession。处理

24、 PLAY 的基本流程:l Step 1:对 rtspURL 及相关 header 的处理,涉及较多的细节。l Step 2:根据不同的 header 对流进行缩放比例或定位的处理。如果为 sawScaleHeader,则进行缩放比例的处理(调用setStreamScale方法,该方法在OnDemandServerMediaSubsession 类中实现)。如果为 sawRangeHeader,则进行寻找流的处理(即是对流进行定位,调用seekStream 方法,该方法在OnDemandServerMediaSubsession 类中实现;同时,该方法的调用是在初始播放前及播放过程中由于用户拖

25、动播放进度条而产生的系列请求) 。在 OnDemandServerMediaSubsession 类中, seekStream方法中调用了 seekStreamSource方法,该方法在对应的媒体格式文件的 FileServerMediaSubsession 类中实现(如针对 WAV 格式,则在 WAVAudioFileServerMediaSubsession 类中实现;针对 MP3 格式,则在 MP3AudioFileServerMediaSubsession 类中实现)。同理, OnDemandServerMediaSubsession 类中的setStreamScale方法中所调用的s

26、etStreamSourceScale方法亦是类似的实现机制。lStep 3:开始进行流式播放(调用startStream 方法,该方法在 OnDemandServerMediaSubsession 类中实现)。n Step 3.1:根据 clientSessionId 从 fDestinationsHashTable 中查找到 destinations(包括了客户端的 IP 地址、RTP 端口号、 RTCP 端口号等信息) 。n Step 3.2:调用 startPlaying 方法,在该方法中根据 RTPSink 或 UDPSink 分别调用 startPlaying 方法。如果是调用RT

27、PSink 的 startPlaying 方法,则接着会调用MediaSink 类中的 startPlaying 方法,并在该方法中调用MultiFramedRTPSink 类中的 continuePlaying 方法,之后便是buildAndSendPacket 了。这里已经来到重点了,即是关于不断读取 Frame 并 Send 的要点。在 MultiFramedRTPSink类中,通过 buildAndSendPacket 、 packFrame、afterGettingFrame 、afterGettingFrame1 、 sendPacketIfNecessary 和 sendNext 构成了一个循环圈,数据包的读取和发送在这里循环进行着。特别注意的是sendP

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论