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

news/2024/7/6 0:19:09 标签: session, header, null, string, 服务器, stream

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之上。


http://www.niftyadmin.cn/n/1863412.html

相关文章

java 调用 jps_java虚拟机学习之旅(1)——jps命令使用

我如今是一名本科大三学生,前面找实习的时候,面试官问了我虚拟机相关的知识,什么类加载机制,GC,内存模型之类的,jvm调优,jvm参数之类的当然没问,自我感觉答的还是比较好。但是后来面…

使用Windows API实现两个进程间(含窗体)的通信

在Windows下的两个进程之间通信通常有多种实现方式,在.NET中,有如命名管道、消息队列、共享内存等实现方式,这篇文章要讲的是使用Windows的API来实现简单的进程间通信,这两个进程既可以都是基于C#开发,也可以都是基于C…

java swing学习_Java学习笔记--Swing

1.创建框架AWT中Frame类用来描述顶层窗口,在Swing中,这个类的名为JFrame,它从Frame类扩展。JFrame是少数几个在Swing不用绘制在画布上的组件之一,因此,它的修饰部件(按钮、标题栏、图标等)由用户的窗口系统绘制。impor…

C#WinForm国际化的简单实现

软件行业发展到今天,国际化问题一直都占据非常重要的位置,而且应该越来越被重视。对于开发人员而言,在编写程序之前,国际化问题是首先要考虑的一个问题,也许有时候这个问题已经在设计者的考虑范围之内,但终…

java检测控制台输入_java扫描控制台输入

由于因最近练习算法的需要,加上API文档中翻译的太过模糊,做了一些小测试,算是武断的记下一些个人结论。Scanner cin new Scanner(System.in);对于cin.next(),若cin缓冲区中有值,获取并返回该String(实际上是返回Strin…

你好,上海世博!

盼望着,盼望着,2010上海世界博览会的脚步悄然而至。 上海世博会开幕了! 远在南国广州的我,期盼着能有这么一天,自己可以亲自奔赴上海,亲身体验上海世博所带来的一切。六个月,说长不长&#xff0…

BPMNJS 在HTML中的引入与使用

BPMNJS 在HTML中的引入与使用 在网上看到的大多是基于vue使用BPMN的示例或者教程,竟然没有在HTML使用的示例,有也是很简单的介绍核心库的引入和使用,并没有涉及到扩展库。于是简单看了下,真的是一波三折,坎坎坷坷。不过…

利用C#实现条形图、饼图的绘制(一)

近日,在编写一个统计程序的时候,希望通过条形图、饼图的形式形象地展现统计数据,为此,专门到sourceforge、codeproject等开源网站阅读查找有关资料,在这过程当中,阅读了一份源码,感觉很多东西都…