RTSP服务器处理客户端点播的基本流程
2011-04-08 11:41
387 查看
RTSP
服务器处理客户端点播的基本流程
处理连接请求的基本流程:
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
之上。
服务器处理客户端点播的基本流程
处理连接请求的基本流程:
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
之上。
相关文章推荐
- [转]RTSP服务器处理客户端点播的基本流程
- RTSP服务器处理客户端点播的基本流程
- RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- live555的安装 RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- RTSP点播消息流程实例(客户端:VLC, RTSP服务器:LIVE555 Media Server)
- live555 RTSP服务器建立及消息处理流程
- live555 RTSP服务器建立及消息处理流程
- SVN服务器搭建及客户端使用的基本流程
- RTSP点播消息流程实例(客户端:VLC, RTSP服务
- android RTSP连接服务器和从服务器接收数据的处理流程
- live555 RTSP服务器建立及消息处理流程
- live555 RTSP服务器建立及消息处理流程 .
- RTSP连接服务器和从服务器接收数据的处理流程
- live555 RTSP服务器建立及消息处理流程
- 服务器网络模型(2)---服务器的请求处理流程
- live555简介、整体框架 、openRTSP客户端流程
- ASP.NET执行模型之IIS服务器处理流程