您的位置:首页 > 其它

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

2011-03-03 16:58 274 查看
处理连接请求的基本流程:


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
之上。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: